From 0e7e9ae03c9f9c79ac258bcbebacff905c4190a9 Mon Sep 17 00:00:00 2001 From: Kat <187942808+northernpaws@users.noreply.github.com> Date: Tue, 28 Oct 2025 21:06:42 -0600 Subject: [PATCH 1/2] nrf: Start implementing driver for nRF5340 --- src/target/adiv5.c | 11 ++ src/target/cortexm.c | 1 + src/target/meson.build | 1 + src/target/nrf5340.c | 269 ++++++++++++++++++++++++++++++++++++++ src/target/target_probe.c | 2 + src/target/target_probe.h | 4 + 6 files changed, 288 insertions(+) create mode 100644 src/target/nrf5340.c diff --git a/src/target/adiv5.c b/src/target/adiv5.c index 8712e2beeb2..7ee90b006b3 100644 --- a/src/target/adiv5.c +++ b/src/target/adiv5.c @@ -466,6 +466,16 @@ void adiv5_dp_init(adiv5_debug_port_s *const dp) return; } + // if (dp->target_designer_code == JEP106_MANUFACTURER_NORDIC && dp->target_partno == 0x70U) { + // // nRF5340 requires special handling due to the AP lacking a register for checking + // // APPROTECT status. Instead, the only way to check if it's protected is to enumerate + // // the list of APs and check if the network core is present. + // if (nrf5340_prepare(dp)) { + // adiv5_dp_unref(dp); + // return; + // } + // } + /* Try to power cycle the APs, affecting a reset on them */ if (!adiv5_power_cycle_aps(dp)) { /* Clean up by freeing the DP - no APs have been constructed at this point, so this is safe */ @@ -514,6 +524,7 @@ void adiv5_dp_init(adiv5_debug_port_s *const dp) kinetis_mdm_probe(ap); nrf51_ctrl_ap_probe(ap); + nrf5340_ctrl_ap_probe(ap); nrf54l_ctrl_ap_probe(ap); efm32_aap_probe(ap); lpc55_dmap_probe(ap); diff --git a/src/target/cortexm.c b/src/target/cortexm.c index 71b571b4fde..3a9886b995f 100644 --- a/src/target/cortexm.c +++ b/src/target/cortexm.c @@ -410,6 +410,7 @@ bool cortexm_probe(adiv5_access_port_s *ap) break; case JEP106_MANUFACTURER_NORDIC: PROBE(nrf51_probe); + PROBE(nrf5340_probe); PROBE(nrf54l_probe); PROBE(nrf91_probe); break; diff --git a/src/target/meson.build b/src/target/meson.build index 4d37805121b..a68d229888d 100644 --- a/src/target/meson.build +++ b/src/target/meson.build @@ -218,6 +218,7 @@ target_lpc = declare_dependency( target_nrf = declare_dependency( sources: files( 'nrf51.c', + 'nrf5340.c', 'nrf54l.c', 'nrf91.c', ), diff --git a/src/target/nrf5340.c b/src/target/nrf5340.c new file mode 100644 index 00000000000..e7d055dd5f4 --- /dev/null +++ b/src/target/nrf5340.c @@ -0,0 +1,269 @@ +/* + * This file is part of the Black Magic Debug project. + * + * Written by Kat Mitchell + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "general.h" +#include "target.h" +#include "target_internal.h" +#include "cortexm.h" +#include "adiv5.h" +#include "gdb_packet.h" + +// Values, registers, etc. are from nrf5340 Specification v1.6: +// https://docs.nordicsemi.com/bundle/ps_nrf5340/page/keyfeatures_html5.html + + +// ==================== +// General Defines + +#define NRF5340_DESIGNER 0x244U +// NOTE: If checking the part number on the DP, it shows as 0xBD for some reason. +#define NRF5340_PARTNO 0x70U +#define NRF5340_CTRL_AP_IDR 0x12880000U + +#define NRF5340_AHB_AP_APP_NUM 0x0U +#define NRF5340_AHB_AP_NET_NUM 0x1U +#define NRF5340_CTRL_AP_APP_NUM 0x2U +#define NRF5340_CTRL_AP_NET_NUM 0x3U + +// ==================== +// CTRL AP (Access Port) Registers and Values + +// Register addresses are from nRF5340 Specification v1.6 P.g. 829. + +// System reset request. +// This register is automatically deactivated during an ERASEALL operation. +#define NRF5340_CTRL_AP_RESET ADIV5_AP_REG(0x00U) +// Perform a secure erase of the device, where flash, SRAM, and UICR will be erased in sequence. +// The device will be returned to factory default settings upon next reset. +#define NRF5340_CTRL_AP_REG_ERASEALL ADIV5_AP_REG(0x004U) +// This is the status register for the ERASEALL operation +#define NRF5340_CTRL_AP_REG_ERASEALLSTATUS ADIV5_AP_REG(0x008U) +// This register disables APPROTECT and enables debug access to non-secure mode +#define NRF5340_CTRL_AP_REG_APPROTECT_DISABLE ADIV5_AP_REG(0x010U) +// This register disables SECUREAPPROTECT and enables debug access to secure mode. +#define NRF5340_CTRL_AP_REG_SECURE_APPROTECT_DISABLE ADIV5_AP_REG(0x014U) +// This is the status register for the UICR ERASEPROTECT configuration. +#define NRF5340_CTRL_AP_REG_ERASEPROTECT_STATUS ADIV5_AP_REG(0x018U) +// This register disables ERASEPROTECT and performs ERASEALL. +#define NRF5340_CTRL_AP_REG_ERASEPROTECT_DISABLE ADIV5_AP_REG(0x01CU) +// CTRL-AP Identification Register, IDR. +#define NRF5340_CTRL_AP_REG_IDR ADIV5_AP_REG(0x0FCU) + +// Status bits for the RESET register. +#define NRF5340_CTRL_AP_RESET_NORESET 0x0U +#define NRF5340_CTRL_AP_RESET_RESET 0x1U + +// Status bits for the ERASEALL register. +#define NRF5340_CTRL_AP_ERASEALL_NOOPERATION 0x0U +#define NRF5340_CTRL_AP_ERASEALL_ERASE 0x1U + +// Status bits for the ERASEALLSTATUS register. +#define NRF5340_CTRL_AP_ERASEALLSTATUS_READY 0x0U +#define NRF5340_CTRL_AP_ERASEALLSTATUS_BUSY 0x1U + +static bool nrf5340_ctrl_ap_mass_erase(target_s *const target, platform_timeout_s *const print_progess) +{ + return true; +} + +/* Handles unlocking/erasing the codes if they've been protected. */ +static bool nrf5340_do_unlock(target_s *target) +{ + DEBUG_ERROR("nrf5340_do_unlock not implemented"); + + return false; +} + + +static bool ap_is_protected(adiv5_access_port_s * ap) +{ + // Checks if we can read from the core to indicate it's not protected. + return (adiv5_ap_read(ap, ADIV5_AP_CSW) & ADIV5_AP_CSW_DBGSWENABLE) == 0; +} + +static bool dp_is_protected(adiv5_debug_port_s *const dp, uint8_t apsel) +{ + adiv5_access_port_s ap = {0}; + ap.dp = dp; + ap.apsel = apsel; + return ap_is_protected(&ap); +} + +/* Log to inform the user that the core needs to be erased to release protection. */ +static bool nrf5340_app_protected_message(target_s *target) +{ + tc_printf(target, "Attached in protected mode, please issue 'monitor erase_mass' to regain chip access\n"); + + /* Patch back in the normal cortexm attach for next time */ + target->attach = cortexm_attach; + + return false; +} + +/* Log to inform the user that the core needs to be erased to release protection. */ +static bool nrf5340_net_protected_message(target_s *target) +{ + tc_printf(target, "Attached in protected mode, please issue 'monitor erase_mass' to regain chip access\n"); + + /* Patch back in the normal cortexm attach for next time */ + target->attach = cortexm_attach; + + return false; +} + +bool nrf5340_ctrl_ap_probe(adiv5_access_port_s *const ap) +{ + DEBUG_INFO("nrf5340_ctrl_ap_probe"); + + switch (ap->idr) { + case NRF5340_CTRL_AP_IDR: + break; + default: + return false; + } + + // Special case for injecting a dummy target to show that + // the network core is offline if the application core is + // protected and the network core isn't powered. + if (ap->apsel == NRF5340_CTRL_AP_NET_NUM) { + // If the network core is unpowered then the AP can't be configured. + adiv5_access_port_s *ap_net = adiv5_new_ap(ap->dp, NRF5340_AHB_AP_NET_NUM); + if (ap_net == NULL) { + target_s *target = target_new(); + if (!target) + return false; + adiv5_ap_ref(ap); + target->priv = ap; + target->priv_free = (void (*)(void *))adiv5_ap_unref; + gdb_out("nRF5340 Network Core: Unprotect Application Core to bring online.\n"); + + target->attach = nrf5340_net_protected_message; + target->driver = "nRF5340 Network Core (Offline)"; + } + } + + return true; +} + +// nRF5340 Specification v1.6 P.g. 121. +#define NRF5340_FICR_INFO_RAM 0x00FF0218 +#define NRF5340_FICR_INFO_FLASH 0x00FF021C + +// nRF5340 Specification v1.6 P.g. 129. +#define NRF5340_UICR 0x00FF8000 +#define NRF5340_RAM 0x20000000U + +static bool nrf5340_mass_erase(target_s *const target, platform_timeout_s *const print_progess) +{ + DEBUG_INFO("nrf5340_mass_erase"); + DEBUG_ERROR("nRF5340 mass erase not implemente yet"); + + return false; +} + +// When one of the cores is online on the nRF5340 it'll be +// picked up by the cortexm probe and processed here. +// +// We need to check if the core(s) are protected or not here +// before letting them be normally attached to and messed with. +bool nrf5340_probe(target_s *const target) +{ + DEBUG_INFO("nrf5340_probe"); + + const adiv5_access_port_s *const ap = cortex_ap(target); + + if (ap->dp->version < 2U) + return false; + + if (ap->designer_code != NRF5340_DESIGNER && ap->partno != NRF5340_PARTNO) + return false; + + // target->target_options |= TOPT_INHIBIT_NRST; + target->mass_erase = nrf5340_mass_erase; // empty method for now + + // Determine which core we're seeing. + if (ap->apsel == NRF5340_AHB_AP_APP_NUM) { + // Check if the core is protected so that we can + // configure special target handling for it. + if (ap_is_protected(ap)) { + gdb_out("nRF5340 Application Core: Attach and issue 'monitor erase_mass' to regain chip access.\n"); + + target->core = "(Protected)"; + target->driver = "nRF5340 Application Core"; + /* + * Overload the default cortexm attach when the nRF5340 is protected. + * + * This function allows the user to temporarily attach and run a full + * device erase to clear the protection on the core. + */ + target->attach = nrf5340_app_protected_message; + target->regs_size = 0x0U; + } else { + target->driver = "nRF5340 Application Core"; + } + } else if (ap->apsel == NRF5340_AHB_AP_NET_NUM) { + // Check if the core is protected so that we can + // configure special target handling for it. + // + // Note that if the network core is offline (as it + // is by default), the application code needs to be + // unprotected first to power it on. A special case + // it handled in nrf5340_ctrl_ap_probe to detect an + // offline network core and show a dummy target as + // feedback to the user. + if (ap_is_protected(ap)) { + gdb_out("nRF5340 Network Core: Attach and issue 'monitor erase_mass' to regain chip access.\n"); + + target->core = "(Protected)"; + target->driver = "nRF5340 Network Core"; + + /* + * Overload the default cortexm attach when the nRF5340 is protected. + * + * This function allows the user to temporarily attach and run a full + * device erase to clear the protection on the core. + */ + target->attach = nrf5340_net_protected_message; + + target->regs_size = 0x0U; + } else { + target->driver = "nRF5340 Network Core"; + } + } + + + // const uint32_t info_ram = target_mem32_read32(target, NRF5340_FICR_INFO_RAM); + // target_add_ram32(target, NRF5340_RAM, info_ram * 1024U); + // add_rram(target, NRF5340_UICR, 0x1000U, 4U); + + return true; +} diff --git a/src/target/target_probe.c b/src/target/target_probe.c index 0171dccb644..1842d173451 100644 --- a/src/target/target_probe.c +++ b/src/target/target_probe.c @@ -96,6 +96,7 @@ CORTEXAR_PROBE_WEAK_NOP(cortexa_armv8_cti_probe) TARGET_PROBE_WEAK_NOP(riscv32_probe) TARGET_PROBE_WEAK_NOP(riscv64_probe) + CORTEXM_PROBE_WEAK_NOP(efm32_aap_probe) CORTEXM_PROBE_WEAK_NOP(kinetis_mdm_probe) CORTEXM_PROBE_WEAK_NOP(lpc55_dmap_probe) @@ -132,6 +133,7 @@ TARGET_PROBE_WEAK_NOP(msp432e4_probe) TARGET_PROBE_WEAK_NOP(msp432p4_probe) TARGET_PROBE_WEAK_NOP(mspm0_probe) TARGET_PROBE_WEAK_NOP(nrf51_probe) +TARGET_PROBE_WEAK_NOP(nrf5340_probe) TARGET_PROBE_WEAK_NOP(nrf54l_probe) TARGET_PROBE_WEAK_NOP(nrf91_probe) TARGET_PROBE_WEAK_NOP(puya_probe) diff --git a/src/target/target_probe.h b/src/target/target_probe.h index 9c906cb3ef0..1de5b4e38f7 100644 --- a/src/target/target_probe.h +++ b/src/target/target_probe.h @@ -47,10 +47,13 @@ bool cortexa_armv8_cti_probe(adiv5_access_port_s *ap, target_addr_t base_address bool riscv32_probe(target_s *target); bool riscv64_probe(target_s *target); +bool nrf5340_prepare(adiv5_debug_port_s *const dp); + bool efm32_aap_probe(adiv5_access_port_s *ap); bool kinetis_mdm_probe(adiv5_access_port_s *ap); bool lpc55_dmap_probe(adiv5_access_port_s *ap); bool nrf51_ctrl_ap_probe(adiv5_access_port_s *ap); +bool nrf5340_ctrl_ap_probe(adiv5_access_port_s *ap); bool nrf54l_ctrl_ap_probe(adiv5_access_port_s *ap); bool rp2040_rescue_probe(adiv5_access_port_s *ap); @@ -83,6 +86,7 @@ bool msp432e4_probe(target_s *target); bool msp432p4_probe(target_s *target); bool mspm0_probe(target_s *target); bool nrf51_probe(target_s *target); +bool nrf5340_probe(target_s *target); bool nrf54l_probe(target_s *target); bool nrf91_probe(target_s *target); bool puya_probe(target_s *target); From f745bae2a7b374c6bd3f65d7df23842738b8fc1f Mon Sep 17 00:00:00 2001 From: Kat <187942808+northernpaws@users.noreply.github.com> Date: Tue, 28 Oct 2025 21:43:12 -0600 Subject: [PATCH 2/2] nrf5340: Add missing `CORTEXM_PROBE_WEAK_NOP` entry for `nrf5340_ctrl_ap_probe` --- .DS_Store | Bin 0 -> 8196 bytes 3rdparty/ftdi/.DS_Store | Bin 0 -> 6148 bytes src/.DS_Store | Bin 0 -> 6148 bytes src/platforms/.DS_Store | Bin 0 -> 10244 bytes src/target/target_probe.c | 1 + 5 files changed, 1 insertion(+) create mode 100644 .DS_Store create mode 100644 3rdparty/ftdi/.DS_Store create mode 100644 src/.DS_Store create mode 100644 src/platforms/.DS_Store diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..f408edcb6d904f2a001267b62db4d1b5c56a8f95 GIT binary patch literal 8196 zcmeHMJ#Q015S>d*Y@kSjAc|XBnm*mHY5=?KG{wXqPd@tf(Fs2 z4Wg%^p$IfYqCzPV1sxIv6>oMocQZa;=nx{i*6y5l-tN46yXV!Mi72S8wyH$4L{vd# zJ9QY%h{ArZxiaQ@&cX&5Pwl1ZLbKb6b4cIe74Qmp1-t@Y0k6Qnq5#fpE|r3F-+F!P z74Qn|O9lA%Aw*>xIh$B(emc;Y6acn_Zc}hQ#TT%lvyrojweX+>b||bJ8n_fAu*1^Ykzw`dO_P6%*$IIf~z(@0xmUrXQGObcWMW?4HF#8ZfayWf#Ywnii zkV9omicyLWy+$w-ZH@ZWq%O7Sq2@y`@(9W2$IH#=ZpKH<)9Ge>icy+R$b2evnR;Ln z(*xK6JyVRPYnMi0B&YaHs!?t($!ag0;x)a$O5{YAHtBKWDU8a``+tzq@C| zc*)}HuXp7gtDr!r_}^lVUp6cB1d8;)Vrbt?9?c^pkC}rXvVFrVoz5e<6r&U$dsrO; zpB`rF<8zK48D)lcPxTX6jl@ZAr>>^l3b5Hu`V&_1w5MQ+cQtlXU#;5U(*)x3O06M!PsOGyM~3|}{`$>S4>gBesUnQxftyAtn`fJu z#MnDp1-f@TkC0rVR?1~)9?7N{rTHYxXB>Qb)KrRG*xblGGXC7o_Jn&n+&CFG?^W@x zUF3Macm<>ak^vFn6R56+=JOETeOsKSx0I4Be*z*#+5)8Zs55jl8Bg8Zk z8$xg=+28qoe90%p&JmHDJ(gpl5fSAWjE64w0k`t|Vq>gDunMEOm`=B~rgFd&^Wx~B=9&@^Fh zaPiRfb!$IAwYA&as{X9p=TGVm7F^fF7%&Em0b}5QGJrdqCEpjc*%&YejDeN`J|8>= zV^C}a-}&1R^0e83RASz&lFmLM8wJ literal 0 HcmV?d00001 diff --git a/src/.DS_Store b/src/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..803c71dbfce0ede14f1a04383b7ab68bc4f6cb32 GIT binary patch literal 6148 zcmeHKy-EW?5T1=8CTNjDP|)H^NtZV`Lo6&Mjivd~DCBZMll~qdmCxZ@*x0Fs5QMym z-|P(W&bx?Mh{z1getWw!yWf3x+}sk8Yt05tqB;>(;f$pkngZi__MDY;WE<%G8Z#Qu z#c0^<^y6H#4g5s~_}OjJHI1oHBT7BLXd-kM2lDj|kQPkiY zQIjivTXZ*f&zsh00xn&e(j~=oLlND|JEc)Ojl1HgG_Uc=bLCBV6|5J>!0boB%V3Qu@T&^E E1OCc(Qvd(} literal 0 HcmV?d00001 diff --git a/src/platforms/.DS_Store b/src/platforms/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..2e5890e5d19c8bfa1f84dec1d4a9b7a200642fe4 GIT binary patch literal 10244 zcmeI1zi-n(6vv<2kcJje#gBmj;Q>Jxqy|u-n_Hy}Y^X~&NR!Y;O-V#4P$VQv3=Dt- ze*mh4SlD3i024w`Sos4GtSpEH1mF9S%RAfGBn+sc=gNNR-FtqY_x0J%U5F@{Uac01 zLLw?)7j|?H4jG&17kg?O&@B;cfOw(`mFXJIQ&b^2M%%y0GmUz-0&Im02vc%8)+LWD?@QkHG2qj zXrQMUfeJ@|DBNKqZDVCsI0Y)40-ZU~Gn7DPM_ee~DTtKyN3VcaAgw@zreT_-3C!9r z@%ejWp*UMBbd9n2e;NKB;#e(x#MyO)K46W6J$pSX;=@)&DPTE-vNxvXn5c>e*er`6AS zzdkj*37-y|%g5r_CEs#G;J8k=a2M3E-nL|s1nXjCB|JFG^G(B&^6JpIy)2%AP-M&D zUL2>hbjl*3xlg>0Gray{7)&f5e_8!jUV0?*4j}JoJLkEd?RK7T=7-5AV|cD)pPffO ze@5i9rV6!J~-ks~v-P`7k0fBM2h!MJiF;b(d zMLGQLNV1=^OX=G9D5~40UT>og;r%e!B=U;Vxg&nU`hFKo_j6Bli}A< zX)8aA3$G7s`{dhX757dBge}lj@jj{JKV0Jke#|a{1UCuM~$EYgtbtdMLiG=jB+`{hZ_32IFAo;2bU= zo8z0{DDXVcB=Kz6*q`OYc@BRzJgIYWrmg%kxJ3Oov-Mdxp!G5RoagOt!(*L;v$%Y0 zju%27zj+0`0$u^Hz|K}+P?aBw_5T@6Lmj{W?`)BL^