mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-11-15 20:19:23 +00:00
feat(core): properly utilize trustzone in kernel and core app
[no changelog]
This commit is contained in:
parent
c0829ec364
commit
b174237684
@ -255,7 +255,7 @@ int main(void) {
|
||||
#ifdef STM32U5
|
||||
tamper_init();
|
||||
|
||||
trustzone_init_boardloader();
|
||||
tz_init_boardloader();
|
||||
#endif
|
||||
|
||||
secret_init();
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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};
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 );
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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).
|
||||
|
Loading…
Reference in New Issue
Block a user