From 571b8ac9b873c38d92d307bae3e7fda71e41ac4c Mon Sep 17 00:00:00 2001 From: ALTracer <11005378+ALTracer@users.noreply.github.com> Date: Sat, 12 Oct 2024 15:40:47 +0300 Subject: [PATCH 1/2] at32f43x: Implement read unprotect over SWD transport --- src/target/at32f43x.c | 83 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 82 insertions(+), 1 deletion(-) diff --git a/src/target/at32f43x.c b/src/target/at32f43x.c index e8678f5ddcd..70743dd4ba7 100644 --- a/src/target/at32f43x.c +++ b/src/target/at32f43x.c @@ -554,6 +554,84 @@ static bool at32f43_mass_erase(target_s *target) return true; } +static bool at32f43x_swd_raw_access_noabort(adiv5_debug_port_s *dp, uint8_t rnw, uint16_t addr, uint32_t value) +{ + const uint8_t request = make_packet_request(rnw, addr); + uint32_t response = 0; + uint8_t ack = SWDP_ACK_WAIT; + platform_timeout_s timeout_progressbar; + platform_timeout_set(&timeout_progressbar, 500U); + platform_timeout_s timeout_erase; + platform_timeout_set(&timeout_erase, 15000U); + while ((ack == SWDP_ACK_WAIT) && !platform_timeout_is_expired(&timeout_erase)) { + swd_proc.seq_out(request, 8U); + ack = swd_proc.seq_in(3U); + /* No data phase */ + platform_delay(5U); + target_print_progress(&timeout_progressbar); + } + + if (ack != SWDP_ACK_OK) { + DEBUG_ERROR("SWD access has invalid ack %x\n", ack); + raise_exception(EXCEPTION_ERROR, "SWD invalid ACK"); + } + + if (platform_timeout_is_expired(&timeout_erase)) { + DEBUG_ERROR("%s timed out after %u ms\n", __func__, 15000U); + raise_exception(EXCEPTION_TIMEOUT, "SWD WAIT"); + } + + if (rnw) { + if (!swd_proc.seq_in_parity(&response, 32U)) { + dp->fault = 1U; + DEBUG_ERROR("SWD access resulted in parity error\n"); + raise_exception(EXCEPTION_ERROR, "SWD parity error"); + } + } else + swd_proc.seq_out_parity(value, 32U); + /* Idle cycles */ + swd_proc.seq_out(0, 8U); + return response; +} + +static bool at32f43x_mem_write_noabort(target_s *target, target_addr32_t dest, uint16_t val) +{ + const uint32_t src_bytes = val; + const void *src = &src_bytes; + const align_e align = ALIGN_16BIT; + adiv5_access_port_s *ap = cortex_ap(target); + + //adi_ap_mem_access_setup(ap, dest, align); + uint32_t csw = ap->csw | ADIV5_AP_CSW_ADDRINC_SINGLE | ADIV5_AP_CSW_SIZE_HALFWORD; + adiv5_ap_write(ap, ADIV5_AP_CSW, csw); + adiv5_dp_write(ap->dp, ADIV5_AP_TAR_LOW, (uint32_t)dest); + + uint32_t value = 0; + adiv5_pack_data(dest, src, &value, align); + /* Submit the memory write */ + adiv5_dp_write(ap->dp, ADIV5_AP_DRW, value); + + /* Poll for completion (RDBUFF will be responding with WAITs) */ + volatile uint32_t rdbuff = 0; + TRY (EXCEPTION_ALL) { + //ack = ap->dp->low_access(dp, rnw, addr, value) + rdbuff = at32f43x_swd_raw_access_noabort(ap->dp, ADIV5_LOW_READ, ADIV5_DP_RDBUFF, 0); + } + CATCH () { + case EXCEPTION_TIMEOUT: + DEBUG_TARGET("Timeout during scan. Is target stuck in WFI?\n"); + break; + case EXCEPTION_ERROR: + DEBUG_TARGET("Exception: %s\n", exception_frame.msg); + break; + default: + return false; + } + (void)rdbuff; + + return true; +} + static bool at32f43_option_erase(target_s *target) { /* bank_reg_offset is 0, option bytes belong to first bank */ @@ -683,8 +761,11 @@ static bool at32f43_cmd_option(target_s *target, int argc, const char **argv) * FIXME: this transaction only completes after typ. 15 seconds (mass erase of both banks of 4032 KiB chip) * and if BMD ABORTs it after 250 ms, then chip considers erase as incomplete and stays read-protected. */ - if (!at32f43_option_write_erased(target, 0U, AT32F43x_USD_RDP_KEY)) + at32f43_flash_clear_eop(target, 0); + target_mem32_write32(target, AT32F43x_FLASH_CTRL, AT32F43x_FLASH_CTRL_USDPRGM | AT32F43x_FLASH_CTRL_USDULKS); + if (!at32f43x_mem_write_noabort(target, AT32F43x_USD_BASE, AT32F43x_USD_RDP_KEY)) return false; + /* Set EOPB0 to default 0b010 for 384 KB SRAM */ if (!at32f43_option_write_erased(target, 8U, AT32F43x_USD_EOPB0_DEFAULT)) return false; From 335b1b66602f45927871eef1e2d4b043e70050e5 Mon Sep 17 00:00:00 2001 From: ALTracer <11005378+ALTracer@users.noreply.github.com> Date: Sat, 12 Oct 2024 16:42:37 +0300 Subject: [PATCH 2/2] at32f43x: Extend read unprotect to JTAG transport --- src/target/at32f43x.c | 47 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/src/target/at32f43x.c b/src/target/at32f43x.c index 70743dd4ba7..63bb8ebaed3 100644 --- a/src/target/at32f43x.c +++ b/src/target/at32f43x.c @@ -554,7 +554,47 @@ static bool at32f43_mass_erase(target_s *target) return true; } -static bool at32f43x_swd_raw_access_noabort(adiv5_debug_port_s *dp, uint8_t rnw, uint16_t addr, uint32_t value) +/* Borrow macros from adiv5_jtag.c */ +#define JTAGDP_ACK_OK 0x02U +#define JTAGDP_ACK_WAIT 0x01U + +#define IR_DPACC 0xaU +#define IR_APACC 0xbU + +uint32_t adiv5_jtag_raw_access_noabort(adiv5_debug_port_s *dp, uint8_t rnw, uint16_t addr, uint32_t value) +{ + const bool is_ap = addr & ADIV5_APnDP; + addr &= 0xffU; + + const uint64_t request = ((uint64_t)value << 3U) | ((addr >> 1U) & 0x06U) | (rnw ? 1U : 0U); + + uint32_t result = 0U; + uint8_t ack = JTAGDP_ACK_WAIT; + + jtag_dev_write_ir(dp->dev_index, is_ap ? IR_APACC : IR_DPACC); + + platform_timeout_s timeout_progressbar; + platform_timeout_set(&timeout_progressbar, 500U); + platform_timeout_s timeout_erase; + platform_timeout_set(&timeout_erase, 15000U); + while (ack == JTAGDP_ACK_WAIT && !platform_timeout_is_expired(&timeout_erase)) { + uint64_t response; + jtag_dev_shift_dr(dp->dev_index, (uint8_t *)&response, (const uint8_t *)&request, 35); + result = response >> 3U; + ack = response & 0x07U; + platform_delay(5U); + target_print_progress(&timeout_progressbar); + } + + if (ack != JTAGDP_ACK_OK) { + DEBUG_ERROR("JTAG access resulted in: %" PRIx32 ":%x\n", result, ack); + raise_exception(EXCEPTION_ERROR, "JTAG-DP invalid ACK"); + } + + return result; +} + +static bool adiv5_swd_raw_access_noabort(adiv5_debug_port_s *dp, uint8_t rnw, uint16_t addr, uint32_t value) { const uint8_t request = make_packet_request(rnw, addr); uint32_t response = 0; @@ -615,7 +655,10 @@ static bool at32f43x_mem_write_noabort(target_s *target, target_addr32_t dest, u volatile uint32_t rdbuff = 0; TRY (EXCEPTION_ALL) { //ack = ap->dp->low_access(dp, rnw, addr, value) - rdbuff = at32f43x_swd_raw_access_noabort(ap->dp, ADIV5_LOW_READ, ADIV5_DP_RDBUFF, 0); + if (ap->dp->low_access == adiv5_swd_raw_access) + rdbuff = adiv5_swd_raw_access_noabort(ap->dp, ADIV5_LOW_READ, ADIV5_DP_RDBUFF, 0); + else if (ap->dp->low_access == adiv5_jtag_raw_access) + rdbuff = adiv5_jtag_raw_access_noabort(ap->dp, ADIV5_LOW_READ, ADIV5_DP_RDBUFF, 0); } CATCH () { case EXCEPTION_TIMEOUT: