30
30
#include <stdlib.h>
31
31
32
32
const char RomBOOT_Version[] = SAM_BA_VERSION;
33
- const char RomBOOT_ExtendedCapabilities[] = "[Arduino:XYZ]";
33
+ // X = Chip Erase, Y = Write Buffer, Z = Checksum Buffer, P = Secure Bit Aware
34
+ const char RomBOOT_ExtendedCapabilities[] = "[Arduino:XYZP]";
34
35
35
36
/* Provides one common interface to handle both USART and USB-CDC */
36
37
typedef struct
@@ -83,6 +84,8 @@ const t_monitor_if usbcdc_if =
83
84
/* The pointer to the interface object use by the monitor */
84
85
t_monitor_if * ptr_monitor_if;
85
86
87
+ bool b_security_enabled = false;
88
+
86
89
/* b_terminal_mode mode (ascii) or hex mode */
87
90
volatile bool b_terminal_mode = false;
88
91
volatile bool b_sam_ba_interface_usart = false;
@@ -225,6 +228,10 @@ void sam_ba_putdata_term(uint8_t* data, uint32_t length)
225
228
volatile uint32_t sp;
226
229
void call_applet(uint32_t address)
227
230
{
231
+ if (b_security_enabled) {
232
+ return;
233
+ }
234
+
228
235
uint32_t app_start_address;
229
236
230
237
__disable_irq();
@@ -242,6 +249,7 @@ void call_applet(uint32_t address)
242
249
}
243
250
244
251
uint32_t current_number;
252
+ uint32_t erased_from = 0;
245
253
uint32_t i, length;
246
254
uint8_t command, *ptr_data, *ptr, data[SIZEBUFMAX];
247
255
uint8_t j;
@@ -264,6 +272,20 @@ static void put_uint32(uint32_t n)
264
272
sam_ba_putdata( ptr_monitor_if, buff, 8);
265
273
}
266
274
275
+ static void eraseFlash(uint32_t dst_addr)
276
+ {
277
+ erased_from = dst_addr;
278
+ while (dst_addr < MAX_FLASH)
279
+ {
280
+ // Execute "ER" Erase Row
281
+ NVMCTRL->ADDR.reg = dst_addr / 2;
282
+ NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_ER;
283
+ while (NVMCTRL->INTFLAG.bit.READY == 0)
284
+ ;
285
+ dst_addr += PAGE_SIZE * 4; // Skip a ROW
286
+ }
287
+ }
288
+
267
289
#ifdef ENABLE_JTAG_LOAD
268
290
static uint32_t offset = __UINT32_MAX__;
269
291
static bool flashNeeded = false;
@@ -284,7 +306,7 @@ static void sam_ba_monitor_loop(void)
284
306
{
285
307
sam_ba_putdata(ptr_monitor_if, "\n\r", 2);
286
308
}
287
- if (command == 'S')
309
+ if (command == 'S') // Write memory (normally RAM, but might be flash, if client handles the Flash MCU commands?)
288
310
{
289
311
//Check if some data are remaining in the "data" buffer
290
312
if(length>i)
@@ -318,37 +340,80 @@ static void sam_ba_monitor_loop(void)
318
340
319
341
__asm("nop");
320
342
}
321
- else if (command == 'R')
343
+ else if (command == 'R') // Read memory (flash or RAM)
322
344
{
345
+ // Flash memory starts at address 0 and runs to flash size 0x40000 (256 KByte)
346
+
347
+ // Internal RWW section is at adress 0x400000. RWW is flash used for EEPROM emulation. Will not let anyone read that, when in secure mode, either.
348
+ // Bootloader ends at 0x1FFF, so user programs start at 0x2000
349
+ // RAM starts at 0x20000000, so redirect FLASH reads into RAM reads, when in secure mode
350
+ if (b_security_enabled && ((uint32_t)ptr_data >= 0x0000 && (uint32_t)ptr_data < 0x20000000))
351
+ {
352
+ ptr_data = (uint8_t *)0x20005000;
353
+ }
354
+
323
355
sam_ba_putdata_xmd(ptr_monitor_if, ptr_data, current_number);
324
356
}
325
- else if (command == 'O')
357
+ else if (command == 'O') // write byte
326
358
{
327
359
*ptr_data = (char) current_number;
328
360
}
329
- else if (command == 'H')
361
+ else if (command == 'H') // Write half word
330
362
{
331
363
*((uint16_t *) ptr_data) = (uint16_t) current_number;
332
364
}
333
- else if (command == 'W')
365
+ else if (command == 'W') // Write word
334
366
{
335
367
*((int *) ptr_data) = current_number;
336
368
}
337
- else if (command == 'o')
369
+ else if (command == 'o') // Read byte
338
370
{
371
+ // Flash memory starts at address 0 and runs to flash size 0x40000 (256 KByte). RAM starts at 0x20000000.
372
+ // Intern RWW section is at adress 0x400000. RWW is flash used for EEPROM emulation. Will not let anyone read that, when in secure mode, either.
373
+ // BOSSA reads address 0 to check something, but using read word instead of read byte, but in any case allow reading first byte
374
+ // Bootloader ends at 0x1FFF, so user programs start at 0x2000
375
+ if (b_security_enabled && ((uint32_t)ptr_data > 0x0003 && (uint32_t)ptr_data < 0x20000000))
376
+ {
377
+ ptr_data = (uint8_t*) ¤t_number;
378
+ }
379
+
339
380
sam_ba_putdata_term(ptr_data, 1);
340
381
}
341
- else if (command == 'h')
382
+ else if (command == 'h') // Read half word
342
383
{
343
- current_number = *((uint16_t *) ptr_data);
384
+ // Flash memory starts at address 0 and runs to flash size 0x40000 (256 KByte). RAM starts at 0x20000000.
385
+ // Intern RWW section is at adress 0x400000. RWW is flash used for EEPROM emulation. Will not let anyone read that, when in secure mode, either.
386
+ // BOSSA reads address 0 to check something, but using read word instead of read byte, but in any case allow reading first byte
387
+ // Bootloader ends at 0x1FFF, so user programs start at 0x2000
388
+ if (b_security_enabled && ((uint32_t)ptr_data > 0x0003 && (uint32_t)ptr_data < 0x20000000))
389
+ {
390
+ current_number = 0;
391
+ }
392
+ else
393
+ {
394
+ current_number = *((uint16_t *) ptr_data);
395
+ }
396
+
344
397
sam_ba_putdata_term((uint8_t*) ¤t_number, 2);
345
398
}
346
- else if (command == 'w')
399
+ else if (command == 'w') // Read word
347
400
{
348
- current_number = *((uint32_t *) ptr_data);
401
+ // Flash memory starts at address 0 and runs to flash size 0x40000 (256 KByte). RAM starts at 0x20000000.
402
+ // Intern RWW section is at adress 0x400000. RWW is flash used for EEPROM emulation. Will not let anyone read that, when in secure mode, either.
403
+ // BOSSA reads address 0 to check something, but using read word instead of read byte, but in any case allow reading first byte
404
+ // Bootloader ends at 0x1FFF, so user programs start at 0x2000
405
+ if (b_security_enabled && ((uint32_t)ptr_data > 0x0003 && (uint32_t)ptr_data < 0x20000000))
406
+ {
407
+ current_number = 0;
408
+ }
409
+ else
410
+ {
411
+ current_number = *((uint32_t *) ptr_data);
412
+ }
413
+
349
414
sam_ba_putdata_term((uint8_t*) ¤t_number, 4);
350
415
}
351
- else if (command == 'G')
416
+ else if (!b_security_enabled && command == 'G') // Execute code. Will not allow when security is enabled.
352
417
{
353
418
call_applet(current_number);
354
419
/* Rebase the Stack Pointer */
@@ -358,20 +423,20 @@ static void sam_ba_monitor_loop(void)
358
423
ptr_monitor_if->put_c(0x6);
359
424
}
360
425
}
361
- else if (command == 'T')
426
+ else if (command == 'T') // Turn on terminal mode
362
427
{
363
428
b_terminal_mode = 1;
364
429
sam_ba_putdata(ptr_monitor_if, "\n\r", 2);
365
430
}
366
- else if (command == 'N')
431
+ else if (command == 'N') // Turn off terminal mode
367
432
{
368
433
if (b_terminal_mode == 0)
369
434
{
370
435
sam_ba_putdata( ptr_monitor_if, "\n\r", 2);
371
436
}
372
437
b_terminal_mode = 0;
373
438
}
374
- else if (command == 'V')
439
+ else if (command == 'V') // Read version information
375
440
{
376
441
sam_ba_putdata( ptr_monitor_if, "v", 1);
377
442
sam_ba_putdata( ptr_monitor_if, (uint8_t *) RomBOOT_Version, strlen(RomBOOT_Version));
@@ -391,7 +456,7 @@ static void sam_ba_monitor_loop(void)
391
456
sam_ba_putdata( ptr_monitor_if, (uint8_t *) &(__TIME__), i);
392
457
sam_ba_putdata( ptr_monitor_if, "\n\r", 2);
393
458
}
394
- else if (command == 'X')
459
+ else if (command == 'X') // Erase flash
395
460
{
396
461
// Syntax: X[ADDR]#
397
462
// Erase the flash memory starting from ADDR to the end of flash.
@@ -400,22 +465,13 @@ static void sam_ba_monitor_loop(void)
400
465
// Even if the starting address is the last byte of a ROW the entire
401
466
// ROW is erased anyway.
402
467
403
- uint32_t dst_addr = current_number; // starting address
404
-
405
- while (dst_addr < MAX_FLASH)
406
- {
407
- // Execute "ER" Erase Row
408
- NVMCTRL->ADDR.reg = dst_addr / 2;
409
- NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_ER;
410
- while (NVMCTRL->INTFLAG.bit.READY == 0)
411
- ;
412
- dst_addr += PAGE_SIZE * 4; // Skip a ROW
413
- }
414
-
468
+ // BOSSAC.exe always erase with 0x2000 as argument, but an attacker might try to erase just parts of the flash, to be able to copy or analyze the untouched parts.
469
+ // To mitigate this, always erase all sketch flash, that is, starting from address 0x2000. This butloader always assume 8 KByte for itself, and sketch starting at 0x2000.
470
+ eraseFlash(b_security_enabled ? 0x2000 : current_number);
415
471
// Notify command completed
416
472
sam_ba_putdata( ptr_monitor_if, "X\n\r", 3);
417
473
}
418
- else if (command == 'Y')
474
+ else if (command == 'Y') // Write buffer to flash
419
475
{
420
476
// This command writes the content of a buffer in SRAM into flash memory.
421
477
@@ -435,6 +491,13 @@ static void sam_ba_monitor_loop(void)
435
491
}
436
492
else
437
493
{
494
+ if (b_security_enabled && erased_from != 0x2000)
495
+ {
496
+ // To mitigate that an attacker might not use the ordinary BOSSA method of erasing flash before programming,
497
+ // always erase flash, if it hasn't been done already.
498
+ eraseFlash(0x2000);
499
+ }
500
+
438
501
// Write to flash
439
502
uint32_t size = current_number/4;
440
503
uint32_t *src_addr = src_buff_addr;
@@ -546,7 +609,7 @@ static void sam_ba_monitor_loop(void)
546
609
// Notify command completed
547
610
sam_ba_putdata( ptr_monitor_if, "Y\n\r", 3);
548
611
}
549
- else if (command == 'Z')
612
+ else if (command == 'Z') // Calculate CRC16
550
613
{
551
614
// This command calculate CRC for a given area of memory.
552
615
// It's useful to quickly check if a transfer has been done
@@ -648,6 +711,7 @@ void sam_ba_monitor_run(void)
648
711
PAGES = NVMCTRL->PARAM.bit.NVMP;
649
712
MAX_FLASH = PAGE_SIZE * PAGES;
650
713
714
+ b_security_enabled = NVMCTRL->STATUS.bit.SB != 0;
651
715
ptr_data = NULL;
652
716
command = 'z';
653
717
while (1)
0 commit comments