1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-12-18 04:18:10 +00:00

feat(core): properly utilize trustzone in kernel and core app

[no changelog]
This commit is contained in:
cepetr 2024-10-31 09:23:37 +01:00 committed by cepetr
parent c0829ec364
commit b174237684
16 changed files with 488 additions and 72 deletions

View File

@ -255,7 +255,7 @@ int main(void) {
#ifdef STM32U5
tamper_init();
trustzone_init_boardloader();
tz_init_boardloader();
#endif
secret_init();

View File

@ -49,6 +49,7 @@
#include "systick.h"
#include "tamper.h"
#include "touch.h"
#include "trustzone.h"
#include "unit_properties.h"
#ifdef USE_OPTIGA
@ -182,24 +183,26 @@ extern uint32_t _coreapp_clear_ram_1_size;
// Initializes coreapp applet
static void coreapp_init(applet_t *applet) {
applet_header_t *coreapp_header =
(applet_header_t *)COREAPP_CODE_ALIGN(KERNEL_START + KERNEL_SIZE);
const uint32_t CODE1_START = COREAPP_CODE_ALIGN(KERNEL_START + KERNEL_SIZE);
#ifdef FIRMWARE_P1_START
const uint32_t CODE1_END = FIRMWARE_P1_START + FIRMWARE_P1_MAXSIZE;
#else
const uint32_t CODE1_END = FIRMWARE_START + FIRMWARE_MAXSIZE;
#endif
applet_header_t *coreapp_header = (applet_header_t *)CODE1_START;
applet_layout_t coreapp_layout = {
.data1.start = (uint32_t)&_coreapp_clear_ram_0_start,
.data1.size = (uint32_t)&_coreapp_clear_ram_0_size,
.data2.start = (uint32_t)&_coreapp_clear_ram_1_start,
.data2.size = (uint32_t)&_coreapp_clear_ram_1_size,
#ifdef FIRMWARE_P1_START
.code1.start = FIRMWARE_P1_START + KERNEL_SIZE,
.code1.size = FIRMWARE_P1_MAXSIZE - KERNEL_SIZE,
.code1.start = CODE1_START,
.code1.size = CODE1_END - CODE1_START,
#ifdef FIRMWARE_P2_START
.code2.start = FIRMWARE_P2_START,
.code2.size = FIRMWARE_P2_MAXSIZE,
#else
.code1.start = FIRMWARE_START + KERNEL_SIZE,
.code1.size = FIRMWARE_MAXSIZE - KERNEL_SIZE,
.code2.start = 0,
.code2.size = 0,
#endif
};
@ -214,7 +217,8 @@ static void show_rsod(const systask_postmortem_t *pminfo) {
// Reset and run the coreapp in RSOD mode
if (applet_reset(&coreapp, 1, pminfo, sizeof(systask_postmortem_t))) {
systask_yield_to(&coreapp.task);
// Run the applet & wait for it to finish
applet_run(&coreapp);
if (coreapp.task.pminfo.reason == TASK_TERM_REASON_EXIT) {
// If the RSOD was shown successfully, proceed to shutdown
@ -257,6 +261,11 @@ int main(void) {
// Initialize system's core services
system_init(&kernel_panic);
#ifdef STM32U5
// Configure unprivileged access for the coreapp
tz_init_kernel();
#endif
// Initialize hardware drivers
drivers_init();
@ -269,7 +278,8 @@ int main(void) {
error_shutdown("Cannot start coreapp");
}
systask_yield_to(&coreapp.task);
// Run the applet & wait for it to finish
applet_run(&coreapp);
// Coreapp crashed, show RSOD
show_rsod(&coreapp.task.pminfo);

View File

@ -75,13 +75,16 @@ void applet_init(applet_t* applet, applet_header_t* header,
// Resets the applet and prepares it for execution from its entry point.
//
// Applet does not start immediately, it needs to be scheduled by
// `systask_yield_to(&applet->task)` after calling this function.
// Applet does not start immediately, it needs to be run by
// `applet_run()` after calling this function.
//
// Returns `true` if the applet was successfully reset.
bool applet_reset(applet_t* applet, uint32_t cmd, const void* arg,
size_t arg_size);
// Runs the applet and waits until it finishes.
void applet_run(applet_t* applet);
// Returns the currently active applet.
//
// Returns `NULL` if no applet is currently active.

View File

@ -17,12 +17,16 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include STM32_HAL_H
#include <string.h>
#include "applet.h"
#include "display.h"
#include "mpu.h"
#include "rng.h"
#include "systask.h"
#include "trustzone.h"
#ifdef SYSCALL_DISPATCH
@ -70,6 +74,33 @@ bool applet_reset(applet_t* applet, uint32_t cmd, const void* arg,
arg3);
}
#ifdef STM32U5
// Sets unprivileged access to the applet memory regions
// and allows applet to use some specific peripherals.
static void applet_set_unpriv(applet_t* applet, bool unpriv) {
applet_layout_t* layout = &applet->layout;
tz_set_sram_unpriv(layout->data1.start, layout->data1.size, unpriv);
tz_set_sram_unpriv(layout->data2.start, layout->data2.size, unpriv);
tz_set_flash_unpriv(layout->code1.start, layout->code1.size, unpriv);
tz_set_flash_unpriv(layout->code2.start, layout->code2.size, unpriv);
display_set_unpriv_access(unpriv);
}
#endif // STM32U5
void applet_run(applet_t* applet) {
#ifdef STM32U5
applet_set_unpriv(applet, true);
#endif
systask_yield_to(&applet->task);
#ifdef STM32U5
applet_set_unpriv(applet, false);
#endif
}
applet_t* applet_active(void) {
systask_t* task = systask_active();

View File

@ -33,7 +33,9 @@
#include "gfx_bitblt.h"
#include "irq.h"
#include "mpu.h"
#include "sizedefs.h"
#include "systemview.h"
#include "trustzone.h"
#ifndef BOARDLOADER
#include "bg_copy.h"
@ -48,20 +50,47 @@
// The following code supports only 1 or 2 frame buffers
_Static_assert(FRAME_BUFFER_COUNT == 1 || FRAME_BUFFER_COUNT == 2);
// Hardware requires physical frame buffer alignment
#ifdef USE_TRUSTZONE
#define PHYSICAL_FRAME_BUFFER_ALIGNMENT TZ_SRAM_ALIGNMENT
#else
#define PHYSICAL_FRAME_BUFFER_ALIGNMENT 32
#endif
// Size of the physical frame buffer in bytes
#define PHYSICAL_FRAME_BUFFER_SIZE (DISPLAY_RESX * DISPLAY_RESY * 2)
#define PHYSICAL_FRAME_BUFFER_SIZE \
ALIGN_UP_CONST(DISPLAY_RESX *DISPLAY_RESY * 2, \
PHYSICAL_FRAME_BUFFER_ALIGNMENT)
// Physical frame buffers in internal SRAM memory.
// Both frame buffers layes in the fixed addresses that
// are shared between bootloaders and the firmware.
static __attribute__((section(".fb1")))
ALIGN_32BYTES(uint8_t physical_frame_buffer_0[PHYSICAL_FRAME_BUFFER_SIZE]);
static
__attribute__((section(".fb1"), aligned(PHYSICAL_FRAME_BUFFER_ALIGNMENT)))
uint8_t physical_frame_buffer_0[PHYSICAL_FRAME_BUFFER_SIZE];
#if (FRAME_BUFFER_COUNT > 1)
static __attribute__((section(".fb2")))
ALIGN_32BYTES(uint8_t physical_frame_buffer_1[PHYSICAL_FRAME_BUFFER_SIZE]);
static
__attribute__((section(".fb2"), aligned(PHYSICAL_FRAME_BUFFER_ALIGNMENT)))
uint8_t physical_frame_buffer_1[PHYSICAL_FRAME_BUFFER_SIZE];
#endif
#ifdef STM32U5
void display_set_unpriv_access(bool unpriv) {
tz_set_sram_unpriv((uint32_t)physical_frame_buffer_0,
PHYSICAL_FRAME_BUFFER_SIZE, unpriv);
#if (FRAME_BUFFER_COUNT > 1)
tz_set_sram_unpriv((uint32_t)physical_frame_buffer_1,
PHYSICAL_FRAME_BUFFER_SIZE, unpriv);
#endif
#ifdef USE_DMA2D
tz_set_dma2d_unpriv(unpriv);
#endif
}
#endif // STM32U5
// Returns the pointer to the physical frame buffer (0.. FRAME_BUFFER_COUNT-1)
// Returns NULL if the framebuffer index is out of range.
static uint8_t *get_fb_ptr(uint32_t index) {

View File

@ -26,6 +26,8 @@
#include STM32_HAL_H
#include "mpu.h"
#include "sizedefs.h"
#include "trustzone.h"
#include "xdisplay.h"
#ifdef USE_CONSUMPTION_MASK
@ -37,14 +39,23 @@
#error "Incompatible display resolution"
#endif
// Hardware requires physical frame buffer alignment
#ifdef USE_TRUSTZONE
#define PHYSICAL_FRAME_BUFFER_ALIGNMENT TZ_SRAM_ALIGNMENT
#else
#define PHYSICAL_FRAME_BUFFER_ALIGNMENT 4
#endif
// This file implements display driver for monochromatic display V-2864KSWEG01
// with 128x64 resolution connected to CPU via SPI interface.
//
// This type of display is used with T3B1 model (Trezor TS3)
#define FRAME_BUFFER_SIZE \
ALIGN_UP_CONST(DISPLAY_RESX *DISPLAY_RESY, PHYSICAL_FRAME_BUFFER_ALIGNMENT)
#define FRAME_BUFFER_SIZE (DISPLAY_RESX * DISPLAY_RESY)
__attribute__((section(".fb1"))) uint8_t g_framebuf[FRAME_BUFFER_SIZE];
static
__attribute__((section(".fb1"), aligned(PHYSICAL_FRAME_BUFFER_ALIGNMENT)))
uint8_t g_framebuf[FRAME_BUFFER_SIZE];
// Display driver context.
typedef struct {
@ -316,6 +327,12 @@ void display_deinit(display_content_mode_t mode) {
drv->initialized = false;
}
#ifdef STM32U5
void display_set_unpriv_access(bool unpriv) {
tz_set_sram_unpriv((uint32_t)g_framebuf, FRAME_BUFFER_SIZE, unpriv);
}
#endif // STM32U5
int display_set_backlight(int level) {
display_driver_t *drv = &g_display_driver;

View File

@ -104,9 +104,9 @@ void bg_copy_start_const_out_8(const uint8_t *src, uint8_t *dst, size_t size,
DMA_Handle.Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;
DMA_Handle.Init.Mode = DMA_NORMAL;
HAL_DMA_Init(&DMA_Handle);
HAL_DMA_ConfigChannelAttributes(&DMA_Handle, DMA_CHANNEL_SEC |
DMA_CHANNEL_SRC_SEC |
DMA_CHANNEL_DEST_SEC);
HAL_DMA_ConfigChannelAttributes(
&DMA_Handle, DMA_CHANNEL_PRIV | DMA_CHANNEL_SEC | DMA_CHANNEL_SRC_SEC |
DMA_CHANNEL_DEST_SEC);
NVIC_SetPriority(GPDMA1_Channel0_IRQn, IRQ_PRI_NORMAL);
NVIC_EnableIRQ(GPDMA1_Channel0_IRQn);

View File

@ -81,9 +81,9 @@ void consumption_mask_init(void) {
dma_handle.InitLinkedList.LinkedListMode = DMA_LINKEDLIST_CIRCULAR;
HAL_DMAEx_List_Init(&dma_handle);
HAL_DMA_ConfigChannelAttributes(&dma_handle, DMA_CHANNEL_SEC |
DMA_CHANNEL_SRC_SEC |
DMA_CHANNEL_DEST_SEC);
HAL_DMA_ConfigChannelAttributes(
&dma_handle, DMA_CHANNEL_PRIV | DMA_CHANNEL_SEC | DMA_CHANNEL_SRC_SEC |
DMA_CHANNEL_DEST_SEC);
/* DMA node configuration declaration */
DMA_NodeConfTypeDef pNodeConfig = {0};

View File

@ -37,9 +37,9 @@ void hash_processor_init(void) {
DMA_Handle.Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;
DMA_Handle.Init.Mode = DMA_NORMAL;
HAL_DMA_Init(&DMA_Handle);
HAL_DMA_ConfigChannelAttributes(&DMA_Handle, DMA_CHANNEL_SEC |
DMA_CHANNEL_SRC_SEC |
DMA_CHANNEL_DEST_SEC);
HAL_DMA_ConfigChannelAttributes(
&DMA_Handle, DMA_CHANNEL_PRIV | DMA_CHANNEL_SEC | DMA_CHANNEL_SRC_SEC |
DMA_CHANNEL_DEST_SEC);
DMA_Handle.Parent = &hhash;

View File

@ -25,6 +25,7 @@
#include "irq.h"
#include "model.h"
#include "mpu.h"
#include "sizedefs.h"
#include "stm32u5xx_ll_cortex.h"
@ -80,6 +81,15 @@ static inline uint32_t mpu_permission_lookup(bool write, bool unpriv) {
#define MPUX_FLAG_YES 1
#define SET_REGION(region, start, size, type, write, unpriv) \
do { \
ENSURE_ALIGNMENT(start, 32); \
ENSURE_ALIGNMENT(size, 32); \
SET_REGRUN(region, start, size, type, write, unpriv); \
} while (0)
// `SET_REGION` variant without static assert that can be used when
// start or size are not compile-time constants
#define SET_REGRUN(region, start, size, type, write, unpriv) \
do { \
uint32_t _type = MPUX_TYPE_##type; \
uint32_t _write = MPUX_FLAG_##write; \
@ -229,9 +239,9 @@ static void mpu_init_fixed_regions(void) {
#endif
#if defined(KERNEL)
// REGION ADDRESS SIZE TYPE WRITE UNPRIV
SET_REGION( 0, KERNEL_FLASH_START, KERNEL_FLASH_SIZE, FLASH_CODE, NO, NO ); // Kernel Code
SET_REGRUN( 0, KERNEL_FLASH_START, KERNEL_FLASH_SIZE, FLASH_CODE, NO, NO ); // Kernel Code
SET_REGION( 1, KERNEL_RAM_START, KERNEL_RAM_SIZE, SRAM, YES, NO ); // Kernel RAM
SET_REGION( 2, COREAPP_FLASH_START, COREAPP_FLASH_SIZE, FLASH_CODE, NO, YES ); // CoreApp Code
SET_REGRUN( 2, COREAPP_FLASH_START, COREAPP_FLASH_SIZE, FLASH_CODE, NO, YES ); // CoreApp Code
SET_REGION( 3, COREAPP_RAM1_START, COREAPP_RAM1_SIZE, SRAM, YES, YES ); // CoraApp RAM
#ifdef STM32U585xx
SET_REGION( 4, COREAPP_RAM2_START, COREAPP_RAM2_SIZE, SRAM, YES, YES ); // CoraAPP RAM2
@ -327,7 +337,7 @@ mpu_mode_t mpu_reconfig(mpu_mode_t mode) {
break;
case MPU_MODE_APP:
if (drv->unpriv_fb_addr != 0) {
SET_REGION( 5, drv->unpriv_fb_addr, drv->unpriv_fb_size, SRAM, YES, YES ); // Frame buffer
SET_REGRUN( 5, drv->unpriv_fb_addr, drv->unpriv_fb_size, SRAM, YES, YES ); // Frame buffer
} else {
DIS_REGION( 5 );
}
@ -368,7 +378,7 @@ mpu_mode_t mpu_reconfig(mpu_mode_t mode) {
SET_REGION( 6, ASSETS_START, ASSETS_MAXSIZE, FLASH_DATA, YES, NO );
break;
case MPU_MODE_SAES:
SET_REGION( 6, KERNEL_FLASH_U_START, KERNEL_FLASH_U_SIZE,FLASH_CODE, NO, YES ); // Unprivileged kernel flash
SET_REGRUN( 6, KERNEL_FLASH_U_START, KERNEL_FLASH_U_SIZE,FLASH_CODE, NO, YES ); // Unprivileged kernel flash
break;
case MPU_MODE_APP:
SET_REGION( 6, ASSETS_START, ASSETS_MAXSIZE, FLASH_DATA, NO, YES );

View File

@ -26,6 +26,7 @@
#include <string.h>
#include "model.h"
#include "syscall.h"
#include "trustzone.h"
#include "memzero.h"
@ -143,6 +144,8 @@ saes_invoke(void) {
extern uint8_t sram_u_start;
extern uint8_t sram_u_end;
extern uint8_t _uflash_start;
extern uint8_t _uflash_end;
secbool unpriv_encrypt(const uint8_t* input, size_t size, uint8_t* output,
secure_aes_keysel_t key) {
@ -159,6 +162,24 @@ secbool unpriv_encrypt(const uint8_t* input, size_t size, uint8_t* output,
uint32_t basepri = __get_BASEPRI();
__set_BASEPRI(IRQ_PRI_HIGHEST + 1);
uint32_t unpriv_ram_start = (uint32_t)&sram_u_start;
uint32_t unpriv_ram_size = &sram_u_end - &sram_u_start;
// `saes_invoke()` function is too small to justigy placing it in a region
// that is aligned to TZ_FLASH_ALIGNMENT (8KB), as doing so would result
// in significant wasted space. Therefore, we need to align the flash
// addresses to the nearest lower and the nearest higher multiple of
// TZ_FLASH_ALIGNMENT.
uint32_t unpriv_flash_start =
ALIGN_DOWN((uint32_t)&_uflash_start, TZ_FLASH_ALIGNMENT);
uint32_t unpriv_flash_size =
ALIGN_UP((uint32_t)&_uflash_end, TZ_FLASH_ALIGNMENT) - unpriv_flash_start;
tz_set_sram_unpriv(unpriv_ram_start, unpriv_ram_size, true);
tz_set_flash_unpriv(unpriv_flash_start, unpriv_flash_size, true);
tz_set_saes_unpriv(true);
tz_set_tamper_unpriv(true);
mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_SAES);
memset(&sram_u_start, 0, &sram_u_end - &sram_u_start);
@ -183,6 +204,11 @@ secbool unpriv_encrypt(const uint8_t* input, size_t size, uint8_t* output,
mpu_reconfig(mpu_mode);
tz_set_sram_unpriv(unpriv_ram_start, unpriv_ram_size, false);
tz_set_flash_unpriv(unpriv_flash_start, unpriv_flash_size, false);
tz_set_saes_unpriv(false);
tz_set_tamper_unpriv(false);
__set_BASEPRI(basepri);
NVIC_SetPriority(SVCall_IRQn, prev_svc_prio);

View File

@ -17,12 +17,16 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <trustzone.h>
#include STM32_HAL_H
#include "irq.h"
#ifdef BOARDLOADER
#include <stddef.h>
#include "common.h"
#include "image.h"
#include "irq.h"
#include "model.h"
#include "sizedefs.h"
#include "trustzone.h"
#define SAU_INIT_CTRL_ENABLE 1
#define SAU_INIT_CTRL_ALLNS 0
@ -32,7 +36,7 @@
SAU->RLAR = ((end) & SAU_RLAR_LADDR_Msk) | \
(((sec) << SAU_RLAR_NSC_Pos) & SAU_RLAR_NSC_Msk) | 1U
static void trustzone_configure_sau(void) {
static void tz_configure_sau(void) {
SAU_INIT_REGION(0, 0x0BF90000, 0x0BFA8FFF, 0); // OTP etc
SAU->CTRL =
@ -41,7 +45,7 @@ static void trustzone_configure_sau(void) {
}
// Configure ARMCortex-M33 SCB and FPU security
static void trustzone_configure_arm(void) {
static void tz_configure_arm(void) {
// Enable FPU in both secure and non-secure modes
SCB->NSACR |= SCB_NSACR_CP10_Msk | SCB_NSACR_CP11_Msk;
@ -54,7 +58,7 @@ static void trustzone_configure_arm(void) {
}
// Configure SRAM security
static void trustzone_configure_sram(void) {
static void tz_configure_sram(void) {
MPCBB_ConfigTypeDef mpcbb = {0};
// No exceptions on illegal access
@ -64,17 +68,17 @@ static void trustzone_configure_sram(void) {
// Set configuration as unlocked
mpcbb.AttributeConfig.MPCBB_LockConfig_array[0] = 0x00000000U;
// Set all blocks secured & unprivileged
// Set all blocks secured & privileged
for (int index = 0; index < GTZC_MPCBB_NB_VCTR_REG_MAX; index++) {
mpcbb.AttributeConfig.MPCBB_SecConfig_array[index] = 0xFFFFFFFFU;
mpcbb.AttributeConfig.MPCBB_PrivConfig_array[index] = 0x00000000U;
mpcbb.AttributeConfig.MPCBB_PrivConfig_array[index] = 0xFFFFFFFFU;
}
HAL_GTZC_MPCBB_ConfigMem(SRAM1_BASE, &mpcbb);
HAL_GTZC_MPCBB_ConfigMem(SRAM2_BASE, &mpcbb);
HAL_GTZC_MPCBB_ConfigMem(SRAM3_BASE, &mpcbb);
HAL_GTZC_MPCBB_ConfigMem(SRAM4_BASE, &mpcbb);
#if defined STM32U5A9xx | defined STM32U5G9xx
#if defined STM32U5A9xx || defined STM32U5G9xx
HAL_GTZC_MPCBB_ConfigMem(SRAM5_BASE, &mpcbb);
#endif
#if defined STM32U5G9xx
@ -82,13 +86,13 @@ static void trustzone_configure_sram(void) {
#endif
}
static void trustzone_configure_fsmc(void) {
static void tz_configure_fsmc(void) {
__HAL_RCC_FMC_CLK_ENABLE();
MPCWM_ConfigTypeDef mpcwm = {0};
mpcwm.AreaId = GTZC_TZSC_MPCWM_ID1;
mpcwm.AreaStatus = ENABLE;
mpcwm.Attribute = GTZC_TZSC_MPCWM_REGION_SEC;
mpcwm.Attribute = GTZC_TZSC_MPCWM_REGION_SEC | GTZC_TZSC_MPCWM_REGION_PRIV;
mpcwm.Length = 128 * 1024;
mpcwm.Offset = 0;
mpcwm.Lock = GTZC_TZSC_MPCWM_LOCK_OFF;
@ -96,10 +100,10 @@ static void trustzone_configure_fsmc(void) {
}
// Configure FLASH security
static void trustzone_configure_flash(void) {
static void tz_configure_flash(void) {
FLASH_BBAttributesTypeDef flash_bb = {0};
// Set all blocks as secured
// Set all blocks as secured & privileged
for (int index = 0; index < FLASH_BLOCKBASED_NB_REG; index++) {
flash_bb.BBAttributes_array[index] = 0xFFFFFFFF;
}
@ -107,34 +111,39 @@ static void trustzone_configure_flash(void) {
flash_bb.Bank = FLASH_BANK_1;
flash_bb.BBAttributesType = FLASH_BB_SEC;
HAL_FLASHEx_ConfigBBAttributes(&flash_bb);
flash_bb.BBAttributesType = FLASH_BB_PRIV;
HAL_FLASHEx_ConfigBBAttributes(&flash_bb);
flash_bb.Bank = FLASH_BANK_2;
flash_bb.BBAttributesType = FLASH_BB_SEC;
HAL_FLASHEx_ConfigBBAttributes(&flash_bb);
flash_bb.BBAttributesType = FLASH_BB_PRIV;
HAL_FLASHEx_ConfigBBAttributes(&flash_bb);
}
void trustzone_init_boardloader(void) {
void tz_init_boardloader(void) {
// Configure ARM SCB/FBU security
trustzone_configure_arm();
tz_configure_arm();
// Configure SAU security attributes
trustzone_configure_sau();
tz_configure_sau();
// Enable GTZC (Global Trust-Zone Controller) peripheral clock
__HAL_RCC_GTZC1_CLK_ENABLE();
__HAL_RCC_GTZC2_CLK_ENABLE();
// Configure SRAM security attributes
trustzone_configure_sram();
tz_configure_sram();
// Configure FLASH security attributes
trustzone_configure_flash();
tz_configure_flash();
// Configure FSMC security attributes
trustzone_configure_fsmc();
tz_configure_fsmc();
// Make all peripherals secure
HAL_GTZC_TZSC_ConfigPeriphAttributes(GTZC_PERIPH_ALL, GTZC_TZSC_PERIPH_SEC);
// Make all peripherals secure & privileged
HAL_GTZC_TZSC_ConfigPeriphAttributes(
GTZC_PERIPH_ALL, GTZC_TZSC_PERIPH_SEC | GTZC_TZSC_PERIPH_PRIV);
// Clear all illegal access flags in GTZC TZIC
HAL_GTZC_TZIC_ClearFlag(GTZC_PERIPH_ALL);
@ -147,4 +156,211 @@ void trustzone_init_boardloader(void) {
NVIC_EnableIRQ(GTZC_IRQn);
}
#endif // BOARDLOADER
void tz_init_kernel(void) {
// Configure SRAM security attributes
tz_configure_sram();
// Configure FLASH security attributes
tz_configure_flash();
// Configure FSMC security attributes
tz_configure_fsmc();
// Make all peripherals secure & privileged
HAL_GTZC_TZSC_ConfigPeriphAttributes(
GTZC_PERIPH_ALL, GTZC_TZSC_PERIPH_SEC | GTZC_TZSC_PERIPH_PRIV);
// Clear all illegal access flags in GTZC TZIC
HAL_GTZC_TZIC_ClearFlag(GTZC_PERIPH_ALL);
// Enable all illegal access interrupts in GTZC TZIC
HAL_GTZC_TZIC_EnableIT(GTZC_PERIPH_ALL);
// Enable GTZC secure interrupt
NVIC_SetPriority(GTZC_IRQn, IRQ_PRI_HIGHEST);
NVIC_EnableIRQ(GTZC_IRQn);
}
static void set_bit_array(volatile uint32_t* regs, uint32_t bit_offset,
uint32_t bit_count, bool value) {
regs += bit_offset / 32;
bit_offset %= 32;
if (bit_offset != 0) {
uint32_t bc = MIN(32 - bit_offset, bit_count);
uint32_t mask = (1 << bc) - 1;
mask <<= bit_offset;
if (value) {
*regs |= mask;
} else {
*regs &= ~mask;
}
regs++;
bit_count -= bc;
}
while (bit_count >= 32) {
*regs = value ? 0xFFFFFFFF : 0;
regs++;
bit_count -= 32;
}
if (bit_count > 0) {
uint32_t mask = (1 << bit_count) - 1;
if (value) {
*regs |= mask;
} else {
*regs &= ~mask;
}
}
}
typedef struct {
// Start address of the region
uint32_t start;
// End address of the region + 1
size_t end;
// MPCBB register base
volatile GTZC_MPCBB_TypeDef* regs;
} sram_region_t;
// SRAM regions must be in order of ascending start address
// and must not overlap
sram_region_t g_sram_regions[] = {
{SRAM1_BASE, SRAM1_BASE + SRAM1_SIZE, GTZC_MPCBB1},
{SRAM2_BASE, SRAM2_BASE + SRAM2_SIZE, GTZC_MPCBB2},
{SRAM3_BASE, SRAM3_BASE + SRAM3_SIZE, GTZC_MPCBB3},
#if defined STM32U5A9xx | defined STM32U5G9xx
{SRAM5_BASE, SRAM5_BASE + SRAM5_SIZE, GTZC_MPCBB5},
#endif
#if defined STM32U5G9xx
{SRAM6_BASE, SRAM6_BASE + SRAM6_SIZE, GTZC_MPCBB6},
#endif
{SRAM4_BASE, SRAM4_BASE + SRAM4_SIZE, GTZC_MPCBB4},
};
void tz_set_sram_unpriv(uint32_t start, uint32_t size, bool unpriv) {
const size_t block_size = TZ_SRAM_ALIGNMENT;
ensure(sectrue * IS_ALIGNED(start, block_size), "TZ alignment");
ensure(sectrue * IS_ALIGNED(size, block_size), "TZ alignment");
uint32_t end = start + size;
for (int idx = 0; idx < ARRAY_LENGTH(g_sram_regions); idx++) {
const sram_region_t* r = &g_sram_regions[idx];
if (start >= r->end) {
continue;
}
if (end <= r->start) {
break;
}
// Clip to region bounds
uint32_t clipped_start = MAX(start, r->start);
uint32_t clipped_end = MIN(end, r->end);
// Calculate bit offsets
uint32_t bit_offset = (clipped_start - r->start) / block_size;
uint32_t bit_count = (clipped_end - clipped_start) / block_size;
// Set/reset bits corresponding to 512B blocks
set_bit_array(r->regs->PRIVCFGR, bit_offset, bit_count, !unpriv);
}
__ISB();
}
typedef struct {
// Start address of the region
uint32_t start;
// End address of the region + 1
size_t end;
// PRIVBB register base
volatile uint32_t* privbb;
} flash_region_t;
#if defined STM32U5A9xx
#define XFLASH_BANK_SIZE 0x200000
#elif defined STM32U5G9xx
#define XFLASH_BANK_SIZE 0x200000
#elif defined STM32U585xx
#define XFLASH_BANK_SIZE 0x100000
#else
#error "Unknown MCU"
#endif
#define FLASH_BANK1_BASE FLASH_BASE
#define FLASH_BANK2_BASE (FLASH_BASE + XFLASH_BANK_SIZE)
// FLASH regions must be in order of ascending start address
// and must not overlap
flash_region_t g_flash_regions[] = {
{FLASH_BANK1_BASE, FLASH_BANK1_BASE + XFLASH_BANK_SIZE, &FLASH->PRIVBB1R1},
{FLASH_BANK2_BASE, FLASH_BANK2_BASE + XFLASH_BANK_SIZE, &FLASH->PRIVBB2R1},
};
void tz_set_flash_unpriv(uint32_t start, uint32_t size, bool unpriv) {
const size_t block_size = TZ_FLASH_ALIGNMENT;
ensure(sectrue * IS_ALIGNED(start, block_size), "TZ alignment");
ensure(sectrue * IS_ALIGNED(size, block_size), "TZ alignment");
uint32_t end = start + size;
for (int idx = 0; idx < ARRAY_LENGTH(g_flash_regions); idx++) {
const flash_region_t* r = &g_flash_regions[idx];
if (start >= r->end) {
continue;
}
if (end <= r->start) {
break;
}
// Clip to region bounds
uint32_t clipped_start = MAX(start, r->start);
uint32_t clipped_end = MIN(end, r->end);
// Calculate bit offsets
uint32_t bit_offset = (clipped_start - r->start) / block_size;
uint32_t bit_count = (clipped_end - clipped_start) / block_size;
// Set/reset bits corresponding to flash pages (8KB)
set_bit_array(r->privbb, bit_offset, bit_count, !unpriv);
}
__ISB();
}
void tz_set_saes_unpriv(bool unpriv) {
HAL_GTZC_TZSC_ConfigPeriphAttributes(
GTZC_PERIPH_SAES,
unpriv ? GTZC_TZSC_PERIPH_NPRIV : GTZC_TZSC_PERIPH_PRIV);
}
void tz_set_tamper_unpriv(bool unpriv) {
HAL_GTZC_TZSC_ConfigPeriphAttributes(
GTZC_PERIPH_TAMP,
unpriv ? GTZC_TZSC_PERIPH_NPRIV : GTZC_TZSC_PERIPH_PRIV);
}
void tz_set_dma2d_unpriv(bool unpriv) {
HAL_GTZC_TZSC_ConfigPeriphAttributes(
GTZC_PERIPH_DMA2D,
unpriv ? GTZC_TZSC_PERIPH_NPRIV : GTZC_TZSC_PERIPH_PRIV);
}
#if defined STM32U5A9xx || defined STM32U5G9xx
void tz_set_gfxmmu_unpriv(bool unpriv) {
HAL_GTZC_TZSC_ConfigPeriphAttributes(
GTZC_PERIPH_GFXMMU,
unpriv ? GTZC_TZSC_PERIPH_NPRIV : GTZC_TZSC_PERIPH_PRIV);
}
#endif

View File

@ -26,21 +26,50 @@
#include <xdisplay.h>
#include "display_internal.h"
#include "mpu.h"
#include "trustzone.h"
#ifdef KERNEL_MODE
// Physical frame buffers in internal SRAM memory
__attribute__((section(".fb1")))
ALIGN_32BYTES(uint8_t physical_frame_buffer_0[PHYSICAL_FRAME_BUFFER_SIZE]);
__attribute__((section(".fb1"), aligned(PHYSICAL_FRAME_BUFFER_ALIGNMENT)))
uint8_t physical_frame_buffer_0[PHYSICAL_FRAME_BUFFER_SIZE];
__attribute__((section(".fb2")))
ALIGN_32BYTES(uint8_t physical_frame_buffer_1[PHYSICAL_FRAME_BUFFER_SIZE]);
__attribute__((section(".fb2"), aligned(PHYSICAL_FRAME_BUFFER_ALIGNMENT)))
uint8_t physical_frame_buffer_1[PHYSICAL_FRAME_BUFFER_SIZE];
// The current frame buffer selector at fixed memory address
// It's shared between bootloaders and the firmware
__attribute__((section(".framebuffer_select"))) uint32_t current_frame_buffer =
0;
void display_set_unpriv_access(bool unpriv) {
// To allow unprivileged access both GFXMMU virtual buffers area and
// underlying SRAM region must be configured as unprivileged.
// Order of GFXMMU and SRAM unprivileged access configuration is important
// to avoid the situation the virtual frame buffer has lower privileges
// than underlying frame buffer in physical memory so LTDC could not
// refresh the display properly.
if (!unpriv) {
tz_set_gfxmmu_unpriv(unpriv);
}
tz_set_sram_unpriv((uint32_t)physical_frame_buffer_0,
PHYSICAL_FRAME_BUFFER_SIZE, unpriv);
tz_set_sram_unpriv((uint32_t)physical_frame_buffer_1,
PHYSICAL_FRAME_BUFFER_SIZE, unpriv);
if (unpriv) {
tz_set_gfxmmu_unpriv(unpriv);
}
#ifdef USE_DMA2D
tz_set_dma2d_unpriv(unpriv);
#endif
}
bool display_get_frame_buffer(display_fb_info_t *fb) {
display_driver_t *drv = &g_display_driver;
@ -87,13 +116,9 @@ void display_refresh(void) {
if (current_frame_buffer == 0) {
current_frame_buffer = 1;
BSP_LCD_SetFrameBuffer(0, GFXMMU_VIRTUAL_BUFFER1_BASE_S);
memcpy(physical_frame_buffer_0, physical_frame_buffer_1,
sizeof(physical_frame_buffer_0));
} else {
current_frame_buffer = 0;
BSP_LCD_SetFrameBuffer(0, GFXMMU_VIRTUAL_BUFFER0_BASE_S);
memcpy(physical_frame_buffer_1, physical_frame_buffer_0,
sizeof(physical_frame_buffer_1));
}
}

View File

@ -23,6 +23,9 @@
#include <stdbool.h>
#include <stdint.h>
#include "sizedefs.h"
#include "trustzone.h"
// Display driver context.
typedef struct {
// Set if the driver is initialized
@ -36,11 +39,19 @@ typedef struct {
// Display driver instance
extern display_driver_t g_display_driver;
// Hardware requires physical frame buffer alignment
#ifdef USE_TRUSTZONE
#define PHYSICAL_FRAME_BUFFER_ALIGNMENT TZ_SRAM_ALIGNMENT
#else
#define PHYSICAL_FRAME_BUFFER_ALIGNMENT 32
#endif
// Size of the physical frame buffer in bytes
//
// It's smaller than size of the virtual frame buffer
// due to used GFXMMU settings
#define PHYSICAL_FRAME_BUFFER_SIZE (184320 * 4)
#define PHYSICAL_FRAME_BUFFER_SIZE \
ALIGN_UP_CONST(184320 * 4, PHYSICAL_FRAME_BUFFER_ALIGNMENT)
// Pitch (in pixels) of the virtual frame buffer
#define FRAME_BUFFER_PIXELS_PER_LINE 768

View File

@ -17,15 +17,49 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __TREZORHAL_TRUSTZONE__
#define __TREZORHAL_TRUSTZONE__
#ifndef TREZORHAL_TRUSTZONE
#define TREZORHAL_TRUSTZONE
#include <stdbool.h>
#include <stdint.h>
#ifdef BOARDLOADER
// Provides initial security configuration of CPU and GTZC
// in the board-loader
void trustzone_init_boardloader(void);
void tz_init_boardloader(void);
#endif // BOARDLOADER
#endif
// Alters configuration of GTZC in the kernel
void tz_init_kernel(void);
// Alignment required by MCPBB/GTZC for SRAM regions
#define TZ_SRAM_ALIGNMENT 512
// Set unprivileged access to an SRAM address range at the
// MCPBB/GTZC level. The region's start and end are automatically aligned to
// 512B to cover the entire specified range.
void tz_set_sram_unpriv(uint32_t start, uint32_t size, bool unpriv);
// Alignment required by GTZC for FLASH regions
#define TZ_FLASH_ALIGNMENT 8192
// Sets unprivileged access to a FLASH address range at the
// MCPBB/GTZC level. The region's start and end are automatically aligned to
// 8KB to cover the entire specified range.
void tz_set_flash_unpriv(uint32_t start, uint32_t size, bool unpriv);
// Sets unprivileged access to the SAES peripheral.
void tz_set_saes_unpriv(bool unpriv);
// Sets unprivileged access to the TAMP peripheral.
void tz_set_tamper_unpriv(bool unpriv);
// Sets unprivileged access to the DMA2D peripheral.
void tz_set_dma2d_unpriv(bool unpriv);
// Sets unprivileged access to the GFXMMU peripheral.
void tz_set_gfxmmu_unpriv(bool unpriv);
#endif // TREZORHAL_TRUSTZONE

View File

@ -71,6 +71,10 @@ void display_init(display_content_mode_t mode);
// `display_init(DISPLAY_RETAIN_CONTENT)`.
void display_deinit(display_content_mode_t mode);
// Allows unprivileged access to the display framebuffer from
// perspective of the GTZC (Global TrustZone Controller).
void display_set_unpriv_access(bool unpriv);
#endif // KERNEL_MODE
// Sets display backlight level ranging from 0 (off)..255 (maximum).