3030#include <stdlib.h>
3131
3232const 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]" ;
3435
3536/* Provides one common interface to handle both USART and USB-CDC */
3637typedef struct
@@ -83,6 +84,12 @@ const t_monitor_if usbcdc_if =
8384/* The pointer to the interface object use by the monitor */
8485t_monitor_if * ptr_monitor_if ;
8586
87+ #ifdef SECURE_BY_DEFAULT
88+ bool b_security_enabled = true;
89+ #else
90+ bool b_security_enabled = false;
91+ #endif
92+
8693/* b_terminal_mode mode (ascii) or hex mode */
8794volatile bool b_terminal_mode = false;
8895volatile bool b_sam_ba_interface_usart = false;
@@ -222,9 +229,12 @@ void sam_ba_putdata_term(uint8_t* data, uint32_t length)
222229 return ;
223230}
224231
232+ #ifndef SECURE_BY_DEFAULT
225233volatile uint32_t sp ;
226234void call_applet (uint32_t address )
227235{
236+ if (b_security_enabled ) return ;
237+
228238 uint32_t app_start_address ;
229239
230240 __disable_irq ();
@@ -240,8 +250,10 @@ void call_applet(uint32_t address)
240250 /* Jump to application Reset Handler in the application */
241251 asm("bx %0" ::"r" (app_start_address ));
242252}
253+ #endif
243254
244255uint32_t current_number ;
256+ uint32_t erased_from = 0 ;
245257uint32_t i , length ;
246258uint8_t command , * ptr_data , * ptr , data [SIZEBUFMAX ];
247259uint8_t j ;
@@ -264,11 +276,26 @@ static void put_uint32(uint32_t n)
264276 sam_ba_putdata ( ptr_monitor_if , buff , 8 );
265277}
266278
279+ static void eraseFlash (uint32_t dst_addr )
280+ {
281+ erased_from = dst_addr ;
282+ while (dst_addr < MAX_FLASH )
283+ {
284+ // Execute "ER" Erase Row
285+ NVMCTRL -> ADDR .reg = dst_addr / 2 ;
286+ NVMCTRL -> CTRLA .reg = NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_ER ;
287+ while (NVMCTRL -> INTFLAG .bit .READY == 0 )
288+ ;
289+ dst_addr += PAGE_SIZE * 4 ; // Skip a ROW
290+ }
291+ }
292+
267293#ifdef ENABLE_JTAG_LOAD
268294static uint32_t offset = __UINT32_MAX__ ;
269295static bool flashNeeded = false;
270296#endif
271297
298+
272299static void sam_ba_monitor_loop (void )
273300{
274301 length = sam_ba_getdata (ptr_monitor_if , data , SIZEBUFMAX );
@@ -284,7 +311,7 @@ static void sam_ba_monitor_loop(void)
284311 {
285312 sam_ba_putdata (ptr_monitor_if , "\n\r" , 2 );
286313 }
287- if (command == 'S' )
314+ if (command == 'S' ) // Write memory (normally RAM, but might be flash, if client handles the Flash MCU commands?)
288315 {
289316 //Check if some data are remaining in the "data" buffer
290317 if (length > i )
@@ -318,37 +345,65 @@ static void sam_ba_monitor_loop(void)
318345
319346 __asm("nop" );
320347 }
321- else if (command == 'R' )
348+ else if (command == 'R' ) // Read memory (flash or RAM)
322349 {
323- sam_ba_putdata_xmd (ptr_monitor_if , ptr_data , current_number );
350+ // Flash memory starts at address 0 and runs to flash size 0x40000 (256 KByte)
351+
352+ // 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.
353+ // Bootloader ends at 0x1FFF, so user programs start at 0x2000
354+ // RAM starts at 0x20000000, so redirect FLASH reads into RAM reads, when in secure mode
355+ if (b_security_enabled && ((uint32_t )ptr_data >= 0x0000 && (uint32_t )ptr_data < 0x20000000 ))
356+ ptr_data = (uint8_t * )0x20005000 ;
357+ sam_ba_putdata_xmd (ptr_monitor_if , ptr_data , current_number );
324358 }
325- else if (command == 'O' )
359+ else if (command == 'O' ) // write byte
326360 {
327361 * ptr_data = (char ) current_number ;
328362 }
329- else if (command == 'H' )
363+ else if (command == 'H' ) // Write half word
330364 {
331365 * ((uint16_t * ) ptr_data ) = (uint16_t ) current_number ;
332366 }
333- else if (command == 'W' )
367+ else if (command == 'W' ) // Write word
334368 {
335369 * ((int * ) ptr_data ) = current_number ;
336370 }
337- else if (command == 'o' )
371+ else if (command == 'o' ) // Read byte
338372 {
339- sam_ba_putdata_term (ptr_data , 1 );
373+ // Flash memory starts at address 0 and runs to flash size 0x40000 (256 KByte). RAM starts at 0x20000000.
374+ // 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.
375+ // BOSSA reads address 0 to check something, but using read word instead of read byte, but in any case allow reading first byte
376+ // Bootloader ends at 0x1FFF, so user programs start at 0x2000
377+ if (b_security_enabled && ((uint32_t )ptr_data > 0x0003 && (uint32_t )ptr_data < 0x20000000 ))
378+ ptr_data = (uint8_t * ) & current_number ;
379+ sam_ba_putdata_term (ptr_data , 1 );
340380 }
341- else if (command == 'h' )
381+ else if (command == 'h' ) // Read half word
342382 {
343- current_number = * ((uint16_t * ) ptr_data );
383+ // Flash memory starts at address 0 and runs to flash size 0x40000 (256 KByte). RAM starts at 0x20000000.
384+ // 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.
385+ // BOSSA reads address 0 to check something, but using read word instead of read byte, but in any case allow reading first byte
386+ // Bootloader ends at 0x1FFF, so user programs start at 0x2000
387+ if (b_security_enabled && ((uint32_t )ptr_data > 0x0003 && (uint32_t )ptr_data < 0x20000000 ))
388+ current_number = 0 ;
389+ else
390+ current_number = * ((uint16_t * ) ptr_data );
344391 sam_ba_putdata_term ((uint8_t * ) & current_number , 2 );
345392 }
346- else if (command == 'w' )
393+ else if (command == 'w' ) // Read word
347394 {
348- current_number = * ((uint32_t * ) ptr_data );
395+ // Flash memory starts at address 0 and runs to flash size 0x40000 (256 KByte). RAM starts at 0x20000000.
396+ // 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.
397+ // BOSSA reads address 0 to check something, but using read word instead of read byte, but in any case allow reading first byte
398+ // Bootloader ends at 0x1FFF, so user programs start at 0x2000
399+ if (b_security_enabled && ((uint32_t )ptr_data > 0x0003 && (uint32_t )ptr_data < 0x20000000 ))
400+ current_number = 0 ;
401+ else
402+ current_number = * ((uint32_t * ) ptr_data );
349403 sam_ba_putdata_term ((uint8_t * ) & current_number , 4 );
350404 }
351- else if (command == 'G' )
405+ #ifndef SECURE_BY_DEFAULT
406+ else if (!b_security_enabled && command == 'G' ) // Execute code. Will not allow when security is enabled.
352407 {
353408 call_applet (current_number );
354409 /* Rebase the Stack Pointer */
@@ -358,40 +413,30 @@ static void sam_ba_monitor_loop(void)
358413 ptr_monitor_if -> put_c (0x6 );
359414 }
360415 }
361- else if (command == 'T' )
416+ #endif
417+ else if (command == 'T' ) // Turn on terminal mode
362418 {
363419 b_terminal_mode = 1 ;
364420 sam_ba_putdata (ptr_monitor_if , "\n\r" , 2 );
365421 }
366- else if (command == 'N' )
422+ else if (command == 'N' ) // Turn off terminal mode
367423 {
368424 if (b_terminal_mode == 0 )
369425 {
370426 sam_ba_putdata ( ptr_monitor_if , "\n\r" , 2 );
371427 }
372428 b_terminal_mode = 0 ;
373429 }
374- else if (command == 'V' )
430+ else if (command == 'V' ) // Read version information
375431 {
376432 sam_ba_putdata ( ptr_monitor_if , "v" , 1 );
377433 sam_ba_putdata ( ptr_monitor_if , (uint8_t * ) RomBOOT_Version , strlen (RomBOOT_Version ));
378434 sam_ba_putdata ( ptr_monitor_if , " " , 1 );
379435 sam_ba_putdata ( ptr_monitor_if , (uint8_t * ) RomBOOT_ExtendedCapabilities , strlen (RomBOOT_ExtendedCapabilities ));
380- sam_ba_putdata ( ptr_monitor_if , " " , 1 );
381- ptr = (uint8_t * ) & (__DATE__ );
382- i = 0 ;
383- while (* ptr ++ != '\0' )
384- i ++ ;
385- sam_ba_putdata ( ptr_monitor_if , (uint8_t * ) & (__DATE__ ), i );
386- sam_ba_putdata ( ptr_monitor_if , " " , 1 );
387- i = 0 ;
388- ptr = (uint8_t * ) & (__TIME__ );
389- while (* ptr ++ != '\0' )
390- i ++ ;
391- sam_ba_putdata ( ptr_monitor_if , (uint8_t * ) & (__TIME__ ), i );
392- sam_ba_putdata ( ptr_monitor_if , "\n\r" , 2 );
436+ ptr = (uint8_t * ) & (" " __DATE__ " " __TIME__ "\n\r" );
437+ sam_ba_putdata ( ptr_monitor_if , ptr , strlen (ptr ));
393438 }
394- else if (command == 'X' )
439+ else if (command == 'X' ) // Erase flash
395440 {
396441 // Syntax: X[ADDR]#
397442 // Erase the flash memory starting from ADDR to the end of flash.
@@ -400,22 +445,13 @@ static void sam_ba_monitor_loop(void)
400445 // Even if the starting address is the last byte of a ROW the entire
401446 // ROW is erased anyway.
402447
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-
448+ // 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.
449+ // 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.
450+ eraseFlash (b_security_enabled ? 0x2000 : current_number );
415451 // Notify command completed
416452 sam_ba_putdata ( ptr_monitor_if , "X\n\r" , 3 );
417453 }
418- else if (command == 'Y' )
454+ else if (command == 'Y' ) // Write buffer to flash
419455 {
420456 // This command writes the content of a buffer in SRAM into flash memory.
421457
@@ -435,6 +471,13 @@ static void sam_ba_monitor_loop(void)
435471 }
436472 else
437473 {
474+ if (b_security_enabled ) {
475+ // To mitigate that an attacker might not use the ordinary BOSSA method of erasing flash before programming,
476+ // always erase flash, if it hasn't been done already.
477+ if (erased_from != 0x2000 )
478+ eraseFlash (0x2000 );
479+ }
480+
438481 // Write to flash
439482 uint32_t size = current_number /4 ;
440483 uint32_t * src_addr = src_buff_addr ;
@@ -546,7 +589,7 @@ static void sam_ba_monitor_loop(void)
546589 // Notify command completed
547590 sam_ba_putdata ( ptr_monitor_if , "Y\n\r" , 3 );
548591 }
549- else if (command == 'Z' )
592+ else if (command == 'Z' ) // Calculate CRC16
550593 {
551594 // This command calculate CRC for a given area of memory.
552595 // It's useful to quickly check if a transfer has been done
@@ -648,6 +691,12 @@ void sam_ba_monitor_run(void)
648691 PAGES = NVMCTRL -> PARAM .bit .NVMP ;
649692 MAX_FLASH = PAGE_SIZE * PAGES ;
650693
694+ #ifdef SECURE_BY_DEFAULT
695+ b_security_enabled = true;
696+ #else
697+ b_security_enabled = NVMCTRL -> STATUS .bit .SB != 0 ;
698+ #endif
699+
651700 ptr_data = NULL ;
652701 command = 'z' ;
653702 while (1 )
0 commit comments