|
| 1 | +# wolfHAL Integration |
| 2 | + |
| 3 | +wolfBoot supports [wolfHAL](https://github.com/wolfSSL/wolfHAL) as an alternative |
| 4 | +hardware abstraction layer backend. wolfHAL provides portable drivers for common MCU |
| 5 | +peripherals (clock, flash, GPIO, UART, SPI, etc.) with a consistent API across |
| 6 | +platforms. |
| 7 | + |
| 8 | +## Overview |
| 9 | + |
| 10 | +The wolfHAL integration uses a single generic `TARGET=wolfhal` with a per-board |
| 11 | +abstraction layer. All board-specific details — device instances, driver bindings, |
| 12 | +build flags, and linker scripts — live in a self-contained board directory. Adding |
| 13 | +support for a new board or MCU family requires no changes to the core build system or |
| 14 | +HAL shim. |
| 15 | + |
| 16 | +The integration consists of four parts: |
| 17 | + |
| 18 | +1. **Generic HAL shim** (`hal/wolfhal.c`) — implements the wolfBoot HAL API |
| 19 | + (`hal_flash_write`, `hal_flash_erase`, etc.) by calling `Board_*` macros. This |
| 20 | + file is shared across all wolfHAL boards. |
| 21 | + |
| 22 | +2. **Board directory** (`hal/boards/<board>/`) — contains three files that fully |
| 23 | + describe a board: |
| 24 | + - `board.h` — `#define` macros mapping generic `Board_*` APIs to chip-specific |
| 25 | + wolfHAL driver functions. |
| 26 | + - `board.c` — device instances (clock, flash, GPIO, UART), configuration |
| 27 | + structs, and `hal_init`/`hal_prepare_boot` implementations. |
| 28 | + - `board.mk` — build variables (`ARCH_FLASH_OFFSET`, `LSCRIPT_IN`, wolfHAL |
| 29 | + driver objects, `RAM_CODE` linker rules). |
| 30 | + |
| 31 | +3. **Generic test application** (`test-app/app_wolfhal.c`) — demonstrates using |
| 32 | + wolfHAL peripherals (GPIO, UART) beyond what the bootloader needs, using the same |
| 33 | + `Board_*` API. |
| 34 | + |
| 35 | +4. **wolfHAL library** (`lib/wolfHAL/`) — the wolfHAL submodule containing the |
| 36 | + platform drivers. |
| 37 | + |
| 38 | +### How It Fits Together |
| 39 | + |
| 40 | +``` |
| 41 | +config/examples/wolfhal_<board>.config |
| 42 | + └─ TARGET=wolfhal BOARD=<board> |
| 43 | +
|
| 44 | +arch.mk |
| 45 | + └─ Sets WOLFHAL_ROOT, CFLAGS += -Ihal/boards/$(BOARD) |
| 46 | +
|
| 47 | +Makefile |
| 48 | + └─ OBJS += hal/boards/$(BOARD)/board.o |
| 49 | + └─ include hal/boards/$(BOARD)/board.mk |
| 50 | +
|
| 51 | +hal/wolfhal.c (generic — calls Board_Flash_Write, Board_Uart_Send, etc.) |
| 52 | + └─ #include "board.h" (resolved via -I to the board directory) |
| 53 | +
|
| 54 | +hal/boards/<board>/ |
| 55 | + ├─ board.h (#define Board_Flash_Write → whal_<family>Flash_Write) |
| 56 | + ├─ board.c (device instances, hal_init, hal_prepare_boot) |
| 57 | + └─ board.mk (ARCH_FLASH_OFFSET, LSCRIPT_IN, driver objects, RAM_CODE rules) |
| 58 | +``` |
| 59 | + |
| 60 | +The `board.h` macros resolve `Board_*` calls directly to the chip-specific wolfHAL |
| 61 | +driver functions at compile time. This avoids vtable indirection and allows the |
| 62 | +linker to garbage-collect unused driver code (with `-Wl,--gc-sections`). |
| 63 | + |
| 64 | +## Configuration |
| 65 | + |
| 66 | +A wolfHAL-based config requires two variables beyond the standard wolfBoot settings: |
| 67 | + |
| 68 | +``` |
| 69 | +TARGET=wolfhal |
| 70 | +BOARD=stm32wb_nucleo |
| 71 | +``` |
| 72 | + |
| 73 | +- `TARGET=wolfhal` selects the generic wolfHAL HAL shim and build path. |
| 74 | +- `BOARD` selects the board directory under `hal/boards/`. |
| 75 | + |
| 76 | +See `config/examples/wolfhal_*.config` for complete examples. |
| 77 | + |
| 78 | +## Adding a New Board |
| 79 | + |
| 80 | +To add a new board, create a directory `hal/boards/<board_name>/` with three files: |
| 81 | + |
| 82 | +### 1. `board.h` — API Mappings |
| 83 | + |
| 84 | +Map each generic `Board_*` macro to the appropriate wolfHAL driver function for your |
| 85 | +MCU family. The required mappings are: |
| 86 | + |
| 87 | +```c |
| 88 | +#ifndef WOLFHAL_BOARD_H |
| 89 | +#define WOLFHAL_BOARD_H |
| 90 | + |
| 91 | +#include <wolfHAL/clock/<family>_clock.h> |
| 92 | +#include <wolfHAL/flash/<family>_flash.h> |
| 93 | +#include <wolfHAL/gpio/<family>_gpio.h> |
| 94 | +#include <wolfHAL/uart/<family>_uart.h> |
| 95 | + |
| 96 | +/* Clock */ |
| 97 | +#define Board_Clock_Init whal_<Family>Clock_Init |
| 98 | +#define Board_Clock_Deinit whal_<Family>Clock_Deinit |
| 99 | +#define Board_Clock_Enable whal_<Family>Clock_Enable |
| 100 | +#define Board_Clock_Disable whal_<Family>Clock_Disable |
| 101 | + |
| 102 | +/* Flash */ |
| 103 | +#define Board_Flash_Init whal_<Family>Flash_Init |
| 104 | +#define Board_Flash_Deinit whal_<Family>Flash_Deinit |
| 105 | +#define Board_Flash_Lock whal_<Family>Flash_Lock |
| 106 | +#define Board_Flash_Unlock whal_<Family>Flash_Unlock |
| 107 | +#define Board_Flash_Write whal_<Family>Flash_Write |
| 108 | +#define Board_Flash_Erase whal_<Family>Flash_Erase |
| 109 | + |
| 110 | +/* GPIO */ |
| 111 | +#define Board_Gpio_Init whal_<Family>Gpio_Init |
| 112 | +#define Board_Gpio_Deinit whal_<Family>Gpio_Deinit |
| 113 | +#define Board_Gpio_Set whal_<Family>Gpio_Set |
| 114 | +#define Board_Gpio_Get whal_<Family>Gpio_Get |
| 115 | + |
| 116 | +/* UART */ |
| 117 | +#define Board_Uart_Init whal_<Family>Uart_Init |
| 118 | +#define Board_Uart_Deinit whal_<Family>Uart_Deinit |
| 119 | +#define Board_Uart_Send whal_<Family>Uart_Send |
| 120 | +#define Board_Uart_Recv whal_<Family>Uart_Recv |
| 121 | + |
| 122 | +#endif /* WOLFHAL_BOARD_H */ |
| 123 | +``` |
| 124 | + |
| 125 | +### 2. `board.c` — Device Instances and Initialization |
| 126 | + |
| 127 | +Define the wolfHAL device instances and implement `hal_init` and `hal_prepare_boot`. |
| 128 | +The file must export `g_wbFlash` (and `g_wbUart` when `DEBUG_UART` is enabled) as |
| 129 | +non-static globals — these are referenced by `hal/wolfhal.c` via `extern`. |
| 130 | + |
| 131 | +```c |
| 132 | +#include "hal.h" |
| 133 | +#include "board.h" |
| 134 | + |
| 135 | +/* Clock controller */ |
| 136 | +whal_Clock g_wbClock = { |
| 137 | + .regmap = { .base = ..., .size = 0x400 }, |
| 138 | + .cfg = &(<family>_clock_cfg) { ... }, |
| 139 | +}; |
| 140 | + |
| 141 | +/* Flash */ |
| 142 | +whal_Flash g_wbFlash = { |
| 143 | + .regmap = { .base = ..., .size = 0x400 }, |
| 144 | + .cfg = &(<family>_flash_cfg) { |
| 145 | + .startAddr = 0x08000000, |
| 146 | + .size = ..., |
| 147 | + }, |
| 148 | +}; |
| 149 | + |
| 150 | +#ifdef DEBUG_UART |
| 151 | +whal_Gpio g_wbGpio = { ... }; |
| 152 | +whal_Uart g_wbUart = { ... }; |
| 153 | +#endif |
| 154 | + |
| 155 | +void hal_init(void) |
| 156 | +{ |
| 157 | + /* Initialize clock tree, flash, and optionally GPIO/UART */ |
| 158 | + Board_Clock_Init(&g_wbClock); |
| 159 | + Board_Flash_Init(&g_wbFlash); |
| 160 | +#ifdef DEBUG_UART |
| 161 | + Board_Gpio_Init(&g_wbGpio); |
| 162 | + Board_Uart_Init(&g_wbUart); |
| 163 | +#endif |
| 164 | +} |
| 165 | + |
| 166 | +void hal_prepare_boot(void) |
| 167 | +{ |
| 168 | +#ifdef DEBUG_UART |
| 169 | + Board_Uart_Deinit(&g_wbUart); |
| 170 | + Board_Gpio_Deinit(&g_wbGpio); |
| 171 | +#endif |
| 172 | + Board_Flash_Deinit(&g_wbFlash); |
| 173 | + Board_Clock_Deinit(&g_wbClock); |
| 174 | +} |
| 175 | +``` |
| 176 | +
|
| 177 | +### 3. `board.mk` — Build Variables |
| 178 | +
|
| 179 | +Provide the build-time configuration: flash offset, linker script, and the wolfHAL |
| 180 | +driver objects needed for your MCU family. |
| 181 | +
|
| 182 | +```makefile |
| 183 | +ARCH_FLASH_OFFSET=0x08000000 |
| 184 | +LSCRIPT_IN=hal/<family>.ld |
| 185 | +
|
| 186 | +WOLFHAL_OBJS+=$(WOLFHAL_ROOT)/src/clock/<family>_clock.o |
| 187 | +WOLFHAL_OBJS+=$(WOLFHAL_ROOT)/src/flash/<family>_flash.o |
| 188 | +ifeq ($(DEBUG_UART),1) |
| 189 | + WOLFHAL_OBJS+=$(WOLFHAL_ROOT)/src/gpio/<family>_gpio.o |
| 190 | + WOLFHAL_OBJS+=$(WOLFHAL_ROOT)/src/uart/<family>_uart.o |
| 191 | +endif |
| 192 | +
|
| 193 | +OBJS+=$(WOLFHAL_OBJS) |
| 194 | +APP_OBJS+=$(WOLFHAL_OBJS) |
| 195 | +
|
| 196 | +ifeq ($(RAM_CODE),1) |
| 197 | + WOLFHAL_FLASH_EXCLUDE_TEXT=*(EXCLUDE_FILE(*<family>_flash.o) .text*) |
| 198 | + WOLFHAL_FLASH_EXCLUDE_RODATA=*(EXCLUDE_FILE(*<family>_flash.o) .rodata*) |
| 199 | + WOLFHAL_FLASH_RAM_SECTIONS=*<family>_flash.o(.text* .rodata*) |
| 200 | +endif |
| 201 | +``` |
| 202 | + |
| 203 | +### 4. Config File |
| 204 | + |
| 205 | +Create `config/examples/wolfhal_<board_name>.config`: |
| 206 | + |
| 207 | +``` |
| 208 | +TARGET=wolfhal |
| 209 | +BOARD=<board_name> |
| 210 | +SIGN=ECC256 |
| 211 | +HASH=SHA256 |
| 212 | +WOLFBOOT_SECTOR_SIZE=0x1000 |
| 213 | +WOLFBOOT_PARTITION_SIZE=0x20000 |
| 214 | +WOLFBOOT_PARTITION_BOOT_ADDRESS=0x08008000 |
| 215 | +WOLFBOOT_PARTITION_UPDATE_ADDRESS=0x08028000 |
| 216 | +WOLFBOOT_PARTITION_SWAP_ADDRESS=0x08048000 |
| 217 | +NVM_FLASH_WRITEONCE=1 |
| 218 | +``` |
| 219 | + |
| 220 | +Adjust partition addresses and sector sizes for your board's flash layout. Optionally |
| 221 | +add `DEBUG_UART=1` to enable UART debug output. |
| 222 | + |
| 223 | +## RAM_CODE |
| 224 | + |
| 225 | +When `RAM_CODE=1` is set, wolfBoot's core flash update functions are placed in RAM |
| 226 | +via the `RAMFUNCTION` attribute. For wolfHAL boards, the `board.mk` defines |
| 227 | +`EXCLUDE_FILE` rules that also place the wolfHAL flash driver into RAM. This ensures |
| 228 | +all flash operations execute from RAM, which is required on MCUs that stall or fault |
| 229 | +when code executes from the same flash bank being programmed. |
| 230 | + |
| 231 | +The linker script uses `@WOLFHAL_FLASH_EXCLUDE_TEXT@`, |
| 232 | +`@WOLFHAL_FLASH_EXCLUDE_RODATA@`, and `@WOLFHAL_FLASH_RAM_SECTIONS@` placeholders |
| 233 | +that are substituted at build time. When `RAM_CODE=1`, these expand to |
| 234 | +`EXCLUDE_FILE` rules that move the flash driver's `.text` and `.rodata` sections from |
| 235 | +flash into the `.data` section (loaded to RAM at startup). When `RAM_CODE` is not |
| 236 | +set, all code remains in flash as normal. |
| 237 | + |
| 238 | +## Test Application |
| 239 | + |
| 240 | +The generic test application (`test-app/app_wolfhal.c`) demonstrates using wolfHAL |
| 241 | +peripherals beyond what the bootloader needs. It initializes GPIO and UART via the |
| 242 | +`Board_*` API, then exercises the wolfBoot update mechanism. |
| 243 | + |
| 244 | +The test app re-uses the board's clock instance via `extern whal_Clock g_wbClock` to |
| 245 | +enable peripheral clocks for its own devices (e.g. GPIO for an LED, UART for serial |
| 246 | +output). |
| 247 | + |
| 248 | +The test-app Makefile compiles its own copy of the board file (`board_<board>.o`) |
| 249 | +with `DEBUG_UART=1` always defined, since the app needs UART and GPIO regardless of |
| 250 | +the bootloader's `DEBUG_UART` setting. |
0 commit comments