Arduino SAMD21 bootloader protection

At IoT – exploration of LoRaWAN – part 2 I reported some quality issues with two low cost SAMD21 Arduino Zero like boards.

In both cases, the bootloader did not work. I did not investigate further but did note that the NVM user row looked like it had been cleared, but just wrote a new bootloader and restored a default user row with protection for the 8192 length bootloader.

Above is one of the culprit boards.

Now I hasten to add that I did not corrupt the bootloader, the boards never enumerated properly on Windows so they arrived with a non-functioning bootloader… but protecting a good bootloader is an important measure for reliability.

Following this up, Arduino 1.8.7 on writing a new bootloader for an Arduino/Genuino Zero using the Atmel-ICE, leaves the bootloader unprotected.

I have listed this as an issue on Github, but it may or may not be fixed, and it might happen sooner or later. (Update 25/10/18: Arduino used protect the bootloader, but a defect in openocd sometimes resulted in an unrecoverable board so they ceased that operation. Later, the underlying defect in openocd was fixed and it properly updates the userrow, but they have chosen to not restore bootloader protection.)

The matter of hardware protection of a bootloader is often discussed, and some argue that not protecting it allows update of the bootloader in place without using special programmer hardware (as would be required with the SMD21). It is this ability of the normal firmware to update the bootloader that is at the risk of ‘bricking’ the device, though some devices thought to be bricked can be recovered with a device programmer.

I consider bootloader protection an important reliability measure, and so I separately apply it using openocd (part of the Arduino install) to run the command sequence:

halt; at91samd nvmuserrow; at91samd nvmuserrow 0xFFFFFC5DD8E0C7FA; reset; at91samd nvmuserrow;

The first nvmuserrow command will display the existing value, the next changes it, and the last reports it back after reset. (You can scrape the command to run openocd from the Arduino IDE log when you install the bootloader, just change the -c parameter as above.

I have decided to reinstall the boot loader and protection on any cheap Chinese SAMD21 boards I buy. Of course that means to buy only boards with the SWD interface conveniently accessible.

J-link solution

If you have a J-link handy, the following is a J-link commander script to unprotect the bootloader, write a new bootloader, and write default userrow with 8k bootloader protection (change the path to the hex file as appropriate).

//display userrow
mem8 0x804000 0x10
//remove boot protection
w1 0x804000 0xff
r
erase
loadfile C:\Users\owen\AppData\Local\Arduino15\packages\arduino\hardware\samd\1.6.19\bootloaders\zero\samd21_sam_ba.hex
// write default userrow with 8k boot protection
w4 0x804000 0xd8e0c7fa
w4 0x804004 0xfffffc5d
w4 0x804008 0xffffffff
w4 0x80400c 0xffffffff
r
mem8 0x804000 0x10

The following is the console output from the script.

J-Link>//display userrow
Unknown command. '?' for help.
J-Link>mem8 0x804000 0x10
00804000 = FA C7 E0 D8 5D FC FF FF FF FF FF FF FF FF FF FF
J-Link>//remove boot protection
Unknown command. '?' for help.
J-Link>w1 0x804000 0xff
Writing FF -> 00804000
J-Link>r
Reset delay: 0 ms
Reset type NORMAL: Resets core & peripherals via SYSRESETREQ & VECTRESET bit.
J-Link: Flash download: Bank 1 @ 0x00804000: 1 range affected (16 bytes)
J-Link: Flash download: Total time needed: 0.077s (Prepare: 0.048s, Compare: 0.002s, Erase: 0.000s, Program: 0.003s, Verify: 0.000s, Restore: 0.022s)
J-Link>erase
Erasing device...
J-Link: Flash download: Total time needed: 0.832s (Prepare: 0.074s, Compare: 0.000s, Erase: 0.709s, Program: 0.000s, Verify: 0.000s, Restore: 0.048s)
J-Link: Flash download: Total time needed: 0.070s (Prepare: 0.046s, Compare: 0.000s, Erase: 0.002s, Program: 0.000s, Verify: 0.000s, Restore: 0.021s)
Erasing done.
J-Link>loadfile C:\Users\owen\AppData\Local\Arduino15\packages\arduino\hardware\samd\1.6.19\bootloaders\zero\samd21_sam_ba.hex
Downloading file [C:\Users\owen\AppData\Local\Arduino15\packages\arduino\hardware\samd\1.6.19\bootloaders\zero\samd21_sam_ba.hex]...
J-Link: Flash download: Bank 0 @ 0x00000000: 1 range affected (6656 bytes)
J-Link: Flash download: Total time needed: 0.210s (Prepare: 0.051s, Compare: 0.017s, Erase: 0.000s, Program: 0.109s, Verify: 0.006s, Restore: 0.025s)
O.K.
J-Link>// write default userrow with 8k boot protection
Unknown command. '?' for help.
J-Link>w4 0x804000 0xd8e0c7fa
Writing D8E0C7FA -> 00804000
J-Link>w4 0x804004 0xfffffc5d
Writing FFFFFC5D -> 00804004
J-Link>w4 0x804008 0xffffffff
Writing FFFFFFFF -> 00804008
J-Link>w4 0x80400c 0xffffffff
Writing FFFFFFFF -> 0080400C
J-Link>r
Reset delay: 0 ms
Reset type NORMAL: Resets core & peripherals via SYSRESETREQ & VECTRESET bit.
J-Link: Flash download: Bank 1 @ 0x00804000: 1 range affected (16 bytes)
J-Link: Flash download: Total time needed: 0.077s (Prepare: 0.048s, Compare: 0.002s, Erase: 0.000s, Program: 0.003s, Verify: 0.000s, Restore: 0.022s)
J-Link>mem8 0x804000 0x10
00804000 = FA C7 E0 D8 5D FC FF FF FF FF FF FF FF FF FF FF
J-Link>

Update 12/11: I have since received two more Wemos SAMD21 mini boards, and neither was recognised by Windows. Replacing and protecting the boot loader rendered the boards usable.

Update: Listing the issue on github was a total waste of space, it was closed within hours with:

we decided to drop protecting the bootloader because openocd was bugged and used to write more than the requested register, leading to an unrecoverable board. This is the relevant commit 153d993#diff-d638a47d1ca0e2a5585fb34c7d7fb0f9 . In the meantime we fixed openocd (arduino/OpenOCD@76b0521 and arduino/OpenOCD@76b0521 ) but we decided not to lock the bootloader again so we have the chance to update it on the field without an external programmer.
If you need bootloader protection simply revert the first patch.

So, your could follow that path, or simply done as I have and write the bootloader and protection as decribed above outside of the Arduino IDE.

openocd with ST-LINK V2

There was a problem with openocd until 2017: Arduino Zero – write bootloader leaves bootloader unprotected, this method will work on more recent releases using an inexpensive ST-LINK V2.

Above is the setup to rewrite the bootloader on a Mini M0 clone using a clone ST-LINK V2. The little cable adapter probably cost more than the clone ST-LINK V2.

Start openocd:

set OPENOCD=%USERPROFILE%\.platformio\packages\tool-openocd\bin\openocd.exe
%OPENOCD% -f "interface/stlink.cfg" -c "set CHIPNAME at91samd21g18a;set CPUTAPID 0x0bc11477" -f target/at91samdXX.cfg

The following is the console output (via telnet) from the script.

Open On-Chip Debugger
> init
> halt
> at91samd chip-erase
chip erase started

> reset
> halt
target halted due to debug-request, current mode: Handler HardFault
xPSR: 0x81000003 pc: 0xfffffffe msp: 0xffffffd8
> at91samd nvmuserrow
NVMUSERROW: 0xFFFFFC5DD8E0C7FA

> at91samd bootloader 0
> reset
> halt
target halted due to debug-request, current mode: Handler HardFault
xPSR: 0x81000003 pc: 0xfffffffe msp: 0xffffffd8
> at91samd nvmuserrow
NVMUSERROW: 0xFFFFFC5DD8E0C7FF

>
> program "C:\\Users\\owen\\.platformio\\packages\\framework-arduino-samd\\bootloaders\\mzero\\Bootloader_D21_M0_150515.hex" verify
target halted due to debug-request, current mode: Thread
xPSR: 0x81000000 pc: 0xfffffffe msp: 0xfffffffc
** Programming Started **
Flash write discontinued at 0x00003380, next section at 0x00004000
** Programming Finished **
** Verify Started **
** Verified OK **
>
> at91samd bootloader 8192
> reset
> halt
target halted due to debug-request, current mode: Thread
xPSR: 0x81000000 pc: 0x000041d8 msp: 0x20007fd0
> at91samd nvmuserrow
NVMUSERROW: 0xFFFFFC5DD8E0C7FA

> #shutdown

More: Arduino SAMD21 bootloader protection II.