3
3
#include "target_internal.h"
4
4
#include "cortexm.h"
5
5
#include "adiv5.h"
6
+ #include "gdb_packet.h"
6
7
7
8
/* Non-Volatile Memory Controller (NVMC) Registers */
8
- #define NRF91_NVMC 0x50039000U
9
- #define NRF91_NVMC_READY (NRF91_NVMC + 0x400U)
10
- #define NRF91_NVMC_CONFIG (NRF91_NVMC + 0x504U)
11
- #define NRF91_NVMC_ERASEALL (NRF91_NVMC + 0x50cU)
9
+ #define NRF91_NVMC 0x50039000U
10
+ #define NRF91_NVMC_READY (NRF91_NVMC + 0x400U)
11
+ #define NRF91_NVMC_READYNEXT (NRF91_NVMC + 0x408U)
12
+ #define NRF91_NVMC_CONFIG (NRF91_NVMC + 0x504U)
13
+ #define NRF91_NVMC_ERASEALL (NRF91_NVMC + 0x50cU)
14
+
15
+ #define NVMC_TIMEOUT_MS 300U
12
16
13
17
#define NRF91_NVMC_CONFIG_REN 0x0U // Read only access
14
18
#define NRF91_NVMC_CONFIG_WEN 0x1U // Write enable
15
19
#define NRF91_NVMC_CONFIG_EEN 0x2U // Erase enable
16
20
#define NRF91_NVMC_CONFIG_PEEN 0x3U // Partial erase enable
17
21
22
+ /* https://infocenter.nordicsemi.com/topic/ps_nrf9160/dif.html */
23
+ #define NRF91_PARTNO 0x90U
24
+
25
+ #define NRF91_CTRL_AP_RESET ADIV5_AP_REG(0x000)
26
+ #define NRF91_CTRL_AP_ERASEALL ADIV5_AP_REG(0x004)
27
+ #define NRF91_CTRL_IDR_EXPECTED 0x12880000
28
+ #define NRF91_AHB_AP_IDR_EXPECTED 0x84770001
29
+ #define NRF91_CTRL_AP_ERASEALLSTATUS ADIV5_AP_REG(0x008)
30
+
31
+ /* https://infocenter.nordicsemi.com/topic/ps_nrf9161/uicr.html */
32
+ #define NRF91_UICR_APPROTECT 0x00FF8000U
33
+ #define NRF91_UICR_SECUREAPPROTECT 0x00FF802CU
34
+ #define NRF91_UICR_APPROTECT_UNPROTECT_VAL 0x50FA50FAU
35
+ #define NRF91_UICR_ERASED_VAL 0xFFFFFFFFU
36
+
37
+ unsigned char empty_app [] = {
38
+ 0x00 , 0x10 , 0x00 , 0x20 , 0x09 , 0x00 , 0x00 , 0x00 , 0x05 , 0x4b , 0x4f , 0xf0 ,
39
+ 0x5a , 0x02 , 0xc3 , 0xf8 , 0x10 , 0x2e , 0x03 , 0x4b , 0x4f , 0xf0 , 0x5a , 0x02 ,
40
+ 0xc3 , 0xf8 , 0x00 , 0x2e , 0xfe , 0xe7 , 0x00 , 0x00 , 0x00 , 0x90 , 0x03 , 0x50
41
+ };
42
+ unsigned int empty_app_len = 36 ;
43
+
44
+ static bool nrf91_ctrl_ap_mass_erase (adiv5_access_port_s * ap )
45
+ {
46
+ adiv5_ap_write (ap , NRF91_CTRL_AP_ERASEALL , 1 );
47
+ platform_timeout_s timeout ;
48
+ platform_timeout_set (& timeout , NVMC_TIMEOUT_MS );
49
+
50
+ bool ret = false;
51
+
52
+ while (true) {
53
+ uint32_t status = adiv5_ap_read (ap , NRF91_CTRL_AP_ERASEALLSTATUS );
54
+ if (status == 0 ) {
55
+ ret = true;
56
+ DEBUG_INFO ("nRF91 mass erase succeeded.\n" );
57
+ break ;
58
+ }
59
+ if (platform_timeout_is_expired (& timeout )) {
60
+ DEBUG_INFO ("nRF91 mass erase failed.\n" );
61
+ break ;
62
+ }
63
+ }
64
+
65
+ platform_delay (10 );
66
+
67
+ adiv5_ap_write (ap , NRF91_CTRL_AP_RESET , 1 );
68
+ adiv5_ap_write (ap , NRF91_CTRL_AP_RESET , 0 );
69
+
70
+ platform_delay (200 );
71
+
72
+ return ret ;
73
+ }
74
+
18
75
static bool nrf91_wait_ready (target_s * const target , platform_timeout_s * const timeout )
19
76
{
20
77
/* Poll for NVMC_READY */
@@ -27,6 +84,18 @@ static bool nrf91_wait_ready(target_s *const target, platform_timeout_s *const t
27
84
return true;
28
85
}
29
86
87
+ static bool nrf91_wait_readynext (target_s * const target , platform_timeout_s * const timeout )
88
+ {
89
+ /* Poll for NVMC_READY */
90
+ while (target_mem_read32 (target , NRF91_NVMC_READYNEXT ) == 0 ) {
91
+ if (target_check_error (target ))
92
+ return false;
93
+ if (timeout )
94
+ target_print_progress (timeout );
95
+ }
96
+ return true;
97
+ }
98
+
30
99
static bool nrf91_flash_erase (target_flash_s * flash , target_addr_t addr , size_t len )
31
100
{
32
101
target_s * target = flash -> t ;
@@ -49,17 +118,42 @@ static bool nrf91_flash_erase(target_flash_s *flash, target_addr_t addr, size_t
49
118
return nrf91_wait_ready (target , NULL );
50
119
}
51
120
52
- static bool nrf91_flash_write (target_flash_s * flash , target_addr_t dest , const void * src , size_t len )
121
+ static bool nrf91_uicr_flash_erase (target_flash_s * flash , target_addr_t addr , size_t len )
53
122
{
54
123
target_s * target = flash -> t ;
55
124
125
+ bool erase_needed = false;
126
+
127
+ for (size_t offset = 0 ; offset < len ; offset += 4 ) {
128
+ if (target_mem_read32 (target , addr + offset ) != NRF91_UICR_ERASED_VAL ) {
129
+ erase_needed = true;
130
+ break ;
131
+ }
132
+ }
133
+
134
+ if (erase_needed ) {
135
+ gdb_out ("Skipping UICR erase, mass erase might be needed\n" );
136
+ }
137
+ return true;
138
+ }
139
+
140
+ static bool nrf91_flash_write (target_flash_s * flash , target_addr_t dest , const void * src , size_t len )
141
+ {
142
+ target_s * target = flash -> t ;
143
+ platform_timeout_s timeout ;
56
144
/* Enable write */
57
145
target_mem_write32 (target , NRF91_NVMC_CONFIG , NRF91_NVMC_CONFIG_WEN );
58
- if (!nrf91_wait_ready (target , NULL ))
146
+
147
+ if (!nrf91_wait_ready (target , & timeout ))
59
148
return false;
60
149
/* Write the data */
61
- target_mem_write (target , dest , src , len );
62
- if (!nrf91_wait_ready (target , NULL ))
150
+ for (size_t offset = 0 ; offset < len ; offset += 4 ) {
151
+ target_mem_write32 (target , dest + offset , src + offset );
152
+ if (!nrf91_wait_readynext (target , & timeout ))
153
+ return false;
154
+ }
155
+ //target_mem_write(target, dest, src, len);
156
+ if (!nrf91_wait_ready (target , & timeout ))
63
157
return false;
64
158
/* Return to read-only */
65
159
target_mem_write32 (target , NRF91_NVMC_CONFIG , NRF91_NVMC_CONFIG_REN );
@@ -68,6 +162,7 @@ static bool nrf91_flash_write(target_flash_s *flash, target_addr_t dest, const v
68
162
69
163
static void nrf91_add_flash (target_s * target , uint32_t addr , size_t length , size_t erasesize )
70
164
{
165
+ /* add main flash */
71
166
target_flash_s * flash = calloc (1 , sizeof (* flash ));
72
167
if (!flash ) { /* calloc failed: heap exhaustion */
73
168
DEBUG_WARN ("calloc: failed in %s\n" , __func__ );
@@ -81,25 +176,208 @@ static void nrf91_add_flash(target_s *target, uint32_t addr, size_t length, size
81
176
flash -> write = nrf91_flash_write ;
82
177
flash -> erased = 0xff ;
83
178
target_add_flash (target , flash );
179
+
180
+ /* add separate UICR flash */
181
+ target_flash_s * flash_uicr = calloc (1 , sizeof (* flash_uicr ));
182
+ if (!flash_uicr ) { /* calloc failed: heap exhaustion */
183
+ DEBUG_WARN ("calloc: failed in %s\n" , __func__ );
184
+ return ;
185
+ }
186
+
187
+ flash_uicr -> start = 0xff8000U ;
188
+ flash_uicr -> length = 0x1000U ;
189
+ flash_uicr -> blocksize = 0x4U ;
190
+ flash_uicr -> erase = nrf91_uicr_flash_erase ;
191
+ flash_uicr -> write = nrf91_flash_write ;
192
+ flash_uicr -> erased = 0xff ;
193
+ target_add_flash (target , flash_uicr );
194
+ }
195
+
196
+ static bool nrf91_mass_erase (target_s * target )
197
+ {
198
+ adiv5_access_port_s * ap = cortex_ap (target );
199
+ adiv5_access_port_s ctrl_ap = {
200
+ .dp = ap -> dp ,
201
+ .apsel = 0x4U ,
202
+ };
203
+
204
+ if (!nrf91_ctrl_ap_mass_erase (& ctrl_ap )) {
205
+ return false;
206
+ }
207
+
208
+ if (ap -> dp -> target_revision > 2 ) {
209
+ target_mem_write32 (target , NRF91_NVMC_CONFIG , NRF91_NVMC_CONFIG_WEN );
210
+ while (target_mem_read32 (target , NRF91_NVMC_READY ) == 0 ) {
211
+ platform_delay (1 );
212
+ DEBUG_INFO ("Waiting for NVMC to become ready\n" );
213
+ }
214
+
215
+ target_mem_write (target , 0 , empty_app , empty_app_len );
216
+ target_mem_write32 (target , NRF91_UICR_APPROTECT , NRF91_UICR_APPROTECT_UNPROTECT_VAL );
217
+ target_mem_write32 (target , NRF91_UICR_SECUREAPPROTECT , NRF91_UICR_APPROTECT_UNPROTECT_VAL );
218
+
219
+ while (target_mem_read32 (target , NRF91_NVMC_READY ) == 0 ) {
220
+ platform_delay (1 );
221
+ DEBUG_INFO ("Waiting for NVMC to become ready\n" );
222
+ }
223
+
224
+ target_mem_write32 (target , NRF91_NVMC_CONFIG , NRF91_NVMC_CONFIG_REN );
225
+ }
226
+
227
+ return true;
228
+ }
229
+
230
+ static bool nrf91_exit_flash_mode (target_s * const target )
231
+ {
232
+ adiv5_access_port_s * ap = cortex_ap (target );
233
+ /* Persist AP access if uninitialized (only needed for devices with hardenend APPROTECT) */
234
+ if (ap -> dp -> target_revision > 2 ) {
235
+ bool approtect_erased = target_mem_read32 (target , NRF91_UICR_APPROTECT ) == NRF91_UICR_ERASED_VAL ;
236
+ bool secureapprotect_erased = target_mem_read32 (target , NRF91_UICR_SECUREAPPROTECT ) == NRF91_UICR_ERASED_VAL ;
237
+
238
+ target_mem_write32 (target , NRF91_NVMC_CONFIG , NRF91_NVMC_CONFIG_WEN );
239
+
240
+ while (target_mem_read32 (target , NRF91_NVMC_READY ) == 0 ) {
241
+ platform_delay (1 );
242
+ DEBUG_INFO ("Waiting for NVMC to become ready\n" );
243
+ }
244
+
245
+ if (approtect_erased ) {
246
+ target_mem_write32 (target , NRF91_UICR_APPROTECT , NRF91_UICR_APPROTECT_UNPROTECT_VAL );
247
+ }
248
+ if (secureapprotect_erased ) {
249
+ target_mem_write32 (target , NRF91_UICR_SECUREAPPROTECT , NRF91_UICR_APPROTECT_UNPROTECT_VAL );
250
+ }
251
+
252
+ while (target_mem_read32 (target , NRF91_NVMC_READY ) == 0 ) {
253
+ platform_delay (1 );
254
+ DEBUG_INFO ("Waiting for NVMC to become ready\n" );
255
+ }
256
+
257
+ target_mem_write32 (target , NRF91_NVMC_CONFIG , NRF91_NVMC_CONFIG_REN );
258
+ }
259
+ return true;
84
260
}
85
261
86
262
bool nrf91_probe (target_s * target )
87
263
{
88
264
adiv5_access_port_s * ap = cortex_ap (target );
89
265
90
- if (ap -> dp -> version < 2U )
266
+ if (ap -> dp -> version < 2U || ap -> dp -> target_partno != NRF91_PARTNO )
91
267
return false;
92
268
93
- switch (ap -> dp -> target_partno ) {
94
- case 0x90 :
269
+ uint32_t partno = target_mem_read32 (target , 0x00FF0140 );
270
+ uint32_t hwrevision = target_mem_read32 (target , 0x00FF0144 );
271
+ uint32_t variant = target_mem_read32 (target , 0x00FF0148 );
272
+
273
+ DEBUG_INFO ("nRF%04" PRIx32 " %4s%4s detected!\n" , partno , (const char * )& variant , (const char * )& hwrevision );
274
+
275
+ switch (ap -> dp -> target_revision ) {
276
+ case 0 :
277
+ case 1 :
278
+ case 2 :
95
279
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 ) ;
280
+ break ;
281
+ case 3 :
282
+ target -> driver = "Nordic nRF91x1" ;
99
283
break ;
100
284
default :
285
+ target -> driver = "Nordic nRF91" ;
286
+ }
287
+
288
+ target -> target_options |= TOPT_INHIBIT_NRST ;
289
+ target_add_ram (target , 0x20000000 , 256U * 1024U );
290
+ nrf91_add_flash (target , 0 , 4096U * 256U , 4096U );
291
+
292
+ target -> mass_erase = nrf91_mass_erase ;
293
+ target -> exit_flash_mode = nrf91_exit_flash_mode ;
294
+
295
+ return true;
296
+ }
297
+
298
+ static bool nrf91_rescue_do_recover (target_s * target )
299
+ {
300
+ adiv5_access_port_s * ap = (adiv5_access_port_s * )target -> priv ;
301
+
302
+ const bool hardened_approtect = ap -> dp -> target_revision > 2 ;
303
+
304
+ /* on some revisions, this needs to be repeated */
305
+ for (size_t i = 0 ; i < 3 ; ++ i ) {
306
+ if (!nrf91_ctrl_ap_mass_erase (ap ))
307
+ continue ;
308
+ if (!hardened_approtect ) {
309
+ /* pin reset is needed on older devices */
310
+ platform_nrst_set_val (true);
311
+ platform_delay (100 );
312
+ platform_nrst_set_val (false);
313
+
314
+ /* repetition not needed and debug port inactive at this point */
315
+ return false;
316
+ }
317
+
318
+ //check if CSW DEVICEEN is set
319
+ struct adiv5_access_port ahb_ap = * ap ;
320
+ ahb_ap .apsel = 0x0U ;
321
+ const uint32_t csw = ap -> dp -> ap_read (& ahb_ap , ADIV5_AP_CSW );
322
+ if (csw & ADIV5_AP_CSW_DEVICEEN ) {
323
+ DEBUG_INFO ("nRF91 Rescue succeeded.\n" );
324
+ break ;
325
+ }
326
+ }
327
+
328
+ return false;
329
+ }
330
+
331
+ bool nrf91_rescue_probe (adiv5_access_port_s * ap )
332
+ {
333
+ target_s * target = target_new ();
334
+ if (!target ) {
101
335
return false;
102
336
}
337
+ adiv5_ap_ref (ap );
338
+ target -> attach = (void * )nrf91_rescue_do_recover ;
339
+ target -> priv = ap ;
340
+ target -> priv_free = (void * )adiv5_ap_unref ;
341
+ target -> driver = "nRF91 Rescue (Attach, then scan again!)" ;
342
+
343
+ return true;
344
+ }
103
345
346
+ /* check if nRF91 target is in secure state, return false if device is protected */
347
+ bool nrf91_dp_prepare (adiv5_debug_port_s * const dp )
348
+ {
349
+ adiv5_access_port_s ahb_ap = {
350
+ .dp = dp ,
351
+ .apsel = 0x0U ,
352
+ };
353
+ adiv5_access_port_s ctrl_ap = {
354
+ .dp = dp ,
355
+ .apsel = 0x4U ,
356
+ };
357
+ ahb_ap .idr = adiv5_ap_read (& ahb_ap , ADIV5_AP_IDR );
358
+ ahb_ap .csw = adiv5_ap_read (& ahb_ap , ADIV5_AP_CSW );
359
+ ctrl_ap .idr = adiv5_ap_read (& ctrl_ap , ADIV5_AP_IDR );
360
+
361
+ if (ahb_ap .idr != NRF91_AHB_AP_IDR_EXPECTED ) {
362
+ DEBUG_ERROR (
363
+ "nRF91: AHB-AP IDR is 0x%08" PRIx32 ", expected 0x%08" PRIx32 "\n" , ahb_ap .idr , NRF91_AHB_AP_IDR_EXPECTED );
364
+ }
365
+
366
+ if (ctrl_ap .idr != NRF91_CTRL_IDR_EXPECTED ) {
367
+ DEBUG_ERROR (
368
+ "nRF91: CTRL-AP IDR is 0x%08" PRIx32 ", expected 0x%08" PRIx32 "\n" , ctrl_ap .idr , NRF91_CTRL_IDR_EXPECTED );
369
+ }
370
+
371
+ if (!(ahb_ap .csw & ADIV5_AP_CSW_DEVICEEN )) {
372
+ DEBUG_INFO ("nRF91 is in secure state, creating rescue target\n" );
373
+ adiv5_access_port_s * ap = calloc (1 , sizeof (* ap ));
374
+ if (!ap ) { /* calloc failed: heap exhaustion */
375
+ DEBUG_ERROR ("calloc: failed in %s\n" , __func__ );
376
+ return false;
377
+ }
378
+ memcpy (ap , & ctrl_ap , sizeof (* ap ));
379
+ nrf91_rescue_probe (ap );
380
+ return false;
381
+ }
104
382
return true;
105
383
}
0 commit comments