From 21f17260d438704deb1591777222e542efb8383d Mon Sep 17 00:00:00 2001 From: Vincent Fazio Date: Wed, 6 Sep 2023 11:10:41 -0500 Subject: [PATCH 01/13] jtag/drivers/bcm2835gpio: fix bcm2835_peri_base output format Previously, the bcm2835_peri_base value would be printed as a decimal value despite having a "0x" prefix, implying it should be a hex value. BCM2835 GPIO: peripheral_base = 0x1056964608 Now, the value is correctly converted to hexidecimal. BCM2835 GPIO: peripheral_base = 0x3F000000 Change-Id: Id59185423917e6350f99ef68320e2102a3192291 Fixes: b41b368255d5 ("jtag/drivers/bcm2835gpio: extend peripheral_base to off_t") Signed-off-by: Vincent Fazio Reviewed-on: https://review.openocd.org/c/openocd/+/7888 Reviewed-by: Tomas Vanek Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/jtag/drivers/bcm2835gpio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jtag/drivers/bcm2835gpio.c b/src/jtag/drivers/bcm2835gpio.c index f41f7b51e..7fd7f3894 100644 --- a/src/jtag/drivers/bcm2835gpio.c +++ b/src/jtag/drivers/bcm2835gpio.c @@ -331,7 +331,7 @@ COMMAND_HANDLER(bcm2835gpio_handle_peripheral_base) } tmp_base = bcm2835_peri_base; - command_print(CMD, "BCM2835 GPIO: peripheral_base = 0x%08" PRIu64, + command_print(CMD, "BCM2835 GPIO: peripheral_base = 0x%08" PRIx64, tmp_base); return ERROR_OK; } From c6ab3abeeecfad4d3f48f8012b531d4172944768 Mon Sep 17 00:00:00 2001 From: Marek Vrbka Date: Tue, 5 Sep 2023 15:25:50 +0200 Subject: [PATCH 02/13] image: log error when unknown image type is specified This patch adds error reporting when unknown image type is specified. Previously, OpenOCD replied with an empty string. Change-Id: I16220b1f5deb3b966a21731f0adf7911a78e8959 Signed-off-by: Marek Vrbka Reviewed-on: https://review.openocd.org/c/openocd/+/7883 Tested-by: jenkins Reviewed-by: Jan Matyas Reviewed-by: Tomas Vanek --- src/target/image.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/target/image.c b/src/target/image.c index ad2d856b5..e998a35f4 100644 --- a/src/target/image.c +++ b/src/target/image.c @@ -96,20 +96,22 @@ static int autodetect_image_type(struct image *image, const char *url) static int identify_image_type(struct image *image, const char *type_string, const char *url) { if (type_string) { - if (!strcmp(type_string, "bin")) + if (!strcmp(type_string, "bin")) { image->type = IMAGE_BINARY; - else if (!strcmp(type_string, "ihex")) + } else if (!strcmp(type_string, "ihex")) { image->type = IMAGE_IHEX; - else if (!strcmp(type_string, "elf")) + } else if (!strcmp(type_string, "elf")) { image->type = IMAGE_ELF; - else if (!strcmp(type_string, "mem")) + } else if (!strcmp(type_string, "mem")) { image->type = IMAGE_MEMORY; - else if (!strcmp(type_string, "s19")) + } else if (!strcmp(type_string, "s19")) { image->type = IMAGE_SRECORD; - else if (!strcmp(type_string, "build")) + } else if (!strcmp(type_string, "build")) { image->type = IMAGE_BUILDER; - else + } else { + LOG_ERROR("Unknown image type: %s, use one of: bin, ihex, elf, mem, s19, build", type_string); return ERROR_IMAGE_TYPE_UNKNOWN; + } } else return autodetect_image_type(image, url); From f76c8de910e1e12f4b180956d0189c9483e949a5 Mon Sep 17 00:00:00 2001 From: Ahmed Boughanmi Date: Wed, 30 Aug 2023 02:26:40 +0200 Subject: [PATCH 03/13] target/cortex_m: support Infineon Cortex-M33 from SLx2 MCU The secure microcontroller Infineon SLx2 uses a custom Cortex-M33. The register CPUID reports value 0x490FDB00. Reference link to the product: Link: https://www.infineon.com/cms/en/about-infineon/press/market-news/2022/INFCSS202211-034.html Change-Id: I8911712c55bd50e24ed53cf49958352f470027a5 Signed-off-by: Ahmed Boughanmi Reviewed-on: https://review.openocd.org/c/openocd/+/7879 Reviewed-by: Karl Palsson Tested-by: jenkins Reviewed-by: Antonio Borneo Reviewed-by: Tomas Vanek --- src/target/arm.h | 1 + src/target/cortex_m.c | 5 +++++ src/target/cortex_m.h | 27 ++++++++++++++------------- 3 files changed, 20 insertions(+), 13 deletions(-) diff --git a/src/target/arm.h b/src/target/arm.h index 28e533019..cc0f14cb6 100644 --- a/src/target/arm.h +++ b/src/target/arm.h @@ -61,6 +61,7 @@ enum arm_arch { /** Known ARM implementor IDs */ enum arm_implementor { ARM_IMPLEMENTOR_ARM = 0x41, + ARM_IMPLEMENTOR_INFINEON = 0x49, ARM_IMPLEMENTOR_REALTEK = 0x72, }; diff --git a/src/target/cortex_m.c b/src/target/cortex_m.c index 854e8eb58..3eafee0a1 100644 --- a/src/target/cortex_m.c +++ b/src/target/cortex_m.c @@ -111,6 +111,11 @@ static const struct cortex_m_part_info cortex_m_parts[] = { .arch = ARM_ARCH_V8M, .flags = CORTEX_M_F_HAS_FPV5, }, + { + .impl_part = INFINEON_SLX2_PARTNO, + .name = "Infineon-SLx2", + .arch = ARM_ARCH_V8M, + }, { .impl_part = REALTEK_M200_PARTNO, .name = "Real-M200 (KM0)", diff --git a/src/target/cortex_m.h b/src/target/cortex_m.h index 065e4d47b..0bc139911 100644 --- a/src/target/cortex_m.h +++ b/src/target/cortex_m.h @@ -45,19 +45,20 @@ */ enum cortex_m_impl_part { CORTEX_M_PARTNO_INVALID, - STAR_MC1_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0x132), /* FIXME - confirm implementor! */ - CORTEX_M0_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xC20), - CORTEX_M1_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xC21), - CORTEX_M3_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xC23), - CORTEX_M4_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xC24), - CORTEX_M7_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xC27), - CORTEX_M0P_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xC60), - CORTEX_M23_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xD20), - CORTEX_M33_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xD21), - CORTEX_M35P_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xD31), - CORTEX_M55_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xD22), - REALTEK_M200_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_REALTEK, 0xd20), - REALTEK_M300_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_REALTEK, 0xd22), + STAR_MC1_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0x132), /* FIXME - confirm implementor! */ + CORTEX_M0_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xC20), + CORTEX_M1_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xC21), + CORTEX_M3_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xC23), + CORTEX_M4_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xC24), + CORTEX_M7_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xC27), + CORTEX_M0P_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xC60), + CORTEX_M23_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xD20), + CORTEX_M33_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xD21), + CORTEX_M35P_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xD31), + CORTEX_M55_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xD22), + INFINEON_SLX2_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_INFINEON, 0xDB0), + REALTEK_M200_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_REALTEK, 0xd20), + REALTEK_M300_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_REALTEK, 0xd22), }; /* Relevant Cortex-M flags, used in struct cortex_m_part_info.flags */ From bdf73617e774b0791f9efec6659c78c1f60c03b5 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Thu, 7 Sep 2023 09:58:25 +0200 Subject: [PATCH 04/13] armv8_dpm: fix registers read at debug entry The comment above armv8_dpm_read_current_registers() doesn't match the implementation, as the function reads all the registers from ARMV8_PC and above. The registers currently read are not relevant to answer to the usual GDB initial request through the 'g' packet. Plus the lack of differentiation per core state (AArch32 vs AArch64) causes the read of not existing registers in AArch32 triggering errors, as tentatively fixed by https://review.openocd.org/5517/ Fix the code to read the registers initially required by GDB. Modify the comment to report the register list in AArch32 and in AArch64. Keep the extra checks inside the read loop, even if they are mostly irrelevant; this could prevent errors if someone needs to extend the number of registers to read. The current implementation of the register's description in OpenOCD does not allow to discriminate among AArch32 and AArch64 registers. Add a TODO comment to highlight it. Change-Id: Icd47d93c19a9e1694a7b51bbc5ca7e21a578df41 Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/7887 Tested-by: jenkins --- src/target/armv8_dpm.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/target/armv8_dpm.c b/src/target/armv8_dpm.c index 9ba6b5453..552bcfa02 100644 --- a/src/target/armv8_dpm.c +++ b/src/target/armv8_dpm.c @@ -725,7 +725,8 @@ static int dpmv8_write_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum) } /** - * Read basic registers of the current context: R0 to R15, and CPSR; + * Read basic registers of the current context: R0 to R15, and CPSR in AArch32 + * state or R0 to R31, PC and CPSR in AArch64 state; * sets the core mode (such as USR or IRQ) and state (such as ARM or Thumb). * In normal operation this is called on entry to halting debug state, * possibly after some other operations supporting restore of debug state @@ -772,9 +773,15 @@ int armv8_dpm_read_current_registers(struct arm_dpm *dpm) /* update core mode and state */ armv8_set_cpsr(arm, cpsr); - for (unsigned int i = ARMV8_PC; i < cache->num_regs ; i++) { + /* read the remaining registers that would be required by GDB 'g' packet */ + for (unsigned int i = ARMV8_R2; i <= ARMV8_PC ; i++) { struct arm_reg *arm_reg; + /* in AArch32 skip AArch64 registers */ + /* TODO: this should be detected below through arm_reg->mode */ + if (arm->core_state != ARM_STATE_AARCH64 && i > ARMV8_R14 && i < ARMV8_PC) + continue; + r = armv8_reg_current(arm, i); if (!r->exist || r->valid) continue; From d20304b3fb0f27f62844144837ee5b99ee040bcd Mon Sep 17 00:00:00 2001 From: Artemiy Volkov Date: Thu, 6 Jul 2023 13:25:00 +0200 Subject: [PATCH 05/13] target/arc: do not invalidate icache when (un)setting breakpoints Currently, instruction cache is being invalidated in arc_{un,}set_breakpoint() regardless of whether the breakpoint's type is HW or SW. For SW breakpoints, this has no net effect as the caches are flushed as a by-product of overwriting instructions in main memory and is thus merely unnecessary; but for HW breakpoints this invalidation is not preceded by a flush and might lead to loss of data. This patch removes the invalidate() call altogether to correct this undesired behavior for HW breakpoints. With this patch applied, all supported HW breakpoint tests from the gdb testsuite are now passing with the arc-openocd backend. Change-Id: I3d252b97f01f1a1e2bf0eb8fb257bdab0c544bc2 Signed-off-by: Artemiy Volkov Reviewed-on: https://review.openocd.org/c/openocd/+/7767 Tested-by: jenkins Reviewed-by: Evgeniy Didin Reviewed-by: Antonio Borneo --- src/target/arc.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/target/arc.c b/src/target/arc.c index 2ca6be16d..45005b29b 100644 --- a/src/target/arc.c +++ b/src/target/arc.c @@ -1573,9 +1573,6 @@ static int arc_set_breakpoint(struct target *target, return ERROR_FAIL; } - /* core instruction cache is now invalid. */ - CHECK_RETVAL(arc_cache_invalidate(target)); - return ERROR_OK; } @@ -1658,9 +1655,6 @@ static int arc_unset_breakpoint(struct target *target, return ERROR_FAIL; } - /* core instruction cache is now invalid. */ - CHECK_RETVAL(arc_cache_invalidate(target)); - return retval; } From 2f17449dff3272e08f509e0f06aa08d3acf7e105 Mon Sep 17 00:00:00 2001 From: Parshintsev Anatoly Date: Tue, 5 Sep 2023 21:08:02 +0300 Subject: [PATCH 06/13] target: return error if attempting to access non-existing registers Change-Id: Ic22edcab46d21dbc71f78275a78bdea9c2bcc394 Signed-off-by: Parshintsev Anatoly Reviewed-on: https://review.openocd.org/c/openocd/+/7886 Reviewed-by: Tim Newsome Reviewed-by: Jan Matyas Reviewed-by: Marek Vrbka Reviewed-by: Antonio Borneo Tested-by: jenkins --- src/target/target.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/target/target.c b/src/target/target.c index 121974375..acd351a66 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -3116,7 +3116,7 @@ COMMAND_HANDLER(handle_reg_command) if (!reg) { command_print(CMD, "%i is out of bounds, the current target " "has only %i registers (0 - %i)", num, count, count - 1); - return ERROR_OK; + return ERROR_FAIL; } } else { /* access a single register by its name */ @@ -3175,7 +3175,7 @@ COMMAND_HANDLER(handle_reg_command) not_found: command_print(CMD, "register %s not found in current target", CMD_ARGV[0]); - return ERROR_OK; + return ERROR_FAIL; } COMMAND_HANDLER(handle_poll_command) From 871276cfead7d1ebf11492a1c82691835e1f135a Mon Sep 17 00:00:00 2001 From: Dubravko Srsan Date: Wed, 13 Sep 2023 14:02:09 -0500 Subject: [PATCH 07/13] tcl/target/ti_k3: Fix smp target description When _v8_smp_targets is used with V8_SMP_DEBUG=1, describe the targets as SMP targets. However, the variable expansion is not in the context of a proc, and a typo in referring to global $_v8_smp_targets causes this to fail. Just refer to $_v8_smp_targets directly. Change-Id: Iffe5fd2703bed6a9c840284285e70b8a8ce84e17 Signed-off-by: Dubravko Srsan Signed-off-by: Nishanth Menon Reviewed-on: https://review.openocd.org/c/openocd/+/7896 Reviewed-by: Antonio Borneo Tested-by: jenkins --- tcl/target/ti_k3.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tcl/target/ti_k3.cfg b/tcl/target/ti_k3.cfg index 01e11c69f..3c000ed59 100644 --- a/tcl/target/ti_k3.cfg +++ b/tcl/target/ti_k3.cfg @@ -340,7 +340,7 @@ if { $_v8_smp_debug == 0 } { _armv8_smp_up } # Declare SMP - target smp $:::_v8_smp_targets + target smp {*}$_v8_smp_targets } for { set _core 0 } { $_core < $_r5_cores } { incr _core } { From 7abb93aad4039f88427e1179660c0ee68146e6d4 Mon Sep 17 00:00:00 2001 From: Dubravko Srsan Date: Wed, 13 Sep 2023 16:23:03 -0500 Subject: [PATCH 08/13] tcl/target/ti_k3: Add coreid identification to SMP processors Describe the SMP Armv8 cores in SMP configuration with coreid explicitly called out. This allows for gdb session to call the smp behavior clearly. Change-Id: Ie43be22db64737bbb66181f09d3c83567044f3ac Signed-off-by: Dubravko Srsan Signed-off-by: Nishanth Menon Reviewed-on: https://review.openocd.org/c/openocd/+/7897 Reviewed-by: Antonio Borneo Tested-by: jenkins --- tcl/target/ti_k3.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tcl/target/ti_k3.cfg b/tcl/target/ti_k3.cfg index 3c000ed59..bd7496e2c 100644 --- a/tcl/target/ti_k3.cfg +++ b/tcl/target/ti_k3.cfg @@ -303,7 +303,7 @@ for { set _core 0 } { $_core < $_armv8_cores } { incr _core } { cti create $_CTINAME.$_armv8_cpu_name.$_core -dap $_CHIPNAME.dap -ap-num 1 \ -baseaddr [lindex $ARMV8_CTIBASE $_core] - target create $_TARGETNAME.$_armv8_cpu_name.$_core aarch64 -dap $_CHIPNAME.dap \ + target create $_TARGETNAME.$_armv8_cpu_name.$_core aarch64 -dap $_CHIPNAME.dap -coreid $_core \ -dbgbase [lindex $ARMV8_DBGBASE $_core] -cti $_CTINAME.$_armv8_cpu_name.$_core -defer-examine set _v8_smp_targets "$_v8_smp_targets $_TARGETNAME.$_armv8_cpu_name.$_core" From d14fef8495e6d0247ea2929053d27b5c561ac1d0 Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Wed, 13 Sep 2023 17:57:29 -0500 Subject: [PATCH 09/13] tcl/target/ti_k3: Introduce RTOS array variable to set various CPU RTOSes The Texas Instruments' K3 devices are a mix of AMP and SMP systems. The operating systems used on these processors can vary dramatically as well. Introduce a RTOS array variable, which is keyed off the cpu to identify which RTOS is used on that CPU. This can be "auto" or "hwthread" in case of SMP debug etc. For example: AM625 with an general purpose M4F running Zephyr and 4 A53s running SMP Linux could be invoked by: openocd -c 'set V8_SMP_DEBUG 1' -c 'set RTOS(am625.cpu.gp_mcu) Zephyr' \ -c "set RTOS(am625.cpu.a53.0) hwthread" -f board/ti_am625evm.cfg Change-Id: Ib5e59fa2583b3115e5799658afcdd0ee91935e82 Reported-by: Dubravko Srsan Signed-off-by: Nishanth Menon Reviewed-on: https://review.openocd.org/c/openocd/+/7898 Tested-by: jenkins Reviewed-by: Antonio Borneo --- tcl/target/ti_k3.cfg | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/tcl/target/ti_k3.cfg b/tcl/target/ti_k3.cfg index bd7496e2c..090f08209 100644 --- a/tcl/target/ti_k3.cfg +++ b/tcl/target/ti_k3.cfg @@ -248,6 +248,13 @@ switch $_soc { } } +proc _get_rtos_type_for_cpu { target_name } { + if { [info exists ::RTOS($target_name)] } { + return $::RTOS($target_name) + } + return none +} + set _CHIPNAME $_soc swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_K3_DAP_TAPID -ignore-version @@ -260,7 +267,10 @@ set _CTINAME $_CHIPNAME.cti # sysctrl is always present cti create $_CTINAME.sysctrl -dap $_CHIPNAME.dap -ap-num 7 -baseaddr [lindex $CM3_CTIBASE 0] -target create $_TARGETNAME.sysctrl cortex_m -dap $_CHIPNAME.dap -ap-num 7 -defer-examine + +target create $_TARGETNAME.sysctrl cortex_m -dap $_CHIPNAME.dap -ap-num 7 -defer-examine \ + -rtos [_get_rtos_type_for_cpu $_TARGETNAME.sysctrl] + $_TARGETNAME.sysctrl configure -event reset-assert { } proc sysctrl_up {} { @@ -304,7 +314,8 @@ for { set _core 0 } { $_core < $_armv8_cores } { incr _core } { -baseaddr [lindex $ARMV8_CTIBASE $_core] target create $_TARGETNAME.$_armv8_cpu_name.$_core aarch64 -dap $_CHIPNAME.dap -coreid $_core \ - -dbgbase [lindex $ARMV8_DBGBASE $_core] -cti $_CTINAME.$_armv8_cpu_name.$_core -defer-examine + -dbgbase [lindex $ARMV8_DBGBASE $_core] -cti $_CTINAME.$_armv8_cpu_name.$_core -defer-examine \ + -rtos [_get_rtos_type_for_cpu $_TARGETNAME.$_armv8_cpu_name.$_core] set _v8_smp_targets "$_v8_smp_targets $_TARGETNAME.$_armv8_cpu_name.$_core" @@ -350,7 +361,8 @@ for { set _core 0 } { $_core < $_r5_cores } { incr _core } { # inactive core examination will fail - wait till startup of additional core target create $_TARGETNAME.$_r5_name cortex_r4 -dap $_CHIPNAME.dap \ - -dbgbase [lindex $R5_DBGBASE $_core] -ap-num 1 -defer-examine + -dbgbase [lindex $R5_DBGBASE $_core] -ap-num 1 -defer-examine \ + -rtos [_get_rtos_type_for_cpu $_TARGETNAME.$_r5_name] $_TARGETNAME.$_r5_name configure -event gdb-attach { _cpu_no_smp_up @@ -368,7 +380,8 @@ proc r5_up { args } { if { $_gp_mcu_cores != 0 } { cti create $_CTINAME.gp_mcu -dap $_CHIPNAME.dap -ap-num 8 -baseaddr [lindex $CM4_CTIBASE 0] - target create $_TARGETNAME.gp_mcu cortex_m -dap $_CHIPNAME.dap -ap-num 8 -defer-examine + target create $_TARGETNAME.gp_mcu cortex_m -dap $_CHIPNAME.dap -ap-num 8 -defer-examine \ + -rtos [_get_rtos_type_for_cpu $_TARGETNAME.gp_mcu] $_TARGETNAME.gp_mcu configure -event reset-assert { } proc gp_mcu_up {} { From 9c7c5ca4eb04b110f66b4e3c2494a1d55a962b33 Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Thu, 14 Sep 2023 07:49:02 -0500 Subject: [PATCH 10/13] tcl/target/ti_k3: Add AXI-AP port for direct SoC memory map access While we can read and write from memory from the view of various processors, all K3 debug systems have a AXI Access port that allows us to directly access memory from debug interface. This port is especially useful in the following scenarios: 1. Debug cache related behavior on processors as this provides a direct bypass path. 2. Processor has crashed or inaccessible for some reason (low power state etc.) 3. Scenarios prior to the processor getting active. 4. Debug MMU or address translation issues (example: TI's Region Address Table {RAT} translation table used to physically map SoC address space into R5/M4F processor address space) The AXI-AP port is the same for all processors in TI's K3 family. To prevent a circular-loop scenario for axi-ap accessing debug memory with dmem (direct memory access debug), enable this only when dmem is disabled. Change-Id: Ie4ca9222f034ffc2fa669fb5124a5f8e37b65e3b Reported-by: Dubravko Srsan Signed-off-by: Nishanth Menon Reviewed-on: https://review.openocd.org/c/openocd/+/7899 Reviewed-by: Antonio Borneo Tested-by: jenkins --- tcl/target/ti_k3.cfg | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tcl/target/ti_k3.cfg b/tcl/target/ti_k3.cfg index 090f08209..1cd85eec3 100644 --- a/tcl/target/ti_k3.cfg +++ b/tcl/target/ti_k3.cfg @@ -417,4 +417,7 @@ if { 0 == [string compare [adapter name] dmem ] } { } else { puts "ERROR: ${SOC} data is missing to support dmem access!" } +} else { + # AXI AP access port for SoC address map + target create $_CHIPNAME.axi_ap mem_ap -dap $_CHIPNAME.dap -ap-num 2 } From 1bc4182cebcbdf93d68d9759f4b4579ea4df7887 Mon Sep 17 00:00:00 2001 From: Frank Plowman Date: Sun, 17 Sep 2023 19:20:04 +0100 Subject: [PATCH 11/13] target/nrf52: Create and configure TPIU Firstly, create the TPIU nrf52.tpiu if using the nrf52 target. This is standard, using AP 0 and TPIU base address 0xE0040000. Secondly, add a pre_enable handler for this TPIU which configures the TRACEMUX field of the TRACECONFIG register. This register is reset every time the MCU resets, so the pre_enable handler creates a reset-end handler to ensure the register remains set. Change-Id: I408b20fc03dc2060c21bad0c21ed713eee55a113 Signed-off-by: Frank Plowman Reviewed-on: https://review.openocd.org/c/openocd/+/7901 Reviewed-by: Antonio Borneo Tested-by: jenkins --- tcl/target/nrf52.cfg | 49 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/tcl/target/nrf52.cfg b/tcl/target/nrf52.cfg index 2539be049..0c82c5758 100644 --- a/tcl/target/nrf52.cfg +++ b/tcl/target/nrf52.cfg @@ -5,6 +5,7 @@ # source [find target/swj-dp.tcl] +source [find mem_helper.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME @@ -116,3 +117,51 @@ proc nrf52_recover {} { } add_help_text nrf52_recover "Mass erase and unlock nRF52 device" + +tpiu create $_CHIPNAME.tpiu -dap $_CHIPNAME.dap -ap-num 0 -baseaddr 0xE0040000 + +lappend _telnet_autocomplete_skip _proc_pre_enable_$_CHIPNAME.tpiu +proc _proc_pre_enable_$_CHIPNAME.tpiu {_targetname _chipname} { + targets $_targetname + + # Read FICR.INFO.PART + set PART [mrw 0x10000100] + + switch $PART { + 0x52840 - + 0x52833 - + 0x52832 { + if { [$_chipname.tpiu cget -protocol] eq "sync" } { + if { [$_chipname.tpiu cget -port-width] != 4 } { + echo "Error. Device only supports 4-bit sync traces." + return + } + + # Set TRACECONFIG.TRACEMUX to enable synchronous trace + mmw 0x4000055C 0x00020000 0x00010000 + $_targetname configure -event reset-end { + mmw 0x4000055C 0x00020000 0x00010000 + } + } else { + # Set TRACECONFIG.TRACEMUX to enable SWO + mmw 0x4000055C 0x00010000 0x00020000 + $_targetname configure -event reset-end { + mmw 0x4000055C 0x00010000 0x00020000 + } + } + } + 0x52820 - + 0x52811 - + 0x52810 - + 0x52805 { + echo "Error: Device does not support TPIU" + return + } + default { + echo "Error: Unknown device" + return + } + } +} + +$_CHIPNAME.tpiu configure -event pre-enable "_proc_pre_enable_$_CHIPNAME.tpiu $_TARGETNAME $_CHIPNAME" From d27a3a00b8582cf2750cbc86c6194f5796ccca06 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Mon, 18 Mar 2019 16:00:07 -0700 Subject: [PATCH 12/13] arm_opcode: Add support for ARM MCRR/MRRC Add support for the ARM MCRR/MRRC instructions which require the use of two registers to transfer a 64-bit co-processor registers. We are going to use this in a subsequent patch in order to properly dump 64-bit page table descriptors that exist on ARMv7A with VMSA extensions. We make use of r0 and r1 to transfer 64-bit quantities to/from DCC. Change-Id: Ic4975026c1ae4f2853795575ac7701d541248736 Signed-off-by: Florian Fainelli Signed-off-by: Michael Chalfant Reviewed-on: https://review.openocd.org/c/openocd/+/5228 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/target/arm.h | 10 ++++ src/target/arm_dpm.c | 48 +++++++++++++++ src/target/arm_dpm.h | 13 +++++ src/target/arm_opcodes.h | 22 +++++++ src/target/armv4_5.c | 122 +++++++++++++++++++++++++++++++++++++++ src/target/cortex_a.c | 47 +++++++++++++++ 6 files changed, 262 insertions(+) diff --git a/src/target/arm.h b/src/target/arm.h index cc0f14cb6..d5053afb8 100644 --- a/src/target/arm.h +++ b/src/target/arm.h @@ -231,12 +231,22 @@ struct arm { uint32_t crn, uint32_t crm, uint32_t *value); + /** Read coprocessor to two registers. */ + int (*mrrc)(struct target *target, int cpnum, + uint32_t op, uint32_t crm, + uint64_t *value); + /** Write coprocessor register. */ int (*mcr)(struct target *target, int cpnum, uint32_t op1, uint32_t op2, uint32_t crn, uint32_t crm, uint32_t value); + /** Write coprocessor from two registers. */ + int (*mcrr)(struct target *target, int cpnum, + uint32_t op, uint32_t crm, + uint64_t value); + void *arch_info; /** For targets conforming to ARM Debug Interface v5, diff --git a/src/target/arm_dpm.c b/src/target/arm_dpm.c index ab9b50e23..9f3a444af 100644 --- a/src/target/arm_dpm.c +++ b/src/target/arm_dpm.c @@ -63,6 +63,29 @@ static int dpm_mrc(struct target *target, int cpnum, return retval; } +static int dpm_mrrc(struct target *target, int cpnum, + uint32_t op, uint32_t crm, uint64_t *value) +{ + struct arm *arm = target_to_arm(target); + struct arm_dpm *dpm = arm->dpm; + int retval; + + retval = dpm->prepare(dpm); + if (retval != ERROR_OK) + return retval; + + LOG_DEBUG("MRRC p%d, %d, r0, r1, c%d", cpnum, + (int)op, (int)crm); + + /* read coprocessor register into R0, R1; return via DCC */ + retval = dpm->instr_read_data_r0_r1(dpm, + ARMV5_T_MRRC(cpnum, op, 0, 1, crm), + value); + + /* (void) */ dpm->finish(dpm); + return retval; +} + static int dpm_mcr(struct target *target, int cpnum, uint32_t op1, uint32_t op2, uint32_t crn, uint32_t crm, uint32_t value) @@ -88,6 +111,29 @@ static int dpm_mcr(struct target *target, int cpnum, return retval; } +static int dpm_mcrr(struct target *target, int cpnum, + uint32_t op, uint32_t crm, uint64_t value) +{ + struct arm *arm = target_to_arm(target); + struct arm_dpm *dpm = arm->dpm; + int retval; + + retval = dpm->prepare(dpm); + if (retval != ERROR_OK) + return retval; + + LOG_DEBUG("MCRR p%d, %d, r0, r1, c%d", cpnum, + (int)op, (int)crm); + + /* read DCC into r0, r1; then write coprocessor register from R0, R1 */ + retval = dpm->instr_write_data_r0_r1(dpm, + ARMV5_T_MCRR(cpnum, op, 0, 1, crm), value); + + /* (void) */ dpm->finish(dpm); + + return retval; +} + /*----------------------------------------------------------------------*/ /* @@ -1070,6 +1116,8 @@ int arm_dpm_setup(struct arm_dpm *dpm) /* coprocessor access setup */ arm->mrc = dpm_mrc; arm->mcr = dpm_mcr; + arm->mrrc = dpm_mrrc; + arm->mcrr = dpm_mcrr; /* breakpoint setup -- optional until it works everywhere */ if (!target->type->add_breakpoint) { diff --git a/src/target/arm_dpm.h b/src/target/arm_dpm.h index d35e9f68d..2da463111 100644 --- a/src/target/arm_dpm.h +++ b/src/target/arm_dpm.h @@ -72,6 +72,12 @@ struct arm_dpm { int (*instr_write_data_r0)(struct arm_dpm *dpm, uint32_t opcode, uint32_t data); + /** + * Runs two instructions, writing data to R0 and R1 before execution. + */ + int (*instr_write_data_r0_r1)(struct arm_dpm *dpm, + uint32_t opcode, uint64_t data); + /** Runs one instruction, writing data to R0 before execution. */ int (*instr_write_data_r0_64)(struct arm_dpm *dpm, uint32_t opcode, uint64_t data); @@ -92,6 +98,13 @@ struct arm_dpm { int (*instr_read_data_r0)(struct arm_dpm *dpm, uint32_t opcode, uint32_t *data); + /** + * Runs two instructions, reading data from r0 and r1 after + * execution. + */ + int (*instr_read_data_r0_r1)(struct arm_dpm *dpm, + uint32_t opcode, uint64_t *data); + int (*instr_read_data_r0_64)(struct arm_dpm *dpm, uint32_t opcode, uint64_t *data); diff --git a/src/target/arm_opcodes.h b/src/target/arm_opcodes.h index c182f41c4..c8ce51f29 100644 --- a/src/target/arm_opcodes.h +++ b/src/target/arm_opcodes.h @@ -187,6 +187,17 @@ (0xee100010 | (crm) | ((op2) << 5) | ((cp) << 8) \ | ((rd) << 12) | ((crn) << 16) | ((op1) << 21)) +/* Move to two ARM registers from coprocessor + * cp: Coprocessor number + * op: Coprocessor opcode + * rt: destination register 1 + * rt2: destination register 2 + * crm: coprocessor source register + */ +#define ARMV5_T_MRRC(cp, op, rt, rt2, crm) \ + (0xec500000 | (crm) | ((op) << 4) | ((cp) << 8) \ + | ((rt) << 12) | ((rt2) << 16)) + /* Move to coprocessor from ARM register * cp: Coprocessor number * op1: Coprocessor opcode @@ -199,6 +210,17 @@ (0xee000010 | (crm) | ((op2) << 5) | ((cp) << 8) \ | ((rd) << 12) | ((crn) << 16) | ((op1) << 21)) +/* Move to coprocessor from two ARM registers + * cp: Coprocessor number + * op: Coprocessor opcode + * rt: destination register 1 + * rt2: destination register 2 + * crm: coprocessor source register + */ +#define ARMV5_T_MCRR(cp, op, rt, rt2, crm) \ + (0xec400000 | (crm) | ((op) << 4) | ((cp) << 8) \ + | ((rt) << 12) | ((rt2) << 16)) + /* Breakpoint instruction (ARMv5) * im: 16-bit immediate */ diff --git a/src/target/armv4_5.c b/src/target/armv4_5.c index 8e3f22417..7debb9498 100644 --- a/src/target/armv4_5.c +++ b/src/target/armv4_5.c @@ -1093,6 +1093,94 @@ COMMAND_HANDLER(handle_armv4_5_mcrmrc) return ERROR_OK; } +COMMAND_HANDLER(handle_armv4_5_mcrrmrrc) +{ + bool is_mcrr = false; + unsigned int arg_cnt = 3; + + if (!strcmp(CMD_NAME, "mcrr")) { + is_mcrr = true; + arg_cnt = 4; + } + + if (arg_cnt != CMD_ARGC) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct target *target = get_current_target(CMD_CTX); + if (!target) { + command_print(CMD, "no current target"); + return ERROR_FAIL; + } + if (!target_was_examined(target)) { + command_print(CMD, "%s: not yet examined", target_name(target)); + return ERROR_TARGET_NOT_EXAMINED; + } + + struct arm *arm = target_to_arm(target); + if (!is_arm(arm)) { + command_print(CMD, "%s: not an ARM", target_name(target)); + return ERROR_FAIL; + } + + if (target->state != TARGET_HALTED) + return ERROR_TARGET_NOT_HALTED; + + int cpnum; + uint32_t op1; + uint32_t crm; + uint64_t value; + + /* NOTE: parameter sequence matches ARM instruction set usage: + * MCRR pNUM, op1, rX1, rX2, CRm ; write CP from rX1 and rX2 + * MREC pNUM, op1, rX1, rX2, CRm ; read CP into rX1 and rX2 + * The "rXn" are necessarily omitted; they use Tcl mechanisms. + */ + COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], cpnum); + if (cpnum & ~0xf) { + command_print(CMD, "coprocessor %d out of range", cpnum); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], op1); + if (op1 & ~0xf) { + command_print(CMD, "op1 %d out of range", op1); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], crm); + if (crm & ~0xf) { + command_print(CMD, "CRm %d out of range", crm); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + /* + * FIXME change the call syntax here ... simplest to just pass + * the MRC() or MCR() instruction to be executed. That will also + * let us support the "mrrc2" and "mcrr2" opcodes (toggling one bit) + * if that's ever needed. + */ + if (is_mcrr) { + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[3], value); + + /* NOTE: parameters reordered! */ + /* ARMV5_T_MCRR(cpnum, op1, crm) */ + int retval = arm->mcrr(target, cpnum, op1, crm, value); + if (retval != ERROR_OK) + return retval; + } else { + value = 0; + /* NOTE: parameters reordered! */ + /* ARMV5_T_MRRC(cpnum, op1, crm) */ + int retval = arm->mrrc(target, cpnum, op1, crm, &value); + if (retval != ERROR_OK) + return retval; + + command_print(CMD, "0x%" PRIx64, value); + } + + return ERROR_OK; +} + static const struct command_registration arm_exec_command_handlers[] = { { .name = "reg", @@ -1115,6 +1203,20 @@ static const struct command_registration arm_exec_command_handlers[] = { .help = "read coprocessor register", .usage = "cpnum op1 CRn CRm op2", }, + { + .name = "mcrr", + .mode = COMMAND_EXEC, + .handler = handle_armv4_5_mcrrmrrc, + .help = "write coprocessor 64-bit register", + .usage = "cpnum op1 CRm value", + }, + { + .name = "mrrc", + .mode = COMMAND_EXEC, + .handler = handle_armv4_5_mcrrmrrc, + .help = "read coprocessor 64-bit register", + .usage = "cpnum op1 CRm", + }, { .chain = arm_all_profiles_command_handlers, }, @@ -1669,6 +1771,14 @@ static int arm_default_mrc(struct target *target, int cpnum, return ERROR_FAIL; } +static int arm_default_mrrc(struct target *target, int cpnum, + uint32_t op, uint32_t crm, + uint64_t *value) +{ + LOG_ERROR("%s doesn't implement MRRC", target_type_name(target)); + return ERROR_FAIL; +} + static int arm_default_mcr(struct target *target, int cpnum, uint32_t op1, uint32_t op2, uint32_t crn, uint32_t crm, @@ -1678,6 +1788,14 @@ static int arm_default_mcr(struct target *target, int cpnum, return ERROR_FAIL; } +static int arm_default_mcrr(struct target *target, int cpnum, + uint32_t op, uint32_t crm, + uint64_t value) +{ + LOG_ERROR("%s doesn't implement MCRR", target_type_name(target)); + return ERROR_FAIL; +} + int arm_init_arch_info(struct target *target, struct arm *arm) { target->arch_info = arm; @@ -1697,8 +1815,12 @@ int arm_init_arch_info(struct target *target, struct arm *arm) if (!arm->mrc) arm->mrc = arm_default_mrc; + if (!arm->mrrc) + arm->mrrc = arm_default_mrrc; if (!arm->mcr) arm->mcr = arm_default_mcr; + if (!arm->mcrr) + arm->mcrr = arm_default_mcrr; return ERROR_OK; } diff --git a/src/target/cortex_a.c b/src/target/cortex_a.c index abfd6ac5f..ba3349d09 100644 --- a/src/target/cortex_a.c +++ b/src/target/cortex_a.c @@ -471,6 +471,28 @@ static int cortex_a_instr_write_data_r0(struct arm_dpm *dpm, return retval; } +static int cortex_a_instr_write_data_r0_r1(struct arm_dpm *dpm, + uint32_t opcode, uint64_t data) +{ + struct cortex_a_common *a = dpm_to_a(dpm); + uint32_t dscr = DSCR_INSTR_COMP; + int retval; + + retval = cortex_a_instr_write_data_rt_dcc(dpm, 0, data & 0xffffffffULL); + if (retval != ERROR_OK) + return retval; + + retval = cortex_a_instr_write_data_rt_dcc(dpm, 1, data >> 32); + if (retval != ERROR_OK) + return retval; + + /* then the opcode, taking data from R0, R1 */ + retval = cortex_a_exec_opcode(a->armv7a_common.arm.target, + opcode, + &dscr); + return retval; +} + static int cortex_a_instr_cpsr_sync(struct arm_dpm *dpm) { struct target *target = dpm->arm->target; @@ -539,6 +561,29 @@ static int cortex_a_instr_read_data_r0(struct arm_dpm *dpm, return cortex_a_instr_read_data_rt_dcc(dpm, 0, data); } +static int cortex_a_instr_read_data_r0_r1(struct arm_dpm *dpm, + uint32_t opcode, uint64_t *data) +{ + uint32_t lo, hi; + int retval; + + /* the opcode, writing data to RO, R1 */ + retval = cortex_a_instr_read_data_r0(dpm, opcode, &lo); + if (retval != ERROR_OK) + return retval; + + *data = lo; + + /* write R1 to DCC */ + retval = cortex_a_instr_read_data_rt_dcc(dpm, 1, &hi); + if (retval != ERROR_OK) + return retval; + + *data |= (uint64_t)hi << 32; + + return retval; +} + static int cortex_a_bpwp_enable(struct arm_dpm *dpm, unsigned index_t, uint32_t addr, uint32_t control) { @@ -612,10 +657,12 @@ static int cortex_a_dpm_setup(struct cortex_a_common *a, uint32_t didr) dpm->instr_write_data_dcc = cortex_a_instr_write_data_dcc; dpm->instr_write_data_r0 = cortex_a_instr_write_data_r0; + dpm->instr_write_data_r0_r1 = cortex_a_instr_write_data_r0_r1; dpm->instr_cpsr_sync = cortex_a_instr_cpsr_sync; dpm->instr_read_data_dcc = cortex_a_instr_read_data_dcc; dpm->instr_read_data_r0 = cortex_a_instr_read_data_r0; + dpm->instr_read_data_r0_r1 = cortex_a_instr_read_data_r0_r1; dpm->bpwp_enable = cortex_a_bpwp_enable; dpm->bpwp_disable = cortex_a_bpwp_disable; From bcaac692d0fce45189279a4c80cbd6852e4bbf4e Mon Sep 17 00:00:00 2001 From: Kirill Radkin Date: Tue, 26 Sep 2023 16:49:09 +0300 Subject: [PATCH 13/13] target: Fix an issue with rwp/rbp command in smp targets If wp/bp is missing at address rwp/rbp won't return zero code (on smp). Now it fixed. Fixes: 022e438292de ("target: Change policy of removing watchpoints/breakpoints.") Change-Id: I3a3c245f7088fc23227b286d2191fc7f3edba702 Signed-off-by: Kirill Radkin Reviewed-on: https://review.openocd.org/c/openocd/+/7910 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/target/breakpoints.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/target/breakpoints.c b/src/target/breakpoints.c index 5ce0346bb..4a613cc28 100644 --- a/src/target/breakpoints.c +++ b/src/target/breakpoints.c @@ -367,8 +367,10 @@ int breakpoint_remove(struct target *target, target_addr_t address) } } - if (num_found_breakpoints == 0) + if (num_found_breakpoints == 0) { LOG_TARGET_ERROR(target, "no breakpoint at address " TARGET_ADDR_FMT " found", address); + return ERROR_BREAKPOINT_NOT_FOUND; + } return retval; } @@ -591,7 +593,7 @@ int watchpoint_remove(struct target *target, target_addr_t address) num_found_watchpoints++; if (status != ERROR_OK) { - LOG_TARGET_ERROR(curr, "failed to remove watchpoint at address" TARGET_ADDR_FMT, address); + LOG_TARGET_ERROR(curr, "failed to remove watchpoint at address " TARGET_ADDR_FMT, address); retval = status; } } @@ -603,12 +605,14 @@ int watchpoint_remove(struct target *target, target_addr_t address) num_found_watchpoints++; if (retval != ERROR_OK) - LOG_TARGET_ERROR(target, "failed to remove watchpoint at address" TARGET_ADDR_FMT, address); + LOG_TARGET_ERROR(target, "failed to remove watchpoint at address " TARGET_ADDR_FMT, address); } } - if (num_found_watchpoints == 0) + if (num_found_watchpoints == 0) { LOG_TARGET_ERROR(target, "no watchpoint at address " TARGET_ADDR_FMT " found", address); + return ERROR_WATCHPOINT_NOT_FOUND; + } return retval; }