Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .github/workflows/test-configs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,18 @@ jobs:
arch: arm
config-file: ./config/examples/same51-dualbank.config

samd21_test:
uses: ./.github/workflows/test-build.yml
with:
arch: arm
config-file: ./config/examples/samd21.config

samd21_j18_test:
uses: ./.github/workflows/test-build.yml
with:
arch: arm
config-file: ./config/examples/samd21_j18.config

imx_rt1040_test:
uses: ./.github/workflows/test-build-mcux-sdk-manifests.yml
with:
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -546,6 +546,8 @@ tools/unit-tests/nxp_t10xx_fixup_extract.h
tools/unit-tests/sama5d3_read_extract.h
tools/unit-tests/samr21_erase_extract.h
tools/unit-tests/samr21_erase_fn_extract.h
tools/unit-tests/samr21_protect_extract.h
tools/unit-tests/samr21_protect_fn_extract.h
tools/unit-tests/sdhci_host.c
tools/unit-tests/stm32l5_write_extract.h
tools/unit-tests/stm32u5_write_extract.h
Expand Down
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -862,6 +862,7 @@ $(LSCRIPT): $(LSCRIPT_IN) FORCE
sed -e "s/@STACK_SIZE_PER_HART@/$(STACK_SIZE_PER_HART)/g" | \
sed -e "s/@WOLFBOOT_L2SCRATCH_SIZE@/$(WOLFBOOT_L2SCRATCH_SIZE)/g" | \
sed -e "s/@STACK_SIZE@/$(STACK_SIZE)/g" | \
sed -e "s/@WOLFBOOT_RAM_SIZE@/$(WOLFBOOT_RAM_SIZE)/g" | \
sed -e 's/@WOLFHAL_FLASH_EXCLUDE_TEXT@/$(WOLFHAL_FLASH_EXCLUDE_TEXT)/g' | \
sed -e 's/@WOLFHAL_FLASH_EXCLUDE_RODATA@/$(WOLFHAL_FLASH_EXCLUDE_RODATA)/g' | \
sed -e 's/@WOLFHAL_FLASH_RAM_SECTIONS@/$(WOLFHAL_FLASH_RAM_SECTIONS)/g' \
Expand Down
3 changes: 3 additions & 0 deletions arch.mk
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,9 @@ ifeq ($(ARCH),ARM)
## Target specific configuration
ifeq ($(TARGET),samr21)
CORTEX_M0=1
# SAMD21x17 and SAMR21 have 16KB of SRAM, SAMD21x18 has 32KB. The
# linker script takes this as the length of its RAM region.
WOLFBOOT_RAM_SIZE?=0x4000
endif
ifeq ($(TARGET),imx_rt)
CORTEX_M7=1
Expand Down
41 changes: 41 additions & 0 deletions config/examples/samd21.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
ARCH?=ARM
TARGET?=samr21
SIGN?=ECC256
HASH?=SHA256
DEBUG?=0
DEBUG_UART?=0
VTOR?=1
CORTEX_M0?=1
NO_ASM?=0
NO_MPU?=1
EXT_FLASH?=0
SPI_FLASH?=0
ALLOW_DOWNGRADE?=0
NVM_FLASH_WRITEONCE?=1
WOLFBOOT_VERSION?=0
V?=0
SPMATH?=1
RAM_CODE?=0
DUALBANK_SWAP?=0

# Cortex-M0+ doesn't support unaligned word accesses. WOLFSSL_USE_ALIGN
# routes word-sized hash operations through byte-safe code paths when the
# input/output buffers aren't 4-byte aligned.
CFLAGS_EXTRA+=-DWOLFSSL_USE_ALIGN

# ATSAMD21J17A/G17A: 128KB flash, 16KB SRAM.
# NVMCTRL erases a 256-byte row, which is the smallest unit wolfBoot can swap.
WOLFBOOT_SECTOR_SIZE?=0x100

# 32KB bootloader, 2 * 47.75KB boot/update partitions, one row of swap.
# Largest signed application is 47KB: the partition less the 256-byte header
# and the two trailer rows NVM_FLASH_WRITEONCE uses.
#
# The bootloader region is 32KB because the NVMCTRL BOOTPROT fuse only
# protects 8KB, 16KB or 32KB. Any other boundary either leaves the
# bootloader writable or extends the protection into the boot partition,
# where it would block the swap.
WOLFBOOT_PARTITION_SIZE?=0xBF00
WOLFBOOT_PARTITION_BOOT_ADDRESS?=0x8000
WOLFBOOT_PARTITION_UPDATE_ADDRESS?=0x13F00
WOLFBOOT_PARTITION_SWAP_ADDRESS?=0x1FE00
38 changes: 38 additions & 0 deletions config/examples/samd21_j18.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
ARCH?=ARM
TARGET?=samr21
SIGN?=ECC256
HASH?=SHA256
DEBUG?=0
DEBUG_UART?=0
VTOR?=1
CORTEX_M0?=1
NO_ASM?=0
NO_MPU?=1
EXT_FLASH?=0
SPI_FLASH?=0
ALLOW_DOWNGRADE?=0
NVM_FLASH_WRITEONCE?=1
WOLFBOOT_VERSION?=0
V?=0
SPMATH?=1
RAM_CODE?=0
DUALBANK_SWAP?=0

# Cortex-M0+ doesn't support unaligned word accesses. WOLFSSL_USE_ALIGN
# routes word-sized hash operations through byte-safe code paths when the
# input/output buffers aren't 4-byte aligned.
CFLAGS_EXTRA+=-DWOLFSSL_USE_ALIGN

# ATSAMD21J18A/G18A: 256KB flash, 32KB SRAM.
# NVMCTRL erases a 256-byte row, which is the smallest unit wolfBoot can swap.
WOLFBOOT_SECTOR_SIZE?=0x100
WOLFBOOT_RAM_SIZE?=0x8000

# 32KB bootloader, 2 * 111.75KB boot/update partitions, one row of swap.
# 32KB is one of the three sizes the NVMCTRL BOOTPROT fuse can protect.
# Largest signed application is 111KB: the partition less the 256-byte header
# and the two trailer rows NVM_FLASH_WRITEONCE uses.
WOLFBOOT_PARTITION_SIZE?=0x1BF00
WOLFBOOT_PARTITION_BOOT_ADDRESS?=0x8000
WOLFBOOT_PARTITION_UPDATE_ADDRESS?=0x23F00
WOLFBOOT_PARTITION_SWAP_ADDRESS?=0x3FE00
115 changes: 115 additions & 0 deletions docs/Targets.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ This README describes configuration of supported targets.
* [Microchip PolarFire SoC](#microchip-polarfire-soc)
* [Microchip SAMA5D3](#microchip-sama5d3)
* [Microchip SAME51](#microchip-same51)
* [Microchip SAMD21 / SAMR21](#microchip-samd21--samr21)
* [Nordic nRF52840](#nordic-nrf52840)
* [Nordic nRF5340](#nordic-nrf5340)
* [Nordic nRF54L15](#nordic-nrf54l15)
Expand Down Expand Up @@ -5329,6 +5330,120 @@ The above is assuming the default configuration where the BOOT partition starts
address `0x8000`.


## Microchip SAMD21 / SAMR21

SAM D21 and SAM R21 are Cortex-M0+ microcontrollers running at up to 48MHz. They
share one SYSCTRL/GCLK/NVMCTRL/PAC design, so a single HAL covers both and the
target name is `samr21` for either part.

NVMCTRL programs a 64-byte page and erases a 256-byte row of four pages. The row
is the smallest unit wolfBoot can swap, so `WOLFBOOT_SECTOR_SIZE` is `0x100`.
That is also the floor for `IMAGE_HEADER_SIZE`, which keeps the practical
signature choice to ECC256 or ED25519: ECC384, ED448 and RSA need a 512-byte
header, and LMS/XMSS need 2KB or more, each forcing a logical sector of that
size and the same amount again of SRAM for the NVM cache.

### Configurations

* `config/examples/samd21.config` - ATSAMD21J17A/G17A, 128KB flash, 16KB SRAM
* `config/examples/samd21_j18.config` - ATSAMD21J18A/G18A, 256KB flash, 32KB SRAM

`WOLFBOOT_RAM_SIZE` gives the linker script the length of the SRAM region, and
must match the part: `0x4000` for the x17 variants and SAMR21, `0x8000` for the
x18. The 128KB layout is a 32KB bootloader, two 47.75KB partitions and one row
of swap, which leaves 47KB for a signed application. The 256KB layout is a 32KB
bootloader, two 111.75KB partitions and one row of swap, leaving 111KB.

Both layouts put the bootloader region at 32KB because the NVMCTRL `BOOTPROT`
fuse in the user row protects 8KB, 16KB or 32KB and nothing in between. A
boundary that is not one of those sizes either leaves the bootloader writable
or pushes the protected region into the boot partition, where it blocks the
swap.

`hal_flash_protect()` locks that region through the NVMCTRL lock regions
rather than the fuse. NVMCTRL splits the array into sixteen regions, so a
region is 8KB on a 128KB part and 16KB on a 256KB one, and a 32KB bootloader
is a whole number of regions either way. wolfBoot applies the lock on the way
out to the application, after any swap has finished writing; `NVMCTRL.LOCK`
reloads from the user row at every reset, so the bootloader itself always runs
with the region writable and re-locks it on each boot.

Setting the persistent `BOOTPROT` fuse is left to whatever programs the part
in production. wolfBoot does not write it, because the user row would have to
be erased and rewritten on every boot to do so.

`WOLFSSL_USE_ALIGN` is set in both configs. Cortex-M0+ does not support
unaligned word accesses, and it routes word-sized hash operations through
byte-safe paths when a buffer is not 4-byte aligned.

### Footprint and signature choice

Measured with arm-none-eabi-gcc 13.2.1 at `-Os`, `SPMATH=1`, `DEBUG=0`,
`DEBUG_UART=0`. "Flash" is the sum of the allocated bootloader sections and
"stack" is the `STACK_USAGE` the build reports for the chosen algorithm:

| Signature | Flash | Stack | Fits 16KB SRAM |
|---|---|---|---|
| ECC256 + SHA256 | 18448 | 7632 | yes |
| ECC256 + SHA256, `NO_ASM=1` | 15428 | 7632 | yes |
| ED25519 + SHA256 | 13476 | 5000 | yes |
| RSA2048 + SHA256 | 13132 | 17568 | no |
| LMS-8-10-1 + SHA256 | 9500 | 1320 | yes |

RSA2048 is the smallest build and has by far the cheapest verification, because
a public-key operation with a small exponent costs much less than an ECDSA
verify. It needs more stack than a 16KB part has, so it is an option on the x18
only. ED25519 gains nothing from `NO_ASM=0`: the Thumb-1 SP assembly accelerates
the integer math that ECC256 and RSA use, and ED25519 does not go through it.

Cortex-M0+ is ARMv6-M, so `sp_armthumb.c` is the only assembly tier available;
`sp_cortexm.c` is Thumb-2 and will not assemble for this core. There is no
Thumb-1 per-algorithm assembly either, so SHA-256 is the portable C
implementation. `NO_ASM=1` drops the SP assembly as well, trading roughly a
factor of four in verification time for about 3KB of flash.

### Uploading the bootloader and the firmware image

The on-board EDBG debugger on an Xplained Pro board presents a CMSIS-DAP
interface that OpenOCD drives with its stock scripts:

```
$ openocd -f interface/cmsis-dap.cfg -f target/at91samdXX.cfg \
-c "program wolfboot.bin 0x0 verify" \
-c "program test-app/image_v1_signed.bin 0x8000 verify reset exit"
```

`0x8000` is `WOLFBOOT_PARTITION_BOOT_ADDRESS`, the same in both configs. A
J-Link or an MPLAB ICD 5 through MDB works equally well.

### Console

`hal/uart/uart_drv_samr21.c` drives a SERCOM in USART mode, and `hal_init()`
brings it up at 115200 8N1 when built with `DEBUG_UART=1`. That costs about
2.5KB of flash over a silent build.

The defaults describe the SAM D21 Xplained Pro EDBG virtual COM port: SERCOM3,
TX on PA22 (pad 0), RX on PA23 (pad 1), both peripheral function C. A board that
wires its console differently overrides `UART_SERCOM`, `UART_PORT_GROUP`,
`UART_TX_PIN`, `UART_RX_PIN`, `UART_PIN_MUX`, `UART_TXPO` and `UART_RXPO`;
`UART_TXPO` and `UART_RXPO` are pad selections out of the SERCOM CTRLA field
tables rather than pin numbers.

The driver sets the SERCOM core's generic clock channel itself, because
`hal_init()` attaches every peripheral channel to GCLK generator 7 and never
configures that generator - only generators 0 and 1 are set up. Nothing else in
wolfBoot needs a peripheral core clock, since NVMCTRL runs from the APB clock,
so the generator 7 assignment is left alone.

### Status

The HAL, both configurations, the console driver and the test application build
and are covered by CI and by the host unit tests `unit-samr21-erase-advance` and
`unit-flash-write-samr21`. **None of it has been validated on silicon yet**, and
the console pin assignment in particular is from the Xplained Pro schematic
rather than from a working board.


## NXP iMX-RT

The NXP iMX-RT10xx family of devices contain a Cortex-M7 with a DCP coprocessor for SHA256 acceleration.
Expand Down
Loading
Loading