2020-08-24 17:43:03 -05:00
|
|
|
|
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
|
|
2016-05-13 15:04:49 -05:00
|
|
|
|
#include <assert.h>
|
2016-06-09 11:23:49 -05:00
|
|
|
|
#include <stdlib.h>
|
2016-05-24 18:59:57 -05:00
|
|
|
|
#include <time.h>
|
2016-05-13 15:04:49 -05:00
|
|
|
|
|
2016-05-10 20:12:22 -05:00
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
|
#include "config.h"
|
|
|
|
|
#endif
|
|
|
|
|
|
2021-08-29 04:18:01 -05:00
|
|
|
|
#include <helper/log.h>
|
|
|
|
|
#include <helper/time_support.h>
|
2017-06-13 14:22:26 -05:00
|
|
|
|
#include "target/target.h"
|
2016-11-16 18:12:27 -06:00
|
|
|
|
#include "target/algorithm.h"
|
2017-06-13 14:22:26 -05:00
|
|
|
|
#include "target/target_type.h"
|
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 commit
615709d14049 ("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
Commit 39650e2273bc ("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 commit 861e75f54efb ("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: f5898bd93ff8 (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
Commit 6541233aa78d ("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: 6541233aa78d ("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
Commit 6541233aa78d ("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: 6541233aa78d ("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: 13cd75b6ecfd (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>
2022-03-03 12:03:55 -06:00
|
|
|
|
#include <target/smp.h>
|
2016-05-13 15:04:49 -05:00
|
|
|
|
#include "jtag/jtag.h"
|
2017-06-13 14:22:26 -05:00
|
|
|
|
#include "target/register.h"
|
|
|
|
|
#include "target/breakpoints.h"
|
2020-10-07 16:31:36 -05:00
|
|
|
|
#include "helper/base64.h"
|
2016-11-16 18:12:27 -06:00
|
|
|
|
#include "helper/time_support.h"
|
2017-02-05 20:00:05 -06:00
|
|
|
|
#include "riscv.h"
|
2023-02-15 11:53:03 -06:00
|
|
|
|
#include "program.h"
|
2017-03-24 20:21:56 -05:00
|
|
|
|
#include "gdb_regs.h"
|
|
|
|
|
#include "rtos/rtos.h"
|
2021-07-23 16:42:05 -05:00
|
|
|
|
#include "debug_defines.h"
|
2021-09-01 17:00:46 -05:00
|
|
|
|
#include <helper/bits.h>
|
2016-05-13 15:04:49 -05:00
|
|
|
|
|
|
|
|
|
#define get_field(reg, mask) (((reg) & (mask)) / ((mask) & ~((mask) << 1)))
|
|
|
|
|
#define set_field(reg, mask, val) (((reg) & ~(mask)) | (((val) * ((mask) & ~((mask) << 1))) & (mask)))
|
|
|
|
|
|
|
|
|
|
/*** JTAG registers. ***/
|
|
|
|
|
|
2016-09-27 10:45:51 -05:00
|
|
|
|
#define DTMCONTROL 0x10
|
|
|
|
|
#define DTMCONTROL_VERSION (0xf)
|
2016-05-21 23:41:10 -05:00
|
|
|
|
|
|
|
|
|
#define DBUS 0x11
|
2016-06-16 14:16:56 -05:00
|
|
|
|
|
2019-01-08 12:30:26 -06:00
|
|
|
|
uint8_t ir_dtmcontrol[4] = {DTMCONTROL};
|
2017-02-05 20:00:05 -06:00
|
|
|
|
struct scan_field select_dtmcontrol = {
|
2017-06-14 16:13:53 -05:00
|
|
|
|
.in_value = NULL,
|
|
|
|
|
.out_value = ir_dtmcontrol
|
2017-02-05 20:00:05 -06:00
|
|
|
|
};
|
2019-01-08 12:30:26 -06:00
|
|
|
|
uint8_t ir_dbus[4] = {DBUS};
|
2017-02-05 20:00:05 -06:00
|
|
|
|
struct scan_field select_dbus = {
|
2017-06-14 16:13:53 -05:00
|
|
|
|
.in_value = NULL,
|
|
|
|
|
.out_value = ir_dbus
|
2017-02-05 20:00:05 -06:00
|
|
|
|
};
|
2019-01-08 12:30:26 -06:00
|
|
|
|
uint8_t ir_idcode[4] = {0x1};
|
2017-02-05 20:00:05 -06:00
|
|
|
|
struct scan_field select_idcode = {
|
2017-06-14 16:13:53 -05:00
|
|
|
|
.in_value = NULL,
|
|
|
|
|
.out_value = ir_idcode
|
2017-02-05 20:00:05 -06:00
|
|
|
|
};
|
|
|
|
|
|
2019-06-10 15:33:50 -05:00
|
|
|
|
bscan_tunnel_type_t bscan_tunnel_type;
|
2019-04-23 18:25:22 -05:00
|
|
|
|
int bscan_tunnel_ir_width; /* if zero, then tunneling is not present/active */
|
2022-04-20 12:16:47 -05:00
|
|
|
|
static int bscan_tunnel_ir_id; /* IR ID of the JTAG TAP to access the tunnel. Valid when not 0 */
|
2019-06-10 15:33:50 -05:00
|
|
|
|
|
2021-01-29 12:58:11 -06:00
|
|
|
|
static const uint8_t bscan_zero[4] = {0};
|
|
|
|
|
static const uint8_t bscan_one[4] = {1};
|
2019-04-23 18:25:22 -05:00
|
|
|
|
|
2020-09-01 12:32:31 -05:00
|
|
|
|
uint8_t ir_user4[4];
|
2019-04-23 18:25:22 -05:00
|
|
|
|
struct scan_field select_user4 = {
|
|
|
|
|
.in_value = NULL,
|
|
|
|
|
.out_value = ir_user4
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
uint8_t bscan_tunneled_ir_width[4] = {5}; /* overridden by assignment in riscv_init_target */
|
2019-06-10 15:33:50 -05:00
|
|
|
|
struct scan_field _bscan_tunnel_data_register_select_dmi[] = {
|
|
|
|
|
{
|
|
|
|
|
.num_bits = 3,
|
|
|
|
|
.out_value = bscan_zero,
|
|
|
|
|
.in_value = NULL,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
.num_bits = 5, /* initialized in riscv_init_target to ir width of DM */
|
|
|
|
|
.out_value = ir_dbus,
|
|
|
|
|
.in_value = NULL,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
.num_bits = 7,
|
|
|
|
|
.out_value = bscan_tunneled_ir_width,
|
|
|
|
|
.in_value = NULL,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
.num_bits = 1,
|
|
|
|
|
.out_value = bscan_zero,
|
|
|
|
|
.in_value = NULL,
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct scan_field _bscan_tunnel_nested_tap_select_dmi[] = {
|
2019-04-23 18:25:22 -05:00
|
|
|
|
{
|
|
|
|
|
.num_bits = 1,
|
|
|
|
|
.out_value = bscan_zero,
|
|
|
|
|
.in_value = NULL,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
.num_bits = 7,
|
|
|
|
|
.out_value = bscan_tunneled_ir_width,
|
|
|
|
|
.in_value = NULL,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
.num_bits = 0, /* initialized in riscv_init_target to ir width of DM */
|
|
|
|
|
.out_value = ir_dbus,
|
|
|
|
|
.in_value = NULL,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
.num_bits = 3,
|
|
|
|
|
.out_value = bscan_zero,
|
|
|
|
|
.in_value = NULL,
|
|
|
|
|
}
|
|
|
|
|
};
|
2019-06-10 15:33:50 -05:00
|
|
|
|
struct scan_field *bscan_tunnel_nested_tap_select_dmi = _bscan_tunnel_nested_tap_select_dmi;
|
2021-05-16 06:57:11 -05:00
|
|
|
|
uint32_t bscan_tunnel_nested_tap_select_dmi_num_fields = ARRAY_SIZE(_bscan_tunnel_nested_tap_select_dmi);
|
2019-06-10 15:33:50 -05:00
|
|
|
|
|
|
|
|
|
struct scan_field *bscan_tunnel_data_register_select_dmi = _bscan_tunnel_data_register_select_dmi;
|
2021-05-16 06:57:11 -05:00
|
|
|
|
uint32_t bscan_tunnel_data_register_select_dmi_num_fields = ARRAY_SIZE(_bscan_tunnel_data_register_select_dmi);
|
2019-04-23 18:25:22 -05:00
|
|
|
|
|
2016-09-17 15:21:34 -05:00
|
|
|
|
struct trigger {
|
|
|
|
|
uint64_t address;
|
|
|
|
|
uint32_t length;
|
|
|
|
|
uint64_t mask;
|
|
|
|
|
uint64_t value;
|
|
|
|
|
bool read, write, execute;
|
|
|
|
|
int unique_id;
|
|
|
|
|
};
|
|
|
|
|
|
2017-08-15 17:55:09 -05:00
|
|
|
|
/* Wall-clock timeout for a command/access. Settable via RISC-V Target commands.*/
|
|
|
|
|
int riscv_command_timeout_sec = DEFAULT_COMMAND_TIMEOUT_SEC;
|
|
|
|
|
|
|
|
|
|
/* Wall-clock timeout after reset. Settable via RISC-V Target commands.*/
|
|
|
|
|
int riscv_reset_timeout_sec = DEFAULT_RESET_TIMEOUT_SEC;
|
|
|
|
|
|
2019-12-10 14:18:03 -06:00
|
|
|
|
bool riscv_enable_virt2phys = true;
|
2020-02-20 15:58:15 -06:00
|
|
|
|
bool riscv_ebreakm = true;
|
|
|
|
|
bool riscv_ebreaks = true;
|
|
|
|
|
bool riscv_ebreaku = true;
|
2018-03-19 16:05:35 -05:00
|
|
|
|
|
2019-07-18 15:15:28 -05:00
|
|
|
|
bool riscv_enable_virtual;
|
|
|
|
|
|
2019-07-15 12:32:28 -05:00
|
|
|
|
static enum {
|
|
|
|
|
RO_NORMAL,
|
|
|
|
|
RO_REVERSED
|
|
|
|
|
} resume_order;
|
|
|
|
|
|
2021-01-29 12:58:11 -06:00
|
|
|
|
const virt2phys_info_t sv32 = {
|
2020-03-05 13:33:51 -06:00
|
|
|
|
.name = "Sv32",
|
|
|
|
|
.va_bits = 32,
|
2019-12-10 14:18:03 -06:00
|
|
|
|
.level = 2,
|
|
|
|
|
.pte_shift = 2,
|
|
|
|
|
.vpn_shift = {12, 22},
|
|
|
|
|
.vpn_mask = {0x3ff, 0x3ff},
|
|
|
|
|
.pte_ppn_shift = {10, 20},
|
|
|
|
|
.pte_ppn_mask = {0x3ff, 0xfff},
|
|
|
|
|
.pa_ppn_shift = {12, 22},
|
|
|
|
|
.pa_ppn_mask = {0x3ff, 0xfff},
|
|
|
|
|
};
|
|
|
|
|
|
2021-01-29 12:58:11 -06:00
|
|
|
|
const virt2phys_info_t sv39 = {
|
2020-03-05 13:33:51 -06:00
|
|
|
|
.name = "Sv39",
|
|
|
|
|
.va_bits = 39,
|
2019-12-10 14:18:03 -06:00
|
|
|
|
.level = 3,
|
|
|
|
|
.pte_shift = 3,
|
|
|
|
|
.vpn_shift = {12, 21, 30},
|
|
|
|
|
.vpn_mask = {0x1ff, 0x1ff, 0x1ff},
|
|
|
|
|
.pte_ppn_shift = {10, 19, 28},
|
|
|
|
|
.pte_ppn_mask = {0x1ff, 0x1ff, 0x3ffffff},
|
|
|
|
|
.pa_ppn_shift = {12, 21, 30},
|
|
|
|
|
.pa_ppn_mask = {0x1ff, 0x1ff, 0x3ffffff},
|
|
|
|
|
};
|
|
|
|
|
|
2021-01-29 12:58:11 -06:00
|
|
|
|
const virt2phys_info_t sv48 = {
|
2020-03-05 13:33:51 -06:00
|
|
|
|
.name = "Sv48",
|
|
|
|
|
.va_bits = 48,
|
2019-12-10 14:18:03 -06:00
|
|
|
|
.level = 4,
|
|
|
|
|
.pte_shift = 3,
|
|
|
|
|
.vpn_shift = {12, 21, 30, 39},
|
|
|
|
|
.vpn_mask = {0x1ff, 0x1ff, 0x1ff, 0x1ff},
|
|
|
|
|
.pte_ppn_shift = {10, 19, 28, 37},
|
|
|
|
|
.pte_ppn_mask = {0x1ff, 0x1ff, 0x1ff, 0x1ffff},
|
|
|
|
|
.pa_ppn_shift = {12, 21, 30, 39},
|
|
|
|
|
.pa_ppn_mask = {0x1ff, 0x1ff, 0x1ff, 0x1ffff},
|
|
|
|
|
};
|
|
|
|
|
|
2020-10-21 14:21:05 -05:00
|
|
|
|
void riscv_sample_buf_maybe_add_timestamp(struct target *target, bool before)
|
2020-10-07 16:31:36 -05:00
|
|
|
|
{
|
|
|
|
|
RISCV_INFO(r);
|
|
|
|
|
uint32_t now = timeval_ms() & 0xffffffff;
|
2020-10-21 14:21:05 -05:00
|
|
|
|
if (r->sample_buf.used + 5 < r->sample_buf.size) {
|
|
|
|
|
if (before)
|
|
|
|
|
r->sample_buf.buf[r->sample_buf.used++] = RISCV_SAMPLE_BUF_TIMESTAMP_BEFORE;
|
|
|
|
|
else
|
|
|
|
|
r->sample_buf.buf[r->sample_buf.used++] = RISCV_SAMPLE_BUF_TIMESTAMP_AFTER;
|
2020-10-07 16:31:36 -05:00
|
|
|
|
r->sample_buf.buf[r->sample_buf.used++] = now & 0xff;
|
|
|
|
|
r->sample_buf.buf[r->sample_buf.used++] = (now >> 8) & 0xff;
|
|
|
|
|
r->sample_buf.buf[r->sample_buf.used++] = (now >> 16) & 0xff;
|
|
|
|
|
r->sample_buf.buf[r->sample_buf.used++] = (now >> 24) & 0xff;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-03 14:13:09 -05:00
|
|
|
|
static int riscv_resume_go_all_harts(struct target *target);
|
|
|
|
|
|
2019-04-23 18:25:22 -05:00
|
|
|
|
void select_dmi_via_bscan(struct target *target)
|
|
|
|
|
{
|
|
|
|
|
jtag_add_ir_scan(target->tap, &select_user4, TAP_IDLE);
|
2019-06-10 15:33:50 -05:00
|
|
|
|
if (bscan_tunnel_type == BSCAN_TUNNEL_DATA_REGISTER)
|
|
|
|
|
jtag_add_dr_scan(target->tap, bscan_tunnel_data_register_select_dmi_num_fields,
|
|
|
|
|
bscan_tunnel_data_register_select_dmi, TAP_IDLE);
|
|
|
|
|
else /* BSCAN_TUNNEL_NESTED_TAP */
|
|
|
|
|
jtag_add_dr_scan(target->tap, bscan_tunnel_nested_tap_select_dmi_num_fields,
|
|
|
|
|
bscan_tunnel_nested_tap_select_dmi, TAP_IDLE);
|
2019-04-23 18:25:22 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint32_t dtmcontrol_scan_via_bscan(struct target *target, uint32_t out)
|
|
|
|
|
{
|
|
|
|
|
/* On BSCAN TAP: Select IR=USER4, issue tunneled IR scan via BSCAN TAP's DR */
|
|
|
|
|
uint8_t tunneled_ir_width[4] = {bscan_tunnel_ir_width};
|
|
|
|
|
uint8_t tunneled_dr_width[4] = {32};
|
|
|
|
|
uint8_t out_value[5] = {0};
|
|
|
|
|
uint8_t in_value[5] = {0};
|
|
|
|
|
|
|
|
|
|
buf_set_u32(out_value, 0, 32, out);
|
2019-06-10 15:33:50 -05:00
|
|
|
|
struct scan_field tunneled_ir[4] = {};
|
|
|
|
|
struct scan_field tunneled_dr[4] = {};
|
|
|
|
|
|
|
|
|
|
if (bscan_tunnel_type == BSCAN_TUNNEL_DATA_REGISTER) {
|
|
|
|
|
tunneled_ir[0].num_bits = 3;
|
|
|
|
|
tunneled_ir[0].out_value = bscan_zero;
|
|
|
|
|
tunneled_ir[0].in_value = NULL;
|
|
|
|
|
tunneled_ir[1].num_bits = bscan_tunnel_ir_width;
|
|
|
|
|
tunneled_ir[1].out_value = ir_dtmcontrol;
|
|
|
|
|
tunneled_ir[1].in_value = NULL;
|
|
|
|
|
tunneled_ir[2].num_bits = 7;
|
|
|
|
|
tunneled_ir[2].out_value = tunneled_ir_width;
|
|
|
|
|
tunneled_ir[2].in_value = NULL;
|
|
|
|
|
tunneled_ir[3].num_bits = 1;
|
|
|
|
|
tunneled_ir[3].out_value = bscan_zero;
|
|
|
|
|
tunneled_ir[3].in_value = NULL;
|
|
|
|
|
|
|
|
|
|
tunneled_dr[0].num_bits = 3;
|
|
|
|
|
tunneled_dr[0].out_value = bscan_zero;
|
|
|
|
|
tunneled_dr[0].in_value = NULL;
|
2020-08-21 14:56:04 -05:00
|
|
|
|
tunneled_dr[1].num_bits = 32 + 1;
|
2019-06-10 15:33:50 -05:00
|
|
|
|
tunneled_dr[1].out_value = out_value;
|
|
|
|
|
tunneled_dr[1].in_value = in_value;
|
|
|
|
|
tunneled_dr[2].num_bits = 7;
|
|
|
|
|
tunneled_dr[2].out_value = tunneled_dr_width;
|
|
|
|
|
tunneled_dr[2].in_value = NULL;
|
|
|
|
|
tunneled_dr[3].num_bits = 1;
|
|
|
|
|
tunneled_dr[3].out_value = bscan_one;
|
|
|
|
|
tunneled_dr[3].in_value = NULL;
|
2020-08-21 14:56:04 -05:00
|
|
|
|
} else {
|
2019-06-10 15:33:50 -05:00
|
|
|
|
/* BSCAN_TUNNEL_NESTED_TAP */
|
|
|
|
|
tunneled_ir[3].num_bits = 3;
|
|
|
|
|
tunneled_ir[3].out_value = bscan_zero;
|
|
|
|
|
tunneled_ir[3].in_value = NULL;
|
|
|
|
|
tunneled_ir[2].num_bits = bscan_tunnel_ir_width;
|
|
|
|
|
tunneled_ir[2].out_value = ir_dtmcontrol;
|
|
|
|
|
tunneled_ir[1].in_value = NULL;
|
|
|
|
|
tunneled_ir[1].num_bits = 7;
|
|
|
|
|
tunneled_ir[1].out_value = tunneled_ir_width;
|
|
|
|
|
tunneled_ir[2].in_value = NULL;
|
|
|
|
|
tunneled_ir[0].num_bits = 1;
|
|
|
|
|
tunneled_ir[0].out_value = bscan_zero;
|
|
|
|
|
tunneled_ir[0].in_value = NULL;
|
|
|
|
|
|
|
|
|
|
tunneled_dr[3].num_bits = 3;
|
|
|
|
|
tunneled_dr[3].out_value = bscan_zero;
|
|
|
|
|
tunneled_dr[3].in_value = NULL;
|
2020-08-21 14:56:04 -05:00
|
|
|
|
tunneled_dr[2].num_bits = 32 + 1;
|
2019-06-10 15:33:50 -05:00
|
|
|
|
tunneled_dr[2].out_value = out_value;
|
|
|
|
|
tunneled_dr[2].in_value = in_value;
|
|
|
|
|
tunneled_dr[1].num_bits = 7;
|
|
|
|
|
tunneled_dr[1].out_value = tunneled_dr_width;
|
|
|
|
|
tunneled_dr[1].in_value = NULL;
|
|
|
|
|
tunneled_dr[0].num_bits = 1;
|
|
|
|
|
tunneled_dr[0].out_value = bscan_one;
|
|
|
|
|
tunneled_dr[0].in_value = NULL;
|
|
|
|
|
}
|
2019-04-23 18:25:22 -05:00
|
|
|
|
jtag_add_ir_scan(target->tap, &select_user4, TAP_IDLE);
|
2021-05-16 06:57:11 -05:00
|
|
|
|
jtag_add_dr_scan(target->tap, ARRAY_SIZE(tunneled_ir), tunneled_ir, TAP_IDLE);
|
|
|
|
|
jtag_add_dr_scan(target->tap, ARRAY_SIZE(tunneled_dr), tunneled_dr, TAP_IDLE);
|
2019-04-23 18:25:22 -05:00
|
|
|
|
select_dmi_via_bscan(target);
|
|
|
|
|
|
|
|
|
|
int retval = jtag_execute_queue();
|
|
|
|
|
if (retval != ERROR_OK) {
|
|
|
|
|
LOG_ERROR("failed jtag scan: %d", retval);
|
|
|
|
|
return retval;
|
|
|
|
|
}
|
|
|
|
|
/* Note the starting offset is bit 1, not bit 0. In BSCAN tunnel, there is a one-bit TCK skew between
|
|
|
|
|
output and input */
|
|
|
|
|
uint32_t in = buf_get_u32(in_value, 1, 32);
|
|
|
|
|
LOG_DEBUG("DTMCS: 0x%x -> 0x%x", out, in);
|
|
|
|
|
|
|
|
|
|
return in;
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-27 10:45:51 -05:00
|
|
|
|
static uint32_t dtmcontrol_scan(struct target *target, uint32_t out)
|
|
|
|
|
{
|
|
|
|
|
struct scan_field field;
|
|
|
|
|
uint8_t in_value[4];
|
2019-12-20 16:56:08 -06:00
|
|
|
|
uint8_t out_value[4] = { 0 };
|
2016-09-27 10:45:51 -05:00
|
|
|
|
|
2019-04-23 18:25:22 -05:00
|
|
|
|
if (bscan_tunnel_ir_width != 0)
|
|
|
|
|
return dtmcontrol_scan_via_bscan(target, out);
|
|
|
|
|
|
|
|
|
|
|
2016-09-27 10:45:51 -05:00
|
|
|
|
buf_set_u32(out_value, 0, 32, out);
|
|
|
|
|
|
|
|
|
|
jtag_add_ir_scan(target->tap, &select_dtmcontrol, TAP_IDLE);
|
|
|
|
|
|
|
|
|
|
field.num_bits = 32;
|
|
|
|
|
field.out_value = out_value;
|
|
|
|
|
field.in_value = in_value;
|
|
|
|
|
jtag_add_dr_scan(target->tap, 1, &field, TAP_IDLE);
|
|
|
|
|
|
2017-02-05 20:00:05 -06:00
|
|
|
|
/* Always return to dbus. */
|
|
|
|
|
jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE);
|
|
|
|
|
|
2016-09-27 10:45:51 -05:00
|
|
|
|
int retval = jtag_execute_queue();
|
|
|
|
|
if (retval != ERROR_OK) {
|
|
|
|
|
LOG_ERROR("failed jtag scan: %d", retval);
|
|
|
|
|
return retval;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint32_t in = buf_get_u32(field.in_value, 0, 32);
|
|
|
|
|
LOG_DEBUG("DTMCONTROL: 0x%x -> 0x%x", out, in);
|
|
|
|
|
|
|
|
|
|
return in;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-05 20:00:05 -06:00
|
|
|
|
static struct target_type *get_target_type(struct target *target)
|
2016-08-12 17:51:27 -05:00
|
|
|
|
{
|
|
|
|
|
riscv_info_t *info = (riscv_info_t *) target->arch_info;
|
2016-10-20 12:42:28 -05:00
|
|
|
|
|
2018-05-21 21:44:01 -05:00
|
|
|
|
if (!info) {
|
|
|
|
|
LOG_ERROR("Target has not been initialized");
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-05 20:00:05 -06:00
|
|
|
|
switch (info->dtm_version) {
|
|
|
|
|
case 0:
|
|
|
|
|
return &riscv011_target;
|
|
|
|
|
case 1:
|
|
|
|
|
return &riscv013_target;
|
|
|
|
|
default:
|
2021-10-21 19:08:49 -05:00
|
|
|
|
LOG_ERROR("[%s] Unsupported DTM version: %d",
|
|
|
|
|
target_name(target), info->dtm_version);
|
2017-02-05 20:00:05 -06:00
|
|
|
|
return NULL;
|
2016-06-06 16:07:54 -05:00
|
|
|
|
}
|
2016-06-10 12:45:45 -05:00
|
|
|
|
}
|
|
|
|
|
|
2020-09-17 15:20:12 -05:00
|
|
|
|
static int riscv_create_target(struct target *target, Jim_Interp *interp)
|
2016-05-10 20:12:22 -05:00
|
|
|
|
{
|
2020-09-17 15:20:12 -05:00
|
|
|
|
LOG_DEBUG("riscv_create_target()");
|
2016-05-13 15:04:49 -05:00
|
|
|
|
target->arch_info = calloc(1, sizeof(riscv_info_t));
|
2021-09-01 17:00:46 -05:00
|
|
|
|
if (!target->arch_info) {
|
|
|
|
|
LOG_ERROR("Failed to allocate RISC-V target structure.");
|
2016-05-13 16:55:32 -05:00
|
|
|
|
return ERROR_FAIL;
|
2021-09-01 17:00:46 -05:00
|
|
|
|
}
|
2020-09-17 15:20:12 -05:00
|
|
|
|
riscv_info_init(target, target->arch_info);
|
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int riscv_init_target(struct command_context *cmd_ctx,
|
|
|
|
|
struct target *target)
|
|
|
|
|
{
|
|
|
|
|
LOG_DEBUG("riscv_init_target()");
|
|
|
|
|
RISCV_INFO(info);
|
2017-02-05 20:00:05 -06:00
|
|
|
|
info->cmd_ctx = cmd_ctx;
|
2016-05-13 15:04:49 -05:00
|
|
|
|
|
2016-09-27 10:45:51 -05:00
|
|
|
|
select_dtmcontrol.num_bits = target->tap->ir_length;
|
2016-05-21 23:41:10 -05:00
|
|
|
|
select_dbus.num_bits = target->tap->ir_length;
|
2016-09-27 15:06:32 -05:00
|
|
|
|
select_idcode.num_bits = target->tap->ir_length;
|
2016-05-19 15:33:47 -05:00
|
|
|
|
|
2019-04-23 18:25:22 -05:00
|
|
|
|
if (bscan_tunnel_ir_width != 0) {
|
2022-04-20 12:16:47 -05:00
|
|
|
|
uint32_t ir_user4_raw = bscan_tunnel_ir_id;
|
|
|
|
|
/* Provide a default value which target some Xilinx FPGA USER4 IR */
|
|
|
|
|
if (ir_user4_raw == 0) {
|
|
|
|
|
assert(target->tap->ir_length >= 6);
|
|
|
|
|
ir_user4_raw = 0x23 << (target->tap->ir_length - 6);
|
|
|
|
|
}
|
2020-09-01 12:32:31 -05:00
|
|
|
|
ir_user4[0] = (uint8_t)ir_user4_raw;
|
|
|
|
|
ir_user4[1] = (uint8_t)(ir_user4_raw >>= 8);
|
|
|
|
|
ir_user4[2] = (uint8_t)(ir_user4_raw >>= 8);
|
|
|
|
|
ir_user4[3] = (uint8_t)(ir_user4_raw >>= 8);
|
2019-04-23 18:25:22 -05:00
|
|
|
|
select_user4.num_bits = target->tap->ir_length;
|
|
|
|
|
bscan_tunneled_ir_width[0] = bscan_tunnel_ir_width;
|
2019-06-10 15:33:50 -05:00
|
|
|
|
if (bscan_tunnel_type == BSCAN_TUNNEL_DATA_REGISTER)
|
|
|
|
|
bscan_tunnel_data_register_select_dmi[1].num_bits = bscan_tunnel_ir_width;
|
|
|
|
|
else /* BSCAN_TUNNEL_NESTED_TAP */
|
|
|
|
|
bscan_tunnel_nested_tap_select_dmi[2].num_bits = bscan_tunnel_ir_width;
|
2019-04-23 18:25:22 -05:00
|
|
|
|
}
|
|
|
|
|
|
2018-06-12 10:15:39 -05:00
|
|
|
|
riscv_semihosting_init(target);
|
|
|
|
|
|
2018-10-30 13:29:00 -05:00
|
|
|
|
target->debug_reason = DBG_REASON_DBGRQ;
|
|
|
|
|
|
2016-05-13 15:04:49 -05:00
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-01 06:47:17 -05:00
|
|
|
|
static void riscv_free_registers(struct target *target)
|
2016-05-13 16:55:32 -05:00
|
|
|
|
{
|
2018-08-29 16:22:50 -05:00
|
|
|
|
/* Free the shared structure use for most registers. */
|
2018-10-18 12:06:23 -05:00
|
|
|
|
if (target->reg_cache) {
|
|
|
|
|
if (target->reg_cache->reg_list) {
|
2020-08-17 02:58:58 -05:00
|
|
|
|
free(target->reg_cache->reg_list[0].arch_info);
|
2018-10-18 12:06:23 -05:00
|
|
|
|
/* Free the ones we allocated separately. */
|
|
|
|
|
for (unsigned i = GDB_REGNO_COUNT; i < target->reg_cache->num_regs; i++)
|
|
|
|
|
free(target->reg_cache->reg_list[i].arch_info);
|
2021-11-02 11:55:07 -05:00
|
|
|
|
for (unsigned int i = 0; i < target->reg_cache->num_regs; i++)
|
|
|
|
|
free(target->reg_cache->reg_list[i].value);
|
2018-10-18 12:06:23 -05:00
|
|
|
|
free(target->reg_cache->reg_list);
|
|
|
|
|
}
|
|
|
|
|
free(target->reg_cache);
|
|
|
|
|
}
|
2019-04-01 06:47:17 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void riscv_deinit_target(struct target *target)
|
|
|
|
|
{
|
|
|
|
|
LOG_DEBUG("riscv_deinit_target()");
|
2020-10-01 13:05:41 -05:00
|
|
|
|
|
2021-09-01 17:00:46 -05:00
|
|
|
|
riscv_info_t *info = target->arch_info;
|
2019-04-01 06:47:17 -05:00
|
|
|
|
struct target_type *tt = get_target_type(target);
|
2020-10-01 13:05:41 -05:00
|
|
|
|
|
2021-10-28 14:52:13 -05:00
|
|
|
|
if (riscv_flush_registers(target) != ERROR_OK)
|
|
|
|
|
LOG_ERROR("[%s] Failed to flush registers. Ignoring this error.", target_name(target));
|
|
|
|
|
|
2020-10-01 13:05:41 -05:00
|
|
|
|
if (tt && info->version_specific)
|
2019-04-01 06:47:17 -05:00
|
|
|
|
tt->deinit_target(target);
|
|
|
|
|
|
|
|
|
|
riscv_free_registers(target);
|
|
|
|
|
|
2020-10-01 13:05:41 -05:00
|
|
|
|
range_list_t *entry, *tmp;
|
2023-02-15 11:53:37 -06:00
|
|
|
|
list_for_each_entry_safe(entry, tmp, &info->hide_csr, list) {
|
|
|
|
|
free(entry->name);
|
|
|
|
|
free(entry);
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-01 13:05:41 -05:00
|
|
|
|
list_for_each_entry_safe(entry, tmp, &info->expose_csr, list) {
|
|
|
|
|
free(entry->name);
|
|
|
|
|
free(entry);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
list_for_each_entry_safe(entry, tmp, &info->expose_custom, list) {
|
|
|
|
|
free(entry->name);
|
|
|
|
|
free(entry);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
free(info->reg_names);
|
|
|
|
|
free(target->arch_info);
|
|
|
|
|
|
2017-02-05 20:00:05 -06:00
|
|
|
|
target->arch_info = NULL;
|
2016-09-17 15:21:34 -05:00
|
|
|
|
}
|
|
|
|
|
|
2017-07-11 16:49:35 -05:00
|
|
|
|
static void trigger_from_breakpoint(struct trigger *trigger,
|
|
|
|
|
const struct breakpoint *breakpoint)
|
2016-09-17 15:21:34 -05:00
|
|
|
|
{
|
2017-07-11 16:49:35 -05:00
|
|
|
|
trigger->address = breakpoint->address;
|
|
|
|
|
trigger->length = breakpoint->length;
|
|
|
|
|
trigger->mask = ~0LL;
|
|
|
|
|
trigger->read = false;
|
|
|
|
|
trigger->write = false;
|
|
|
|
|
trigger->execute = true;
|
2017-12-22 16:35:38 -06:00
|
|
|
|
/* unique_id is unique across both breakpoints and watchpoints. */
|
2017-07-11 16:49:35 -05:00
|
|
|
|
trigger->unique_id = breakpoint->unique_id;
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-09 16:48:31 -06:00
|
|
|
|
static bool can_use_napot_match(struct trigger *trigger, riscv_reg_t *tdata2)
|
|
|
|
|
{
|
|
|
|
|
riscv_reg_t addr = trigger->address;
|
|
|
|
|
riscv_reg_t size = trigger->length;
|
|
|
|
|
bool sizePowerOf2 = (size & (size - 1)) == 0;
|
|
|
|
|
bool addrAligned = (addr & (size - 1)) == 0;
|
|
|
|
|
if (size > 1 && sizePowerOf2 && addrAligned) {
|
|
|
|
|
if (tdata2)
|
|
|
|
|
*tdata2 = addr | ((size - 1) >> 1);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-03 12:08:18 -06:00
|
|
|
|
static int find_trigger(struct target *target, int type, bool chained, unsigned int *idx)
|
2022-11-09 16:48:31 -06:00
|
|
|
|
{
|
|
|
|
|
RISCV_INFO(r);
|
|
|
|
|
|
|
|
|
|
unsigned int num_found = 0;
|
|
|
|
|
unsigned int num_required = chained ? 2 : 1;
|
|
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < r->trigger_count; i++) {
|
|
|
|
|
if (r->trigger_unique_id[i] == -1) {
|
|
|
|
|
if (r->trigger_tinfo[i] & (1 << type)) {
|
|
|
|
|
num_found++;
|
|
|
|
|
bool done = (num_required == num_found);
|
|
|
|
|
if (done) {
|
|
|
|
|
/* Found num_required consecutive free triggers - success, done. */
|
|
|
|
|
if (idx)
|
|
|
|
|
*idx = i - (num_required - 1);
|
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
/* Found a trigger but need more consecutive ones */
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* Trigger already occupied or incompatible type.
|
|
|
|
|
* Reset the counter of found consecutive triggers */
|
|
|
|
|
num_found = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-18 17:57:17 -06:00
|
|
|
|
static int find_first_trigger_by_id(struct target *target, int unique_id)
|
|
|
|
|
{
|
|
|
|
|
RISCV_INFO(r);
|
|
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < r->trigger_count; i++) {
|
|
|
|
|
if (r->trigger_unique_id[i] == unique_id)
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-03 12:08:18 -06:00
|
|
|
|
static int set_trigger(struct target *target, unsigned int idx, riscv_reg_t tdata1, riscv_reg_t tdata2,
|
2022-11-17 11:47:01 -06:00
|
|
|
|
riscv_reg_t tdata1_ignore_mask)
|
2022-11-09 16:48:31 -06:00
|
|
|
|
{
|
2023-01-02 15:53:56 -06:00
|
|
|
|
riscv_reg_t tdata1_rb, tdata2_rb;
|
2022-11-09 16:48:31 -06:00
|
|
|
|
if (riscv_set_register(target, GDB_REGNO_TSELECT, idx) != ERROR_OK)
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
if (riscv_set_register(target, GDB_REGNO_TDATA1, tdata1) != ERROR_OK)
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
if (riscv_get_register(target, &tdata1_rb, GDB_REGNO_TDATA1) != ERROR_OK)
|
|
|
|
|
return ERROR_FAIL;
|
2022-11-17 11:47:01 -06:00
|
|
|
|
if ((tdata1 & ~tdata1_ignore_mask) != (tdata1_rb & ~tdata1_ignore_mask)) {
|
2023-01-02 15:53:56 -06:00
|
|
|
|
LOG_TARGET_DEBUG(target,
|
|
|
|
|
"Trigger %u doesn't support what we need; After writing 0x%"
|
2022-11-17 11:47:01 -06:00
|
|
|
|
PRIx64 " to tdata1 it contains 0x%" PRIx64
|
|
|
|
|
"; tdata1_ignore_mask=0x%" PRIx64,
|
2023-01-02 15:53:56 -06:00
|
|
|
|
idx, tdata1, tdata1_rb, tdata1_ignore_mask);
|
2022-11-09 16:48:31 -06:00
|
|
|
|
riscv_set_register(target, GDB_REGNO_TDATA1, 0);
|
|
|
|
|
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
|
|
|
|
}
|
|
|
|
|
if (riscv_set_register(target, GDB_REGNO_TDATA2, tdata2) != ERROR_OK)
|
|
|
|
|
return ERROR_FAIL;
|
2023-01-02 15:53:56 -06:00
|
|
|
|
if (riscv_get_register(target, &tdata2_rb, GDB_REGNO_TDATA2) != ERROR_OK)
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
if (tdata2 != tdata2_rb) {
|
|
|
|
|
LOG_TARGET_DEBUG(target,
|
|
|
|
|
"Trigger %u doesn't support what we need; wrote 0x%"
|
|
|
|
|
PRIx64 " to tdata2 but read back 0x%" PRIx64,
|
|
|
|
|
idx, tdata2, tdata2_rb);
|
|
|
|
|
riscv_set_register(target, GDB_REGNO_TDATA1, 0);
|
|
|
|
|
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
|
|
|
|
}
|
2022-11-09 16:48:31 -06:00
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int maybe_add_trigger_t1(struct target *target, struct trigger *trigger)
|
2017-07-11 16:49:35 -05:00
|
|
|
|
{
|
2023-01-03 12:08:18 -06:00
|
|
|
|
int ret;
|
2022-11-09 16:48:31 -06:00
|
|
|
|
riscv_reg_t tdata1, tdata2;
|
|
|
|
|
|
2017-07-11 16:49:35 -05:00
|
|
|
|
RISCV_INFO(r);
|
|
|
|
|
|
|
|
|
|
const uint32_t bpcontrol_x = 1<<0;
|
|
|
|
|
const uint32_t bpcontrol_w = 1<<1;
|
|
|
|
|
const uint32_t bpcontrol_r = 1<<2;
|
|
|
|
|
const uint32_t bpcontrol_u = 1<<3;
|
|
|
|
|
const uint32_t bpcontrol_s = 1<<4;
|
|
|
|
|
const uint32_t bpcontrol_h = 1<<5;
|
|
|
|
|
const uint32_t bpcontrol_m = 1<<6;
|
|
|
|
|
const uint32_t bpcontrol_bpmatch = 0xf << 7;
|
|
|
|
|
const uint32_t bpcontrol_bpaction = 0xff << 11;
|
|
|
|
|
|
2023-01-03 12:08:18 -06:00
|
|
|
|
unsigned int idx;
|
2022-11-09 16:48:31 -06:00
|
|
|
|
ret = find_trigger(target, CSR_TDATA1_TYPE_LEGACY, false, &idx);
|
|
|
|
|
if (ret != ERROR_OK)
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
|
|
if (riscv_get_register(target, &tdata1, GDB_REGNO_TDATA1) != ERROR_OK)
|
|
|
|
|
return ERROR_FAIL;
|
2017-07-11 16:49:35 -05:00
|
|
|
|
if (tdata1 & (bpcontrol_r | bpcontrol_w | bpcontrol_x)) {
|
2017-12-22 16:35:38 -06:00
|
|
|
|
/* Trigger is already in use, presumably by user code. */
|
2017-07-11 16:49:35 -05:00
|
|
|
|
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-09 16:48:31 -06:00
|
|
|
|
tdata1 = 0;
|
2017-07-11 16:49:35 -05:00
|
|
|
|
tdata1 = set_field(tdata1, bpcontrol_r, trigger->read);
|
|
|
|
|
tdata1 = set_field(tdata1, bpcontrol_w, trigger->write);
|
|
|
|
|
tdata1 = set_field(tdata1, bpcontrol_x, trigger->execute);
|
2022-11-09 16:48:31 -06:00
|
|
|
|
tdata1 = set_field(tdata1, bpcontrol_u, !!(r->misa & BIT('U' - 'A')));
|
|
|
|
|
tdata1 = set_field(tdata1, bpcontrol_s, !!(r->misa & BIT('S' - 'A')));
|
|
|
|
|
tdata1 = set_field(tdata1, bpcontrol_h, !!(r->misa & BIT('H' - 'A')));
|
|
|
|
|
tdata1 = set_field(tdata1, bpcontrol_m, 1);
|
2017-12-22 16:35:38 -06:00
|
|
|
|
tdata1 = set_field(tdata1, bpcontrol_bpaction, 0); /* cause bp exception */
|
2022-11-09 16:48:31 -06:00
|
|
|
|
tdata1 = set_field(tdata1, bpcontrol_bpmatch, 0); /* exact match */
|
|
|
|
|
tdata2 = trigger->address;
|
2022-11-17 11:47:01 -06:00
|
|
|
|
ret = set_trigger(target, idx, tdata1, tdata2, 0);
|
2022-11-09 16:48:31 -06:00
|
|
|
|
if (ret != ERROR_OK)
|
|
|
|
|
return ret;
|
|
|
|
|
r->trigger_unique_id[idx] = trigger->unique_id;
|
2017-07-11 16:49:35 -05:00
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-09 16:48:31 -06:00
|
|
|
|
static int maybe_add_trigger_t2(struct target *target, struct trigger *trigger)
|
2017-07-11 16:49:35 -05:00
|
|
|
|
{
|
2023-01-03 12:08:18 -06:00
|
|
|
|
int ret;
|
2022-11-09 16:48:31 -06:00
|
|
|
|
riscv_reg_t tdata1, tdata2;
|
2017-07-11 16:49:35 -05:00
|
|
|
|
|
2022-11-09 16:48:31 -06:00
|
|
|
|
RISCV_INFO(r);
|
2017-07-11 16:49:35 -05:00
|
|
|
|
|
2022-11-09 16:48:31 -06:00
|
|
|
|
tdata1 = 0;
|
|
|
|
|
tdata1 = set_field(tdata1, CSR_MCONTROL_TYPE(riscv_xlen(target)), 2);
|
|
|
|
|
tdata1 = set_field(tdata1, CSR_MCONTROL_DMODE(riscv_xlen(target)), 1);
|
|
|
|
|
tdata1 = set_field(tdata1, CSR_MCONTROL_ACTION, CSR_MCONTROL_ACTION_DEBUG_MODE);
|
|
|
|
|
tdata1 = set_field(tdata1, CSR_MCONTROL_M, 1);
|
|
|
|
|
tdata1 = set_field(tdata1, CSR_MCONTROL_S, !!(r->misa & (1 << ('S' - 'A'))));
|
|
|
|
|
tdata1 = set_field(tdata1, CSR_MCONTROL_U, !!(r->misa & (1 << ('U' - 'A'))));
|
|
|
|
|
tdata1 = set_field(tdata1, CSR_MCONTROL_EXECUTE, trigger->execute);
|
|
|
|
|
tdata1 = set_field(tdata1, CSR_MCONTROL_LOAD, trigger->read);
|
|
|
|
|
tdata1 = set_field(tdata1, CSR_MCONTROL_STORE, trigger->write);
|
|
|
|
|
tdata1 = set_field(tdata1, CSR_MCONTROL_SIZELO, CSR_MCONTROL_SIZELO_ANY & 3);
|
|
|
|
|
tdata1 = set_field(tdata1, CSR_MCONTROL_SIZEHI, (CSR_MCONTROL_SIZELO_ANY >> 2) & 3);
|
|
|
|
|
|
|
|
|
|
if (trigger->execute || trigger->length == 1)
|
|
|
|
|
goto MATCH_EQUAL;
|
|
|
|
|
if (!can_use_napot_match(trigger, &tdata2))
|
|
|
|
|
goto MATCH_GE_LT;
|
|
|
|
|
|
2023-01-03 12:08:18 -06:00
|
|
|
|
unsigned int idx;
|
2022-11-09 16:48:31 -06:00
|
|
|
|
ret = find_trigger(target, CSR_TDATA1_TYPE_MCONTROL, false, &idx);
|
|
|
|
|
if (ret != ERROR_OK)
|
|
|
|
|
return ret;
|
|
|
|
|
tdata1 = set_field(tdata1, CSR_MCONTROL_MATCH, CSR_MCONTROL_MATCH_NAPOT);
|
|
|
|
|
tdata1 = set_field(tdata1, CSR_MCONTROL_CHAIN, CSR_MCONTROL_CHAIN_DISABLED);
|
2022-11-17 11:47:01 -06:00
|
|
|
|
ret = set_trigger(target, idx, tdata1, tdata2, CSR_MCONTROL_MASKMAX(riscv_xlen(target)));
|
2022-11-09 16:48:31 -06:00
|
|
|
|
if (ret != ERROR_OK) {
|
|
|
|
|
if (ret == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
|
|
|
|
|
goto MATCH_GE_LT; /* Fallback to chained MATCH using GT and LE */
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
r->trigger_unique_id[idx] = trigger->unique_id;
|
|
|
|
|
return ERROR_OK;
|
2017-07-11 16:49:35 -05:00
|
|
|
|
|
2022-11-09 16:48:31 -06:00
|
|
|
|
MATCH_GE_LT:
|
|
|
|
|
ret = find_trigger(target, CSR_TDATA1_TYPE_MCONTROL, true, &idx);
|
|
|
|
|
if (ret != ERROR_OK)
|
|
|
|
|
return ret;
|
|
|
|
|
tdata1 = set_field(tdata1, CSR_MCONTROL_MATCH, CSR_MCONTROL_MATCH_GE);
|
|
|
|
|
tdata1 = set_field(tdata1, CSR_MCONTROL_CHAIN, CSR_MCONTROL_CHAIN_ENABLED);
|
|
|
|
|
tdata2 = trigger->address;
|
2022-11-17 11:47:01 -06:00
|
|
|
|
ret = set_trigger(target, idx, tdata1, tdata2, 0);
|
2022-11-09 16:48:31 -06:00
|
|
|
|
if (ret != ERROR_OK) {
|
|
|
|
|
if (ret == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
|
|
|
|
|
goto MATCH_EQUAL; /* Fallback to EQUAL MATCH */
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
tdata1 = set_field(tdata1, CSR_MCONTROL_MATCH, CSR_MCONTROL_MATCH_LT);
|
|
|
|
|
tdata1 = set_field(tdata1, CSR_MCONTROL_CHAIN, CSR_MCONTROL_CHAIN_DISABLED);
|
|
|
|
|
tdata2 = trigger->address + trigger->length;
|
2022-11-17 11:47:01 -06:00
|
|
|
|
ret = set_trigger(target, idx + 1, tdata1, tdata2, 0);
|
2022-11-09 16:48:31 -06:00
|
|
|
|
if (ret != ERROR_OK) {
|
2022-11-17 11:47:01 -06:00
|
|
|
|
/* Undo the setting of the previous trigger*/
|
|
|
|
|
set_trigger(target, idx, 0, 0, CSR_MCONTROL_MASKMAX(riscv_xlen(target)));
|
2022-11-09 16:48:31 -06:00
|
|
|
|
if (ret == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
|
|
|
|
|
goto MATCH_EQUAL; /* Fallback to EQUAL MATCH */
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
r->trigger_unique_id[idx] = trigger->unique_id;
|
|
|
|
|
r->trigger_unique_id[idx + 1] = trigger->unique_id;
|
|
|
|
|
return ERROR_OK;
|
2017-07-11 16:49:35 -05:00
|
|
|
|
|
2022-11-09 16:48:31 -06:00
|
|
|
|
MATCH_EQUAL:
|
|
|
|
|
ret = find_trigger(target, CSR_TDATA1_TYPE_MCONTROL, false, &idx);
|
|
|
|
|
if (ret != ERROR_OK)
|
|
|
|
|
return ret;
|
|
|
|
|
tdata1 = set_field(tdata1, CSR_MCONTROL_MATCH, CSR_MCONTROL_MATCH_EQUAL);
|
|
|
|
|
if (trigger->length == 1) {
|
|
|
|
|
tdata1 = set_field(tdata1, CSR_MCONTROL_SIZELO, CSR_MCONTROL_SIZELO_8BIT & 3);
|
|
|
|
|
tdata1 = set_field(tdata1, CSR_MCONTROL_SIZEHI, (CSR_MCONTROL_SIZELO_8BIT >> 2) & 3);
|
|
|
|
|
}
|
|
|
|
|
tdata1 = set_field(tdata1, CSR_MCONTROL_CHAIN, CSR_MCONTROL_CHAIN_DISABLED);
|
|
|
|
|
tdata2 = trigger->address;
|
2022-11-17 11:47:01 -06:00
|
|
|
|
ret = set_trigger(target, idx, tdata1, tdata2, CSR_MCONTROL_MASKMAX(riscv_xlen(target)));
|
2022-11-09 16:48:31 -06:00
|
|
|
|
if (ret != ERROR_OK)
|
|
|
|
|
return ret;
|
|
|
|
|
r->trigger_unique_id[idx] = trigger->unique_id;
|
2017-07-11 16:49:35 -05:00
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-18 17:57:17 -06:00
|
|
|
|
static int maybe_add_trigger_t4(struct target *target, bool vs, bool vu,
|
|
|
|
|
bool nmi, bool m, bool s, bool u, riscv_reg_t interrupts,
|
|
|
|
|
int unique_id)
|
|
|
|
|
{
|
2023-01-03 12:08:18 -06:00
|
|
|
|
int ret;
|
2022-11-18 17:57:17 -06:00
|
|
|
|
riscv_reg_t tdata1, tdata2;
|
|
|
|
|
|
|
|
|
|
RISCV_INFO(r);
|
|
|
|
|
|
|
|
|
|
tdata1 = 0;
|
|
|
|
|
tdata1 = set_field(tdata1, CSR_ITRIGGER_TYPE(riscv_xlen(target)), CSR_TDATA1_TYPE_ITRIGGER);
|
|
|
|
|
tdata1 = set_field(tdata1, CSR_ITRIGGER_DMODE(riscv_xlen(target)), 1);
|
|
|
|
|
tdata1 = set_field(tdata1, CSR_ITRIGGER_ACTION, CSR_ITRIGGER_ACTION_DEBUG_MODE);
|
|
|
|
|
tdata1 = set_field(tdata1, CSR_ITRIGGER_VS, vs);
|
|
|
|
|
tdata1 = set_field(tdata1, CSR_ITRIGGER_VU, vu);
|
|
|
|
|
tdata1 = set_field(tdata1, CSR_ITRIGGER_NMI, nmi);
|
|
|
|
|
tdata1 = set_field(tdata1, CSR_ITRIGGER_M, m);
|
|
|
|
|
tdata1 = set_field(tdata1, CSR_ITRIGGER_S, s);
|
|
|
|
|
tdata1 = set_field(tdata1, CSR_ITRIGGER_U, u);
|
|
|
|
|
|
|
|
|
|
tdata2 = interrupts;
|
|
|
|
|
|
2023-01-03 12:08:18 -06:00
|
|
|
|
unsigned int idx;
|
2022-11-18 17:57:17 -06:00
|
|
|
|
ret = find_trigger(target, CSR_TDATA1_TYPE_ITRIGGER, false, &idx);
|
|
|
|
|
if (ret != ERROR_OK)
|
|
|
|
|
return ret;
|
|
|
|
|
ret = set_trigger(target, idx, tdata1, tdata2, 0);
|
|
|
|
|
if (ret != ERROR_OK)
|
|
|
|
|
return ret;
|
|
|
|
|
r->trigger_unique_id[idx] = unique_id;
|
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-28 13:47:50 -06:00
|
|
|
|
static int maybe_add_trigger_t5(struct target *target, bool vs, bool vu,
|
|
|
|
|
bool m, bool s, bool u, riscv_reg_t exception_codes,
|
|
|
|
|
int unique_id)
|
|
|
|
|
{
|
2023-01-03 12:08:18 -06:00
|
|
|
|
int ret;
|
2022-12-28 13:47:50 -06:00
|
|
|
|
riscv_reg_t tdata1, tdata2;
|
|
|
|
|
|
|
|
|
|
RISCV_INFO(r);
|
|
|
|
|
|
|
|
|
|
tdata1 = 0;
|
|
|
|
|
tdata1 = set_field(tdata1, CSR_ETRIGGER_TYPE(riscv_xlen(target)), CSR_TDATA1_TYPE_ETRIGGER);
|
|
|
|
|
tdata1 = set_field(tdata1, CSR_ETRIGGER_DMODE(riscv_xlen(target)), 1);
|
|
|
|
|
tdata1 = set_field(tdata1, CSR_ETRIGGER_ACTION, CSR_ETRIGGER_ACTION_DEBUG_MODE);
|
|
|
|
|
tdata1 = set_field(tdata1, CSR_ETRIGGER_VS, vs);
|
|
|
|
|
tdata1 = set_field(tdata1, CSR_ETRIGGER_VU, vu);
|
|
|
|
|
tdata1 = set_field(tdata1, CSR_ETRIGGER_M, m);
|
|
|
|
|
tdata1 = set_field(tdata1, CSR_ETRIGGER_S, s);
|
|
|
|
|
tdata1 = set_field(tdata1, CSR_ETRIGGER_U, u);
|
|
|
|
|
|
|
|
|
|
tdata2 = exception_codes;
|
|
|
|
|
|
2023-01-03 12:08:18 -06:00
|
|
|
|
unsigned int idx;
|
2022-12-28 13:47:50 -06:00
|
|
|
|
ret = find_trigger(target, CSR_TDATA1_TYPE_ETRIGGER, false, &idx);
|
|
|
|
|
if (ret != ERROR_OK)
|
|
|
|
|
return ret;
|
|
|
|
|
ret = set_trigger(target, idx, tdata1, tdata2, 0);
|
|
|
|
|
if (ret != ERROR_OK)
|
|
|
|
|
return ret;
|
|
|
|
|
r->trigger_unique_id[idx] = unique_id;
|
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-09 16:48:31 -06:00
|
|
|
|
static int maybe_add_trigger_t6(struct target *target, struct trigger *trigger)
|
2021-07-23 16:42:05 -05:00
|
|
|
|
{
|
2023-01-03 12:08:18 -06:00
|
|
|
|
int ret;
|
2022-11-09 16:48:31 -06:00
|
|
|
|
riscv_reg_t tdata1, tdata2;
|
2021-07-23 16:42:05 -05:00
|
|
|
|
|
2022-11-09 16:48:31 -06:00
|
|
|
|
RISCV_INFO(r);
|
2021-07-23 16:42:05 -05:00
|
|
|
|
|
2022-11-09 16:48:31 -06:00
|
|
|
|
tdata1 = 0;
|
|
|
|
|
tdata1 = set_field(tdata1, CSR_MCONTROL6_TYPE(riscv_xlen(target)), 6);
|
|
|
|
|
tdata1 = set_field(tdata1, CSR_MCONTROL6_DMODE(riscv_xlen(target)), 1);
|
|
|
|
|
tdata1 = set_field(tdata1, CSR_MCONTROL6_ACTION, CSR_MCONTROL6_ACTION_DEBUG_MODE);
|
|
|
|
|
tdata1 = set_field(tdata1, CSR_MCONTROL6_M, 1);
|
|
|
|
|
tdata1 = set_field(tdata1, CSR_MCONTROL6_S, !!(r->misa & (1 << ('S' - 'A'))));
|
|
|
|
|
tdata1 = set_field(tdata1, CSR_MCONTROL6_U, !!(r->misa & (1 << ('U' - 'A'))));
|
|
|
|
|
tdata1 = set_field(tdata1, CSR_MCONTROL6_EXECUTE, trigger->execute);
|
|
|
|
|
tdata1 = set_field(tdata1, CSR_MCONTROL6_LOAD, trigger->read);
|
|
|
|
|
tdata1 = set_field(tdata1, CSR_MCONTROL6_STORE, trigger->write);
|
|
|
|
|
tdata1 = set_field(tdata1, CSR_MCONTROL6_SIZE, CSR_MCONTROL6_SIZE_ANY);
|
|
|
|
|
|
|
|
|
|
if (trigger->execute || trigger->length == 1)
|
|
|
|
|
goto MATCH_EQUAL;
|
|
|
|
|
if (!can_use_napot_match(trigger, &tdata2))
|
|
|
|
|
goto MATCH_GE_LT;
|
|
|
|
|
|
2023-01-03 12:08:18 -06:00
|
|
|
|
unsigned int idx;
|
2022-11-09 16:48:31 -06:00
|
|
|
|
ret = find_trigger(target, CSR_TDATA1_TYPE_MCONTROL6, false, &idx);
|
|
|
|
|
if (ret != ERROR_OK)
|
|
|
|
|
return ret;
|
|
|
|
|
tdata1 = set_field(tdata1, CSR_MCONTROL6_MATCH, CSR_MCONTROL6_MATCH_NAPOT);
|
|
|
|
|
tdata1 = set_field(tdata1, CSR_MCONTROL6_CHAIN, CSR_MCONTROL6_CHAIN_DISABLED);
|
2022-11-17 11:47:01 -06:00
|
|
|
|
ret = set_trigger(target, idx, tdata1, tdata2, 0);
|
2022-11-09 16:48:31 -06:00
|
|
|
|
if (ret != ERROR_OK) {
|
|
|
|
|
if (ret == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
|
|
|
|
|
goto MATCH_GE_LT; /* Fallback to chained MATCH using GT and LE */
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
r->trigger_unique_id[idx] = trigger->unique_id;
|
|
|
|
|
return ERROR_OK;
|
2021-07-23 16:42:05 -05:00
|
|
|
|
|
2022-11-09 16:48:31 -06:00
|
|
|
|
MATCH_GE_LT:
|
|
|
|
|
ret = find_trigger(target, CSR_TDATA1_TYPE_MCONTROL6, true, &idx);
|
|
|
|
|
if (ret != ERROR_OK)
|
|
|
|
|
return ret;
|
|
|
|
|
tdata1 = set_field(tdata1, CSR_MCONTROL6_MATCH, CSR_MCONTROL6_MATCH_GE);
|
|
|
|
|
tdata1 = set_field(tdata1, CSR_MCONTROL6_CHAIN, CSR_MCONTROL6_CHAIN_ENABLED);
|
|
|
|
|
tdata2 = trigger->address;
|
2022-11-17 11:47:01 -06:00
|
|
|
|
ret = set_trigger(target, idx, tdata1, tdata2, 0);
|
2022-11-09 16:48:31 -06:00
|
|
|
|
if (ret != ERROR_OK) {
|
|
|
|
|
if (ret == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
|
|
|
|
|
goto MATCH_EQUAL; /* Fallback to EQUAL MATCH */
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
tdata1 = set_field(tdata1, CSR_MCONTROL6_MATCH, CSR_MCONTROL6_MATCH_LT);
|
|
|
|
|
tdata1 = set_field(tdata1, CSR_MCONTROL6_CHAIN, CSR_MCONTROL6_CHAIN_DISABLED);
|
|
|
|
|
tdata2 = trigger->address + trigger->length;
|
2022-11-17 11:47:01 -06:00
|
|
|
|
ret = set_trigger(target, idx + 1, tdata1, tdata2, 0);
|
2022-11-09 16:48:31 -06:00
|
|
|
|
if (ret != ERROR_OK) {
|
2022-11-17 11:47:01 -06:00
|
|
|
|
set_trigger(target, idx, 0, 0, 0); /* Undo the setting of the previous trigger*/
|
2022-11-09 16:48:31 -06:00
|
|
|
|
if (ret == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
|
|
|
|
|
goto MATCH_EQUAL; /* Fallback to EQUAL MATCH */
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
r->trigger_unique_id[idx] = trigger->unique_id;
|
|
|
|
|
r->trigger_unique_id[idx + 1] = trigger->unique_id;
|
|
|
|
|
return ERROR_OK;
|
2021-07-23 16:42:05 -05:00
|
|
|
|
|
2022-11-09 16:48:31 -06:00
|
|
|
|
MATCH_EQUAL:
|
|
|
|
|
ret = find_trigger(target, CSR_TDATA1_TYPE_MCONTROL6, false, &idx);
|
|
|
|
|
if (ret != ERROR_OK)
|
|
|
|
|
return ret;
|
|
|
|
|
tdata1 = set_field(tdata1, CSR_MCONTROL6_MATCH, CSR_MCONTROL6_MATCH_EQUAL);
|
|
|
|
|
if (trigger->length == 1)
|
|
|
|
|
tdata1 = set_field(tdata1, CSR_MCONTROL6_SIZE, CSR_MCONTROL6_SIZE_8BIT);
|
|
|
|
|
tdata1 = set_field(tdata1, CSR_MCONTROL6_CHAIN, CSR_MCONTROL6_CHAIN_DISABLED);
|
|
|
|
|
tdata2 = trigger->address;
|
2022-11-17 11:47:01 -06:00
|
|
|
|
ret = set_trigger(target, idx, tdata1, tdata2, 0);
|
2022-11-09 16:48:31 -06:00
|
|
|
|
if (ret != ERROR_OK)
|
|
|
|
|
return ret;
|
|
|
|
|
r->trigger_unique_id[idx] = trigger->unique_id;
|
2021-07-23 16:42:05 -05:00
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2017-07-11 16:49:35 -05:00
|
|
|
|
static int add_trigger(struct target *target, struct trigger *trigger)
|
|
|
|
|
{
|
2022-11-09 16:48:31 -06:00
|
|
|
|
int ret;
|
|
|
|
|
riscv_reg_t tselect;
|
2017-07-11 16:49:35 -05:00
|
|
|
|
|
2018-05-22 14:32:01 -05:00
|
|
|
|
if (riscv_enumerate_triggers(target) != ERROR_OK)
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
|
2022-11-09 16:48:31 -06:00
|
|
|
|
int result = riscv_get_register(target, &tselect, GDB_REGNO_TSELECT);
|
|
|
|
|
if (result != ERROR_OK)
|
|
|
|
|
return result;
|
2017-07-11 16:49:35 -05:00
|
|
|
|
|
2022-11-09 16:48:31 -06:00
|
|
|
|
do {
|
|
|
|
|
ret = maybe_add_trigger_t1(target, trigger);
|
|
|
|
|
if (ret == ERROR_OK)
|
|
|
|
|
break;
|
|
|
|
|
ret = maybe_add_trigger_t2(target, trigger);
|
|
|
|
|
if (ret == ERROR_OK)
|
|
|
|
|
break;
|
|
|
|
|
ret = maybe_add_trigger_t6(target, trigger);
|
|
|
|
|
if (ret == ERROR_OK)
|
|
|
|
|
break;
|
|
|
|
|
} while (0);
|
2017-07-11 16:49:35 -05:00
|
|
|
|
|
2021-01-18 14:22:43 -06:00
|
|
|
|
riscv_set_register(target, GDB_REGNO_TSELECT, tselect);
|
2017-07-11 16:49:35 -05:00
|
|
|
|
|
2022-11-09 16:48:31 -06:00
|
|
|
|
return ret;
|
2016-09-17 15:21:34 -05:00
|
|
|
|
}
|
|
|
|
|
|
2020-09-14 10:00:59 -05:00
|
|
|
|
/**
|
|
|
|
|
* Write one memory item of given "size". Use memory access of given "access_size".
|
|
|
|
|
* Utilize read-modify-write, if needed.
|
|
|
|
|
* */
|
|
|
|
|
static int write_by_given_size(struct target *target, target_addr_t address,
|
|
|
|
|
uint32_t size, uint8_t *buffer, uint32_t access_size)
|
|
|
|
|
{
|
|
|
|
|
assert(size == 1 || size == 2 || size == 4 || size == 8);
|
|
|
|
|
assert(access_size == 1 || access_size == 2 || access_size == 4 || access_size == 8);
|
|
|
|
|
|
|
|
|
|
if (access_size <= size && address % access_size == 0)
|
|
|
|
|
/* Can do the memory access directly without a helper buffer. */
|
|
|
|
|
return target_write_memory(target, address, access_size, size / access_size, buffer);
|
|
|
|
|
|
2021-09-01 17:00:46 -05:00
|
|
|
|
unsigned int offset_head = address % access_size;
|
|
|
|
|
unsigned int n_blocks = ((size + offset_head) <= access_size) ? 1 : 2;
|
2020-09-14 10:00:59 -05:00
|
|
|
|
uint8_t helper_buf[n_blocks * access_size];
|
|
|
|
|
|
|
|
|
|
/* Read from memory */
|
|
|
|
|
if (target_read_memory(target, address - offset_head, access_size, n_blocks, helper_buf) != ERROR_OK)
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
|
|
|
|
|
/* Modify and write back */
|
|
|
|
|
memcpy(helper_buf + offset_head, buffer, size);
|
|
|
|
|
return target_write_memory(target, address - offset_head, access_size, n_blocks, helper_buf);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Read one memory item of given "size". Use memory access of given "access_size".
|
|
|
|
|
* Read larger section of memory and pick out the required portion, if needed.
|
|
|
|
|
* */
|
|
|
|
|
static int read_by_given_size(struct target *target, target_addr_t address,
|
|
|
|
|
uint32_t size, uint8_t *buffer, uint32_t access_size)
|
|
|
|
|
{
|
|
|
|
|
assert(size == 1 || size == 2 || size == 4 || size == 8);
|
|
|
|
|
assert(access_size == 1 || access_size == 2 || access_size == 4 || access_size == 8);
|
|
|
|
|
|
|
|
|
|
if (access_size <= size && address % access_size == 0)
|
|
|
|
|
/* Can do the memory access directly without a helper buffer. */
|
|
|
|
|
return target_read_memory(target, address, access_size, size / access_size, buffer);
|
|
|
|
|
|
2021-09-01 17:00:46 -05:00
|
|
|
|
unsigned int offset_head = address % access_size;
|
|
|
|
|
unsigned int n_blocks = ((size + offset_head) <= access_size) ? 1 : 2;
|
2020-09-14 10:00:59 -05:00
|
|
|
|
uint8_t helper_buf[n_blocks * access_size];
|
|
|
|
|
|
|
|
|
|
/* Read from memory */
|
|
|
|
|
if (target_read_memory(target, address - offset_head, access_size, n_blocks, helper_buf) != ERROR_OK)
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
|
|
|
|
|
/* Pick the requested portion from the buffer */
|
|
|
|
|
memcpy(buffer, helper_buf + offset_head, size);
|
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Write one memory item using any memory access size that will work.
|
|
|
|
|
* Utilize read-modify-write, if needed.
|
|
|
|
|
* */
|
2020-10-16 11:19:53 -05:00
|
|
|
|
int riscv_write_by_any_size(struct target *target, target_addr_t address, uint32_t size, uint8_t *buffer)
|
2020-09-14 10:00:59 -05:00
|
|
|
|
{
|
|
|
|
|
assert(size == 1 || size == 2 || size == 4 || size == 8);
|
|
|
|
|
|
|
|
|
|
/* Find access size that correspond to data size and the alignment. */
|
2021-09-01 17:00:46 -05:00
|
|
|
|
unsigned int preferred_size = size;
|
2020-09-14 10:00:59 -05:00
|
|
|
|
while (address % preferred_size != 0)
|
|
|
|
|
preferred_size /= 2;
|
|
|
|
|
|
|
|
|
|
/* First try the preferred (most natural) access size. */
|
|
|
|
|
if (write_by_given_size(target, address, size, buffer, preferred_size) == ERROR_OK)
|
|
|
|
|
return ERROR_OK;
|
|
|
|
|
|
|
|
|
|
/* On failure, try other access sizes.
|
|
|
|
|
Minimize the number of accesses by trying first the largest size. */
|
2021-09-01 17:00:46 -05:00
|
|
|
|
for (unsigned int access_size = 8; access_size > 0; access_size /= 2) {
|
2020-09-14 10:00:59 -05:00
|
|
|
|
if (access_size == preferred_size)
|
|
|
|
|
/* Already tried this size. */
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (write_by_given_size(target, address, size, buffer, access_size) == ERROR_OK)
|
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* No access attempt succeeded. */
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Read one memory item using any memory access size that will work.
|
|
|
|
|
* Read larger section of memory and pick out the required portion, if needed.
|
|
|
|
|
* */
|
2020-10-16 11:19:53 -05:00
|
|
|
|
int riscv_read_by_any_size(struct target *target, target_addr_t address, uint32_t size, uint8_t *buffer)
|
2020-09-14 10:00:59 -05:00
|
|
|
|
{
|
|
|
|
|
assert(size == 1 || size == 2 || size == 4 || size == 8);
|
|
|
|
|
|
|
|
|
|
/* Find access size that correspond to data size and the alignment. */
|
2021-09-01 17:00:46 -05:00
|
|
|
|
unsigned int preferred_size = size;
|
2020-09-14 10:00:59 -05:00
|
|
|
|
while (address % preferred_size != 0)
|
|
|
|
|
preferred_size /= 2;
|
|
|
|
|
|
|
|
|
|
/* First try the preferred (most natural) access size. */
|
|
|
|
|
if (read_by_given_size(target, address, size, buffer, preferred_size) == ERROR_OK)
|
2021-09-01 17:00:46 -05:00
|
|
|
|
return ERROR_OK;
|
2020-09-14 10:00:59 -05:00
|
|
|
|
|
|
|
|
|
/* On failure, try other access sizes.
|
|
|
|
|
Minimize the number of accesses by trying first the largest size. */
|
2021-09-01 17:00:46 -05:00
|
|
|
|
for (unsigned int access_size = 8; access_size > 0; access_size /= 2) {
|
2020-09-14 10:00:59 -05:00
|
|
|
|
if (access_size == preferred_size)
|
|
|
|
|
/* Already tried this size. */
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (read_by_given_size(target, address, size, buffer, access_size) == ERROR_OK)
|
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* No access attempt succeeded. */
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
|
|
|
|
|
2017-07-11 16:49:35 -05:00
|
|
|
|
int riscv_add_breakpoint(struct target *target, struct breakpoint *breakpoint)
|
|
|
|
|
{
|
2022-09-29 17:09:49 -05:00
|
|
|
|
LOG_TARGET_DEBUG(target, "@0x%" TARGET_PRIxADDR, breakpoint->address);
|
2018-11-05 13:34:44 -06:00
|
|
|
|
assert(breakpoint);
|
2017-07-11 16:49:35 -05:00
|
|
|
|
if (breakpoint->type == BKPT_SOFT) {
|
2018-11-07 15:53:52 -06:00
|
|
|
|
/** @todo check RVC for size/alignment */
|
2018-11-05 13:34:44 -06:00
|
|
|
|
if (!(breakpoint->length == 4 || breakpoint->length == 2)) {
|
|
|
|
|
LOG_ERROR("Invalid breakpoint length %d", breakpoint->length);
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (0 != (breakpoint->address % 2)) {
|
|
|
|
|
LOG_ERROR("Invalid breakpoint alignment for address 0x%" TARGET_PRIxADDR, breakpoint->address);
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-14 10:00:59 -05:00
|
|
|
|
/* Read the original instruction. */
|
2020-10-16 11:19:53 -05:00
|
|
|
|
if (riscv_read_by_any_size(
|
2020-09-14 10:00:59 -05:00
|
|
|
|
target, breakpoint->address, breakpoint->length, breakpoint->orig_instr) != ERROR_OK) {
|
2017-07-11 16:49:35 -05:00
|
|
|
|
LOG_ERROR("Failed to read original instruction at 0x%" TARGET_PRIxADDR,
|
|
|
|
|
breakpoint->address);
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-20 16:56:08 -06:00
|
|
|
|
uint8_t buff[4] = { 0 };
|
2018-11-05 13:34:44 -06:00
|
|
|
|
buf_set_u32(buff, 0, breakpoint->length * CHAR_BIT, breakpoint->length == 4 ? ebreak() : ebreak_c());
|
2020-09-14 10:00:59 -05:00
|
|
|
|
/* Write the ebreak instruction. */
|
2020-10-16 11:19:53 -05:00
|
|
|
|
if (riscv_write_by_any_size(target, breakpoint->address, breakpoint->length, buff) != ERROR_OK) {
|
2017-07-11 16:49:35 -05:00
|
|
|
|
LOG_ERROR("Failed to write %d-byte breakpoint instruction at 0x%"
|
|
|
|
|
TARGET_PRIxADDR, breakpoint->length, breakpoint->address);
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else if (breakpoint->type == BKPT_HARD) {
|
|
|
|
|
struct trigger trigger;
|
|
|
|
|
trigger_from_breakpoint(&trigger, breakpoint);
|
2018-11-05 13:34:44 -06:00
|
|
|
|
int const result = add_trigger(target, &trigger);
|
2017-12-22 16:35:38 -06:00
|
|
|
|
if (result != ERROR_OK)
|
2017-07-11 16:49:35 -05:00
|
|
|
|
return result;
|
|
|
|
|
} else {
|
|
|
|
|
LOG_INFO("OpenOCD only supports hardware and software breakpoints.");
|
|
|
|
|
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-13 04:21:18 -05:00
|
|
|
|
breakpoint->is_set = true;
|
2017-07-11 16:49:35 -05:00
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-18 17:57:17 -06:00
|
|
|
|
static int remove_trigger(struct target *target, int unique_id)
|
2017-07-11 16:49:35 -05:00
|
|
|
|
{
|
|
|
|
|
RISCV_INFO(r);
|
|
|
|
|
|
2018-05-22 14:32:01 -05:00
|
|
|
|
if (riscv_enumerate_triggers(target) != ERROR_OK)
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
|
2022-11-09 16:48:31 -06:00
|
|
|
|
riscv_reg_t tselect;
|
|
|
|
|
int result = riscv_get_register(target, &tselect, GDB_REGNO_TSELECT);
|
|
|
|
|
if (result != ERROR_OK)
|
|
|
|
|
return result;
|
|
|
|
|
|
|
|
|
|
bool done = false;
|
|
|
|
|
for (unsigned int i = 0; i < r->trigger_count; i++) {
|
2022-11-18 17:57:17 -06:00
|
|
|
|
if (r->trigger_unique_id[i] == unique_id) {
|
2022-11-09 16:48:31 -06:00
|
|
|
|
riscv_set_register(target, GDB_REGNO_TSELECT, i);
|
|
|
|
|
riscv_set_register(target, GDB_REGNO_TDATA1, 0);
|
|
|
|
|
r->trigger_unique_id[i] = -1;
|
|
|
|
|
LOG_TARGET_DEBUG(target, "Stop using resource %d for bp %d",
|
2022-11-18 17:57:17 -06:00
|
|
|
|
i, unique_id);
|
2022-11-09 16:48:31 -06:00
|
|
|
|
done = true;
|
|
|
|
|
}
|
2017-07-11 16:49:35 -05:00
|
|
|
|
}
|
2022-11-09 16:48:31 -06:00
|
|
|
|
if (!done) {
|
2017-07-11 16:49:35 -05:00
|
|
|
|
LOG_ERROR("Couldn't find the hardware resources used by hardware "
|
|
|
|
|
"trigger.");
|
2022-02-09 14:36:58 -06:00
|
|
|
|
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
2017-07-11 16:49:35 -05:00
|
|
|
|
}
|
2021-01-18 14:22:43 -06:00
|
|
|
|
|
|
|
|
|
riscv_set_register(target, GDB_REGNO_TSELECT, tselect);
|
2017-07-11 16:49:35 -05:00
|
|
|
|
|
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int riscv_remove_breakpoint(struct target *target,
|
2016-09-17 15:21:34 -05:00
|
|
|
|
struct breakpoint *breakpoint)
|
|
|
|
|
{
|
2017-07-11 16:49:35 -05:00
|
|
|
|
if (breakpoint->type == BKPT_SOFT) {
|
2020-09-14 10:00:59 -05:00
|
|
|
|
/* Write the original instruction. */
|
2020-10-16 11:19:53 -05:00
|
|
|
|
if (riscv_write_by_any_size(
|
2020-09-14 10:00:59 -05:00
|
|
|
|
target, breakpoint->address, breakpoint->length, breakpoint->orig_instr) != ERROR_OK) {
|
2017-07-11 16:49:35 -05:00
|
|
|
|
LOG_ERROR("Failed to restore instruction for %d-byte breakpoint at "
|
|
|
|
|
"0x%" TARGET_PRIxADDR, breakpoint->length, breakpoint->address);
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else if (breakpoint->type == BKPT_HARD) {
|
|
|
|
|
struct trigger trigger;
|
|
|
|
|
trigger_from_breakpoint(&trigger, breakpoint);
|
2022-11-18 17:57:17 -06:00
|
|
|
|
int result = remove_trigger(target, trigger.unique_id);
|
2017-12-22 16:35:38 -06:00
|
|
|
|
if (result != ERROR_OK)
|
2017-07-11 16:49:35 -05:00
|
|
|
|
return result;
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
LOG_INFO("OpenOCD only supports hardware and software breakpoints.");
|
|
|
|
|
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-13 04:21:18 -05:00
|
|
|
|
breakpoint->is_set = false;
|
2017-07-11 16:49:35 -05:00
|
|
|
|
|
|
|
|
|
return ERROR_OK;
|
2016-09-17 15:21:34 -05:00
|
|
|
|
}
|
|
|
|
|
|
2017-07-11 16:49:35 -05:00
|
|
|
|
static void trigger_from_watchpoint(struct trigger *trigger,
|
|
|
|
|
const struct watchpoint *watchpoint)
|
2016-09-17 15:21:34 -05:00
|
|
|
|
{
|
2017-07-11 16:49:35 -05:00
|
|
|
|
trigger->address = watchpoint->address;
|
|
|
|
|
trigger->length = watchpoint->length;
|
|
|
|
|
trigger->mask = watchpoint->mask;
|
|
|
|
|
trigger->value = watchpoint->value;
|
|
|
|
|
trigger->read = (watchpoint->rw == WPT_READ || watchpoint->rw == WPT_ACCESS);
|
|
|
|
|
trigger->write = (watchpoint->rw == WPT_WRITE || watchpoint->rw == WPT_ACCESS);
|
|
|
|
|
trigger->execute = false;
|
2017-12-22 16:35:38 -06:00
|
|
|
|
/* unique_id is unique across both breakpoints and watchpoints. */
|
2017-07-11 16:49:35 -05:00
|
|
|
|
trigger->unique_id = watchpoint->unique_id;
|
2016-09-17 15:21:34 -05:00
|
|
|
|
}
|
|
|
|
|
|
2017-07-11 16:49:35 -05:00
|
|
|
|
int riscv_add_watchpoint(struct target *target, struct watchpoint *watchpoint)
|
|
|
|
|
{
|
|
|
|
|
struct trigger trigger;
|
|
|
|
|
trigger_from_watchpoint(&trigger, watchpoint);
|
|
|
|
|
|
2019-01-25 17:31:42 -06:00
|
|
|
|
int result = add_trigger(target, &trigger);
|
|
|
|
|
if (result != ERROR_OK)
|
|
|
|
|
return result;
|
2021-06-13 04:21:18 -05:00
|
|
|
|
watchpoint->is_set = true;
|
2017-07-11 16:49:35 -05:00
|
|
|
|
|
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int riscv_remove_watchpoint(struct target *target,
|
2016-09-17 15:21:34 -05:00
|
|
|
|
struct watchpoint *watchpoint)
|
|
|
|
|
{
|
2019-01-24 17:15:18 -06:00
|
|
|
|
LOG_DEBUG("[%d] @0x%" TARGET_PRIxADDR, target->coreid, watchpoint->address);
|
|
|
|
|
|
2017-07-11 16:49:35 -05:00
|
|
|
|
struct trigger trigger;
|
|
|
|
|
trigger_from_watchpoint(&trigger, watchpoint);
|
|
|
|
|
|
2022-11-18 17:57:17 -06:00
|
|
|
|
int result = remove_trigger(target, trigger.unique_id);
|
2019-01-25 17:31:42 -06:00
|
|
|
|
if (result != ERROR_OK)
|
|
|
|
|
return result;
|
2021-06-13 04:21:18 -05:00
|
|
|
|
watchpoint->is_set = false;
|
2017-07-11 16:49:35 -05:00
|
|
|
|
|
|
|
|
|
return ERROR_OK;
|
2016-09-17 15:21:34 -05:00
|
|
|
|
}
|
|
|
|
|
|
2022-04-27 14:58:09 -05:00
|
|
|
|
/**
|
|
|
|
|
* Look at the trigger hit bits to find out which trigger is the reason we're
|
|
|
|
|
* halted. Sets *unique_id to the unique ID of that trigger. If *unique_id is
|
|
|
|
|
* ~0, no match was found.
|
|
|
|
|
*/
|
|
|
|
|
static int riscv_hit_trigger_hit_bit(struct target *target, uint32_t *unique_id)
|
|
|
|
|
{
|
|
|
|
|
RISCV_INFO(r);
|
|
|
|
|
|
|
|
|
|
riscv_reg_t tselect;
|
|
|
|
|
if (riscv_get_register(target, &tselect, GDB_REGNO_TSELECT) != ERROR_OK)
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
|
|
|
|
|
*unique_id = ~0;
|
|
|
|
|
for (unsigned int i = 0; i < r->trigger_count; i++) {
|
|
|
|
|
if (r->trigger_unique_id[i] == -1)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (riscv_set_register(target, GDB_REGNO_TSELECT, i) != ERROR_OK)
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
|
|
|
|
|
uint64_t tdata1;
|
|
|
|
|
if (riscv_get_register(target, &tdata1, GDB_REGNO_TDATA1) != ERROR_OK)
|
|
|
|
|
return ERROR_FAIL;
|
2022-05-25 12:08:43 -05:00
|
|
|
|
int type = get_field(tdata1, CSR_TDATA1_TYPE(riscv_xlen(target)));
|
2022-04-27 14:58:09 -05:00
|
|
|
|
|
|
|
|
|
uint64_t hit_mask = 0;
|
|
|
|
|
switch (type) {
|
2022-12-27 14:53:52 -06:00
|
|
|
|
case CSR_TDATA1_TYPE_LEGACY:
|
2022-04-27 14:58:09 -05:00
|
|
|
|
/* Doesn't support hit bit. */
|
|
|
|
|
break;
|
2022-12-27 14:53:52 -06:00
|
|
|
|
case CSR_TDATA1_TYPE_MCONTROL:
|
2022-04-27 14:58:09 -05:00
|
|
|
|
hit_mask = CSR_MCONTROL_HIT;
|
|
|
|
|
break;
|
2022-12-27 14:53:52 -06:00
|
|
|
|
case CSR_TDATA1_TYPE_MCONTROL6:
|
2022-04-27 14:58:09 -05:00
|
|
|
|
hit_mask = CSR_MCONTROL6_HIT;
|
|
|
|
|
break;
|
2022-11-18 17:57:17 -06:00
|
|
|
|
case CSR_TDATA1_TYPE_ITRIGGER:
|
|
|
|
|
hit_mask = CSR_ITRIGGER_HIT(riscv_xlen(target));
|
|
|
|
|
break;
|
2022-12-28 13:47:50 -06:00
|
|
|
|
case CSR_TDATA1_TYPE_ETRIGGER:
|
|
|
|
|
hit_mask = CSR_ETRIGGER_HIT(riscv_xlen(target));
|
|
|
|
|
break;
|
2022-04-27 14:58:09 -05:00
|
|
|
|
default:
|
|
|
|
|
LOG_DEBUG("trigger %d has unknown type %d", i, type);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Note: If we ever use chained triggers, then this logic needs
|
|
|
|
|
* to be changed to ignore triggers that are not the last one in
|
|
|
|
|
* the chain. */
|
|
|
|
|
if (tdata1 & hit_mask) {
|
|
|
|
|
LOG_DEBUG("Trigger %d (unique_id=%d) has hit bit set.", i, r->trigger_unique_id[i]);
|
|
|
|
|
if (riscv_set_register(target, GDB_REGNO_TDATA1, tdata1 & ~hit_mask) != ERROR_OK)
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
|
|
|
|
|
*unique_id = r->trigger_unique_id[i];
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (riscv_set_register(target, GDB_REGNO_TSELECT, tselect) != ERROR_OK)
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
|
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2018-08-27 14:42:34 -05:00
|
|
|
|
/* Sets *hit_watchpoint to the first watchpoint identified as causing the
|
|
|
|
|
* current halt.
|
|
|
|
|
*
|
|
|
|
|
* The GDB server uses this information to tell GDB what data address has
|
|
|
|
|
* been hit, which enables GDB to print the hit variable along with its old
|
|
|
|
|
* and new value. */
|
|
|
|
|
int riscv_hit_watchpoint(struct target *target, struct watchpoint **hit_watchpoint)
|
|
|
|
|
{
|
2022-04-27 15:02:00 -05:00
|
|
|
|
RISCV_INFO(r);
|
2018-08-27 14:42:34 -05:00
|
|
|
|
|
2022-09-29 17:09:49 -05:00
|
|
|
|
LOG_TARGET_DEBUG(target, "Hit Watchpoint");
|
2018-08-27 14:42:34 -05:00
|
|
|
|
|
2022-04-27 15:02:00 -05:00
|
|
|
|
/* If we identified which trigger caused the halt earlier, then just use
|
|
|
|
|
* that. */
|
|
|
|
|
for (struct watchpoint *wp = target->watchpoints; wp; wp = wp->next) {
|
|
|
|
|
if (wp->unique_id == r->trigger_hit) {
|
|
|
|
|
*hit_watchpoint = wp;
|
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-08-27 14:42:34 -05:00
|
|
|
|
riscv_reg_t dpc;
|
|
|
|
|
riscv_get_register(target, &dpc, GDB_REGNO_DPC);
|
|
|
|
|
const uint8_t length = 4;
|
|
|
|
|
LOG_DEBUG("dpc is 0x%" PRIx64, dpc);
|
|
|
|
|
|
|
|
|
|
/* fetch the instruction at dpc */
|
|
|
|
|
uint8_t buffer[length];
|
|
|
|
|
if (target_read_buffer(target, dpc, length, buffer) != ERROR_OK) {
|
|
|
|
|
LOG_ERROR("Failed to read instruction at dpc 0x%" PRIx64, dpc);
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint32_t instruction = 0;
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < length; i++) {
|
|
|
|
|
LOG_DEBUG("Next byte is %x", buffer[i]);
|
|
|
|
|
instruction += (buffer[i] << 8 * i);
|
|
|
|
|
}
|
|
|
|
|
LOG_DEBUG("Full instruction is %x", instruction);
|
|
|
|
|
|
|
|
|
|
/* find out which memory address is accessed by the instruction at dpc */
|
|
|
|
|
/* opcode is first 7 bits of the instruction */
|
|
|
|
|
uint8_t opcode = instruction & 0x7F;
|
|
|
|
|
uint32_t rs1;
|
|
|
|
|
int16_t imm;
|
|
|
|
|
riscv_reg_t mem_addr;
|
|
|
|
|
|
|
|
|
|
if (opcode == MATCH_LB || opcode == MATCH_SB) {
|
|
|
|
|
rs1 = (instruction & 0xf8000) >> 15;
|
|
|
|
|
riscv_get_register(target, &mem_addr, rs1);
|
|
|
|
|
|
|
|
|
|
if (opcode == MATCH_SB) {
|
|
|
|
|
LOG_DEBUG("%x is store instruction", instruction);
|
|
|
|
|
imm = ((instruction & 0xf80) >> 7) | ((instruction & 0xfe000000) >> 20);
|
|
|
|
|
} else {
|
|
|
|
|
LOG_DEBUG("%x is load instruction", instruction);
|
|
|
|
|
imm = (instruction & 0xfff00000) >> 20;
|
|
|
|
|
}
|
|
|
|
|
/* sign extend 12-bit imm to 16-bits */
|
|
|
|
|
if (imm & (1 << 11))
|
|
|
|
|
imm |= 0xf000;
|
|
|
|
|
mem_addr += imm;
|
|
|
|
|
LOG_DEBUG("memory address=0x%" PRIx64, mem_addr);
|
|
|
|
|
} else {
|
|
|
|
|
LOG_DEBUG("%x is not a RV32I load or store", instruction);
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-27 14:46:09 -05:00
|
|
|
|
struct watchpoint *wp = target->watchpoints;
|
2018-08-27 14:42:34 -05:00
|
|
|
|
while (wp) {
|
|
|
|
|
/*TODO support length/mask */
|
|
|
|
|
if (wp->address == mem_addr) {
|
|
|
|
|
*hit_watchpoint = wp;
|
|
|
|
|
LOG_DEBUG("Hit address=%" TARGET_PRIxADDR, wp->address);
|
2018-10-24 15:02:44 -05:00
|
|
|
|
return ERROR_OK;
|
2018-08-27 14:42:34 -05:00
|
|
|
|
}
|
|
|
|
|
wp = wp->next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* No match found - either we hit a watchpoint caused by an instruction that
|
|
|
|
|
* this function does not yet disassemble, or we hit a breakpoint.
|
|
|
|
|
*
|
|
|
|
|
* OpenOCD will behave as if this function had never been implemented i.e.
|
|
|
|
|
* report the halt to GDB with no address information. */
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-11 12:40:43 -05:00
|
|
|
|
static int oldriscv_step(struct target *target, int current, uint32_t address,
|
2016-06-10 12:24:02 -05:00
|
|
|
|
int handle_breakpoints)
|
|
|
|
|
{
|
2017-02-05 20:00:05 -06:00
|
|
|
|
struct target_type *tt = get_target_type(target);
|
|
|
|
|
return tt->step(target, current, address, handle_breakpoints);
|
2016-06-10 12:24:02 -05:00
|
|
|
|
}
|
|
|
|
|
|
2019-05-06 11:32:02 -05:00
|
|
|
|
static int old_or_new_riscv_step(struct target *target, int current,
|
|
|
|
|
target_addr_t address, int handle_breakpoints)
|
|
|
|
|
{
|
2017-05-11 12:40:43 -05:00
|
|
|
|
RISCV_INFO(r);
|
2018-02-07 14:16:22 -06:00
|
|
|
|
LOG_DEBUG("handle_breakpoints=%d", handle_breakpoints);
|
2022-11-10 12:27:04 -06:00
|
|
|
|
if (!r->get_hart_state)
|
2017-05-11 12:40:43 -05:00
|
|
|
|
return oldriscv_step(target, current, address, handle_breakpoints);
|
|
|
|
|
else
|
|
|
|
|
return riscv_openocd_step(target, current, address, handle_breakpoints);
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-13 16:55:32 -05:00
|
|
|
|
static int riscv_examine(struct target *target)
|
2016-05-13 15:04:49 -05:00
|
|
|
|
{
|
2021-10-21 19:08:49 -05:00
|
|
|
|
LOG_DEBUG("[%s]", target_name(target));
|
2016-05-13 15:04:49 -05:00
|
|
|
|
if (target_was_examined(target)) {
|
2017-08-26 18:53:00 -05:00
|
|
|
|
LOG_DEBUG("Target was already examined.");
|
2016-05-13 15:04:49 -05:00
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2017-12-22 16:35:38 -06:00
|
|
|
|
/* Don't need to select dbus, since the first thing we do is read dtmcontrol. */
|
2016-05-31 14:28:20 -05:00
|
|
|
|
|
2020-09-17 15:20:12 -05:00
|
|
|
|
RISCV_INFO(info);
|
2016-09-27 10:45:51 -05:00
|
|
|
|
uint32_t dtmcontrol = dtmcontrol_scan(target, 0);
|
|
|
|
|
LOG_DEBUG("dtmcontrol=0x%x", dtmcontrol);
|
2017-02-05 20:00:05 -06:00
|
|
|
|
info->dtm_version = get_field(dtmcontrol, DTMCONTROL_VERSION);
|
|
|
|
|
LOG_DEBUG(" version=0x%x", info->dtm_version);
|
2016-06-03 01:53:45 -05:00
|
|
|
|
|
2017-02-05 20:00:05 -06:00
|
|
|
|
struct target_type *tt = get_target_type(target);
|
2021-07-03 11:51:20 -05:00
|
|
|
|
if (!tt)
|
2016-09-17 15:21:34 -05:00
|
|
|
|
return ERROR_FAIL;
|
2016-09-29 12:23:46 -05:00
|
|
|
|
|
2017-02-05 20:00:05 -06:00
|
|
|
|
int result = tt->init_target(info->cmd_ctx, target);
|
|
|
|
|
if (result != ERROR_OK)
|
2016-10-14 14:40:52 -05:00
|
|
|
|
return result;
|
2016-10-27 15:00:26 -05:00
|
|
|
|
|
2017-02-05 20:00:05 -06:00
|
|
|
|
return tt->examine(target);
|
2016-05-13 16:55:32 -05:00
|
|
|
|
}
|
|
|
|
|
|
2017-03-24 20:21:56 -05:00
|
|
|
|
static int oldriscv_poll(struct target *target)
|
2016-09-17 15:21:34 -05:00
|
|
|
|
{
|
2017-02-05 20:00:05 -06:00
|
|
|
|
struct target_type *tt = get_target_type(target);
|
|
|
|
|
return tt->poll(target);
|
2016-09-17 15:21:34 -05:00
|
|
|
|
}
|
|
|
|
|
|
2017-04-26 17:16:39 -05:00
|
|
|
|
static int old_or_new_riscv_poll(struct target *target)
|
|
|
|
|
{
|
|
|
|
|
RISCV_INFO(r);
|
2022-11-10 12:27:04 -06:00
|
|
|
|
if (!r->get_hart_state)
|
2017-04-26 17:16:39 -05:00
|
|
|
|
return oldriscv_poll(target);
|
|
|
|
|
else
|
|
|
|
|
return riscv_openocd_poll(target);
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-23 17:07:38 -05:00
|
|
|
|
int riscv_flush_registers(struct target *target)
|
|
|
|
|
{
|
|
|
|
|
RISCV_INFO(r);
|
|
|
|
|
|
|
|
|
|
if (!target->reg_cache)
|
|
|
|
|
return ERROR_OK;
|
|
|
|
|
|
2021-10-29 12:43:22 -05:00
|
|
|
|
LOG_DEBUG("[%s]", target_name(target));
|
|
|
|
|
|
2021-09-23 17:07:38 -05:00
|
|
|
|
for (uint32_t number = 0; number < target->reg_cache->num_regs; number++) {
|
|
|
|
|
struct reg *reg = &target->reg_cache->reg_list[number];
|
|
|
|
|
if (reg->valid && reg->dirty) {
|
|
|
|
|
uint64_t value = buf_get_u64(reg->value, 0, reg->size);
|
|
|
|
|
LOG_DEBUG("[%s] %s is dirty; write back 0x%" PRIx64,
|
|
|
|
|
target_name(target), reg->name, value);
|
|
|
|
|
int result = r->set_register(target, number, value);
|
|
|
|
|
if (result != ERROR_OK)
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
reg->dirty = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-24 12:20:15 -06:00
|
|
|
|
/* Convert: RISC-V hart's halt reason --> OpenOCD's generic debug reason */
|
|
|
|
|
int set_debug_reason(struct target *target, enum riscv_halt_reason halt_reason)
|
|
|
|
|
{
|
2022-04-27 15:00:47 -05:00
|
|
|
|
RISCV_INFO(r);
|
|
|
|
|
r->trigger_hit = -1;
|
2021-11-24 12:20:15 -06:00
|
|
|
|
switch (halt_reason) {
|
2022-11-21 15:01:03 -06:00
|
|
|
|
case RISCV_HALT_EBREAK:
|
2021-11-24 12:20:15 -06:00
|
|
|
|
target->debug_reason = DBG_REASON_BREAKPOINT;
|
|
|
|
|
break;
|
|
|
|
|
case RISCV_HALT_TRIGGER:
|
2022-04-27 15:00:47 -05:00
|
|
|
|
if (riscv_hit_trigger_hit_bit(target, &r->trigger_hit) != ERROR_OK)
|
|
|
|
|
return ERROR_FAIL;
|
2021-11-24 12:20:15 -06:00
|
|
|
|
target->debug_reason = DBG_REASON_WATCHPOINT;
|
2022-04-27 15:01:14 -05:00
|
|
|
|
/* Check if we hit a hardware breakpoint. */
|
|
|
|
|
for (struct breakpoint *bp = target->breakpoints; bp; bp = bp->next) {
|
|
|
|
|
if (bp->unique_id == r->trigger_hit)
|
|
|
|
|
target->debug_reason = DBG_REASON_BREAKPOINT;
|
|
|
|
|
}
|
2021-11-24 12:20:15 -06:00
|
|
|
|
break;
|
|
|
|
|
case RISCV_HALT_INTERRUPT:
|
|
|
|
|
case RISCV_HALT_GROUP:
|
|
|
|
|
target->debug_reason = DBG_REASON_DBGRQ;
|
|
|
|
|
break;
|
|
|
|
|
case RISCV_HALT_SINGLESTEP:
|
|
|
|
|
target->debug_reason = DBG_REASON_SINGLESTEP;
|
|
|
|
|
break;
|
|
|
|
|
case RISCV_HALT_UNKNOWN:
|
|
|
|
|
target->debug_reason = DBG_REASON_UNDEFINED;
|
|
|
|
|
break;
|
|
|
|
|
case RISCV_HALT_ERROR:
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
|
|
|
|
LOG_DEBUG("[%s] debug_reason=%d", target_name(target), target->debug_reason);
|
|
|
|
|
|
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-09 13:32:04 -05:00
|
|
|
|
int halt_prep(struct target *target)
|
2016-05-23 18:27:43 -05:00
|
|
|
|
{
|
2017-05-11 12:40:43 -05:00
|
|
|
|
RISCV_INFO(r);
|
2019-05-09 13:32:04 -05:00
|
|
|
|
|
2021-01-18 14:22:43 -06:00
|
|
|
|
LOG_DEBUG("[%s] prep hart, debug_reason=%d", target_name(target),
|
|
|
|
|
target->debug_reason);
|
2022-11-10 12:27:04 -06:00
|
|
|
|
r->prepped = false;
|
|
|
|
|
if (target->state == TARGET_HALTED) {
|
|
|
|
|
LOG_TARGET_DEBUG(target, "Hart is already halted.");
|
|
|
|
|
} else if (target->state == TARGET_UNAVAILABLE) {
|
|
|
|
|
LOG_TARGET_DEBUG(target, "Hart is unavailable.");
|
2021-01-18 14:22:43 -06:00
|
|
|
|
} else {
|
|
|
|
|
if (r->halt_prep(target) != ERROR_OK)
|
2019-05-09 13:32:04 -05:00
|
|
|
|
return ERROR_FAIL;
|
2021-01-18 14:22:43 -06:00
|
|
|
|
r->prepped = true;
|
2019-05-09 13:32:04 -05:00
|
|
|
|
}
|
2021-01-18 14:22:43 -06:00
|
|
|
|
|
2019-05-09 13:32:04 -05:00
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int riscv_halt_go_all_harts(struct target *target)
|
|
|
|
|
{
|
|
|
|
|
RISCV_INFO(r);
|
|
|
|
|
|
2022-11-10 12:27:04 -06:00
|
|
|
|
enum riscv_hart_state state;
|
|
|
|
|
if (riscv_get_hart_state(target, &state) != ERROR_OK)
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
if (state == RISCV_STATE_HALTED) {
|
2021-01-18 14:22:43 -06:00
|
|
|
|
LOG_DEBUG("[%s] Hart is already halted.", target_name(target));
|
|
|
|
|
} else {
|
|
|
|
|
if (r->halt_go(target) != ERROR_OK)
|
2019-05-09 13:32:04 -05:00
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
|
2021-10-29 12:43:22 -05:00
|
|
|
|
riscv_invalidate_register_cache(target);
|
|
|
|
|
}
|
2019-05-09 13:32:04 -05:00
|
|
|
|
|
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int halt_go(struct target *target)
|
|
|
|
|
{
|
|
|
|
|
riscv_info_t *r = riscv_info(target);
|
|
|
|
|
int result;
|
2022-11-10 12:27:04 -06:00
|
|
|
|
if (!r->get_hart_state) {
|
2019-05-09 13:32:04 -05:00
|
|
|
|
struct target_type *tt = get_target_type(target);
|
|
|
|
|
result = tt->halt(target);
|
|
|
|
|
} else {
|
|
|
|
|
result = riscv_halt_go_all_harts(target);
|
|
|
|
|
}
|
|
|
|
|
if (target->debug_reason == DBG_REASON_NOTHALTED)
|
|
|
|
|
target->debug_reason = DBG_REASON_DBGRQ;
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int halt_finish(struct target *target)
|
|
|
|
|
{
|
|
|
|
|
return target_call_event_callbacks(target, TARGET_EVENT_HALTED);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int riscv_halt(struct target *target)
|
|
|
|
|
{
|
|
|
|
|
RISCV_INFO(r);
|
|
|
|
|
|
2022-11-10 12:27:04 -06:00
|
|
|
|
if (!r->get_hart_state) {
|
2019-05-09 13:32:04 -05:00
|
|
|
|
struct target_type *tt = get_target_type(target);
|
|
|
|
|
return tt->halt(target);
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-29 17:09:49 -05:00
|
|
|
|
LOG_TARGET_DEBUG(target, "halting all harts");
|
2019-05-09 13:32:04 -05:00
|
|
|
|
|
|
|
|
|
int result = ERROR_OK;
|
|
|
|
|
if (target->smp) {
|
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 commit
615709d14049 ("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
Commit 39650e2273bc ("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 commit 861e75f54efb ("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: f5898bd93ff8 (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
Commit 6541233aa78d ("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: 6541233aa78d ("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
Commit 6541233aa78d ("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: 6541233aa78d ("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: 13cd75b6ecfd (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>
2022-03-03 12:03:55 -06:00
|
|
|
|
struct target_list *tlist;
|
|
|
|
|
foreach_smp_target(tlist, target->smp_targets) {
|
2019-05-09 13:32:04 -05:00
|
|
|
|
struct target *t = tlist->target;
|
|
|
|
|
if (halt_prep(t) != ERROR_OK)
|
|
|
|
|
result = ERROR_FAIL;
|
|
|
|
|
}
|
|
|
|
|
|
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 commit
615709d14049 ("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
Commit 39650e2273bc ("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 commit 861e75f54efb ("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: f5898bd93ff8 (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
Commit 6541233aa78d ("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: 6541233aa78d ("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
Commit 6541233aa78d ("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: 6541233aa78d ("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: 13cd75b6ecfd (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>
2022-03-03 12:03:55 -06:00
|
|
|
|
foreach_smp_target(tlist, target->smp_targets) {
|
2019-05-09 13:32:04 -05:00
|
|
|
|
struct target *t = tlist->target;
|
|
|
|
|
riscv_info_t *i = riscv_info(t);
|
|
|
|
|
if (i->prepped) {
|
|
|
|
|
if (halt_go(t) != ERROR_OK)
|
|
|
|
|
result = ERROR_FAIL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
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 commit
615709d14049 ("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
Commit 39650e2273bc ("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 commit 861e75f54efb ("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: f5898bd93ff8 (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
Commit 6541233aa78d ("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: 6541233aa78d ("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
Commit 6541233aa78d ("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: 6541233aa78d ("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: 13cd75b6ecfd (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>
2022-03-03 12:03:55 -06:00
|
|
|
|
foreach_smp_target(tlist, target->smp_targets) {
|
2019-05-09 13:32:04 -05:00
|
|
|
|
struct target *t = tlist->target;
|
|
|
|
|
if (halt_finish(t) != ERROR_OK)
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
if (halt_prep(target) != ERROR_OK)
|
|
|
|
|
result = ERROR_FAIL;
|
|
|
|
|
if (halt_go(target) != ERROR_OK)
|
|
|
|
|
result = ERROR_FAIL;
|
|
|
|
|
if (halt_finish(target) != ERROR_OK)
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
2016-05-23 18:27:43 -05:00
|
|
|
|
}
|
|
|
|
|
|
2017-09-19 17:04:00 -05:00
|
|
|
|
static int riscv_assert_reset(struct target *target)
|
2016-05-19 15:33:47 -05:00
|
|
|
|
{
|
2019-01-25 15:11:06 -06:00
|
|
|
|
LOG_DEBUG("[%d]", target->coreid);
|
2017-02-05 20:00:05 -06:00
|
|
|
|
struct target_type *tt = get_target_type(target);
|
2019-01-25 15:11:06 -06:00
|
|
|
|
riscv_invalidate_register_cache(target);
|
2017-02-05 20:00:05 -06:00
|
|
|
|
return tt->assert_reset(target);
|
2016-05-19 15:33:47 -05:00
|
|
|
|
}
|
|
|
|
|
|
2017-09-19 17:04:00 -05:00
|
|
|
|
static int riscv_deassert_reset(struct target *target)
|
2016-05-19 15:33:47 -05:00
|
|
|
|
{
|
2019-01-25 15:11:06 -06:00
|
|
|
|
LOG_DEBUG("[%d]", target->coreid);
|
2017-02-05 20:00:05 -06:00
|
|
|
|
struct target_type *tt = get_target_type(target);
|
|
|
|
|
return tt->deassert_reset(target);
|
2016-05-19 15:33:47 -05:00
|
|
|
|
}
|
|
|
|
|
|
2020-06-18 16:47:42 -05:00
|
|
|
|
/* state must be riscv_reg_t state[RISCV_MAX_HWBPS] = {0}; */
|
|
|
|
|
static int disable_triggers(struct target *target, riscv_reg_t *state)
|
2017-05-11 12:40:43 -05:00
|
|
|
|
{
|
2019-04-03 14:13:09 -05:00
|
|
|
|
RISCV_INFO(r);
|
|
|
|
|
|
2020-06-18 16:47:42 -05:00
|
|
|
|
LOG_DEBUG("deal with triggers");
|
2019-04-03 14:13:09 -05:00
|
|
|
|
|
2020-06-18 16:47:42 -05:00
|
|
|
|
if (riscv_enumerate_triggers(target) != ERROR_OK)
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
|
|
|
|
|
if (r->manual_hwbp_set) {
|
|
|
|
|
/* Look at every trigger that may have been set. */
|
|
|
|
|
riscv_reg_t tselect;
|
|
|
|
|
if (riscv_get_register(target, &tselect, GDB_REGNO_TSELECT) != ERROR_OK)
|
|
|
|
|
return ERROR_FAIL;
|
2021-09-01 17:00:46 -05:00
|
|
|
|
for (unsigned int t = 0; t < r->trigger_count; t++) {
|
2020-06-18 16:47:42 -05:00
|
|
|
|
if (riscv_set_register(target, GDB_REGNO_TSELECT, t) != ERROR_OK)
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
riscv_reg_t tdata1;
|
|
|
|
|
if (riscv_get_register(target, &tdata1, GDB_REGNO_TDATA1) != ERROR_OK)
|
|
|
|
|
return ERROR_FAIL;
|
2022-05-25 12:08:43 -05:00
|
|
|
|
if (tdata1 & CSR_TDATA1_DMODE(riscv_xlen(target))) {
|
2020-06-18 16:47:42 -05:00
|
|
|
|
state[t] = tdata1;
|
|
|
|
|
if (riscv_set_register(target, GDB_REGNO_TDATA1, 0) != ERROR_OK)
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (riscv_set_register(target, GDB_REGNO_TSELECT, tselect) != ERROR_OK)
|
|
|
|
|
return ERROR_FAIL;
|
2019-04-03 14:13:09 -05:00
|
|
|
|
|
2020-06-18 16:47:42 -05:00
|
|
|
|
} else {
|
|
|
|
|
/* Just go through the triggers we manage. */
|
|
|
|
|
struct watchpoint *watchpoint = target->watchpoints;
|
2019-04-03 14:13:09 -05:00
|
|
|
|
int i = 0;
|
2020-06-18 16:47:42 -05:00
|
|
|
|
while (watchpoint) {
|
2021-06-13 04:21:18 -05:00
|
|
|
|
LOG_DEBUG("watchpoint %d: set=%d", i, watchpoint->is_set);
|
|
|
|
|
state[i] = watchpoint->is_set;
|
|
|
|
|
if (watchpoint->is_set) {
|
2020-06-18 16:47:42 -05:00
|
|
|
|
if (riscv_remove_watchpoint(target, watchpoint) != ERROR_OK)
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
2019-04-03 14:13:09 -05:00
|
|
|
|
watchpoint = watchpoint->next;
|
|
|
|
|
i++;
|
|
|
|
|
}
|
2020-06-18 16:47:42 -05:00
|
|
|
|
}
|
2019-04-03 14:13:09 -05:00
|
|
|
|
|
2020-06-18 16:47:42 -05:00
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int enable_triggers(struct target *target, riscv_reg_t *state)
|
|
|
|
|
{
|
|
|
|
|
RISCV_INFO(r);
|
|
|
|
|
|
|
|
|
|
if (r->manual_hwbp_set) {
|
|
|
|
|
/* Look at every trigger that may have been set. */
|
|
|
|
|
riscv_reg_t tselect;
|
|
|
|
|
if (riscv_get_register(target, &tselect, GDB_REGNO_TSELECT) != ERROR_OK)
|
|
|
|
|
return ERROR_FAIL;
|
2021-09-01 17:00:46 -05:00
|
|
|
|
for (unsigned int t = 0; t < r->trigger_count; t++) {
|
2020-06-18 16:47:42 -05:00
|
|
|
|
if (state[t] != 0) {
|
|
|
|
|
if (riscv_set_register(target, GDB_REGNO_TSELECT, t) != ERROR_OK)
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
if (riscv_set_register(target, GDB_REGNO_TDATA1, state[t]) != ERROR_OK)
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (riscv_set_register(target, GDB_REGNO_TSELECT, tselect) != ERROR_OK)
|
|
|
|
|
return ERROR_FAIL;
|
2019-04-03 14:13:09 -05:00
|
|
|
|
|
2020-06-18 16:47:42 -05:00
|
|
|
|
} else {
|
|
|
|
|
struct watchpoint *watchpoint = target->watchpoints;
|
|
|
|
|
int i = 0;
|
2019-04-03 14:13:09 -05:00
|
|
|
|
while (watchpoint) {
|
2020-06-18 16:47:42 -05:00
|
|
|
|
LOG_DEBUG("watchpoint %d: cleared=%" PRId64, i, state[i]);
|
|
|
|
|
if (state[i]) {
|
|
|
|
|
if (riscv_add_watchpoint(target, watchpoint) != ERROR_OK)
|
|
|
|
|
return ERROR_FAIL;
|
2019-04-03 14:13:09 -05:00
|
|
|
|
}
|
|
|
|
|
watchpoint = watchpoint->next;
|
|
|
|
|
i++;
|
|
|
|
|
}
|
2020-06-18 16:47:42 -05:00
|
|
|
|
}
|
2019-04-03 14:13:09 -05:00
|
|
|
|
|
2020-06-18 16:47:42 -05:00
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get everything ready to resume.
|
|
|
|
|
*/
|
|
|
|
|
static int resume_prep(struct target *target, int current,
|
|
|
|
|
target_addr_t address, int handle_breakpoints, int debug_execution)
|
|
|
|
|
{
|
|
|
|
|
RISCV_INFO(r);
|
2022-09-29 17:09:49 -05:00
|
|
|
|
LOG_TARGET_DEBUG(target, "target->state=%d", target->state);
|
2020-06-18 16:47:42 -05:00
|
|
|
|
|
|
|
|
|
if (!current)
|
|
|
|
|
riscv_set_register(target, GDB_REGNO_PC, address);
|
|
|
|
|
|
|
|
|
|
if (target->debug_reason == DBG_REASON_WATCHPOINT) {
|
|
|
|
|
/* To be able to run off a trigger, disable all the triggers, step, and
|
|
|
|
|
* then resume as usual. */
|
|
|
|
|
riscv_reg_t trigger_state[RISCV_MAX_HWBPS] = {0};
|
|
|
|
|
|
|
|
|
|
if (disable_triggers(target, trigger_state) != ERROR_OK)
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
|
|
|
|
|
if (old_or_new_riscv_step(target, true, 0, false) != ERROR_OK)
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
|
|
|
|
|
if (enable_triggers(target, trigger_state) != ERROR_OK)
|
|
|
|
|
return ERROR_FAIL;
|
2019-04-03 14:13:09 -05:00
|
|
|
|
}
|
|
|
|
|
|
2022-11-10 12:27:04 -06:00
|
|
|
|
if (r->get_hart_state) {
|
2021-09-23 17:07:38 -05:00
|
|
|
|
if (r->resume_prep(target) != ERROR_OK)
|
2019-04-03 14:13:09 -05:00
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LOG_DEBUG("[%d] mark as prepped", target->coreid);
|
|
|
|
|
r->prepped = true;
|
|
|
|
|
|
|
|
|
|
return ERROR_OK;
|
2017-05-11 12:40:43 -05:00
|
|
|
|
}
|
|
|
|
|
|
2019-04-03 14:13:09 -05:00
|
|
|
|
/**
|
|
|
|
|
* Resume all the harts that have been prepped, as close to instantaneous as
|
|
|
|
|
* possible.
|
|
|
|
|
*/
|
|
|
|
|
static int resume_go(struct target *target, int current,
|
|
|
|
|
target_addr_t address, int handle_breakpoints, int debug_execution)
|
|
|
|
|
{
|
|
|
|
|
riscv_info_t *r = riscv_info(target);
|
|
|
|
|
int result;
|
2022-11-10 12:27:04 -06:00
|
|
|
|
if (!r->get_hart_state) {
|
2019-04-03 14:13:09 -05:00
|
|
|
|
struct target_type *tt = get_target_type(target);
|
|
|
|
|
result = tt->resume(target, current, address, handle_breakpoints,
|
|
|
|
|
debug_execution);
|
|
|
|
|
} else {
|
|
|
|
|
result = riscv_resume_go_all_harts(target);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-21 11:02:07 -06:00
|
|
|
|
static int resume_finish(struct target *target, int debug_execution)
|
2019-04-03 14:13:09 -05:00
|
|
|
|
{
|
|
|
|
|
register_cache_invalidate(target->reg_cache);
|
|
|
|
|
|
2022-02-21 11:02:07 -06:00
|
|
|
|
target->state = debug_execution ? TARGET_DEBUG_RUNNING : TARGET_RUNNING;
|
2019-05-09 13:32:04 -05:00
|
|
|
|
target->debug_reason = DBG_REASON_NOTHALTED;
|
2022-02-21 11:02:07 -06:00
|
|
|
|
return target_call_event_callbacks(target,
|
|
|
|
|
debug_execution ? TARGET_EVENT_DEBUG_RESUMED : TARGET_EVENT_RESUMED);
|
2019-04-03 14:13:09 -05:00
|
|
|
|
}
|
|
|
|
|
|
2019-08-26 13:24:29 -05:00
|
|
|
|
/**
|
|
|
|
|
* @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.
|
|
|
|
|
*/
|
2020-05-19 12:34:36 -05:00
|
|
|
|
int riscv_resume(
|
2017-06-14 16:13:53 -05:00
|
|
|
|
struct target *target,
|
|
|
|
|
int current,
|
|
|
|
|
target_addr_t address,
|
|
|
|
|
int handle_breakpoints,
|
2019-08-26 13:24:29 -05:00
|
|
|
|
int debug_execution,
|
|
|
|
|
bool single_hart)
|
|
|
|
|
{
|
2018-02-07 14:16:22 -06:00
|
|
|
|
LOG_DEBUG("handle_breakpoints=%d", handle_breakpoints);
|
2019-04-03 14:13:09 -05:00
|
|
|
|
int result = ERROR_OK;
|
|
|
|
|
|
2022-10-13 12:50:39 -05:00
|
|
|
|
struct list_head *targets;
|
2019-04-03 14:13:09 -05:00
|
|
|
|
|
2022-10-13 12:50:39 -05:00
|
|
|
|
LIST_HEAD(single_target_list);
|
|
|
|
|
struct target_list single_target_entry = {
|
|
|
|
|
.lh = {NULL, NULL},
|
|
|
|
|
.target = target
|
|
|
|
|
};
|
2019-04-03 14:13:09 -05:00
|
|
|
|
|
2022-10-13 12:50:39 -05:00
|
|
|
|
if (target->smp && !single_hart) {
|
|
|
|
|
targets = target->smp_targets;
|
2019-04-03 14:13:09 -05:00
|
|
|
|
} else {
|
2022-10-13 12:50:39 -05:00
|
|
|
|
/* Make a list that just contains a single target, so we can
|
|
|
|
|
* share code below. */
|
|
|
|
|
list_add(&single_target_entry.lh, &single_target_list);
|
|
|
|
|
targets = &single_target_list;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct target_list *tlist;
|
|
|
|
|
foreach_smp_target_direction(resume_order == RO_NORMAL, tlist, targets) {
|
|
|
|
|
struct target *t = tlist->target;
|
2022-10-13 15:29:15 -05:00
|
|
|
|
if (t->state != TARGET_UNAVAILABLE) {
|
|
|
|
|
if (resume_prep(t, current, address, handle_breakpoints,
|
|
|
|
|
debug_execution) != ERROR_OK)
|
|
|
|
|
result = ERROR_FAIL;
|
|
|
|
|
}
|
2022-10-13 12:50:39 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach_smp_target_direction(resume_order == RO_NORMAL, tlist, targets) {
|
|
|
|
|
struct target *t = tlist->target;
|
|
|
|
|
riscv_info_t *i = riscv_info(t);
|
|
|
|
|
if (i->prepped) {
|
|
|
|
|
if (resume_go(t, current, address, handle_breakpoints,
|
|
|
|
|
debug_execution) != ERROR_OK)
|
|
|
|
|
result = ERROR_FAIL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach_smp_target_direction(resume_order == RO_NORMAL, tlist, targets) {
|
|
|
|
|
struct target *t = tlist->target;
|
2022-10-13 15:29:15 -05:00
|
|
|
|
if (t->state != TARGET_UNAVAILABLE) {
|
|
|
|
|
if (resume_finish(t, debug_execution) != ERROR_OK)
|
|
|
|
|
result = ERROR_FAIL;
|
|
|
|
|
}
|
2019-01-03 17:06:35 -06:00
|
|
|
|
}
|
|
|
|
|
|
2019-04-03 14:13:09 -05:00
|
|
|
|
return result;
|
2017-05-11 12:40:43 -05:00
|
|
|
|
}
|
|
|
|
|
|
2020-05-19 12:34:36 -05:00
|
|
|
|
static int riscv_target_resume(struct target *target, int current, target_addr_t address,
|
2019-08-26 13:24:29 -05:00
|
|
|
|
int handle_breakpoints, int debug_execution)
|
|
|
|
|
{
|
2020-05-19 12:34:36 -05:00
|
|
|
|
return riscv_resume(target, current, address, handle_breakpoints,
|
2019-08-26 13:24:29 -05:00
|
|
|
|
debug_execution, false);
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-10 14:18:03 -06:00
|
|
|
|
static int riscv_mmu(struct target *target, int *enabled)
|
|
|
|
|
{
|
2019-12-31 13:27:22 -06:00
|
|
|
|
if (!riscv_enable_virt2phys) {
|
|
|
|
|
*enabled = 0;
|
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-26 12:33:30 -05:00
|
|
|
|
/* Don't use MMU in explicit or effective M (machine) mode */
|
|
|
|
|
riscv_reg_t priv;
|
|
|
|
|
if (riscv_get_register(target, &priv, GDB_REGNO_PRIV) != ERROR_OK) {
|
|
|
|
|
LOG_ERROR("Failed to read priv register.");
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
riscv_reg_t mstatus;
|
|
|
|
|
if (riscv_get_register(target, &mstatus, GDB_REGNO_MSTATUS) != ERROR_OK) {
|
|
|
|
|
LOG_ERROR("Failed to read mstatus register.");
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((get_field(mstatus, MSTATUS_MPRV) ? get_field(mstatus, MSTATUS_MPP) : priv) == PRV_M) {
|
|
|
|
|
LOG_DEBUG("SATP/MMU ignored in Machine mode (mstatus=0x%" PRIx64 ").", mstatus);
|
|
|
|
|
*enabled = 0;
|
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
riscv_reg_t satp;
|
|
|
|
|
if (riscv_get_register(target, &satp, GDB_REGNO_SATP) != ERROR_OK) {
|
2019-12-10 14:18:03 -06:00
|
|
|
|
LOG_DEBUG("Couldn't read SATP.");
|
2020-04-13 14:53:26 -05:00
|
|
|
|
/* If we can't read SATP, then there must not be an MMU. */
|
|
|
|
|
*enabled = 0;
|
|
|
|
|
return ERROR_OK;
|
2019-12-10 14:18:03 -06:00
|
|
|
|
}
|
|
|
|
|
|
2020-05-26 12:33:30 -05:00
|
|
|
|
if (get_field(satp, RISCV_SATP_MODE(riscv_xlen(target))) == SATP_MODE_OFF) {
|
2019-12-10 14:18:03 -06:00
|
|
|
|
LOG_DEBUG("MMU is disabled.");
|
|
|
|
|
*enabled = 0;
|
|
|
|
|
} else {
|
|
|
|
|
LOG_DEBUG("MMU is enabled.");
|
|
|
|
|
*enabled = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int riscv_address_translate(struct target *target,
|
|
|
|
|
target_addr_t virtual, target_addr_t *physical)
|
|
|
|
|
{
|
2020-08-18 13:01:41 -05:00
|
|
|
|
RISCV_INFO(r);
|
2019-12-10 14:18:03 -06:00
|
|
|
|
riscv_reg_t satp_value;
|
|
|
|
|
int mode;
|
|
|
|
|
uint64_t ppn_value;
|
|
|
|
|
target_addr_t table_address;
|
2021-01-29 12:58:11 -06:00
|
|
|
|
const virt2phys_info_t *info;
|
From upstream (#580)
* configure: do not make Capstone dependency automagic
This adds regular ./configure options to control dependency on the
Capstone disassembly engine. See [0] for the rationale.
[0] https://wiki.gentoo.org/wiki/Project:Quality_Assurance/Automagic_dependencies
Change-Id: I3e16dc5255d650aa1949ccf896b26dc96e522a75
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/5985
Tested-by: jenkins
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
* configure.ac: fix build with libusb0 and without libusb1
Driver 'openjtag' requires both libftdi and libusb1.
The current check is incorrect and the driver is built when
libftdi is present with libusb0 and without libusb1, which causes
the linker to fail resolving the required libusb1 symbols.
Remove the check for libusb0 on driver 'openjtag'.
Create a new adapters group LIBFTDI_USB1_ADAPTERS to hold the
driver 'openjtag'.
Change-Id: I1f5e554b519e51c829d116ede894639cb55a26aa
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/5989
Tested-by: jenkins
* doc: fix over/underfull hboxes in PDF
This adds some cosmetic changes to make the PDF User Manual look
proper.
Building it now requires Texinfo 5.0 which shouldn't be problematic
according to [0]. Commit 79fdeb37f486f74658f1eaf658abac8efb3eba6a is
effectively reverted.
[0] https://repology.org/project/texinfo/versions
Change-Id: I990bc23bdb53d24c302b26d74fd770ea738e4096
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/5995
Reviewed-by: Jonathan McDowell <noodles-openocd@earth.li>
Tested-by: jenkins
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
* contrib: rpc_examples: haskell: fix ftbs with current libraries
And get rid of some warnings along the way.
Change-Id: I8fdbe1fa304276be6b0f25249b902b3576aa3793
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/5987
Tested-by: jenkins
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
* Makefile.am: fix override of target 'check-recursive'
To prevent executing the Jim Tcl tests, the makefile's target
'check-recursive' has been overridden in commit 56d163ce7951
("jimtcl: update to 0.77, the current version, enable only
specific modules").
This causes a runtime warning during build:
Makefile:6332: warning: overriding recipe for target 'check-recursive'
Makefile:5098: warning: ignoring old recipe for target 'check-recursive'
Instead of override the makefile's target 'check-recursive',
prevent the recursion by re-assigning as empty the variable
SUBDIRS for this specific target only.
Change-Id: I03d1c467eba42316a59aeed4612d6bdbe6211282
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Fixes: 56d163ce7951 ("jimtcl: update to 0.77, the current version, enable only specific modules")
Reviewed-on: http://openocd.zylin.com/5986
Tested-by: jenkins
* contrib: udev file for Cypress SuperSpeed Explorer kit
lsusb output:
Bus 003 Device 011: ID 04b4:0007 Cypress Semiconductor Corp.
Couldn't open device, some information will be missing
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 2.00
bDeviceClass 0 (Defined at Interface level)
bDeviceSubClass 0
bDeviceProtocol 0
bMaxPacketSize0 8
idVendor 0x04b4 Cypress Semiconductor Corp.
idProduct 0x0007
bcdDevice 0.00
iManufacturer 1
iProduct 2
iSerial 0
bNumConfigurations 1
Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 114
bNumInterfaces 4
bConfigurationValue 1
iConfiguration 0
bmAttributes 0xa0
(Bus Powered)
Remote Wakeup
MaxPower 100mA
Interface Association:
bLength 8
bDescriptorType 11
bFirstInterface 0
bInterfaceCount 2
bFunctionClass 2 Communications
bFunctionSubClass 2 Abstract (modem)
bFunctionProtocol 1 AT-commands (v.25ter)
iFunction 0
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 1
bInterfaceClass 2 Communications
bInterfaceSubClass 2 Abstract (modem)
bInterfaceProtocol 1 AT-commands (v.25ter)
iInterface 0
CDC Header:
bcdCDC 1.10
CDC ACM:
bmCapabilities 0x02
line coding and serial state
CDC Union:
bMasterInterface 0
bSlaveInterface 1
CDC Call Management:
bmCapabilities 0x00
bDataInterface 1
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x83 EP 3 IN
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0040 1x 64 bytes
bInterval 10
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 1
bAlternateSetting 0
bNumEndpoints 2
bInterfaceClass 10 CDC Data
bInterfaceSubClass 0 Unused
bInterfaceProtocol 0
iInterface 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x01 EP 1 OUT
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0040 1x 64 bytes
bInterval 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x82 EP 2 IN
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0040 1x 64 bytes
bInterval 0
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 2
bAlternateSetting 0
bNumEndpoints 3
bInterfaceClass 255 Vendor Specific Class
bInterfaceSubClass 4
bInterfaceProtocol 0
iInterface 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x04 EP 4 OUT
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0040 1x 64 bytes
bInterval 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x85 EP 5 IN
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0040 1x 64 bytes
bInterval 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x86 EP 6 IN
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0040 1x 64 bytes
bInterval 10
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 3
bAlternateSetting 0
bNumEndpoints 0
bInterfaceClass 255 Vendor Specific Class
bInterfaceSubClass 5
bInterfaceProtocol 0
iInterface 0
Change-Id: I62f0300199da3551c8774a4a5a4cd106a3ab2904
Signed-off-by: Ricardo Ribalda Delgado <ricardo.ribalda@gmail.com>
Signed-off-by: Jiri Kastner <cz172638@gmail.com>
Reviewed-on: http://openocd.zylin.com/3611
Tested-by: jenkins
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
* target: fix memory leak on multiple '-gdb-port' flag
In the odd case of multiple flags '-gdb-port' during 'target
create' or following 'configure', the new strdup()'ed value will
replace the old one without freeing it.
Free the old value (if it exists) before replacing it.
Change-Id: I1673346613ce7023880046e3a9ba473e75f18b8a
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6005
Tested-by: jenkins
* udev: fix permission for Ambiq Micro EVK's
Commit 68e204f1e91a ("udev: Add rules for Ambiq Micro EVK's.") was
initially proposed as http://openocd.zylin.com/3429/ then replaced
by http://openocd.zylin.com/3980/
The initial proposal was for file '99-openocd.rules', in which
MODE="664" was the norm.
After merge of http://openocd.zylin.com/2804/ the new udev rules
in '60-openocd.rules' switched to MODE="660", but the evolution of
the above patch missed this change.
Switch udev rules of Ambiq Micro EVK's to MODE="660" and uniform
them to the rest of the file.
Change-Id: I4b4eea535184ee8569da3264bff4f1fafb5bce4d
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Fixes: 68e204f1e91a ("udev: Add rules for Ambiq Micro EVK's.")
Reviewed-on: http://openocd.zylin.com/6004
Tested-by: jenkins
* doc/style: fix doxygen error
Doxygen complains about non-closed nested comments:
doc/manual/style.txt:423: warning: Reached end of file
while still inside a (nested) comment. Nesting level 1
(probable line reference: 149)
This is caused by the string '/**' that is interpreted as the
beginning of a comment.
Escape the string to not let doxygen consider it as a comment
While there, replace @code/@endcode with @verbatim/@endverbatim to
properly render the line.
Change-Id: If2a27c4cf659326e317cc4ac8c0b313e97e40432
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/5996
Tested-by: jenkins
* flash/nor/max32xxx: fix path of include file
The relative path should have three times '..'.
Issue identified by doxygen:
src/flash/nor/max32xxx.c:85: warning: include file
../../contrib/loaders/flash/max32xxx/max32xxx.inc not
found, perhaps you forgot to add its directory to
INCLUDE_PATH?
Change-Id: Ie7b4948c6770b8acb9eff26e08eea32945ebb219
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/5997
Tested-by: jenkins
* Doxyfile.in: fix build out-of-tree
When doxygen is built out-of-tree, it fails to find the generated
file startup_tcl.inc:
src/openocd.c:59: warning: include file startup_tcl.inc
not found, perhaps you forgot to add its directory to
INCLUDE_PATH?
Add '@builddir@/src' to INCLUDE_PATH.
Change-Id: I51f2f6fe7224bba0f8b3db7219f9831de4e67139
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/5998
Tested-by: jenkins
* doc/manual/primer/jtag.txt: remove duplicated section name
The section name 'primerjtag' is used twice, causing doxygen to
complain:
warning: multiple use of section label 'primerjtag',
(first occurrence: doc/manual/primer/jtag.txt, line 107)
Rename one of them.
Change-Id: Id307915dbc51a7f647fab4fb28ab431e65344d61
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/5999
Tested-by: jenkins
* Doxyfile.in: exclude libjaylink from doxygen
When build using libjaylink as git submodule, doxygen includes the
libjaylink files and complains for multiple 'mainpage' comment
block, one in OpenOCD and the other in libjaylink:
src/jtag/drivers/libjaylink/libjaylink/core.c:37: warning:
found more than one \mainpage comment block! (first
occurrence: doc/manual/main.txt, line 1), Skipping current
block!
Exclude libjaylink submodule from doxygen.
Change-Id: I5e856817344c9f21f8c26f077a23c00b83cfbcb5
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6000
Tested-by: jenkins
* openocd: fix incorrect doxygen comments
Use '@param' in front of function's parameters and '@a' when the
parameter is recalled in the description.
This fixes doxygen complains:
warning: Found unknown command '@buff16'
While there, fix a minor typo s/occured/occurred/ in a comment and
the typo s/@apram/@param/ in a doxygen comment.
Change-Id: I5cd86a80adef552331310a21c55ec5d11354be21
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6001
Tested-by: jenkins
* openocd: fix doxygen parameters of functions
Add to doxygen comment the missing parameters.
Remove from doxygen comment any non-existing parameter.
Fix the parameter names in doxygen comment to match the one in the
function prototype.
Where the parameter name in the doxygen description seems better
than the one in the code, change the code.
Escape the character '<' to prevent doxygen to interpret it as an
xml tag.
Change-Id: I22da723339ac7d7a7a64ac4c1cc4336e2416c2cc
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6002
Tested-by: jenkins
* doc/manual/primer/autotools.txt: fix doxygen warning
Commit ab90b8777855 ("configure: remove AM_MAINTAINER_MODE,
effectively always enabling all the rules") removes the configure
flag '--enable-maintainer-mode' and its documentation, but have
left a reference to the removed subsection 'primermaintainermode'
and this triggers a warning in doxygen:
doc/manual/primer/autotools.txt:21: warning: unable to
resolve reference to 'primermaintainermode' for \ref
command
Remove the obsoleted paragraph.
Change-Id: I56e69ef033d546d159745bed1b47c6105827e7ae
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Fixes: ab90b8777855 ("configure: remove AM_MAINTAINER_MODE, effectively always enabling all the rules")
Reviewed-on: http://openocd.zylin.com/6003
Tested-by: jenkins
* flash/stmqspi: fix build error with -Werror=maybe-uninitialized
using gcc 9.3 on ubuntu focal fossa with -Werror=maybe-uninitialized
we get this error:
/src/flash/nor/stmqspi.c: In function ‘read_flash_id’:
/src/flash/nor/stmqspi.c:1948:6: error: ‘retval’ may be used uninitialized
Change-Id: Ifd8ae60df847fc61e22ca100c008e3914c9af79b
Signed-off-by: Tarek BOCHKATI <tarek.bouchkati@st.com>
Reviewed-on: http://openocd.zylin.com/6012
Tested-by: jenkins
Reviewed-by: Tarek BOCHKATI <tarek.bouchkati@gmail.com>
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
* target/riscv: fix build error with -Werror=maybe-uninitialized
using gcc 9.3 on ubuntu focal fossa with -Werror=maybe-uninitialized
we get this error:
/src/target/riscv/riscv.c: In function ‘riscv_address_translate’:
/src/target/riscv/riscv.c:1536:13: error: ‘pte’ may be used uninitialized
Change-Id: I51e180b43f9b6996e4e4058db49c179b9f81bcdc
Signed-off-by: Tarek BOCHKATI <tarek.bouchkati@st.com>
Reviewed-on: http://openocd.zylin.com/6013
Tested-by: jenkins
Reviewed-by: Tim Newsome <tim@sifive.com>
Reviewed-by: Tarek BOCHKATI <tarek.bouchkati@gmail.com>
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
* cortex_m: [FIX] ARMv8-M does not support VECTRESET
ref: Arm®v8-M Architecture Reference Manual (DDI0553B.m)
D1.2.3: AIRCR, Application Interrupt and Reset Control Register
Bit [0] is RES0
Change-Id: I6ef451b2c114487e2732852a60e86c292ffa6a50
Signed-off-by: Tarek BOCHKATI <tarek.bouchkati@st.com>
Reviewed-on: http://openocd.zylin.com/6014
Tested-by: jenkins
Reviewed-by: Tarek BOCHKATI <tarek.bouchkati@gmail.com>
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
* driver/ftdi: skip trst in swd mode
When using the adapter olimex arm-jtag-swd (to convert to SWD a
JTAG-only FTDI adapter), the pin trst on JTAG side is re-used to
control the direction of pin SWDIO on SWD side.
There is a single reset API at adapter driver to assert/deassert
either srst and/or trst. A request to assert/deassert srst can
cause also trst to change value, hanging the SWD communication.
In SWD mode, ignore the value passed to trst.
Change-Id: I5fe1eed851177d405d77ae6079da9642dc1a08f1
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6006
Tested-by: jenkins
* configure.ac: drop macro 'AC_PROG_CC_C99' from autoconf 2.70
The macro AC_PROG_CC_C99 has been obsoleted by autoconf 2.70 and
triggers a set of warnings from both 'aclocal' and 'autoconf'.
The test of AC_PROG_CC_C99 is now included in AC_PROG_CC.
For autoconf 2.69 and earlier the macro is still required, so
cannot be simply dropped.
Use a conditional test to avoid the warning on autoconf 2.70 but
still use AC_PROG_CC_C99 on older autoconf.
Change-Id: I5e8437f5a826fb63be6d07bcb5bb824f94683020
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6009
Tested-by: jenkins
Reviewed-by: Marc Schink <dev@zapb.de>
* configure: drop macro 'AC_HEADER_TIME'
The macro AC_HEADER_TIME has been obsoleted by autoconf 2.70.
Not all systems provide 'sys/time.h', plus some old system didn't
allowed to include both 'time.h' and 'sys/time.h' because 'time.h'
was included by 'sys/time.h' and was not properly protected to
allow multiple inclusion.
The macro AC_HEADER_TIME helps to detect such odd case.
Nowadays all the systems properly protect 'time.h', so its safe to
unconditionally include 'time.h', even if it is also included by
'sys/time.h'.
The case of systems without 'sys/time.h' is already covered by
configure.ac through the directive
AC_CHECK_HEADERS([sys/time.h])
Remove the obsoleted autoconf macro and simplify the code by
including 'time.h' unconditionally and check HAVE_SYS_TIME_H to
include 'sys/time.h'.
Change-Id: Iddb3f3f1d90c22668b97f8e756e1b4f733367a7d
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6010
Tested-by: jenkins
Reviewed-by: Marc Schink <dev@zapb.de>
* README.macOS: explain how to install suitable Texinfo
Change-Id: Ic5906111f412eebd906a9be3fd0e133484def3eb
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/6026
Tested-by: jenkins
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
* jlink: fix device discovery when network is off
If user specifies a serial number for the jlink device, openocd
extends the search to network jlink devices too, without checking
if the host has a valid and functional network connection. If the
network is not functional, libjaylink returns error. This error
invalidates the discovery on USB, even if it was successful.
Factor-out parts of the jlink_init into separate jlink_open_device
function, use that function to firstly discover and match USB
devices and, if matching device was not found on the USB bus and
serial number was specified, repeat discovery and matching via TCP.
Fixes: https://sourceforge.net/p/openocd/tickets/294/
Change-Id: Iea0de1640d4e5b21ecc7e9c1dd6d36f214d647c2
Signed-off-by: Bohdan Tymkiv <bohdan200@gmail.com>
Reviewed-on: http://openocd.zylin.com/6025
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
Tested-by: jenkins
Reviewed-by: Marc Schink <dev@zapb.de>
* README: add missing items for 0.11
JTAG adapters
Cadence DPI, Cypress Kitpro, FTDI FT232R, Linux GPIOD, Mellanox rshim,
Nuvoton Nu-Link, Nu-Link2, NXP IMX GPIO, Remote Bitbang, TI XDS110,
Xilinx XVC/PCIe
Debug targets
AArch64, Cortex-M (ARMv8-M), ARCv2, MIPS64, RISC-V, ST-STM8
Flash Drivers
ATmega128RFA1, Atmel SAM, eSi-RISC, EZR32HG, MAX32, MXC, nRF52, PSoC6,
Renesas RPC HF and SH QSPI, SiFive Freedom E, ST BlueNRG,
STM32 QUAD/OCTO-SPI for Flash/FRAM/EEPROM, SWM050, TI CC13xx, TI CC26xx,
TI CC32xx, TI MSP432, Winner Micro w600, Xilinx XCF
Change-Id: I341618ac5d7189e4f98268cecd66c99447b72af8
Signed-off-by: Tarek BOCHKATI <tarek.bouchkati@st.com>
Reviewed-on: http://openocd.zylin.com/6027
Tested-by: jenkins
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
* The openocd-0.11.0-rc2 release candidate
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
* Restore +dev suffix
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
* steppenprobe: fix file permission
Commit 895d4a599585 ("tcl/interface/ftdi: Add Steppenprobe open
hardware interface") erroneously set the execution permission to
the configuration file.
Strip the execution permission.
Change-Id: I556451d5e6fee4aee385451e8c90216a25b6ef46
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Fixes: http://openocd.zylin.com/5653
Reviewed-on: http://openocd.zylin.com/6038
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
Tested-by: Paul Fertser <fercerpav@gmail.com>
* github: fix github wokflow while pushing a tag
this fix permits to add correctly the generated artifact (windows binaries)
into the release section.
Change-Id: Ia982370d3a1e08c623ebcabb5ac97e9fb49d00e0
Signed-off-by: Tarek BOCHKATI <tarek.bouchkati@gmail.com>
Reviewed-on: http://openocd.zylin.com/6047
Tested-by: jenkins
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
* doc: Fix type in Hooking up the JTAG Adapter
We are talking about adapter connectivity in this chapter. It should
be "dongles" instead of "cables".
Change-Id: I7bd4307765517375caa2af86dfc929d0ef66c3e6
Signed-off-by: Yasushi SHOJI <yashi@spacecubics.com>
Reviewed-on: http://openocd.zylin.com/6040
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
Tested-by: jenkins
* doc/manual: Fix @subpage handling
The subpage "thelist" used to have a title "Pending and Open Tasks"
but the commit c41db358a0100ab changed it to "The List". With
@subpage, it now renders:
"The List of The List enumerates opportunities for"
instead of
"The List of Pending and Open Tasks enumerates opportunities for"
This commit fix it to
"The List enumerates opportunities for"
Change-Id: Ifee0dcd9b3c9f7e651a8748a7afda99eedea3c5c
Signed-off-by: Yasushi SHOJI <yashi@spacecubics.com>
Reviewed-on: http://openocd.zylin.com/6041
Tested-by: jenkins
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
* doc/manual: Fix function name typo
We have both the singular form, register_command(), and the plural form
register_commands().
Change-Id: I905ea83988b8ac70dd809b02d53b646aa4d66697
Signed-off-by: Yasushi SHOJI <yashi@spacecubics.com>
Reviewed-on: http://openocd.zylin.com/6042
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
Tested-by: jenkins
Co-authored-by: Paul Fertser <fercerpav@gmail.com>
Co-authored-by: Antonio Borneo <borneo.antonio@gmail.com>
Co-authored-by: Jiri Kastner <cz172638@gmail.com>
Co-authored-by: Tarek BOCHKATI <tarek.bouchkati@st.com>
Co-authored-by: Bohdan Tymkiv <bohdan200@gmail.com>
Co-authored-by: Tarek BOCHKATI <tarek.bouchkati@gmail.com>
Co-authored-by: Yasushi SHOJI <yashi@spacecubics.com>
2021-02-11 13:27:18 -06:00
|
|
|
|
uint64_t pte = 0;
|
2019-12-10 14:18:03 -06:00
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
int result = riscv_get_register(target, &satp_value, GDB_REGNO_SATP);
|
|
|
|
|
if (result != ERROR_OK)
|
|
|
|
|
return result;
|
|
|
|
|
|
2020-03-05 13:33:51 -06:00
|
|
|
|
unsigned xlen = riscv_xlen(target);
|
|
|
|
|
mode = get_field(satp_value, RISCV_SATP_MODE(xlen));
|
2019-12-10 14:18:03 -06:00
|
|
|
|
switch (mode) {
|
|
|
|
|
case SATP_MODE_SV32:
|
|
|
|
|
info = &sv32;
|
|
|
|
|
break;
|
|
|
|
|
case SATP_MODE_SV39:
|
|
|
|
|
info = &sv39;
|
|
|
|
|
break;
|
|
|
|
|
case SATP_MODE_SV48:
|
|
|
|
|
info = &sv48;
|
|
|
|
|
break;
|
|
|
|
|
case SATP_MODE_OFF:
|
|
|
|
|
LOG_ERROR("No translation or protection." \
|
2020-08-21 14:56:04 -05:00
|
|
|
|
" (satp: 0x%" PRIx64 ")", satp_value);
|
2019-12-10 14:18:03 -06:00
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
default:
|
|
|
|
|
LOG_ERROR("The translation mode is not supported." \
|
2020-08-21 14:56:04 -05:00
|
|
|
|
" (satp: 0x%" PRIx64 ")", satp_value);
|
2019-12-10 14:18:03 -06:00
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
2020-03-05 13:33:51 -06:00
|
|
|
|
LOG_DEBUG("virtual=0x%" TARGET_PRIxADDR "; mode=%s", virtual, info->name);
|
|
|
|
|
|
|
|
|
|
/* verify bits xlen-1:va_bits-1 are all equal */
|
2020-08-21 14:56:04 -05:00
|
|
|
|
target_addr_t mask = ((target_addr_t)1 << (xlen - (info->va_bits - 1))) - 1;
|
|
|
|
|
target_addr_t masked_msbs = (virtual >> (info->va_bits - 1)) & mask;
|
2020-03-05 13:33:51 -06:00
|
|
|
|
if (masked_msbs != 0 && masked_msbs != mask) {
|
|
|
|
|
LOG_ERROR("Virtual address 0x%" TARGET_PRIxADDR " is not sign-extended "
|
|
|
|
|
"for %s mode.", virtual, info->name);
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
2019-12-10 14:18:03 -06:00
|
|
|
|
|
2020-03-05 13:33:51 -06:00
|
|
|
|
ppn_value = get_field(satp_value, RISCV_SATP_PPN(xlen));
|
2019-12-10 14:18:03 -06:00
|
|
|
|
table_address = ppn_value << RISCV_PGSHIFT;
|
|
|
|
|
i = info->level - 1;
|
|
|
|
|
while (i >= 0) {
|
|
|
|
|
uint64_t vpn = virtual >> info->vpn_shift[i];
|
|
|
|
|
vpn &= info->vpn_mask[i];
|
|
|
|
|
target_addr_t pte_address = table_address +
|
|
|
|
|
(vpn << info->pte_shift);
|
|
|
|
|
uint8_t buffer[8];
|
|
|
|
|
assert(info->pte_shift <= 3);
|
2020-08-18 13:01:41 -05:00
|
|
|
|
int retval = r->read_memory(target, pte_address,
|
|
|
|
|
4, (1 << info->pte_shift) / 4, buffer, 4);
|
2019-12-10 14:18:03 -06:00
|
|
|
|
if (retval != ERROR_OK)
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
|
|
|
|
|
if (info->pte_shift == 2)
|
|
|
|
|
pte = buf_get_u32(buffer, 0, 32);
|
|
|
|
|
else
|
|
|
|
|
pte = buf_get_u64(buffer, 0, 64);
|
|
|
|
|
|
2020-01-06 18:57:15 -06:00
|
|
|
|
LOG_DEBUG("i=%d; PTE @0x%" TARGET_PRIxADDR " = 0x%" PRIx64, i,
|
|
|
|
|
pte_address, pte);
|
|
|
|
|
|
2019-12-10 14:18:03 -06:00
|
|
|
|
if (!(pte & PTE_V) || (!(pte & PTE_R) && (pte & PTE_W)))
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
|
|
|
|
|
if ((pte & PTE_R) || (pte & PTE_X)) /* Found leaf PTE. */
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
i--;
|
|
|
|
|
if (i < 0)
|
|
|
|
|
break;
|
|
|
|
|
ppn_value = pte >> PTE_PPN_SHIFT;
|
|
|
|
|
table_address = ppn_value << RISCV_PGSHIFT;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (i < 0) {
|
|
|
|
|
LOG_ERROR("Couldn't find the PTE.");
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-05 13:33:51 -06:00
|
|
|
|
/* Make sure to clear out the high bits that may be set. */
|
2020-08-21 14:56:04 -05:00
|
|
|
|
*physical = virtual & (((target_addr_t)1 << info->va_bits) - 1);
|
2019-12-10 14:18:03 -06:00
|
|
|
|
|
|
|
|
|
while (i < info->level) {
|
|
|
|
|
ppn_value = pte >> info->pte_ppn_shift[i];
|
|
|
|
|
ppn_value &= info->pte_ppn_mask[i];
|
2020-08-21 14:56:04 -05:00
|
|
|
|
*physical &= ~(((target_addr_t)info->pa_ppn_mask[i]) <<
|
2020-01-06 18:57:15 -06:00
|
|
|
|
info->pa_ppn_shift[i]);
|
2019-12-10 14:18:03 -06:00
|
|
|
|
*physical |= (ppn_value << info->pa_ppn_shift[i]);
|
|
|
|
|
i++;
|
|
|
|
|
}
|
2020-01-06 18:57:15 -06:00
|
|
|
|
LOG_DEBUG("0x%" TARGET_PRIxADDR " -> 0x%" TARGET_PRIxADDR, virtual,
|
|
|
|
|
*physical);
|
2019-12-10 14:18:03 -06:00
|
|
|
|
|
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int riscv_virt2phys(struct target *target, target_addr_t virtual, target_addr_t *physical)
|
|
|
|
|
{
|
|
|
|
|
int enabled;
|
|
|
|
|
if (riscv_mmu(target, &enabled) == ERROR_OK) {
|
|
|
|
|
if (!enabled)
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
|
|
|
|
|
if (riscv_address_translate(target, virtual, physical) == ERROR_OK)
|
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int riscv_read_phys_memory(struct target *target, target_addr_t phys_address,
|
|
|
|
|
uint32_t size, uint32_t count, uint8_t *buffer)
|
|
|
|
|
{
|
2020-08-18 13:01:41 -05:00
|
|
|
|
RISCV_INFO(r);
|
|
|
|
|
return r->read_memory(target, phys_address, size, count, buffer, size);
|
2019-12-10 14:18:03 -06:00
|
|
|
|
}
|
|
|
|
|
|
2017-06-13 14:22:26 -05:00
|
|
|
|
static int riscv_read_memory(struct target *target, target_addr_t address,
|
2016-05-25 14:15:35 -05:00
|
|
|
|
uint32_t size, uint32_t count, uint8_t *buffer)
|
|
|
|
|
{
|
2020-07-01 10:28:27 -05:00
|
|
|
|
if (count == 0) {
|
|
|
|
|
LOG_WARNING("0-length read from 0x%" TARGET_PRIxADDR, address);
|
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-10 14:18:03 -06:00
|
|
|
|
target_addr_t physical_addr;
|
|
|
|
|
if (target->type->virt2phys(target, address, &physical_addr) == ERROR_OK)
|
|
|
|
|
address = physical_addr;
|
|
|
|
|
|
2020-08-18 13:01:41 -05:00
|
|
|
|
RISCV_INFO(r);
|
|
|
|
|
return r->read_memory(target, address, size, count, buffer, size);
|
2016-06-20 18:02:13 -05:00
|
|
|
|
}
|
|
|
|
|
|
2019-12-10 14:18:03 -06:00
|
|
|
|
static int riscv_write_phys_memory(struct target *target, target_addr_t phys_address,
|
|
|
|
|
uint32_t size, uint32_t count, const uint8_t *buffer)
|
|
|
|
|
{
|
|
|
|
|
struct target_type *tt = get_target_type(target);
|
|
|
|
|
return tt->write_memory(target, phys_address, size, count, buffer);
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-13 14:22:26 -05:00
|
|
|
|
static int riscv_write_memory(struct target *target, target_addr_t address,
|
2016-06-20 18:02:13 -05:00
|
|
|
|
uint32_t size, uint32_t count, const uint8_t *buffer)
|
|
|
|
|
{
|
2020-07-01 10:28:27 -05:00
|
|
|
|
if (count == 0) {
|
|
|
|
|
LOG_WARNING("0-length write to 0x%" TARGET_PRIxADDR, address);
|
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-10 14:18:03 -06:00
|
|
|
|
target_addr_t physical_addr;
|
|
|
|
|
if (target->type->virt2phys(target, address, &physical_addr) == ERROR_OK)
|
|
|
|
|
address = physical_addr;
|
|
|
|
|
|
2017-02-05 20:00:05 -06:00
|
|
|
|
struct target_type *tt = get_target_type(target);
|
|
|
|
|
return tt->write_memory(target, address, size, count, buffer);
|
2016-05-25 19:31:23 -05:00
|
|
|
|
}
|
|
|
|
|
|
2021-06-16 12:38:00 -05:00
|
|
|
|
const char *riscv_get_gdb_arch(struct target *target)
|
|
|
|
|
{
|
|
|
|
|
switch (riscv_xlen(target)) {
|
|
|
|
|
case 32:
|
|
|
|
|
return "riscv:rv32";
|
|
|
|
|
case 64:
|
|
|
|
|
return "riscv:rv64";
|
|
|
|
|
}
|
|
|
|
|
LOG_ERROR("Unsupported xlen: %d", riscv_xlen(target));
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-07 15:24:44 -06:00
|
|
|
|
static int riscv_get_gdb_reg_list_internal(struct target *target,
|
2016-05-26 21:05:02 -05:00
|
|
|
|
struct reg **reg_list[], int *reg_list_size,
|
2019-02-07 15:24:44 -06:00
|
|
|
|
enum target_register_class reg_class, bool read)
|
2016-05-26 21:05:02 -05:00
|
|
|
|
{
|
2022-09-29 17:09:49 -05:00
|
|
|
|
LOG_TARGET_DEBUG(target, "reg_class=%d, read=%d", reg_class, read);
|
2017-06-20 19:17:54 -05:00
|
|
|
|
|
2017-11-17 17:34:18 -06:00
|
|
|
|
if (!target->reg_cache) {
|
|
|
|
|
LOG_ERROR("Target not initialized. Return ERROR_FAIL.");
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-26 21:05:02 -05:00
|
|
|
|
switch (reg_class) {
|
|
|
|
|
case REG_CLASS_GENERAL:
|
2019-01-17 14:46:20 -06:00
|
|
|
|
*reg_list_size = 33;
|
2016-05-26 21:05:02 -05:00
|
|
|
|
break;
|
|
|
|
|
case REG_CLASS_ALL:
|
2018-08-29 16:22:50 -05:00
|
|
|
|
*reg_list_size = target->reg_cache->num_regs;
|
2016-05-26 21:05:02 -05:00
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
LOG_ERROR("Unsupported reg_class: %d", reg_class);
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*reg_list = calloc(*reg_list_size, sizeof(struct reg *));
|
2017-12-22 16:35:38 -06:00
|
|
|
|
if (!*reg_list)
|
2016-06-03 23:02:08 -05:00
|
|
|
|
return ERROR_FAIL;
|
2017-11-17 17:34:18 -06:00
|
|
|
|
|
2016-06-03 23:02:08 -05:00
|
|
|
|
for (int i = 0; i < *reg_list_size; i++) {
|
2017-11-17 17:34:18 -06:00
|
|
|
|
assert(!target->reg_cache->reg_list[i].valid ||
|
|
|
|
|
target->reg_cache->reg_list[i].size > 0);
|
2016-10-20 12:42:28 -05:00
|
|
|
|
(*reg_list)[i] = &target->reg_cache->reg_list[i];
|
2019-07-08 14:26:01 -05:00
|
|
|
|
if (read &&
|
|
|
|
|
target->reg_cache->reg_list[i].exist &&
|
|
|
|
|
!target->reg_cache->reg_list[i].valid) {
|
2019-01-07 14:17:41 -06:00
|
|
|
|
if (target->reg_cache->reg_list[i].type->get(
|
|
|
|
|
&target->reg_cache->reg_list[i]) != ERROR_OK)
|
2019-02-07 15:24:44 -06:00
|
|
|
|
return ERROR_FAIL;
|
2019-01-07 14:17:41 -06:00
|
|
|
|
}
|
2016-06-03 23:02:08 -05:00
|
|
|
|
}
|
2016-05-26 21:05:02 -05:00
|
|
|
|
|
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-07 15:24:44 -06:00
|
|
|
|
static int riscv_get_gdb_reg_list_noread(struct target *target,
|
|
|
|
|
struct reg **reg_list[], int *reg_list_size,
|
|
|
|
|
enum target_register_class reg_class)
|
|
|
|
|
{
|
|
|
|
|
return riscv_get_gdb_reg_list_internal(target, reg_list, reg_list_size,
|
|
|
|
|
reg_class, false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int riscv_get_gdb_reg_list(struct target *target,
|
|
|
|
|
struct reg **reg_list[], int *reg_list_size,
|
|
|
|
|
enum target_register_class reg_class)
|
|
|
|
|
{
|
|
|
|
|
return riscv_get_gdb_reg_list_internal(target, reg_list, reg_list_size,
|
|
|
|
|
reg_class, true);
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-16 18:12:27 -06:00
|
|
|
|
static int riscv_arch_state(struct target *target)
|
2016-06-16 14:16:56 -05:00
|
|
|
|
{
|
2017-02-05 20:00:05 -06:00
|
|
|
|
struct target_type *tt = get_target_type(target);
|
|
|
|
|
return tt->arch_state(target);
|
2016-06-16 14:16:56 -05:00
|
|
|
|
}
|
|
|
|
|
|
2017-12-22 16:35:38 -06:00
|
|
|
|
/* Algorithm must end with a software breakpoint instruction. */
|
2016-11-16 18:12:27 -06:00
|
|
|
|
static int riscv_run_algorithm(struct target *target, int num_mem_params,
|
|
|
|
|
struct mem_param *mem_params, int num_reg_params,
|
2017-06-13 14:22:26 -05:00
|
|
|
|
struct reg_param *reg_params, target_addr_t entry_point,
|
|
|
|
|
target_addr_t exit_point, int timeout_ms, void *arch_info)
|
2016-11-16 18:12:27 -06:00
|
|
|
|
{
|
2020-09-17 15:20:12 -05:00
|
|
|
|
RISCV_INFO(info);
|
2016-11-16 18:12:27 -06:00
|
|
|
|
|
|
|
|
|
if (target->state != TARGET_HALTED) {
|
|
|
|
|
LOG_WARNING("target not halted");
|
|
|
|
|
return ERROR_TARGET_NOT_HALTED;
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-02 11:38:40 -06:00
|
|
|
|
/* Write memory parameters to the target memory */
|
|
|
|
|
for (int i = 0; i < num_mem_params; i++) {
|
|
|
|
|
if (mem_params[i].direction == PARAM_OUT ||
|
|
|
|
|
mem_params[i].direction == PARAM_IN_OUT) {
|
|
|
|
|
int retval = target_write_buffer(target, mem_params[i].address, mem_params[i].size, mem_params[i].value);
|
|
|
|
|
if (retval != ERROR_OK) {
|
|
|
|
|
LOG_ERROR("Couldn't write input mem param into the memory, addr=0x%" TARGET_PRIxADDR " size=0x%" PRIx32,
|
|
|
|
|
mem_params[i].address, mem_params[i].size);
|
|
|
|
|
return retval;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-12-22 16:35:38 -06:00
|
|
|
|
/* Save registers */
|
2021-06-04 07:38:17 -05:00
|
|
|
|
struct reg *reg_pc = register_get_by_name(target->reg_cache, "pc", true);
|
2017-12-22 16:35:38 -06:00
|
|
|
|
if (!reg_pc || reg_pc->type->get(reg_pc) != ERROR_OK)
|
2016-11-16 18:12:27 -06:00
|
|
|
|
return ERROR_FAIL;
|
2017-02-05 20:00:05 -06:00
|
|
|
|
uint64_t saved_pc = buf_get_u64(reg_pc->value, 0, reg_pc->size);
|
2019-08-26 13:24:29 -05:00
|
|
|
|
LOG_DEBUG("saved_pc=0x%" PRIx64, saved_pc);
|
2016-11-16 18:12:27 -06:00
|
|
|
|
|
|
|
|
|
uint64_t saved_regs[32];
|
|
|
|
|
for (int i = 0; i < num_reg_params; i++) {
|
|
|
|
|
LOG_DEBUG("save %s", reg_params[i].reg_name);
|
2021-06-04 07:38:17 -05:00
|
|
|
|
struct reg *r = register_get_by_name(target->reg_cache, reg_params[i].reg_name, false);
|
2016-11-16 18:12:27 -06:00
|
|
|
|
if (!r) {
|
|
|
|
|
LOG_ERROR("Couldn't find register named '%s'", reg_params[i].reg_name);
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (r->size != reg_params[i].size) {
|
|
|
|
|
LOG_ERROR("Register %s is %d bits instead of %d bits.",
|
|
|
|
|
reg_params[i].reg_name, r->size, reg_params[i].size);
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-27 16:47:33 -06:00
|
|
|
|
if (r->number > GDB_REGNO_XPR31) {
|
2016-11-16 18:12:27 -06:00
|
|
|
|
LOG_ERROR("Only GPRs can be use as argument registers.");
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
|
|
|
|
|
2017-12-22 16:35:38 -06:00
|
|
|
|
if (r->type->get(r) != ERROR_OK)
|
2016-11-16 18:12:27 -06:00
|
|
|
|
return ERROR_FAIL;
|
2017-02-05 20:00:05 -06:00
|
|
|
|
saved_regs[r->number] = buf_get_u64(r->value, 0, r->size);
|
2019-06-19 12:56:37 -05:00
|
|
|
|
|
|
|
|
|
if (reg_params[i].direction == PARAM_OUT || reg_params[i].direction == PARAM_IN_OUT) {
|
|
|
|
|
if (r->type->set(r, reg_params[i].value) != ERROR_OK)
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
2016-11-16 18:12:27 -06:00
|
|
|
|
}
|
|
|
|
|
|
2017-12-22 16:35:38 -06:00
|
|
|
|
/* Disable Interrupts before attempting to run the algorithm. */
|
2017-01-25 13:35:57 -06:00
|
|
|
|
uint64_t current_mstatus;
|
2022-03-01 12:05:54 -06:00
|
|
|
|
uint64_t irq_disabled_mask = MSTATUS_MIE | MSTATUS_HIE | MSTATUS_SIE | MSTATUS_UIE;
|
|
|
|
|
if (riscv_interrupts_disable(target, irq_disabled_mask, ¤t_mstatus) != ERROR_OK)
|
2017-12-21 18:41:50 -06:00
|
|
|
|
return ERROR_FAIL;
|
2017-01-25 13:35:57 -06:00
|
|
|
|
|
2017-12-22 16:35:38 -06:00
|
|
|
|
/* Run algorithm */
|
2017-06-13 14:22:26 -05:00
|
|
|
|
LOG_DEBUG("resume at 0x%" TARGET_PRIxADDR, entry_point);
|
2022-02-21 11:02:07 -06:00
|
|
|
|
if (riscv_resume(target, 0, entry_point, 0, 1, true) != ERROR_OK)
|
2016-11-16 18:12:27 -06:00
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
|
|
|
|
|
int64_t start = timeval_ms();
|
|
|
|
|
while (target->state != TARGET_HALTED) {
|
|
|
|
|
LOG_DEBUG("poll()");
|
|
|
|
|
int64_t now = timeval_ms();
|
|
|
|
|
if (now - start > timeout_ms) {
|
2019-09-09 14:01:17 -05:00
|
|
|
|
LOG_ERROR("Algorithm timed out after %" PRId64 " ms.", now - start);
|
2019-05-09 13:32:04 -05:00
|
|
|
|
riscv_halt(target);
|
2017-04-26 17:16:39 -05:00
|
|
|
|
old_or_new_riscv_poll(target);
|
2019-09-09 14:01:17 -05:00
|
|
|
|
enum gdb_regno regnums[] = {
|
|
|
|
|
GDB_REGNO_RA, GDB_REGNO_SP, GDB_REGNO_GP, GDB_REGNO_TP,
|
|
|
|
|
GDB_REGNO_T0, GDB_REGNO_T1, GDB_REGNO_T2, GDB_REGNO_FP,
|
|
|
|
|
GDB_REGNO_S1, GDB_REGNO_A0, GDB_REGNO_A1, GDB_REGNO_A2,
|
|
|
|
|
GDB_REGNO_A3, GDB_REGNO_A4, GDB_REGNO_A5, GDB_REGNO_A6,
|
|
|
|
|
GDB_REGNO_A7, GDB_REGNO_S2, GDB_REGNO_S3, GDB_REGNO_S4,
|
|
|
|
|
GDB_REGNO_S5, GDB_REGNO_S6, GDB_REGNO_S7, GDB_REGNO_S8,
|
|
|
|
|
GDB_REGNO_S9, GDB_REGNO_S10, GDB_REGNO_S11, GDB_REGNO_T3,
|
|
|
|
|
GDB_REGNO_T4, GDB_REGNO_T5, GDB_REGNO_T6,
|
|
|
|
|
GDB_REGNO_PC,
|
|
|
|
|
GDB_REGNO_MSTATUS, GDB_REGNO_MEPC, GDB_REGNO_MCAUSE,
|
|
|
|
|
};
|
2021-05-16 06:57:11 -05:00
|
|
|
|
for (unsigned i = 0; i < ARRAY_SIZE(regnums); i++) {
|
2019-09-09 14:01:17 -05:00
|
|
|
|
enum gdb_regno regno = regnums[i];
|
2019-07-09 12:05:07 -05:00
|
|
|
|
riscv_reg_t reg_value;
|
|
|
|
|
if (riscv_get_register(target, ®_value, regno) != ERROR_OK)
|
|
|
|
|
break;
|
|
|
|
|
LOG_ERROR("%s = 0x%" PRIx64, gdb_regno_name(regno), reg_value);
|
|
|
|
|
}
|
2016-11-16 18:12:27 -06:00
|
|
|
|
return ERROR_TARGET_TIMEOUT;
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-26 17:16:39 -05:00
|
|
|
|
int result = old_or_new_riscv_poll(target);
|
2017-12-22 16:35:38 -06:00
|
|
|
|
if (result != ERROR_OK)
|
2016-11-16 18:12:27 -06:00
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-23 13:32:42 -05:00
|
|
|
|
/* TODO: The current hart id might have been changed in poll(). */
|
|
|
|
|
/* if (riscv_select_current_hart(target) != ERROR_OK)
|
|
|
|
|
return ERROR_FAIL; */
|
2019-09-09 14:01:17 -05:00
|
|
|
|
|
2017-12-22 16:35:38 -06:00
|
|
|
|
if (reg_pc->type->get(reg_pc) != ERROR_OK)
|
2016-11-16 18:12:27 -06:00
|
|
|
|
return ERROR_FAIL;
|
2017-02-05 20:00:05 -06:00
|
|
|
|
uint64_t final_pc = buf_get_u64(reg_pc->value, 0, reg_pc->size);
|
2019-06-19 12:56:37 -05:00
|
|
|
|
if (exit_point && final_pc != exit_point) {
|
2017-06-13 14:22:26 -05:00
|
|
|
|
LOG_ERROR("PC ended up at 0x%" PRIx64 " instead of 0x%"
|
|
|
|
|
TARGET_PRIxADDR, final_pc, exit_point);
|
2016-11-16 18:12:27 -06:00
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
|
|
|
|
|
2017-12-22 16:35:38 -06:00
|
|
|
|
/* Restore Interrupts */
|
2022-03-01 12:05:54 -06:00
|
|
|
|
if (riscv_interrupts_restore(target, current_mstatus) != ERROR_OK)
|
|
|
|
|
return ERROR_FAIL;
|
2017-01-25 17:23:10 -06:00
|
|
|
|
|
2017-12-22 16:35:38 -06:00
|
|
|
|
/* Restore registers */
|
2019-12-20 16:56:08 -06:00
|
|
|
|
uint8_t buf[8] = { 0 };
|
2021-01-18 14:22:43 -06:00
|
|
|
|
buf_set_u64(buf, 0, info->xlen, saved_pc);
|
2017-12-22 16:35:38 -06:00
|
|
|
|
if (reg_pc->type->set(reg_pc, buf) != ERROR_OK)
|
2016-11-16 18:12:27 -06:00
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < num_reg_params; i++) {
|
2019-06-19 12:56:37 -05:00
|
|
|
|
if (reg_params[i].direction == PARAM_IN ||
|
|
|
|
|
reg_params[i].direction == PARAM_IN_OUT) {
|
2021-06-04 07:38:17 -05:00
|
|
|
|
struct reg *r = register_get_by_name(target->reg_cache, reg_params[i].reg_name, false);
|
2019-09-09 14:01:17 -05:00
|
|
|
|
if (r->type->get(r) != ERROR_OK) {
|
|
|
|
|
LOG_ERROR("get(%s) failed", r->name);
|
2019-06-19 12:56:37 -05:00
|
|
|
|
return ERROR_FAIL;
|
2019-09-09 14:01:17 -05:00
|
|
|
|
}
|
2019-06-19 12:56:37 -05:00
|
|
|
|
buf_cpy(r->value, reg_params[i].value, reg_params[i].size);
|
|
|
|
|
}
|
2016-11-16 18:12:27 -06:00
|
|
|
|
LOG_DEBUG("restore %s", reg_params[i].reg_name);
|
2021-06-04 07:38:17 -05:00
|
|
|
|
struct reg *r = register_get_by_name(target->reg_cache, reg_params[i].reg_name, false);
|
2021-01-18 14:22:43 -06:00
|
|
|
|
buf_set_u64(buf, 0, info->xlen, saved_regs[r->number]);
|
2019-09-09 14:01:17 -05:00
|
|
|
|
if (r->type->set(r, buf) != ERROR_OK) {
|
|
|
|
|
LOG_ERROR("set(%s) failed", r->name);
|
2016-11-16 18:12:27 -06:00
|
|
|
|
return ERROR_FAIL;
|
2019-09-09 14:01:17 -05:00
|
|
|
|
}
|
2016-11-16 18:12:27 -06:00
|
|
|
|
}
|
|
|
|
|
|
2022-12-02 11:38:40 -06:00
|
|
|
|
/* Read memory parameters from the target memory */
|
|
|
|
|
for (int i = 0; i < num_mem_params; i++) {
|
|
|
|
|
if (mem_params[i].direction == PARAM_IN ||
|
|
|
|
|
mem_params[i].direction == PARAM_IN_OUT) {
|
|
|
|
|
int retval = target_read_buffer(target, mem_params[i].address, mem_params[i].size,
|
|
|
|
|
mem_params[i].value);
|
|
|
|
|
if (retval != ERROR_OK) {
|
|
|
|
|
LOG_ERROR("Couldn't read output mem param from the memory, addr=0x%" TARGET_PRIxADDR " size=0x%" PRIx32,
|
|
|
|
|
mem_params[i].address, mem_params[i].size);
|
|
|
|
|
return retval;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-16 18:12:27 -06:00
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-05 20:00:05 -06:00
|
|
|
|
static int riscv_checksum_memory(struct target *target,
|
2017-06-14 16:13:53 -05:00
|
|
|
|
target_addr_t address, uint32_t count,
|
2017-12-22 16:35:38 -06:00
|
|
|
|
uint32_t *checksum)
|
2017-02-05 20:00:05 -06:00
|
|
|
|
{
|
2019-06-19 12:56:37 -05:00
|
|
|
|
struct working_area *crc_algorithm;
|
|
|
|
|
struct reg_param reg_params[2];
|
|
|
|
|
int retval;
|
|
|
|
|
|
2021-03-03 14:41:03 -06:00
|
|
|
|
LOG_DEBUG("address=0x%" TARGET_PRIxADDR "; count=0x%" PRIx32, address, count);
|
2019-06-19 12:56:37 -05:00
|
|
|
|
|
|
|
|
|
static const uint8_t riscv32_crc_code[] = {
|
2021-10-08 11:43:06 -05:00
|
|
|
|
#include "../../../contrib/loaders/checksum/riscv32_crc.inc"
|
2019-06-19 12:56:37 -05:00
|
|
|
|
};
|
|
|
|
|
static const uint8_t riscv64_crc_code[] = {
|
2021-10-08 11:43:06 -05:00
|
|
|
|
#include "../../../contrib/loaders/checksum/riscv64_crc.inc"
|
2019-06-19 12:56:37 -05:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const uint8_t *crc_code;
|
|
|
|
|
|
2021-03-03 14:41:03 -06:00
|
|
|
|
unsigned xlen = riscv_xlen(target);
|
2019-06-19 12:56:37 -05:00
|
|
|
|
unsigned crc_code_size;
|
|
|
|
|
if (xlen == 32) {
|
|
|
|
|
crc_code = riscv32_crc_code;
|
|
|
|
|
crc_code_size = sizeof(riscv32_crc_code);
|
|
|
|
|
} else {
|
|
|
|
|
crc_code = riscv64_crc_code;
|
|
|
|
|
crc_code_size = sizeof(riscv64_crc_code);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (count < crc_code_size * 4) {
|
|
|
|
|
/* Don't use the algorithm for relatively small buffers. It's faster
|
|
|
|
|
* just to read the memory. target_checksum_memory() will take care of
|
|
|
|
|
* that if we fail. */
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
retval = target_alloc_working_area(target, crc_code_size, &crc_algorithm);
|
|
|
|
|
if (retval != ERROR_OK)
|
|
|
|
|
return retval;
|
|
|
|
|
|
|
|
|
|
if (crc_algorithm->address + crc_algorithm->size > address &&
|
|
|
|
|
crc_algorithm->address < address + count) {
|
|
|
|
|
/* Region to checksum overlaps with the work area we've been assigned.
|
|
|
|
|
* Bail. (Would be better to manually checksum what we read there, and
|
|
|
|
|
* use the algorithm for the rest.) */
|
|
|
|
|
target_free_working_area(target, crc_algorithm);
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
retval = target_write_buffer(target, crc_algorithm->address, crc_code_size,
|
|
|
|
|
crc_code);
|
|
|
|
|
if (retval != ERROR_OK) {
|
|
|
|
|
LOG_ERROR("Failed to write code to " TARGET_ADDR_FMT ": %d",
|
|
|
|
|
crc_algorithm->address, retval);
|
|
|
|
|
target_free_working_area(target, crc_algorithm);
|
|
|
|
|
return retval;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
init_reg_param(®_params[0], "a0", xlen, PARAM_IN_OUT);
|
|
|
|
|
init_reg_param(®_params[1], "a1", xlen, PARAM_OUT);
|
|
|
|
|
buf_set_u64(reg_params[0].value, 0, xlen, address);
|
|
|
|
|
buf_set_u64(reg_params[1].value, 0, xlen, count);
|
|
|
|
|
|
|
|
|
|
/* 20 second timeout/megabyte */
|
|
|
|
|
int timeout = 20000 * (1 + (count / (1024 * 1024)));
|
|
|
|
|
|
|
|
|
|
retval = target_run_algorithm(target, 0, NULL, 2, reg_params,
|
|
|
|
|
crc_algorithm->address,
|
|
|
|
|
0, /* Leave exit point unspecified because we don't know. */
|
|
|
|
|
timeout, NULL);
|
|
|
|
|
|
|
|
|
|
if (retval == ERROR_OK)
|
|
|
|
|
*checksum = buf_get_u32(reg_params[0].value, 0, 32);
|
|
|
|
|
else
|
|
|
|
|
LOG_ERROR("error executing RISC-V CRC algorithm");
|
|
|
|
|
|
|
|
|
|
destroy_reg_param(®_params[0]);
|
|
|
|
|
destroy_reg_param(®_params[1]);
|
|
|
|
|
|
|
|
|
|
target_free_working_area(target, crc_algorithm);
|
|
|
|
|
|
2021-03-03 14:41:03 -06:00
|
|
|
|
LOG_DEBUG("checksum=0x%" PRIx32 ", result=%d", *checksum, retval);
|
2019-06-19 12:56:37 -05:00
|
|
|
|
|
|
|
|
|
return retval;
|
2016-12-07 17:09:35 -06:00
|
|
|
|
}
|
|
|
|
|
|
2017-03-24 20:21:56 -05:00
|
|
|
|
/*** OpenOCD Helper Functions ***/
|
|
|
|
|
|
2022-10-10 12:59:09 -05:00
|
|
|
|
enum riscv_next_action {
|
|
|
|
|
RPH_NONE,
|
|
|
|
|
RPH_RESUME,
|
|
|
|
|
RPH_REMAIN_HALTED
|
2018-03-12 19:26:29 -05:00
|
|
|
|
};
|
2022-10-10 12:59:09 -05:00
|
|
|
|
static int riscv_poll_hart(struct target *target, enum riscv_next_action *next_action)
|
2017-03-24 20:21:56 -05:00
|
|
|
|
{
|
|
|
|
|
RISCV_INFO(r);
|
|
|
|
|
|
2022-09-29 17:09:49 -05:00
|
|
|
|
LOG_TARGET_DEBUG(target, "polling, target->state=%d", target->state);
|
2017-03-24 20:21:56 -05:00
|
|
|
|
|
2022-10-10 12:59:09 -05:00
|
|
|
|
*next_action = RPH_NONE;
|
|
|
|
|
|
|
|
|
|
enum riscv_hart_state previous_riscv_state = 0;
|
|
|
|
|
enum target_state previous_target_state = target->state;
|
|
|
|
|
switch (target->state) {
|
|
|
|
|
case TARGET_UNKNOWN:
|
|
|
|
|
/* Special case, handled further down. */
|
|
|
|
|
previous_riscv_state = RISCV_STATE_UNAVAILABLE; /* Need to assign something. */
|
|
|
|
|
break;
|
|
|
|
|
case TARGET_RUNNING:
|
|
|
|
|
previous_riscv_state = RISCV_STATE_RUNNING;
|
|
|
|
|
break;
|
|
|
|
|
case TARGET_HALTED:
|
|
|
|
|
previous_riscv_state = RISCV_STATE_HALTED;
|
|
|
|
|
break;
|
|
|
|
|
case TARGET_RESET:
|
|
|
|
|
previous_riscv_state = RISCV_STATE_HALTED;
|
|
|
|
|
break;
|
|
|
|
|
case TARGET_DEBUG_RUNNING:
|
|
|
|
|
previous_riscv_state = RISCV_STATE_RUNNING;
|
|
|
|
|
break;
|
|
|
|
|
case TARGET_UNAVAILABLE:
|
|
|
|
|
previous_riscv_state = RISCV_STATE_UNAVAILABLE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-12 19:26:29 -05:00
|
|
|
|
/* If OpenOCD thinks we're running but this hart is halted then it's time
|
2017-03-24 20:21:56 -05:00
|
|
|
|
* to raise an event. */
|
2022-11-10 12:27:04 -06:00
|
|
|
|
enum riscv_hart_state state;
|
|
|
|
|
if (riscv_get_hart_state(target, &state) != ERROR_OK)
|
|
|
|
|
return ERROR_FAIL;
|
2021-10-28 14:52:13 -05:00
|
|
|
|
|
2022-10-10 12:59:09 -05:00
|
|
|
|
if (state == RISCV_STATE_NON_EXISTENT) {
|
|
|
|
|
LOG_TARGET_ERROR(target, "Hart is non-existent!");
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (state == RISCV_STATE_HALTED && timeval_ms() - r->last_activity > 100) {
|
2021-10-28 14:52:13 -05:00
|
|
|
|
/* If we've been idle for a while, flush the register cache. Just in case
|
|
|
|
|
* OpenOCD is going to be disconnected without shutting down cleanly. */
|
|
|
|
|
if (riscv_flush_registers(target) != ERROR_OK)
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-10 12:59:09 -05:00
|
|
|
|
if (target->state == TARGET_UNKNOWN || state != previous_riscv_state) {
|
|
|
|
|
switch (state) {
|
|
|
|
|
case RISCV_STATE_HALTED:
|
|
|
|
|
LOG_TARGET_DEBUG(target, " triggered a halt; previous_target_state=%d",
|
|
|
|
|
previous_target_state);
|
|
|
|
|
target->state = TARGET_HALTED;
|
|
|
|
|
enum riscv_halt_reason halt_reason = riscv_halt_reason(target);
|
|
|
|
|
if (set_debug_reason(target, halt_reason) != ERROR_OK)
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
|
2022-11-21 15:01:03 -06:00
|
|
|
|
if (halt_reason == RISCV_HALT_EBREAK) {
|
2022-10-10 12:59:09 -05:00
|
|
|
|
int retval;
|
|
|
|
|
/* Detect if this EBREAK is a semihosting request. If so, handle it. */
|
|
|
|
|
switch (riscv_semihosting(target, &retval)) {
|
|
|
|
|
case SEMI_NONE:
|
|
|
|
|
break;
|
|
|
|
|
case SEMI_WAITING:
|
|
|
|
|
/* This hart should remain halted. */
|
|
|
|
|
*next_action = RPH_REMAIN_HALTED;
|
|
|
|
|
break;
|
|
|
|
|
case SEMI_HANDLED:
|
|
|
|
|
/* This hart should be resumed, along with any other
|
|
|
|
|
* harts that halted due to haltgroups. */
|
|
|
|
|
*next_action = RPH_RESUME;
|
|
|
|
|
return ERROR_OK;
|
|
|
|
|
case SEMI_ERROR:
|
|
|
|
|
return retval;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
r->on_halt(target);
|
|
|
|
|
|
|
|
|
|
/* We shouldn't do the callbacks yet. What if
|
|
|
|
|
* there are multiple harts that halted at the
|
|
|
|
|
* same time? We need to set debug reason on each
|
|
|
|
|
* of them before calling a callback, which is
|
|
|
|
|
* going to figure out the "current thread". */
|
|
|
|
|
|
|
|
|
|
r->halted_needs_event_callback = true;
|
|
|
|
|
if (previous_target_state == TARGET_DEBUG_RUNNING)
|
|
|
|
|
r->halted_callback_event = TARGET_EVENT_DEBUG_HALTED;
|
|
|
|
|
else
|
|
|
|
|
r->halted_callback_event = TARGET_EVENT_HALTED;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case RISCV_STATE_RUNNING:
|
|
|
|
|
LOG_TARGET_DEBUG(target, " triggered running");
|
|
|
|
|
target->state = TARGET_RUNNING;
|
|
|
|
|
target->debug_reason = DBG_REASON_NOTHALTED;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case RISCV_STATE_UNAVAILABLE:
|
|
|
|
|
LOG_TARGET_DEBUG(target, " became unavailable");
|
|
|
|
|
LOG_TARGET_INFO(target, "became unavailable.");
|
|
|
|
|
target->state = TARGET_UNAVAILABLE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case RISCV_STATE_NON_EXISTENT:
|
|
|
|
|
LOG_TARGET_ERROR(target, "Hart is non-existent!");
|
|
|
|
|
target->state = TARGET_UNAVAILABLE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2017-03-24 20:21:56 -05:00
|
|
|
|
}
|
|
|
|
|
|
2022-10-10 12:59:09 -05:00
|
|
|
|
return ERROR_OK;
|
2017-03-24 20:21:56 -05:00
|
|
|
|
}
|
|
|
|
|
|
2020-10-07 16:31:36 -05:00
|
|
|
|
int sample_memory(struct target *target)
|
|
|
|
|
{
|
|
|
|
|
RISCV_INFO(r);
|
|
|
|
|
|
|
|
|
|
if (!r->sample_buf.buf || !r->sample_config.enabled)
|
|
|
|
|
return ERROR_OK;
|
|
|
|
|
|
|
|
|
|
LOG_DEBUG("buf used/size: %d/%d", r->sample_buf.used, r->sample_buf.size);
|
|
|
|
|
|
|
|
|
|
uint64_t start = timeval_ms();
|
2020-10-21 14:21:05 -05:00
|
|
|
|
riscv_sample_buf_maybe_add_timestamp(target, true);
|
2020-10-07 16:31:36 -05:00
|
|
|
|
int result = ERROR_OK;
|
|
|
|
|
if (r->sample_memory) {
|
|
|
|
|
result = r->sample_memory(target, &r->sample_buf, &r->sample_config,
|
|
|
|
|
start + TARGET_DEFAULT_POLLING_INTERVAL);
|
|
|
|
|
if (result != ERROR_NOT_IMPLEMENTED)
|
|
|
|
|
goto exit;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Default slow path. */
|
|
|
|
|
while (timeval_ms() - start < TARGET_DEFAULT_POLLING_INTERVAL) {
|
2021-09-01 17:00:46 -05:00
|
|
|
|
for (unsigned int i = 0; i < ARRAY_SIZE(r->sample_config.bucket); i++) {
|
2020-10-07 16:31:36 -05:00
|
|
|
|
if (r->sample_config.bucket[i].enabled &&
|
|
|
|
|
r->sample_buf.used + 1 + r->sample_config.bucket[i].size_bytes < r->sample_buf.size) {
|
2020-10-21 14:21:05 -05:00
|
|
|
|
assert(i < RISCV_SAMPLE_BUF_TIMESTAMP_BEFORE);
|
2020-10-07 16:31:36 -05:00
|
|
|
|
r->sample_buf.buf[r->sample_buf.used] = i;
|
|
|
|
|
result = riscv_read_phys_memory(
|
|
|
|
|
target, r->sample_config.bucket[i].address,
|
|
|
|
|
r->sample_config.bucket[i].size_bytes, 1,
|
|
|
|
|
r->sample_buf.buf + r->sample_buf.used + 1);
|
|
|
|
|
if (result == ERROR_OK)
|
|
|
|
|
r->sample_buf.used += 1 + r->sample_config.bucket[i].size_bytes;
|
|
|
|
|
else
|
|
|
|
|
goto exit;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
exit:
|
2020-10-21 14:21:05 -05:00
|
|
|
|
riscv_sample_buf_maybe_add_timestamp(target, false);
|
2020-10-07 16:31:36 -05:00
|
|
|
|
if (result != ERROR_OK) {
|
|
|
|
|
LOG_INFO("Turning off memory sampling because it failed.");
|
|
|
|
|
r->sample_config.enabled = false;
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-24 20:21:56 -05:00
|
|
|
|
/*** OpenOCD Interface ***/
|
|
|
|
|
int riscv_openocd_poll(struct target *target)
|
|
|
|
|
{
|
|
|
|
|
LOG_DEBUG("polling all harts");
|
2020-10-07 16:31:36 -05:00
|
|
|
|
|
2022-10-06 13:42:55 -05:00
|
|
|
|
struct list_head *targets;
|
2019-01-24 17:15:18 -06:00
|
|
|
|
|
2022-10-06 13:42:55 -05:00
|
|
|
|
LIST_HEAD(single_target_list);
|
|
|
|
|
struct target_list single_target_entry = {
|
|
|
|
|
.lh = {NULL, NULL},
|
|
|
|
|
.target = target
|
|
|
|
|
};
|
2020-05-19 12:34:36 -05:00
|
|
|
|
|
2022-10-06 13:42:55 -05:00
|
|
|
|
if (target->smp) {
|
|
|
|
|
targets = target->smp_targets;
|
|
|
|
|
} else {
|
|
|
|
|
/* Make a list that just contains a single target, so we can
|
|
|
|
|
* share code below. */
|
|
|
|
|
list_add(&single_target_entry.lh, &single_target_list);
|
|
|
|
|
targets = &single_target_list;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unsigned should_remain_halted = 0;
|
|
|
|
|
unsigned should_resume = 0;
|
2022-10-10 12:59:09 -05:00
|
|
|
|
unsigned halted = 0;
|
|
|
|
|
unsigned running = 0;
|
|
|
|
|
struct target_list *entry;
|
|
|
|
|
foreach_smp_target(entry, targets) {
|
|
|
|
|
struct target *t = entry->target;
|
|
|
|
|
riscv_info_t *info = riscv_info(t);
|
|
|
|
|
|
|
|
|
|
/* Clear here just in case there were errors and we never got to
|
|
|
|
|
* check this flag further down. */
|
|
|
|
|
info->halted_needs_event_callback = false;
|
|
|
|
|
|
2022-10-06 13:42:55 -05:00
|
|
|
|
if (!target_was_examined(t))
|
|
|
|
|
continue;
|
2019-05-09 13:32:04 -05:00
|
|
|
|
|
2022-10-10 12:59:09 -05:00
|
|
|
|
enum riscv_next_action next_action;
|
|
|
|
|
if (riscv_poll_hart(t, &next_action) != ERROR_OK)
|
2018-03-12 19:26:29 -05:00
|
|
|
|
return ERROR_FAIL;
|
2022-10-10 12:59:09 -05:00
|
|
|
|
|
|
|
|
|
switch (next_action) {
|
|
|
|
|
case RPH_NONE:
|
|
|
|
|
if (t->state == TARGET_HALTED)
|
|
|
|
|
halted++;
|
|
|
|
|
if (t->state == TARGET_RUNNING ||
|
|
|
|
|
t->state == TARGET_DEBUG_RUNNING)
|
|
|
|
|
running++;
|
|
|
|
|
break;
|
|
|
|
|
case RPH_REMAIN_HALTED:
|
|
|
|
|
should_remain_halted++;
|
|
|
|
|
break;
|
|
|
|
|
case RPH_RESUME:
|
|
|
|
|
should_resume++;
|
|
|
|
|
break;
|
2021-09-01 17:00:46 -05:00
|
|
|
|
}
|
2022-10-06 13:42:55 -05:00
|
|
|
|
}
|
2017-03-24 20:21:56 -05:00
|
|
|
|
|
2022-10-06 13:42:55 -05:00
|
|
|
|
LOG_DEBUG("should_remain_halted=%d, should_resume=%d",
|
|
|
|
|
should_remain_halted, should_resume);
|
|
|
|
|
if (should_remain_halted && should_resume) {
|
|
|
|
|
LOG_WARNING("%d harts should remain halted, and %d should resume.",
|
|
|
|
|
should_remain_halted, should_resume);
|
|
|
|
|
}
|
|
|
|
|
if (should_remain_halted) {
|
2022-10-10 12:59:09 -05:00
|
|
|
|
LOG_TARGET_DEBUG(target, "halt all; should_remain_halted=%d",
|
|
|
|
|
should_remain_halted);
|
2022-10-06 13:42:55 -05:00
|
|
|
|
riscv_halt(target);
|
|
|
|
|
} else if (should_resume) {
|
|
|
|
|
LOG_DEBUG("resume all");
|
|
|
|
|
riscv_resume(target, true, 0, 0, 0, false);
|
2022-10-10 12:59:09 -05:00
|
|
|
|
} else if (halted && running) {
|
|
|
|
|
LOG_TARGET_DEBUG(target, "halt all; halted=%d",
|
|
|
|
|
halted);
|
|
|
|
|
riscv_halt(target);
|
|
|
|
|
} else {
|
|
|
|
|
/* For targets that were discovered to be halted, call the
|
|
|
|
|
* appropriate callback. */
|
|
|
|
|
foreach_smp_target(entry, targets)
|
|
|
|
|
{
|
|
|
|
|
struct target *t = entry->target;
|
|
|
|
|
riscv_info_t *info = riscv_info(t);
|
|
|
|
|
if (info->halted_needs_event_callback) {
|
|
|
|
|
target_call_event_callbacks(t, info->halted_callback_event);
|
|
|
|
|
info->halted_needs_event_callback = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-03-24 20:21:56 -05:00
|
|
|
|
}
|
|
|
|
|
|
2022-10-06 13:42:55 -05:00
|
|
|
|
/* Sample memory if any target is running. */
|
2022-10-10 12:59:09 -05:00
|
|
|
|
foreach_smp_target(entry, targets) {
|
|
|
|
|
struct target *t = entry->target;
|
2022-10-06 13:42:55 -05:00
|
|
|
|
if (t->state == TARGET_RUNNING) {
|
|
|
|
|
sample_memory(target);
|
|
|
|
|
break;
|
2020-05-19 12:34:36 -05:00
|
|
|
|
}
|
2018-06-12 10:15:39 -05:00
|
|
|
|
}
|
|
|
|
|
|
2017-03-24 20:21:56 -05:00
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-06 11:32:02 -05:00
|
|
|
|
int riscv_openocd_step(struct target *target, int current,
|
2022-03-01 12:05:54 -06:00
|
|
|
|
target_addr_t address, int handle_breakpoints)
|
2019-05-06 11:32:02 -05:00
|
|
|
|
{
|
2022-10-14 11:40:16 -05:00
|
|
|
|
LOG_TARGET_DEBUG(target, "stepping hart");
|
2017-03-24 20:21:56 -05:00
|
|
|
|
|
2022-10-14 11:40:16 -05:00
|
|
|
|
if (!current) {
|
|
|
|
|
if (riscv_set_register(target, GDB_REGNO_PC, address) != ERROR_OK)
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct breakpoint *breakpoint = NULL;
|
|
|
|
|
/* the front-end may request us not to handle breakpoints */
|
|
|
|
|
if (handle_breakpoints) {
|
|
|
|
|
if (current) {
|
|
|
|
|
if (riscv_get_register(target, &address, GDB_REGNO_PC) != ERROR_OK)
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
|
|
|
|
breakpoint = breakpoint_find(target, address);
|
|
|
|
|
if (breakpoint && (riscv_remove_breakpoint(target, breakpoint) != ERROR_OK))
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
2017-03-24 20:21:56 -05:00
|
|
|
|
|
2020-06-18 16:47:42 -05:00
|
|
|
|
riscv_reg_t trigger_state[RISCV_MAX_HWBPS] = {0};
|
|
|
|
|
if (disable_triggers(target, trigger_state) != ERROR_OK)
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
|
2022-03-01 12:05:54 -06:00
|
|
|
|
bool success = true;
|
|
|
|
|
uint64_t current_mstatus;
|
|
|
|
|
RISCV_INFO(info);
|
|
|
|
|
|
|
|
|
|
if (info->isrmask_mode == RISCV_ISRMASK_STEPONLY) {
|
|
|
|
|
/* Disable Interrupts before stepping. */
|
|
|
|
|
uint64_t irq_disabled_mask = MSTATUS_MIE | MSTATUS_HIE | MSTATUS_SIE | MSTATUS_UIE;
|
|
|
|
|
if (riscv_interrupts_disable(target, irq_disabled_mask,
|
|
|
|
|
¤t_mstatus) != ERROR_OK) {
|
|
|
|
|
success = false;
|
|
|
|
|
LOG_ERROR("unable to disable interrupts");
|
|
|
|
|
goto _exit;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (riscv_step_rtos_hart(target) != ERROR_OK) {
|
|
|
|
|
success = false;
|
2017-03-24 20:21:56 -05:00
|
|
|
|
LOG_ERROR("unable to step rtos hart");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
register_cache_invalidate(target->reg_cache);
|
2020-06-18 16:47:42 -05:00
|
|
|
|
|
2022-03-01 12:05:54 -06:00
|
|
|
|
if (info->isrmask_mode == RISCV_ISRMASK_STEPONLY)
|
|
|
|
|
if (riscv_interrupts_restore(target, current_mstatus) != ERROR_OK) {
|
|
|
|
|
success = false;
|
|
|
|
|
LOG_ERROR("unable to restore interrupts");
|
|
|
|
|
}
|
2020-06-18 16:47:42 -05:00
|
|
|
|
|
2022-03-01 12:05:54 -06:00
|
|
|
|
_exit:
|
|
|
|
|
if (enable_triggers(target, trigger_state) != ERROR_OK) {
|
|
|
|
|
success = false;
|
|
|
|
|
LOG_ERROR("unable to enable triggers");
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-14 11:40:16 -05:00
|
|
|
|
if (breakpoint && (riscv_add_breakpoint(target, breakpoint) != ERROR_OK)) {
|
|
|
|
|
success = false;
|
|
|
|
|
LOG_TARGET_ERROR(target, "unable to restore the disabled breakpoint");
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-01 12:05:54 -06:00
|
|
|
|
if (success) {
|
|
|
|
|
target->state = TARGET_RUNNING;
|
|
|
|
|
target_call_event_callbacks(target, TARGET_EVENT_RESUMED);
|
|
|
|
|
target->state = TARGET_HALTED;
|
|
|
|
|
target->debug_reason = DBG_REASON_SINGLESTEP;
|
|
|
|
|
target_call_event_callbacks(target, TARGET_EVENT_HALTED);
|
|
|
|
|
}
|
|
|
|
|
return success ? ERROR_OK : ERROR_FAIL;
|
2017-03-24 20:21:56 -05:00
|
|
|
|
}
|
|
|
|
|
|
2017-08-15 19:04:59 -05:00
|
|
|
|
/* Command Handlers */
|
2017-10-27 15:15:22 -05:00
|
|
|
|
COMMAND_HANDLER(riscv_set_command_timeout_sec)
|
|
|
|
|
{
|
2017-08-15 19:04:59 -05:00
|
|
|
|
if (CMD_ARGC != 1) {
|
|
|
|
|
LOG_ERROR("Command takes exactly 1 parameter");
|
|
|
|
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
|
|
|
|
}
|
|
|
|
|
int timeout = atoi(CMD_ARGV[0]);
|
2017-12-22 16:35:38 -06:00
|
|
|
|
if (timeout <= 0) {
|
2017-08-15 19:04:59 -05:00
|
|
|
|
LOG_ERROR("%s is not a valid integer argument for command.", CMD_ARGV[0]);
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
riscv_command_timeout_sec = timeout;
|
|
|
|
|
|
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-27 15:15:22 -05:00
|
|
|
|
COMMAND_HANDLER(riscv_set_reset_timeout_sec)
|
|
|
|
|
{
|
2017-08-15 19:04:59 -05:00
|
|
|
|
if (CMD_ARGC != 1) {
|
2017-10-27 15:15:22 -05:00
|
|
|
|
LOG_ERROR("Command takes exactly 1 parameter");
|
|
|
|
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
2017-08-15 19:04:59 -05:00
|
|
|
|
}
|
|
|
|
|
int timeout = atoi(CMD_ARGV[0]);
|
2017-12-22 16:35:38 -06:00
|
|
|
|
if (timeout <= 0) {
|
2017-08-15 19:04:59 -05:00
|
|
|
|
LOG_ERROR("%s is not a valid integer argument for command.", CMD_ARGV[0]);
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
riscv_reset_timeout_sec = timeout;
|
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-19 16:05:35 -05:00
|
|
|
|
COMMAND_HANDLER(riscv_set_prefer_sba)
|
|
|
|
|
{
|
2020-09-10 15:57:51 -05:00
|
|
|
|
struct target *target = get_current_target(CMD_CTX);
|
|
|
|
|
RISCV_INFO(r);
|
|
|
|
|
bool prefer_sba;
|
|
|
|
|
LOG_WARNING("`riscv set_prefer_sba` is deprecated. Please use `riscv set_mem_access` instead.");
|
2018-03-19 16:05:35 -05:00
|
|
|
|
if (CMD_ARGC != 1) {
|
|
|
|
|
LOG_ERROR("Command takes exactly 1 parameter");
|
|
|
|
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
|
|
|
|
}
|
2020-09-10 15:57:51 -05:00
|
|
|
|
COMMAND_PARSE_ON_OFF(CMD_ARGV[0], prefer_sba);
|
|
|
|
|
if (prefer_sba) {
|
|
|
|
|
/* Use system bus with highest priority */
|
|
|
|
|
r->mem_access_methods[0] = RISCV_MEM_ACCESS_SYSBUS;
|
|
|
|
|
r->mem_access_methods[1] = RISCV_MEM_ACCESS_PROGBUF;
|
|
|
|
|
r->mem_access_methods[2] = RISCV_MEM_ACCESS_ABSTRACT;
|
|
|
|
|
} else {
|
|
|
|
|
/* Use progbuf with highest priority */
|
|
|
|
|
r->mem_access_methods[0] = RISCV_MEM_ACCESS_PROGBUF;
|
|
|
|
|
r->mem_access_methods[1] = RISCV_MEM_ACCESS_SYSBUS;
|
|
|
|
|
r->mem_access_methods[2] = RISCV_MEM_ACCESS_ABSTRACT;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Reset warning flags */
|
|
|
|
|
r->mem_access_progbuf_warn = true;
|
|
|
|
|
r->mem_access_sysbus_warn = true;
|
|
|
|
|
r->mem_access_abstract_warn = true;
|
|
|
|
|
|
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
COMMAND_HANDLER(riscv_set_mem_access)
|
|
|
|
|
{
|
|
|
|
|
struct target *target = get_current_target(CMD_CTX);
|
|
|
|
|
RISCV_INFO(r);
|
|
|
|
|
int progbuf_cnt = 0;
|
|
|
|
|
int sysbus_cnt = 0;
|
|
|
|
|
int abstract_cnt = 0;
|
|
|
|
|
|
|
|
|
|
if (CMD_ARGC < 1 || CMD_ARGC > RISCV_NUM_MEM_ACCESS_METHODS) {
|
|
|
|
|
LOG_ERROR("Command takes 1 to %d parameters", RISCV_NUM_MEM_ACCESS_METHODS);
|
|
|
|
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Check argument validity */
|
2021-09-01 17:00:46 -05:00
|
|
|
|
for (unsigned int i = 0; i < CMD_ARGC; i++) {
|
|
|
|
|
if (strcmp("progbuf", CMD_ARGV[i]) == 0) {
|
2020-09-10 15:57:51 -05:00
|
|
|
|
progbuf_cnt++;
|
2021-09-01 17:00:46 -05:00
|
|
|
|
} else if (strcmp("sysbus", CMD_ARGV[i]) == 0) {
|
2020-09-10 15:57:51 -05:00
|
|
|
|
sysbus_cnt++;
|
2021-09-01 17:00:46 -05:00
|
|
|
|
} else if (strcmp("abstract", CMD_ARGV[i]) == 0) {
|
2020-09-10 15:57:51 -05:00
|
|
|
|
abstract_cnt++;
|
2021-09-01 17:00:46 -05:00
|
|
|
|
} else {
|
2020-09-10 15:57:51 -05:00
|
|
|
|
LOG_ERROR("Unknown argument '%s'. "
|
|
|
|
|
"Must be one of: 'progbuf', 'sysbus' or 'abstract'.", CMD_ARGV[i]);
|
|
|
|
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (progbuf_cnt > 1 || sysbus_cnt > 1 || abstract_cnt > 1) {
|
|
|
|
|
LOG_ERROR("Syntax error - duplicate arguments to `riscv set_mem_access`.");
|
|
|
|
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Args are valid, store them */
|
2021-09-01 17:00:46 -05:00
|
|
|
|
for (unsigned int i = 0; i < RISCV_NUM_MEM_ACCESS_METHODS; i++)
|
2020-09-10 15:57:51 -05:00
|
|
|
|
r->mem_access_methods[i] = RISCV_MEM_ACCESS_UNSPECIFIED;
|
2021-09-01 17:00:46 -05:00
|
|
|
|
for (unsigned int i = 0; i < CMD_ARGC; i++) {
|
2020-09-10 15:57:51 -05:00
|
|
|
|
if (strcmp("progbuf", CMD_ARGV[i]) == 0)
|
|
|
|
|
r->mem_access_methods[i] = RISCV_MEM_ACCESS_PROGBUF;
|
|
|
|
|
else if (strcmp("sysbus", CMD_ARGV[i]) == 0)
|
|
|
|
|
r->mem_access_methods[i] = RISCV_MEM_ACCESS_SYSBUS;
|
|
|
|
|
else if (strcmp("abstract", CMD_ARGV[i]) == 0)
|
|
|
|
|
r->mem_access_methods[i] = RISCV_MEM_ACCESS_ABSTRACT;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Reset warning flags */
|
|
|
|
|
r->mem_access_progbuf_warn = true;
|
|
|
|
|
r->mem_access_sysbus_warn = true;
|
|
|
|
|
r->mem_access_abstract_warn = true;
|
|
|
|
|
|
2018-03-19 16:05:35 -05:00
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-18 15:15:28 -05:00
|
|
|
|
COMMAND_HANDLER(riscv_set_enable_virtual)
|
|
|
|
|
{
|
|
|
|
|
if (CMD_ARGC != 1) {
|
|
|
|
|
LOG_ERROR("Command takes exactly 1 parameter");
|
|
|
|
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
|
|
|
|
}
|
|
|
|
|
COMMAND_PARSE_ON_OFF(CMD_ARGV[0], riscv_enable_virtual);
|
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-01 17:00:46 -05:00
|
|
|
|
int parse_ranges(struct list_head *ranges, const char *tcl_arg, const char *reg_type, unsigned int max_val)
|
2017-12-15 15:27:26 -06:00
|
|
|
|
{
|
2020-10-01 13:05:41 -05:00
|
|
|
|
char *args = strdup(tcl_arg);
|
|
|
|
|
if (!args)
|
|
|
|
|
return ERROR_FAIL;
|
2017-12-15 15:27:26 -06:00
|
|
|
|
|
2020-10-01 13:05:41 -05:00
|
|
|
|
/* For backward compatibility, allow multiple parameters within one TCL argument, separated by ',' */
|
|
|
|
|
char *arg = strtok(args, ",");
|
|
|
|
|
while (arg) {
|
2017-12-15 15:27:26 -06:00
|
|
|
|
unsigned low = 0;
|
|
|
|
|
unsigned high = 0;
|
2020-10-01 13:05:41 -05:00
|
|
|
|
char *name = NULL;
|
|
|
|
|
|
|
|
|
|
char *dash = strchr(arg, '-');
|
|
|
|
|
char *equals = strchr(arg, '=');
|
2021-09-01 17:00:46 -05:00
|
|
|
|
unsigned int pos;
|
2020-10-01 13:05:41 -05:00
|
|
|
|
|
|
|
|
|
if (!dash && !equals) {
|
|
|
|
|
/* Expecting single register number. */
|
|
|
|
|
if (sscanf(arg, "%u%n", &low, &pos) != 1 || pos != strlen(arg)) {
|
|
|
|
|
LOG_ERROR("Failed to parse single register number from '%s'.", arg);
|
|
|
|
|
free(args);
|
|
|
|
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
|
|
|
|
}
|
|
|
|
|
} else if (dash && !equals) {
|
|
|
|
|
/* Expecting register range - two numbers separated by a dash: ##-## */
|
|
|
|
|
*dash = 0;
|
|
|
|
|
dash++;
|
|
|
|
|
if (sscanf(arg, "%u%n", &low, &pos) != 1 || pos != strlen(arg)) {
|
|
|
|
|
LOG_ERROR("Failed to parse single register number from '%s'.", arg);
|
|
|
|
|
free(args);
|
|
|
|
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
|
|
|
|
}
|
|
|
|
|
if (sscanf(dash, "%u%n", &high, &pos) != 1 || pos != strlen(dash)) {
|
|
|
|
|
LOG_ERROR("Failed to parse single register number from '%s'.", dash);
|
|
|
|
|
free(args);
|
|
|
|
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
|
|
|
|
}
|
|
|
|
|
if (high < low) {
|
|
|
|
|
LOG_ERROR("Incorrect range encountered [%u, %u].", low, high);
|
|
|
|
|
free(args);
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
|
|
|
|
} else if (!dash && equals) {
|
|
|
|
|
/* Expecting single register number with textual name specified: ##=name */
|
|
|
|
|
*equals = 0;
|
|
|
|
|
equals++;
|
|
|
|
|
if (sscanf(arg, "%u%n", &low, &pos) != 1 || pos != strlen(arg)) {
|
|
|
|
|
LOG_ERROR("Failed to parse single register number from '%s'.", arg);
|
|
|
|
|
free(args);
|
|
|
|
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
2017-12-15 15:27:26 -06:00
|
|
|
|
}
|
|
|
|
|
|
2020-10-01 13:05:41 -05:00
|
|
|
|
name = calloc(1, strlen(equals) + strlen(reg_type) + 2);
|
|
|
|
|
if (!name) {
|
2021-09-01 17:00:46 -05:00
|
|
|
|
LOG_ERROR("Failed to allocate register name.");
|
2020-10-01 13:05:41 -05:00
|
|
|
|
free(args);
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
2017-12-15 15:27:26 -06:00
|
|
|
|
|
2020-10-01 13:05:41 -05:00
|
|
|
|
/* Register prefix: "csr_" or "custom_" */
|
|
|
|
|
strcpy(name, reg_type);
|
|
|
|
|
name[strlen(reg_type)] = '_';
|
|
|
|
|
|
|
|
|
|
if (sscanf(equals, "%[_a-zA-Z0-9]%n", name + strlen(reg_type) + 1, &pos) != 1 || pos != strlen(equals)) {
|
|
|
|
|
LOG_ERROR("Failed to parse register name from '%s'.", equals);
|
|
|
|
|
free(args);
|
|
|
|
|
free(name);
|
|
|
|
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
2017-12-15 15:27:26 -06:00
|
|
|
|
}
|
2020-10-01 13:05:41 -05:00
|
|
|
|
} else {
|
|
|
|
|
LOG_ERROR("Invalid argument '%s'.", arg);
|
|
|
|
|
free(args);
|
|
|
|
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
2017-12-15 15:27:26 -06:00
|
|
|
|
}
|
|
|
|
|
|
2020-10-01 13:05:41 -05:00
|
|
|
|
high = high > low ? high : low;
|
|
|
|
|
|
|
|
|
|
if (high > max_val) {
|
|
|
|
|
LOG_ERROR("Cannot expose %s register number %u, maximum allowed value is %u.", reg_type, high, max_val);
|
|
|
|
|
free(name);
|
|
|
|
|
free(args);
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Check for overlap, name uniqueness. */
|
|
|
|
|
range_list_t *entry;
|
|
|
|
|
list_for_each_entry(entry, ranges, list) {
|
|
|
|
|
if ((entry->low <= high) && (low <= entry->high)) {
|
|
|
|
|
if (low == high)
|
|
|
|
|
LOG_WARNING("Duplicate %s register number - "
|
|
|
|
|
"Register %u has already been exposed previously", reg_type, low);
|
|
|
|
|
else
|
|
|
|
|
LOG_WARNING("Overlapping register ranges - Register range starting from %u overlaps "
|
|
|
|
|
"with already exposed register/range at %u.", low, entry->low);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (entry->name && name && (strcasecmp(entry->name, name) == 0)) {
|
|
|
|
|
LOG_ERROR("Duplicate register name \"%s\" found.", name);
|
|
|
|
|
free(name);
|
|
|
|
|
free(args);
|
2020-09-03 13:57:25 -05:00
|
|
|
|
return ERROR_FAIL;
|
2020-10-01 13:05:41 -05:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
range_list_t *range = calloc(1, sizeof(range_list_t));
|
|
|
|
|
if (!range) {
|
2021-09-01 17:00:46 -05:00
|
|
|
|
LOG_ERROR("Failed to allocate range list.");
|
2020-10-01 13:05:41 -05:00
|
|
|
|
free(name);
|
|
|
|
|
free(args);
|
|
|
|
|
return ERROR_FAIL;
|
2017-12-15 15:27:26 -06:00
|
|
|
|
}
|
2020-10-01 13:05:41 -05:00
|
|
|
|
|
|
|
|
|
range->low = low;
|
|
|
|
|
range->high = high;
|
|
|
|
|
range->name = name;
|
|
|
|
|
list_add(&range->list, ranges);
|
|
|
|
|
|
|
|
|
|
arg = strtok(NULL, ",");
|
2017-12-15 15:27:26 -06:00
|
|
|
|
}
|
2018-08-29 16:22:50 -05:00
|
|
|
|
|
2020-10-01 13:05:41 -05:00
|
|
|
|
free(args);
|
2017-12-15 15:27:26 -06:00
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2018-08-29 16:22:50 -05:00
|
|
|
|
COMMAND_HANDLER(riscv_set_expose_csrs)
|
|
|
|
|
{
|
2020-10-01 13:05:41 -05:00
|
|
|
|
if (CMD_ARGC == 0) {
|
|
|
|
|
LOG_ERROR("Command expects parameters");
|
2018-08-29 16:22:50 -05:00
|
|
|
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-01 13:05:41 -05:00
|
|
|
|
struct target *target = get_current_target(CMD_CTX);
|
|
|
|
|
RISCV_INFO(info);
|
|
|
|
|
int ret = ERROR_OK;
|
|
|
|
|
|
2021-09-01 17:00:46 -05:00
|
|
|
|
for (unsigned int i = 0; i < CMD_ARGC; i++) {
|
2020-10-01 13:05:41 -05:00
|
|
|
|
ret = parse_ranges(&info->expose_csr, CMD_ARGV[i], "csr", 0xfff);
|
|
|
|
|
if (ret != ERROR_OK)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ret;
|
2018-08-29 16:22:50 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
COMMAND_HANDLER(riscv_set_expose_custom)
|
|
|
|
|
{
|
2020-10-01 13:05:41 -05:00
|
|
|
|
if (CMD_ARGC == 0) {
|
|
|
|
|
LOG_ERROR("Command expects parameters");
|
2018-08-29 16:22:50 -05:00
|
|
|
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-01 13:05:41 -05:00
|
|
|
|
struct target *target = get_current_target(CMD_CTX);
|
|
|
|
|
RISCV_INFO(info);
|
|
|
|
|
int ret = ERROR_OK;
|
|
|
|
|
|
2021-09-01 17:00:46 -05:00
|
|
|
|
for (unsigned int i = 0; i < CMD_ARGC; i++) {
|
2020-10-01 13:05:41 -05:00
|
|
|
|
ret = parse_ranges(&info->expose_custom, CMD_ARGV[i], "custom", 0x3fff);
|
|
|
|
|
if (ret != ERROR_OK)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ret;
|
2018-08-29 16:22:50 -05:00
|
|
|
|
}
|
|
|
|
|
|
2023-02-15 11:53:37 -06:00
|
|
|
|
COMMAND_HANDLER(riscv_hide_csrs)
|
|
|
|
|
{
|
|
|
|
|
if (CMD_ARGC == 0) {
|
|
|
|
|
LOG_ERROR("Command expects parameters");
|
|
|
|
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct target *target = get_current_target(CMD_CTX);
|
|
|
|
|
RISCV_INFO(info);
|
|
|
|
|
int ret = ERROR_OK;
|
|
|
|
|
|
|
|
|
|
for (unsigned int i = 0; i < CMD_ARGC; i++) {
|
|
|
|
|
ret = parse_ranges(&info->hide_csr, CMD_ARGV[i], "csr", 0xfff);
|
|
|
|
|
if (ret != ERROR_OK)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-27 11:27:00 -06:00
|
|
|
|
COMMAND_HANDLER(riscv_authdata_read)
|
|
|
|
|
{
|
2021-09-01 17:00:46 -05:00
|
|
|
|
unsigned int index = 0;
|
2021-01-28 11:56:51 -06:00
|
|
|
|
if (CMD_ARGC == 0) {
|
|
|
|
|
/* nop */
|
|
|
|
|
} else if (CMD_ARGC == 1) {
|
|
|
|
|
COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], index);
|
|
|
|
|
} else {
|
|
|
|
|
LOG_ERROR("Command takes at most one parameter");
|
2018-02-27 11:27:00 -06:00
|
|
|
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct target *target = get_current_target(CMD_CTX);
|
|
|
|
|
if (!target) {
|
|
|
|
|
LOG_ERROR("target is NULL!");
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RISCV_INFO(r);
|
|
|
|
|
if (!r) {
|
|
|
|
|
LOG_ERROR("riscv_info is NULL!");
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (r->authdata_read) {
|
|
|
|
|
uint32_t value;
|
2021-01-28 11:56:51 -06:00
|
|
|
|
if (r->authdata_read(target, &value, index) != ERROR_OK)
|
2018-02-27 11:27:00 -06:00
|
|
|
|
return ERROR_FAIL;
|
From upstream (#620)
* cortex_m: use unsigned int for FPB and DWT quantifiers
related quantifiers are:
- fp_num_lit
- fp_num_code
- dwt_num_comp
- dwt_comp_available
Change-Id: I07dec2d4aa21bc0e580be0d9fd0a6809f876c2a8
Signed-off-by: Tarek BOCHKATI <tarek.bouchkati@gmail.com>
Reviewed-on: http://openocd.zylin.com/6185
Tested-by: jenkins
Reviewed-by: Tomas Vanek <vanekt@fbl.cz>
* telnet: allow hiding selected commands during auto-completion
We have TCL procedure and commands that we do not want to show in
the list of auto-completion. E.g. TCL wrappers for deprecated
commands, internal procedures that are not supposed to be exposed
to user, or even commands that the user decides to hide.
Create a TCL procedure to be called by telnet auto-complete code
in place of the hard-coded TCL command. The procedure will run the
same command and will filter-out the unwanted command names.
Initialize the list of commands to be filtered-out with the name
of the TCL procedure above, as it is considered as internal.
Change-Id: I2d83bbf8194502368c589c85cccb617e69128c69
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6194
Tested-by: jenkins
Reviewed-by: Tarek BOCHKATI <tarek.bouchkati@gmail.com>
* telnet/auto-complete: hide deprecated and internal commands
For both:
- TCL proc that redirect deprecated commands to the new commands,
- TCL proc used internally and not supposed to be exposed to user,
add their name to the list of commands that should be hide by the
telnet auto-complete.
Change-Id: I05237c6a79334b7d2b151dfb129fb57b2f40bba6
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6195
Tested-by: jenkins
Reviewed-by: Tarek BOCHKATI <tarek.bouchkati@gmail.com>
* startup.tcl: prepare for jimtcl 0.81 'expr' syntax change
Jimtcl commit 1843b79a03dd ("expr: TIP 526, only support a single
arg") drops the support for multi-argument syntax for the TCL
command 'expr'.
Modify the script startup.tcl compiled-in OpenOCD binary to comply
with the new jimtcl.
Change-Id: I520dcafacadaa289a815035f93f250447ca66ea0
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6158
Tested-by: jenkins
Reviewed-by: Oleksij Rempel <linux@rempel-privat.de>
Reviewed-by: Tomas Vanek <vanekt@fbl.cz>
* tcl: [1/3] prepare for jimtcl 0.81 'expr' syntax change
Jimtcl commit 1843b79a03dd ("expr: TIP 526, only support a single
arg") drops the support for multi-argument syntax for the TCL
command 'expr'.
In the TCL scripts distributed with OpenOCD there are 1700+ lines
that should be modified before switching to jimtcl 0.81.
Apply the script below on every script in tcl folder. It fixes
more than 92% of the lines
%<---%<---%<---%<---%<---%<---%<---%<---%<---%<---%<---%<---%<---
#!/usr/bin/perl -Wpi
my $re_sym = qr{[a-z_][a-z0-9_]*}i;
my $re_var = qr{(?:\$|\$::)$re_sym};
my $re_const = qr{0x[0-9a-f]+|[0-9]+|[0-9]*\.[0-9]*}i;
my $re_item = qr{(?:~\s*)?(?:$re_var|$re_const)};
my $re_op = qr{<<|>>|[+\-*/&|]};
my $re_expr = qr{(
(?:\(\s*(?:$re_item|(?-1))\s*\)|$re_item)
\s*$re_op\s*
(?:$re_item|(?-1)|\(\s*(?:$re_item|(?-1))\s*\))
)}x;
# [expr [dict get $regsC100 SYM] + HEXNUM]
s/\[expr (\[dict get $re_var $re_sym\s*\] \+ *$re_const)\]/\[expr \{$1\}\]/;
# [ expr (EXPR) ]
# [ expr EXPR ]
# note: $re_expr captures '$3'
s/\[(\s*expr\s*)\((\s*$re_expr\s*)\)(\s*)\]/\[$1\{$2\}$4\]/;
s/\[(\s*expr\s*)($re_expr)(\s*)\]/\[$1\{$2\}$4\]/;
%<---%<---%<---%<---%<---%<---%<---%<---%<---%<---%<---%<---%<---
Change-Id: I0d6bddc6abf6dd29062f2b4e72b5a2b5080293b9
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6159
Tested-by: jenkins
Reviewed-by: Tomas Vanek <vanekt@fbl.cz>
* tcl: [2/3] prepare for jimtcl 0.81 'expr' syntax change
Jimtcl commit 1843b79a03dd ("expr: TIP 526, only support a single
arg") drops the support for multi-argument syntax for the TCL
command 'expr'.
Enclose within double quote the argument of 'expr' when there is
the need to concatenate strings.
Change-Id: Ic0ea990ed37337a7e6c3a99670583685b570b8b1
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6160
Tested-by: jenkins
* tcl: [3/3] prepare for jimtcl 0.81 'expr' syntax change
Jimtcl commit 1843b79a03dd ("expr: TIP 526, only support a single
arg") drops the support for multi-argument syntax for the TCL
command 'expr'.
Fix manually the remaining lines that don't match simple patterns
and would require dedicated boring scripting.
Remove the 'expr' command where appropriate.
Change-Id: Ia75210c8447f88d38515addab4a836af9103096d
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6161
Tested-by: jenkins
Reviewed-by: Tomas Vanek <vanekt@fbl.cz>
* target/stm8: Make 'stm8_command_handlers' static
Change-Id: I5237a8f2a1ecba9383672e37bd56f8ccd17598b6
Signed-off-by: Marc Schink <dev@zapb.de>
Reviewed-on: http://openocd.zylin.com/6200
Tested-by: jenkins
Reviewed-by: Tarek BOCHKATI <tarek.bouchkati@gmail.com>
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
* target/riscv: Change 'authdata_read' output
Use a constant output length and remove the line break to make the
authentication data easier to parse.
Change-Id: Iebbf1f171947ef89b0f360a2cb286a4ea15c6ba5
Signed-off-by: Marc Schink <dev@zapb.de>
Reviewed-on: http://openocd.zylin.com/6199
Tested-by: jenkins
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-by: Tim Newsome <tim@sifive.com>
* Enable adapter "Bus Pirate" by default.
The Bus Pirate is now listed in the "OpenOCD configuration summary" too.
Change-Id: Ieb7bf9134af456ebe9803f3108a243204fb2a62d
Signed-off-by: R. Diez <rdiezmail-openocd@yahoo.de>
Reviewed-on: http://openocd.zylin.com/5637
Tested-by: jenkins
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
* coding-style: additional style for C code
To improve readability and to push more uniform code style.
Prefer 'if (false) {...}' for unused code so it get checked by the
compiler.
Define preferred indentation for 'switch' statement.
Require balanced brackets in 'if/else'.
Report the max line length.
Report the formatting strings for stdint/inttypes types.
Report the type 'target_addr_t'.
Prefer 'unsigned int' to 'unsigned'.
Change-Id: I0192a4ed298f6c6c432764fdd156cffd4b13fc89
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6203
Reviewed-by: Tomas Vanek <vanekt@fbl.cz>
Tested-by: jenkins
Reviewed-by: Oleksij Rempel <linux@rempel-privat.de>
Reviewed-by: Tarek BOCHKATI <tarek.bouchkati@gmail.com>
Reviewed-by: Marc Schink <dev@zapb.de>
* Add IPDBG JtagHost functionality to OpenOCD
IPDBG are utilities to debug IP-cores. It uses JTAG for
transport to/from the FPGA. The different UIs use TCP/IP
as transport. The JtagHost makes the bridge between these
two.
Comparable to the bridge between GDB and the in-circuit-
debugging-unit of a micro controller.
Change-Id: Ib1bc10dcbd4ea426e492bb7b2d85c1ed1b7a8d5a
Signed-off-by: Daniel Anselmi <danselmi@gmx.ch>
Reviewed-on: http://openocd.zylin.com/5938
Tested-by: jenkins
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
* flash/nor/xcf: Do not use 'Yoda conditions'
Change-Id: I17308f5237338ce468e5b86289a0634429deaaa9
Signed-off-by: Marc Schink <dev@zapb.de>
Reviewed-on: http://openocd.zylin.com/6201
Tested-by: jenkins
Reviewed-by: Tomas Vanek <vanekt@fbl.cz>
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
* cortex_m: add armv8m special registers
Change-Id: I1942f375a5f4282ad1fe4a2ff3b8f3cbc64d8f7f
Signed-off-by: Tarek BOCHKATI <tarek.bouchkati@gmail.com>
Reviewed-on: http://openocd.zylin.com/6016
Tested-by: jenkins
Reviewed-by: Tomas Vanek <vanekt@fbl.cz>
* rtos: Add support for Zephyr RTOS
With this patch, the Zephyr[1] RTOS is supported by OpenOCD.
As usual with support for other RTOSes, Zephyr must be compiled with
the DEBUG_THREAD_INFO option. This will generate some symbols
with information needed in order to build the list of threads.
The current implementation is limited to Zephyr running on ARM
Cortex-M processors. This is the only ARM variant supported by Zephyr
at the moment and is used on most of the officially supported boards.
[1] https://www.zephyrproject.org/
Change-Id: I22afdbec91562f3a22cf5b88cd4ea3a7a59ba0b4
Signed-off-by: Evgeniy Didin <didin@synopsys.com>
Signed-off-by: Leandro Pereira <leandro.pereira@intel.com>
Signed-off-by: Daniel Glöckner <dg@emlix.com>
Reviewed-on: http://openocd.zylin.com/4988
Tested-by: jenkins
Reviewed-by: Oleksij Rempel <linux@rempel-privat.de>
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
* target/armv7m.h: [style] replace tab with space between variable type and name
Change-Id: I9740c25857295a2a655d3046322a3f23f0ee7f78
Signed-off-by: Tarek BOCHKATI <tarek.bouchkati@gmail.com>
Reviewed-on: http://openocd.zylin.com/6230
Reviewed-by: Marc Schink <dev@zapb.de>
Tested-by: jenkins
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
* server: gdb_server: Add colon for target extended-remote
Both GDB commands "target remote" and "target extended-remote" require
to have ":" right before port number.
e.g.
(gdb) target extended-remote :3333
Add ":" to the warning message so that users can copy & past it.
Change-Id: Id6d8ec1e4dfd3c12cb7f3b314064f2c35fa7ab55
Signed-off-by: Yasushi SHOJI <yashi@spacecubics.com>
Reviewed-on: http://openocd.zylin.com/6237
Reviewed-by: Tarek BOCHKATI <tarek.bouchkati@gmail.com>
Tested-by: jenkins
Reviewed-by: Marc Schink <dev@zapb.de>
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
* jimtcl: restrict memory leak workaround on Linux only
The workaround for jimtcl 0.80 in commit 36ae487ed04b ("jimtcl:
add temporary workaround for memory leak in jimtcl 0.80") issues a
compile time error on macOS:
../src/helper/command.c:157:22: error: aliases are not
supported on darwin
__attribute__((weak, alias("workaround_createcommand")));
The OS is x86_64-apple-darwin19.6.0 and the compiler used is
x86_64-apple-darwin13.4.0-clang.
Restrict the workaround on Linux host only. The fix for 'expr'
syntax change is already merged and the workaround will be dropped
soon.
Change-Id: I925109a9c57c05f8c95b70bc7d6604eb1172cd79
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reported-by: Adam Jeliński <ajelinski@users.sourceforge.net>
Fixes: 36ae487ed04b ("jimtcl: add temporary workaround for memory leak in jimtcl 0.80")
Fixes: https://sourceforge.net/p/openocd/tickets/304/
Reviewed-on: http://openocd.zylin.com/6241
Tested-by: jenkins
* target/armv7m: fix static analyzer warning
Despite of assert(is_packed) clang static analyser complains on use
of the uninitialized offset variable.
Cross compiling with latest x86_64-w64-mingw32-gcc hits warnings
src/target/armv7m.c: In function ‘armv7m_read_core_reg’:
src/target/armv7m.c:337:54: error: ‘reg32_id’ may be used
uninitialized in this function [-Werror=maybe-uninitialized]
It happens because mingw32 defines assert() without the attribute
"noreturn", whatever NDEBUG is defined or not.
Replace assert(is_packed) by if (is_packed) conditional and call
assert(false) in the else branch.
Change-Id: Id3c7dcccb65106e28be200b9a4d2b642f4d31019
Signed-off-by: Tomas Vanek <vanekt@fbl.cz>
Reviewed-on: http://openocd.zylin.com/6256
Tested-by: jenkins
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-by: Tarek BOCHKATI <tarek.bouchkati@gmail.com>
Reviewed-by: Andrzej Sierżęga <asier70@gmail.com>
* cmsis_dap: fix build on macOS
Compile fails with error:
src/jtag/drivers/cmsis_dap.c:683:28: error: format specifies type
'unsigned char' but the argument has type 'int' [-Werror,-Wformat]
" received 0x%" PRIx8, CMD_DAP_TFER, resp[0]);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~
Fix the format specifier.
Change-Id: I0a5a1a35452d634019989d14d849501fb8a7e93a
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6255
Tested-by: jenkins
Reviewed-by: Tomas Vanek <vanekt@fbl.cz>
* cortex_m: do not perform soft_reset_halt on targets without VECTRESET
Change-Id: Ib3df457e0afe4e342c82ad1af25e03aad6979d87
Signed-off-by: Tarek BOCHKATI <tarek.bouchkati@gmail.com>
Reviewed-on: http://openocd.zylin.com/6209
Tested-by: jenkins
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-by: Tomas Vanek <vanekt@fbl.cz>
* cortex_m: fix VECTRESET detection for ARMv6-M cores
VECTRESET check should be done after verifying if the core is an ARMv6-M core,
and not before that.
Fixes: 2dc9c1df81b6 ("cortex_m: [FIX] ARMv8-M does not support VECTRESET")
Change-Id: I8306affd332b3a35cea69bba39ef24ca71244273
Signed-off-by: Tarek BOCHKATI <tarek.bouchkati@gmail.com>
Reviewed-on: http://openocd.zylin.com/6232
Tested-by: jenkins
Reviewed-by: Tomas Vanek <vanekt@fbl.cz>
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
* target/arm_dpm: rename 'wp_pc' as 'wp_addr'
The field 'wp_pc' was originally introduced in commit 55eeea7fceb6
("ARMv7a/Cortex-A8: report watchpoint trigger insn") in end 2009
to contain the address of the instruction which triggered a
watchpoint. Later on with commit 651b861d5d5f ("target/aarch64:
Add watchpoint support") it has been reused in to hold directly
the memory address that triggered a watchpoint.
Rename 'wp_pc' as 'wp_addr' and change its doxygen description.
While there, fix the format string to print the field.
Change-Id: I2e5ced1497e4a6fb6b38f91e881807512e8d8c47
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6204
Tested-by: jenkins
Reviewed-by: Liming Sun <limings@nvidia.com>
* target/aarch64: fix watchpoint management
The early documentation for armv8a report the debug register WFAR
as containing the address of the instruction that triggered the
watchpoint. More recent documentation report the register EDWAR as
containing the data memory address that triggered the watchpoint.
The name of macros CPUV8_DBG_WFAR0 and CPUV8_DBG_WFAR1 is not
correct as they point to the debug register EDWAR, so reading such
register returns directly the data memory address that triggered
the watchpoint. The code incorrectly passes this address value to
the function armv8_dpm_report_wfar(); this function is supposed to
adjust the PC value, decrementing it to remove the effects of the
CPU pipeline. This pipeline offset, that has no meaning on the
value in EDWAR, caused commit 651b861d5d5f ("target/aarch64: Add
watchpoint support") to add back the offset while comparing the
address with the watchpoint enabled.
The upper 32 bits of EDWAR are not valid in aarch32 mode and have
to be ignored.
Rename CPUV8_DBG_WFAR0/1 as CPUV8_DBG_EDWAR0/1.
Remove the function armv8_dpm_report_wfar().
Remove the offset while searching the matching watchpoint.
Ignore the upper 32 bits of EDWAR in aarch32 mode.
Fix a comment and the LOG text.
Change-Id: I7cbdbeb766fa18e31cc72be098ca2bc501877ed1
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6205
Tested-by: jenkins
Reviewed-by: Liming Sun <limings@nvidia.com>
* flash/stm32l4x: add missing break statement
this is not a bug fix, this for loop will issue only one match
adding the break will save unnecessary more loops.
Change-Id: Ic1484ea8cdea1b284eb570f9e3e7818e07daf5cd
Signed-off-by: Tarek BOCHKATI <tarek.bouchkati@gmail.com>
Reviewed-on: http://openocd.zylin.com/6248
Reviewed-by: Oleksij Rempel <linux@rempel-privat.de>
Tested-by: jenkins
* github/action: create a permanent 'latest' release
this commit extends the existing snapshot action to create a release named
'latest' with the built binaries for windows.
this 'latest' release will be updated after every push to github.
Change-Id: I75a64c598169241743add3ac9aa7a0337fbab7f2
Signed-off-by: Tarek BOCHKATI <tarek.bouchkati@gmail.com>
Reviewed-on: http://openocd.zylin.com/6127
Tested-by: jenkins
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
* tcl/rp2040: remove empty line at end of file
Change-Id: I212a96b77282b151a8ecbd46a6436e2bbbda4161
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6221
Tested-by: jenkins
* tcl: fix some minor typo
Minor typos found by the new checkpatch boosted by the dictionary
provided by 'codespell'.
While there, fix one indentation.
Change-Id: I72369ed26f363bacd760b40b8c83dd95e89d28a4
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6214
Tested-by: jenkins
* flash: fix some minor typo
Minor typos found by the new checkpatch boosted by the dictionary
provided by 'codespell'.
Change-Id: Ia5f134c91beb483fd865df9e4877e0ec3e789478
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6215
Tested-by: jenkins
* jtag: fix some minor typo
Minor typos found by the new checkpatch boosted by the dictionary
provided by 'codespell'.
Change-Id: I101c76a638805d77c1ff356cf0f027552389e5d3
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6216
Tested-by: jenkins
* target: fix some minor typo
Minor typos found by the new checkpatch boosted by the dictionary
provided by 'codespell'.
Change-Id: I548581247db72e683249749d1b8725035530b06e
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6217
Tested-by: jenkins
* openocd: fix some minor typo
Minor typos found by the new checkpatch boosted by the dictionary
provided by 'codespell'.
Change-Id: I7b4cae1798ff5ea048fcbc671a397af763fdc605
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6218
Tested-by: jenkins
* Document the buspirate interface driver.
Change-Id: Iaff13fc5187041a840f4f00eb6b4ee52880cf47e
Signed-off-by: R. Diez <rdiezmail-openocd@yahoo.de>
Reviewed-on: http://openocd.zylin.com/6231
Tested-by: jenkins
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
* Warn on undefined preprocessor symbols
Preprocessor directives like "#if SYMBOL" silently replace undefined or
misspelt symbols with 0, which makes configuration bugs hard to spot.
Compiler flag "-Wundef" prevents such errors.
Change-Id: I91b7ba2db02ef0c3c452d334601c53aebda4660e
Signed-off-by: R. Diez <rdiezmail-openocd@yahoo.de>
Reviewed-on: http://openocd.zylin.com/6238
Tested-by: jenkins
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
* Remove compatibility macros m4_ifblank and m4_ifnblank
They are at least since Autoconf 2.67 present,
and we are requiring version 2.69.
Change-Id: I41b33d4ebe02198f03cdddcc4a3c1beedd993d78
Signed-off-by: R. Diez <rdiezmail-openocd@yahoo.de>
Reviewed-on: http://openocd.zylin.com/6239
Tested-by: jenkins
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
* configure.ac: use a separate folder for Autoconf-generated files
Autoconf generates several files in root folder of the project.
Keep the root folder cleaner by specifying subfolder 'build-aux'.
Align .gitignore accordingly.
Signed-off-by: R. Diez <rdiezmail-openocd@yahoo.de>
Change-Id: Ied87faba495d9eeb8f98e78c2e2b7e7e596febfb
Reviewed-on: http://openocd.zylin.com/6236
Tested-by: jenkins
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
* helper/command: silent debug msg on command register/unregister
Commit e216186fab59 ("helper/command: register full-name commands
in jim") and commit a7d68878e4ba ("helper/command: unregister
commands through their full-name") introduce a LOG_DEBUG() message
each for command registration and unregistration.
The messages above are quite noisy and pollute the log when
debug_level is 3 or higher.
They can be useful to debug the command registration logic, but
for the other debug activities on OpenOCD are just noisy.
Already commit a03ac1ba3087 ("helper/command: disable logging of
registered commands [RFC]") was merged to silent the first case
that is now back with additional logs.
Silent both log messages.
Use 'if (false)' to silent them, making easy to re-enable it when
or if someone needs it.
Change-Id: Id8a067e60e822d4ecbddcb036d081298f7e6181f
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6220
Tested-by: jenkins
* mem_ap: fix target arch_info type
The target mem_ap appears as an ARM target, thus it allows the
execution of ARM specific commands causing the crash of OpenOCD.
E.g. 'arm mrc ...' can be executed and segfaults.
Replace the incorrect ARM magic number with a dedicated one.
While there, remove the 'struct arm', that is now holding only the
mem_ap's dap, and replace it with a pointer to the dap.
Change-Id: I881332d3fdf8d8f8271b8711607737b052a5699b
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6213
Tested-by: jenkins
* riscv: drop unused variable
The array newly_halted[] is assigned but its value is never used.
Drop it!
Change-Id: I678812a31c45a3ec03716e3eee6a30b8e8947926
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6257
Tested-by: jenkins
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Tim Newsome <tim@sifive.com>
* riscv: replace macro DIM() with ARRAY_SIZE()
OpenOCD already defines the macro ARRAY_SIZE, while riscv code
uses a local macro DIM.
Prefer using the macro ARRAY_SIZE() instead of DIM().
Not all the riscv code has been upstreamed, yes; this patch only
covers the code already upstreamed.
Change-Id: I89a58a6d91916d85c53ba5e4091b558271f8d618
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6258
Reviewed-by: Xiang W <wxjstz@126.com>
Tested-by: jenkins
Reviewed-by: Tim Newsome <tim@sifive.com>
* target/zynqmp : Add AXI AP access port
The Xilinx Zynq UltraScale+ SoC have an "AXI-AP" access port for direct memory accesses without halting CPUs.
Change-Id: I6303331c217795657575de4759444938e775dee1
Signed-off-by: Olivier DANET <odanet@caramail.com>
Reviewed-on: http://openocd.zylin.com/6263
Reviewed-by: Tarek BOCHKATI <tarek.bouchkati@gmail.com>
Tested-by: jenkins
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
* drivers/versaloon: use ARRAY_SIZE()
Replace the custom macro dimof() with the OpenOCD macro
ARRAY_SIZE().
Change-Id: I2fe638444f6c16f2a78c1fd558b21550f76282d6
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6259
Tested-by: jenkins
Reviewed-by: Xiang W <wxjstz@126.com>
* openocd: use macro ARRAY_SIZE()
There are still few cases where the macro ARRAY_SIZE() should be
used in place of custom code.
Use ARRAY_SIZE() whenever possible.
Change-Id: Iba0127a02357bc704fe639e08562a4f9aa7011df
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6260
Reviewed-by: Xiang W <wxjstz@126.com>
Tested-by: jenkins
* rtos: use ARRAY_SIZE() and simplify rtos_type.create()
Use the existing macro ARRAY_SIZE().
Rewrite the functions rtos_type.create() to simplify the logic.
Change-Id: I8833354767045d1642801d26944c9087a77add00
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6261
Tested-by: jenkins
* tcl: remove remaining deprecated commands
There are still few adapter_khz, ftdi_location, jtag_nsrst_delay
and xds110_serial strolling around ...
Change-Id: I3e8503dcc3875e3c92e6536f3d455a5e448d51ff
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6270
Tested-by: jenkins
* help text: remove trailing space
Some help text end with a useless space character.
Remove it.
Change-Id: I397e1194fac8042f0fab694222f925f906716de3
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6222
Tested-by: jenkins
* help: fix line size in 'usage' output
The implementation of command 'usage' is broken while checking the
line limit of 76 chars per line (e.g. 'usage load_image') and the
line wrapping is not correct. The same broken code is used for the
first output line of command 'help' too.
When call command_help_show_wrap(), include the command's name in
the string so the whole text would be wrapped.
Change-Id: Idece01ce54994db7e851d8522435ff764b11f3ac
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6223
Tested-by: jenkins
* LICENSES: Add the MIT license
Add the full text of the MIT license to the kernel tree. It was copied
directly from:
https://spdx.org/licenses/MIT.html#licenseText
Add the required tags for reference and tooling.
Change-Id: I94a5dea5ced6421809ea2a3448f8dda19a93f5c9
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6219
Tested-by: jenkins
* stlink: add comment of firmware version for each flag bit
Change-Id: I7f7c7b9c9cfd88125f82662ed864a2c0715140b1
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6211
Tested-by: jenkins
* stlink: reorder the flag macro by firmware release
The corresponding bit for each macro is changed, but this is not
relevant in the code.
Change-Id: I7039464f5a3d55d008208f44952aadeb815bd5a3
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6212
Tested-by: jenkins
* tcl/board: Add ST NUCLEO-8S208RB
Change-Id: I384c6ad9b4cbabbc004160677f600d8c4bd3eb71
Signed-off-by: Marc Schink <dev@zapb.de>
Reviewed-on: http://openocd.zylin.com/6268
Tested-by: jenkins
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
* target/arm_adi_v5: Fix clear sticky overrun flag during replay of commands
When a WAIT occurs the commands after the WAIT are replayed and the
STICKYORUN is cleared. However if another WAIT occurs during the
command replay, the command itself is resent but the STICKYORUN bit
shall also be cleared. If this is not done, the MEM-AP hangs.
Change-Id: I14e8340cd5d8f58f4de31509da96cfa2ecb630d1
Signed-off-by: micbis <michele.bisogno.ct@renesas.com>
Reviewed-on: http://openocd.zylin.com/6278
Tested-by: jenkins
Reviewed-by: Matthias Welwarsky <matthias@welwarsky.de>
* target/cortex_a: add support for watchpoints
The current implementation of OpenOCD does not support watchpoints for
cortex_a architecture. So, I replaced the add_watchpoint and
remove_watchpoint with the specific implementation for the
cortex a and using the breakpoint implementation and the arm
documentation [1] as reference. In particular, I have made the
following changes:
* added the following functions
- cortex_a_add_watchpoint
This wrapper function check whether there are any watchpoint
available on the target device by calling cortex_a_set_watchpoint.
- cortex_a_set_watchpoint
This function is responsible for settings the watchpoint register
pair. In particular, it sets the WVR and the WCR registers with
the cortex_a_dap command.
- cortex_a_remove_watchpoint
This wrapper function the selected watchpoint on the target device
by calling cortex_a_unset_watchpoint.
- cortex_a_unset_watchpoint
This function sets both the WVR and the WCR registers to zero, thus
unsetting the watchpoint.
[1]
http://infocenter.arm.com/help/topic/com.arm.doc.ddi0464f/BCGDHIEJ.html
Change-Id: I86611dab474cb84836662af572b17636dc68e282
Signed-off-by: Chengyu Zheng <chengyu.zheng@polimi.it>
Reviewed-on: http://openocd.zylin.com/3913
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-by: Matthias Welwarsky <matthias@welwarsky.de>
Reviewed-by: Marc Schink <dev@zapb.de>
Tested-by: jenkins
* target/cortex_a: fix number of watchpoints
Decrement the available watchpoints only when succeed setting it.
Initialize the available watchpoint with the correct value.
Change-Id: I0f93b347300b8ebedbcd9e718d4ba32b26cf6846
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6196
Tested-by: jenkins
Reviewed-by: Matthias Welwarsky <matthias@welwarsky.de>
* target/cortex_a: add support for watchpoint length of 1, 2 and 4 bytes
Use byte address select for 1 and 2 bytes length.
Use normal mode for 4 bytes length.
Change-Id: I28d182f25145d0635de64d0361d456f1ad96640e
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6197
Tested-by: jenkins
Reviewed-by: Matthias Welwarsky <matthias@welwarsky.de>
* target/cortex_a: fix memory leak on watchpoints
The memory allocated to hold the watchpoints is not freed at
OpenOCD exit.
Free the watchpoint memory at OpenOCD exit.
Change-Id: I518c9ce0dc901cde2913d752e3154734f878b854
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6210
Tested-by: jenkins
Reviewed-by: Matthias Welwarsky <matthias@welwarsky.de>
* helper/jim-nvp: comply with coding style [1/2]
The helper jim-nvp does not comply with OpenOCD coding style due
to typedef of struct and CamelCase symbol names.
While it's trivial fixing the helper and all its current use in
the code, changing these APIs will potentially break a number of
patches pending in gerrit. Gerrit will not trigger any alert, but
the code will generate compile error after the merge.
Add the compile flag "-Wno-error=deprecated-declarations" to keep
as warning (not as error) the use of "deprecated" functions and
types.
Rename all the CamelCase symbols is lowercase and provide struct
prototypes in place of the typedef.
Add a DEPRECATED section to 'jim-nvp.h' where the old CamelCase
symbols and the old typedef are re-declared with compile attribute
'deprecated'.
With this change OpenOCD compiles, but generates warnings.
The remaining changes allover OpenOCD code will be fixed in a
separate patch for easier review.
The patches merged later that still use the old deprecated API
will compile with warnings. This will permit to identify and fix
these cases.
Change-Id: I786385d0f662dbb1be5be313ae42623156d68ce5
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6183
Tested-by: jenkins
Reviewed-by: Marc Schink <dev@zapb.de>
* helper/jim-nvp: comply with coding style [2/2]
With the API fixed to comply with OpenOCD coding style, fix all
the references in the code.
Patch generated automatically with the script below.
The list is in reverse order to replace a common prefix after the
replacement of the symbols with the same prefix.
%<---%<---%<---%<---%<---%<---%<---%<---%<---%<---%<---%<---%<---
(cat << EOF
Jim_SetResult_NvpUnknown jim_set_result_nvp_unknown
Jim_Nvp_value2name_simple jim_nvp_value2name_simple
Jim_Nvp_value2name_obj jim_nvp_value2name_obj
Jim_Nvp_value2name jim_nvp_value2name
Jim_Nvp_name2value_simple jim_nvp_name2value_simple
Jim_Nvp_name2value_obj_nocase jim_nvp_name2value_obj_nocase
Jim_Nvp_name2value_obj jim_nvp_name2value_obj
Jim_Nvp_name2value_nocase_simple jim_nvp_name2value_nocase_simple
Jim_Nvp_name2value_nocase jim_nvp_name2value_nocase
Jim_Nvp_name2value jim_nvp_name2value
Jim_Nvp struct jim_nvp
Jim_GetOpt_Wide jim_getopt_wide
Jim_GetOpt_String jim_getopt_string
Jim_GetOpt_Setup jim_getopt_setup
Jim_GetOpt_Obj jim_getopt_obj
Jim_GetOpt_NvpUnknown jim_getopt_nvp_unknown
Jim_GetOpt_Nvp jim_getopt_nvp
Jim_GetOpt_Enum jim_getopt_enum
Jim_GetOpt_Double jim_getopt_double
Jim_GetOpt_Debug jim_getopt_debug
Jim_GetOptInfo struct jim_getopt_info
Jim_GetNvp jim_get_nvp
Jim_Debug_ArgvString jim_debug_argv_string
EOF
) | while read a b; do
sed -i "s/$a/$b/g" $(find src -type f ! -name jim-nvp.\? )
done
%<---%<---%<---%<---%<---%<---%<---%<---%<---%<---%<---%<---%<---
Change-Id: I10a12bd64bb8b17575fd9150482c989c92b298a2
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6184
Reviewed-by: Marc Schink <dev@zapb.de>
Tested-by: jenkins
* server/telnet: fix autocomplete for jimtcl commands
Current autocomplete filters-out some command reported by "info
commands". One of the filter rule concerns the command's private
data.
Every command registered by OpenOCD has its 'struct command' as
private data.
By ignoring commands without private data, we loose several TCL
commands registered by jimtcl, e.g. 'foreach', 'llength'.
By assuming that every command with non-NULL private data has
'struct command' as private data, we risk at best to access
inconsistent data, at worst to trigger a segmentation fault.
Export the already available functions:
- to check if a command has been registered by OpenOCD and
- to get the private data.
While there, rename jimcmd_is_ocd_command() as
jimcmd_is_oocd_command().
Don't filter-out jimtcl commands with no private data.
Check the private data only on OpenOCD commands.
Change-Id: Ib5bf8d2bc5c12440c0cfae438f637c38724a79b7
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6282
Tested-by: jenkins
Reviewed-by: Tarek BOCHKATI <tarek.bouchkati@gmail.com>
* helper/list.h: align file to Linux v5.12
Main improvement is in the doxygen comments.
Minimize the delta with kernel file.
Skip the functions hlist_unhashed_lockless() and
__list_del_clearprev() that are relevant only in kernel.
Remove gcc extension "omitted conditional operand".
Change-Id: I2e9ddb54cfe2fa5f7cf18f44726acd144e1f98b9
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6276
Reviewed-by: <rdiezmail-openocd@yahoo.de>
Tested-by: jenkins
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
* contrib: add an example of using list.h
Change-Id: Ic3d399d7ad2e4d10677cf78d64968040941b74e5
Signed-off-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6280
Tested-by: jenkins
Reviewed-by: Tim Newsome <tim@sifive.com>
* helper/list.h: add mention to the example in contrib
Without such reference, it could be difficult to find the example.
Change-Id: Ia9ffb06bc1a45446c2c7b53197ab3400e1d8a9e9
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6281
Tested-by: jenkins
Reviewed-by: Tim Newsome <tim@sifive.com>
* tcl/target/stm32f4x: fix hardcoded chip name
Fixes: c945d6e61605 ("tcl/target: start using the new TPIU/SWO support")
Change-Id: I4543c9a204f7b4b3b14e6eabc5042653106aff0e
Signed-off-by: Tarek BOCHKATI <tarek.bouchkati@gmail.com>
Reviewed-on: http://openocd.zylin.com/6277
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
Tested-by: jenkins
* Makefile: add special target .DELETE_ON_ERROR
The special .DELETE_ON_ERROR deletes the target file on recipe error.
Otherwise, an incomplete output file may be considered up to date
the next time around. .DELETE_ON_ERROR provides reasonable
protection at virtually no cost.
Signed-off-by: R. Diez <rdiezmail-openocd@yahoo.de>
Change-Id: I67dca47ae5ddf3786993c87b9991b3046a85f00b
Reviewed-on: http://openocd.zylin.com/6235
Tested-by: jenkins
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
* gdb_server: Log both incoming and outgoing GDB packets
- Made sure that also outgoing GDB packets are logged,
not only the incoming ones.
- Improved the treatment of non-printable characters
in the packets to make it more robust.
Prior to this change:
- Outgoing packets were not printed unless OpenOCD was
re-compiled with _DEBUG_GDB_IO_.
- Non-prinable characters were only treated in incoming
'X' packets.
After this change:
- Both incoming and outgoing GDB packets are logged
on debug_level >= 3, so that both directions of the
GDB channel are visible.
- Non-printable characters are checked for in every packet
so that hey do not interfere with the terminal.
Change-Id: I0613e57ae5059b3279b0abcb71276cf5719a8699
Signed-off-by: Jan Matyas <matyas@codasip.com>
Reviewed-on: http://openocd.zylin.com/6269
Tested-by: jenkins
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
* target/renesas_rz_g2: Introduce tcl config file for RZ/G2 devices
Initial support for Renesas RZ/G2 MPU family
Change-Id: I5ca74cddfd0c105a5307de56c3ade7084f9c28d2
Signed-off-by: micbis <michele.bisogno.ct@renesas.com>
Reviewed-on: http://openocd.zylin.com/6250
Tested-by: jenkins
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
* drivers/jlink: Remove trailing dots
This makes the messages consistent with most of the rest of
the OpenOCD output.
Change-Id: I915a01187e7fc317e02483ac0bbd39ec077d6321
Signed-off-by: Marc Schink <dev@zapb.de>
Reviewed-on: http://openocd.zylin.com/6274
Tested-by: jenkins
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
* target: Use 'bool' for 'reset_halt'
Change-Id: I974a6360ea7467067511541ac212f2e9d3de7895
Signed-off-by: Marc Schink <dev@zapb.de>
Reviewed-on: http://openocd.zylin.com/6262
Tested-by: jenkins
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
* cmsis_dap: add support for swo commands
Replaced mixed snake_case_CamelCase with snake_case.
Define variables at first-use location.
CMSIS-DAP SWO specification:
https://arm-software.github.io/CMSIS_5/DAP/html/group__DAP__swo__gr.html
Change-Id: Ieba79b16efd445143f964b614673d041aae74f92
Signed-off-by: Adrian Negreanu <adrian.negreanu@nxp.com>
Reviewed-on: http://openocd.zylin.com/5820
Tested-by: jenkins
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
* Add target_data_bits().
This is used to compute memory block read alignment, and specifically
allows 64-bit targets to ensure that memory block reads are only
requested on 64-bit boundaries.
Signed-off-by: Tim Newsome <tim@sifive.com>
Change-Id: Idb1a27b9fc02c46245556bb0f3d6d94b368c4817
Reviewed-on: http://openocd.zylin.com/6249
Reviewed-by: Marc Schink <dev@zapb.de>
Tested-by: jenkins
Reviewed-by: Jan Matyas <matyas@codasip.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
* Avoid non-standard conditionals with omitted operands.
Fixes bug #257.
Change-Id: I05fc6468306d46399e769098e031e7e588798afc
Signed-off-by: R. Diez <rdiezmail-openocd@yahoo.de>
Reviewed-on: http://openocd.zylin.com/6271
Tested-by: jenkins
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
* target/startup.tcl: Do not use 'Yoda conditions'
Change-Id: I5e1bbaf032659dda1b365ef4ec6ea4a635d921ce
Signed-off-by: Marc Schink <dev@zapb.de>
Reviewed-on: http://openocd.zylin.com/6284
Tested-by: jenkins
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
* Fix build.
Change-Id: I4f2667db91f84f07af354691aac5d4c9e3aea3fa
Signed-off-by: Tim Newsome <tim@sifive.com>
Co-authored-by: Tarek BOCHKATI <tarek.bouchkati@gmail.com>
Co-authored-by: Antonio Borneo <borneo.antonio@gmail.com>
Co-authored-by: Marc Schink <dev@zapb.de>
Co-authored-by: R. Diez <rdiezmail-openocd@yahoo.de>
Co-authored-by: Daniel Anselmi <danselmi@gmx.ch>
Co-authored-by: Evgeniy Didin <didin@synopsys.com>
Co-authored-by: Yasushi SHOJI <yashi@spacecubics.com>
Co-authored-by: Tomas Vanek <vanekt@fbl.cz>
Co-authored-by: Olivier DANET <odanet@caramail.com>
Co-authored-by: Thomas Gleixner <tglx@linutronix.de>
Co-authored-by: micbis <michele.bisogno.ct@renesas.com>
Co-authored-by: Chengyu Zheng <chengyu.zheng@polimi.it>
Co-authored-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
Co-authored-by: Jan Matyas <matyas@codasip.com>
Co-authored-by: Adrian Negreanu <adrian.negreanu@nxp.com>
2021-06-11 15:01:55 -05:00
|
|
|
|
command_print_sameline(CMD, "0x%08" PRIx32, value);
|
2018-02-27 11:27:00 -06:00
|
|
|
|
return ERROR_OK;
|
|
|
|
|
} else {
|
|
|
|
|
LOG_ERROR("authdata_read is not implemented for this target.");
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
COMMAND_HANDLER(riscv_authdata_write)
|
|
|
|
|
{
|
2021-01-28 11:56:51 -06:00
|
|
|
|
uint32_t value;
|
2021-09-01 17:00:46 -05:00
|
|
|
|
unsigned int index = 0;
|
2021-01-28 11:56:51 -06:00
|
|
|
|
|
|
|
|
|
if (CMD_ARGC == 0) {
|
|
|
|
|
/* nop */
|
|
|
|
|
} else if (CMD_ARGC == 1) {
|
|
|
|
|
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], value);
|
|
|
|
|
} else if (CMD_ARGC == 2) {
|
|
|
|
|
COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], index);
|
|
|
|
|
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value);
|
|
|
|
|
} else {
|
|
|
|
|
LOG_ERROR("Command takes at most 2 arguments");
|
2018-02-27 11:27:00 -06:00
|
|
|
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct target *target = get_current_target(CMD_CTX);
|
|
|
|
|
RISCV_INFO(r);
|
|
|
|
|
|
|
|
|
|
if (r->authdata_write) {
|
2021-01-28 11:56:51 -06:00
|
|
|
|
return r->authdata_write(target, value, index);
|
2018-02-27 11:27:00 -06:00
|
|
|
|
} else {
|
|
|
|
|
LOG_ERROR("authdata_write is not implemented for this target.");
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-06 14:44:53 -06:00
|
|
|
|
COMMAND_HANDLER(riscv_dmi_read)
|
|
|
|
|
{
|
|
|
|
|
if (CMD_ARGC != 1) {
|
|
|
|
|
LOG_ERROR("Command takes 1 parameter");
|
|
|
|
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct target *target = get_current_target(CMD_CTX);
|
|
|
|
|
if (!target) {
|
|
|
|
|
LOG_ERROR("target is NULL!");
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RISCV_INFO(r);
|
|
|
|
|
if (!r) {
|
|
|
|
|
LOG_ERROR("riscv_info is NULL!");
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (r->dmi_read) {
|
|
|
|
|
uint32_t address, value;
|
|
|
|
|
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], address);
|
|
|
|
|
if (r->dmi_read(target, &value, address) != ERROR_OK)
|
|
|
|
|
return ERROR_FAIL;
|
helper/command: change prototype of command_print/command_print_sameline
To prepare for handling TCL return values consistently, all calls
to command_print/command_print_sameline should switch to CMD as
first parameter.
Change prototype of command_print() and command_print_sameline()
to pass CMD instead of CMD_CTX.
Since the first parameter is currently not used, the change can be
done though scripts without manual coding.
This patch is created using the command:
sed -i PATTERN $(find src/ doc/ -type f)
with all the following patters:
's/\(command_print(cmd\)->ctx,/\1,/'
's/\(command_print(CMD\)_CTX,/\1,/'
's/\(command_print(struct command_\)context \*context,/\1invocation *cmd,/'
's/\(command_print_sameline(cmd\)->ctx,/\1,/'
's/\(command_print_sameline(CMD\)_CTX,/\1,/'
's/\(command_print_sameline(struct command_\)context \*context,/\1invocation *cmd,/'
This change is inspired by http://openocd.zylin.com/1815 from Paul
Fertser but is now done through scripting.
Change-Id: I3386d8f96cdc477e7a2308dd18269de3bed04385
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/5081
Tested-by: jenkins
Reviewed-by: Tomas Vanek <vanekt@fbl.cz>
2019-04-03 03:37:24 -05:00
|
|
|
|
command_print(CMD, "0x%" PRIx32, value);
|
2018-03-06 14:44:53 -06:00
|
|
|
|
return ERROR_OK;
|
|
|
|
|
} else {
|
2018-03-06 15:22:57 -06:00
|
|
|
|
LOG_ERROR("dmi_read is not implemented for this target.");
|
2018-03-06 14:44:53 -06:00
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
COMMAND_HANDLER(riscv_dmi_write)
|
|
|
|
|
{
|
|
|
|
|
if (CMD_ARGC != 2) {
|
|
|
|
|
LOG_ERROR("Command takes exactly 2 arguments");
|
|
|
|
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct target *target = get_current_target(CMD_CTX);
|
|
|
|
|
RISCV_INFO(r);
|
|
|
|
|
|
|
|
|
|
uint32_t address, value;
|
|
|
|
|
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], address);
|
|
|
|
|
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value);
|
|
|
|
|
|
|
|
|
|
if (r->dmi_write) {
|
2022-02-11 01:16:10 -06:00
|
|
|
|
/* Perform the DMI write */
|
|
|
|
|
int retval = r->dmi_write(target, address, value);
|
|
|
|
|
|
2022-02-14 07:10:17 -06:00
|
|
|
|
/* Invalidate our cached progbuf copy:
|
|
|
|
|
- if the user tinkered directly with a progbuf register
|
|
|
|
|
- if debug module was reset, in which case progbuf registers
|
|
|
|
|
may not retain their value.
|
|
|
|
|
*/
|
|
|
|
|
bool progbufTouched = (address >= DM_PROGBUF0 && address <= DM_PROGBUF15);
|
|
|
|
|
bool dmDeactivated = (address == DM_DMCONTROL && (value & DM_DMCONTROL_DMACTIVE) == 0);
|
|
|
|
|
if (progbufTouched || dmDeactivated) {
|
2022-02-11 01:16:10 -06:00
|
|
|
|
if (r->invalidate_cached_debug_buffer)
|
|
|
|
|
r->invalidate_cached_debug_buffer(target);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return retval;
|
2018-03-06 14:44:53 -06:00
|
|
|
|
}
|
2022-02-11 01:16:10 -06:00
|
|
|
|
|
|
|
|
|
LOG_ERROR("dmi_write is not implemented for this target.");
|
|
|
|
|
return ERROR_FAIL;
|
2018-03-06 14:44:53 -06:00
|
|
|
|
}
|
|
|
|
|
|
2018-12-04 14:38:51 -06:00
|
|
|
|
COMMAND_HANDLER(riscv_reset_delays)
|
|
|
|
|
{
|
|
|
|
|
int wait = 0;
|
|
|
|
|
|
|
|
|
|
if (CMD_ARGC > 1) {
|
|
|
|
|
LOG_ERROR("Command takes at most one argument");
|
|
|
|
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (CMD_ARGC == 1)
|
|
|
|
|
COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], wait);
|
|
|
|
|
|
|
|
|
|
struct target *target = get_current_target(CMD_CTX);
|
|
|
|
|
RISCV_INFO(r);
|
2019-01-08 15:40:56 -06:00
|
|
|
|
r->reset_delays_wait = wait;
|
|
|
|
|
return ERROR_OK;
|
2018-12-04 14:38:51 -06:00
|
|
|
|
}
|
|
|
|
|
|
2019-01-08 12:30:26 -06:00
|
|
|
|
COMMAND_HANDLER(riscv_set_ir)
|
|
|
|
|
{
|
|
|
|
|
if (CMD_ARGC != 2) {
|
|
|
|
|
LOG_ERROR("Command takes exactly 2 arguments");
|
|
|
|
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint32_t value;
|
|
|
|
|
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value);
|
|
|
|
|
|
2019-07-15 12:32:28 -05:00
|
|
|
|
if (!strcmp(CMD_ARGV[0], "idcode"))
|
2019-01-08 12:30:26 -06:00
|
|
|
|
buf_set_u32(ir_idcode, 0, 32, value);
|
2019-07-15 12:32:28 -05:00
|
|
|
|
else if (!strcmp(CMD_ARGV[0], "dtmcs"))
|
2019-01-08 12:30:26 -06:00
|
|
|
|
buf_set_u32(ir_dtmcontrol, 0, 32, value);
|
2019-07-15 12:32:28 -05:00
|
|
|
|
else if (!strcmp(CMD_ARGV[0], "dmi"))
|
2019-01-08 12:30:26 -06:00
|
|
|
|
buf_set_u32(ir_dbus, 0, 32, value);
|
2019-07-15 12:32:28 -05:00
|
|
|
|
else
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
|
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
COMMAND_HANDLER(riscv_resume_order)
|
|
|
|
|
{
|
|
|
|
|
if (CMD_ARGC > 1) {
|
|
|
|
|
LOG_ERROR("Command takes at most one argument");
|
|
|
|
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!strcmp(CMD_ARGV[0], "normal")) {
|
|
|
|
|
resume_order = RO_NORMAL;
|
|
|
|
|
} else if (!strcmp(CMD_ARGV[0], "reversed")) {
|
|
|
|
|
resume_order = RO_REVERSED;
|
2019-01-08 12:30:26 -06:00
|
|
|
|
} else {
|
2019-07-15 12:32:28 -05:00
|
|
|
|
LOG_ERROR("Unsupported resume order: %s", CMD_ARGV[0]);
|
2019-01-08 12:30:26 -06:00
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
2019-07-15 12:32:28 -05:00
|
|
|
|
|
|
|
|
|
return ERROR_OK;
|
2019-01-08 12:30:26 -06:00
|
|
|
|
}
|
|
|
|
|
|
2019-04-23 18:25:22 -05:00
|
|
|
|
COMMAND_HANDLER(riscv_use_bscan_tunnel)
|
|
|
|
|
{
|
|
|
|
|
int irwidth = 0;
|
2019-06-10 15:33:50 -05:00
|
|
|
|
int tunnel_type = BSCAN_TUNNEL_NESTED_TAP;
|
2019-04-23 18:25:22 -05:00
|
|
|
|
|
2019-06-10 15:33:50 -05:00
|
|
|
|
if (CMD_ARGC > 2) {
|
|
|
|
|
LOG_ERROR("Command takes at most two arguments");
|
2019-04-23 18:25:22 -05:00
|
|
|
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
2019-06-10 15:33:50 -05:00
|
|
|
|
} else if (CMD_ARGC == 1) {
|
2019-04-23 18:25:22 -05:00
|
|
|
|
COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], irwidth);
|
2019-06-10 15:33:50 -05:00
|
|
|
|
} else if (CMD_ARGC == 2) {
|
|
|
|
|
COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], irwidth);
|
|
|
|
|
COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], tunnel_type);
|
|
|
|
|
}
|
|
|
|
|
if (tunnel_type == BSCAN_TUNNEL_NESTED_TAP)
|
|
|
|
|
LOG_INFO("Nested Tap based Bscan Tunnel Selected");
|
|
|
|
|
else if (tunnel_type == BSCAN_TUNNEL_DATA_REGISTER)
|
|
|
|
|
LOG_INFO("Simple Register based Bscan Tunnel Selected");
|
|
|
|
|
else
|
|
|
|
|
LOG_INFO("Invalid Tunnel type selected ! : selecting default Nested Tap Type");
|
2019-04-23 18:25:22 -05:00
|
|
|
|
|
2019-06-10 15:33:50 -05:00
|
|
|
|
bscan_tunnel_type = tunnel_type;
|
2019-04-23 18:25:22 -05:00
|
|
|
|
bscan_tunnel_ir_width = irwidth;
|
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-20 12:16:47 -05:00
|
|
|
|
COMMAND_HANDLER(riscv_set_bscan_tunnel_ir)
|
|
|
|
|
{
|
|
|
|
|
int ir_id = 0;
|
|
|
|
|
|
|
|
|
|
if (CMD_ARGC > 1) {
|
|
|
|
|
LOG_ERROR("Command takes at most one arguments");
|
|
|
|
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
|
|
|
|
} else if (CMD_ARGC == 1) {
|
|
|
|
|
COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], ir_id);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LOG_INFO("Bscan tunnel IR 0x%x selected", ir_id);
|
|
|
|
|
|
|
|
|
|
bscan_tunnel_ir_id = ir_id;
|
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2022-03-01 12:05:54 -06:00
|
|
|
|
COMMAND_HANDLER(riscv_set_maskisr)
|
|
|
|
|
{
|
|
|
|
|
struct target *target = get_current_target(CMD_CTX);
|
|
|
|
|
RISCV_INFO(info);
|
|
|
|
|
|
|
|
|
|
static const struct jim_nvp nvp_maskisr_modes[] = {
|
|
|
|
|
{ .name = "off", .value = RISCV_ISRMASK_OFF },
|
|
|
|
|
{ .name = "steponly", .value = RISCV_ISRMASK_STEPONLY },
|
|
|
|
|
{ .name = NULL, .value = -1 },
|
|
|
|
|
};
|
|
|
|
|
const struct jim_nvp *n;
|
|
|
|
|
|
|
|
|
|
if (CMD_ARGC > 0) {
|
|
|
|
|
n = jim_nvp_name2value_simple(nvp_maskisr_modes, CMD_ARGV[0]);
|
|
|
|
|
if (!n->name)
|
|
|
|
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
|
|
|
|
info->isrmask_mode = n->value;
|
|
|
|
|
} else {
|
|
|
|
|
n = jim_nvp_value2name_simple(nvp_maskisr_modes, info->isrmask_mode);
|
|
|
|
|
command_print(CMD, "riscv interrupt mask %s", n->name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-10 14:18:03 -06:00
|
|
|
|
COMMAND_HANDLER(riscv_set_enable_virt2phys)
|
|
|
|
|
{
|
|
|
|
|
if (CMD_ARGC != 1) {
|
|
|
|
|
LOG_ERROR("Command takes exactly 1 parameter");
|
|
|
|
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
|
|
|
|
}
|
|
|
|
|
COMMAND_PARSE_ON_OFF(CMD_ARGV[0], riscv_enable_virt2phys);
|
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-20 15:58:15 -06:00
|
|
|
|
COMMAND_HANDLER(riscv_set_ebreakm)
|
|
|
|
|
{
|
|
|
|
|
if (CMD_ARGC != 1) {
|
|
|
|
|
LOG_ERROR("Command takes exactly 1 parameter");
|
|
|
|
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
|
|
|
|
}
|
|
|
|
|
COMMAND_PARSE_ON_OFF(CMD_ARGV[0], riscv_ebreakm);
|
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
COMMAND_HANDLER(riscv_set_ebreaks)
|
|
|
|
|
{
|
|
|
|
|
if (CMD_ARGC != 1) {
|
|
|
|
|
LOG_ERROR("Command takes exactly 1 parameter");
|
|
|
|
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
|
|
|
|
}
|
|
|
|
|
COMMAND_PARSE_ON_OFF(CMD_ARGV[0], riscv_ebreaks);
|
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
COMMAND_HANDLER(riscv_set_ebreaku)
|
|
|
|
|
{
|
|
|
|
|
if (CMD_ARGC != 1) {
|
|
|
|
|
LOG_ERROR("Command takes exactly 1 parameter");
|
|
|
|
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
|
|
|
|
}
|
|
|
|
|
COMMAND_PARSE_ON_OFF(CMD_ARGV[0], riscv_ebreaku);
|
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-18 17:57:17 -06:00
|
|
|
|
COMMAND_HANDLER(riscv_itrigger)
|
|
|
|
|
{
|
|
|
|
|
if (CMD_ARGC < 1) {
|
|
|
|
|
LOG_ERROR("Command takes at least 1 parameter");
|
|
|
|
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct target *target = get_current_target(CMD_CTX);
|
|
|
|
|
const int ITRIGGER_UNIQUE_ID = -CSR_TDATA1_TYPE_ITRIGGER;
|
|
|
|
|
|
|
|
|
|
if (riscv_enumerate_triggers(target) != ERROR_OK)
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
|
|
|
|
|
if (!strcmp(CMD_ARGV[0], "set")) {
|
|
|
|
|
if (find_first_trigger_by_id(target, ITRIGGER_UNIQUE_ID) >= 0) {
|
|
|
|
|
LOG_TARGET_ERROR(target, "An itrigger is already set, and OpenOCD "
|
|
|
|
|
"doesn't support setting more than one at a time.");
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
|
|
|
|
bool vs = false;
|
|
|
|
|
bool vu = false;
|
|
|
|
|
bool nmi = false;
|
|
|
|
|
bool m = false;
|
|
|
|
|
bool s = false;
|
|
|
|
|
bool u = false;
|
|
|
|
|
riscv_reg_t interrupts = 0;
|
|
|
|
|
|
|
|
|
|
for (unsigned int i = 1; i < CMD_ARGC; i++) {
|
|
|
|
|
if (!strcmp(CMD_ARGV[i], "vs"))
|
|
|
|
|
vs = true;
|
|
|
|
|
else if (!strcmp(CMD_ARGV[i], "vu"))
|
|
|
|
|
vu = true;
|
|
|
|
|
else if (!strcmp(CMD_ARGV[i], "nmi"))
|
|
|
|
|
nmi = true;
|
|
|
|
|
else if (!strcmp(CMD_ARGV[i], "m"))
|
|
|
|
|
m = true;
|
|
|
|
|
else if (!strcmp(CMD_ARGV[i], "s"))
|
|
|
|
|
s = true;
|
|
|
|
|
else if (!strcmp(CMD_ARGV[i], "u"))
|
|
|
|
|
u = true;
|
|
|
|
|
else
|
|
|
|
|
COMMAND_PARSE_NUMBER(u64, CMD_ARGV[i], interrupts);
|
|
|
|
|
}
|
|
|
|
|
if (!nmi && interrupts == 0) {
|
|
|
|
|
LOG_ERROR("Doesn't make sense to set itrigger with "
|
|
|
|
|
"mie_bits=0 and without nmi.");
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
} else if (!vs && !vu && !m && !s && !u) {
|
|
|
|
|
LOG_ERROR("Doesn't make sense to set itrigger without at "
|
|
|
|
|
"least one of vs, vu, m, s, or u.");
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
|
|
|
|
int result = maybe_add_trigger_t4(target, vs, vu, nmi, m, s, u, interrupts, ITRIGGER_UNIQUE_ID);
|
|
|
|
|
if (result != ERROR_OK)
|
|
|
|
|
LOG_TARGET_ERROR(target, "Failed to set requested itrigger.");
|
|
|
|
|
return result;
|
|
|
|
|
|
|
|
|
|
} else if (!strcmp(CMD_ARGV[0], "clear")) {
|
|
|
|
|
if (CMD_ARGC != 1) {
|
|
|
|
|
LOG_ERROR("clear command takes no extra arguments.");
|
|
|
|
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
|
|
|
|
}
|
|
|
|
|
if (find_first_trigger_by_id(target, ITRIGGER_UNIQUE_ID) < 0) {
|
|
|
|
|
LOG_TARGET_ERROR(target, "No itrigger is set. Nothing to clear.");
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
|
|
|
|
return remove_trigger(target, ITRIGGER_UNIQUE_ID);
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
LOG_ERROR("First argument must be either 'set' or 'clear'.");
|
|
|
|
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
|
|
|
|
}
|
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-28 13:47:50 -06:00
|
|
|
|
COMMAND_HANDLER(riscv_etrigger)
|
|
|
|
|
{
|
|
|
|
|
if (CMD_ARGC < 1) {
|
|
|
|
|
LOG_ERROR("Command takes at least 1 parameter");
|
|
|
|
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct target *target = get_current_target(CMD_CTX);
|
|
|
|
|
const int ETRIGGER_UNIQUE_ID = -CSR_TDATA1_TYPE_ETRIGGER;
|
|
|
|
|
|
|
|
|
|
if (riscv_enumerate_triggers(target) != ERROR_OK)
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
|
|
|
|
|
if (!strcmp(CMD_ARGV[0], "set")) {
|
|
|
|
|
if (find_first_trigger_by_id(target, ETRIGGER_UNIQUE_ID) >= 0) {
|
|
|
|
|
LOG_TARGET_ERROR(target, "An etrigger is already set, and OpenOCD "
|
|
|
|
|
"doesn't support setting more than one at a time.");
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
|
|
|
|
bool vs = false;
|
|
|
|
|
bool vu = false;
|
|
|
|
|
bool m = false;
|
|
|
|
|
bool s = false;
|
|
|
|
|
bool u = false;
|
|
|
|
|
riscv_reg_t exception_codes = 0;
|
|
|
|
|
|
|
|
|
|
for (unsigned int i = 1; i < CMD_ARGC; i++) {
|
|
|
|
|
if (!strcmp(CMD_ARGV[i], "vs"))
|
|
|
|
|
vs = true;
|
|
|
|
|
else if (!strcmp(CMD_ARGV[i], "vu"))
|
|
|
|
|
vu = true;
|
|
|
|
|
else if (!strcmp(CMD_ARGV[i], "m"))
|
|
|
|
|
m = true;
|
|
|
|
|
else if (!strcmp(CMD_ARGV[i], "s"))
|
|
|
|
|
s = true;
|
|
|
|
|
else if (!strcmp(CMD_ARGV[i], "u"))
|
|
|
|
|
u = true;
|
|
|
|
|
else
|
|
|
|
|
COMMAND_PARSE_NUMBER(u64, CMD_ARGV[i], exception_codes);
|
|
|
|
|
}
|
|
|
|
|
if (exception_codes == 0) {
|
|
|
|
|
LOG_ERROR("Doesn't make sense to set etrigger with "
|
|
|
|
|
"exception_codes=0.");
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
} else if (!vs && !vu && !m && !s && !u) {
|
|
|
|
|
LOG_ERROR("Doesn't make sense to set etrigger without at "
|
|
|
|
|
"least one of vs, vu, m, s, or u.");
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
|
|
|
|
int result = maybe_add_trigger_t5(target, vs, vu, m, s, u, exception_codes, ETRIGGER_UNIQUE_ID);
|
|
|
|
|
if (result != ERROR_OK)
|
|
|
|
|
LOG_TARGET_ERROR(target, "Failed to set requested etrigger.");
|
|
|
|
|
return result;
|
|
|
|
|
|
|
|
|
|
} else if (!strcmp(CMD_ARGV[0], "clear")) {
|
|
|
|
|
if (CMD_ARGC != 1) {
|
|
|
|
|
LOG_ERROR("clear command takes no extra arguments.");
|
|
|
|
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
|
|
|
|
}
|
|
|
|
|
if (find_first_trigger_by_id(target, ETRIGGER_UNIQUE_ID) < 0) {
|
|
|
|
|
LOG_TARGET_ERROR(target, "No etrigger is set. Nothing to clear.");
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
|
|
|
|
return remove_trigger(target, ETRIGGER_UNIQUE_ID);
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
LOG_ERROR("First argument must be either 'set' or 'clear'.");
|
|
|
|
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
|
|
|
|
}
|
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-18 13:01:41 -05:00
|
|
|
|
COMMAND_HANDLER(handle_repeat_read)
|
|
|
|
|
{
|
|
|
|
|
struct target *target = get_current_target(CMD_CTX);
|
|
|
|
|
RISCV_INFO(r);
|
|
|
|
|
|
|
|
|
|
if (CMD_ARGC < 2) {
|
|
|
|
|
LOG_ERROR("Command requires at least count and address arguments.");
|
|
|
|
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
|
|
|
|
}
|
|
|
|
|
if (CMD_ARGC > 3) {
|
|
|
|
|
LOG_ERROR("Command takes at most 3 arguments.");
|
|
|
|
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint32_t count;
|
|
|
|
|
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], count);
|
|
|
|
|
target_addr_t address;
|
|
|
|
|
COMMAND_PARSE_ADDRESS(CMD_ARGV[1], address);
|
|
|
|
|
uint32_t size = 4;
|
|
|
|
|
if (CMD_ARGC > 2)
|
|
|
|
|
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], size);
|
|
|
|
|
|
|
|
|
|
if (count == 0)
|
|
|
|
|
return ERROR_OK;
|
|
|
|
|
|
|
|
|
|
uint8_t *buffer = malloc(size * count);
|
|
|
|
|
if (!buffer) {
|
|
|
|
|
LOG_ERROR("malloc failed");
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
|
|
|
|
int result = r->read_memory(target, address, size, count, buffer, 0);
|
|
|
|
|
if (result == ERROR_OK) {
|
|
|
|
|
target_handle_md_output(cmd, target, address, size, count, buffer,
|
|
|
|
|
false);
|
|
|
|
|
}
|
|
|
|
|
free(buffer);
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-07 16:31:36 -05:00
|
|
|
|
COMMAND_HANDLER(handle_memory_sample_command)
|
|
|
|
|
{
|
|
|
|
|
struct target *target = get_current_target(CMD_CTX);
|
|
|
|
|
RISCV_INFO(r);
|
|
|
|
|
|
|
|
|
|
if (CMD_ARGC == 0) {
|
|
|
|
|
command_print(CMD, "Memory sample configuration for %s:", target_name(target));
|
2021-05-16 06:53:10 -05:00
|
|
|
|
for (unsigned i = 0; i < ARRAY_SIZE(r->sample_config.bucket); i++) {
|
2020-10-07 16:31:36 -05:00
|
|
|
|
if (r->sample_config.bucket[i].enabled) {
|
|
|
|
|
command_print(CMD, "bucket %d; address=0x%" TARGET_PRIxADDR "; size=%d", i,
|
|
|
|
|
r->sample_config.bucket[i].address,
|
|
|
|
|
r->sample_config.bucket[i].size_bytes);
|
|
|
|
|
} else {
|
|
|
|
|
command_print(CMD, "bucket %d; disabled", i);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (CMD_ARGC < 2) {
|
|
|
|
|
LOG_ERROR("Command requires at least bucket and address arguments.");
|
|
|
|
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint32_t bucket;
|
|
|
|
|
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], bucket);
|
2021-05-16 06:53:10 -05:00
|
|
|
|
if (bucket > ARRAY_SIZE(r->sample_config.bucket)) {
|
|
|
|
|
LOG_ERROR("Max bucket number is %d.", (unsigned) ARRAY_SIZE(r->sample_config.bucket));
|
2020-10-07 16:31:36 -05:00
|
|
|
|
return ERROR_COMMAND_ARGUMENT_INVALID;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!strcmp(CMD_ARGV[1], "clear")) {
|
|
|
|
|
r->sample_config.bucket[bucket].enabled = false;
|
|
|
|
|
} else {
|
|
|
|
|
COMMAND_PARSE_ADDRESS(CMD_ARGV[1], r->sample_config.bucket[bucket].address);
|
|
|
|
|
|
|
|
|
|
if (CMD_ARGC > 2) {
|
|
|
|
|
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], r->sample_config.bucket[bucket].size_bytes);
|
|
|
|
|
if (r->sample_config.bucket[bucket].size_bytes != 4 &&
|
|
|
|
|
r->sample_config.bucket[bucket].size_bytes != 8) {
|
|
|
|
|
LOG_ERROR("Only 4-byte and 8-byte sizes are supported.");
|
|
|
|
|
return ERROR_COMMAND_ARGUMENT_INVALID;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
r->sample_config.bucket[bucket].size_bytes = 4;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
r->sample_config.bucket[bucket].enabled = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!r->sample_buf.buf) {
|
|
|
|
|
r->sample_buf.size = 1024 * 1024;
|
|
|
|
|
r->sample_buf.buf = malloc(r->sample_buf.size);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Clear the buffer when the configuration is changed. */
|
|
|
|
|
r->sample_buf.used = 0;
|
|
|
|
|
|
|
|
|
|
r->sample_config.enabled = true;
|
|
|
|
|
|
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
COMMAND_HANDLER(handle_dump_sample_buf_command)
|
|
|
|
|
{
|
|
|
|
|
struct target *target = get_current_target(CMD_CTX);
|
|
|
|
|
RISCV_INFO(r);
|
|
|
|
|
|
|
|
|
|
if (CMD_ARGC > 1) {
|
|
|
|
|
LOG_ERROR("Command takes at most 1 arguments.");
|
|
|
|
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
|
|
|
|
}
|
|
|
|
|
bool base64 = false;
|
|
|
|
|
if (CMD_ARGC > 0) {
|
|
|
|
|
if (!strcmp(CMD_ARGV[0], "base64")) {
|
|
|
|
|
base64 = true;
|
|
|
|
|
} else {
|
|
|
|
|
LOG_ERROR("Unknown argument: %s", CMD_ARGV[0]);
|
|
|
|
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int result = ERROR_OK;
|
|
|
|
|
if (base64) {
|
|
|
|
|
unsigned char *encoded = base64_encode(r->sample_buf.buf,
|
|
|
|
|
r->sample_buf.used, NULL);
|
|
|
|
|
if (!encoded) {
|
|
|
|
|
LOG_ERROR("Failed base64 encode!");
|
|
|
|
|
result = ERROR_FAIL;
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
command_print(CMD, "%s", encoded);
|
|
|
|
|
free(encoded);
|
|
|
|
|
} else {
|
|
|
|
|
unsigned i = 0;
|
|
|
|
|
while (i < r->sample_buf.used) {
|
|
|
|
|
uint8_t command = r->sample_buf.buf[i++];
|
2020-10-21 14:21:05 -05:00
|
|
|
|
if (command == RISCV_SAMPLE_BUF_TIMESTAMP_BEFORE) {
|
|
|
|
|
uint32_t timestamp = buf_get_u32(r->sample_buf.buf + i, 0, 32);
|
|
|
|
|
i += 4;
|
|
|
|
|
command_print(CMD, "timestamp before: %u", timestamp);
|
|
|
|
|
} else if (command == RISCV_SAMPLE_BUF_TIMESTAMP_AFTER) {
|
2020-10-07 16:31:36 -05:00
|
|
|
|
uint32_t timestamp = buf_get_u32(r->sample_buf.buf + i, 0, 32);
|
|
|
|
|
i += 4;
|
2020-10-21 14:21:05 -05:00
|
|
|
|
command_print(CMD, "timestamp after: %u", timestamp);
|
2021-05-16 06:53:10 -05:00
|
|
|
|
} else if (command < ARRAY_SIZE(r->sample_config.bucket)) {
|
2020-10-07 16:31:36 -05:00
|
|
|
|
command_print_sameline(CMD, "0x%" TARGET_PRIxADDR ": ",
|
|
|
|
|
r->sample_config.bucket[command].address);
|
|
|
|
|
if (r->sample_config.bucket[command].size_bytes == 4) {
|
|
|
|
|
uint32_t value = buf_get_u32(r->sample_buf.buf + i, 0, 32);
|
|
|
|
|
i += 4;
|
|
|
|
|
command_print(CMD, "0x%08" PRIx32, value);
|
|
|
|
|
} else if (r->sample_config.bucket[command].size_bytes == 8) {
|
|
|
|
|
uint64_t value = buf_get_u64(r->sample_buf.buf + i, 0, 64);
|
|
|
|
|
i += 8;
|
|
|
|
|
command_print(CMD, "0x%016" PRIx64, value);
|
|
|
|
|
} else {
|
|
|
|
|
LOG_ERROR("Found invalid size in bucket %d: %d", command,
|
|
|
|
|
r->sample_config.bucket[command].size_bytes);
|
|
|
|
|
result = ERROR_FAIL;
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
LOG_ERROR("Found invalid command byte in sample buf: 0x%2x at offset 0x%x",
|
|
|
|
|
command, i - 1);
|
|
|
|
|
result = ERROR_FAIL;
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
error:
|
|
|
|
|
/* Clear the sample buffer even when there was an error. */
|
|
|
|
|
r->sample_buf.used = 0;
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-14 14:40:08 -06:00
|
|
|
|
COMMAND_HELPER(riscv_print_info_line, const char *section, const char *key,
|
|
|
|
|
unsigned value)
|
|
|
|
|
{
|
|
|
|
|
char full_key[80];
|
|
|
|
|
snprintf(full_key, sizeof(full_key), "%s.%s", section, key);
|
|
|
|
|
command_print(CMD, "%-21s %3d", full_key, value);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
COMMAND_HANDLER(handle_info)
|
|
|
|
|
{
|
|
|
|
|
struct target *target = get_current_target(CMD_CTX);
|
|
|
|
|
RISCV_INFO(r);
|
|
|
|
|
|
|
|
|
|
/* This output format can be fed directly into TCL's "array set". */
|
|
|
|
|
|
|
|
|
|
riscv_print_info_line(CMD, "hart", "xlen", riscv_xlen(target));
|
|
|
|
|
riscv_enumerate_triggers(target);
|
|
|
|
|
riscv_print_info_line(CMD, "hart", "trigger_count",
|
2021-01-18 14:22:43 -06:00
|
|
|
|
r->trigger_count);
|
2020-12-14 14:40:08 -06:00
|
|
|
|
|
|
|
|
|
if (r->print_info)
|
|
|
|
|
return CALL_COMMAND_HANDLER(r->print_info, target);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-15 11:53:03 -06:00
|
|
|
|
COMMAND_HANDLER(riscv_exec_progbuf)
|
|
|
|
|
{
|
|
|
|
|
if (CMD_ARGC < 1 || CMD_ARGC > 16) {
|
|
|
|
|
LOG_ERROR("Command 'exec_progbuf' takes 1 to 16 arguments.");
|
|
|
|
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct target *target = get_current_target(CMD_CTX);
|
|
|
|
|
|
|
|
|
|
RISCV_INFO(r);
|
|
|
|
|
if (r->dtm_version != 1) {
|
|
|
|
|
LOG_TARGET_ERROR(target, "exec_progbuf: Program buffer is "
|
|
|
|
|
"only supported on v0.13 or v1.0 targets.");
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (target->state != TARGET_HALTED) {
|
|
|
|
|
LOG_TARGET_ERROR(target, "exec_progbuf: Can't execute "
|
|
|
|
|
"program buffer, target not halted.");
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (riscv_debug_buffer_size(target) == 0) {
|
|
|
|
|
LOG_TARGET_ERROR(target, "exec_progbuf: Program buffer not implemented "
|
|
|
|
|
"in the target.");
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct riscv_program prog;
|
|
|
|
|
riscv_program_init(&prog, target);
|
|
|
|
|
|
|
|
|
|
for (unsigned int i = 0; i < CMD_ARGC; i++) {
|
|
|
|
|
riscv_insn_t instr;
|
|
|
|
|
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[i], instr);
|
|
|
|
|
if (riscv_program_insert(&prog, instr) != ERROR_OK)
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (riscv_program_exec(&prog, target) == ERROR_OK)
|
|
|
|
|
LOG_TARGET_DEBUG(target, "exec_progbuf: Program buffer execution successful.");
|
|
|
|
|
else
|
|
|
|
|
LOG_TARGET_ERROR(target, "exec_progbuf: Program buffer execution failed.");
|
|
|
|
|
|
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-15 19:04:59 -05:00
|
|
|
|
static const struct command_registration riscv_exec_command_handlers[] = {
|
2020-10-07 16:31:36 -05:00
|
|
|
|
{
|
|
|
|
|
.name = "dump_sample_buf",
|
|
|
|
|
.handler = handle_dump_sample_buf_command,
|
|
|
|
|
.mode = COMMAND_ANY,
|
2021-10-25 12:12:57 -05:00
|
|
|
|
.usage = "[base64]",
|
2020-10-07 16:31:36 -05:00
|
|
|
|
.help = "Print the contents of the sample buffer, and clear the buffer."
|
|
|
|
|
},
|
2020-12-14 14:40:08 -06:00
|
|
|
|
{
|
|
|
|
|
.name = "info",
|
|
|
|
|
.handler = handle_info,
|
|
|
|
|
.mode = COMMAND_ANY,
|
2021-09-01 17:00:46 -05:00
|
|
|
|
.usage = "",
|
2020-12-14 14:40:08 -06:00
|
|
|
|
.help = "Displays some information OpenOCD detected about the target."
|
|
|
|
|
},
|
2020-10-07 16:31:36 -05:00
|
|
|
|
{
|
|
|
|
|
.name = "memory_sample",
|
|
|
|
|
.handler = handle_memory_sample_command,
|
|
|
|
|
.mode = COMMAND_ANY,
|
2021-10-25 12:12:57 -05:00
|
|
|
|
.usage = "bucket address|clear [size=4]",
|
2020-10-07 16:31:36 -05:00
|
|
|
|
.help = "Causes OpenOCD to frequently read size bytes at the given address."
|
|
|
|
|
},
|
2020-08-18 13:01:41 -05:00
|
|
|
|
{
|
|
|
|
|
.name = "repeat_read",
|
|
|
|
|
.handler = handle_repeat_read,
|
|
|
|
|
.mode = COMMAND_ANY,
|
2020-09-03 13:59:48 -05:00
|
|
|
|
.usage = "count address [size=4]",
|
2020-08-18 13:01:41 -05:00
|
|
|
|
.help = "Repeatedly read the value at address."
|
|
|
|
|
},
|
2017-08-15 19:04:59 -05:00
|
|
|
|
{
|
|
|
|
|
.name = "set_command_timeout_sec",
|
|
|
|
|
.handler = riscv_set_command_timeout_sec,
|
|
|
|
|
.mode = COMMAND_ANY,
|
2020-09-03 13:59:48 -05:00
|
|
|
|
.usage = "[sec]",
|
2017-08-15 19:04:59 -05:00
|
|
|
|
.help = "Set the wall-clock timeout (in seconds) for individual commands"
|
2017-10-27 15:15:22 -05:00
|
|
|
|
},
|
|
|
|
|
{
|
2017-08-15 19:04:59 -05:00
|
|
|
|
.name = "set_reset_timeout_sec",
|
|
|
|
|
.handler = riscv_set_reset_timeout_sec,
|
|
|
|
|
.mode = COMMAND_ANY,
|
2020-09-03 13:59:48 -05:00
|
|
|
|
.usage = "[sec]",
|
2017-08-15 19:04:59 -05:00
|
|
|
|
.help = "Set the wall-clock timeout (in seconds) after reset is deasserted"
|
|
|
|
|
},
|
2018-03-19 16:05:35 -05:00
|
|
|
|
{
|
|
|
|
|
.name = "set_prefer_sba",
|
|
|
|
|
.handler = riscv_set_prefer_sba,
|
|
|
|
|
.mode = COMMAND_ANY,
|
2020-09-03 13:59:48 -05:00
|
|
|
|
.usage = "on|off",
|
2018-03-19 16:05:35 -05:00
|
|
|
|
.help = "When on, prefer to use System Bus Access to access memory. "
|
2020-03-27 13:21:02 -05:00
|
|
|
|
"When off (default), prefer to use the Program Buffer to access memory."
|
2018-03-19 16:05:35 -05:00
|
|
|
|
},
|
2020-09-10 15:57:51 -05:00
|
|
|
|
{
|
|
|
|
|
.name = "set_mem_access",
|
|
|
|
|
.handler = riscv_set_mem_access,
|
|
|
|
|
.mode = COMMAND_ANY,
|
|
|
|
|
.usage = "method1 [method2] [method3]",
|
|
|
|
|
.help = "Set which memory access methods shall be used and in which order "
|
|
|
|
|
"of priority. Method can be one of: 'progbuf', 'sysbus' or 'abstract'."
|
|
|
|
|
},
|
2019-07-18 15:15:28 -05:00
|
|
|
|
{
|
|
|
|
|
.name = "set_enable_virtual",
|
|
|
|
|
.handler = riscv_set_enable_virtual,
|
|
|
|
|
.mode = COMMAND_ANY,
|
2020-09-03 13:59:48 -05:00
|
|
|
|
.usage = "on|off",
|
2019-07-18 15:15:28 -05:00
|
|
|
|
.help = "When on, memory accesses are performed on physical or virtual "
|
|
|
|
|
"memory depending on the current system configuration. "
|
2020-03-27 13:21:02 -05:00
|
|
|
|
"When off (default), all memory accessses are performed on physical memory."
|
2019-07-18 15:15:28 -05:00
|
|
|
|
},
|
2017-12-15 15:27:26 -06:00
|
|
|
|
{
|
|
|
|
|
.name = "expose_csrs",
|
|
|
|
|
.handler = riscv_set_expose_csrs,
|
2020-10-01 13:05:41 -05:00
|
|
|
|
.mode = COMMAND_CONFIG,
|
|
|
|
|
.usage = "n0[-m0|=name0][,n1[-m1|=name1]]...",
|
2017-12-15 15:27:26 -06:00
|
|
|
|
.help = "Configure a list of inclusive ranges for CSRs to expose in "
|
|
|
|
|
"addition to the standard ones. This must be executed before "
|
|
|
|
|
"`init`."
|
|
|
|
|
},
|
2018-08-29 16:22:50 -05:00
|
|
|
|
{
|
|
|
|
|
.name = "expose_custom",
|
|
|
|
|
.handler = riscv_set_expose_custom,
|
2020-10-01 13:05:41 -05:00
|
|
|
|
.mode = COMMAND_CONFIG,
|
|
|
|
|
.usage = "n0[-m0|=name0][,n1[-m1|=name1]]...",
|
2018-08-29 16:22:50 -05:00
|
|
|
|
.help = "Configure a list of inclusive ranges for custom registers to "
|
|
|
|
|
"expose. custom0 is accessed as abstract register number 0xc000, "
|
|
|
|
|
"etc. This must be executed before `init`."
|
|
|
|
|
},
|
2023-02-15 11:53:37 -06:00
|
|
|
|
{
|
|
|
|
|
.name = "hide_csrs",
|
|
|
|
|
.handler = riscv_hide_csrs,
|
|
|
|
|
.mode = COMMAND_CONFIG,
|
|
|
|
|
.usage = "{n0|n-m0}[,n1|n-m1]......",
|
|
|
|
|
.help = "Configure a list of inclusive ranges for CSRs to hide from gdb. "
|
|
|
|
|
"Hidden registers are still available, but are not listed in "
|
|
|
|
|
"gdb target description and `reg` command output. "
|
|
|
|
|
"This must be executed before `init`."
|
|
|
|
|
},
|
2018-02-27 11:27:00 -06:00
|
|
|
|
{
|
|
|
|
|
.name = "authdata_read",
|
|
|
|
|
.handler = riscv_authdata_read,
|
2021-01-28 11:56:51 -06:00
|
|
|
|
.usage = "[index]",
|
2018-02-27 11:27:00 -06:00
|
|
|
|
.mode = COMMAND_ANY,
|
2021-01-28 11:56:51 -06:00
|
|
|
|
.help = "Return the 32-bit value read from authdata or authdata0 "
|
|
|
|
|
"(index=0), or authdata1 (index=1)."
|
2018-02-27 11:27:00 -06:00
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
.name = "authdata_write",
|
|
|
|
|
.handler = riscv_authdata_write,
|
|
|
|
|
.mode = COMMAND_ANY,
|
2021-01-28 11:56:51 -06:00
|
|
|
|
.usage = "[index] value",
|
|
|
|
|
.help = "Write the 32-bit value to authdata or authdata0 (index=0), "
|
|
|
|
|
"or authdata1 (index=1)."
|
2018-02-27 11:27:00 -06:00
|
|
|
|
},
|
2018-03-06 14:44:53 -06:00
|
|
|
|
{
|
|
|
|
|
.name = "dmi_read",
|
|
|
|
|
.handler = riscv_dmi_read,
|
|
|
|
|
.mode = COMMAND_ANY,
|
2020-09-03 13:59:48 -05:00
|
|
|
|
.usage = "address",
|
2018-03-06 14:44:53 -06:00
|
|
|
|
.help = "Perform a 32-bit DMI read at address, returning the value."
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
.name = "dmi_write",
|
|
|
|
|
.handler = riscv_dmi_write,
|
|
|
|
|
.mode = COMMAND_ANY,
|
2020-09-03 13:59:48 -05:00
|
|
|
|
.usage = "address value",
|
2018-03-06 14:44:53 -06:00
|
|
|
|
.help = "Perform a 32-bit DMI write of value at address."
|
|
|
|
|
},
|
2018-12-04 14:38:51 -06:00
|
|
|
|
{
|
|
|
|
|
.name = "reset_delays",
|
|
|
|
|
.handler = riscv_reset_delays,
|
|
|
|
|
.mode = COMMAND_ANY,
|
2020-09-03 13:59:48 -05:00
|
|
|
|
.usage = "[wait]",
|
2018-12-04 14:38:51 -06:00
|
|
|
|
.help = "OpenOCD learns how many Run-Test/Idle cycles are required "
|
|
|
|
|
"between scans to avoid encountering the target being busy. This "
|
|
|
|
|
"command resets those learned values after `wait` scans. It's only "
|
|
|
|
|
"useful for testing OpenOCD itself."
|
|
|
|
|
},
|
2019-07-15 12:32:28 -05:00
|
|
|
|
{
|
|
|
|
|
.name = "resume_order",
|
|
|
|
|
.handler = riscv_resume_order,
|
|
|
|
|
.mode = COMMAND_ANY,
|
2020-09-03 13:59:48 -05:00
|
|
|
|
.usage = "normal|reversed",
|
2019-07-15 12:32:28 -05:00
|
|
|
|
.help = "Choose the order that harts are resumed in when `hasel` is not "
|
|
|
|
|
"supported. Normal order is from lowest hart index to highest. "
|
|
|
|
|
"Reversed order is from highest hart index to lowest."
|
|
|
|
|
},
|
2019-01-08 12:30:26 -06:00
|
|
|
|
{
|
|
|
|
|
.name = "set_ir",
|
|
|
|
|
.handler = riscv_set_ir,
|
|
|
|
|
.mode = COMMAND_ANY,
|
2020-09-03 13:59:48 -05:00
|
|
|
|
.usage = "[idcode|dtmcs|dmi] value",
|
2019-01-08 12:30:26 -06:00
|
|
|
|
.help = "Set IR value for specified JTAG register."
|
|
|
|
|
},
|
2019-04-23 18:25:22 -05:00
|
|
|
|
{
|
|
|
|
|
.name = "use_bscan_tunnel",
|
|
|
|
|
.handler = riscv_use_bscan_tunnel,
|
|
|
|
|
.mode = COMMAND_ANY,
|
2020-09-03 13:59:48 -05:00
|
|
|
|
.usage = "value [type]",
|
2019-04-23 18:25:22 -05:00
|
|
|
|
.help = "Enable or disable use of a BSCAN tunnel to reach DM. Supply "
|
|
|
|
|
"the width of the DM transport TAP's instruction register to "
|
2019-06-10 15:33:50 -05:00
|
|
|
|
"enable. Supply a value of 0 to disable. Pass A second argument "
|
|
|
|
|
"(optional) to indicate Bscan Tunnel Type {0:(default) NESTED_TAP , "
|
|
|
|
|
"1: DATA_REGISTER}"
|
2019-04-23 18:25:22 -05:00
|
|
|
|
},
|
2022-04-20 12:16:47 -05:00
|
|
|
|
{
|
|
|
|
|
.name = "set_bscan_tunnel_ir",
|
|
|
|
|
.handler = riscv_set_bscan_tunnel_ir,
|
|
|
|
|
.mode = COMMAND_ANY,
|
|
|
|
|
.usage = "value",
|
|
|
|
|
.help = "Specify the JTAG TAP IR used to access the bscan tunnel. "
|
|
|
|
|
"By default it is 0x23 << (ir_length - 6), which map some "
|
|
|
|
|
"Xilinx FPGA (IR USER4)"
|
|
|
|
|
},
|
2022-03-01 12:05:54 -06:00
|
|
|
|
{
|
|
|
|
|
.name = "set_maskisr",
|
|
|
|
|
.handler = riscv_set_maskisr,
|
|
|
|
|
.mode = COMMAND_EXEC,
|
|
|
|
|
.help = "mask riscv interrupts",
|
|
|
|
|
.usage = "['off'|'steponly']",
|
|
|
|
|
},
|
2019-12-10 14:18:03 -06:00
|
|
|
|
{
|
|
|
|
|
.name = "set_enable_virt2phys",
|
|
|
|
|
.handler = riscv_set_enable_virt2phys,
|
|
|
|
|
.mode = COMMAND_ANY,
|
2020-09-03 13:59:48 -05:00
|
|
|
|
.usage = "on|off",
|
2020-03-27 13:21:02 -05:00
|
|
|
|
.help = "When on (default), enable translation from virtual address to "
|
|
|
|
|
"physical address."
|
2019-12-10 14:18:03 -06:00
|
|
|
|
},
|
2020-02-20 15:58:15 -06:00
|
|
|
|
{
|
|
|
|
|
.name = "set_ebreakm",
|
|
|
|
|
.handler = riscv_set_ebreakm,
|
|
|
|
|
.mode = COMMAND_ANY,
|
2020-09-03 13:59:48 -05:00
|
|
|
|
.usage = "on|off",
|
2020-02-20 15:58:15 -06:00
|
|
|
|
.help = "Control dcsr.ebreakm. When off, M-mode ebreak instructions "
|
|
|
|
|
"don't trap to OpenOCD. Defaults to on."
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
.name = "set_ebreaks",
|
|
|
|
|
.handler = riscv_set_ebreaks,
|
|
|
|
|
.mode = COMMAND_ANY,
|
2020-09-03 13:59:48 -05:00
|
|
|
|
.usage = "on|off",
|
2020-02-20 15:58:15 -06:00
|
|
|
|
.help = "Control dcsr.ebreaks. When off, S-mode ebreak instructions "
|
|
|
|
|
"don't trap to OpenOCD. Defaults to on."
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
.name = "set_ebreaku",
|
|
|
|
|
.handler = riscv_set_ebreaku,
|
|
|
|
|
.mode = COMMAND_ANY,
|
2020-09-03 13:59:48 -05:00
|
|
|
|
.usage = "on|off",
|
2020-02-20 15:58:15 -06:00
|
|
|
|
.help = "Control dcsr.ebreaku. When off, U-mode ebreak instructions "
|
|
|
|
|
"don't trap to OpenOCD. Defaults to on."
|
|
|
|
|
},
|
2022-12-28 13:47:50 -06:00
|
|
|
|
{
|
|
|
|
|
.name = "etrigger",
|
|
|
|
|
.handler = riscv_etrigger,
|
|
|
|
|
.mode = COMMAND_EXEC,
|
|
|
|
|
.usage = "set [vs] [vu] [m] [s] [u] <exception_codes>|clear",
|
|
|
|
|
.help = "Set or clear a single exception trigger."
|
|
|
|
|
},
|
2022-11-18 17:57:17 -06:00
|
|
|
|
{
|
|
|
|
|
.name = "itrigger",
|
|
|
|
|
.handler = riscv_itrigger,
|
|
|
|
|
.mode = COMMAND_EXEC,
|
|
|
|
|
.usage = "set [vs] [vu] [nmi] [m] [s] [u] <mie_bits>|clear",
|
|
|
|
|
.help = "Set or clear a single interrupt trigger."
|
|
|
|
|
},
|
2023-02-15 11:53:03 -06:00
|
|
|
|
{
|
|
|
|
|
.name = "exec_progbuf",
|
|
|
|
|
.handler = riscv_exec_progbuf,
|
|
|
|
|
.mode = COMMAND_EXEC,
|
|
|
|
|
.usage = "instr1 [instr2 [... instr16]]",
|
|
|
|
|
.help = "Execute a sequence of 32-bit instructions using the program buffer. "
|
|
|
|
|
"The final ebreak instruction is added automatically, if needed."
|
|
|
|
|
},
|
2017-08-15 19:04:59 -05:00
|
|
|
|
COMMAND_REGISTRATION_DONE
|
|
|
|
|
};
|
|
|
|
|
|
2018-06-12 15:54:41 -05:00
|
|
|
|
/*
|
2018-06-12 15:58:56 -05:00
|
|
|
|
* To be noted that RISC-V targets use the same semihosting commands as
|
2018-06-12 15:54:41 -05:00
|
|
|
|
* ARM targets.
|
2018-06-12 15:58:56 -05:00
|
|
|
|
*
|
|
|
|
|
* The main reason is compatibility with existing tools. For example the
|
|
|
|
|
* Eclipse OpenOCD/SEGGER J-Link/QEMU plug-ins have several widgets to
|
|
|
|
|
* configure semihosting, which generate commands like `arm semihosting
|
|
|
|
|
* enable`.
|
|
|
|
|
* A secondary reason is the fact that the protocol used is exactly the
|
|
|
|
|
* one specified by ARM. If RISC-V will ever define its own semihosting
|
|
|
|
|
* protocol, then a command like `riscv semihosting enable` will make
|
|
|
|
|
* sense, but for now all semihosting commands are prefixed with `arm`.
|
2018-06-12 15:54:41 -05:00
|
|
|
|
*/
|
2020-02-25 12:35:44 -06:00
|
|
|
|
extern const struct command_registration semihosting_common_handlers[];
|
2018-06-12 10:15:39 -05:00
|
|
|
|
|
2017-08-15 19:04:59 -05:00
|
|
|
|
const struct command_registration riscv_command_handlers[] = {
|
|
|
|
|
{
|
|
|
|
|
.name = "riscv",
|
|
|
|
|
.mode = COMMAND_ANY,
|
|
|
|
|
.help = "RISC-V Command Group",
|
2020-09-10 15:53:27 -05:00
|
|
|
|
.usage = "",
|
2017-08-15 19:04:59 -05:00
|
|
|
|
.chain = riscv_exec_command_handlers
|
|
|
|
|
},
|
2018-06-12 10:15:39 -05:00
|
|
|
|
{
|
|
|
|
|
.name = "arm",
|
|
|
|
|
.mode = COMMAND_ANY,
|
|
|
|
|
.help = "ARM Command Group",
|
2020-09-10 15:53:27 -05:00
|
|
|
|
.usage = "",
|
2020-02-25 12:35:44 -06:00
|
|
|
|
.chain = semihosting_common_handlers
|
2018-06-12 10:15:39 -05:00
|
|
|
|
},
|
2017-08-15 19:04:59 -05:00
|
|
|
|
COMMAND_REGISTRATION_DONE
|
|
|
|
|
};
|
|
|
|
|
|
2019-11-04 13:04:30 -06:00
|
|
|
|
static unsigned riscv_xlen_nonconst(struct target *target)
|
2019-02-25 16:02:30 -06:00
|
|
|
|
{
|
|
|
|
|
return riscv_xlen(target);
|
|
|
|
|
}
|
|
|
|
|
|
From upstream (#620)
* cortex_m: use unsigned int for FPB and DWT quantifiers
related quantifiers are:
- fp_num_lit
- fp_num_code
- dwt_num_comp
- dwt_comp_available
Change-Id: I07dec2d4aa21bc0e580be0d9fd0a6809f876c2a8
Signed-off-by: Tarek BOCHKATI <tarek.bouchkati@gmail.com>
Reviewed-on: http://openocd.zylin.com/6185
Tested-by: jenkins
Reviewed-by: Tomas Vanek <vanekt@fbl.cz>
* telnet: allow hiding selected commands during auto-completion
We have TCL procedure and commands that we do not want to show in
the list of auto-completion. E.g. TCL wrappers for deprecated
commands, internal procedures that are not supposed to be exposed
to user, or even commands that the user decides to hide.
Create a TCL procedure to be called by telnet auto-complete code
in place of the hard-coded TCL command. The procedure will run the
same command and will filter-out the unwanted command names.
Initialize the list of commands to be filtered-out with the name
of the TCL procedure above, as it is considered as internal.
Change-Id: I2d83bbf8194502368c589c85cccb617e69128c69
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6194
Tested-by: jenkins
Reviewed-by: Tarek BOCHKATI <tarek.bouchkati@gmail.com>
* telnet/auto-complete: hide deprecated and internal commands
For both:
- TCL proc that redirect deprecated commands to the new commands,
- TCL proc used internally and not supposed to be exposed to user,
add their name to the list of commands that should be hide by the
telnet auto-complete.
Change-Id: I05237c6a79334b7d2b151dfb129fb57b2f40bba6
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6195
Tested-by: jenkins
Reviewed-by: Tarek BOCHKATI <tarek.bouchkati@gmail.com>
* startup.tcl: prepare for jimtcl 0.81 'expr' syntax change
Jimtcl commit 1843b79a03dd ("expr: TIP 526, only support a single
arg") drops the support for multi-argument syntax for the TCL
command 'expr'.
Modify the script startup.tcl compiled-in OpenOCD binary to comply
with the new jimtcl.
Change-Id: I520dcafacadaa289a815035f93f250447ca66ea0
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6158
Tested-by: jenkins
Reviewed-by: Oleksij Rempel <linux@rempel-privat.de>
Reviewed-by: Tomas Vanek <vanekt@fbl.cz>
* tcl: [1/3] prepare for jimtcl 0.81 'expr' syntax change
Jimtcl commit 1843b79a03dd ("expr: TIP 526, only support a single
arg") drops the support for multi-argument syntax for the TCL
command 'expr'.
In the TCL scripts distributed with OpenOCD there are 1700+ lines
that should be modified before switching to jimtcl 0.81.
Apply the script below on every script in tcl folder. It fixes
more than 92% of the lines
%<---%<---%<---%<---%<---%<---%<---%<---%<---%<---%<---%<---%<---
#!/usr/bin/perl -Wpi
my $re_sym = qr{[a-z_][a-z0-9_]*}i;
my $re_var = qr{(?:\$|\$::)$re_sym};
my $re_const = qr{0x[0-9a-f]+|[0-9]+|[0-9]*\.[0-9]*}i;
my $re_item = qr{(?:~\s*)?(?:$re_var|$re_const)};
my $re_op = qr{<<|>>|[+\-*/&|]};
my $re_expr = qr{(
(?:\(\s*(?:$re_item|(?-1))\s*\)|$re_item)
\s*$re_op\s*
(?:$re_item|(?-1)|\(\s*(?:$re_item|(?-1))\s*\))
)}x;
# [expr [dict get $regsC100 SYM] + HEXNUM]
s/\[expr (\[dict get $re_var $re_sym\s*\] \+ *$re_const)\]/\[expr \{$1\}\]/;
# [ expr (EXPR) ]
# [ expr EXPR ]
# note: $re_expr captures '$3'
s/\[(\s*expr\s*)\((\s*$re_expr\s*)\)(\s*)\]/\[$1\{$2\}$4\]/;
s/\[(\s*expr\s*)($re_expr)(\s*)\]/\[$1\{$2\}$4\]/;
%<---%<---%<---%<---%<---%<---%<---%<---%<---%<---%<---%<---%<---
Change-Id: I0d6bddc6abf6dd29062f2b4e72b5a2b5080293b9
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6159
Tested-by: jenkins
Reviewed-by: Tomas Vanek <vanekt@fbl.cz>
* tcl: [2/3] prepare for jimtcl 0.81 'expr' syntax change
Jimtcl commit 1843b79a03dd ("expr: TIP 526, only support a single
arg") drops the support for multi-argument syntax for the TCL
command 'expr'.
Enclose within double quote the argument of 'expr' when there is
the need to concatenate strings.
Change-Id: Ic0ea990ed37337a7e6c3a99670583685b570b8b1
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6160
Tested-by: jenkins
* tcl: [3/3] prepare for jimtcl 0.81 'expr' syntax change
Jimtcl commit 1843b79a03dd ("expr: TIP 526, only support a single
arg") drops the support for multi-argument syntax for the TCL
command 'expr'.
Fix manually the remaining lines that don't match simple patterns
and would require dedicated boring scripting.
Remove the 'expr' command where appropriate.
Change-Id: Ia75210c8447f88d38515addab4a836af9103096d
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6161
Tested-by: jenkins
Reviewed-by: Tomas Vanek <vanekt@fbl.cz>
* target/stm8: Make 'stm8_command_handlers' static
Change-Id: I5237a8f2a1ecba9383672e37bd56f8ccd17598b6
Signed-off-by: Marc Schink <dev@zapb.de>
Reviewed-on: http://openocd.zylin.com/6200
Tested-by: jenkins
Reviewed-by: Tarek BOCHKATI <tarek.bouchkati@gmail.com>
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
* target/riscv: Change 'authdata_read' output
Use a constant output length and remove the line break to make the
authentication data easier to parse.
Change-Id: Iebbf1f171947ef89b0f360a2cb286a4ea15c6ba5
Signed-off-by: Marc Schink <dev@zapb.de>
Reviewed-on: http://openocd.zylin.com/6199
Tested-by: jenkins
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-by: Tim Newsome <tim@sifive.com>
* Enable adapter "Bus Pirate" by default.
The Bus Pirate is now listed in the "OpenOCD configuration summary" too.
Change-Id: Ieb7bf9134af456ebe9803f3108a243204fb2a62d
Signed-off-by: R. Diez <rdiezmail-openocd@yahoo.de>
Reviewed-on: http://openocd.zylin.com/5637
Tested-by: jenkins
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
* coding-style: additional style for C code
To improve readability and to push more uniform code style.
Prefer 'if (false) {...}' for unused code so it get checked by the
compiler.
Define preferred indentation for 'switch' statement.
Require balanced brackets in 'if/else'.
Report the max line length.
Report the formatting strings for stdint/inttypes types.
Report the type 'target_addr_t'.
Prefer 'unsigned int' to 'unsigned'.
Change-Id: I0192a4ed298f6c6c432764fdd156cffd4b13fc89
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6203
Reviewed-by: Tomas Vanek <vanekt@fbl.cz>
Tested-by: jenkins
Reviewed-by: Oleksij Rempel <linux@rempel-privat.de>
Reviewed-by: Tarek BOCHKATI <tarek.bouchkati@gmail.com>
Reviewed-by: Marc Schink <dev@zapb.de>
* Add IPDBG JtagHost functionality to OpenOCD
IPDBG are utilities to debug IP-cores. It uses JTAG for
transport to/from the FPGA. The different UIs use TCP/IP
as transport. The JtagHost makes the bridge between these
two.
Comparable to the bridge between GDB and the in-circuit-
debugging-unit of a micro controller.
Change-Id: Ib1bc10dcbd4ea426e492bb7b2d85c1ed1b7a8d5a
Signed-off-by: Daniel Anselmi <danselmi@gmx.ch>
Reviewed-on: http://openocd.zylin.com/5938
Tested-by: jenkins
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
* flash/nor/xcf: Do not use 'Yoda conditions'
Change-Id: I17308f5237338ce468e5b86289a0634429deaaa9
Signed-off-by: Marc Schink <dev@zapb.de>
Reviewed-on: http://openocd.zylin.com/6201
Tested-by: jenkins
Reviewed-by: Tomas Vanek <vanekt@fbl.cz>
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
* cortex_m: add armv8m special registers
Change-Id: I1942f375a5f4282ad1fe4a2ff3b8f3cbc64d8f7f
Signed-off-by: Tarek BOCHKATI <tarek.bouchkati@gmail.com>
Reviewed-on: http://openocd.zylin.com/6016
Tested-by: jenkins
Reviewed-by: Tomas Vanek <vanekt@fbl.cz>
* rtos: Add support for Zephyr RTOS
With this patch, the Zephyr[1] RTOS is supported by OpenOCD.
As usual with support for other RTOSes, Zephyr must be compiled with
the DEBUG_THREAD_INFO option. This will generate some symbols
with information needed in order to build the list of threads.
The current implementation is limited to Zephyr running on ARM
Cortex-M processors. This is the only ARM variant supported by Zephyr
at the moment and is used on most of the officially supported boards.
[1] https://www.zephyrproject.org/
Change-Id: I22afdbec91562f3a22cf5b88cd4ea3a7a59ba0b4
Signed-off-by: Evgeniy Didin <didin@synopsys.com>
Signed-off-by: Leandro Pereira <leandro.pereira@intel.com>
Signed-off-by: Daniel Glöckner <dg@emlix.com>
Reviewed-on: http://openocd.zylin.com/4988
Tested-by: jenkins
Reviewed-by: Oleksij Rempel <linux@rempel-privat.de>
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
* target/armv7m.h: [style] replace tab with space between variable type and name
Change-Id: I9740c25857295a2a655d3046322a3f23f0ee7f78
Signed-off-by: Tarek BOCHKATI <tarek.bouchkati@gmail.com>
Reviewed-on: http://openocd.zylin.com/6230
Reviewed-by: Marc Schink <dev@zapb.de>
Tested-by: jenkins
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
* server: gdb_server: Add colon for target extended-remote
Both GDB commands "target remote" and "target extended-remote" require
to have ":" right before port number.
e.g.
(gdb) target extended-remote :3333
Add ":" to the warning message so that users can copy & past it.
Change-Id: Id6d8ec1e4dfd3c12cb7f3b314064f2c35fa7ab55
Signed-off-by: Yasushi SHOJI <yashi@spacecubics.com>
Reviewed-on: http://openocd.zylin.com/6237
Reviewed-by: Tarek BOCHKATI <tarek.bouchkati@gmail.com>
Tested-by: jenkins
Reviewed-by: Marc Schink <dev@zapb.de>
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
* jimtcl: restrict memory leak workaround on Linux only
The workaround for jimtcl 0.80 in commit 36ae487ed04b ("jimtcl:
add temporary workaround for memory leak in jimtcl 0.80") issues a
compile time error on macOS:
../src/helper/command.c:157:22: error: aliases are not
supported on darwin
__attribute__((weak, alias("workaround_createcommand")));
The OS is x86_64-apple-darwin19.6.0 and the compiler used is
x86_64-apple-darwin13.4.0-clang.
Restrict the workaround on Linux host only. The fix for 'expr'
syntax change is already merged and the workaround will be dropped
soon.
Change-Id: I925109a9c57c05f8c95b70bc7d6604eb1172cd79
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reported-by: Adam Jeliński <ajelinski@users.sourceforge.net>
Fixes: 36ae487ed04b ("jimtcl: add temporary workaround for memory leak in jimtcl 0.80")
Fixes: https://sourceforge.net/p/openocd/tickets/304/
Reviewed-on: http://openocd.zylin.com/6241
Tested-by: jenkins
* target/armv7m: fix static analyzer warning
Despite of assert(is_packed) clang static analyser complains on use
of the uninitialized offset variable.
Cross compiling with latest x86_64-w64-mingw32-gcc hits warnings
src/target/armv7m.c: In function ‘armv7m_read_core_reg’:
src/target/armv7m.c:337:54: error: ‘reg32_id’ may be used
uninitialized in this function [-Werror=maybe-uninitialized]
It happens because mingw32 defines assert() without the attribute
"noreturn", whatever NDEBUG is defined or not.
Replace assert(is_packed) by if (is_packed) conditional and call
assert(false) in the else branch.
Change-Id: Id3c7dcccb65106e28be200b9a4d2b642f4d31019
Signed-off-by: Tomas Vanek <vanekt@fbl.cz>
Reviewed-on: http://openocd.zylin.com/6256
Tested-by: jenkins
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-by: Tarek BOCHKATI <tarek.bouchkati@gmail.com>
Reviewed-by: Andrzej Sierżęga <asier70@gmail.com>
* cmsis_dap: fix build on macOS
Compile fails with error:
src/jtag/drivers/cmsis_dap.c:683:28: error: format specifies type
'unsigned char' but the argument has type 'int' [-Werror,-Wformat]
" received 0x%" PRIx8, CMD_DAP_TFER, resp[0]);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~
Fix the format specifier.
Change-Id: I0a5a1a35452d634019989d14d849501fb8a7e93a
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6255
Tested-by: jenkins
Reviewed-by: Tomas Vanek <vanekt@fbl.cz>
* cortex_m: do not perform soft_reset_halt on targets without VECTRESET
Change-Id: Ib3df457e0afe4e342c82ad1af25e03aad6979d87
Signed-off-by: Tarek BOCHKATI <tarek.bouchkati@gmail.com>
Reviewed-on: http://openocd.zylin.com/6209
Tested-by: jenkins
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-by: Tomas Vanek <vanekt@fbl.cz>
* cortex_m: fix VECTRESET detection for ARMv6-M cores
VECTRESET check should be done after verifying if the core is an ARMv6-M core,
and not before that.
Fixes: 2dc9c1df81b6 ("cortex_m: [FIX] ARMv8-M does not support VECTRESET")
Change-Id: I8306affd332b3a35cea69bba39ef24ca71244273
Signed-off-by: Tarek BOCHKATI <tarek.bouchkati@gmail.com>
Reviewed-on: http://openocd.zylin.com/6232
Tested-by: jenkins
Reviewed-by: Tomas Vanek <vanekt@fbl.cz>
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
* target/arm_dpm: rename 'wp_pc' as 'wp_addr'
The field 'wp_pc' was originally introduced in commit 55eeea7fceb6
("ARMv7a/Cortex-A8: report watchpoint trigger insn") in end 2009
to contain the address of the instruction which triggered a
watchpoint. Later on with commit 651b861d5d5f ("target/aarch64:
Add watchpoint support") it has been reused in to hold directly
the memory address that triggered a watchpoint.
Rename 'wp_pc' as 'wp_addr' and change its doxygen description.
While there, fix the format string to print the field.
Change-Id: I2e5ced1497e4a6fb6b38f91e881807512e8d8c47
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6204
Tested-by: jenkins
Reviewed-by: Liming Sun <limings@nvidia.com>
* target/aarch64: fix watchpoint management
The early documentation for armv8a report the debug register WFAR
as containing the address of the instruction that triggered the
watchpoint. More recent documentation report the register EDWAR as
containing the data memory address that triggered the watchpoint.
The name of macros CPUV8_DBG_WFAR0 and CPUV8_DBG_WFAR1 is not
correct as they point to the debug register EDWAR, so reading such
register returns directly the data memory address that triggered
the watchpoint. The code incorrectly passes this address value to
the function armv8_dpm_report_wfar(); this function is supposed to
adjust the PC value, decrementing it to remove the effects of the
CPU pipeline. This pipeline offset, that has no meaning on the
value in EDWAR, caused commit 651b861d5d5f ("target/aarch64: Add
watchpoint support") to add back the offset while comparing the
address with the watchpoint enabled.
The upper 32 bits of EDWAR are not valid in aarch32 mode and have
to be ignored.
Rename CPUV8_DBG_WFAR0/1 as CPUV8_DBG_EDWAR0/1.
Remove the function armv8_dpm_report_wfar().
Remove the offset while searching the matching watchpoint.
Ignore the upper 32 bits of EDWAR in aarch32 mode.
Fix a comment and the LOG text.
Change-Id: I7cbdbeb766fa18e31cc72be098ca2bc501877ed1
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6205
Tested-by: jenkins
Reviewed-by: Liming Sun <limings@nvidia.com>
* flash/stm32l4x: add missing break statement
this is not a bug fix, this for loop will issue only one match
adding the break will save unnecessary more loops.
Change-Id: Ic1484ea8cdea1b284eb570f9e3e7818e07daf5cd
Signed-off-by: Tarek BOCHKATI <tarek.bouchkati@gmail.com>
Reviewed-on: http://openocd.zylin.com/6248
Reviewed-by: Oleksij Rempel <linux@rempel-privat.de>
Tested-by: jenkins
* github/action: create a permanent 'latest' release
this commit extends the existing snapshot action to create a release named
'latest' with the built binaries for windows.
this 'latest' release will be updated after every push to github.
Change-Id: I75a64c598169241743add3ac9aa7a0337fbab7f2
Signed-off-by: Tarek BOCHKATI <tarek.bouchkati@gmail.com>
Reviewed-on: http://openocd.zylin.com/6127
Tested-by: jenkins
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
* tcl/rp2040: remove empty line at end of file
Change-Id: I212a96b77282b151a8ecbd46a6436e2bbbda4161
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6221
Tested-by: jenkins
* tcl: fix some minor typo
Minor typos found by the new checkpatch boosted by the dictionary
provided by 'codespell'.
While there, fix one indentation.
Change-Id: I72369ed26f363bacd760b40b8c83dd95e89d28a4
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6214
Tested-by: jenkins
* flash: fix some minor typo
Minor typos found by the new checkpatch boosted by the dictionary
provided by 'codespell'.
Change-Id: Ia5f134c91beb483fd865df9e4877e0ec3e789478
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6215
Tested-by: jenkins
* jtag: fix some minor typo
Minor typos found by the new checkpatch boosted by the dictionary
provided by 'codespell'.
Change-Id: I101c76a638805d77c1ff356cf0f027552389e5d3
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6216
Tested-by: jenkins
* target: fix some minor typo
Minor typos found by the new checkpatch boosted by the dictionary
provided by 'codespell'.
Change-Id: I548581247db72e683249749d1b8725035530b06e
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6217
Tested-by: jenkins
* openocd: fix some minor typo
Minor typos found by the new checkpatch boosted by the dictionary
provided by 'codespell'.
Change-Id: I7b4cae1798ff5ea048fcbc671a397af763fdc605
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6218
Tested-by: jenkins
* Document the buspirate interface driver.
Change-Id: Iaff13fc5187041a840f4f00eb6b4ee52880cf47e
Signed-off-by: R. Diez <rdiezmail-openocd@yahoo.de>
Reviewed-on: http://openocd.zylin.com/6231
Tested-by: jenkins
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
* Warn on undefined preprocessor symbols
Preprocessor directives like "#if SYMBOL" silently replace undefined or
misspelt symbols with 0, which makes configuration bugs hard to spot.
Compiler flag "-Wundef" prevents such errors.
Change-Id: I91b7ba2db02ef0c3c452d334601c53aebda4660e
Signed-off-by: R. Diez <rdiezmail-openocd@yahoo.de>
Reviewed-on: http://openocd.zylin.com/6238
Tested-by: jenkins
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
* Remove compatibility macros m4_ifblank and m4_ifnblank
They are at least since Autoconf 2.67 present,
and we are requiring version 2.69.
Change-Id: I41b33d4ebe02198f03cdddcc4a3c1beedd993d78
Signed-off-by: R. Diez <rdiezmail-openocd@yahoo.de>
Reviewed-on: http://openocd.zylin.com/6239
Tested-by: jenkins
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
* configure.ac: use a separate folder for Autoconf-generated files
Autoconf generates several files in root folder of the project.
Keep the root folder cleaner by specifying subfolder 'build-aux'.
Align .gitignore accordingly.
Signed-off-by: R. Diez <rdiezmail-openocd@yahoo.de>
Change-Id: Ied87faba495d9eeb8f98e78c2e2b7e7e596febfb
Reviewed-on: http://openocd.zylin.com/6236
Tested-by: jenkins
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
* helper/command: silent debug msg on command register/unregister
Commit e216186fab59 ("helper/command: register full-name commands
in jim") and commit a7d68878e4ba ("helper/command: unregister
commands through their full-name") introduce a LOG_DEBUG() message
each for command registration and unregistration.
The messages above are quite noisy and pollute the log when
debug_level is 3 or higher.
They can be useful to debug the command registration logic, but
for the other debug activities on OpenOCD are just noisy.
Already commit a03ac1ba3087 ("helper/command: disable logging of
registered commands [RFC]") was merged to silent the first case
that is now back with additional logs.
Silent both log messages.
Use 'if (false)' to silent them, making easy to re-enable it when
or if someone needs it.
Change-Id: Id8a067e60e822d4ecbddcb036d081298f7e6181f
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6220
Tested-by: jenkins
* mem_ap: fix target arch_info type
The target mem_ap appears as an ARM target, thus it allows the
execution of ARM specific commands causing the crash of OpenOCD.
E.g. 'arm mrc ...' can be executed and segfaults.
Replace the incorrect ARM magic number with a dedicated one.
While there, remove the 'struct arm', that is now holding only the
mem_ap's dap, and replace it with a pointer to the dap.
Change-Id: I881332d3fdf8d8f8271b8711607737b052a5699b
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6213
Tested-by: jenkins
* riscv: drop unused variable
The array newly_halted[] is assigned but its value is never used.
Drop it!
Change-Id: I678812a31c45a3ec03716e3eee6a30b8e8947926
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6257
Tested-by: jenkins
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Tim Newsome <tim@sifive.com>
* riscv: replace macro DIM() with ARRAY_SIZE()
OpenOCD already defines the macro ARRAY_SIZE, while riscv code
uses a local macro DIM.
Prefer using the macro ARRAY_SIZE() instead of DIM().
Not all the riscv code has been upstreamed, yes; this patch only
covers the code already upstreamed.
Change-Id: I89a58a6d91916d85c53ba5e4091b558271f8d618
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6258
Reviewed-by: Xiang W <wxjstz@126.com>
Tested-by: jenkins
Reviewed-by: Tim Newsome <tim@sifive.com>
* target/zynqmp : Add AXI AP access port
The Xilinx Zynq UltraScale+ SoC have an "AXI-AP" access port for direct memory accesses without halting CPUs.
Change-Id: I6303331c217795657575de4759444938e775dee1
Signed-off-by: Olivier DANET <odanet@caramail.com>
Reviewed-on: http://openocd.zylin.com/6263
Reviewed-by: Tarek BOCHKATI <tarek.bouchkati@gmail.com>
Tested-by: jenkins
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
* drivers/versaloon: use ARRAY_SIZE()
Replace the custom macro dimof() with the OpenOCD macro
ARRAY_SIZE().
Change-Id: I2fe638444f6c16f2a78c1fd558b21550f76282d6
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6259
Tested-by: jenkins
Reviewed-by: Xiang W <wxjstz@126.com>
* openocd: use macro ARRAY_SIZE()
There are still few cases where the macro ARRAY_SIZE() should be
used in place of custom code.
Use ARRAY_SIZE() whenever possible.
Change-Id: Iba0127a02357bc704fe639e08562a4f9aa7011df
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6260
Reviewed-by: Xiang W <wxjstz@126.com>
Tested-by: jenkins
* rtos: use ARRAY_SIZE() and simplify rtos_type.create()
Use the existing macro ARRAY_SIZE().
Rewrite the functions rtos_type.create() to simplify the logic.
Change-Id: I8833354767045d1642801d26944c9087a77add00
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6261
Tested-by: jenkins
* tcl: remove remaining deprecated commands
There are still few adapter_khz, ftdi_location, jtag_nsrst_delay
and xds110_serial strolling around ...
Change-Id: I3e8503dcc3875e3c92e6536f3d455a5e448d51ff
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6270
Tested-by: jenkins
* help text: remove trailing space
Some help text end with a useless space character.
Remove it.
Change-Id: I397e1194fac8042f0fab694222f925f906716de3
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6222
Tested-by: jenkins
* help: fix line size in 'usage' output
The implementation of command 'usage' is broken while checking the
line limit of 76 chars per line (e.g. 'usage load_image') and the
line wrapping is not correct. The same broken code is used for the
first output line of command 'help' too.
When call command_help_show_wrap(), include the command's name in
the string so the whole text would be wrapped.
Change-Id: Idece01ce54994db7e851d8522435ff764b11f3ac
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6223
Tested-by: jenkins
* LICENSES: Add the MIT license
Add the full text of the MIT license to the kernel tree. It was copied
directly from:
https://spdx.org/licenses/MIT.html#licenseText
Add the required tags for reference and tooling.
Change-Id: I94a5dea5ced6421809ea2a3448f8dda19a93f5c9
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6219
Tested-by: jenkins
* stlink: add comment of firmware version for each flag bit
Change-Id: I7f7c7b9c9cfd88125f82662ed864a2c0715140b1
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6211
Tested-by: jenkins
* stlink: reorder the flag macro by firmware release
The corresponding bit for each macro is changed, but this is not
relevant in the code.
Change-Id: I7039464f5a3d55d008208f44952aadeb815bd5a3
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6212
Tested-by: jenkins
* tcl/board: Add ST NUCLEO-8S208RB
Change-Id: I384c6ad9b4cbabbc004160677f600d8c4bd3eb71
Signed-off-by: Marc Schink <dev@zapb.de>
Reviewed-on: http://openocd.zylin.com/6268
Tested-by: jenkins
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
* target/arm_adi_v5: Fix clear sticky overrun flag during replay of commands
When a WAIT occurs the commands after the WAIT are replayed and the
STICKYORUN is cleared. However if another WAIT occurs during the
command replay, the command itself is resent but the STICKYORUN bit
shall also be cleared. If this is not done, the MEM-AP hangs.
Change-Id: I14e8340cd5d8f58f4de31509da96cfa2ecb630d1
Signed-off-by: micbis <michele.bisogno.ct@renesas.com>
Reviewed-on: http://openocd.zylin.com/6278
Tested-by: jenkins
Reviewed-by: Matthias Welwarsky <matthias@welwarsky.de>
* target/cortex_a: add support for watchpoints
The current implementation of OpenOCD does not support watchpoints for
cortex_a architecture. So, I replaced the add_watchpoint and
remove_watchpoint with the specific implementation for the
cortex a and using the breakpoint implementation and the arm
documentation [1] as reference. In particular, I have made the
following changes:
* added the following functions
- cortex_a_add_watchpoint
This wrapper function check whether there are any watchpoint
available on the target device by calling cortex_a_set_watchpoint.
- cortex_a_set_watchpoint
This function is responsible for settings the watchpoint register
pair. In particular, it sets the WVR and the WCR registers with
the cortex_a_dap command.
- cortex_a_remove_watchpoint
This wrapper function the selected watchpoint on the target device
by calling cortex_a_unset_watchpoint.
- cortex_a_unset_watchpoint
This function sets both the WVR and the WCR registers to zero, thus
unsetting the watchpoint.
[1]
http://infocenter.arm.com/help/topic/com.arm.doc.ddi0464f/BCGDHIEJ.html
Change-Id: I86611dab474cb84836662af572b17636dc68e282
Signed-off-by: Chengyu Zheng <chengyu.zheng@polimi.it>
Reviewed-on: http://openocd.zylin.com/3913
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-by: Matthias Welwarsky <matthias@welwarsky.de>
Reviewed-by: Marc Schink <dev@zapb.de>
Tested-by: jenkins
* target/cortex_a: fix number of watchpoints
Decrement the available watchpoints only when succeed setting it.
Initialize the available watchpoint with the correct value.
Change-Id: I0f93b347300b8ebedbcd9e718d4ba32b26cf6846
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6196
Tested-by: jenkins
Reviewed-by: Matthias Welwarsky <matthias@welwarsky.de>
* target/cortex_a: add support for watchpoint length of 1, 2 and 4 bytes
Use byte address select for 1 and 2 bytes length.
Use normal mode for 4 bytes length.
Change-Id: I28d182f25145d0635de64d0361d456f1ad96640e
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6197
Tested-by: jenkins
Reviewed-by: Matthias Welwarsky <matthias@welwarsky.de>
* target/cortex_a: fix memory leak on watchpoints
The memory allocated to hold the watchpoints is not freed at
OpenOCD exit.
Free the watchpoint memory at OpenOCD exit.
Change-Id: I518c9ce0dc901cde2913d752e3154734f878b854
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6210
Tested-by: jenkins
Reviewed-by: Matthias Welwarsky <matthias@welwarsky.de>
* helper/jim-nvp: comply with coding style [1/2]
The helper jim-nvp does not comply with OpenOCD coding style due
to typedef of struct and CamelCase symbol names.
While it's trivial fixing the helper and all its current use in
the code, changing these APIs will potentially break a number of
patches pending in gerrit. Gerrit will not trigger any alert, but
the code will generate compile error after the merge.
Add the compile flag "-Wno-error=deprecated-declarations" to keep
as warning (not as error) the use of "deprecated" functions and
types.
Rename all the CamelCase symbols is lowercase and provide struct
prototypes in place of the typedef.
Add a DEPRECATED section to 'jim-nvp.h' where the old CamelCase
symbols and the old typedef are re-declared with compile attribute
'deprecated'.
With this change OpenOCD compiles, but generates warnings.
The remaining changes allover OpenOCD code will be fixed in a
separate patch for easier review.
The patches merged later that still use the old deprecated API
will compile with warnings. This will permit to identify and fix
these cases.
Change-Id: I786385d0f662dbb1be5be313ae42623156d68ce5
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6183
Tested-by: jenkins
Reviewed-by: Marc Schink <dev@zapb.de>
* helper/jim-nvp: comply with coding style [2/2]
With the API fixed to comply with OpenOCD coding style, fix all
the references in the code.
Patch generated automatically with the script below.
The list is in reverse order to replace a common prefix after the
replacement of the symbols with the same prefix.
%<---%<---%<---%<---%<---%<---%<---%<---%<---%<---%<---%<---%<---
(cat << EOF
Jim_SetResult_NvpUnknown jim_set_result_nvp_unknown
Jim_Nvp_value2name_simple jim_nvp_value2name_simple
Jim_Nvp_value2name_obj jim_nvp_value2name_obj
Jim_Nvp_value2name jim_nvp_value2name
Jim_Nvp_name2value_simple jim_nvp_name2value_simple
Jim_Nvp_name2value_obj_nocase jim_nvp_name2value_obj_nocase
Jim_Nvp_name2value_obj jim_nvp_name2value_obj
Jim_Nvp_name2value_nocase_simple jim_nvp_name2value_nocase_simple
Jim_Nvp_name2value_nocase jim_nvp_name2value_nocase
Jim_Nvp_name2value jim_nvp_name2value
Jim_Nvp struct jim_nvp
Jim_GetOpt_Wide jim_getopt_wide
Jim_GetOpt_String jim_getopt_string
Jim_GetOpt_Setup jim_getopt_setup
Jim_GetOpt_Obj jim_getopt_obj
Jim_GetOpt_NvpUnknown jim_getopt_nvp_unknown
Jim_GetOpt_Nvp jim_getopt_nvp
Jim_GetOpt_Enum jim_getopt_enum
Jim_GetOpt_Double jim_getopt_double
Jim_GetOpt_Debug jim_getopt_debug
Jim_GetOptInfo struct jim_getopt_info
Jim_GetNvp jim_get_nvp
Jim_Debug_ArgvString jim_debug_argv_string
EOF
) | while read a b; do
sed -i "s/$a/$b/g" $(find src -type f ! -name jim-nvp.\? )
done
%<---%<---%<---%<---%<---%<---%<---%<---%<---%<---%<---%<---%<---
Change-Id: I10a12bd64bb8b17575fd9150482c989c92b298a2
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6184
Reviewed-by: Marc Schink <dev@zapb.de>
Tested-by: jenkins
* server/telnet: fix autocomplete for jimtcl commands
Current autocomplete filters-out some command reported by "info
commands". One of the filter rule concerns the command's private
data.
Every command registered by OpenOCD has its 'struct command' as
private data.
By ignoring commands without private data, we loose several TCL
commands registered by jimtcl, e.g. 'foreach', 'llength'.
By assuming that every command with non-NULL private data has
'struct command' as private data, we risk at best to access
inconsistent data, at worst to trigger a segmentation fault.
Export the already available functions:
- to check if a command has been registered by OpenOCD and
- to get the private data.
While there, rename jimcmd_is_ocd_command() as
jimcmd_is_oocd_command().
Don't filter-out jimtcl commands with no private data.
Check the private data only on OpenOCD commands.
Change-Id: Ib5bf8d2bc5c12440c0cfae438f637c38724a79b7
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6282
Tested-by: jenkins
Reviewed-by: Tarek BOCHKATI <tarek.bouchkati@gmail.com>
* helper/list.h: align file to Linux v5.12
Main improvement is in the doxygen comments.
Minimize the delta with kernel file.
Skip the functions hlist_unhashed_lockless() and
__list_del_clearprev() that are relevant only in kernel.
Remove gcc extension "omitted conditional operand".
Change-Id: I2e9ddb54cfe2fa5f7cf18f44726acd144e1f98b9
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6276
Reviewed-by: <rdiezmail-openocd@yahoo.de>
Tested-by: jenkins
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
* contrib: add an example of using list.h
Change-Id: Ic3d399d7ad2e4d10677cf78d64968040941b74e5
Signed-off-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6280
Tested-by: jenkins
Reviewed-by: Tim Newsome <tim@sifive.com>
* helper/list.h: add mention to the example in contrib
Without such reference, it could be difficult to find the example.
Change-Id: Ia9ffb06bc1a45446c2c7b53197ab3400e1d8a9e9
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/6281
Tested-by: jenkins
Reviewed-by: Tim Newsome <tim@sifive.com>
* tcl/target/stm32f4x: fix hardcoded chip name
Fixes: c945d6e61605 ("tcl/target: start using the new TPIU/SWO support")
Change-Id: I4543c9a204f7b4b3b14e6eabc5042653106aff0e
Signed-off-by: Tarek BOCHKATI <tarek.bouchkati@gmail.com>
Reviewed-on: http://openocd.zylin.com/6277
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
Tested-by: jenkins
* Makefile: add special target .DELETE_ON_ERROR
The special .DELETE_ON_ERROR deletes the target file on recipe error.
Otherwise, an incomplete output file may be considered up to date
the next time around. .DELETE_ON_ERROR provides reasonable
protection at virtually no cost.
Signed-off-by: R. Diez <rdiezmail-openocd@yahoo.de>
Change-Id: I67dca47ae5ddf3786993c87b9991b3046a85f00b
Reviewed-on: http://openocd.zylin.com/6235
Tested-by: jenkins
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
* gdb_server: Log both incoming and outgoing GDB packets
- Made sure that also outgoing GDB packets are logged,
not only the incoming ones.
- Improved the treatment of non-printable characters
in the packets to make it more robust.
Prior to this change:
- Outgoing packets were not printed unless OpenOCD was
re-compiled with _DEBUG_GDB_IO_.
- Non-prinable characters were only treated in incoming
'X' packets.
After this change:
- Both incoming and outgoing GDB packets are logged
on debug_level >= 3, so that both directions of the
GDB channel are visible.
- Non-printable characters are checked for in every packet
so that hey do not interfere with the terminal.
Change-Id: I0613e57ae5059b3279b0abcb71276cf5719a8699
Signed-off-by: Jan Matyas <matyas@codasip.com>
Reviewed-on: http://openocd.zylin.com/6269
Tested-by: jenkins
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
* target/renesas_rz_g2: Introduce tcl config file for RZ/G2 devices
Initial support for Renesas RZ/G2 MPU family
Change-Id: I5ca74cddfd0c105a5307de56c3ade7084f9c28d2
Signed-off-by: micbis <michele.bisogno.ct@renesas.com>
Reviewed-on: http://openocd.zylin.com/6250
Tested-by: jenkins
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
* drivers/jlink: Remove trailing dots
This makes the messages consistent with most of the rest of
the OpenOCD output.
Change-Id: I915a01187e7fc317e02483ac0bbd39ec077d6321
Signed-off-by: Marc Schink <dev@zapb.de>
Reviewed-on: http://openocd.zylin.com/6274
Tested-by: jenkins
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
* target: Use 'bool' for 'reset_halt'
Change-Id: I974a6360ea7467067511541ac212f2e9d3de7895
Signed-off-by: Marc Schink <dev@zapb.de>
Reviewed-on: http://openocd.zylin.com/6262
Tested-by: jenkins
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
* cmsis_dap: add support for swo commands
Replaced mixed snake_case_CamelCase with snake_case.
Define variables at first-use location.
CMSIS-DAP SWO specification:
https://arm-software.github.io/CMSIS_5/DAP/html/group__DAP__swo__gr.html
Change-Id: Ieba79b16efd445143f964b614673d041aae74f92
Signed-off-by: Adrian Negreanu <adrian.negreanu@nxp.com>
Reviewed-on: http://openocd.zylin.com/5820
Tested-by: jenkins
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
* Add target_data_bits().
This is used to compute memory block read alignment, and specifically
allows 64-bit targets to ensure that memory block reads are only
requested on 64-bit boundaries.
Signed-off-by: Tim Newsome <tim@sifive.com>
Change-Id: Idb1a27b9fc02c46245556bb0f3d6d94b368c4817
Reviewed-on: http://openocd.zylin.com/6249
Reviewed-by: Marc Schink <dev@zapb.de>
Tested-by: jenkins
Reviewed-by: Jan Matyas <matyas@codasip.com>
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
* Avoid non-standard conditionals with omitted operands.
Fixes bug #257.
Change-Id: I05fc6468306d46399e769098e031e7e588798afc
Signed-off-by: R. Diez <rdiezmail-openocd@yahoo.de>
Reviewed-on: http://openocd.zylin.com/6271
Tested-by: jenkins
Reviewed-by: Xiang W <wxjstz@126.com>
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
* target/startup.tcl: Do not use 'Yoda conditions'
Change-Id: I5e1bbaf032659dda1b365ef4ec6ea4a635d921ce
Signed-off-by: Marc Schink <dev@zapb.de>
Reviewed-on: http://openocd.zylin.com/6284
Tested-by: jenkins
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
* Fix build.
Change-Id: I4f2667db91f84f07af354691aac5d4c9e3aea3fa
Signed-off-by: Tim Newsome <tim@sifive.com>
Co-authored-by: Tarek BOCHKATI <tarek.bouchkati@gmail.com>
Co-authored-by: Antonio Borneo <borneo.antonio@gmail.com>
Co-authored-by: Marc Schink <dev@zapb.de>
Co-authored-by: R. Diez <rdiezmail-openocd@yahoo.de>
Co-authored-by: Daniel Anselmi <danselmi@gmx.ch>
Co-authored-by: Evgeniy Didin <didin@synopsys.com>
Co-authored-by: Yasushi SHOJI <yashi@spacecubics.com>
Co-authored-by: Tomas Vanek <vanekt@fbl.cz>
Co-authored-by: Olivier DANET <odanet@caramail.com>
Co-authored-by: Thomas Gleixner <tglx@linutronix.de>
Co-authored-by: micbis <michele.bisogno.ct@renesas.com>
Co-authored-by: Chengyu Zheng <chengyu.zheng@polimi.it>
Co-authored-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
Co-authored-by: Jan Matyas <matyas@codasip.com>
Co-authored-by: Adrian Negreanu <adrian.negreanu@nxp.com>
2021-06-11 15:01:55 -05:00
|
|
|
|
static unsigned int riscv_data_bits(struct target *target)
|
2019-11-22 13:37:46 -06:00
|
|
|
|
{
|
|
|
|
|
RISCV_INFO(r);
|
|
|
|
|
if (r->data_bits)
|
|
|
|
|
return r->data_bits(target);
|
|
|
|
|
return riscv_xlen(target);
|
|
|
|
|
}
|
|
|
|
|
|
2017-12-22 16:35:38 -06:00
|
|
|
|
struct target_type riscv_target = {
|
2017-05-09 15:33:06 -05:00
|
|
|
|
.name = "riscv",
|
|
|
|
|
|
2020-09-17 15:20:12 -05:00
|
|
|
|
.target_create = riscv_create_target,
|
2017-05-09 15:33:06 -05:00
|
|
|
|
.init_target = riscv_init_target,
|
|
|
|
|
.deinit_target = riscv_deinit_target,
|
|
|
|
|
.examine = riscv_examine,
|
|
|
|
|
|
|
|
|
|
/* poll current target status */
|
|
|
|
|
.poll = old_or_new_riscv_poll,
|
|
|
|
|
|
2019-05-09 13:32:04 -05:00
|
|
|
|
.halt = riscv_halt,
|
2020-05-19 12:34:36 -05:00
|
|
|
|
.resume = riscv_target_resume,
|
2017-05-11 12:40:43 -05:00
|
|
|
|
.step = old_or_new_riscv_step,
|
2017-05-09 15:33:06 -05:00
|
|
|
|
|
2017-09-19 17:04:00 -05:00
|
|
|
|
.assert_reset = riscv_assert_reset,
|
|
|
|
|
.deassert_reset = riscv_deassert_reset,
|
2017-05-09 15:33:06 -05:00
|
|
|
|
|
|
|
|
|
.read_memory = riscv_read_memory,
|
|
|
|
|
.write_memory = riscv_write_memory,
|
2019-12-10 14:18:03 -06:00
|
|
|
|
.read_phys_memory = riscv_read_phys_memory,
|
|
|
|
|
.write_phys_memory = riscv_write_phys_memory,
|
2017-05-09 15:33:06 -05:00
|
|
|
|
|
|
|
|
|
.checksum_memory = riscv_checksum_memory,
|
|
|
|
|
|
2019-12-10 14:18:03 -06:00
|
|
|
|
.mmu = riscv_mmu,
|
|
|
|
|
.virt2phys = riscv_virt2phys,
|
|
|
|
|
|
2021-06-16 12:38:00 -05:00
|
|
|
|
.get_gdb_arch = riscv_get_gdb_arch,
|
2017-05-09 15:33:06 -05:00
|
|
|
|
.get_gdb_reg_list = riscv_get_gdb_reg_list,
|
2019-02-07 15:24:44 -06:00
|
|
|
|
.get_gdb_reg_list_noread = riscv_get_gdb_reg_list_noread,
|
2017-05-09 15:33:06 -05:00
|
|
|
|
|
|
|
|
|
.add_breakpoint = riscv_add_breakpoint,
|
|
|
|
|
.remove_breakpoint = riscv_remove_breakpoint,
|
|
|
|
|
|
|
|
|
|
.add_watchpoint = riscv_add_watchpoint,
|
|
|
|
|
.remove_watchpoint = riscv_remove_watchpoint,
|
2018-08-27 14:42:34 -05:00
|
|
|
|
.hit_watchpoint = riscv_hit_watchpoint,
|
2017-05-09 15:33:06 -05:00
|
|
|
|
|
|
|
|
|
.arch_state = riscv_arch_state,
|
|
|
|
|
|
|
|
|
|
.run_algorithm = riscv_run_algorithm,
|
2017-08-15 17:55:09 -05:00
|
|
|
|
|
2019-02-25 16:02:30 -06:00
|
|
|
|
.commands = riscv_command_handlers,
|
|
|
|
|
|
2019-11-04 13:04:30 -06:00
|
|
|
|
.address_bits = riscv_xlen_nonconst,
|
2019-11-22 13:37:46 -06:00
|
|
|
|
.data_bits = riscv_data_bits
|
2017-05-09 15:33:06 -05:00
|
|
|
|
};
|
|
|
|
|
|
2017-03-24 20:21:56 -05:00
|
|
|
|
/*** RISC-V Interface ***/
|
|
|
|
|
|
2017-06-20 19:12:53 -05:00
|
|
|
|
void riscv_info_init(struct target *target, riscv_info_t *r)
|
2017-03-24 20:21:56 -05:00
|
|
|
|
{
|
|
|
|
|
memset(r, 0, sizeof(*r));
|
|
|
|
|
r->dtm_version = 1;
|
2020-09-17 15:20:12 -05:00
|
|
|
|
r->version_specific = NULL;
|
2017-03-24 20:21:56 -05:00
|
|
|
|
|
2017-07-11 16:49:35 -05:00
|
|
|
|
memset(r->trigger_unique_id, 0xff, sizeof(r->trigger_unique_id));
|
|
|
|
|
|
2021-01-18 14:22:43 -06:00
|
|
|
|
r->xlen = -1;
|
2020-09-10 15:57:51 -05:00
|
|
|
|
|
2022-03-01 12:05:54 -06:00
|
|
|
|
r->isrmask_mode = RISCV_ISRMASK_OFF;
|
|
|
|
|
|
2020-09-10 15:57:51 -05:00
|
|
|
|
r->mem_access_methods[0] = RISCV_MEM_ACCESS_PROGBUF;
|
|
|
|
|
r->mem_access_methods[1] = RISCV_MEM_ACCESS_SYSBUS;
|
|
|
|
|
r->mem_access_methods[2] = RISCV_MEM_ACCESS_ABSTRACT;
|
|
|
|
|
|
|
|
|
|
r->mem_access_progbuf_warn = true;
|
|
|
|
|
r->mem_access_sysbus_warn = true;
|
|
|
|
|
r->mem_access_abstract_warn = true;
|
2020-10-01 13:05:41 -05:00
|
|
|
|
|
|
|
|
|
INIT_LIST_HEAD(&r->expose_csr);
|
|
|
|
|
INIT_LIST_HEAD(&r->expose_custom);
|
2023-02-15 11:53:37 -06:00
|
|
|
|
INIT_LIST_HEAD(&r->hide_csr);
|
2023-02-08 13:03:33 -06:00
|
|
|
|
|
|
|
|
|
r->vsew64_supported = YNM_MAYBE;
|
2017-03-24 20:21:56 -05:00
|
|
|
|
}
|
|
|
|
|
|
2019-04-03 14:13:09 -05:00
|
|
|
|
static int riscv_resume_go_all_harts(struct target *target)
|
2017-03-24 20:21:56 -05:00
|
|
|
|
{
|
2019-04-03 14:13:09 -05:00
|
|
|
|
RISCV_INFO(r);
|
2019-07-15 12:32:28 -05:00
|
|
|
|
|
2022-09-29 17:09:49 -05:00
|
|
|
|
LOG_TARGET_DEBUG(target, "resuming hart, state=%d", target->state);
|
2022-11-10 12:27:04 -06:00
|
|
|
|
if (target->state == TARGET_HALTED) {
|
2021-01-18 14:22:43 -06:00
|
|
|
|
if (r->resume_go(target) != ERROR_OK)
|
2019-04-03 14:13:09 -05:00
|
|
|
|
return ERROR_FAIL;
|
2021-01-18 14:22:43 -06:00
|
|
|
|
} else {
|
|
|
|
|
LOG_DEBUG("[%s] hart requested resume, but was already resumed",
|
|
|
|
|
target_name(target));
|
2017-03-24 20:21:56 -05:00
|
|
|
|
}
|
|
|
|
|
|
2017-05-25 15:10:28 -05:00
|
|
|
|
riscv_invalidate_register_cache(target);
|
2017-03-24 20:21:56 -05:00
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-01 12:05:54 -06:00
|
|
|
|
int riscv_interrupts_disable(struct target *target, uint64_t irq_mask, uint64_t *old_mstatus)
|
|
|
|
|
{
|
|
|
|
|
LOG_DEBUG("Disabling Interrupts");
|
|
|
|
|
struct reg *reg_mstatus = register_get_by_name(target->reg_cache,
|
|
|
|
|
"mstatus", true);
|
|
|
|
|
if (!reg_mstatus) {
|
|
|
|
|
LOG_ERROR("Couldn't find mstatus!");
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int retval = reg_mstatus->type->get(reg_mstatus);
|
|
|
|
|
if (retval != ERROR_OK)
|
|
|
|
|
return retval;
|
|
|
|
|
|
|
|
|
|
RISCV_INFO(info);
|
|
|
|
|
uint8_t mstatus_bytes[8] = { 0 };
|
|
|
|
|
uint64_t current_mstatus = buf_get_u64(reg_mstatus->value, 0, reg_mstatus->size);
|
|
|
|
|
buf_set_u64(mstatus_bytes, 0, info->xlen, set_field(current_mstatus,
|
|
|
|
|
irq_mask, 0));
|
|
|
|
|
|
|
|
|
|
retval = reg_mstatus->type->set(reg_mstatus, mstatus_bytes);
|
|
|
|
|
if (retval != ERROR_OK)
|
|
|
|
|
return retval;
|
|
|
|
|
|
|
|
|
|
if (old_mstatus)
|
|
|
|
|
*old_mstatus = current_mstatus;
|
|
|
|
|
|
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int riscv_interrupts_restore(struct target *target, uint64_t old_mstatus)
|
|
|
|
|
{
|
|
|
|
|
LOG_DEBUG("Restore Interrupts");
|
|
|
|
|
struct reg *reg_mstatus = register_get_by_name(target->reg_cache,
|
|
|
|
|
"mstatus", true);
|
|
|
|
|
if (!reg_mstatus) {
|
|
|
|
|
LOG_ERROR("Couldn't find mstatus!");
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RISCV_INFO(info);
|
|
|
|
|
uint8_t mstatus_bytes[8];
|
|
|
|
|
buf_set_u64(mstatus_bytes, 0, info->xlen, old_mstatus);
|
|
|
|
|
return reg_mstatus->type->set(reg_mstatus, mstatus_bytes);
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-24 20:21:56 -05:00
|
|
|
|
int riscv_step_rtos_hart(struct target *target)
|
|
|
|
|
{
|
|
|
|
|
RISCV_INFO(r);
|
2021-01-18 14:22:43 -06:00
|
|
|
|
LOG_DEBUG("[%s] stepping", target_name(target));
|
2017-03-24 20:21:56 -05:00
|
|
|
|
|
2022-11-10 12:27:04 -06:00
|
|
|
|
if (target->state != TARGET_HALTED) {
|
2017-12-27 15:04:30 -06:00
|
|
|
|
LOG_ERROR("Hart isn't halted before single step!");
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
2017-03-24 20:21:56 -05:00
|
|
|
|
r->on_step(target);
|
2017-12-27 15:04:30 -06:00
|
|
|
|
if (r->step_current_hart(target) != ERROR_OK)
|
|
|
|
|
return ERROR_FAIL;
|
2017-03-24 20:21:56 -05:00
|
|
|
|
r->on_halt(target);
|
2022-11-10 12:27:04 -06:00
|
|
|
|
if (target->state != TARGET_HALTED) {
|
2017-12-27 15:04:30 -06:00
|
|
|
|
LOG_ERROR("Hart was not halted after single step!");
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
2017-03-24 20:21:56 -05:00
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-18 14:22:43 -06:00
|
|
|
|
bool riscv_supports_extension(struct target *target, char letter)
|
2017-11-13 15:14:07 -06:00
|
|
|
|
{
|
|
|
|
|
RISCV_INFO(r);
|
|
|
|
|
unsigned num;
|
2017-12-22 16:35:38 -06:00
|
|
|
|
if (letter >= 'a' && letter <= 'z')
|
2017-11-13 15:14:07 -06:00
|
|
|
|
num = letter - 'a';
|
2017-12-22 16:35:38 -06:00
|
|
|
|
else if (letter >= 'A' && letter <= 'Z')
|
2017-11-13 15:14:07 -06:00
|
|
|
|
num = letter - 'A';
|
2017-12-22 16:35:38 -06:00
|
|
|
|
else
|
2017-11-13 15:14:07 -06:00
|
|
|
|
return false;
|
2021-09-01 17:00:46 -05:00
|
|
|
|
return r->misa & BIT(num);
|
2017-11-13 15:14:07 -06:00
|
|
|
|
}
|
|
|
|
|
|
2019-11-04 13:04:30 -06:00
|
|
|
|
unsigned riscv_xlen(const struct target *target)
|
2017-03-24 20:21:56 -05:00
|
|
|
|
{
|
|
|
|
|
RISCV_INFO(r);
|
2021-01-18 14:22:43 -06:00
|
|
|
|
return r->xlen;
|
2017-03-24 20:21:56 -05:00
|
|
|
|
}
|
|
|
|
|
|
2017-05-25 15:10:28 -05:00
|
|
|
|
void riscv_invalidate_register_cache(struct target *target)
|
|
|
|
|
{
|
2022-06-16 11:58:45 -05:00
|
|
|
|
/* Do not invalidate the register cache if it is not yet set up
|
|
|
|
|
* (e.g. when the target failed to get examined). */
|
|
|
|
|
if (!target->reg_cache)
|
|
|
|
|
return;
|
2017-05-25 15:10:28 -05:00
|
|
|
|
|
2019-02-07 15:24:44 -06:00
|
|
|
|
LOG_DEBUG("[%d]", target->coreid);
|
2017-03-24 20:21:56 -05:00
|
|
|
|
register_cache_invalidate(target->reg_cache);
|
2018-08-29 16:22:50 -05:00
|
|
|
|
for (size_t i = 0; i < target->reg_cache->num_regs; ++i) {
|
2017-03-24 20:21:56 -05:00
|
|
|
|
struct reg *reg = &target->reg_cache->reg_list[i];
|
|
|
|
|
reg->valid = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2022-09-23 13:32:42 -05:00
|
|
|
|
unsigned int riscv_count_harts(struct target *target)
|
2017-03-24 20:21:56 -05:00
|
|
|
|
{
|
2021-07-03 11:51:20 -05:00
|
|
|
|
if (!target)
|
2017-12-22 16:35:38 -06:00
|
|
|
|
return 1;
|
2017-03-24 20:21:56 -05:00
|
|
|
|
RISCV_INFO(r);
|
2021-07-03 14:29:32 -05:00
|
|
|
|
if (!r || !r->hart_count)
|
2017-12-22 16:35:38 -06:00
|
|
|
|
return 1;
|
2019-04-03 14:13:09 -05:00
|
|
|
|
return r->hart_count(target);
|
2017-03-24 20:21:56 -05:00
|
|
|
|
}
|
|
|
|
|
|
2020-04-21 16:58:59 -05:00
|
|
|
|
/**
|
|
|
|
|
* If write is true:
|
|
|
|
|
* return true iff we are guaranteed that the register will contain exactly
|
|
|
|
|
* the value we just wrote when it's read.
|
|
|
|
|
* If write is false:
|
|
|
|
|
* return true iff we are guaranteed that the register will read the same
|
|
|
|
|
* value in the future as the value we just read.
|
|
|
|
|
*/
|
|
|
|
|
static bool gdb_regno_cacheable(enum gdb_regno regno, bool write)
|
|
|
|
|
{
|
|
|
|
|
/* GPRs, FPRs, vector registers are just normal data stores. */
|
|
|
|
|
if (regno <= GDB_REGNO_XPR31 ||
|
|
|
|
|
(regno >= GDB_REGNO_FPR0 && regno <= GDB_REGNO_FPR31) ||
|
2020-05-06 10:43:59 -05:00
|
|
|
|
(regno >= GDB_REGNO_V0 && regno <= GDB_REGNO_V31))
|
2020-04-21 16:58:59 -05:00
|
|
|
|
return true;
|
|
|
|
|
|
2021-01-29 12:58:11 -06:00
|
|
|
|
/* Most CSRs won't change value on us, but we can't assume it about arbitrary
|
2020-04-21 16:58:59 -05:00
|
|
|
|
* CSRs. */
|
|
|
|
|
switch (regno) {
|
2020-05-06 10:43:59 -05:00
|
|
|
|
case GDB_REGNO_DPC:
|
|
|
|
|
return true;
|
|
|
|
|
|
2020-04-21 16:58:59 -05:00
|
|
|
|
case GDB_REGNO_VSTART:
|
|
|
|
|
case GDB_REGNO_VXSAT:
|
|
|
|
|
case GDB_REGNO_VXRM:
|
|
|
|
|
case GDB_REGNO_VLENB:
|
|
|
|
|
case GDB_REGNO_VL:
|
|
|
|
|
case GDB_REGNO_VTYPE:
|
|
|
|
|
case GDB_REGNO_MISA:
|
|
|
|
|
case GDB_REGNO_DCSR:
|
2020-08-24 17:42:45 -05:00
|
|
|
|
case GDB_REGNO_DSCRATCH0:
|
2020-04-21 16:58:59 -05:00
|
|
|
|
case GDB_REGNO_MSTATUS:
|
|
|
|
|
case GDB_REGNO_MEPC:
|
|
|
|
|
case GDB_REGNO_MCAUSE:
|
|
|
|
|
case GDB_REGNO_SATP:
|
|
|
|
|
/*
|
|
|
|
|
* WARL registers might not contain the value we just wrote, but
|
|
|
|
|
* these ones won't spontaneously change their value either. *
|
|
|
|
|
*/
|
|
|
|
|
return !write;
|
|
|
|
|
|
|
|
|
|
case GDB_REGNO_TSELECT: /* I think this should be above, but then it doesn't work. */
|
|
|
|
|
case GDB_REGNO_TDATA1: /* Changes value when tselect is changed. */
|
|
|
|
|
case GDB_REGNO_TDATA2: /* Changse value when tselect is changed. */
|
|
|
|
|
default:
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-05-17 20:01:00 -05:00
|
|
|
|
/**
|
|
|
|
|
* This function is called when the debug user wants to change the value of a
|
|
|
|
|
* register. The new value may be cached, and may not be written until the hart
|
2018-05-17 20:08:08 -05:00
|
|
|
|
* is resumed. */
|
2021-01-18 14:22:43 -06:00
|
|
|
|
int riscv_set_register(struct target *target, enum gdb_regno regid, riscv_reg_t value)
|
2017-03-24 20:21:56 -05:00
|
|
|
|
{
|
|
|
|
|
RISCV_INFO(r);
|
2021-01-18 14:22:43 -06:00
|
|
|
|
LOG_DEBUG("[%s] %s <- %" PRIx64, target_name(target), gdb_regno_name(regid), value);
|
2017-07-10 12:26:24 -05:00
|
|
|
|
assert(r->set_register);
|
2019-07-08 14:26:01 -05:00
|
|
|
|
|
2021-05-12 13:43:26 -05:00
|
|
|
|
keep_alive();
|
|
|
|
|
|
2019-07-08 14:26:01 -05:00
|
|
|
|
/* TODO: Hack to deal with gdb that thinks these registers still exist. */
|
|
|
|
|
if (regid > GDB_REGNO_XPR15 && regid <= GDB_REGNO_XPR31 && value == 0 &&
|
2021-01-18 14:22:43 -06:00
|
|
|
|
riscv_supports_extension(target, 'E'))
|
2019-07-08 14:26:01 -05:00
|
|
|
|
return ERROR_OK;
|
|
|
|
|
|
2020-04-21 16:58:59 -05:00
|
|
|
|
struct reg *reg = &target->reg_cache->reg_list[regid];
|
|
|
|
|
buf_set_u64(reg->value, 0, reg->size, value);
|
|
|
|
|
|
2021-09-23 17:07:38 -05:00
|
|
|
|
if (gdb_regno_cacheable(regid, true)) {
|
|
|
|
|
reg->valid = true;
|
|
|
|
|
reg->dirty = true;
|
|
|
|
|
} else {
|
|
|
|
|
if (r->set_register(target, regid, value) != ERROR_OK)
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-18 14:22:43 -06:00
|
|
|
|
LOG_DEBUG("[%s] wrote 0x%" PRIx64 " to %s valid=%d",
|
|
|
|
|
target_name(target), value, reg->name, reg->valid);
|
2021-09-23 17:07:38 -05:00
|
|
|
|
return ERROR_OK;
|
2017-03-24 20:21:56 -05:00
|
|
|
|
}
|
|
|
|
|
|
2017-12-29 16:35:49 -06:00
|
|
|
|
int riscv_get_register(struct target *target, riscv_reg_t *value,
|
2021-01-18 14:22:43 -06:00
|
|
|
|
enum gdb_regno regid)
|
2017-03-24 20:21:56 -05:00
|
|
|
|
{
|
|
|
|
|
RISCV_INFO(r);
|
2018-10-30 13:29:00 -05:00
|
|
|
|
|
2021-09-01 17:00:46 -05:00
|
|
|
|
keep_alive();
|
|
|
|
|
|
2019-01-10 14:32:03 -06:00
|
|
|
|
struct reg *reg = &target->reg_cache->reg_list[regid];
|
2020-04-21 16:58:59 -05:00
|
|
|
|
if (!reg->exist) {
|
2021-01-18 14:22:43 -06:00
|
|
|
|
LOG_DEBUG("[%s] %s does not exist.",
|
|
|
|
|
target_name(target), gdb_regno_name(regid));
|
2020-04-21 16:58:59 -05:00
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
2019-02-07 15:24:44 -06:00
|
|
|
|
|
2021-01-18 14:22:43 -06:00
|
|
|
|
if (reg && reg->valid) {
|
2019-01-10 14:32:03 -06:00
|
|
|
|
*value = buf_get_u64(reg->value, 0, reg->size);
|
2021-01-18 14:22:43 -06:00
|
|
|
|
LOG_DEBUG("[%s] %s: %" PRIx64 " (cached)", target_name(target),
|
2020-04-21 16:58:59 -05:00
|
|
|
|
gdb_regno_name(regid), *value);
|
2019-01-10 14:32:03 -06:00
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-08 14:26:01 -05:00
|
|
|
|
/* TODO: Hack to deal with gdb that thinks these registers still exist. */
|
|
|
|
|
if (regid > GDB_REGNO_XPR15 && regid <= GDB_REGNO_XPR31 &&
|
2021-01-18 14:22:43 -06:00
|
|
|
|
riscv_supports_extension(target, 'E')) {
|
2019-07-08 14:26:01 -05:00
|
|
|
|
*value = 0;
|
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-18 14:22:43 -06:00
|
|
|
|
int result = r->get_register(target, value, regid);
|
2018-10-30 13:29:00 -05:00
|
|
|
|
|
2021-09-23 17:07:38 -05:00
|
|
|
|
if (result == ERROR_OK) {
|
|
|
|
|
/* Update the cache in case we're called from
|
|
|
|
|
* riscv_save_register(). */
|
|
|
|
|
buf_set_u64(reg->value, 0, reg->size, *value);
|
2020-04-21 16:58:59 -05:00
|
|
|
|
reg->valid = gdb_regno_cacheable(regid, false);
|
2021-09-23 17:07:38 -05:00
|
|
|
|
}
|
2020-04-21 16:58:59 -05:00
|
|
|
|
|
2021-01-18 14:22:43 -06:00
|
|
|
|
LOG_DEBUG("[%s] %s: %" PRIx64, target_name(target),
|
|
|
|
|
gdb_regno_name(regid), *value);
|
2017-12-29 16:35:49 -06:00
|
|
|
|
return result;
|
2017-03-24 20:21:56 -05:00
|
|
|
|
}
|
|
|
|
|
|
2021-09-23 17:07:38 -05:00
|
|
|
|
int riscv_save_register(struct target *target, enum gdb_regno regid)
|
|
|
|
|
{
|
2021-10-28 14:52:13 -05:00
|
|
|
|
RISCV_INFO(r);
|
2021-09-23 17:07:38 -05:00
|
|
|
|
riscv_reg_t value;
|
|
|
|
|
if (!target->reg_cache) {
|
|
|
|
|
assert(!target_was_examined(target));
|
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct reg *reg = &target->reg_cache->reg_list[regid];
|
|
|
|
|
LOG_DEBUG("[%s] save %s", target_name(target), reg->name);
|
|
|
|
|
if (riscv_get_register(target, &value, regid) != ERROR_OK)
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
|
|
|
|
|
if (!reg->valid)
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
/* Mark the register dirty. We assume that this function is called
|
|
|
|
|
* because the caller is about to mess with the underlying value of the
|
|
|
|
|
* register. */
|
|
|
|
|
reg->dirty = true;
|
2021-10-28 14:52:13 -05:00
|
|
|
|
|
|
|
|
|
r->last_activity = timeval_ms();
|
|
|
|
|
|
2021-09-23 17:07:38 -05:00
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-10 12:27:04 -06:00
|
|
|
|
int riscv_get_hart_state(struct target *target, enum riscv_hart_state *state)
|
2017-03-24 20:21:56 -05:00
|
|
|
|
{
|
|
|
|
|
RISCV_INFO(r);
|
2022-11-10 12:27:04 -06:00
|
|
|
|
assert(r->get_hart_state);
|
|
|
|
|
return r->get_hart_state(target, state);
|
2017-03-24 20:21:56 -05:00
|
|
|
|
}
|
|
|
|
|
|
2022-09-23 13:32:42 -05:00
|
|
|
|
enum riscv_halt_reason riscv_halt_reason(struct target *target)
|
2017-03-24 20:21:56 -05:00
|
|
|
|
{
|
|
|
|
|
RISCV_INFO(r);
|
2022-09-23 13:32:42 -05:00
|
|
|
|
if (target->state != TARGET_HALTED) {
|
2017-12-27 15:04:30 -06:00
|
|
|
|
LOG_ERROR("Hart is not halted!");
|
|
|
|
|
return RISCV_HALT_UNKNOWN;
|
|
|
|
|
}
|
2017-03-24 20:21:56 -05:00
|
|
|
|
return r->halt_reason(target);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t riscv_debug_buffer_size(struct target *target)
|
|
|
|
|
{
|
|
|
|
|
RISCV_INFO(r);
|
2021-01-18 14:22:43 -06:00
|
|
|
|
return r->debug_buffer_size;
|
2017-03-24 20:21:56 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int riscv_write_debug_buffer(struct target *target, int index, riscv_insn_t insn)
|
|
|
|
|
{
|
|
|
|
|
RISCV_INFO(r);
|
|
|
|
|
r->write_debug_buffer(target, index, insn);
|
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
riscv_insn_t riscv_read_debug_buffer(struct target *target, int index)
|
|
|
|
|
{
|
|
|
|
|
RISCV_INFO(r);
|
|
|
|
|
return r->read_debug_buffer(target, index);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int riscv_execute_debug_buffer(struct target *target)
|
|
|
|
|
{
|
|
|
|
|
RISCV_INFO(r);
|
|
|
|
|
return r->execute_debug_buffer(target);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void riscv_fill_dmi_write_u64(struct target *target, char *buf, int a, uint64_t d)
|
|
|
|
|
{
|
|
|
|
|
RISCV_INFO(r);
|
|
|
|
|
r->fill_dmi_write_u64(target, buf, a, d);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void riscv_fill_dmi_read_u64(struct target *target, char *buf, int a)
|
|
|
|
|
{
|
|
|
|
|
RISCV_INFO(r);
|
|
|
|
|
r->fill_dmi_read_u64(target, buf, a);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void riscv_fill_dmi_nop_u64(struct target *target, char *buf)
|
|
|
|
|
{
|
|
|
|
|
RISCV_INFO(r);
|
|
|
|
|
r->fill_dmi_nop_u64(target, buf);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int riscv_dmi_write_u64_bits(struct target *target)
|
|
|
|
|
{
|
|
|
|
|
RISCV_INFO(r);
|
|
|
|
|
return r->dmi_write_u64_bits(target);
|
|
|
|
|
}
|
2017-06-20 19:14:18 -05:00
|
|
|
|
|
2017-07-10 12:26:24 -05:00
|
|
|
|
/**
|
|
|
|
|
* Count triggers, and initialize trigger_count for each hart.
|
|
|
|
|
* trigger_count is initialized even if this function fails to discover
|
|
|
|
|
* something.
|
|
|
|
|
* Disable any hardware triggers that have dmode set. We can't have set them
|
|
|
|
|
* ourselves. Maybe they're left over from some killed debug session.
|
|
|
|
|
* */
|
|
|
|
|
int riscv_enumerate_triggers(struct target *target)
|
|
|
|
|
{
|
|
|
|
|
RISCV_INFO(r);
|
|
|
|
|
|
2018-05-22 14:32:01 -05:00
|
|
|
|
if (r->triggers_enumerated)
|
|
|
|
|
return ERROR_OK;
|
|
|
|
|
|
|
|
|
|
r->triggers_enumerated = true; /* At the very least we tried. */
|
|
|
|
|
|
2021-01-18 14:22:43 -06:00
|
|
|
|
riscv_reg_t tselect;
|
|
|
|
|
int result = riscv_get_register(target, &tselect, GDB_REGNO_TSELECT);
|
|
|
|
|
/* If tselect is not readable, the trigger module is likely not
|
|
|
|
|
* implemented. There are no triggers to enumerate then and no error
|
|
|
|
|
* should be thrown. */
|
|
|
|
|
if (result != ERROR_OK) {
|
|
|
|
|
LOG_DEBUG("[%s] Cannot access tselect register. "
|
|
|
|
|
"Assuming that triggers are not implemented.", target_name(target));
|
|
|
|
|
r->trigger_count = 0;
|
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
2017-07-10 12:26:24 -05:00
|
|
|
|
|
2021-09-01 17:00:46 -05:00
|
|
|
|
for (unsigned int t = 0; t < RISCV_MAX_TRIGGERS; ++t) {
|
2021-01-18 14:22:43 -06:00
|
|
|
|
r->trigger_count = t;
|
2017-07-11 16:49:35 -05:00
|
|
|
|
|
2021-01-18 14:22:43 -06:00
|
|
|
|
/* If we can't write tselect, then this hart does not support triggers. */
|
|
|
|
|
if (riscv_set_register(target, GDB_REGNO_TSELECT, t) != ERROR_OK)
|
|
|
|
|
break;
|
|
|
|
|
uint64_t tselect_rb;
|
|
|
|
|
result = riscv_get_register(target, &tselect_rb, GDB_REGNO_TSELECT);
|
|
|
|
|
if (result != ERROR_OK)
|
|
|
|
|
return result;
|
|
|
|
|
/* Mask off the top bit, which is used as tdrmode in old
|
|
|
|
|
* implementations. */
|
2021-09-01 17:00:46 -05:00
|
|
|
|
tselect_rb &= ~(1ULL << (riscv_xlen(target) - 1));
|
2021-01-18 14:22:43 -06:00
|
|
|
|
if (tselect_rb != t)
|
|
|
|
|
break;
|
2017-07-10 12:26:24 -05:00
|
|
|
|
|
2022-11-09 16:48:31 -06:00
|
|
|
|
uint64_t tinfo;
|
|
|
|
|
result = riscv_get_register(target, &tinfo, GDB_REGNO_TINFO);
|
|
|
|
|
if (result == ERROR_OK) {
|
|
|
|
|
/* tinfo == 0 invalid tinfo
|
|
|
|
|
* tinfo == 1 trigger doesn’t exist */
|
|
|
|
|
if (tinfo == 0 || tinfo == 1)
|
2017-07-10 12:26:24 -05:00
|
|
|
|
break;
|
2022-11-09 16:48:31 -06:00
|
|
|
|
r->trigger_tinfo[t] = tinfo;
|
|
|
|
|
} else {
|
|
|
|
|
uint64_t tdata1;
|
|
|
|
|
result = riscv_get_register(target, &tdata1, GDB_REGNO_TDATA1);
|
|
|
|
|
if (result != ERROR_OK)
|
|
|
|
|
return result;
|
|
|
|
|
|
|
|
|
|
int type = get_field(tdata1, CSR_TDATA1_TYPE(riscv_xlen(target)));
|
|
|
|
|
if (type == 0)
|
2020-07-07 13:55:57 -05:00
|
|
|
|
break;
|
2022-11-09 16:48:31 -06:00
|
|
|
|
switch (type) {
|
2022-12-27 14:53:52 -06:00
|
|
|
|
case CSR_TDATA1_TYPE_LEGACY:
|
2022-11-09 16:48:31 -06:00
|
|
|
|
/* On these older cores we don't support software using
|
|
|
|
|
* triggers. */
|
2021-10-05 12:03:19 -05:00
|
|
|
|
riscv_set_register(target, GDB_REGNO_TDATA1, 0);
|
2022-11-09 16:48:31 -06:00
|
|
|
|
break;
|
2022-12-27 14:53:52 -06:00
|
|
|
|
case CSR_TDATA1_TYPE_MCONTROL:
|
2022-11-09 16:48:31 -06:00
|
|
|
|
if (tdata1 & CSR_MCONTROL_DMODE(riscv_xlen(target)))
|
|
|
|
|
riscv_set_register(target, GDB_REGNO_TDATA1, 0);
|
|
|
|
|
break;
|
2022-12-27 14:53:52 -06:00
|
|
|
|
case CSR_TDATA1_TYPE_MCONTROL6:
|
2022-11-09 16:48:31 -06:00
|
|
|
|
if (tdata1 & CSR_MCONTROL6_DMODE(riscv_xlen(target)))
|
|
|
|
|
riscv_set_register(target, GDB_REGNO_TDATA1, 0);
|
|
|
|
|
break;
|
2022-11-18 17:57:17 -06:00
|
|
|
|
case CSR_TDATA1_TYPE_ITRIGGER:
|
|
|
|
|
if (tdata1 & CSR_ITRIGGER_DMODE(riscv_xlen(target)))
|
|
|
|
|
riscv_set_register(target, GDB_REGNO_TDATA1, 0);
|
|
|
|
|
break;
|
2022-12-28 13:47:50 -06:00
|
|
|
|
case CSR_TDATA1_TYPE_ETRIGGER:
|
|
|
|
|
if (tdata1 & CSR_ETRIGGER_DMODE(riscv_xlen(target)))
|
|
|
|
|
riscv_set_register(target, GDB_REGNO_TDATA1, 0);
|
|
|
|
|
break;
|
2022-11-09 16:48:31 -06:00
|
|
|
|
}
|
|
|
|
|
r->trigger_tinfo[t] = 1 << type;
|
2017-07-10 12:26:24 -05:00
|
|
|
|
}
|
2022-11-09 16:48:31 -06:00
|
|
|
|
LOG_TARGET_DEBUG(target, "Trigger %u: supported types (mask) = 0x%08x", t, r->trigger_tinfo[t]);
|
2021-01-18 14:22:43 -06:00
|
|
|
|
}
|
2017-07-10 12:26:24 -05:00
|
|
|
|
|
2021-01-18 14:22:43 -06:00
|
|
|
|
riscv_set_register(target, GDB_REGNO_TSELECT, tselect);
|
2017-07-11 16:49:35 -05:00
|
|
|
|
|
2021-01-18 14:22:43 -06:00
|
|
|
|
LOG_INFO("[%s] Found %d triggers", target_name(target), r->trigger_count);
|
2017-07-10 12:26:24 -05:00
|
|
|
|
|
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
2017-07-27 15:45:26 -05:00
|
|
|
|
|
|
|
|
|
const char *gdb_regno_name(enum gdb_regno regno)
|
|
|
|
|
{
|
|
|
|
|
static char buf[32];
|
|
|
|
|
|
|
|
|
|
switch (regno) {
|
|
|
|
|
case GDB_REGNO_ZERO:
|
|
|
|
|
return "zero";
|
2019-07-09 12:05:07 -05:00
|
|
|
|
case GDB_REGNO_RA:
|
|
|
|
|
return "ra";
|
|
|
|
|
case GDB_REGNO_SP:
|
|
|
|
|
return "sp";
|
|
|
|
|
case GDB_REGNO_GP:
|
|
|
|
|
return "gp";
|
|
|
|
|
case GDB_REGNO_TP:
|
|
|
|
|
return "tp";
|
|
|
|
|
case GDB_REGNO_T0:
|
|
|
|
|
return "t0";
|
|
|
|
|
case GDB_REGNO_T1:
|
|
|
|
|
return "t1";
|
|
|
|
|
case GDB_REGNO_T2:
|
|
|
|
|
return "t2";
|
2017-07-27 15:45:26 -05:00
|
|
|
|
case GDB_REGNO_S0:
|
|
|
|
|
return "s0";
|
|
|
|
|
case GDB_REGNO_S1:
|
|
|
|
|
return "s1";
|
2019-07-09 12:05:07 -05:00
|
|
|
|
case GDB_REGNO_A0:
|
|
|
|
|
return "a0";
|
|
|
|
|
case GDB_REGNO_A1:
|
|
|
|
|
return "a1";
|
|
|
|
|
case GDB_REGNO_A2:
|
|
|
|
|
return "a2";
|
|
|
|
|
case GDB_REGNO_A3:
|
|
|
|
|
return "a3";
|
|
|
|
|
case GDB_REGNO_A4:
|
|
|
|
|
return "a4";
|
|
|
|
|
case GDB_REGNO_A5:
|
|
|
|
|
return "a5";
|
|
|
|
|
case GDB_REGNO_A6:
|
|
|
|
|
return "a6";
|
|
|
|
|
case GDB_REGNO_A7:
|
|
|
|
|
return "a7";
|
|
|
|
|
case GDB_REGNO_S2:
|
|
|
|
|
return "s2";
|
|
|
|
|
case GDB_REGNO_S3:
|
|
|
|
|
return "s3";
|
|
|
|
|
case GDB_REGNO_S4:
|
|
|
|
|
return "s4";
|
|
|
|
|
case GDB_REGNO_S5:
|
|
|
|
|
return "s5";
|
|
|
|
|
case GDB_REGNO_S6:
|
|
|
|
|
return "s6";
|
|
|
|
|
case GDB_REGNO_S7:
|
|
|
|
|
return "s7";
|
|
|
|
|
case GDB_REGNO_S8:
|
|
|
|
|
return "s8";
|
|
|
|
|
case GDB_REGNO_S9:
|
|
|
|
|
return "s9";
|
|
|
|
|
case GDB_REGNO_S10:
|
|
|
|
|
return "s10";
|
|
|
|
|
case GDB_REGNO_S11:
|
|
|
|
|
return "s11";
|
|
|
|
|
case GDB_REGNO_T3:
|
|
|
|
|
return "t3";
|
|
|
|
|
case GDB_REGNO_T4:
|
|
|
|
|
return "t4";
|
|
|
|
|
case GDB_REGNO_T5:
|
|
|
|
|
return "t5";
|
|
|
|
|
case GDB_REGNO_T6:
|
|
|
|
|
return "t6";
|
2017-07-27 15:45:26 -05:00
|
|
|
|
case GDB_REGNO_PC:
|
|
|
|
|
return "pc";
|
|
|
|
|
case GDB_REGNO_FPR0:
|
|
|
|
|
return "fpr0";
|
|
|
|
|
case GDB_REGNO_FPR31:
|
|
|
|
|
return "fpr31";
|
|
|
|
|
case GDB_REGNO_CSR0:
|
|
|
|
|
return "csr0";
|
|
|
|
|
case GDB_REGNO_TSELECT:
|
|
|
|
|
return "tselect";
|
|
|
|
|
case GDB_REGNO_TDATA1:
|
|
|
|
|
return "tdata1";
|
|
|
|
|
case GDB_REGNO_TDATA2:
|
|
|
|
|
return "tdata2";
|
|
|
|
|
case GDB_REGNO_MISA:
|
|
|
|
|
return "misa";
|
|
|
|
|
case GDB_REGNO_DPC:
|
|
|
|
|
return "dpc";
|
|
|
|
|
case GDB_REGNO_DCSR:
|
|
|
|
|
return "dcsr";
|
2020-08-24 17:42:45 -05:00
|
|
|
|
case GDB_REGNO_DSCRATCH0:
|
|
|
|
|
return "dscratch0";
|
2017-07-27 15:45:26 -05:00
|
|
|
|
case GDB_REGNO_MSTATUS:
|
|
|
|
|
return "mstatus";
|
2019-09-09 14:01:17 -05:00
|
|
|
|
case GDB_REGNO_MEPC:
|
|
|
|
|
return "mepc";
|
|
|
|
|
case GDB_REGNO_MCAUSE:
|
|
|
|
|
return "mcause";
|
2017-07-27 15:45:26 -05:00
|
|
|
|
case GDB_REGNO_PRIV:
|
|
|
|
|
return "priv";
|
2019-12-10 14:18:03 -06:00
|
|
|
|
case GDB_REGNO_SATP:
|
|
|
|
|
return "satp";
|
2020-02-14 16:54:05 -06:00
|
|
|
|
case GDB_REGNO_VTYPE:
|
|
|
|
|
return "vtype";
|
|
|
|
|
case GDB_REGNO_VL:
|
|
|
|
|
return "vl";
|
|
|
|
|
case GDB_REGNO_V0:
|
|
|
|
|
return "v0";
|
|
|
|
|
case GDB_REGNO_V1:
|
|
|
|
|
return "v1";
|
|
|
|
|
case GDB_REGNO_V2:
|
|
|
|
|
return "v2";
|
|
|
|
|
case GDB_REGNO_V3:
|
|
|
|
|
return "v3";
|
|
|
|
|
case GDB_REGNO_V4:
|
|
|
|
|
return "v4";
|
|
|
|
|
case GDB_REGNO_V5:
|
|
|
|
|
return "v5";
|
|
|
|
|
case GDB_REGNO_V6:
|
|
|
|
|
return "v6";
|
|
|
|
|
case GDB_REGNO_V7:
|
|
|
|
|
return "v7";
|
|
|
|
|
case GDB_REGNO_V8:
|
|
|
|
|
return "v8";
|
|
|
|
|
case GDB_REGNO_V9:
|
|
|
|
|
return "v9";
|
|
|
|
|
case GDB_REGNO_V10:
|
|
|
|
|
return "v10";
|
|
|
|
|
case GDB_REGNO_V11:
|
|
|
|
|
return "v11";
|
|
|
|
|
case GDB_REGNO_V12:
|
|
|
|
|
return "v12";
|
|
|
|
|
case GDB_REGNO_V13:
|
|
|
|
|
return "v13";
|
|
|
|
|
case GDB_REGNO_V14:
|
|
|
|
|
return "v14";
|
|
|
|
|
case GDB_REGNO_V15:
|
|
|
|
|
return "v15";
|
|
|
|
|
case GDB_REGNO_V16:
|
|
|
|
|
return "v16";
|
|
|
|
|
case GDB_REGNO_V17:
|
|
|
|
|
return "v17";
|
|
|
|
|
case GDB_REGNO_V18:
|
|
|
|
|
return "v18";
|
|
|
|
|
case GDB_REGNO_V19:
|
|
|
|
|
return "v19";
|
|
|
|
|
case GDB_REGNO_V20:
|
|
|
|
|
return "v20";
|
|
|
|
|
case GDB_REGNO_V21:
|
|
|
|
|
return "v21";
|
|
|
|
|
case GDB_REGNO_V22:
|
|
|
|
|
return "v22";
|
|
|
|
|
case GDB_REGNO_V23:
|
|
|
|
|
return "v23";
|
|
|
|
|
case GDB_REGNO_V24:
|
|
|
|
|
return "v24";
|
|
|
|
|
case GDB_REGNO_V25:
|
|
|
|
|
return "v25";
|
|
|
|
|
case GDB_REGNO_V26:
|
|
|
|
|
return "v26";
|
|
|
|
|
case GDB_REGNO_V27:
|
|
|
|
|
return "v27";
|
|
|
|
|
case GDB_REGNO_V28:
|
|
|
|
|
return "v28";
|
|
|
|
|
case GDB_REGNO_V29:
|
|
|
|
|
return "v29";
|
|
|
|
|
case GDB_REGNO_V30:
|
|
|
|
|
return "v30";
|
|
|
|
|
case GDB_REGNO_V31:
|
|
|
|
|
return "v31";
|
2017-07-27 15:45:26 -05:00
|
|
|
|
default:
|
2017-12-22 16:35:38 -06:00
|
|
|
|
if (regno <= GDB_REGNO_XPR31)
|
2017-11-27 16:47:33 -06:00
|
|
|
|
sprintf(buf, "x%d", regno - GDB_REGNO_ZERO);
|
2017-12-22 16:35:38 -06:00
|
|
|
|
else if (regno >= GDB_REGNO_CSR0 && regno <= GDB_REGNO_CSR4095)
|
2017-07-27 15:45:26 -05:00
|
|
|
|
sprintf(buf, "csr%d", regno - GDB_REGNO_CSR0);
|
2017-12-22 16:35:38 -06:00
|
|
|
|
else if (regno >= GDB_REGNO_FPR0 && regno <= GDB_REGNO_FPR31)
|
2017-09-14 18:21:49 -05:00
|
|
|
|
sprintf(buf, "f%d", regno - GDB_REGNO_FPR0);
|
2017-12-22 16:35:38 -06:00
|
|
|
|
else
|
2017-07-27 15:45:26 -05:00
|
|
|
|
sprintf(buf, "gdb_regno_%d", regno);
|
|
|
|
|
return buf;
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-12-01 14:42:16 -06:00
|
|
|
|
|
|
|
|
|
static int register_get(struct reg *reg)
|
|
|
|
|
{
|
2018-08-29 16:22:50 -05:00
|
|
|
|
riscv_reg_info_t *reg_info = reg->arch_info;
|
|
|
|
|
struct target *target = reg_info->target;
|
2020-02-14 16:54:05 -06:00
|
|
|
|
RISCV_INFO(r);
|
|
|
|
|
|
|
|
|
|
if (reg->number >= GDB_REGNO_V0 && reg->number <= GDB_REGNO_V31) {
|
|
|
|
|
if (!r->get_register_buf) {
|
|
|
|
|
LOG_ERROR("Reading register %s not supported on this RISC-V target.",
|
|
|
|
|
gdb_regno_name(reg->number));
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (r->get_register_buf(target, reg->value, reg->number) != ERROR_OK)
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
} else {
|
|
|
|
|
uint64_t value;
|
|
|
|
|
int result = riscv_get_register(target, &value, reg->number);
|
|
|
|
|
if (result != ERROR_OK)
|
|
|
|
|
return result;
|
|
|
|
|
buf_set_u64(reg->value, 0, reg->size, value);
|
|
|
|
|
}
|
2020-04-21 16:58:59 -05:00
|
|
|
|
reg->valid = gdb_regno_cacheable(reg->number, false);
|
2020-10-14 03:41:12 -05:00
|
|
|
|
char *str = buf_to_hex_str(reg->value, reg->size);
|
2021-01-18 14:22:43 -06:00
|
|
|
|
LOG_DEBUG("[%s] read 0x%s from %s (valid=%d)", target_name(target),
|
|
|
|
|
str, reg->name, reg->valid);
|
2020-02-14 16:54:05 -06:00
|
|
|
|
free(str);
|
2017-12-01 14:42:16 -06:00
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int register_set(struct reg *reg, uint8_t *buf)
|
|
|
|
|
{
|
2018-08-29 16:22:50 -05:00
|
|
|
|
riscv_reg_info_t *reg_info = reg->arch_info;
|
|
|
|
|
struct target *target = reg_info->target;
|
2020-02-14 16:54:05 -06:00
|
|
|
|
RISCV_INFO(r);
|
2017-12-01 14:42:16 -06:00
|
|
|
|
|
2020-10-14 03:41:12 -05:00
|
|
|
|
char *str = buf_to_hex_str(buf, reg->size);
|
2021-01-18 14:22:43 -06:00
|
|
|
|
LOG_DEBUG("[%s] write 0x%s to %s (valid=%d)", target_name(target),
|
|
|
|
|
str, reg->name, reg->valid);
|
2020-02-14 16:54:05 -06:00
|
|
|
|
free(str);
|
2017-12-01 14:42:16 -06:00
|
|
|
|
|
2021-01-14 15:52:50 -06:00
|
|
|
|
/* Exit early for writing x0, which on the hardware would be ignored, and we
|
|
|
|
|
* don't want to update our cache. */
|
|
|
|
|
if (reg->number == GDB_REGNO_ZERO)
|
|
|
|
|
return ERROR_OK;
|
|
|
|
|
|
2020-02-14 16:54:05 -06:00
|
|
|
|
memcpy(reg->value, buf, DIV_ROUND_UP(reg->size, 8));
|
2020-04-21 16:58:59 -05:00
|
|
|
|
reg->valid = gdb_regno_cacheable(reg->number, true);
|
2020-02-14 16:54:05 -06:00
|
|
|
|
|
2020-06-18 16:47:42 -05:00
|
|
|
|
if (reg->number == GDB_REGNO_TDATA1 ||
|
|
|
|
|
reg->number == GDB_REGNO_TDATA2) {
|
|
|
|
|
r->manual_hwbp_set = true;
|
|
|
|
|
/* When enumerating triggers, we clear any triggers with DMODE set,
|
|
|
|
|
* assuming they were left over from a previous debug session. So make
|
|
|
|
|
* sure that is done before a user might be setting their own triggers.
|
|
|
|
|
*/
|
|
|
|
|
if (riscv_enumerate_triggers(target) != ERROR_OK)
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-14 16:54:05 -06:00
|
|
|
|
if (reg->number >= GDB_REGNO_V0 && reg->number <= GDB_REGNO_V31) {
|
|
|
|
|
if (!r->set_register_buf) {
|
|
|
|
|
LOG_ERROR("Writing register %s not supported on this RISC-V target.",
|
|
|
|
|
gdb_regno_name(reg->number));
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (r->set_register_buf(target, reg->number, reg->value) != ERROR_OK)
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
} else {
|
|
|
|
|
uint64_t value = buf_get_u64(buf, 0, reg->size);
|
|
|
|
|
if (riscv_set_register(target, reg->number, value) != ERROR_OK)
|
|
|
|
|
return ERROR_FAIL;
|
|
|
|
|
}
|
2017-12-01 14:42:16 -06:00
|
|
|
|
|
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct reg_arch_type riscv_reg_arch_type = {
|
|
|
|
|
.get = register_get,
|
|
|
|
|
.set = register_set
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct csr_info {
|
|
|
|
|
unsigned number;
|
|
|
|
|
const char *name;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static int cmp_csr_info(const void *p1, const void *p2)
|
|
|
|
|
{
|
|
|
|
|
return (int) (((struct csr_info *)p1)->number) - (int) (((struct csr_info *)p2)->number);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int riscv_init_registers(struct target *target)
|
|
|
|
|
{
|
|
|
|
|
RISCV_INFO(info);
|
|
|
|
|
|
2019-04-01 06:47:17 -05:00
|
|
|
|
riscv_free_registers(target);
|
2017-12-01 14:42:16 -06:00
|
|
|
|
|
|
|
|
|
target->reg_cache = calloc(1, sizeof(*target->reg_cache));
|
2020-09-03 13:57:25 -05:00
|
|
|
|
if (!target->reg_cache)
|
|
|
|
|
return ERROR_FAIL;
|
2017-12-01 14:42:16 -06:00
|
|
|
|
target->reg_cache->name = "RISC-V Registers";
|
|
|
|
|
target->reg_cache->num_regs = GDB_REGNO_COUNT;
|
|
|
|
|
|
2020-10-01 13:05:41 -05:00
|
|
|
|
if (!list_empty(&info->expose_custom)) {
|
|
|
|
|
range_list_t *entry;
|
|
|
|
|
list_for_each_entry(entry, &info->expose_custom, list)
|
|
|
|
|
target->reg_cache->num_regs += entry->high - entry->low + 1;
|
2018-08-29 16:22:50 -05:00
|
|
|
|
}
|
|
|
|
|
|
2021-10-21 19:08:49 -05:00
|
|
|
|
LOG_DEBUG("[%s] create register cache for %d registers",
|
|
|
|
|
target_name(target), target->reg_cache->num_regs);
|
2018-08-29 16:22:50 -05:00
|
|
|
|
|
|
|
|
|
target->reg_cache->reg_list =
|
|
|
|
|
calloc(target->reg_cache->num_regs, sizeof(struct reg));
|
2020-09-03 13:57:25 -05:00
|
|
|
|
if (!target->reg_cache->reg_list)
|
|
|
|
|
return ERROR_FAIL;
|
2017-12-01 14:42:16 -06:00
|
|
|
|
|
|
|
|
|
const unsigned int max_reg_name_len = 12;
|
2020-09-03 13:57:25 -05:00
|
|
|
|
free(info->reg_names);
|
2018-08-29 16:22:50 -05:00
|
|
|
|
info->reg_names =
|
|
|
|
|
calloc(target->reg_cache->num_regs, max_reg_name_len);
|
2020-09-03 13:57:25 -05:00
|
|
|
|
if (!info->reg_names)
|
|
|
|
|
return ERROR_FAIL;
|
2017-12-01 14:42:16 -06:00
|
|
|
|
char *reg_name = info->reg_names;
|
|
|
|
|
|
|
|
|
|
static struct reg_feature feature_cpu = {
|
|
|
|
|
.name = "org.gnu.gdb.riscv.cpu"
|
|
|
|
|
};
|
|
|
|
|
static struct reg_feature feature_fpu = {
|
|
|
|
|
.name = "org.gnu.gdb.riscv.fpu"
|
|
|
|
|
};
|
|
|
|
|
static struct reg_feature feature_csr = {
|
|
|
|
|
.name = "org.gnu.gdb.riscv.csr"
|
|
|
|
|
};
|
2020-02-14 16:54:05 -06:00
|
|
|
|
static struct reg_feature feature_vector = {
|
|
|
|
|
.name = "org.gnu.gdb.riscv.vector"
|
|
|
|
|
};
|
2017-12-01 14:42:16 -06:00
|
|
|
|
static struct reg_feature feature_virtual = {
|
|
|
|
|
.name = "org.gnu.gdb.riscv.virtual"
|
|
|
|
|
};
|
2018-08-29 16:22:50 -05:00
|
|
|
|
static struct reg_feature feature_custom = {
|
|
|
|
|
.name = "org.gnu.gdb.riscv.custom"
|
|
|
|
|
};
|
2017-12-01 14:42:16 -06:00
|
|
|
|
|
2020-02-14 16:54:05 -06:00
|
|
|
|
/* These types are built into gdb. */
|
|
|
|
|
static struct reg_data_type type_ieee_single = { .type = REG_TYPE_IEEE_SINGLE, .id = "ieee_single" };
|
|
|
|
|
static struct reg_data_type type_ieee_double = { .type = REG_TYPE_IEEE_DOUBLE, .id = "ieee_double" };
|
2020-04-10 15:32:12 -05:00
|
|
|
|
static struct reg_data_type_union_field single_double_fields[] = {
|
|
|
|
|
{"float", &type_ieee_single, single_double_fields + 1},
|
|
|
|
|
{"double", &type_ieee_double, NULL},
|
|
|
|
|
};
|
|
|
|
|
static struct reg_data_type_union single_double_union = {
|
|
|
|
|
.fields = single_double_fields
|
|
|
|
|
};
|
|
|
|
|
static struct reg_data_type type_ieee_single_double = {
|
|
|
|
|
.type = REG_TYPE_ARCH_DEFINED,
|
|
|
|
|
.id = "FPU_FD",
|
|
|
|
|
.type_class = REG_TYPE_CLASS_UNION,
|
|
|
|
|
.reg_type_union = &single_double_union
|
|
|
|
|
};
|
2020-02-14 16:54:05 -06:00
|
|
|
|
static struct reg_data_type type_uint8 = { .type = REG_TYPE_UINT8, .id = "uint8" };
|
|
|
|
|
static struct reg_data_type type_uint16 = { .type = REG_TYPE_UINT16, .id = "uint16" };
|
|
|
|
|
static struct reg_data_type type_uint32 = { .type = REG_TYPE_UINT32, .id = "uint32" };
|
|
|
|
|
static struct reg_data_type type_uint64 = { .type = REG_TYPE_UINT64, .id = "uint64" };
|
|
|
|
|
static struct reg_data_type type_uint128 = { .type = REG_TYPE_UINT128, .id = "uint128" };
|
|
|
|
|
|
|
|
|
|
/* This is roughly the XML we want:
|
|
|
|
|
* <vector id="bytes" type="uint8" count="16"/>
|
|
|
|
|
* <vector id="shorts" type="uint16" count="8"/>
|
|
|
|
|
* <vector id="words" type="uint32" count="4"/>
|
|
|
|
|
* <vector id="longs" type="uint64" count="2"/>
|
|
|
|
|
* <vector id="quads" type="uint128" count="1"/>
|
|
|
|
|
* <union id="riscv_vector_type">
|
|
|
|
|
* <field name="b" type="bytes"/>
|
|
|
|
|
* <field name="s" type="shorts"/>
|
|
|
|
|
* <field name="w" type="words"/>
|
|
|
|
|
* <field name="l" type="longs"/>
|
|
|
|
|
* <field name="q" type="quads"/>
|
|
|
|
|
* </union>
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
info->vector_uint8.type = &type_uint8;
|
2021-01-18 14:22:43 -06:00
|
|
|
|
info->vector_uint8.count = info->vlenb;
|
2020-02-14 16:54:05 -06:00
|
|
|
|
info->type_uint8_vector.type = REG_TYPE_ARCH_DEFINED;
|
|
|
|
|
info->type_uint8_vector.id = "bytes";
|
|
|
|
|
info->type_uint8_vector.type_class = REG_TYPE_CLASS_VECTOR;
|
|
|
|
|
info->type_uint8_vector.reg_type_vector = &info->vector_uint8;
|
|
|
|
|
|
|
|
|
|
info->vector_uint16.type = &type_uint16;
|
2021-01-18 14:22:43 -06:00
|
|
|
|
info->vector_uint16.count = info->vlenb / 2;
|
2020-02-14 16:54:05 -06:00
|
|
|
|
info->type_uint16_vector.type = REG_TYPE_ARCH_DEFINED;
|
|
|
|
|
info->type_uint16_vector.id = "shorts";
|
|
|
|
|
info->type_uint16_vector.type_class = REG_TYPE_CLASS_VECTOR;
|
|
|
|
|
info->type_uint16_vector.reg_type_vector = &info->vector_uint16;
|
|
|
|
|
|
|
|
|
|
info->vector_uint32.type = &type_uint32;
|
2021-01-18 14:22:43 -06:00
|
|
|
|
info->vector_uint32.count = info->vlenb / 4;
|
2020-02-14 16:54:05 -06:00
|
|
|
|
info->type_uint32_vector.type = REG_TYPE_ARCH_DEFINED;
|
|
|
|
|
info->type_uint32_vector.id = "words";
|
|
|
|
|
info->type_uint32_vector.type_class = REG_TYPE_CLASS_VECTOR;
|
|
|
|
|
info->type_uint32_vector.reg_type_vector = &info->vector_uint32;
|
|
|
|
|
|
|
|
|
|
info->vector_uint64.type = &type_uint64;
|
2021-01-18 14:22:43 -06:00
|
|
|
|
info->vector_uint64.count = info->vlenb / 8;
|
2020-02-14 16:54:05 -06:00
|
|
|
|
info->type_uint64_vector.type = REG_TYPE_ARCH_DEFINED;
|
|
|
|
|
info->type_uint64_vector.id = "longs";
|
|
|
|
|
info->type_uint64_vector.type_class = REG_TYPE_CLASS_VECTOR;
|
|
|
|
|
info->type_uint64_vector.reg_type_vector = &info->vector_uint64;
|
|
|
|
|
|
|
|
|
|
info->vector_uint128.type = &type_uint128;
|
2021-01-18 14:22:43 -06:00
|
|
|
|
info->vector_uint128.count = info->vlenb / 16;
|
2020-02-14 16:54:05 -06:00
|
|
|
|
info->type_uint128_vector.type = REG_TYPE_ARCH_DEFINED;
|
|
|
|
|
info->type_uint128_vector.id = "quads";
|
|
|
|
|
info->type_uint128_vector.type_class = REG_TYPE_CLASS_VECTOR;
|
|
|
|
|
info->type_uint128_vector.reg_type_vector = &info->vector_uint128;
|
|
|
|
|
|
|
|
|
|
info->vector_fields[0].name = "b";
|
|
|
|
|
info->vector_fields[0].type = &info->type_uint8_vector;
|
2021-01-18 14:22:43 -06:00
|
|
|
|
if (info->vlenb >= 2) {
|
2020-02-14 16:54:05 -06:00
|
|
|
|
info->vector_fields[0].next = info->vector_fields + 1;
|
|
|
|
|
info->vector_fields[1].name = "s";
|
|
|
|
|
info->vector_fields[1].type = &info->type_uint16_vector;
|
|
|
|
|
} else {
|
|
|
|
|
info->vector_fields[0].next = NULL;
|
|
|
|
|
}
|
2021-01-18 14:22:43 -06:00
|
|
|
|
if (info->vlenb >= 4) {
|
2020-02-14 16:54:05 -06:00
|
|
|
|
info->vector_fields[1].next = info->vector_fields + 2;
|
|
|
|
|
info->vector_fields[2].name = "w";
|
|
|
|
|
info->vector_fields[2].type = &info->type_uint32_vector;
|
|
|
|
|
} else {
|
|
|
|
|
info->vector_fields[1].next = NULL;
|
|
|
|
|
}
|
2021-01-18 14:22:43 -06:00
|
|
|
|
if (info->vlenb >= 8) {
|
2020-02-14 16:54:05 -06:00
|
|
|
|
info->vector_fields[2].next = info->vector_fields + 3;
|
|
|
|
|
info->vector_fields[3].name = "l";
|
|
|
|
|
info->vector_fields[3].type = &info->type_uint64_vector;
|
|
|
|
|
} else {
|
|
|
|
|
info->vector_fields[2].next = NULL;
|
|
|
|
|
}
|
2021-01-18 14:22:43 -06:00
|
|
|
|
if (info->vlenb >= 16) {
|
2020-02-14 16:54:05 -06:00
|
|
|
|
info->vector_fields[3].next = info->vector_fields + 4;
|
|
|
|
|
info->vector_fields[4].name = "q";
|
|
|
|
|
info->vector_fields[4].type = &info->type_uint128_vector;
|
|
|
|
|
} else {
|
|
|
|
|
info->vector_fields[3].next = NULL;
|
|
|
|
|
}
|
|
|
|
|
info->vector_fields[4].next = NULL;
|
|
|
|
|
|
|
|
|
|
info->vector_union.fields = info->vector_fields;
|
|
|
|
|
|
|
|
|
|
info->type_vector.type = REG_TYPE_ARCH_DEFINED;
|
|
|
|
|
info->type_vector.id = "riscv_vector";
|
|
|
|
|
info->type_vector.type_class = REG_TYPE_CLASS_UNION;
|
|
|
|
|
info->type_vector.reg_type_union = &info->vector_union;
|
|
|
|
|
|
2017-12-01 14:42:16 -06:00
|
|
|
|
struct csr_info csr_info[] = {
|
|
|
|
|
#define DECLARE_CSR(name, number) { number, #name },
|
|
|
|
|
#include "encoding.h"
|
|
|
|
|
#undef DECLARE_CSR
|
|
|
|
|
};
|
2017-12-22 16:35:38 -06:00
|
|
|
|
/* encoding.h does not contain the registers in sorted order. */
|
2021-05-16 06:57:11 -05:00
|
|
|
|
qsort(csr_info, ARRAY_SIZE(csr_info), sizeof(*csr_info), cmp_csr_info);
|
2017-12-01 14:42:16 -06:00
|
|
|
|
unsigned csr_info_index = 0;
|
|
|
|
|
|
2018-08-29 16:22:50 -05:00
|
|
|
|
int custom_within_range = 0;
|
|
|
|
|
|
|
|
|
|
riscv_reg_info_t *shared_reg_info = calloc(1, sizeof(riscv_reg_info_t));
|
2020-09-03 13:57:25 -05:00
|
|
|
|
if (!shared_reg_info)
|
|
|
|
|
return ERROR_FAIL;
|
2018-08-29 16:22:50 -05:00
|
|
|
|
shared_reg_info->target = target;
|
|
|
|
|
|
|
|
|
|
/* When gdb requests register N, gdb_get_register_packet() assumes that this
|
2017-12-22 16:35:38 -06:00
|
|
|
|
* is register at index N in reg_list. So if there are certain registers
|
|
|
|
|
* that don't exist, we need to leave holes in the list (or renumber, but
|
|
|
|
|
* it would be nice not to have yet another set of numbers to translate
|
|
|
|
|
* between). */
|
2018-08-29 16:22:50 -05:00
|
|
|
|
for (uint32_t number = 0; number < target->reg_cache->num_regs; number++) {
|
2017-12-01 14:42:16 -06:00
|
|
|
|
struct reg *r = &target->reg_cache->reg_list[number];
|
|
|
|
|
r->dirty = false;
|
|
|
|
|
r->valid = false;
|
|
|
|
|
r->exist = true;
|
|
|
|
|
r->type = &riscv_reg_arch_type;
|
2018-08-29 16:22:50 -05:00
|
|
|
|
r->arch_info = shared_reg_info;
|
2017-12-01 14:42:16 -06:00
|
|
|
|
r->number = number;
|
|
|
|
|
r->size = riscv_xlen(target);
|
2017-12-22 16:35:38 -06:00
|
|
|
|
/* r->size is set in riscv_invalidate_register_cache, maybe because the
|
|
|
|
|
* target is in theory allowed to change XLEN on us. But I expect a lot
|
|
|
|
|
* of other things to break in that case as well. */
|
2017-12-01 14:42:16 -06:00
|
|
|
|
if (number <= GDB_REGNO_XPR31) {
|
2019-07-08 14:26:01 -05:00
|
|
|
|
r->exist = number <= GDB_REGNO_XPR15 ||
|
2021-01-18 14:22:43 -06:00
|
|
|
|
!riscv_supports_extension(target, 'E');
|
2019-07-08 14:26:01 -05:00
|
|
|
|
/* TODO: For now we fake that all GPRs exist because otherwise gdb
|
|
|
|
|
* doesn't work. */
|
|
|
|
|
r->exist = true;
|
2018-01-31 17:33:45 -06:00
|
|
|
|
r->caller_save = true;
|
2017-12-01 14:42:16 -06:00
|
|
|
|
switch (number) {
|
2017-12-22 16:35:38 -06:00
|
|
|
|
case GDB_REGNO_ZERO:
|
|
|
|
|
r->name = "zero";
|
|
|
|
|
break;
|
|
|
|
|
case GDB_REGNO_RA:
|
|
|
|
|
r->name = "ra";
|
|
|
|
|
break;
|
|
|
|
|
case GDB_REGNO_SP:
|
|
|
|
|
r->name = "sp";
|
|
|
|
|
break;
|
|
|
|
|
case GDB_REGNO_GP:
|
|
|
|
|
r->name = "gp";
|
|
|
|
|
break;
|
|
|
|
|
case GDB_REGNO_TP:
|
|
|
|
|
r->name = "tp";
|
|
|
|
|
break;
|
|
|
|
|
case GDB_REGNO_T0:
|
|
|
|
|
r->name = "t0";
|
|
|
|
|
break;
|
|
|
|
|
case GDB_REGNO_T1:
|
|
|
|
|
r->name = "t1";
|
|
|
|
|
break;
|
|
|
|
|
case GDB_REGNO_T2:
|
|
|
|
|
r->name = "t2";
|
|
|
|
|
break;
|
|
|
|
|
case GDB_REGNO_FP:
|
|
|
|
|
r->name = "fp";
|
|
|
|
|
break;
|
|
|
|
|
case GDB_REGNO_S1:
|
|
|
|
|
r->name = "s1";
|
|
|
|
|
break;
|
|
|
|
|
case GDB_REGNO_A0:
|
|
|
|
|
r->name = "a0";
|
|
|
|
|
break;
|
|
|
|
|
case GDB_REGNO_A1:
|
|
|
|
|
r->name = "a1";
|
|
|
|
|
break;
|
|
|
|
|
case GDB_REGNO_A2:
|
|
|
|
|
r->name = "a2";
|
|
|
|
|
break;
|
|
|
|
|
case GDB_REGNO_A3:
|
|
|
|
|
r->name = "a3";
|
|
|
|
|
break;
|
|
|
|
|
case GDB_REGNO_A4:
|
|
|
|
|
r->name = "a4";
|
|
|
|
|
break;
|
|
|
|
|
case GDB_REGNO_A5:
|
|
|
|
|
r->name = "a5";
|
|
|
|
|
break;
|
|
|
|
|
case GDB_REGNO_A6:
|
|
|
|
|
r->name = "a6";
|
|
|
|
|
break;
|
|
|
|
|
case GDB_REGNO_A7:
|
|
|
|
|
r->name = "a7";
|
|
|
|
|
break;
|
|
|
|
|
case GDB_REGNO_S2:
|
|
|
|
|
r->name = "s2";
|
|
|
|
|
break;
|
|
|
|
|
case GDB_REGNO_S3:
|
|
|
|
|
r->name = "s3";
|
|
|
|
|
break;
|
|
|
|
|
case GDB_REGNO_S4:
|
|
|
|
|
r->name = "s4";
|
|
|
|
|
break;
|
|
|
|
|
case GDB_REGNO_S5:
|
|
|
|
|
r->name = "s5";
|
|
|
|
|
break;
|
|
|
|
|
case GDB_REGNO_S6:
|
|
|
|
|
r->name = "s6";
|
|
|
|
|
break;
|
|
|
|
|
case GDB_REGNO_S7:
|
|
|
|
|
r->name = "s7";
|
|
|
|
|
break;
|
|
|
|
|
case GDB_REGNO_S8:
|
|
|
|
|
r->name = "s8";
|
|
|
|
|
break;
|
|
|
|
|
case GDB_REGNO_S9:
|
|
|
|
|
r->name = "s9";
|
|
|
|
|
break;
|
|
|
|
|
case GDB_REGNO_S10:
|
|
|
|
|
r->name = "s10";
|
|
|
|
|
break;
|
|
|
|
|
case GDB_REGNO_S11:
|
|
|
|
|
r->name = "s11";
|
|
|
|
|
break;
|
|
|
|
|
case GDB_REGNO_T3:
|
|
|
|
|
r->name = "t3";
|
|
|
|
|
break;
|
|
|
|
|
case GDB_REGNO_T4:
|
|
|
|
|
r->name = "t4";
|
|
|
|
|
break;
|
|
|
|
|
case GDB_REGNO_T5:
|
|
|
|
|
r->name = "t5";
|
|
|
|
|
break;
|
|
|
|
|
case GDB_REGNO_T6:
|
|
|
|
|
r->name = "t6";
|
|
|
|
|
break;
|
2017-12-01 14:42:16 -06:00
|
|
|
|
}
|
|
|
|
|
r->group = "general";
|
|
|
|
|
r->feature = &feature_cpu;
|
|
|
|
|
} else if (number == GDB_REGNO_PC) {
|
2018-01-31 17:33:45 -06:00
|
|
|
|
r->caller_save = true;
|
2017-12-01 14:42:16 -06:00
|
|
|
|
sprintf(reg_name, "pc");
|
|
|
|
|
r->group = "general";
|
|
|
|
|
r->feature = &feature_cpu;
|
|
|
|
|
} else if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) {
|
2018-01-31 17:33:45 -06:00
|
|
|
|
r->caller_save = true;
|
2021-01-18 14:22:43 -06:00
|
|
|
|
if (riscv_supports_extension(target, 'D')) {
|
2017-12-01 14:42:16 -06:00
|
|
|
|
r->size = 64;
|
2021-01-18 14:22:43 -06:00
|
|
|
|
if (riscv_supports_extension(target, 'F'))
|
2020-04-10 15:32:12 -05:00
|
|
|
|
r->reg_data_type = &type_ieee_single_double;
|
|
|
|
|
else
|
|
|
|
|
r->reg_data_type = &type_ieee_double;
|
2021-01-18 14:22:43 -06:00
|
|
|
|
} else if (riscv_supports_extension(target, 'F')) {
|
2017-12-01 14:42:16 -06:00
|
|
|
|
r->reg_data_type = &type_ieee_single;
|
|
|
|
|
r->size = 32;
|
|
|
|
|
} else {
|
|
|
|
|
r->exist = false;
|
|
|
|
|
}
|
2017-12-14 15:06:31 -06:00
|
|
|
|
switch (number) {
|
2017-12-22 16:35:38 -06:00
|
|
|
|
case GDB_REGNO_FT0:
|
|
|
|
|
r->name = "ft0";
|
|
|
|
|
break;
|
|
|
|
|
case GDB_REGNO_FT1:
|
|
|
|
|
r->name = "ft1";
|
|
|
|
|
break;
|
|
|
|
|
case GDB_REGNO_FT2:
|
|
|
|
|
r->name = "ft2";
|
|
|
|
|
break;
|
|
|
|
|
case GDB_REGNO_FT3:
|
|
|
|
|
r->name = "ft3";
|
|
|
|
|
break;
|
|
|
|
|
case GDB_REGNO_FT4:
|
|
|
|
|
r->name = "ft4";
|
|
|
|
|
break;
|
|
|
|
|
case GDB_REGNO_FT5:
|
|
|
|
|
r->name = "ft5";
|
|
|
|
|
break;
|
|
|
|
|
case GDB_REGNO_FT6:
|
|
|
|
|
r->name = "ft6";
|
|
|
|
|
break;
|
|
|
|
|
case GDB_REGNO_FT7:
|
|
|
|
|
r->name = "ft7";
|
|
|
|
|
break;
|
|
|
|
|
case GDB_REGNO_FS0:
|
|
|
|
|
r->name = "fs0";
|
|
|
|
|
break;
|
|
|
|
|
case GDB_REGNO_FS1:
|
|
|
|
|
r->name = "fs1";
|
|
|
|
|
break;
|
|
|
|
|
case GDB_REGNO_FA0:
|
|
|
|
|
r->name = "fa0";
|
|
|
|
|
break;
|
|
|
|
|
case GDB_REGNO_FA1:
|
|
|
|
|
r->name = "fa1";
|
|
|
|
|
break;
|
|
|
|
|
case GDB_REGNO_FA2:
|
|
|
|
|
r->name = "fa2";
|
|
|
|
|
break;
|
|
|
|
|
case GDB_REGNO_FA3:
|
|
|
|
|
r->name = "fa3";
|
|
|
|
|
break;
|
|
|
|
|
case GDB_REGNO_FA4:
|
|
|
|
|
r->name = "fa4";
|
|
|
|
|
break;
|
|
|
|
|
case GDB_REGNO_FA5:
|
|
|
|
|
r->name = "fa5";
|
|
|
|
|
break;
|
|
|
|
|
case GDB_REGNO_FA6:
|
|
|
|
|
r->name = "fa6";
|
|
|
|
|
break;
|
|
|
|
|
case GDB_REGNO_FA7:
|
|
|
|
|
r->name = "fa7";
|
|
|
|
|
break;
|
|
|
|
|
case GDB_REGNO_FS2:
|
|
|
|
|
r->name = "fs2";
|
|
|
|
|
break;
|
|
|
|
|
case GDB_REGNO_FS3:
|
|
|
|
|
r->name = "fs3";
|
|
|
|
|
break;
|
|
|
|
|
case GDB_REGNO_FS4:
|
|
|
|
|
r->name = "fs4";
|
|
|
|
|
break;
|
|
|
|
|
case GDB_REGNO_FS5:
|
|
|
|
|
r->name = "fs5";
|
|
|
|
|
break;
|
|
|
|
|
case GDB_REGNO_FS6:
|
|
|
|
|
r->name = "fs6";
|
|
|
|
|
break;
|
|
|
|
|
case GDB_REGNO_FS7:
|
|
|
|
|
r->name = "fs7";
|
|
|
|
|
break;
|
|
|
|
|
case GDB_REGNO_FS8:
|
|
|
|
|
r->name = "fs8";
|
|
|
|
|
break;
|
|
|
|
|
case GDB_REGNO_FS9:
|
|
|
|
|
r->name = "fs9";
|
|
|
|
|
break;
|
|
|
|
|
case GDB_REGNO_FS10:
|
|
|
|
|
r->name = "fs10";
|
|
|
|
|
break;
|
|
|
|
|
case GDB_REGNO_FS11:
|
|
|
|
|
r->name = "fs11";
|
|
|
|
|
break;
|
|
|
|
|
case GDB_REGNO_FT8:
|
|
|
|
|
r->name = "ft8";
|
|
|
|
|
break;
|
|
|
|
|
case GDB_REGNO_FT9:
|
|
|
|
|
r->name = "ft9";
|
|
|
|
|
break;
|
|
|
|
|
case GDB_REGNO_FT10:
|
|
|
|
|
r->name = "ft10";
|
|
|
|
|
break;
|
|
|
|
|
case GDB_REGNO_FT11:
|
|
|
|
|
r->name = "ft11";
|
|
|
|
|
break;
|
2017-12-14 15:06:31 -06:00
|
|
|
|
}
|
2017-12-01 14:42:16 -06:00
|
|
|
|
r->group = "float";
|
|
|
|
|
r->feature = &feature_fpu;
|
|
|
|
|
} else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) {
|
|
|
|
|
r->group = "csr";
|
|
|
|
|
r->feature = &feature_csr;
|
|
|
|
|
unsigned csr_number = number - GDB_REGNO_CSR0;
|
|
|
|
|
|
|
|
|
|
while (csr_info[csr_info_index].number < csr_number &&
|
2021-05-16 06:57:11 -05:00
|
|
|
|
csr_info_index < ARRAY_SIZE(csr_info) - 1) {
|
2017-12-01 14:42:16 -06:00
|
|
|
|
csr_info_index++;
|
|
|
|
|
}
|
|
|
|
|
if (csr_info[csr_info_index].number == csr_number) {
|
|
|
|
|
r->name = csr_info[csr_info_index].name;
|
|
|
|
|
} else {
|
|
|
|
|
sprintf(reg_name, "csr%d", csr_number);
|
2017-12-22 16:35:38 -06:00
|
|
|
|
/* Assume unnamed registers don't exist, unless we have some
|
|
|
|
|
* configuration that tells us otherwise. That's important
|
|
|
|
|
* because eg. Eclipse crashes if a target has too many
|
|
|
|
|
* registers, and apparently has no way of only showing a
|
|
|
|
|
* subset of registers in any case. */
|
2017-12-01 14:42:16 -06:00
|
|
|
|
r->exist = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (csr_number) {
|
|
|
|
|
case CSR_FFLAGS:
|
|
|
|
|
case CSR_FRM:
|
|
|
|
|
case CSR_FCSR:
|
2021-01-18 14:22:43 -06:00
|
|
|
|
r->exist = riscv_supports_extension(target, 'F');
|
2017-12-01 14:42:16 -06:00
|
|
|
|
r->group = "float";
|
|
|
|
|
r->feature = &feature_fpu;
|
|
|
|
|
break;
|
2017-12-14 15:43:14 -06:00
|
|
|
|
case CSR_SSTATUS:
|
|
|
|
|
case CSR_STVEC:
|
|
|
|
|
case CSR_SIP:
|
|
|
|
|
case CSR_SIE:
|
|
|
|
|
case CSR_SCOUNTEREN:
|
|
|
|
|
case CSR_SSCRATCH:
|
|
|
|
|
case CSR_SEPC:
|
|
|
|
|
case CSR_SCAUSE:
|
|
|
|
|
case CSR_STVAL:
|
|
|
|
|
case CSR_SATP:
|
2021-01-18 14:22:43 -06:00
|
|
|
|
r->exist = riscv_supports_extension(target, 'S');
|
2017-12-14 15:43:14 -06:00
|
|
|
|
break;
|
2018-03-23 15:43:12 -05:00
|
|
|
|
case CSR_MEDELEG:
|
|
|
|
|
case CSR_MIDELEG:
|
|
|
|
|
/* "In systems with only M-mode, or with both M-mode and
|
|
|
|
|
* U-mode but without U-mode trap support, the medeleg and
|
|
|
|
|
* mideleg registers should not exist." */
|
2021-01-18 14:22:43 -06:00
|
|
|
|
r->exist = riscv_supports_extension(target, 'S') ||
|
|
|
|
|
riscv_supports_extension(target, 'N');
|
2017-12-14 15:43:14 -06:00
|
|
|
|
break;
|
2018-05-02 17:14:16 -05:00
|
|
|
|
|
2019-10-23 13:37:51 -05:00
|
|
|
|
case CSR_PMPCFG1:
|
|
|
|
|
case CSR_PMPCFG3:
|
2018-05-02 17:14:16 -05:00
|
|
|
|
case CSR_CYCLEH:
|
|
|
|
|
case CSR_TIMEH:
|
|
|
|
|
case CSR_INSTRETH:
|
|
|
|
|
case CSR_HPMCOUNTER3H:
|
|
|
|
|
case CSR_HPMCOUNTER4H:
|
|
|
|
|
case CSR_HPMCOUNTER5H:
|
|
|
|
|
case CSR_HPMCOUNTER6H:
|
|
|
|
|
case CSR_HPMCOUNTER7H:
|
|
|
|
|
case CSR_HPMCOUNTER8H:
|
|
|
|
|
case CSR_HPMCOUNTER9H:
|
|
|
|
|
case CSR_HPMCOUNTER10H:
|
|
|
|
|
case CSR_HPMCOUNTER11H:
|
|
|
|
|
case CSR_HPMCOUNTER12H:
|
|
|
|
|
case CSR_HPMCOUNTER13H:
|
|
|
|
|
case CSR_HPMCOUNTER14H:
|
|
|
|
|
case CSR_HPMCOUNTER15H:
|
|
|
|
|
case CSR_HPMCOUNTER16H:
|
|
|
|
|
case CSR_HPMCOUNTER17H:
|
|
|
|
|
case CSR_HPMCOUNTER18H:
|
|
|
|
|
case CSR_HPMCOUNTER19H:
|
|
|
|
|
case CSR_HPMCOUNTER20H:
|
|
|
|
|
case CSR_HPMCOUNTER21H:
|
|
|
|
|
case CSR_HPMCOUNTER22H:
|
|
|
|
|
case CSR_HPMCOUNTER23H:
|
|
|
|
|
case CSR_HPMCOUNTER24H:
|
|
|
|
|
case CSR_HPMCOUNTER25H:
|
|
|
|
|
case CSR_HPMCOUNTER26H:
|
|
|
|
|
case CSR_HPMCOUNTER27H:
|
|
|
|
|
case CSR_HPMCOUNTER28H:
|
|
|
|
|
case CSR_HPMCOUNTER29H:
|
|
|
|
|
case CSR_HPMCOUNTER30H:
|
|
|
|
|
case CSR_HPMCOUNTER31H:
|
|
|
|
|
case CSR_MCYCLEH:
|
|
|
|
|
case CSR_MINSTRETH:
|
|
|
|
|
case CSR_MHPMCOUNTER3H:
|
|
|
|
|
case CSR_MHPMCOUNTER4H:
|
|
|
|
|
case CSR_MHPMCOUNTER5H:
|
|
|
|
|
case CSR_MHPMCOUNTER6H:
|
|
|
|
|
case CSR_MHPMCOUNTER7H:
|
|
|
|
|
case CSR_MHPMCOUNTER8H:
|
|
|
|
|
case CSR_MHPMCOUNTER9H:
|
|
|
|
|
case CSR_MHPMCOUNTER10H:
|
|
|
|
|
case CSR_MHPMCOUNTER11H:
|
|
|
|
|
case CSR_MHPMCOUNTER12H:
|
|
|
|
|
case CSR_MHPMCOUNTER13H:
|
|
|
|
|
case CSR_MHPMCOUNTER14H:
|
|
|
|
|
case CSR_MHPMCOUNTER15H:
|
|
|
|
|
case CSR_MHPMCOUNTER16H:
|
|
|
|
|
case CSR_MHPMCOUNTER17H:
|
|
|
|
|
case CSR_MHPMCOUNTER18H:
|
|
|
|
|
case CSR_MHPMCOUNTER19H:
|
|
|
|
|
case CSR_MHPMCOUNTER20H:
|
|
|
|
|
case CSR_MHPMCOUNTER21H:
|
|
|
|
|
case CSR_MHPMCOUNTER22H:
|
|
|
|
|
case CSR_MHPMCOUNTER23H:
|
|
|
|
|
case CSR_MHPMCOUNTER24H:
|
|
|
|
|
case CSR_MHPMCOUNTER25H:
|
|
|
|
|
case CSR_MHPMCOUNTER26H:
|
|
|
|
|
case CSR_MHPMCOUNTER27H:
|
|
|
|
|
case CSR_MHPMCOUNTER28H:
|
|
|
|
|
case CSR_MHPMCOUNTER29H:
|
|
|
|
|
case CSR_MHPMCOUNTER30H:
|
|
|
|
|
case CSR_MHPMCOUNTER31H:
|
|
|
|
|
r->exist = riscv_xlen(target) == 32;
|
2017-12-14 15:43:14 -06:00
|
|
|
|
break;
|
2020-02-14 16:54:05 -06:00
|
|
|
|
|
|
|
|
|
case CSR_VSTART:
|
|
|
|
|
case CSR_VXSAT:
|
|
|
|
|
case CSR_VXRM:
|
|
|
|
|
case CSR_VL:
|
2023-01-10 08:39:52 -06:00
|
|
|
|
case CSR_VCSR:
|
2020-02-14 16:54:05 -06:00
|
|
|
|
case CSR_VTYPE:
|
|
|
|
|
case CSR_VLENB:
|
2022-11-10 12:27:46 -06:00
|
|
|
|
r->exist = (info->vlenb > 0);
|
2020-02-14 16:54:05 -06:00
|
|
|
|
break;
|
2023-02-09 17:08:40 -06:00
|
|
|
|
case CSR_MCOUNTEREN:
|
|
|
|
|
r->exist = riscv_supports_extension(target, 'U');
|
|
|
|
|
break;
|
2017-12-01 14:42:16 -06:00
|
|
|
|
}
|
2017-12-15 15:27:26 -06:00
|
|
|
|
|
2020-10-01 13:05:41 -05:00
|
|
|
|
if (!r->exist && !list_empty(&info->expose_csr)) {
|
|
|
|
|
range_list_t *entry;
|
|
|
|
|
list_for_each_entry(entry, &info->expose_csr, list)
|
|
|
|
|
if ((entry->low <= csr_number) && (csr_number <= entry->high)) {
|
|
|
|
|
if (entry->name) {
|
|
|
|
|
*reg_name = 0;
|
|
|
|
|
r->name = entry->name;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LOG_DEBUG("Exposing additional CSR %d (name=%s)",
|
|
|
|
|
csr_number, entry->name ? entry->name : reg_name);
|
|
|
|
|
|
2017-12-15 15:27:26 -06:00
|
|
|
|
r->exist = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2023-02-15 11:53:37 -06:00
|
|
|
|
} else if (r->exist && !list_empty(&info->hide_csr)) {
|
|
|
|
|
range_list_t *entry;
|
|
|
|
|
list_for_each_entry(entry, &info->hide_csr, list)
|
|
|
|
|
if ((entry->low <= csr_number) && (csr_number <= entry->high)) {
|
|
|
|
|
LOG_TARGET_DEBUG(target, "Hiding CSR %d (name=%s)", csr_number, r->name);
|
|
|
|
|
r->hidden = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2017-12-15 15:27:26 -06:00
|
|
|
|
}
|
|
|
|
|
|
2017-12-01 14:42:16 -06:00
|
|
|
|
} else if (number == GDB_REGNO_PRIV) {
|
|
|
|
|
sprintf(reg_name, "priv");
|
|
|
|
|
r->group = "general";
|
|
|
|
|
r->feature = &feature_virtual;
|
2017-12-08 15:51:40 -06:00
|
|
|
|
r->size = 8;
|
2018-08-29 16:22:50 -05:00
|
|
|
|
|
2020-02-14 16:54:05 -06:00
|
|
|
|
} else if (number >= GDB_REGNO_V0 && number <= GDB_REGNO_V31) {
|
|
|
|
|
r->caller_save = false;
|
2022-11-10 12:27:46 -06:00
|
|
|
|
r->exist = (info->vlenb > 0);
|
2021-01-18 14:22:43 -06:00
|
|
|
|
r->size = info->vlenb * 8;
|
2020-02-14 16:54:05 -06:00
|
|
|
|
sprintf(reg_name, "v%d", number - GDB_REGNO_V0);
|
|
|
|
|
r->group = "vector";
|
|
|
|
|
r->feature = &feature_vector;
|
|
|
|
|
r->reg_data_type = &info->type_vector;
|
|
|
|
|
|
2019-07-08 14:26:01 -05:00
|
|
|
|
} else if (number >= GDB_REGNO_COUNT) {
|
2018-08-29 16:22:50 -05:00
|
|
|
|
/* Custom registers. */
|
2020-10-01 13:05:41 -05:00
|
|
|
|
assert(!list_empty(&info->expose_custom));
|
|
|
|
|
|
|
|
|
|
range_list_t *range = list_first_entry(&info->expose_custom, range_list_t, list);
|
2018-08-29 16:22:50 -05:00
|
|
|
|
|
|
|
|
|
unsigned custom_number = range->low + custom_within_range;
|
|
|
|
|
|
|
|
|
|
r->group = "custom";
|
|
|
|
|
r->feature = &feature_custom;
|
|
|
|
|
r->arch_info = calloc(1, sizeof(riscv_reg_info_t));
|
2020-09-03 13:57:25 -05:00
|
|
|
|
if (!r->arch_info)
|
|
|
|
|
return ERROR_FAIL;
|
2018-08-29 16:22:50 -05:00
|
|
|
|
((riscv_reg_info_t *) r->arch_info)->target = target;
|
|
|
|
|
((riscv_reg_info_t *) r->arch_info)->custom_number = custom_number;
|
|
|
|
|
sprintf(reg_name, "custom%d", custom_number);
|
|
|
|
|
|
2020-10-01 13:05:41 -05:00
|
|
|
|
if (range->name) {
|
|
|
|
|
*reg_name = 0;
|
|
|
|
|
r->name = range->name;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LOG_DEBUG("Exposing additional custom register %d (name=%s)",
|
|
|
|
|
number, range->name ? range->name : reg_name);
|
|
|
|
|
|
2018-08-29 16:22:50 -05:00
|
|
|
|
custom_within_range++;
|
|
|
|
|
if (custom_within_range > range->high - range->low) {
|
|
|
|
|
custom_within_range = 0;
|
2020-10-01 13:05:41 -05:00
|
|
|
|
list_rotate_left(&info->expose_custom);
|
2018-08-29 16:22:50 -05:00
|
|
|
|
}
|
2017-12-01 14:42:16 -06:00
|
|
|
|
}
|
2018-08-29 16:22:50 -05:00
|
|
|
|
|
2020-10-01 13:05:41 -05:00
|
|
|
|
if (reg_name[0]) {
|
2017-12-01 14:42:16 -06:00
|
|
|
|
r->name = reg_name;
|
2020-10-01 13:05:41 -05:00
|
|
|
|
reg_name += strlen(reg_name) + 1;
|
|
|
|
|
assert(reg_name < info->reg_names + target->reg_cache->num_regs *
|
|
|
|
|
max_reg_name_len);
|
|
|
|
|
}
|
2021-11-02 11:55:07 -05:00
|
|
|
|
r->value = calloc(1, DIV_ROUND_UP(r->size, 8));
|
2017-12-01 14:42:16 -06:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ERROR_OK;
|
|
|
|
|
}
|
2019-11-12 11:00:35 -06:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void riscv_add_bscan_tunneled_scan(struct target *target, struct scan_field *field,
|
|
|
|
|
riscv_bscan_tunneled_scan_context_t *ctxt)
|
|
|
|
|
{
|
|
|
|
|
jtag_add_ir_scan(target->tap, &select_user4, TAP_IDLE);
|
|
|
|
|
|
|
|
|
|
memset(ctxt->tunneled_dr, 0, sizeof(ctxt->tunneled_dr));
|
|
|
|
|
if (bscan_tunnel_type == BSCAN_TUNNEL_DATA_REGISTER) {
|
|
|
|
|
ctxt->tunneled_dr[3].num_bits = 1;
|
|
|
|
|
ctxt->tunneled_dr[3].out_value = bscan_one;
|
|
|
|
|
ctxt->tunneled_dr[2].num_bits = 7;
|
|
|
|
|
ctxt->tunneled_dr_width = field->num_bits;
|
|
|
|
|
ctxt->tunneled_dr[2].out_value = &ctxt->tunneled_dr_width;
|
|
|
|
|
/* for BSCAN tunnel, there is a one-TCK skew between shift in and shift out, so
|
|
|
|
|
scanning num_bits + 1, and then will right shift the input field after executing the queues */
|
|
|
|
|
|
2020-08-21 14:56:04 -05:00
|
|
|
|
ctxt->tunneled_dr[1].num_bits = field->num_bits + 1;
|
2019-11-12 11:00:35 -06:00
|
|
|
|
ctxt->tunneled_dr[1].out_value = field->out_value;
|
|
|
|
|
ctxt->tunneled_dr[1].in_value = field->in_value;
|
|
|
|
|
|
|
|
|
|
ctxt->tunneled_dr[0].num_bits = 3;
|
|
|
|
|
ctxt->tunneled_dr[0].out_value = bscan_zero;
|
|
|
|
|
} else {
|
|
|
|
|
/* BSCAN_TUNNEL_NESTED_TAP */
|
|
|
|
|
ctxt->tunneled_dr[0].num_bits = 1;
|
|
|
|
|
ctxt->tunneled_dr[0].out_value = bscan_one;
|
|
|
|
|
ctxt->tunneled_dr[1].num_bits = 7;
|
|
|
|
|
ctxt->tunneled_dr_width = field->num_bits;
|
|
|
|
|
ctxt->tunneled_dr[1].out_value = &ctxt->tunneled_dr_width;
|
|
|
|
|
/* for BSCAN tunnel, there is a one-TCK skew between shift in and shift out, so
|
|
|
|
|
scanning num_bits + 1, and then will right shift the input field after executing the queues */
|
2020-08-21 14:56:04 -05:00
|
|
|
|
ctxt->tunneled_dr[2].num_bits = field->num_bits + 1;
|
2019-11-12 11:00:35 -06:00
|
|
|
|
ctxt->tunneled_dr[2].out_value = field->out_value;
|
|
|
|
|
ctxt->tunneled_dr[2].in_value = field->in_value;
|
|
|
|
|
ctxt->tunneled_dr[3].num_bits = 3;
|
|
|
|
|
ctxt->tunneled_dr[3].out_value = bscan_zero;
|
|
|
|
|
}
|
|
|
|
|
jtag_add_dr_scan(target->tap, ARRAY_SIZE(ctxt->tunneled_dr), ctxt->tunneled_dr, TAP_IDLE);
|
|
|
|
|
}
|