You can subscribe to this list here.
| 2001 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
(57) |
Oct
|
Nov
|
Dec
|
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2006 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
(14) |
Nov
(36) |
Dec
(7) |
| 2007 |
Jan
(48) |
Feb
(10) |
Mar
(17) |
Apr
(8) |
May
(35) |
Jun
(28) |
Jul
(50) |
Aug
(71) |
Sep
(40) |
Oct
(19) |
Nov
(22) |
Dec
(143) |
| 2008 |
Jan
(184) |
Feb
(549) |
Mar
(381) |
Apr
(388) |
May
(148) |
Jun
(128) |
Jul
(502) |
Aug
(243) |
Sep
(136) |
Oct
(327) |
Nov
(252) |
Dec
(475) |
| 2009 |
Jan
(344) |
Feb
(185) |
Mar
(338) |
Apr
(826) |
May
(1559) |
Jun
(1429) |
Jul
(817) |
Aug
(451) |
Sep
(639) |
Oct
(935) |
Nov
(1222) |
Dec
(826) |
| 2010 |
Jan
(552) |
Feb
(532) |
Mar
(355) |
Apr
(206) |
May
(162) |
Jun
(203) |
Jul
(168) |
Aug
(232) |
Sep
(270) |
Oct
(259) |
Nov
(439) |
Dec
(468) |
| 2011 |
Jan
(224) |
Feb
(249) |
Mar
(278) |
Apr
(381) |
May
(316) |
Jun
(637) |
Jul
(544) |
Aug
(465) |
Sep
(159) |
Oct
(440) |
Nov
(139) |
Dec
|
| 2012 |
Jan
(204) |
Feb
(383) |
Mar
(295) |
Apr
(196) |
May
(590) |
Jun
(158) |
Jul
(167) |
Aug
(177) |
Sep
(179) |
Oct
(301) |
Nov
(144) |
Dec
(173) |
| 2013 |
Jan
(299) |
Feb
(120) |
Mar
(238) |
Apr
(140) |
May
(69) |
Jun
(133) |
Jul
(160) |
Aug
(107) |
Sep
(164) |
Oct
(196) |
Nov
(105) |
Dec
(74) |
| 2014 |
Jan
(205) |
Feb
(156) |
Mar
(175) |
Apr
(181) |
May
(162) |
Jun
(158) |
Jul
(117) |
Aug
(109) |
Sep
(148) |
Oct
(106) |
Nov
(82) |
Dec
(72) |
| 2015 |
Jan
(191) |
Feb
(205) |
Mar
(197) |
Apr
(163) |
May
(136) |
Jun
(36) |
Jul
(79) |
Aug
(55) |
Sep
(64) |
Oct
(146) |
Nov
(142) |
Dec
(78) |
| 2016 |
Jan
(65) |
Feb
(190) |
Mar
(53) |
Apr
(38) |
May
(95) |
Jun
(53) |
Jul
(58) |
Aug
(113) |
Sep
(96) |
Oct
(59) |
Nov
(136) |
Dec
(124) |
| 2017 |
Jan
(80) |
Feb
(109) |
Mar
(163) |
Apr
(78) |
May
(61) |
Jun
(73) |
Jul
(29) |
Aug
(47) |
Sep
(60) |
Oct
(76) |
Nov
(48) |
Dec
(35) |
| 2018 |
Jan
(138) |
Feb
(84) |
Mar
(109) |
Apr
(49) |
May
(24) |
Jun
(62) |
Jul
(96) |
Aug
(116) |
Sep
(53) |
Oct
(99) |
Nov
(80) |
Dec
(88) |
| 2019 |
Jan
(100) |
Feb
(141) |
Mar
(72) |
Apr
(174) |
May
(129) |
Jun
(102) |
Jul
(52) |
Aug
(45) |
Sep
(28) |
Oct
(43) |
Nov
(78) |
Dec
(47) |
| 2020 |
Jan
(113) |
Feb
(72) |
Mar
(94) |
Apr
(141) |
May
(82) |
Jun
(68) |
Jul
(125) |
Aug
(76) |
Sep
(33) |
Oct
(184) |
Nov
(61) |
Dec
(95) |
| 2021 |
Jan
(109) |
Feb
(77) |
Mar
(145) |
Apr
(116) |
May
(134) |
Jun
(113) |
Jul
(71) |
Aug
(118) |
Sep
(116) |
Oct
(92) |
Nov
(124) |
Dec
(68) |
| 2022 |
Jan
(57) |
Feb
(61) |
Mar
(57) |
Apr
(74) |
May
(86) |
Jun
(80) |
Jul
(43) |
Aug
(85) |
Sep
(120) |
Oct
(88) |
Nov
(100) |
Dec
(108) |
| 2023 |
Jan
(39) |
Feb
(56) |
Mar
(92) |
Apr
(81) |
May
(84) |
Jun
(72) |
Jul
(182) |
Aug
(82) |
Sep
(54) |
Oct
(68) |
Nov
(67) |
Dec
(75) |
| 2024 |
Jan
(79) |
Feb
(65) |
Mar
(42) |
Apr
(47) |
May
(68) |
Jun
(111) |
Jul
(43) |
Aug
(73) |
Sep
(100) |
Oct
(35) |
Nov
(100) |
Dec
(99) |
| 2025 |
Jan
(71) |
Feb
(68) |
Mar
(44) |
Apr
(40) |
May
(92) |
Jun
(45) |
Jul
(86) |
Aug
(60) |
Sep
(76) |
Oct
(69) |
Nov
(102) |
Dec
(6) |
|
From: <ge...@op...> - 2025-11-22 21:08:57
|
This is an automated email from Gerrit. "Antonio Borneo <bor...@gm...>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/9266 -- gerrit commit 8cbe10664925176d2ea836b2855b18b64fc7ca29 Author: Antonio Borneo <bor...@gm...> Date: Sat Nov 22 22:03:10 2025 +0100 server: fix a new double free() By reorganizing the free() of the service and its subfields, the patch reported in 'fixes' exposes a new double free(). Issue detected by 'scan-build'. Fix it. Fixes: 5ff384be086a ("semihosting: fix memory leak and double free") Change-Id: Ief4262e98c9ecdca39d4e2d77e7a0ea87cfa198c Signed-off-by: Antonio Borneo <bor...@gm...> diff --git a/src/server/server.c b/src/server/server.c index 494fd9da30..81d79d41b1 100644 --- a/src/server/server.c +++ b/src/server/server.c @@ -378,7 +378,6 @@ int remove_service(const char *name, const char *port) if (tmp->type != CONNECTION_STDINOUT) close_socket(tmp->fd); - free(tmp->priv); free_service(tmp); return ERROR_OK; -- |
|
From: <ge...@op...> - 2025-11-21 18:17:59
|
This is an automated email from Gerrit. "Lucien Buchmann <luc...@du...>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/9265 -- gerrit commit 93618f2c351c8719924c88ee7f3a2c5c8edf1c47 Author: Lucien Dufour <luc...@du...> Date: Fri Nov 21 19:13:30 2025 +0100 Add libusb_open() result to error log Change-Id: Ic59e29d4dd06868920c2b912e4c866d4f176a563 Signed-off-by: Lucien Dufour <luc...@du...> diff --git a/src/jtag/drivers/xds110.c b/src/jtag/drivers/xds110.c index a2b0dd213e..75d6a4f815 100644 --- a/src/jtag/drivers/xds110.c +++ b/src/jtag/drivers/xds110.c @@ -373,6 +373,9 @@ static bool usb_connect(void) /* If we fall though to here, we don't want this device */ libusb_close(dev); dev = NULL; + } else { + const char *err_msg = libusb_error_name(result); + LOG_ERROR("libusb_open(): %s", err_msg); } } } -- |
|
From: <ge...@op...> - 2025-11-21 17:20:17
|
This is an automated email from Gerrit. "Daniel Goehring <dgo...@os...>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/9264 -- gerrit commit 5a04b064ed6566f52a349a4c9465631f2ac7c398 Author: Daniel Goehring <dgo...@os...> Date: Mon Jul 14 19:29:24 2025 -0600 target/arm: add nested AP Cortex M target support For the Cortex M processor target, add nested AP support. Change-Id: I624e3c0dfa899968ebca06b3b0d0d963fc0f9828 Signed-off-by: Daniel Goehring <dgo...@os...> diff --git a/src/target/cortex_m.c b/src/target/cortex_m.c index 9f0b6284b0..a01ce2a3ee 100644 --- a/src/target/cortex_m.c +++ b/src/target/cortex_m.c @@ -2775,7 +2775,11 @@ int cortex_m_examine(struct target *target) return retval; } } else { - armv7m->debug_ap = dap_get_ap(swjdp, cortex_m->apsel); + if (cortex_m->apsel_gateway == DP_APSEL_INVALID) + armv7m->debug_ap = dap_get_ap(swjdp, cortex_m->apsel); + else + armv7m->debug_ap = dap_get_ap_gateway(swjdp, cortex_m->apsel, cortex_m->apsel_gateway); + if (!armv7m->debug_ap) { LOG_TARGET_ERROR(target, "Cannot get AP"); return ERROR_FAIL; @@ -3147,6 +3151,7 @@ static int cortex_m_target_create(struct target *target) cortex_m->common_magic = CORTEX_M_COMMON_MAGIC; cortex_m->apsel = pc->ap_num; + cortex_m->apsel_gateway = pc->ap_num_gateway; cortex_m_init_arch_info(target, cortex_m, pc->dap); diff --git a/src/target/cortex_m.h b/src/target/cortex_m.h index 615369f344..1588ddee00 100644 --- a/src/target/cortex_m.h +++ b/src/target/cortex_m.h @@ -304,6 +304,7 @@ struct cortex_m_common { bool slow_register_read; /* A register has not been ready, poll S_REGRDY */ uint64_t apsel; + uint64_t apsel_gateway; /* Whether this target has the erratum that makes C_MASKINTS not apply to * already pending interrupts */ -- |
|
From: <ge...@op...> - 2025-11-21 17:20:17
|
This is an automated email from Gerrit. "Daniel Goehring <dgo...@os...>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/9262 -- gerrit commit 12a62b772e3e23b76acd0bca056d32eed38d2b4e Author: Daniel Goehring <dgo...@os...> Date: Mon Jul 14 19:22:24 2025 -0600 target/arm: add nested AP CTI support For the Cross-Trigger-Interface, add nested AP support. Change-Id: Ie566805785e669f71e3a5cc830a4f4c6189900fb Signed-off-by: Daniel Goehring <dgo...@os...> diff --git a/src/target/arm_cti.c b/src/target/arm_cti.c index 032e5ac379..6f05794f46 100644 --- a/src/target/arm_cti.c +++ b/src/target/arm_cti.c @@ -502,7 +502,11 @@ COMMAND_HANDLER(handle_cti_create) list_add_tail(&cti->lh, &all_cti); - cti->ap = dap_get_ap(cti->spot.dap, cti->spot.ap_num); + if (cti->spot.ap_num_gateway == DP_APSEL_INVALID) + cti->ap = dap_get_ap(cti->spot.dap, cti->spot.ap_num); + else + cti->ap = dap_get_ap_gateway(cti->spot.dap, cti->spot.ap_num, cti->spot.ap_num_gateway); + if (!cti->ap) { command_print(CMD, "Cannot get AP"); free(cti->name); -- |
|
From: <ge...@op...> - 2025-11-21 17:20:17
|
This is an automated email from Gerrit. "Daniel Goehring <dgo...@os...>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/9260 -- gerrit commit 4fbb777427da42c8d9cfc40207e0c803bae8ca83 Author: Daniel Goehring <dgo...@os...> Date: Mon Jul 14 10:46:11 2025 -0600 target/arm: add nested AP MEM_AP target support For the MEM_AP target, add nested AP support. Change-Id: Ic084e3c0d33fc74006d7119e3983f19348ce1f17 Signed-off-by: Daniel Goehring <dgo...@os...> diff --git a/src/target/mem_ap.c b/src/target/mem_ap.c index c5618c9ccd..00ab1de7bf 100644 --- a/src/target/mem_ap.c +++ b/src/target/mem_ap.c @@ -22,6 +22,7 @@ struct mem_ap { struct adiv5_dap *dap; struct adiv5_ap *ap; uint64_t ap_num; + uint64_t ap_num_gateway; }; static int mem_ap_target_create(struct target *target) @@ -45,6 +46,7 @@ static int mem_ap_target_create(struct target *target) } mem_ap->ap_num = pc->ap_num; + mem_ap->ap_num_gateway = pc->ap_num_gateway; mem_ap->common_magic = MEM_AP_COMMON_MAGIC; mem_ap->dap = pc->dap; @@ -137,7 +139,10 @@ static int mem_ap_examine(struct target *target) if (!target_was_examined(target)) { if (!mem_ap->ap) { - mem_ap->ap = dap_get_ap(mem_ap->dap, mem_ap->ap_num); + if (mem_ap->ap_num_gateway == DP_APSEL_INVALID) + mem_ap->ap = dap_get_ap(mem_ap->dap, mem_ap->ap_num); + else + mem_ap->ap = dap_get_ap_gateway(mem_ap->dap, mem_ap->ap_num, mem_ap->ap_num_gateway); if (!mem_ap->ap) { LOG_TARGET_ERROR(target, "Cannot get AP"); return ERROR_FAIL; -- |
|
From: <ge...@op...> - 2025-11-21 17:20:14
|
This is an automated email from Gerrit. "Daniel Goehring <dgo...@os...>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/9261 -- gerrit commit 8bebf1d7b58d2cd9c4194b1b731f51850fd7473e Author: Daniel Goehring <dgo...@os...> Date: Mon Jul 14 19:20:46 2025 -0600 target/arm: add nested AP AArch64 target support For the AArch64 processor target, add nested AP support. Change-Id: I2aecb950edf32eac8bc0ee40c7a29cc631103e78 Signed-off-by: Daniel Goehring <dgo...@os...> diff --git a/src/target/aarch64.c b/src/target/aarch64.c index ed9cb48aa7..d776eeba16 100644 --- a/src/target/aarch64.c +++ b/src/target/aarch64.c @@ -2639,7 +2639,11 @@ static int aarch64_examine_first(struct target *target) return retval; } } else { - armv8->debug_ap = dap_get_ap(swjdp, pc->adiv5_config.ap_num); + if (pc->adiv5_config.ap_num_gateway == DP_APSEL_INVALID) + armv8->debug_ap = dap_get_ap(swjdp, pc->adiv5_config.ap_num); + else + armv8->debug_ap = dap_get_ap_gateway(swjdp, pc->adiv5_config.ap_num, pc->adiv5_config.ap_num_gateway); + if (!armv8->debug_ap) { LOG_ERROR("Cannot get AP"); return ERROR_FAIL; @@ -2919,6 +2923,7 @@ static int aarch64_jim_configure(struct target *target, struct jim_getopt_info * if (!pc) { pc = calloc(1, sizeof(struct aarch64_private_config)); pc->adiv5_config.ap_num = DP_APSEL_INVALID; + pc->adiv5_config.ap_num_gateway = DP_APSEL_INVALID; target->private_config = pc; } -- |
|
From: <ge...@op...> - 2025-11-21 17:20:14
|
This is an automated email from Gerrit. "Daniel Goehring <dgo...@os...>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/9258 -- gerrit commit 19e30fd8e9e5e3d8988c89cf28159a6af74787fe Author: Daniel Goehring <dgo...@os...> Date: Mon Jul 14 21:05:02 2025 -0600 target/arm: add nested AP DAP 'baseaddr' cmd support Add nested AP support to the DAP 'baseaddr' command. Change-Id: If242e93bf4f6405acab37cbf7256435bc6f0070c Signed-off-by: Daniel Goehring <dgo...@os...> diff --git a/src/target/arm_adi_v5.c b/src/target/arm_adi_v5.c index 995f0db1df..cb4a917136 100644 --- a/src/target/arm_adi_v5.c +++ b/src/target/arm_adi_v5.c @@ -2708,9 +2708,10 @@ COMMAND_HANDLER(handle_dap_info_command) COMMAND_HANDLER(dap_baseaddr_command) { struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA); + struct adiv5_ap *ap; uint64_t apsel; + uint64_t apsel_gateway = DP_APSEL_INVALID; uint32_t baseaddr_lower, baseaddr_upper; - struct adiv5_ap *ap; target_addr_t baseaddr; int retval; @@ -2719,6 +2720,7 @@ COMMAND_HANDLER(dap_baseaddr_command) switch (CMD_ARGC) { case 0: apsel = dap->apsel; + apsel_gateway = dap->apsel_gateway; break; case 1: COMMAND_PARSE_NUMBER(u64, CMD_ARGV[0], apsel); @@ -2727,6 +2729,18 @@ COMMAND_HANDLER(dap_baseaddr_command) return ERROR_COMMAND_ARGUMENT_INVALID; } break; + case 2: + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[0], apsel); + if (!is_ap_num_valid(dap, apsel)) { + command_print(CMD, "Invalid AP number"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[1], apsel_gateway); + if (!is_ap_num_valid(dap, apsel_gateway)) { + command_print(CMD, "Invalid AP_GATEWAY number"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + break; default: return ERROR_COMMAND_SYNTAX_ERROR; } @@ -2737,7 +2751,11 @@ COMMAND_HANDLER(dap_baseaddr_command) * use the ID register to verify it's a MEM-AP. */ - ap = dap_get_ap(dap, apsel); + if (apsel_gateway == DP_APSEL_INVALID) + ap = dap_get_ap(dap, apsel); + else + ap = dap_get_ap_gateway(dap, apsel, apsel_gateway); + if (!ap) { command_print(CMD, "Cannot get AP"); return ERROR_FAIL; @@ -3275,7 +3293,7 @@ const struct command_registration dap_instance_commands[] = { .mode = COMMAND_EXEC, .help = "return debug base address from MEM-AP " "(default currently selected AP)", - .usage = "[ap_num]", + .usage = "[ap_num [ap_num_gateway]]", }, { .name = "memaccess", -- |
|
From: <ge...@op...> - 2025-11-21 17:20:13
|
This is an automated email from Gerrit. "Daniel Goehring <dgo...@os...>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/9263 -- gerrit commit 8b55996f6513dda53df8fd2a34c6de4ae196a59a Author: Daniel Goehring <dgo...@os...> Date: Mon Jul 14 19:25:47 2025 -0600 target/arm: add nested AP Cortex A target support For the Cortex A processor target, add nested AP support. Change-Id: Idfa7ad7f952119298e85aa3459a20c6ab60b6628 Signed-off-by: Daniel Goehring <dgo...@os...> diff --git a/src/target/cortex_a.c b/src/target/cortex_a.c index bc7550509c..0c1bf5c365 100644 --- a/src/target/cortex_a.c +++ b/src/target/cortex_a.c @@ -2958,7 +2958,11 @@ static int cortex_a_examine_first(struct target *target) return retval; } } else { - armv7a->debug_ap = dap_get_ap(swjdp, pc->ap_num); + if (pc->ap_num_gateway == DP_APSEL_INVALID) + armv7a->debug_ap = dap_get_ap(swjdp, pc->ap_num); + else + armv7a->debug_ap = dap_get_ap_gateway(swjdp, pc->ap_num, pc->ap_num_gateway); + if (!armv7a->debug_ap) { LOG_ERROR("Cannot get AP"); return ERROR_FAIL; @@ -3118,6 +3122,10 @@ static int cortex_a_examine_first(struct target *target) /* select debug_ap as default */ swjdp->apsel = armv7a->debug_ap->ap_num; + if (armv7a->debug_ap->ap_gateway) + swjdp->apsel_gateway = armv7a->debug_ap->ap_gateway->ap_num; + else + swjdp->apsel_gateway = DP_APSEL_INVALID; target_set_examined(target); return ERROR_OK; -- |
|
From: <ge...@op...> - 2025-11-21 17:20:13
|
This is an automated email from Gerrit. "Daniel Goehring <dgo...@os...>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/9259 -- gerrit commit 8b51fc44bfb7b67d40dfd6dcbd809158179ec9c1 Author: Daniel Goehring <dgo...@os...> Date: Mon Jul 14 21:06:48 2025 -0600 target/arm: add nested AP DAP 'info' cmd support Add nested AP support to the DAP 'info' command. Change-Id: Ie5f155cb2d1ebe28d0b25b471040866dea24dd05 Signed-off-by: Daniel Goehring <dgo...@os...> diff --git a/src/target/arm_adi_v5.c b/src/target/arm_adi_v5.c index cb4a917136..663b18b116 100644 --- a/src/target/arm_adi_v5.c +++ b/src/target/arm_adi_v5.c @@ -2032,7 +2032,12 @@ static int rtp_rom_loop(enum coresight_access_mode mode, const struct rtp_ops *o /* Recurse */ if (mode == CS_ACCESS_AP) { - struct adiv5_ap *next_ap = dap_get_ap(ap->dap, component_base); + struct adiv5_ap *next_ap; + if (!ap->ap_gateway) + next_ap = dap_get_ap(ap->dap, component_base); + else + next_ap = dap_get_ap_gateway(ap->dap, component_base, ap->ap_gateway->ap_num); + if (!next_ap) { LOG_DEBUG("Wrong AP # 0x%" PRIx64, component_base); continue; @@ -2180,7 +2185,11 @@ static int dap_info_ap_header(struct adiv5_ap *ap, int depth, void *priv) return ERROR_FAIL; } - command_print(cmd, "%sAP # 0x%" PRIx64, (depth) ? "\t\t" : "", ap->ap_num); + if (!ap->ap_gateway) + command_print(cmd, "%sAP # 0x%" PRIx64, (depth) ? "\t\t" : "", ap->ap_num); + else + command_print(cmd, "%sAP # 0x%" PRIx64 ", GW # 0x%" PRIx64, (depth) ? "\t\t" : "", + ap->ap_num, ap->ap_gateway->ap_num); return ERROR_OK; } @@ -2206,7 +2215,11 @@ static int dap_info_mem_ap_header(int retval, struct adiv5_ap *ap, command_print(cmd, "\t\tAP ID register 0x%8.8" PRIx32, apid); if (apid == 0) { - command_print(cmd, "\t\tNo AP found at this AP#0x%" PRIx64, ap->ap_num); + if (!ap->ap_gateway) + command_print(cmd, "\t\tNo AP found at this AP#0x%" PRIx64, ap->ap_num); + else + command_print(cmd, "\t\tNo AP found at this AP#0x%" PRIx64 " GW#0x%" PRIx64, + ap->ap_num, ap->ap_gateway->ap_num); return ERROR_FAIL; } @@ -2665,11 +2678,14 @@ int adiv5_mem_ap_spot_init(struct adiv5_mem_ap_spot *p) COMMAND_HANDLER(handle_dap_info_command) { struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA); + struct adiv5_ap *ap; uint64_t apsel; + uint64_t apsel_gateway = DP_APSEL_INVALID; switch (CMD_ARGC) { case 0: apsel = dap->apsel; + apsel_gateway = dap->apsel_gateway; break; case 1: if (!strcmp(CMD_ARGV[0], "root")) { @@ -2690,11 +2706,27 @@ COMMAND_HANDLER(handle_dap_info_command) return ERROR_COMMAND_ARGUMENT_INVALID; } break; + case 2: + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[0], apsel); + if (!is_ap_num_valid(dap, apsel)) { + command_print(CMD, "Invalid AP number"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[1], apsel_gateway); + if (!is_ap_num_valid(dap, apsel_gateway)) { + command_print(CMD, "Invalid AP_GATEWAY number"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + break; default: return ERROR_COMMAND_SYNTAX_ERROR; } - struct adiv5_ap *ap = dap_get_ap(dap, apsel); + if (apsel_gateway == DP_APSEL_INVALID) + ap = dap_get_ap(dap, apsel); + else + ap = dap_get_ap_gateway(dap, apsel, apsel_gateway); + if (!ap) { command_print(CMD, "Cannot get AP"); return ERROR_FAIL; @@ -3237,7 +3269,7 @@ const struct command_registration dap_instance_commands[] = { .mode = COMMAND_EXEC, .help = "display ROM table for specified MEM-AP (default currently selected AP) " "or the ADIv6 root ROM table", - .usage = "[ap_num | 'root']", + .usage = "[ap_num [ap_num_gateway] | 'root']", }, { .name = "apsel", -- |
|
From: <ge...@op...> - 2025-11-21 17:20:13
|
This is an automated email from Gerrit. "Daniel Goehring <dgo...@os...>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/9256 -- gerrit commit 0d0b74b001373717b226684fd2c07752a74da469 Author: Daniel Goehring <dgo...@os...> Date: Mon Jul 14 20:56:58 2025 -0600 target/arm: add nested AP DAP 'apsel' cmd support Add nested AP support to the DAP 'apsel' command. Change-Id: I60fb9331dd9057a18081e24b1d595b74ad0b28e8 Signed-off-by: Daniel Goehring <dgo...@os...> diff --git a/src/target/arm_adi_v5.c b/src/target/arm_adi_v5.c index adf43bd1aa..5c491ae413 100644 --- a/src/target/arm_adi_v5.c +++ b/src/target/arm_adi_v5.c @@ -2808,10 +2808,14 @@ COMMAND_HANDLER(dap_apsel_command) { struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA); uint64_t apsel; + uint64_t apsel_gateway = DP_APSEL_INVALID; switch (CMD_ARGC) { case 0: - command_print(CMD, "0x%" PRIx64, dap->apsel); + if (dap->apsel_gateway == DP_APSEL_INVALID) + command_print(CMD, "AP 0x%" PRIx64, dap->apsel); + else + command_print(CMD, "AP 0x%" PRIx64 ", GW 0x%" PRIx64, dap->apsel, dap->apsel_gateway); return ERROR_OK; case 1: COMMAND_PARSE_NUMBER(u64, CMD_ARGV[0], apsel); @@ -2820,11 +2824,25 @@ COMMAND_HANDLER(dap_apsel_command) return ERROR_COMMAND_ARGUMENT_INVALID; } break; + case 2: + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[0], apsel); + if (!is_ap_num_valid(dap, apsel)) { + command_print(CMD, "Invalid AP number"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[1], apsel_gateway); + if (!is_ap_num_valid(dap, apsel_gateway)) { + command_print(CMD, "Invalid AP_GATEWAY number"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + break; default: return ERROR_COMMAND_SYNTAX_ERROR; } dap->apsel = apsel; + dap->apsel_gateway = apsel_gateway; + return ERROR_OK; } @@ -3201,7 +3219,7 @@ const struct command_registration dap_instance_commands[] = { .mode = COMMAND_ANY, .help = "Set the currently selected AP (default 0) " "and display the result", - .usage = "[ap_num]", + .usage = "[ap_num [ap_num_gateway]]", }, { .name = "apcsw", -- |
|
From: <ge...@op...> - 2025-11-21 17:20:10
|
This is an automated email from Gerrit. "Daniel Goehring <dgo...@os...>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/9253 -- gerrit commit 42858f6af9dc0bf48d1a7ab3646f8119829c7d1d Author: Daniel Goehring <dgo...@os...> Date: Tue Aug 5 11:01:26 2025 -0600 target/arm: add nested AP DAP 'apreg_gw' cmd support Create a new DAP 'apreg_gw' command for nested AP support. The abbreviation 'gw' refers to 'gateway', the top-level nested access port. Change-Id: Iaebf0a44cd3394767eefce5ec0e9d280dd3f3500 Signed-off-by: Daniel Goehring <dgo...@os...> diff --git a/src/target/arm_adi_v5.c b/src/target/arm_adi_v5.c index 77e3202927..9fdf32476f 100644 --- a/src/target/arm_adi_v5.c +++ b/src/target/arm_adi_v5.c @@ -3009,6 +3009,100 @@ COMMAND_HANDLER(dap_apreg_command) return retval; } +COMMAND_HANDLER(dap_apreg_gw_command) +{ + struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA); + struct adiv5_ap *ap; + uint64_t apsel; + uint64_t apsel_gateway = DP_APSEL_INVALID; + uint32_t reg, value; + int retval; + + if (CMD_ARGC < 2 || CMD_ARGC > 4) + return ERROR_COMMAND_SYNTAX_ERROR; + + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[0], apsel); + if (!is_ap_num_valid(dap, apsel)) { + command_print(CMD, "Invalid AP number"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[1], apsel_gateway); + if (!is_ap_num_valid(dap, apsel_gateway)) { + command_print(CMD, "Invalid AP_GATEWAY number"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], reg); + if (is_adiv6(dap)) { + if (reg >= 4096 || (reg & 3)) { + command_print(CMD, "Invalid reg value (should be less than 4096 and 4 bytes aligned)"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + } else { /* ADI version 5 */ + if (reg >= 256 || (reg & 3)) { + command_print(CMD, "Invalid reg value (should be less than 256 and 4 bytes aligned)"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + } + + if (apsel_gateway == DP_APSEL_INVALID) + ap = dap_get_ap(dap, apsel); + else + ap = dap_get_ap_gateway(dap, apsel, apsel_gateway); + + if (!ap) { + command_print(CMD, "Cannot get AP"); + return ERROR_FAIL; + } + + if (CMD_ARGC == 4) { + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], value); + /* see if user supplied register address is a match for the CSW or TAR register */ + if (reg == MEM_AP_REG_CSW(dap)) { + ap->csw_value = 0; /* invalid, in case write fails */ + retval = dap_queue_ap_write(ap, reg, value); + if (retval == ERROR_OK) + ap->csw_value = value; + } else if (reg == MEM_AP_REG_TAR(dap)) { + retval = dap_queue_ap_write(ap, reg, value); + if (retval == ERROR_OK) { + ap->tar_value = (ap->tar_value & ~0xFFFFFFFFull) | value; + } else { + /* To track independent writes to TAR and TAR64, two tar_valid flags */ + /* should be used. To keep it simple, tar_valid is only invalidated on a */ + /* write fail. This approach causes a later re-write of the TAR and TAR64 */ + /* if tar_valid is false. */ + ap->tar_valid = false; + } + } else if (reg == MEM_AP_REG_TAR64(dap)) { + retval = dap_queue_ap_write(ap, reg, value); + if (retval == ERROR_OK) { + ap->tar_value = (ap->tar_value & 0xFFFFFFFFull) | (((target_addr_t)value) << 32); + } else { + /* See above comment for the MEM_AP_REG_TAR failed write case */ + ap->tar_valid = false; + } + } else { + retval = dap_queue_ap_write(ap, reg, value); + } + } else { + retval = dap_queue_ap_read(ap, reg, &value); + } + if (retval == ERROR_OK) + retval = dap_run(dap); + + dap_put_ap(ap); + + if (retval != ERROR_OK) + return retval; + + if (CMD_ARGC == 3) + command_print(CMD, "0x%08" PRIx32, value); + + return retval; +} + COMMAND_HANDLER(dap_dpreg_command) { struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA); @@ -3093,10 +3187,18 @@ const struct command_registration dap_instance_commands[] = { .name = "apreg", .handler = dap_apreg_command, .mode = COMMAND_EXEC, - .help = "read/write a register from AP " + .help = "read/write a register from a non-nested AP " "(reg is byte address of a word register, like 0 4 8...)", .usage = "ap_num reg [value]", }, + { + .name = "apreg_gw", + .handler = dap_apreg_gw_command, + .mode = COMMAND_EXEC, + .help = "read/write a register from a nested AP " + "(reg is byte address of a word register, like 0 4 8...)", + .usage = "ap_num ap_num_gateway reg [value]", + }, { .name = "dpreg", .handler = dap_dpreg_command, -- |
|
From: <ge...@op...> - 2025-11-21 17:20:07
|
This is an automated email from Gerrit. "Daniel Goehring <dgo...@os...>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/9257 -- gerrit commit f095c26e0d624644aaa2ca31f518df730e1fa65c Author: Daniel Goehring <dgo...@os...> Date: Mon Jul 14 21:01:23 2025 -0600 target/arm: add nested AP DAP 'memaccess' cmd support Add nested AP support to the DAP 'memaccess' command. Change-Id: If21e7f02ccaef7267f7e8f9b954c7c8a3d0e4b52 Signed-off-by: Daniel Goehring <dgo...@os...> diff --git a/src/target/arm_adi_v5.c b/src/target/arm_adi_v5.c index 5c491ae413..995f0db1df 100644 --- a/src/target/arm_adi_v5.c +++ b/src/target/arm_adi_v5.c @@ -2776,7 +2776,11 @@ COMMAND_HANDLER(dap_memaccess_command) switch (CMD_ARGC) { case 0: - ap = dap_get_ap(dap, dap->apsel); + if (dap->apsel_gateway == DP_APSEL_INVALID) + ap = dap_get_ap(dap, dap->apsel); + else + ap = dap_get_ap_gateway(dap, dap->apsel, dap->apsel_gateway); + if (!ap) { command_print(CMD, "Cannot get AP"); return ERROR_FAIL; @@ -2784,7 +2788,11 @@ COMMAND_HANDLER(dap_memaccess_command) memaccess_tck = ap->memaccess_tck; break; case 1: - ap = dap_get_config_ap(dap, dap->apsel); + if (dap->apsel_gateway == DP_APSEL_INVALID) + ap = dap_get_config_ap(dap, dap->apsel); + else + ap = dap_get_config_ap_gateway(dap, dap->apsel, dap->apsel_gateway); + if (!ap) { command_print(CMD, "Cannot get AP"); return ERROR_FAIL; -- |
|
From: <ge...@op...> - 2025-11-21 17:20:06
|
This is an automated email from Gerrit. "Daniel Goehring <dgo...@os...>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/9255 -- gerrit commit 0178ab8d293b340f38740b0a60c1f859c4da3dad Author: Daniel Goehring <dgo...@os...> Date: Mon Jul 14 20:41:13 2025 -0600 target/arm: add nested AP DAP 'apcsw' cmd support Add nested AP support to the DAP 'apcsw' command. Change-Id: I1e4ac9807421b1a57a3b99e5839051eecac47a88 Signed-off-by: Daniel Goehring <dgo...@os...> diff --git a/src/target/arm_adi_v5.c b/src/target/arm_adi_v5.c index b99c67ee5c..adf43bd1aa 100644 --- a/src/target/arm_adi_v5.c +++ b/src/target/arm_adi_v5.c @@ -2836,13 +2836,22 @@ COMMAND_HANDLER(dap_apcsw_command) switch (CMD_ARGC) { case 0: - ap = dap_get_ap(dap, dap->apsel); + if (dap->apsel_gateway == DP_APSEL_INVALID) + ap = dap_get_ap(dap, dap->apsel); + else + ap = dap_get_ap_gateway(dap, dap->apsel, dap->apsel_gateway); + if (!ap) { command_print(CMD, "Cannot get AP"); return ERROR_FAIL; } - command_print(CMD, "AP#0x%" PRIx64 " selected, csw 0x%8.8" PRIx32, - dap->apsel, ap->csw_default); + + if (dap->apsel_gateway == DP_APSEL_INVALID) + command_print(CMD, "AP#0x%" PRIx64 " selected, csw 0x%8.8" PRIx32, + dap->apsel, ap->csw_default); + else + command_print(CMD, "AP#0x%" PRIx64 " GW#0x%" PRIx64 " selected, csw 0x%8.8" PRIx32, + dap->apsel, dap->apsel_gateway, ap->csw_default); break; case 1: if (strcmp(CMD_ARGV[0], "default") == 0) @@ -2854,7 +2863,11 @@ COMMAND_HANDLER(dap_apcsw_command) LOG_ERROR("CSW value cannot include 'Size' and 'AddrInc' bit-fields"); return ERROR_COMMAND_ARGUMENT_INVALID; } - ap = dap_get_config_ap(dap, dap->apsel); + if (dap->apsel_gateway == DP_APSEL_INVALID) + ap = dap_get_config_ap(dap, dap->apsel); + else + ap = dap_get_config_ap_gateway(dap, dap->apsel, dap->apsel_gateway); + if (!ap) { command_print(CMD, "Cannot get AP"); return ERROR_FAIL; @@ -2868,7 +2881,11 @@ COMMAND_HANDLER(dap_apcsw_command) LOG_ERROR("CSW mask cannot include 'Size' and 'AddrInc' bit-fields"); return ERROR_COMMAND_ARGUMENT_INVALID; } - ap = dap_get_config_ap(dap, dap->apsel); + if (dap->apsel_gateway == DP_APSEL_INVALID) + ap = dap_get_config_ap(dap, dap->apsel); + else + ap = dap_get_config_ap_gateway(dap, dap->apsel, dap->apsel_gateway); + if (!ap) { command_print(CMD, "Cannot get AP"); return ERROR_FAIL; -- |
|
From: <ge...@op...> - 2025-11-21 17:20:05
|
This is an automated email from Gerrit. "Daniel Goehring <dgo...@os...>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/9254 -- gerrit commit 6c6a92c6bcb4f9b8e134b417c5f4f79f180bde87 Author: Daniel Goehring <dgo...@os...> Date: Mon Jul 14 20:27:56 2025 -0600 target/arm: add nested AP DAP 'apid' cmd support Add nested AP support to the DAP 'apid' command. Change-Id: Ic51dee2636191cf6fdad6f302dedb36b94f3cea6 Signed-off-by: Daniel Goehring <dgo...@os...> diff --git a/src/target/arm_adi_v5.c b/src/target/arm_adi_v5.c index 9fdf32476f..b99c67ee5c 100644 --- a/src/target/arm_adi_v5.c +++ b/src/target/arm_adi_v5.c @@ -2888,13 +2888,16 @@ COMMAND_HANDLER(dap_apcsw_command) COMMAND_HANDLER(dap_apid_command) { struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA); + struct adiv5_ap *ap; uint64_t apsel; + uint64_t apsel_gateway = DP_APSEL_INVALID; uint32_t apid; int retval; switch (CMD_ARGC) { case 0: apsel = dap->apsel; + apsel_gateway = dap->apsel_gateway; break; case 1: COMMAND_PARSE_NUMBER(u64, CMD_ARGV[0], apsel); @@ -2903,11 +2906,27 @@ COMMAND_HANDLER(dap_apid_command) return ERROR_COMMAND_ARGUMENT_INVALID; } break; + case 2: + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[0], apsel); + if (!is_ap_num_valid(dap, apsel)) { + command_print(CMD, "Invalid AP number"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[1], apsel_gateway); + if (!is_ap_num_valid(dap, apsel_gateway)) { + command_print(CMD, "Invalid AP_GATEWAY number"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + break; default: return ERROR_COMMAND_SYNTAX_ERROR; } - struct adiv5_ap *ap = dap_get_ap(dap, apsel); + if (apsel_gateway == DP_APSEL_INVALID) + ap = dap_get_ap(dap, apsel); + else + ap = dap_get_ap_gateway(dap, apsel, apsel_gateway); + if (!ap) { command_print(CMD, "Cannot get AP"); return ERROR_FAIL; @@ -3181,7 +3200,7 @@ const struct command_registration dap_instance_commands[] = { .mode = COMMAND_EXEC, .help = "return ID register from AP " "(default currently selected AP)", - .usage = "[ap_num]", + .usage = "[ap_num [ap_num_gateway]]", }, { .name = "apreg", -- |
|
From: <ge...@op...> - 2025-11-21 17:20:05
|
This is an automated email from Gerrit. "Daniel Goehring <dgo...@os...>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/9250 -- gerrit commit 82eb9a8b9d58531689a85dfca87f2b2e2729d77b Author: Daniel Goehring <dgo...@os...> Date: Fri Jul 18 21:36:57 2025 -0600 target/arm: add nested AP lookup support Add equivalent AP lookup commands which support gateways for nested APs. Since a nested AP's address can be identical to a non-nested AP's address, these added routines use the gateway AP's address for the AP lookup. Change-Id: I5a8d25f258233f709cb5dc831f029fb6f9fb2a01 Signed-off-by: Daniel Goehring <dgo...@os...> diff --git a/src/target/arm_adi_v5.c b/src/target/arm_adi_v5.c index 2a599904c4..def4faa75a 100644 --- a/src/target/arm_adi_v5.c +++ b/src/target/arm_adi_v5.c @@ -1167,20 +1167,24 @@ static inline bool is_ap_in_use(struct adiv5_ap *ap) static struct adiv5_ap *_dap_get_ap(struct adiv5_dap *dap, uint64_t ap_num) { + struct adiv5_ap *ap; + struct adiv5_ap *ap_gateway; + if (!is_ap_num_valid(dap, ap_num)) { LOG_ERROR("Invalid AP#0x%" PRIx64, ap_num); return NULL; } if (is_adiv6(dap)) { for (unsigned int i = 0; i <= DP_APSEL_MAX; i++) { - struct adiv5_ap *ap = &dap->ap[i]; - if (is_ap_in_use(ap) && ap->ap_num == ap_num) { + ap = &dap->ap[i]; + ap_gateway = ap->ap_gateway; + if (is_ap_in_use(ap) && !ap_gateway && ap->ap_num == ap_num) { ++ap->refcount; return ap; } } for (unsigned int i = 0; i <= DP_APSEL_MAX; i++) { - struct adiv5_ap *ap = &dap->ap[i]; + ap = &dap->ap[i]; if (!is_ap_in_use(ap)) { ap->ap_gateway = NULL; ap->ap_num = ap_num; @@ -1193,13 +1197,68 @@ static struct adiv5_ap *_dap_get_ap(struct adiv5_dap *dap, uint64_t ap_num) } /* ADIv5 */ - struct adiv5_ap *ap = &dap->ap[ap_num]; + ap = &dap->ap[ap_num]; ap->ap_gateway = NULL; ap->ap_num = ap_num; ++ap->refcount; return ap; } +static struct adiv5_ap *_dap_get_ap_gateway(struct adiv5_dap *dap, uint64_t ap_num, uint64_t ap_num_gateway) +{ + struct adiv5_ap *ap; + struct adiv5_ap *ap_gateway; + + if (!is_ap_num_valid(dap, ap_num)) { + LOG_ERROR("Invalid AP#0x%" PRIx64, ap_num); + return NULL; + } + if (!is_ap_num_valid(dap, ap_num_gateway)) { + LOG_ERROR("Invalid AP_GATEWAY#0x%" PRIx64, ap_num_gateway); + return NULL; + } + + if (is_adiv6(dap)) { + for (unsigned int i = 0; i <= DP_APSEL_MAX; i++) { + ap = &dap->ap[i]; + ap_gateway = ap->ap_gateway; + if (is_ap_in_use(ap) && ap_gateway && is_ap_in_use(ap_gateway) && + ap->ap_num == ap_num && ap_gateway->ap_num == ap_num_gateway) { + ++ap->refcount; + ++ap_gateway->refcount; + return ap; + } + } + ap_gateway = dap_get_ap(dap, ap_num_gateway); + if (!ap_gateway) { + LOG_ERROR("No more AP available!"); + return NULL; + } + for (unsigned int i = 0; i <= DP_APSEL_MAX; i++) { + ap = &dap->ap[i]; + if (!is_ap_in_use(ap)) { + ap->ap_gateway = ap_gateway; + ap->ap_num = ap_num; + ++ap->refcount; + return ap; + } + } + dap_put_ap(ap_gateway); + LOG_ERROR("No more AP available!"); + return NULL; + } + + /* ADIv5 */ + ap = &dap->ap[ap_num]; + ap_gateway = &dap->ap[ap_num_gateway]; + ap->ap_gateway = ap_gateway; + ap->ap_num = ap_num; + ap_gateway->ap_num = ap_num_gateway; + ++ap->refcount; + ++ap_gateway->refcount; + return ap; +} + /* Return AP with specified ap_num. Increment AP refcount */ struct adiv5_ap *dap_get_ap(struct adiv5_dap *dap, uint64_t ap_num) { @@ -1209,6 +1268,18 @@ struct adiv5_ap *dap_get_ap(struct adiv5_dap *dap, uint64_t ap_num) return ap; } +struct adiv5_ap *dap_get_ap_gateway(struct adiv5_dap *dap, uint64_t ap_num, uint64_t ap_num_gateway) +{ + struct adiv5_ap *ap = _dap_get_ap_gateway(dap, ap_num, ap_num_gateway); + if (ap) { + LOG_DEBUG("refcount AP#0x%" PRIx64 " get %u", ap_num, ap->refcount); + if (ap->ap_gateway) + LOG_DEBUG("refcount AP_GATEWAY#0x%" PRIx64 " get %u", + ap_num_gateway, ap->ap_gateway->refcount); + } + return ap; +} + /* Return AP with specified ap_num. Increment AP refcount and keep it non-zero */ struct adiv5_ap *dap_get_config_ap(struct adiv5_dap *dap, uint64_t ap_num) { @@ -1220,9 +1291,27 @@ struct adiv5_ap *dap_get_config_ap(struct adiv5_dap *dap, uint64_t ap_num) return ap; } +/* Return AP with specified ap_num. Increment AP refcount and keep it non-zero */ +struct adiv5_ap *dap_get_config_ap_gateway(struct adiv5_dap *dap, uint64_t ap_num, uint64_t ap_num_gateway) +{ + struct adiv5_ap *ap = _dap_get_ap_gateway(dap, ap_num, ap_num_gateway); + if (ap) { + ap->config_ap_never_release = true; + LOG_DEBUG("refcount AP#0x%" PRIx64 " get_config %u", ap_num, ap->refcount); + if (ap->ap_gateway) { + ap->ap_gateway->config_ap_never_release = true; + LOG_DEBUG("refcount AP_GATEWAY#0x%" PRIx64 " get_config %u", + ap_num_gateway, ap->ap_gateway->refcount); + } + } + return ap; +} + /* Decrement AP refcount and release the AP when refcount reaches zero */ int dap_put_ap(struct adiv5_ap *ap) { + struct adiv5_ap *ap_gateway = ap->ap_gateway; + if (ap->refcount == 0) { LOG_ERROR("BUG: refcount AP#0x%" PRIx64 " put underflow", ap->ap_num); return ERROR_FAIL; @@ -1234,11 +1323,33 @@ int dap_put_ap(struct adiv5_ap *ap) if (!is_ap_in_use(ap)) { /* defaults from dap_instance_init() */ ap->ap_num = DP_APSEL_INVALID; + ap->ap_gateway = NULL; ap->memaccess_tck = 255; ap->tar_autoincr_block = (1 << 10); ap->csw_default = CSW_AHB_DEFAULT; ap->cfg_reg = MEM_AP_REG_CFG_INVALID; } + + if (ap_gateway) { + if (ap_gateway->refcount == 0) { + LOG_ERROR("BUG: refcount AP_GATEWAY#0x%" PRIx64 " put underflow", ap_gateway->ap_num); + return ERROR_FAIL; + } + + --ap_gateway->refcount; + + LOG_DEBUG("refcount AP_GATEWAY#0x%" PRIx64 " put %u", ap_gateway->ap_num, ap_gateway->refcount); + if (!is_ap_in_use(ap_gateway)) { + /* defaults from dap_instance_init() */ + ap_gateway->ap_num = DP_APSEL_INVALID; + ap_gateway->ap_gateway = NULL; + ap_gateway->memaccess_tck = 255; + ap_gateway->tar_autoincr_block = (1 << 10); + ap_gateway->csw_default = CSW_AHB_DEFAULT; + ap_gateway->cfg_reg = MEM_AP_REG_CFG_INVALID; + } + } + return ERROR_OK; } diff --git a/src/target/arm_adi_v5.h b/src/target/arm_adi_v5.h index 49bc3ff0b0..72a29faff2 100644 --- a/src/target/arm_adi_v5.h +++ b/src/target/arm_adi_v5.h @@ -750,9 +750,11 @@ int dap_find_get_ap(struct adiv5_dap *dap, /* Return AP with specified ap_num. Increment AP refcount */ struct adiv5_ap *dap_get_ap(struct adiv5_dap *dap, uint64_t ap_num); +struct adiv5_ap *dap_get_ap_gateway(struct adiv5_dap *dap, uint64_t ap_num, uint64_t ap_num_gateway); /* Return AP with specified ap_num. Increment AP refcount and keep it non-zero */ struct adiv5_ap *dap_get_config_ap(struct adiv5_dap *dap, uint64_t ap_num); +struct adiv5_ap *dap_get_config_ap_gateway(struct adiv5_dap *dap, uint64_t ap_num, uint64_t ap_num_gateway); /* Decrement AP refcount and release the AP when refcount reaches zero */ int dap_put_ap(struct adiv5_ap *ap); -- |
|
From: <ge...@op...> - 2025-11-21 17:20:05
|
This is an automated email from Gerrit. "Daniel Goehring <dgo...@os...>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/9252 -- gerrit commit 67ab3419ae8737197e61f1d60b21b996101aec45 Author: Daniel Goehring <dgo...@os...> Date: Mon Jul 14 19:35:48 2025 -0600 target/arm: add nested AP DAP base support For the DAP structure, add nested AP base support. This framework provides nested AP base support for the DAP info, baseaddr, memaccess, apsel, apcsw, apid, and apreg commands. Change-Id: I96fb8487b7fa87ef79cef2f4064680ace70c47e0 Signed-off-by: Daniel Goehring <dgo...@os...> diff --git a/src/target/arm_adi_v5.h b/src/target/arm_adi_v5.h index 27fa5a2784..bbf38c90b0 100644 --- a/src/target/arm_adi_v5.h +++ b/src/target/arm_adi_v5.h @@ -370,6 +370,7 @@ struct adiv5_dap { /* The current manually selected AP by the "dap apsel" command */ uint64_t apsel; + uint64_t apsel_gateway; /** Cache for DP SELECT and SELECT1 (ADIv6) register. */ uint64_t select; diff --git a/src/target/arm_dap.c b/src/target/arm_dap.c index 55f2c99150..91d8c9066b 100644 --- a/src/target/arm_dap.c +++ b/src/target/arm_dap.c @@ -435,7 +435,9 @@ COMMAND_HANDLER(handle_dap_info_command) struct target *target = get_current_target(CMD_CTX); struct arm *arm = target_to_arm(target); struct adiv5_dap *dap = arm->dap; + struct adiv5_ap *ap; uint64_t apsel; + uint64_t apsel_gateway = DP_APSEL_INVALID; if (!dap) { LOG_ERROR("DAP instance not available. Probably a HLA target..."); @@ -445,6 +447,7 @@ COMMAND_HANDLER(handle_dap_info_command) switch (CMD_ARGC) { case 0: apsel = dap->apsel; + apsel_gateway = dap->apsel_gateway; break; case 1: if (!strcmp(CMD_ARGV[0], "root")) { @@ -463,11 +466,23 @@ COMMAND_HANDLER(handle_dap_info_command) if (!is_ap_num_valid(dap, apsel)) return ERROR_COMMAND_SYNTAX_ERROR; break; + case 2: + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[0], apsel); + if (!is_ap_num_valid(dap, apsel)) + return ERROR_COMMAND_SYNTAX_ERROR; + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[1], apsel_gateway); + if (!is_ap_num_valid(dap, apsel_gateway)) + return ERROR_COMMAND_SYNTAX_ERROR; + break; default: return ERROR_COMMAND_SYNTAX_ERROR; } - struct adiv5_ap *ap = dap_get_ap(dap, apsel); + if (apsel_gateway == DP_APSEL_INVALID) + ap = dap_get_ap(dap, apsel); + else + ap = dap_get_ap_gateway(dap, apsel, apsel_gateway); + if (!ap) { command_print(CMD, "Cannot get AP"); return ERROR_FAIL; @@ -505,7 +520,7 @@ static const struct command_registration dap_subcommand_handlers[] = { .mode = COMMAND_EXEC, .help = "display ROM table for specified MEM-AP (default MEM-AP of current target) " "or the ADIv6 root ROM table of current target's DAP", - .usage = "[ap_num | 'root']", + .usage = "[ap_num [ap_num_gateway] | 'root']", }, COMMAND_REGISTRATION_DONE }; -- |
|
From: <ge...@op...> - 2025-11-21 17:20:00
|
This is an automated email from Gerrit. "Daniel Goehring <dgo...@os...>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/9251 -- gerrit commit ab6d45e8e6b4b7d135d0eee59fa67f2afb8094a1 Author: Daniel Goehring <dgo...@os...> Date: Mon Jul 14 16:04:32 2025 -0600 target/arm: add nested AP config file option support Add configuration file target support for a nested AP parameter. For systems with nested access ports, this additional target creation parameter specifies the top-level access port which connects to a secondary access port in a configuration file. Change-Id: Ib1f1270dbfc01a071092573c47a9373997a721fc Signed-off-by: Daniel Goehring <dgo...@os...> diff --git a/src/target/arm_adi_v5.c b/src/target/arm_adi_v5.c index def4faa75a..77e3202927 100644 --- a/src/target/arm_adi_v5.c +++ b/src/target/arm_adi_v5.c @@ -2447,6 +2447,7 @@ int dap_lookup_cs_component(struct adiv5_ap *ap, uint8_t type, enum adiv5_cfg_param { CFG_DAP, CFG_AP_NUM, + CFG_AP_NUM_GATEWAY, CFG_BASEADDR, CFG_CTIBASE, /* DEPRECATED */ }; @@ -2454,15 +2455,16 @@ enum adiv5_cfg_param { static const struct jim_nvp nvp_config_opts[] = { { .name = "-dap", .value = CFG_DAP }, { .name = "-ap-num", .value = CFG_AP_NUM }, + { .name = "-ap-num-gateway", .value = CFG_AP_NUM_GATEWAY }, { .name = "-baseaddr", .value = CFG_BASEADDR }, { .name = "-ctibase", .value = CFG_CTIBASE }, /* DEPRECATED */ { .name = NULL, .value = -1 } }; static int adiv5_jim_spot_configure(struct jim_getopt_info *goi, - struct adiv5_dap **dap_p, uint64_t *ap_num_p, uint32_t *base_p) + struct adiv5_dap **dap_p, uint64_t *ap_num_p, uint64_t *ap_num_gateway_p, uint32_t *base_p) { - assert(dap_p && ap_num_p); + assert(dap_p && ap_num_p && ap_num_gateway_p); if (!goi->argc) return JIM_OK; @@ -2539,6 +2541,30 @@ static int adiv5_jim_spot_configure(struct jim_getopt_info *goi, } break; + case CFG_AP_NUM_GATEWAY: + if (goi->is_configure) { + /* jim_wide is a signed 64 bits int, ap_num_gateway is unsigned with max 52 bits */ + jim_wide ap_num_gateway; + e = jim_getopt_wide(goi, &ap_num_gateway); + if (e != JIM_OK) + return e; + /* we still don't know dap->adi_version */ + if (ap_num_gateway < 0 || (ap_num_gateway > DP_APSEL_MAX && (ap_num_gateway & 0xfff))) { + Jim_SetResultString(goi->interp, "Invalid AP_GATEWAY number!", -1); + return JIM_ERR; + } + *ap_num_gateway_p = ap_num_gateway; + } else { + if (goi->argc) + goto err_no_param; + if (*ap_num_gateway_p == DP_APSEL_INVALID) { + Jim_SetResultString(goi->interp, "AP_GATEWAY number not configured", -1); + return JIM_ERR; + } + Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, *ap_num_gateway_p)); + } + break; + case CFG_CTIBASE: LOG_WARNING("DEPRECATED! use \'-baseaddr' not \'-ctibase\'"); /* fall through */ @@ -2578,6 +2604,7 @@ int adiv5_jim_configure_ext(struct target *target, struct jim_getopt_info *goi, return JIM_ERR; } pc->ap_num = DP_APSEL_INVALID; + pc->ap_num_gateway = DP_APSEL_INVALID; target->private_config = pc; } } @@ -2585,7 +2612,7 @@ int adiv5_jim_configure_ext(struct target *target, struct jim_getopt_info *goi, if (optional == ADI_CONFIGURE_DAP_COMPULSORY) target->has_dap = true; - e = adiv5_jim_spot_configure(goi, &pc->dap, &pc->ap_num, NULL); + e = adiv5_jim_spot_configure(goi, &pc->dap, &pc->ap_num, &pc->ap_num_gateway, NULL); if (e != JIM_OK) return e; @@ -2623,13 +2650,14 @@ int adiv5_verify_config(struct adiv5_private_config *pc) int adiv5_jim_mem_ap_spot_configure(struct adiv5_mem_ap_spot *cfg, struct jim_getopt_info *goi) { - return adiv5_jim_spot_configure(goi, &cfg->dap, &cfg->ap_num, &cfg->base); + return adiv5_jim_spot_configure(goi, &cfg->dap, &cfg->ap_num, &cfg->ap_num_gateway, &cfg->base); } int adiv5_mem_ap_spot_init(struct adiv5_mem_ap_spot *p) { p->dap = NULL; p->ap_num = DP_APSEL_INVALID; + p->ap_num_gateway = DP_APSEL_INVALID; p->base = 0; return ERROR_OK; } diff --git a/src/target/arm_adi_v5.h b/src/target/arm_adi_v5.h index 72a29faff2..27fa5a2784 100644 --- a/src/target/arm_adi_v5.h +++ b/src/target/arm_adi_v5.h @@ -791,6 +791,7 @@ extern int dap_cleanup_all(void); struct adiv5_private_config { uint64_t ap_num; + uint64_t ap_num_gateway; struct adiv5_dap *dap; }; @@ -809,6 +810,7 @@ extern int adiv5_jim_configure(struct target *target, struct jim_getopt_info *go struct adiv5_mem_ap_spot { struct adiv5_dap *dap; uint64_t ap_num; + uint64_t ap_num_gateway; uint32_t base; }; -- |
|
From: <ge...@op...> - 2025-11-21 17:19:59
|
This is an automated email from Gerrit. "Daniel Goehring <dgo...@os...>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/9249 -- gerrit commit 91440118e3ca25699814eaf1cc0655bac0eaf6d6 Author: Daniel Goehring <dgo...@os...> Date: Tue Aug 5 10:10:23 2025 -0600 target/arm: add nested AP low level ADI support Update the debug log message for the mem_ap_setup_transfer_verify_size_packing() procedure to support nested APs. Change-Id: I18d01e9c70614131e344e6403f01e07bcb971542 Signed-off-by: Daniel Goehring <dgo...@os...> diff --git a/src/target/arm_adi_v5.c b/src/target/arm_adi_v5.c index a87933fe0f..2a599904c4 100644 --- a/src/target/arm_adi_v5.c +++ b/src/target/arm_adi_v5.c @@ -405,8 +405,13 @@ static int mem_ap_setup_transfer_verify_size_packing(struct adiv5_ap *ap, return retval; bool size_supported = ((csw_readback & CSW_SIZE_MASK) == csw_size); - LOG_DEBUG("AP#0x%" PRIx64 " probed size %u: %s", ap->ap_num, size, - size_supported ? "supported" : "not supported"); + if (!ap->ap_gateway) + LOG_DEBUG("AP#0x%" PRIx64 " probed size %u: %s", ap->ap_num, size, + size_supported ? "supported" : "not supported"); + else + LOG_DEBUG("AP#0x%" PRIx64 " GW#0x%" PRIx64 " probed size %u: %s", + ap->ap_num, ap->ap_gateway->ap_num, size, + size_supported ? "supported" : "not supported"); ap->csw_size_probed_mask |= size; if (size_supported) { ap->csw_size_supported_mask |= size; -- |
|
From: <ge...@op...> - 2025-11-21 17:19:58
|
This is an automated email from Gerrit. "Daniel Goehring <dgo...@os...>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/9248 -- gerrit commit fdaede4c76ef9c6465825b9d7551b45428d46d1a Author: Daniel Goehring <dgo...@os...> Date: Fri Jul 18 21:08:45 2025 -0600 target/arm: add nested AP low level JTAG support Add nested Access-Port support to the low level JTAG procedures jtag_ap_q_read() jtag_ap_q_write() When calling these two procedures, if the access port is nested, generate transactions on the first MEM-AP port to access the TAR, CSW, and DRW registers of the downstream AHB-AP port. The updated JTAG read/write queue routines provide the framework for future nested AP support modifications. Change-Id: Id972131378d03db691c3b074cc014413068435a4 Signed-off-by: Daniel Goehring <dgo...@os...> diff --git a/src/target/adi_v5_jtag.c b/src/target/adi_v5_jtag.c index c9ed5b948b..3d52cd55cf 100644 --- a/src/target/adi_v5_jtag.c +++ b/src/target/adi_v5_jtag.c @@ -818,9 +818,14 @@ static int jtag_ap_q_bankselect(struct adiv5_ap *ap, unsigned int reg) return ERROR_OK; } +static int jtag_ap_q_write(struct adiv5_ap *ap, unsigned int reg, + uint32_t data); + static int jtag_ap_q_read(struct adiv5_ap *ap, unsigned int reg, uint32_t *data) { + struct adiv5_ap *ap_gateway = ap->ap_gateway; + int retval = jtag_limit_queue_size(ap->dap); if (retval != ERROR_OK) return retval; @@ -829,13 +834,41 @@ static int jtag_ap_q_read(struct adiv5_ap *ap, unsigned int reg, if (retval != ERROR_OK) return retval; - retval = jtag_ap_q_bankselect(ap, reg); - if (retval != ERROR_OK) - return retval; + if (ap_gateway) { + uint32_t csw = CSW_32BIT | CSW_ADDRINC_OFF | ap_gateway->csw_default; + uint32_t tar = ap->ap_num | reg; + + if (csw != ap_gateway->csw_value) { + retval = jtag_ap_q_write(ap_gateway, MEM_AP_REG_CSW(ap_gateway->dap), csw); + if (retval != ERROR_OK) { + ap_gateway->csw_value = 0; + return retval; + } + ap_gateway->csw_value = csw; + } + + if (!ap_gateway->tar_valid || tar != ap_gateway->tar_value) { + retval = jtag_ap_q_write(ap_gateway, MEM_AP_REG_TAR(ap_gateway->dap), tar); + if (retval != ERROR_OK) { + ap_gateway->tar_valid = false; + return retval; + } + ap_gateway->tar_value = tar; + ap_gateway->tar_valid = true; + } - retval = adi_jtag_dp_scan_u32(ap->dap, JTAG_DP_APACC, reg, - DPAP_READ, 0, ap->dap->last_read, ap->memaccess_tck, NULL); - ap->dap->last_read = data; + retval = jtag_ap_q_read(ap_gateway, MEM_AP_REG_DRW(ap_gateway->dap), data); + if (retval != ERROR_OK) + return retval; + } else { + retval = jtag_ap_q_bankselect(ap, reg); + if (retval != ERROR_OK) + return retval; + + retval = adi_jtag_dp_scan_u32(ap->dap, JTAG_DP_APACC, reg, + DPAP_READ, 0, ap->dap->last_read, ap->memaccess_tck, NULL); + ap->dap->last_read = data; + } return retval; } @@ -843,6 +876,8 @@ static int jtag_ap_q_read(struct adiv5_ap *ap, unsigned int reg, static int jtag_ap_q_write(struct adiv5_ap *ap, unsigned int reg, uint32_t data) { + struct adiv5_ap *ap_gateway = ap->ap_gateway; + int retval = jtag_limit_queue_size(ap->dap); if (retval != ERROR_OK) return retval; @@ -851,13 +886,42 @@ static int jtag_ap_q_write(struct adiv5_ap *ap, unsigned int reg, if (retval != ERROR_OK) return retval; - retval = jtag_ap_q_bankselect(ap, reg); - if (retval != ERROR_OK) - return retval; + if (ap_gateway) { + uint32_t csw = CSW_32BIT | CSW_ADDRINC_OFF | ap_gateway->csw_default; + uint32_t tar = ap->ap_num | reg; + + if (csw != ap_gateway->csw_value) { + retval = jtag_ap_q_write(ap_gateway, MEM_AP_REG_CSW(ap_gateway->dap), csw); + if (retval != ERROR_OK) { + ap_gateway->csw_value = 0; + return retval; + } + ap_gateway->csw_value = csw; + } + + if (!ap_gateway->tar_valid || tar != ap_gateway->tar_value) { + retval = jtag_ap_q_write(ap_gateway, MEM_AP_REG_TAR(ap_gateway->dap), tar); + if (retval != ERROR_OK) { + ap_gateway->tar_valid = false; + return retval; + } + ap_gateway->tar_value = tar; + ap_gateway->tar_valid = true; + } + + retval = jtag_ap_q_write(ap_gateway, MEM_AP_REG_DRW(ap_gateway->dap), data); + if (retval != ERROR_OK) + return retval; + } else { + retval = jtag_ap_q_bankselect(ap, reg); + if (retval != ERROR_OK) + return retval; + + retval = adi_jtag_dp_scan_u32(ap->dap, JTAG_DP_APACC, reg, + DPAP_WRITE, data, ap->dap->last_read, ap->memaccess_tck, NULL); + ap->dap->last_read = NULL; + } - retval = adi_jtag_dp_scan_u32(ap->dap, JTAG_DP_APACC, reg, - DPAP_WRITE, data, ap->dap->last_read, ap->memaccess_tck, NULL); - ap->dap->last_read = NULL; return retval; } diff --git a/src/target/arm_adi_v5.c b/src/target/arm_adi_v5.c index 67a3fcc577..a87933fe0f 100644 --- a/src/target/arm_adi_v5.c +++ b/src/target/arm_adi_v5.c @@ -1177,6 +1177,7 @@ static struct adiv5_ap *_dap_get_ap(struct adiv5_dap *dap, uint64_t ap_num) for (unsigned int i = 0; i <= DP_APSEL_MAX; i++) { struct adiv5_ap *ap = &dap->ap[i]; if (!is_ap_in_use(ap)) { + ap->ap_gateway = NULL; ap->ap_num = ap_num; ++ap->refcount; return ap; @@ -1188,6 +1189,7 @@ static struct adiv5_ap *_dap_get_ap(struct adiv5_dap *dap, uint64_t ap_num) /* ADIv5 */ struct adiv5_ap *ap = &dap->ap[ap_num]; + ap->ap_gateway = NULL; ap->ap_num = ap_num; ++ap->refcount; return ap; diff --git a/src/target/arm_adi_v5.h b/src/target/arm_adi_v5.h index ebd2752bd8..49bc3ff0b0 100644 --- a/src/target/arm_adi_v5.h +++ b/src/target/arm_adi_v5.h @@ -260,6 +260,11 @@ struct adiv5_ap { */ uint64_t ap_num; + /** + * Gateway AP + */ + struct adiv5_ap *ap_gateway; + /** * Default value for (MEM-AP) AP_REG_CSW register. */ diff --git a/src/target/arm_dap.c b/src/target/arm_dap.c index 5ba5e1c387..55f2c99150 100644 --- a/src/target/arm_dap.c +++ b/src/target/arm_dap.c @@ -37,6 +37,7 @@ static void dap_instance_init(struct adiv5_dap *dap) for (i = 0; i <= DP_APSEL_MAX; i++) { dap->ap[i].dap = dap; dap->ap[i].ap_num = DP_APSEL_INVALID; + dap->ap[i].ap_gateway = NULL; /* memaccess_tck max is 255 */ dap->ap[i].memaccess_tck = 255; /* Number of bits for tar autoincrement, impl. dep. at least 10 */ -- |
|
From: <ge...@op...> - 2025-11-21 12:40:55
|
This is an automated email from Gerrit. "Tomas Vanek <va...@fb...>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/9246 -- gerrit commit 591687564c0c466cee1c900748aa8abe335e930b Author: Tomas Vanek <va...@fb...> Date: Fri Nov 21 12:21:16 2025 +0100 target/aarch64: fix semihosting on SMP Semihosting worked only on the first/gdb assigned core of a SMP group. If a semihosting call was issued on another core, aarch64_update_halt_gdb() emitted 'halted' event on core0 before semihosting decoding started. Use target's smp_halt_event_postponed flag to keep events from emitting until semihosting is decoded. If a semihosting call is confirmed, clear flags and do not send 'halted' event for any core of SMP group. Change-Id: Ie7eff7e493c2a4df3039f49fce1744d996050a59 Signed-off-by: Tomas Vanek <va...@fb...> diff --git a/src/target/aarch64.c b/src/target/aarch64.c index 4910714ba9..74df97c274 100644 --- a/src/target/aarch64.c +++ b/src/target/aarch64.c @@ -39,7 +39,8 @@ struct aarch64_private_config { struct arm_cti *cti; }; -static int aarch64_poll_smp(struct target *target, bool smp); +static int aarch64_poll_smp(struct target *target, bool smp, + bool postpone_event); static int aarch64_debug_entry(struct target *target); static int aarch64_restore_context(struct target *target, bool bpwp); static int aarch64_set_breakpoint(struct target *target, @@ -471,7 +472,6 @@ static int aarch64_halt_smp(struct target *target, bool exc_target) static int aarch64_update_halt_gdb(struct target *target, enum target_debug_reason debug_reason) { - struct target *gdb_target = NULL; struct target_list *head; struct target *curr; @@ -480,7 +480,7 @@ static int aarch64_update_halt_gdb(struct target *target, enum target_debug_reas aarch64_halt_smp(target, true); } - /* poll all targets in the group, but skip the target that serves GDB */ + /* poll all targets in the group */ foreach_smp_target(head, target->smp_targets) { curr = head->target; /* skip calling context */ @@ -491,31 +491,43 @@ static int aarch64_update_halt_gdb(struct target *target, enum target_debug_reas /* skip targets that were already halted */ if (curr->state == TARGET_HALTED) continue; - /* remember the gdb_service->target */ - if (curr->gdb_service) - gdb_target = curr->gdb_service->target; - /* skip it */ - if (curr == gdb_target) - continue; const bool smp = false; - aarch64_poll_smp(curr, smp); - } - - /* after all targets were updated, poll the gdb serving target */ - if (gdb_target && gdb_target != target) { - const bool smp = false; - aarch64_poll_smp(gdb_target, smp); + const bool postpone_event = true; + aarch64_poll_smp(curr, smp, postpone_event); } return ERROR_OK; } +enum postponed_halt_events_op { + POSTPONED_HALT_EVENT_CLEAR, + POSTPONED_HALT_EVENT_EMIT +}; + +static void aarch64_smp_postponed_halt_events(struct list_head *smp_targets, + enum postponed_halt_events_op op) +{ + struct target_list *head; + foreach_smp_target(head, smp_targets) { + struct target *t = head->target; + if (!t->smp_halt_event_postponed) + continue; + + if (op == POSTPONED_HALT_EVENT_EMIT) { + LOG_TARGET_DEBUG(t, "sending postponed target event 'halted'"); + target_call_event_callbacks(t, TARGET_EVENT_HALTED); + } + t->smp_halt_event_postponed = false; + } +} + /* * Aarch64 Run control */ -static int aarch64_poll_smp(struct target *target, bool smp) +static int aarch64_poll_smp(struct target *target, bool smp, + bool postpone_event) { struct armv8_common *armv8 = target_to_armv8(target); enum target_state prev_target_state; @@ -553,14 +565,22 @@ static int aarch64_poll_smp(struct target *target, bool smp) if (smp) aarch64_update_halt_gdb(target, debug_reason); - if (arm_semihosting(target, &retval) != 0) + if (arm_semihosting(target, &retval) != 0) { + if (smp) + aarch64_smp_postponed_halt_events(target->smp_targets, + POSTPONED_HALT_EVENT_CLEAR); + return retval; + } switch (prev_target_state) { case TARGET_RUNNING: case TARGET_UNKNOWN: case TARGET_RESET: - target_call_event_callbacks(target, TARGET_EVENT_HALTED); + if (postpone_event) + target->smp_halt_event_postponed = true; + else + target_call_event_callbacks(target, TARGET_EVENT_HALTED); break; case TARGET_DEBUG_RUNNING: target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED); @@ -568,6 +588,10 @@ static int aarch64_poll_smp(struct target *target, bool smp) default: break; } + + if (smp) + aarch64_smp_postponed_halt_events(target->smp_targets, + POSTPONED_HALT_EVENT_EMIT); } } else if (prsr & PRSR_RESET) { target->state = TARGET_RESET; @@ -580,7 +604,8 @@ static int aarch64_poll_smp(struct target *target, bool smp) static int aarch64_poll(struct target *target) { - return aarch64_poll_smp(target, target->smp != 0); + const bool postpone_event = false; + return aarch64_poll_smp(target, target->smp != 0, postpone_event); } static int aarch64_halt(struct target *target) @@ -866,7 +891,7 @@ static int aarch64_step_restart_smp(struct target *target) retval = aarch64_do_restart_one(curr, RESTART_LAZY); if (retval != ERROR_OK) break; -} + } return retval; } -- |
|
From: <ge...@op...> - 2025-11-21 12:40:55
|
This is an automated email from Gerrit. "Tomas Vanek <va...@fb...>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/9245 -- gerrit commit e4f776372e637c1dbb70344b9fa53b393c16f729 Author: Tomas Vanek <va...@fb...> Date: Fri Nov 21 12:01:34 2025 +0100 target/aarch64: improve handling recursion in SMP halt update_halt_gdb() called aarch64_poll() recursively with temporary switching target's smp flag off to prevent deeper recursion. This was not possible for gdb assigned target or hwthread failed with "SMP node change, disconnect GDB from core/thread". Therefore the aarch64_poll(gdb_target) resulted in the useless recursion back to update_halt_gdb(). Introduce aarch64_poll_smp() with smp parameter to avoid update_halt_gdb() recursion properly and without fiddling with target's smp flags. While on it, add 'aarch64_' prefix to update_halt_gdb() function. Change-Id: I645166f50c106f4a6d4d35dc70ad49041d2442aa Signed-off-by: Tomas Vanek <va...@fb...> diff --git a/src/target/aarch64.c b/src/target/aarch64.c index ed9cb48aa7..4910714ba9 100644 --- a/src/target/aarch64.c +++ b/src/target/aarch64.c @@ -39,7 +39,7 @@ struct aarch64_private_config { struct arm_cti *cti; }; -static int aarch64_poll(struct target *target); +static int aarch64_poll_smp(struct target *target, bool smp); static int aarch64_debug_entry(struct target *target); static int aarch64_restore_context(struct target *target, bool bpwp); static int aarch64_set_breakpoint(struct target *target, @@ -469,7 +469,7 @@ static int aarch64_halt_smp(struct target *target, bool exc_target) return retval; } -static int update_halt_gdb(struct target *target, enum target_debug_reason debug_reason) +static int aarch64_update_halt_gdb(struct target *target, enum target_debug_reason debug_reason) { struct target *gdb_target = NULL; struct target_list *head; @@ -498,15 +498,15 @@ static int update_halt_gdb(struct target *target, enum target_debug_reason debug if (curr == gdb_target) continue; - /* avoid recursion in aarch64_poll() */ - curr->smp = 0; - aarch64_poll(curr); - curr->smp = 1; + const bool smp = false; + aarch64_poll_smp(curr, smp); } /* after all targets were updated, poll the gdb serving target */ - if (gdb_target && gdb_target != target) - aarch64_poll(gdb_target); + if (gdb_target && gdb_target != target) { + const bool smp = false; + aarch64_poll_smp(gdb_target, smp); + } return ERROR_OK; } @@ -515,7 +515,7 @@ static int update_halt_gdb(struct target *target, enum target_debug_reason debug * Aarch64 Run control */ -static int aarch64_poll(struct target *target) +static int aarch64_poll_smp(struct target *target, bool smp) { struct armv8_common *armv8 = target_to_armv8(target); enum target_state prev_target_state; @@ -550,8 +550,8 @@ static int aarch64_poll(struct target *target) if (retval != ERROR_OK) return retval; - if (target->smp) - update_halt_gdb(target, debug_reason); + if (smp) + aarch64_update_halt_gdb(target, debug_reason); if (arm_semihosting(target, &retval) != 0) return retval; @@ -578,6 +578,11 @@ static int aarch64_poll(struct target *target) return retval; } +static int aarch64_poll(struct target *target) +{ + return aarch64_poll_smp(target, target->smp != 0); +} + static int aarch64_halt(struct target *target) { struct armv8_common *armv8 = target_to_armv8(target); -- |
|
From: <ge...@op...> - 2025-11-21 12:40:41
|
This is an automated email from Gerrit. "Tomas Vanek <va...@fb...>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/9247 -- gerrit commit b99899b0b4526dc7038419fe37ccaea48b91cf82 Author: Tomas Vanek <va...@fb...> Date: Fri Nov 21 12:39:56 2025 +0100 target/aarch64: fix last_run_control_op on SMP aarch64_resume() set the last_run_control_op on the current core only and left last_run_control_op as is on the rest of the SMP group. It caused semihosting call on other cores to stop because last_run_control_op sticked on ARMV8_RUNCONTROL_STEP Set last_run_control_op to ARMV8_RUNCONTROL_RESUME on all cores in the SMP group. Change-Id: I55a97bb1f7ea25bfc5937c3cc846532cdf390064 Signed-off-by: Tomas Vanek <va...@fb...> diff --git a/src/target/aarch64.c b/src/target/aarch64.c index 74df97c274..5c88d732ff 100644 --- a/src/target/aarch64.c +++ b/src/target/aarch64.c @@ -955,6 +955,8 @@ static int aarch64_resume(struct target *target, bool current, } if (curr->state != TARGET_RUNNING) { + struct armv8_common *curr_armv8 = target_to_armv8(curr); + curr_armv8->last_run_control_op = ARMV8_RUNCONTROL_RESUME; curr->state = TARGET_RUNNING; curr->debug_reason = DBG_REASON_NOTHALTED; target_call_event_callbacks(curr, TARGET_EVENT_RESUMED); -- |
|
From: <ge...@op...> - 2025-11-21 11:52:09
|
This is an automated email from Gerrit. "Tomas Vanek <va...@fb...>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/9244 -- gerrit commit d01abd49848698d0fca3b6e75a69df889f47ad3c Author: Tomas Vanek <va...@fb...> Date: Fri Nov 21 09:27:20 2025 +0100 target/cortex_a: emit 'resumed' event for all SMP cores In a SMP configuration 'resumed' event was emitted only for the active core, in contradiction to 'halted' event, which gets emitted for all cores from the SMP group: > resume target event 3 (resume-start) for core stm32mp15x.cpu0 target event 2 (resumed) for core stm32mp15x.cpu0 target event 4 (resume-end) for core stm32mp15x.cpu0 target event 7 (gdb-start) for core stm32mp15x.cpu0 > halt target event 0 (gdb-halt) for core stm32mp15x.cpu1 target event 1 (halted) for core stm32mp15x.cpu1 target event 0 (gdb-halt) for core stm32mp15x.cpu0 target event 1 (halted) for core stm32mp15x.cpu0 target event 8 (gdb-end) for core stm32mp15x.cpu0 Emit 'resumed' event in cortex_a_restore_smp(). While on it replace adding the returned errors together with the proper error handling. Change-Id: I9debef0884519cde767707f78f163b136ecc7aa5 Signed-off-by: Tomas Vanek <va...@fb...> diff --git a/src/target/cortex_a.c b/src/target/cortex_a.c index a9c034b55d..3d8603a4ba 100644 --- a/src/target/cortex_a.c +++ b/src/target/cortex_a.c @@ -968,7 +968,7 @@ static int cortex_a_internal_restart(struct target *target) static int cortex_a_restore_smp(struct target *target, bool handle_breakpoints) { - int retval = 0; + int retval = ERROR_OK; struct target_list *head; target_addr_t address; @@ -977,9 +977,17 @@ static int cortex_a_restore_smp(struct target *target, bool handle_breakpoints) if ((curr != target) && (curr->state != TARGET_RUNNING) && target_was_examined(curr)) { /* resume current address , not in step mode */ - retval += cortex_a_internal_restore(curr, true, &address, + int retval2 = cortex_a_internal_restore(curr, true, &address, handle_breakpoints, false); - retval += cortex_a_internal_restart(curr); + + if (retval2 == ERROR_OK) + retval2 = cortex_a_internal_restart(curr); + + if (retval2 == ERROR_OK) + target_call_event_callbacks(curr, TARGET_EVENT_RESUMED); + + if (retval == ERROR_OK) + retval = retval2; // save the first error } } return retval; -- |
|
From: <ge...@op...> - 2025-11-20 04:22:43
|
This is an automated email from Gerrit. "liangzhen <zhe...@sp...>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/9224 -- gerrit commit 59a4e60b86d912821b390c424a6b4ee349b9629b Author: liangzhen <zhe...@sp...> Date: Mon Mar 31 15:18:52 2025 +0800 target/riscv: Introduce `riscv set_group` command Add support for associating a halt/resume group with current target or an external trigger via a newly exposed configuration option "riscv set_group". Change-Id: I343dbbfa5c6c1043cf6a939b4d6352adaee3703c Signed-off-by: liangzhen <zhe...@sp...> diff --git a/doc/openocd.texi b/doc/openocd.texi index 63d07533e6..531c00d752 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -11874,6 +11874,22 @@ The second argument configures how OpenOCD should use the selected trigger featu With no parameters, prints current trigger features configuration. @end deffn +@deffn {Command} {riscv set_group} <@option{halt_group}|@option{resume_group}> group ['trigger' triggernum] +OpenOCD assigns a hart or a given external trigger into a RISC-V halt/resume group. +This command associates current target or supplied external trigger(s) with this halt/resume group. + +@option{trigger} and @var{triggernum} Specify the index of the external trigger. +When an external input trigger fires, the harts in the halt/resume group will get halted/resume. +Similarly, all external output triggers will be notified when a hart in the halt/resume group halts/resumes. + +The only supported value of @var{grouptype} is @option{halt_group}. RISC-V resume groups +are not allowed because the concept of a target resuming due to a different reason than +user's resume request is not supported by OpenOCD and GDB. Allowing @var{grouptype} to +be set to @option{resume_group} might be useful for hardware testing, but OpenOCD will +report a warning. +@end deffn + + @subsection RISC-V Authentication Commands The following commands can be used to authenticate to a RISC-V system. Eg. a diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 6fa5e025be..3d6a404de8 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -68,12 +68,8 @@ static int riscv013_access_memory(struct target *target, const struct riscv_mem_ static bool riscv013_get_impebreak(const struct target *target); static unsigned int riscv013_get_progbufsize(const struct target *target); -enum grouptype { - HALT_GROUP, - RESUME_GROUP -}; static int set_group(struct target *target, bool *supported, unsigned int group, - enum grouptype grouptype); + enum grouptype grouptype, bool is_trigger, unsigned int trigger_num); /** * Since almost everything can be accomplish by scanning the dbus register, all @@ -138,6 +134,8 @@ typedef struct { * abstractcs.busy may have remained set. In that case we may need to * re-check the busy state before executing these operations. */ bool abstract_cmd_maybe_busy; + + struct riscv_ext_trigger external_triggers[RISCV_MAX_EXTTRIGGERS]; } dm013_info_t; typedef struct { @@ -1739,7 +1737,7 @@ static int halt_set_dcsr_ebreak(struct target *target) if (info->haltgroup_supported) { bool supported; - if (set_group(target, &supported, 0, HALT_GROUP) != ERROR_OK) + if (set_group(target, &supported, 0, HALT_GROUP, false, 0) != ERROR_OK) return ERROR_FAIL; if (!supported) LOG_TARGET_ERROR(target, "Couldn't place hart in halt group 0. " @@ -1761,7 +1759,7 @@ static int halt_set_dcsr_ebreak(struct target *target) /* Add it back to the halt group. */ if (info->haltgroup_supported) { bool supported; - if (set_group(target, &supported, target->smp, HALT_GROUP) != ERROR_OK) + if (set_group(target, &supported, target->smp, HALT_GROUP, false, 0) != ERROR_OK) return ERROR_FAIL; if (!supported) LOG_TARGET_ERROR(target, "Couldn't place hart back in halt group %d. " @@ -1792,19 +1790,54 @@ static void deinit_target(struct target *target) } static int set_group(struct target *target, bool *supported, unsigned int group, - enum grouptype grouptype) + enum grouptype grouptype, bool is_trigger, unsigned int trigger_num) { - uint32_t write_val = DM_DMCS2_HGWRITE; assert(group <= 31); + assert(trigger_num < 16); + + if (!is_trigger && dm013_select_target(target) != ERROR_OK) + return ERROR_FAIL; + + dm013_info_t *dm = get_dm(target); + if (!dm) + return ERROR_FAIL; + if (is_trigger && ((dm->external_triggers[trigger_num].haltgroup_was_set && + dm->external_triggers[trigger_num].haltgroup_num == group) || + (dm->external_triggers[trigger_num].resumegroup_was_set && + dm->external_triggers[trigger_num].resumegroup_num == group))) { + LOG_TARGET_WARNING(target, "External trigger %d (at address dbgbase=0x%" PRIx32 ") " + "for %s group %d has been set.", trigger_num, dm->base, + (grouptype == HALT_GROUP) ? "halt" : "resume", group); + return ERROR_OK; + } + + uint32_t write_val = DM_DMCS2_HGWRITE; write_val = set_field(write_val, DM_DMCS2_GROUP, group); write_val = set_field(write_val, DM_DMCS2_GROUPTYPE, (grouptype == HALT_GROUP) ? 0 : 1); + write_val = set_field(write_val, DM_DMCS2_DMEXTTRIGGER, trigger_num); + write_val = set_field(write_val, DM_DMCS2_HGSELECT, + is_trigger ? DM_DMCS2_HGSELECT_TRIGGERS : DM_DMCS2_HGSELECT_HARTS); if (dm_write(target, DM_DMCS2, write_val) != ERROR_OK) return ERROR_FAIL; uint32_t read_val; if (dm_read(target, &read_val, DM_DMCS2) != ERROR_OK) return ERROR_FAIL; if (supported) - *supported = (get_field(read_val, DM_DMCS2_GROUP) == group); + *supported = (get_field(read_val, DM_DMCS2_GROUP) == group && + get_field(read_val, DM_DMCS2_GROUPTYPE) == ((grouptype == HALT_GROUP) ? 0 : 1) && + get_field(read_val, DM_DMCS2_HGSELECT) == + (is_trigger ? DM_DMCS2_HGSELECT_TRIGGERS : DM_DMCS2_HGSELECT_HARTS) && + get_field(read_val, DM_DMCS2_DMEXTTRIGGER) == trigger_num); + if (is_trigger && *supported) { + if (grouptype == HALT_GROUP) { + dm->external_triggers[trigger_num].haltgroup_was_set = true; + dm->external_triggers[trigger_num].haltgroup_num = group; + } else { + dm->external_triggers[trigger_num].resumegroup_was_set = true; + dm->external_triggers[trigger_num].resumegroup_num = group; + } + } + return ERROR_OK; } @@ -2152,8 +2185,9 @@ static int examine(struct target *target) } if (target->smp) { - if (set_group(target, &info->haltgroup_supported, target->smp, HALT_GROUP) != ERROR_OK) + if (set_group(target, &info->haltgroup_supported, target->smp, HALT_GROUP, false, 0) != ERROR_OK) return ERROR_FAIL; + if (info->haltgroup_supported) LOG_TARGET_INFO(target, "Core %d made part of halt group %d.", info->index, target->smp); @@ -2888,6 +2922,8 @@ static int init_target(struct command_context *cmd_ctx, generic_info->handle_became_unavailable = &handle_became_unavailable; generic_info->tick = &tick; + generic_info->set_group = &set_group; + if (!generic_info->version_specific) { generic_info->version_specific = calloc(1, sizeof(riscv013_info_t)); if (!generic_info->version_specific) diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index 8054a1c9b7..6f272dd959 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -5576,6 +5576,80 @@ COMMAND_HANDLER(handle_riscv_virt2phys_mode) return ERROR_OK; } +COMMAND_HANDLER(riscv_set_group) +{ + struct target *target = get_current_target(CMD_CTX); + RISCV_INFO(r); + + if (CMD_ARGC < 2) + return ERROR_COMMAND_SYNTAX_ERROR; + + enum grouptype grouptype; + if (!strcmp("halt_group", CMD_ARGV[0])) { + grouptype = HALT_GROUP; + } else if (!strcmp("resume_group", CMD_ARGV[0])) { + /* Ext. triggers for resume groups are not supported: neither OpenOCD nor GDB + * have a concept of hart resuming on its own due to an external reason, without + * an explicit resume request. */ + LOG_WARNING("triggers for resume groups are not supported, please use with caution."); + grouptype = RESUME_GROUP; + } else { + LOG_ERROR("%s is not a valid argument.", CMD_ARGV[1]); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + unsigned int group; + COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], group); + if (group > 31) { + LOG_ERROR("%d is not a valid group number - expecting a number in range 0..31.", + group); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + if (!r->set_group) { + LOG_TARGET_ERROR(target, "set_group is not implemented for this target."); + return ERROR_FAIL; + } + + bool is_trigger = false; + unsigned int trigger_num = 0; + switch (CMD_ARGC) { + case 2: + break; + case 4: + if (strcmp("trigger", CMD_ARGV[2])) + return ERROR_COMMAND_SYNTAX_ERROR; + is_trigger = true; + COMMAND_PARSE_NUMBER(uint, CMD_ARGV[3], trigger_num); + if (trigger_num > 15) { + LOG_ERROR("%d is not a valid external trigger number - expecting a number in range 0..15.", + trigger_num); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + break; + default: + return ERROR_COMMAND_SYNTAX_ERROR; + } + + bool supported; + if (r->set_group(target, &supported, group, grouptype, is_trigger, trigger_num) != ERROR_OK) + return ERROR_FAIL; + + if (supported) + LOG_TARGET_INFO(target, "%s %d made part of %s group %d.", + (is_trigger ? "External trigger" : "Core"), + (is_trigger ? trigger_num : (unsigned int)target->coreid), + (grouptype == HALT_GROUP) ? "halt" : "resume", group); + else + LOG_TARGET_WARNING(target, "%s %d could not be made part of %s group %d.", + (is_trigger ? "External trigger" : "Core"), + (is_trigger ? trigger_num : (unsigned int)target->coreid), + (grouptype == HALT_GROUP) ? "halt" : "resume", group); + + return ERROR_OK; +} + + static const struct command_registration riscv_exec_command_handlers[] = { { .name = "dump_sample_buf", @@ -5838,6 +5912,13 @@ static const struct command_registration riscv_exec_command_handlers[] = { "When off, users need to take care of memory coherency themselves, for example by using " "`riscv exec_progbuf` to execute fence or CMO instructions." }, + { + .name = "set_group", + .handler = riscv_set_group, + .mode = COMMAND_ANY, + .usage = "<'halt_group'|'resume_group'> group ['trigger' triggernum]", + .help = "Set a hart or a given external trigger to the halt/resume group." + }, { .chain = smp_command_handlers }, diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h index 2a0a9b95f0..91e62fc692 100644 --- a/src/target/riscv/riscv.h +++ b/src/target/riscv/riscv.h @@ -21,6 +21,7 @@ struct riscv_program; #define RISCV_MAX_TRIGGERS 32 #define RISCV_MAX_HWBPS 16 #define RISCV_MAX_DMS 100 +#define RISCV_MAX_EXTTRIGGERS 16 #define DEFAULT_COMMAND_TIMEOUT_SEC 5 @@ -122,6 +123,11 @@ typedef struct { char *name; } range_list_t; +enum grouptype { + HALT_GROUP, + RESUME_GROUP +}; + #define DTM_DTMCS_VERSION_UNKNOWN ((unsigned int)-1) #define RISCV_TINFO_VERSION_UNKNOWN (-1) @@ -144,6 +150,13 @@ struct riscv_mem_access_args { uint32_t increment; }; +struct riscv_ext_trigger { + bool haltgroup_was_set; + unsigned int haltgroup_num; + bool resumegroup_was_set; + unsigned int resumegroup_num; +}; + static inline bool riscv_mem_access_is_valid(const struct riscv_mem_access_args args) { @@ -307,6 +320,9 @@ struct riscv_info { unsigned int (*data_bits)(struct target *target); + int (*set_group)(struct target *target, bool *supported, unsigned int group, + enum grouptype grouptype, bool is_trigger, unsigned int trigger_num); + COMMAND_HELPER((*print_info), struct target *target); /* Storage for arch_info of non-custom registers. */ -- |
|
From: <ge...@op...> - 2025-11-20 01:44:00
|
This is an automated email from Gerrit. "liangzhen <zhe...@sp...>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/9223 -- gerrit commit 37a5fae1631b55525649c7bd2823576f06f4ae25 Author: liangzhen <zhe...@sp...> Date: Tue May 13 13:49:22 2025 +0800 target/riscv: add `cetrig` control Introduce RISC-V-sepecific `configure` parameter `-cetrig` Change-Id: If490838b81cdd918fae0b29a8e5bf1508afafba2 Signed-off-by: liangzhen <zhe...@sp...> diff --git a/doc/openocd.texi b/doc/openocd.texi index 63d07533e6..49e75a44b0 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -11638,6 +11638,15 @@ action pairs. @end itemize @end itemize +@itemize +@item @code{-cetrig} @option{disable}|@option{enable} -- determines how OpenOCD should +configure the @code{cetrig} in the dcsr register. Defaults to @option{disable}. + +@itemize +@item @code{cget} returns the currently configured state for @code{cetrig}. +@end itemize +@end itemize + @subsection RISC-V Debug Configuration Commands @deffn {Command} {riscv dump_sample_buf} [base64] diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 6fa5e025be..9cbd6030fd 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -251,9 +251,9 @@ typedef struct { /* This target was selected using hasel. */ bool selected; - /* When false, we need to set dcsr.ebreak*, halting the target if that's - * necessary. */ - bool dcsr_ebreak_is_set; + /* When false, we need to configure certain bits in the dcsr register. + * To do that, we may momentarily halt the target, if necessary. */ + bool dcsr_register_is_set; /* This hart was placed into a halt group in examine(). */ bool haltgroup_supported; @@ -1681,9 +1681,9 @@ static int wait_for_authbusy(struct target *target, uint32_t *dmstatus) return ERROR_OK; } -static int set_dcsr_ebreak(struct target *target, bool step) +static int set_dcsr_config(struct target *target, bool step) { - LOG_TARGET_DEBUG(target, "Set dcsr.ebreak*"); + LOG_TARGET_DEBUG(target, "Set dcsr config"); if (dm013_select_target(target) != ERROR_OK) return ERROR_FAIL; @@ -1701,18 +1701,20 @@ static int set_dcsr_ebreak(struct target *target, bool step) dcsr = set_field(dcsr, CSR_DCSR_EBREAKU, config->dcsr_ebreak_fields[RISCV_MODE_U]); dcsr = set_field(dcsr, CSR_DCSR_EBREAKVS, config->dcsr_ebreak_fields[RISCV_MODE_VS]); dcsr = set_field(dcsr, CSR_DCSR_EBREAKVU, config->dcsr_ebreak_fields[RISCV_MODE_VU]); + dcsr = set_field(dcsr, CSR_DCSR_CETRIG, config->dcsr_cetrig); if (dcsr != original_dcsr && riscv_reg_set(target, GDB_REGNO_DCSR, dcsr) != ERROR_OK) return ERROR_FAIL; - info->dcsr_ebreak_is_set = true; + // TODO: Read back the DCSR and check if these WARL bits are set as the user intended. + info->dcsr_register_is_set = true; return ERROR_OK; } -static int halt_set_dcsr_ebreak(struct target *target) +static int halt_set_dcsr_config(struct target *target) { RISCV_INFO(r); RISCV013_INFO(info); - LOG_TARGET_DEBUG(target, "Halt to set DCSR.ebreak*"); + LOG_TARGET_DEBUG(target, "Halt to set dcsr config"); /* Remove this hart from the halt group. This won't work on all targets * because the debug spec allows halt groups to be hard-coded, but I @@ -1750,7 +1752,7 @@ static int halt_set_dcsr_ebreak(struct target *target) r->prepped = true; if (riscv013_halt_go(target) != ERROR_OK || - set_dcsr_ebreak(target, false) != ERROR_OK || + set_dcsr_config(target, false) != ERROR_OK || riscv013_step_or_resume_current_hart(target, false) != ERROR_OK) { result = ERROR_FAIL; } else { @@ -2139,7 +2141,7 @@ static int examine(struct target *target) if (result != ERROR_OK) return result; - if (set_dcsr_ebreak(target, false) != ERROR_OK) + if (set_dcsr_config(target, false) != ERROR_OK) return ERROR_FAIL; if (state_at_examine_start == RISCV_STATE_RUNNING) { @@ -2786,7 +2788,7 @@ static int riscv013_get_hart_state(struct target *target, enum riscv_hart_state return ERROR_FAIL; if (get_field(dmstatus, DM_DMSTATUS_ANYHAVERESET)) { LOG_TARGET_INFO(target, "Hart unexpectedly reset!"); - info->dcsr_ebreak_is_set = false; + info->dcsr_register_is_set = false; /* TODO: Can we make this more obvious to eg. a gdb user? */ uint32_t dmcontrol = DM_DMCONTROL_DMACTIVE | DM_DMCONTROL_ACKHAVERESET; @@ -2837,17 +2839,17 @@ static int handle_became_unavailable(struct target *target, riscv_reg_cache_invalidate_all(target); - info->dcsr_ebreak_is_set = false; + info->dcsr_register_is_set = false; return ERROR_OK; } static int tick(struct target *target) { RISCV013_INFO(info); - if (!info->dcsr_ebreak_is_set && + if (!info->dcsr_register_is_set && target->state == TARGET_RUNNING && target_was_examined(target)) - return halt_set_dcsr_ebreak(target); + return halt_set_dcsr_config(target); return ERROR_OK; } @@ -2946,13 +2948,13 @@ static int assert_reset(struct target *target) return riscv013_invalidate_cached_progbuf(target); } -static bool dcsr_ebreak_config_equals_reset_value(const struct target *target) +static bool dcsr_config_equals_reset_value(const struct target *target) { const struct riscv_private_config * const config = riscv_private_config(target); for (int i = 0; i < N_RISCV_MODE; ++i) if (config->dcsr_ebreak_fields[i]) return false; - return true; + return !config->dcsr_cetrig; } static int deassert_reset(struct target *target) @@ -3030,7 +3032,7 @@ static int deassert_reset(struct target *target) target->state = TARGET_RUNNING; target->debug_reason = DBG_REASON_NOTHALTED; } - info->dcsr_ebreak_is_set = dcsr_ebreak_config_equals_reset_value(target); + info->dcsr_register_is_set = dcsr_config_equals_reset_value(target); return ERROR_OK; } @@ -5381,6 +5383,16 @@ static enum riscv_halt_reason riscv013_halt_reason(struct target *target) return RISCV_HALT_INTERRUPT; case CSR_DCSR_CAUSE_GROUP: return RISCV_HALT_GROUP; + case CSR_DCSR_CAUSE_OTHER: + switch (get_field(dcsr, CSR_DCSR_EXTCAUSE)) { + case 0: + LOG_TARGET_WARNING(target, "halted because of hart in a critical error state."); + return RISCV_HALT_CRITICAL_ERROR; + default: + LOG_TARGET_ERROR(target, "Unknown DCSR extcause field: 0x%" + PRIx64, get_field(dcsr, CSR_DCSR_EXTCAUSE)); + return RISCV_HALT_UNKNOWN; + } } LOG_TARGET_ERROR(target, "Unknown DCSR cause field: 0x%" PRIx64, get_field(dcsr, CSR_DCSR_CAUSE)); @@ -5476,7 +5488,7 @@ static int riscv013_on_step_or_resume(struct target *target, bool step) if (execute_autofence(target) != ERROR_OK) return ERROR_FAIL; - if (set_dcsr_ebreak(target, step) != ERROR_OK) + if (set_dcsr_config(target, step) != ERROR_OK) return ERROR_FAIL; if (riscv_reg_flush_all(target) != ERROR_OK) diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index 8054a1c9b7..bfa8addde0 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -486,6 +486,8 @@ static struct riscv_private_config *alloc_default_riscv_private_config(void) for (unsigned int i = 0; i < ARRAY_SIZE(config->dcsr_ebreak_fields); ++i) config->dcsr_ebreak_fields[i] = true; + config->dcsr_cetrig = true; + return config; } @@ -525,6 +527,15 @@ static struct jim_nvp nvp_ebreak_mode_opts[] = { { .name = NULL, .value = RISCV_EBREAK_MODE_INVALID } }; + +#define RISCV_CETRIG_INVALID -1 + +static struct jim_nvp nvp_cetrig_opts[] = { + { .name = "disable", .value = false }, + { .name = "enable", .value = true }, + { .name = NULL, .value = RISCV_CETRIG_INVALID } +}; + static int jim_configure_ebreak(struct riscv_private_config *config, struct jim_getopt_info *goi) { if (goi->argc == 0) { @@ -611,13 +622,42 @@ static int jim_report_ebreak_config(const struct riscv_private_config *config, return JIM_OK; } +static int jim_configure_cetrig(struct riscv_private_config *config, + struct jim_getopt_info *goi) +{ + if (goi->argc == 0) { + Jim_WrongNumArgs(goi->interp, 1, goi->argv - 1, + "?disable|enable?"); + return JIM_ERR; + } + + struct jim_nvp *opt_nvp; + if (jim_getopt_nvp(goi, nvp_cetrig_opts, &opt_nvp) != JIM_OK) { + jim_getopt_nvp_unknown(goi, nvp_cetrig_opts, /*hadprefix*/ true); + return JIM_ERR; + } + config->dcsr_cetrig = opt_nvp->value; + return JIM_OK; +} + +static int jim_report_cetrig_config(const struct riscv_private_config *config, + Jim_Interp *interp) +{ + const char *cetrig_opt = jim_nvp_value2name_simple(nvp_cetrig_opts, + config->dcsr_cetrig)->name; + Jim_SetResultString(interp, cetrig_opt, strlen(cetrig_opt)); + return JIM_OK; +} + enum riscv_cfg_opts { RISCV_CFG_EBREAK, + RISCV_CFG_CETRIG, RISCV_CFG_INVALID = -1 }; static struct jim_nvp nvp_config_opts[] = { { .name = "-ebreak", .value = RISCV_CFG_EBREAK }, + { .name = "-cetrig", .value = RISCV_CFG_CETRIG }, { .name = NULL, .value = RISCV_CFG_INVALID } }; @@ -654,6 +694,10 @@ static int riscv_jim_configure(struct target *target, return goi->is_configure ? jim_configure_ebreak(config, goi) : jim_report_ebreak_config(config, goi->interp); + case RISCV_CFG_CETRIG: + return goi->is_configure + ? jim_configure_cetrig(config, goi) + : jim_report_cetrig_config(config, goi->interp); default: assert(false && "'jim_getopt_nvp' should have returned an error."); } @@ -2617,6 +2661,7 @@ static int set_debug_reason(struct target *target, enum riscv_halt_reason halt_r break; case RISCV_HALT_INTERRUPT: case RISCV_HALT_GROUP: + case RISCV_HALT_CRITICAL_ERROR: target->debug_reason = DBG_REASON_DBGRQ; break; case RISCV_HALT_SINGLESTEP: diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h index 2a0a9b95f0..d1a72c88e5 100644 --- a/src/target/riscv/riscv.h +++ b/src/target/riscv/riscv.h @@ -75,6 +75,7 @@ enum riscv_halt_reason { RISCV_HALT_TRIGGER, RISCV_HALT_UNKNOWN, RISCV_HALT_GROUP, + RISCV_HALT_CRITICAL_ERROR, RISCV_HALT_ERROR }; @@ -378,6 +379,7 @@ enum riscv_priv_mode { struct riscv_private_config { bool dcsr_ebreak_fields[N_RISCV_MODE]; + bool dcsr_cetrig; }; static inline struct riscv_private_config -- |