wolfBoot/hal/stm32_tz.c

458 lines
13 KiB
C

/* stm32_tz.c
*
* Copyright (C) 2026 wolfSSL Inc.
*
* This file is part of wolfBoot.
*
* wolfBoot is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* wolfBoot is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/
#include <stdint.h>
#include <string.h>
#ifdef TARGET_stm32l5
#include "hal/stm32l5.h"
#endif
#ifdef TARGET_stm32u5
#include "hal/stm32u5.h"
#endif
#if defined(TARGET_stm32h5)
#include "hal/stm32h5.h"
#endif
#include "hal/armv8m_tz.h"
#include "image.h"
#include "hal.h"
#include "target.h"
#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) && (!defined(FLAGS_HOME) || !defined(DISABLE_BACKUP))
static void RAMFUNCTION hal_flash_nonsecure_unlock(void)
{
hal_flash_wait_complete(0);
if ((FLASH_NS_CR & FLASH_CR_LOCK) != 0) {
FLASH_NS_KEYR = FLASH_KEY1;
DMB();
FLASH_NS_KEYR = FLASH_KEY2;
DMB();
}
}
static void RAMFUNCTION hal_flash_nonsecure_lock(void)
{
hal_flash_wait_complete(0);
if ((FLASH_NS_CR & FLASH_CR_LOCK) == 0)
FLASH_NS_CR |= FLASH_CR_LOCK;
}
static int is_range_nonsecure(uint32_t address, int len)
{
#ifndef DUALBANK_SWAP
/* The non secure area begins at the BOOT partition */
uint32_t min = WOLFBOOT_PARTITION_BOOT_ADDRESS;
uint32_t max = FLASH_TOP + 1;
uint32_t end;
if (len < 0)
return 0;
end = (uint32_t)(address + len);
if ((address >= min) && (end <= max))
return 1;
return 0;
#else
/* In this case, the secure area is in the lower side of both banks. */
uint32_t boot_offset = WOLFBOOT_PARTITION_BOOT_ADDRESS - ARCH_FLASH_OFFSET;
uint32_t min1 = WOLFBOOT_PARTITION_BOOT_ADDRESS;
uint32_t max1 = FLASH_BANK2_BASE + 1;
uint32_t min2 = WOLFBOOT_PARTITION_UPDATE_ADDRESS;
uint32_t max2 = FLASH_TOP + 1;
uint32_t end;
(void)boot_offset; /* calculated for reference, but not used */
if (len < 0)
return 0;
end = (uint32_t)(address + len);
if (((address >= min1) && (end <= max1)) ||
((address >= min2) && (end <= max2)) )
return 1;
return 0;
#endif
}
void hal_tz_claim_nonsecure_area(uint32_t address, int len)
{
int page_n, reg_idx;
uint32_t end = address + len;
uint32_t start_page_n;
uint32_t bank = 0;
int pos;
if (!is_range_nonsecure(address, len))
return;
if (address < FLASH_BANK2_BASE) {
start_page_n = (address - ARCH_FLASH_OFFSET) / FLASH_PAGE_SIZE;
bank = 0;
} else {
start_page_n = (address - FLASH_BANK2_BASE) / FLASH_PAGE_SIZE;
bank = 1;
}
page_n = start_page_n;
#ifdef TARGET_stm32h5
/* Take into account current swap configuration */
if ((FLASH_OPTSR_CUR & FLASH_OPTSR_SWAP_BANK) >> 31)
bank = !bank;
#endif
while (address < end) {
reg_idx = page_n / 32;
pos = page_n % 32;
hal_flash_wait_complete(bank);
hal_flash_clear_errors(bank);
if (bank == 0)
FLASH_SECBB1[reg_idx] |= (1u << pos);
else
FLASH_SECBB2[reg_idx] |= (1u << pos);
ISB();
hal_flash_wait_complete(bank);
address += FLASH_PAGE_SIZE;
page_n++;
}
}
#else
#define claim_nonsecure_area(...) do{}while(0)
#endif
#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U)
void hal_tz_release_nonsecure_area(void)
{
#ifndef DUALBANK_SWAP
int i;
/* Set all banks as non-secure */
for (i = 0; i < FLASH_SECBB_NREGS; i++) {
FLASH_SECBB1[i] = 0;
FLASH_SECBB2[i] = 0;
}
#else
uint32_t addr;
int bank_swp = 0;
/* Take into account current swap configuration */
if ((FLASH_OPTSR_CUR & FLASH_OPTSR_SWAP_BANK) >> 31)
bank_swp = 1;
/* Bank 1 */
for(addr = WOLFBOOT_PARTITION_BOOT_ADDRESS;
addr < FLASH_BANK2_BASE; addr += FLASH_PAGE_SIZE) {
uint32_t page_n = (addr - FLASHMEM_ADDRESS_SPACE) / FLASH_PAGE_SIZE;
uint32_t reg_idx = page_n / 32;
uint32_t pos = page_n % 32;
hal_flash_wait_complete(0);
hal_flash_clear_errors(0);
if (!bank_swp)
FLASH_SECBB1[reg_idx] &= ~( 1 << pos);
else
FLASH_SECBB2[reg_idx] &= ~( 1 << pos);
ISB();
hal_flash_wait_complete(0);
}
/* Bank 2 */
for(addr = WOLFBOOT_PARTITION_UPDATE_ADDRESS;
addr < FLASH_TOP; addr += FLASH_PAGE_SIZE) {
uint32_t page_n = (addr - FLASH_BANK2_BASE) / FLASH_PAGE_SIZE;
uint32_t reg_idx = page_n / 32;
uint32_t pos = page_n % 32;
hal_flash_wait_complete(1);
hal_flash_clear_errors(1);
if (!bank_swp)
FLASH_SECBB2[reg_idx] &= ~( 1 << pos);
else
FLASH_SECBB1[reg_idx] &= ~( 1 << pos);
ISB();
hal_flash_wait_complete(1);
}
#endif
}
#else
#define release_nonsecure_area(...) do{}while(0)
#endif
#ifdef TARGET_stm32h5
#define GTZC1_BASE (0x50032400)
#define GTZC1_TZSC (*(volatile uint32_t *)(GTZC1_BASE + 0x00))
#define GTZC1_TZIC (*(volatile uint32_t *)(GTZC1_BASE + 0x0400))
#define GTZC1_MPCBB1_SECCFGR ((volatile uint32_t *)(GTZC1_BASE + 0x0800 + 0x100))
#define GTZC1_MPCBB2_SECCFGR ((volatile uint32_t *)(GTZC1_BASE + 0x0C00 + 0x100))
#define GTZC1_MPCBB3_SECCFGR ((volatile uint32_t *)(GTZC1_BASE + 0x1000 + 0x100))
#define SET_GTZC1_MPCBBx_SECCFGR_VCTR(bank,n,val) \
(*((volatile uint32_t *)(GTZC1_MPCBB##bank##_SECCFGR) + n )) = val
/* PRIVCFGR_VCTR sits 0x100 bytes (0x40 words) after SECCFGR_VCTR in each
* MPCBB block. */
#define GTZC_MPCBB_PRIVCFGR_WORD_OFFSET (0x100u / sizeof(uint32_t))
#define SET_GTZC1_MPCBBx_PRIVCFGR_VCTR(bank,n,val) \
(*((volatile uint32_t *)(GTZC1_MPCBB##bank##_SECCFGR) + \
GTZC_MPCBB_PRIVCFGR_WORD_OFFSET + n )) = val
void hal_gtzc_init(void)
{
int i;
/* One bit in the bitmask: 512B
* 1: Secure access only to block
* 0: Non-secure access only to block
*/
/* Configure SRAM1 as secure (Low 256 KB).
* wolfBoot links its own RAM/RAM_HEAP into the SRAM1 secure alias
* (0x30000000-0x3003FFFF, see hal/stm32h5.ld), so SRAM1 must stay
* secure for wolfBoot's .bss/stack/heap to remain accessible. */
for (i = 0; i < 16; i++) {
SET_GTZC1_MPCBBx_SECCFGR_VCTR(1, i, 0xFFFFFFFF);
}
/* Configure SRAM2 as non-secure (64 KB) and unprivileged. SRAM2 is
* the ETH DMA arena: the NS wolfIP app pins its ETH descriptors and
* buffers (.eth_buffers) into SRAM2. wolfBoot does not use SRAM2.
* The PRIVCFGR clear is required because the H5 ETH DMA master is
* unprivileged; with the reset default (PRIVCFGR=0xFFFFFFFF) the
* DMA's descriptor/buffer reads from SRAM2 raise illegal-access
* (TZIC1_SR4 bit 26) and the channel suspends with TPS=6 (TBU). */
for (i = 0; i < 4; i++) {
SET_GTZC1_MPCBBx_SECCFGR_VCTR(2, i, 0x0);
SET_GTZC1_MPCBBx_PRIVCFGR_VCTR(2, i, 0x0);
}
/* Configure SRAM3 as non-secure (320 KB) but PRIVILEGED. The NS CPU
* runs privileged (Thread mode) and can use SRAM3 freely; only the
* unprivileged ETH DMA master needs unprivileged RAM, and its
* descriptors/buffers are pinned to SRAM2 (.eth_buffers). Leaving
* SRAM3 privileged lets a future NS OS own the unprivileged
* boundary. */
for (i = 0; i < 20; i++) {
SET_GTZC1_MPCBBx_SECCFGR_VCTR(3, i, 0x0);
}
}
#elif defined(TARGET_stm32u5)
#define GTZC_MPCBB1_S_BASE (0x50032C00)
#define GTZC_MPCBB1_S_VCTR_BASE (GTZC_MPCBB1_S_BASE + 0x100)
#define GTZC_MPCBB2_S_BASE (0x50033000)
#define GTZC_MPCBB2_S_VCTR_BASE (GTZC_MPCBB2_S_BASE + 0x100)
#define SET_GTZC_MPCBBx_S_VCTR(bank,n,val) \
(*((volatile uint32_t *)(GTZC_MPCBB##bank##_S_VCTR_BASE ) + n ))= val
void hal_gtzc_init(void)
{
int i;
/* One bit in the bitmask: 512B (STM32U5) */
/* Configure SRAM1 lower 128 KB as secure (0x20000000 - 0x2001FFFF). */
for (i = 0; i < 8; i++) {
SET_GTZC_MPCBBx_S_VCTR(1, i, 0xFFFFFFFF);
}
/* Configure SRAM1 upper 128 KB as non-secure (0x20020000 - 0x2003FFFF). */
for (i = 8; i < 16; i++) {
SET_GTZC_MPCBBx_S_VCTR(1, i, 0x0);
}
/* Configure SRAM2 as non-secure (0x20030000 - 0x2003FFFF). */
for (i = 0; i < 4; i++) {
SET_GTZC_MPCBBx_S_VCTR(2, i, 0x0);
}
}
#else
#define GTZC_MPCBB1_S_BASE (0x50032C00)
#define GTZC_MPCBB1_S_VCTR_BASE (GTZC_MPCBB1_S_BASE + 0x100)
#define GTZC_MPCBB2_S_BASE (0x50033000)
#define GTZC_MPCBB2_S_VCTR_BASE (GTZC_MPCBB2_S_BASE + 0x100)
#define SET_GTZC_MPCBBx_S_VCTR(bank,n,val) \
(*((volatile uint32_t *)(GTZC_MPCBB##bank##_S_VCTR_BASE ) + n ))= val
void hal_gtzc_init(void)
{
int i;
/* One bit in the bitmask: 256B */
/* Configure lower half of total RAM as secure
* 0x3000 0000 : 0x3001 FFFF - 128KB
*/
for (i = 0; i < 16; i++) {
SET_GTZC_MPCBBx_S_VCTR(1, i, 0xFFFFFFFF);
}
/* Configure high portion of SRAM1 as non-secure
* 0x2002 0000 : 0x2002 FFFF - 64 KB
*/
for (i = 16; i < 24; i++) {
SET_GTZC_MPCBBx_S_VCTR(1, i, 0x0);
}
/* Configure SRAM2 as non-secure
* 0x2003 0000 : 0x2003 FFFF - 64 KB
*/
for (i = 0; i < 8; i++) {
SET_GTZC_MPCBBx_S_VCTR(2, i, 0x0);
}
}
#endif
#ifdef TARGET_stm32h5
void hal_tz_sau_init(void)
{
/* SAU is set up before staging. Define non-secure windows only. */
/* Non-secure callable: NSC functions area */
sau_init_region(0, WOLFBOOT_NSC_ADDRESS,
WOLFBOOT_NSC_ADDRESS + WOLFBOOT_NSC_SIZE - 1, 1);
/* Non-secure flash alias (boot partition only) */
sau_init_region(1, WOLFBOOT_PARTITION_BOOT_ADDRESS,
WOLFBOOT_PARTITION_BOOT_ADDRESS + WOLFBOOT_PARTITION_SIZE - 1, 0);
/* Non-secure RAM region: SRAM2 (64 KB) + SRAM3 (320 KB).
* Lower bound widened from 0x20050000 to 0x20040000 to cover SRAM2,
* which hal_gtzc_init also leaves non-secure. SRAM1 (0x20000000-
* 0x2003FFFF) stays secure for wolfBoot's own RAM/heap. */
sau_init_region(2, 0x20040000, 0x2009FFFF, 0);
/* Non-secure: internal peripherals */
sau_init_region(3, 0x40000000, 0x4FFFFFFF, 0);
/* Set as non-secure: OTP + RO area */
sau_init_region(4, 0x08FFF000, 0x08FFFFFF, 0);
/* Enable SAU */
SAU_CTRL = SAU_INIT_CTRL_ENABLE;
/* Enable securefault handler */
SCB_SHCSR |= SCB_SHCSR_SECUREFAULT_EN;
}
#else
void hal_tz_sau_init(void)
{
/* Non-secure callable: NSC functions area */
sau_init_region(0, WOLFBOOT_NSC_ADDRESS,
WOLFBOOT_NSC_ADDRESS + WOLFBOOT_NSC_SIZE - 1, 1);
/* Non-secure: application flash area (boot partition only) */
sau_init_region(1, WOLFBOOT_PARTITION_BOOT_ADDRESS,
WOLFBOOT_PARTITION_BOOT_ADDRESS + WOLFBOOT_PARTITION_SIZE - 1,
0);
/* Non-secure RAM region in SRAM1/SRAM2 */
sau_init_region(2, 0x20020000, 0x2003FFFF, 0);
/* Non-secure: internal peripherals */
sau_init_region(3, 0x40000000, 0x4FFFFFFF, 0);
/* Enable SAU */
SAU_CTRL = SAU_INIT_CTRL_ENABLE;
/* Enable securefault handler */
SCB_SHCSR |= SCB_SHCSR_SECUREFAULT_EN;
}
#endif
#ifdef WOLFCRYPT_SECURE_MODE
#define TRNG_BASE 0x520C0800
#define TRNG_CR *((volatile uint32_t *)(TRNG_BASE + 0x00))
#define TRNG_SR *((volatile uint32_t *)(TRNG_BASE + 0x04))
#define TRNG_DR *((volatile uint32_t *)(TRNG_BASE + 0x08))
#define TRNG_SR_DRDY (1 << 0)
#define TRNG_CR_RNGEN (1 << 2)
#define TRNG_CR_CONFIG3_SHIFT (8)
#define TRNG_CR_CONFIG2_SHIFT (13)
#define TRNG_CR_CLKDIV_SHIFT (16)
#define TRNG_CR_CONFIG1_SHIFT (20)
#define TRNG_CR_CONDRST (1 << 30)
static void hsi48_on(void)
{
#ifdef TARGET_stm32l5
RCC_CRRCR |= RCC_CRRCR_HSI48ON;
while ((RCC_CRRCR & RCC_CRRCR_HSI48RDY) == 0)
;
#else /* U5 and H5 */
RCC_CR |= RCC_CR_HSI48ON;
while ((RCC_CR & RCC_CR_HSI48RDY) == 0)
;
#endif
}
void hal_trng_init(void)
{
uint32_t reg_val;
hsi48_on();
RCC_AHB2_CLOCK_ER |= TRNG_AHB2_CLOCK_ER;
reg_val = TRNG_CR;
reg_val &= ~(0x1F << TRNG_CR_CONFIG1_SHIFT);
reg_val &= ~(0x7 << TRNG_CR_CLKDIV_SHIFT);
reg_val &= ~(0x3 << TRNG_CR_CONFIG2_SHIFT);
reg_val &= ~(0x7 << TRNG_CR_CONFIG3_SHIFT);
reg_val |= 0x0F << TRNG_CR_CONFIG1_SHIFT;
reg_val |= 0x0D << TRNG_CR_CONFIG3_SHIFT;
#ifdef TARGET_stm32u5 /* RM0456 40.6.2 */
reg_val |= 0x06 << TRNG_CR_CLKDIV_SHIFT;
#endif
TRNG_CR = TRNG_CR_CONDRST | reg_val;
while ((TRNG_CR & TRNG_CR_CONDRST) == 0)
;
TRNG_CR = reg_val | TRNG_CR_RNGEN;
while ((TRNG_SR & TRNG_SR_DRDY) == 0)
;
}
/* Never used (RNG keeps running when in secure-mode) */
void hal_trng_fini(void)
{
TRNG_CR &= (~TRNG_CR_RNGEN);
}
int hal_trng_get_entropy(unsigned char *out, unsigned len)
{
unsigned i;
uint32_t rand_seed = 0;
for (i = 0; i < len; i += 4)
{
while ((TRNG_SR & TRNG_SR_DRDY) == 0)
;
rand_seed = TRNG_DR;
if ((len - i) < 4)
memcpy(out + i, &rand_seed, len - i);
else
memcpy(out + i, &rand_seed, 4);
}
return 0;
}
#endif