33#include "target_internal.h"
44#include "cortexm.h"
55#include "adiv5.h"
6+ #include "gdb_packet.h"
67
78/* Non-Volatile Memory Controller (NVMC) Registers */
89#define NRF91_NVMC 0x50039000U
1516#define NRF91_NVMC_CONFIG_EEN 0x2U // Erase enable
1617#define NRF91_NVMC_CONFIG_PEEN 0x3U // Partial erase enable
1718
19+ /* https://infocenter.nordicsemi.com/topic/ps_nrf9160/dif.html */
20+ #define NRF91_PARTNO 0x90U
21+
22+ #define NRF91_CTRL_AP_RESET ADIV5_AP_REG(0x000)
23+ #define NRF91_CTRL_AP_ERASEALL ADIV5_AP_REG(0x004)
24+ #define NRF91_CTRL_IDR_EXPECTED 0x12880000
25+ #define NRF91_AHB_AP_IDR_EXPECTED 0x84770001
26+ #define NRF91_CTRL_AP_ERASEALLSTATUS ADIV5_AP_REG(0x008)
27+
28+ /* https://infocenter.nordicsemi.com/topic/ps_nrf9161/uicr.html */
29+ #define NRF91_UICR_APPROTECT 0x00FF8000U
30+ #define NRF91_UICR_SECUREAPPROTECT 0x00FF802CU
31+ #define NRF91_UICR_APPROTECT_UNPROTECT_VAL 0x50FA50FAU
32+ #define NRF91_UICR_ERASED_VAL 0xFFFFFFFFU
33+
34+ static bool nrf91_ctrl_ap_mass_erase (adiv5_access_port_s * ap )
35+ {
36+ adiv5_ap_write (ap , NRF91_CTRL_AP_ERASEALL , 1 );
37+ platform_timeout_s timeout ;
38+ platform_timeout_set (& timeout , 300 );
39+
40+ bool ret = false;
41+
42+ while (true) {
43+ uint32_t status = adiv5_ap_read (ap , NRF91_CTRL_AP_ERASEALLSTATUS );
44+ if (status == 0 ) {
45+ ret = true;
46+ DEBUG_INFO ("nRF91 mass erase succeeded.\n" );
47+ break ;
48+ }
49+ if (platform_timeout_is_expired (& timeout )) {
50+ DEBUG_INFO ("nRF91 mass erase failed.\n" );
51+ break ;
52+ }
53+ }
54+
55+ platform_delay (10 );
56+
57+ adiv5_ap_write (ap , NRF91_CTRL_AP_RESET , 1 );
58+ adiv5_ap_write (ap , NRF91_CTRL_AP_RESET , 0 );
59+
60+ platform_delay (200 );
61+
62+ return ret ;
63+ }
64+
1865static bool nrf91_wait_ready (target_s * const target , platform_timeout_s * const timeout )
1966{
2067 /* Poll for NVMC_READY */
@@ -49,6 +96,25 @@ static bool nrf91_flash_erase(target_flash_s *flash, target_addr_t addr, size_t
4996 return nrf91_wait_ready (target , NULL );
5097}
5198
99+ static bool nrf91_uicr_flash_erase (target_flash_s * flash , target_addr_t addr , size_t len )
100+ {
101+ target_s * target = flash -> t ;
102+
103+ bool erase_needed = false;
104+
105+ for (size_t offset = 0 ; offset < len ; offset += 4 ) {
106+ if (target_mem_read32 (target , addr + offset ) != NRF91_UICR_ERASED_VAL ) {
107+ erase_needed = true;
108+ break ;
109+ }
110+ }
111+
112+ if (erase_needed ) {
113+ gdb_out ("Skipping UICR erase, mass erase might be needed\n" );
114+ }
115+ return true;
116+ }
117+
52118static bool nrf91_flash_write (target_flash_s * flash , target_addr_t dest , const void * src , size_t len )
53119{
54120 target_s * target = flash -> t ;
@@ -68,6 +134,7 @@ static bool nrf91_flash_write(target_flash_s *flash, target_addr_t dest, const v
68134
69135static void nrf91_add_flash (target_s * target , uint32_t addr , size_t length , size_t erasesize )
70136{
137+ /* add main flash */
71138 target_flash_s * flash = calloc (1 , sizeof (* flash ));
72139 if (!flash ) { /* calloc failed: heap exhaustion */
73140 DEBUG_WARN ("calloc: failed in %s\n" , __func__ );
@@ -81,25 +148,180 @@ static void nrf91_add_flash(target_s *target, uint32_t addr, size_t length, size
81148 flash -> write = nrf91_flash_write ;
82149 flash -> erased = 0xff ;
83150 target_add_flash (target , flash );
151+
152+ /* add separate UICR flash */
153+ target_flash_s * flash_uicr = calloc (1 , sizeof (* flash_uicr ));
154+ if (!flash_uicr ) { /* calloc failed: heap exhaustion */
155+ DEBUG_WARN ("calloc: failed in %s\n" , __func__ );
156+ return ;
157+ }
158+
159+ flash_uicr -> start = 0xff8000U ;
160+ flash_uicr -> length = 0x1000U ;
161+ flash_uicr -> blocksize = 0x4U ;
162+ flash_uicr -> erase = nrf91_uicr_flash_erase ;
163+ flash_uicr -> write = nrf91_flash_write ;
164+ flash_uicr -> erased = 0xff ;
165+ target_add_flash (target , flash_uicr );
166+ }
167+
168+ static bool nrf91_mass_erase (target_s * target )
169+ {
170+ adiv5_access_port_s * ap = cortex_ap (target );
171+ adiv5_access_port_s ctrl_ap = {
172+ .dp = ap -> dp ,
173+ .apsel = 0x4U ,
174+ };
175+
176+ return nrf91_ctrl_ap_mass_erase (& ctrl_ap );
177+ }
178+
179+ static bool nrf91_exit_flash_mode (target_s * const target )
180+ {
181+ adiv5_access_port_s * ap = cortex_ap (target );
182+ /* Persist AP access if uninitialized (only needed for devices with hardenend APPROTECT) */
183+ if (ap -> dp -> target_revision > 2 ) {
184+ bool approtect_erased = target_mem_read32 (target , NRF91_UICR_APPROTECT ) == NRF91_UICR_ERASED_VAL ;
185+ bool secureapprotect_erased = target_mem_read32 (target , NRF91_UICR_SECUREAPPROTECT ) == NRF91_UICR_ERASED_VAL ;
186+
187+ target_mem_write32 (target , NRF91_NVMC_CONFIG , NRF91_NVMC_CONFIG_WEN );
188+
189+ while (target_mem_read32 (target , NRF91_NVMC_READY ) == 0 ) {
190+ platform_delay (1 );
191+ DEBUG_INFO ("Waiting for NVMC to become ready\n" );
192+ }
193+
194+ if (approtect_erased ) {
195+ target_mem_write32 (target , NRF91_UICR_APPROTECT , NRF91_UICR_APPROTECT_UNPROTECT_VAL );
196+ }
197+ if (secureapprotect_erased ) {
198+ target_mem_write32 (target , NRF91_UICR_SECUREAPPROTECT , NRF91_UICR_APPROTECT_UNPROTECT_VAL );
199+ }
200+
201+ target_mem_write32 (target , NRF91_NVMC_CONFIG , NRF91_NVMC_CONFIG_REN );
202+ }
203+ return true;
84204}
85205
86206bool nrf91_probe (target_s * target )
87207{
88208 adiv5_access_port_s * ap = cortex_ap (target );
89209
90- if (ap -> dp -> version < 2U )
210+ if (ap -> dp -> version < 2U || ap -> dp -> target_partno != NRF91_PARTNO )
91211 return false;
92212
93- switch (ap -> dp -> target_partno ) {
94- case 0x90 :
213+ uint32_t partno = target_mem_read32 (target , 0x00FF0140 );
214+ uint32_t hwrevision = target_mem_read32 (target , 0x00FF0144 );
215+ uint32_t variant = target_mem_read32 (target , 0x00FF0148 );
216+
217+ DEBUG_INFO ("nRF%04" PRIx32 " %4s%4s detected!\n" , partno , (const char * )& variant , (const char * )& hwrevision );
218+
219+ switch (ap -> dp -> target_revision ) {
220+ case 0 :
221+ case 1 :
222+ case 2 :
95223 target -> driver = "Nordic nRF9160" ;
96- target -> target_options |= TOPT_INHIBIT_NRST ;
97- target_add_ram ( target , 0x20000000 , 256U * 1024U );
98- nrf91_add_flash ( target , 0 , 4096U * 256U , 4096U ) ;
224+ break ;
225+ case 3 :
226+ target -> driver = "Nordic nRF91x1" ;
99227 break ;
100228 default :
229+ target -> driver = "Nordic nRF91" ;
230+ }
231+
232+ target -> target_options |= TOPT_INHIBIT_NRST ;
233+ target_add_ram (target , 0x20000000 , 256U * 1024U );
234+ nrf91_add_flash (target , 0 , 4096U * 256U , 4096U );
235+
236+ target -> mass_erase = nrf91_mass_erase ;
237+ target -> exit_flash_mode = nrf91_exit_flash_mode ;
238+
239+ return true;
240+ }
241+
242+ static bool nrf91_rescue_do_recover (target_s * target )
243+ {
244+ adiv5_access_port_s * ap = (adiv5_access_port_s * )target -> priv ;
245+
246+ const bool hardened_approtect = ap -> dp -> target_revision > 2 ;
247+
248+ /* on some revisions, this needs to be repeated */
249+ for (size_t i = 0 ; i < 3 ; ++ i ) {
250+ if (!nrf91_ctrl_ap_mass_erase (ap ))
251+ continue ;
252+ if (!hardened_approtect ) {
253+ /* pin reset is needed on older devices */
254+ platform_nrst_set_val (true);
255+ platform_delay (100 );
256+ platform_nrst_set_val (false);
257+
258+ /* repetition not needed and debug port inactive at this point */
259+ return false;
260+ }
261+
262+ //check if CSW DEVICEEN is set
263+ struct adiv5_access_port ahb_ap = * ap ;
264+ ahb_ap .apsel = 0x0U ;
265+ const uint32_t csw = ap -> dp -> ap_read (& ahb_ap , ADIV5_AP_CSW );
266+ if (csw & ADIV5_AP_CSW_DEVICEEN ) {
267+ DEBUG_INFO ("nRF91 Rescue succeeded.\n" );
268+ break ;
269+ }
270+ }
271+
272+ return false;
273+ }
274+
275+ bool nrf91_rescue_probe (adiv5_access_port_s * ap )
276+ {
277+ target_s * target = target_new ();
278+ if (!target ) {
101279 return false;
102280 }
281+ adiv5_ap_ref (ap );
282+ target -> attach = (void * )nrf91_rescue_do_recover ;
283+ target -> priv = ap ;
284+ target -> priv_free = (void * )adiv5_ap_unref ;
285+ target -> driver = "nRF91 Rescue (Attach, then scan again!)" ;
286+
287+ return true;
288+ }
103289
290+ /* check if nRF91 target is in secure state, return false if device is protected */
291+ bool nrf91_dp_prepare (adiv5_debug_port_s * const dp )
292+ {
293+ adiv5_access_port_s ahb_ap = {
294+ .dp = dp ,
295+ .apsel = 0x0U ,
296+ };
297+ adiv5_access_port_s ctrl_ap = {
298+ .dp = dp ,
299+ .apsel = 0x4U ,
300+ };
301+ ahb_ap .idr = adiv5_ap_read (& ahb_ap , ADIV5_AP_IDR );
302+ ahb_ap .csw = adiv5_ap_read (& ahb_ap , ADIV5_AP_CSW );
303+ ctrl_ap .idr = adiv5_ap_read (& ctrl_ap , ADIV5_AP_IDR );
304+
305+ if (ahb_ap .idr != NRF91_AHB_AP_IDR_EXPECTED ) {
306+ DEBUG_ERROR (
307+ "nRF91: AHB-AP IDR is 0x%08" PRIx32 ", expected 0x%08" PRIx32 "\n" , ahb_ap .idr , NRF91_AHB_AP_IDR_EXPECTED );
308+ }
309+
310+ if (ctrl_ap .idr != NRF91_CTRL_IDR_EXPECTED ) {
311+ DEBUG_ERROR (
312+ "nRF91: CTRL-AP IDR is 0x%08" PRIx32 ", expected 0x%08" PRIx32 "\n" , ctrl_ap .idr , NRF91_CTRL_IDR_EXPECTED );
313+ }
314+
315+ if (!(ahb_ap .csw & ADIV5_AP_CSW_DEVICEEN )) {
316+ DEBUG_INFO ("nRF91 is in secure state, creating rescue target\n" );
317+ adiv5_access_port_s * ap = calloc (1 , sizeof (* ap ));
318+ if (!ap ) { /* calloc failed: heap exhaustion */
319+ DEBUG_ERROR ("calloc: failed in %s\n" , __func__ );
320+ return false;
321+ }
322+ memcpy (ap , & ctrl_ap , sizeof (* ap ));
323+ nrf91_rescue_probe (ap );
324+ return false;
325+ }
104326 return true;
105327}
0 commit comments