mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-08-03 12:28:13 +00:00
feat(core): allow execution of syscalls in thread mode
[no changelog]
This commit is contained in:
parent
a133a01a1f
commit
37b608827c
@ -28,6 +28,7 @@
|
||||
#include <sys/applet.h>
|
||||
#include <sys/bootutils.h>
|
||||
#include <sys/mpu.h>
|
||||
#include <sys/syscall_ipc.h>
|
||||
#include <sys/sysevent.h>
|
||||
#include <sys/system.h>
|
||||
#include <sys/systick.h>
|
||||
@ -191,11 +192,19 @@ void drivers_init() {
|
||||
// Returns when the coreapp task is terminated
|
||||
static void kernel_loop(applet_t *coreapp) {
|
||||
do {
|
||||
sysevents_t awaited = {0};
|
||||
sysevents_t awaited = {
|
||||
.read_ready = 1 << SYSHANDLE_SYSCALL,
|
||||
.write_ready = 0,
|
||||
};
|
||||
|
||||
sysevents_t signalled = {0};
|
||||
|
||||
sysevents_poll(&awaited, &signalled, ticks_timeout(100));
|
||||
|
||||
if (signalled.read_ready & (1 << SYSHANDLE_SYSCALL)) {
|
||||
syscall_ipc_dequeue();
|
||||
}
|
||||
|
||||
} while (applet_is_alive(coreapp));
|
||||
}
|
||||
|
||||
|
@ -143,7 +143,7 @@ saes_invoke(void) {
|
||||
// reset the key loaded in SAES
|
||||
MODIFY_REG(SAES->CR, AES_CR_KEYSEL, CRYP_KEYSEL_NORMAL);
|
||||
|
||||
syscall_return_from_callback(sectrue);
|
||||
svc_return_from_unpriv(sectrue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -36,20 +36,12 @@
|
||||
//
|
||||
// Return values must be copied to `args[0]` and
|
||||
// `args[1]` (if returning a 64-bit value).
|
||||
void syscall_handler(uint32_t* args, uint32_t syscall);
|
||||
|
||||
// Invokes the application callback from the syscall handler.
|
||||
//
|
||||
// This is a *temporary* helper function used to invoke application callbacks
|
||||
// from the syscall handler. It will be removed once all callback arguments
|
||||
// are eliminated from syscalls.
|
||||
uint32_t invoke_app_callback(uint32_t args1, uint32_t arg2, uint32_t arg3,
|
||||
void* callback);
|
||||
void syscall_handler(uint32_t* args, uint32_t syscall, void* applet);
|
||||
|
||||
// Internal function for returning from an application callback.
|
||||
// This function is called from an unprivileged app via an SVC call. It restores
|
||||
// the stack pointer and returns control to the privileged caller.
|
||||
void return_from_app_callback(uint32_t retval, uint32_t* msp);
|
||||
void return_from_unpriv(uint32_t retval, uint32_t* msp);
|
||||
|
||||
// Invokes an unprivileged function from privileged mode.
|
||||
//
|
||||
@ -58,8 +50,6 @@ void return_from_app_callback(uint32_t retval, uint32_t* msp);
|
||||
// different hardware keys being used in privileged and unprivileged modes).
|
||||
uint32_t invoke_unpriv(void* func);
|
||||
|
||||
#endif // KERNEL_MODE
|
||||
|
||||
// Returns from an unprivileged callback.
|
||||
//
|
||||
// Same as `invoke_unpriv`, this function should be removed once
|
||||
@ -67,10 +57,12 @@ uint32_t invoke_unpriv(void* func);
|
||||
// unprivileged mode.
|
||||
|
||||
static void inline __attribute__((no_stack_protector))
|
||||
syscall_return_from_callback(uint32_t retval) {
|
||||
svc_return_from_unpriv(uint32_t retval) {
|
||||
register uint32_t r0 __asm__("r0") = retval;
|
||||
__asm__ volatile("svc %[svid]\n"
|
||||
:
|
||||
: [svid] "i"(SVC_CALLBACK_RETURN), "r"(r0)
|
||||
: "memory");
|
||||
}
|
||||
|
||||
#endif // KERNEL_MODE
|
||||
|
46
core/embed/sys/syscall/inc/sys/syscall_ipc.h
Normal file
46
core/embed/sys/syscall/inc/sys/syscall_ipc.h
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef KERNEL
|
||||
|
||||
#include <trezor_types.h>
|
||||
|
||||
#include <sys/syscall_numbers.h>
|
||||
|
||||
// Initializes IPC for syscalls
|
||||
bool syscall_ipc_init(void);
|
||||
|
||||
// Enqueues a syscall for processing in the kernel event loop
|
||||
//
|
||||
// Queued syscalls are signalled to the kernel task by
|
||||
// asserting SYSEVENT_SYSCALL.
|
||||
//
|
||||
// The function may be called only from kernel handler mode
|
||||
// (respectively from SVCall handler).
|
||||
void syscall_ipc_enqueue(uint32_t* args, syscall_number_t syscall);
|
||||
|
||||
// Dequeues and processed a syscall
|
||||
//
|
||||
// Removes the syscall from the queue and executes it. This
|
||||
// function is intended to be called from the kernel event loop.
|
||||
void syscall_ipc_dequeue(void);
|
||||
|
||||
#endif // KERNEL
|
@ -19,10 +19,19 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
// All syscalls with SYSCALL_THREAD_MODE flag are executed
|
||||
// in kernel thread mode
|
||||
#define SYSCALL_THREAD_MODE 0x80000000
|
||||
|
||||
// Syscall identifiers
|
||||
typedef enum {
|
||||
|
||||
SYSCALL_SYSTEM_EXIT = 1,
|
||||
// ------------------------------------------------------
|
||||
// Following syscalls are executed in kernel handler mode
|
||||
|
||||
SYSCALL_RETURN_FROM_CALLBACK = 1,
|
||||
|
||||
SYSCALL_SYSTEM_EXIT,
|
||||
SYSCALL_SYSTEM_EXIT_ERROR,
|
||||
SYSCALL_SYSTEM_EXIT_FATAL,
|
||||
|
||||
@ -108,25 +117,6 @@ typedef enum {
|
||||
SYSCALL_OPTIGA_RANDOM_BUFFER,
|
||||
SYSCALL_OPTIGA_SET_SEC_MAX,
|
||||
|
||||
SYSCALL_STORAGE_INIT,
|
||||
SYSCALL_STORAGE_WIPE,
|
||||
SYSCALL_STORAGE_IS_UNLOCKED,
|
||||
SYSCALL_STORAGE_LOCK,
|
||||
SYSCALL_STORAGE_UNLOCK,
|
||||
SYSCALL_STORAGE_HAS_PIN,
|
||||
SYSCALL_STORAGE_PIN_FAILS_INCREASE,
|
||||
SYSCALL_STORAGE_GET_PIN_REM,
|
||||
SYSCALL_STORAGE_CHANGE_PIN,
|
||||
SYSCALL_STORAGE_ENSURE_NOT_WIPE_CODE,
|
||||
SYSCALL_STORAGE_HAS_WIPE_CODE,
|
||||
SYSCALL_STORAGE_CHANGE_WIPE_CODE,
|
||||
SYSCALL_STORAGE_HAS,
|
||||
SYSCALL_STORAGE_GET,
|
||||
SYSCALL_STORAGE_SET,
|
||||
SYSCALL_STORAGE_DELETE,
|
||||
SYSCALL_STORAGE_SET_COUNTER,
|
||||
SYSCALL_STORAGE_NEXT_COUNTER,
|
||||
|
||||
SYSCALL_ENTROPY_GET,
|
||||
|
||||
SYSCALL_TRANSLATIONS_WRITE,
|
||||
@ -179,4 +169,28 @@ typedef enum {
|
||||
SYSCALL_TROPIC_ECC_KEY_GENERATE,
|
||||
SYSCALL_TROPIC_ECC_SIGN,
|
||||
|
||||
SYSCALL_STORAGE_GET,
|
||||
|
||||
// ------------------------------------------------------
|
||||
// Following syscalls are executed in kernel thread mode
|
||||
|
||||
SYSCALL_STORAGE_INIT = SYSCALL_THREAD_MODE,
|
||||
SYSCALL_STORAGE_WIPE,
|
||||
SYSCALL_STORAGE_IS_UNLOCKED,
|
||||
SYSCALL_STORAGE_LOCK,
|
||||
SYSCALL_STORAGE_UNLOCK,
|
||||
SYSCALL_STORAGE_HAS_PIN,
|
||||
SYSCALL_STORAGE_PIN_FAILS_INCREASE,
|
||||
SYSCALL_STORAGE_GET_PIN_REM,
|
||||
SYSCALL_STORAGE_CHANGE_PIN,
|
||||
SYSCALL_STORAGE_ENSURE_NOT_WIPE_CODE,
|
||||
SYSCALL_STORAGE_HAS_WIPE_CODE,
|
||||
SYSCALL_STORAGE_CHANGE_WIPE_CODE,
|
||||
SYSCALL_STORAGE_HAS,
|
||||
// SYSCALL_STORAGE_GET,
|
||||
SYSCALL_STORAGE_SET,
|
||||
SYSCALL_STORAGE_DELETE,
|
||||
SYSCALL_STORAGE_SET_COUNTER,
|
||||
SYSCALL_STORAGE_NEXT_COUNTER,
|
||||
|
||||
} syscall_number_t;
|
@ -21,70 +21,10 @@
|
||||
|
||||
#include <sys/mpu.h>
|
||||
|
||||
#include "syscall_context.h"
|
||||
#include "syscall_internal.h"
|
||||
|
||||
__attribute__((naked, no_stack_protector)) static uint32_t _invoke_app_callback(
|
||||
uint32_t arg1, uint32_t arg2, uint32_t arg3, void *callback) {
|
||||
__asm__ volatile(
|
||||
"push {r1-r12, lr} \n"
|
||||
|
||||
#if defined(__ARM_ARCH_8M_MAIN__) || defined(__ARM_ARCH_8M_BASE__)
|
||||
"mrs r12, PSPLIM \n" // Backup unprivileged stack limit
|
||||
"push {r12} \n"
|
||||
#endif
|
||||
"mrs r12, PSP \n" // Backup unprivileged stack pointer
|
||||
"push {r12} \n"
|
||||
|
||||
"sub r12, r12, #32 \n" // Reserve space for stack frame
|
||||
"msr PSP, r12 \n"
|
||||
|
||||
"str r0, [r12, #0] \n" // pass r0
|
||||
"str r1, [r12, #4] \n" // pass r1
|
||||
"str r2, [r12, #8] \n" // pass r2
|
||||
|
||||
"mov r1, #0 \n"
|
||||
|
||||
"mov r4, r1 \n" // Clear registers r4-r11
|
||||
"mov r5, r1 \n"
|
||||
"mov r6, r1 \n"
|
||||
"mov r7, r1 \n"
|
||||
"mov r8, r1 \n"
|
||||
"mov r9, r1 \n"
|
||||
"mov r10, r1 \n"
|
||||
"mov r11, r1 \n"
|
||||
|
||||
"str r1, [r12, #12] \n" // clear r3
|
||||
"str r1, [r12, #16] \n" // clear r12
|
||||
"str r1, [r12, #20] \n" // clear lr
|
||||
|
||||
"bic r3, r3, #1 \n"
|
||||
"str r3, [r12, #24] \n" // return address
|
||||
|
||||
"ldr r1, = 0x01000000 \n"
|
||||
"str r1, [r12, #28] \n" // xPSR
|
||||
|
||||
"vmov r0, s0 \n" // Use FPU instruction to ensure lazy
|
||||
// stacking
|
||||
|
||||
#if !defined(__ARM_FEATURE_CMSE) || (__ARM_FEATURE_CMSE == 3U)
|
||||
// return to Secure Thread mode (use Secure PSP)
|
||||
"ldr lr, = 0xFFFFFFFD \n"
|
||||
#else
|
||||
// return to Thread mode (use PSP)
|
||||
"ldr lr, = 0xFFFFFFBC \n"
|
||||
#endif
|
||||
"bx lr \n");
|
||||
}
|
||||
|
||||
uint32_t invoke_app_callback(uint32_t args1, uint32_t arg2, uint32_t arg3,
|
||||
void *callback) {
|
||||
mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_APP);
|
||||
uint32_t retval = _invoke_app_callback(args1, arg2, arg3, callback);
|
||||
mpu_reconfig(mpu_mode);
|
||||
return retval;
|
||||
}
|
||||
|
||||
__attribute__((naked, no_stack_protector)) void return_from_app_callback(
|
||||
__attribute__((naked, no_stack_protector)) void return_from_unpriv(
|
||||
uint32_t retval, uint32_t *msp) {
|
||||
__asm__ volatile(
|
||||
"MSR MSP, R1 \n"
|
||||
|
30
core/embed/sys/syscall/stm32/syscall_context.c
Normal file
30
core/embed/sys/syscall/stm32/syscall_context.c
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "syscall_context.h"
|
||||
|
||||
#ifdef KERNEL
|
||||
|
||||
applet_t* g_syscall_context;
|
||||
|
||||
void syscall_set_context(applet_t* applet) { g_syscall_context = applet; }
|
||||
|
||||
applet_t* syscall_get_context(void) { return g_syscall_context; }
|
||||
|
||||
#endif // KERNEL
|
32
core/embed/sys/syscall/stm32/syscall_context.h
Normal file
32
core/embed/sys/syscall/stm32/syscall_context.h
Normal file
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <sys/applet.h>
|
||||
|
||||
#ifdef KERNEL
|
||||
|
||||
// Sets the context (applet) for all subsequent syscall processing
|
||||
void syscall_set_context(applet_t* applet);
|
||||
|
||||
// Gets current syscall context (applet)
|
||||
applet_t* syscall_get_context(void);
|
||||
|
||||
#endif // KERNEL
|
@ -77,25 +77,34 @@
|
||||
#include <io/touch.h>
|
||||
#endif
|
||||
|
||||
#include "syscall_context.h"
|
||||
#include "syscall_internal.h"
|
||||
#include "syscall_verifiers.h"
|
||||
|
||||
bool g_in_app_callback = false;
|
||||
|
||||
static PIN_UI_WAIT_CALLBACK storage_init_callback = NULL;
|
||||
|
||||
static secbool storage_init_callback_wrapper(
|
||||
uint32_t wait, uint32_t progress, enum storage_ui_message_t message) {
|
||||
secbool result;
|
||||
g_in_app_callback = true;
|
||||
result = invoke_app_callback(wait, progress, message, storage_init_callback);
|
||||
g_in_app_callback = false;
|
||||
|
||||
applet_t *applet = syscall_get_context();
|
||||
result = systask_invoke_callback(&applet->task, wait, progress, message,
|
||||
storage_init_callback);
|
||||
return result;
|
||||
}
|
||||
|
||||
__attribute((no_stack_protector)) void syscall_handler(uint32_t *args,
|
||||
uint32_t syscall) {
|
||||
uint32_t syscall,
|
||||
void *applet) {
|
||||
syscall_set_context((applet_t *)applet);
|
||||
|
||||
switch (syscall) {
|
||||
case SYSCALL_RETURN_FROM_CALLBACK: {
|
||||
syscall_get_context()->task.in_callback = false;
|
||||
systask_yield_to(systask_kernel());
|
||||
break;
|
||||
}
|
||||
|
||||
case SYSCALL_SYSTEM_EXIT: {
|
||||
int exit_code = (int)args[0];
|
||||
system_exit__verified(exit_code);
|
||||
@ -148,7 +157,7 @@ __attribute((no_stack_protector)) void syscall_handler(uint32_t *args,
|
||||
const sysevents_t *awaited = (sysevents_t *)args[0];
|
||||
sysevents_t *signalled = (sysevents_t *)args[1];
|
||||
uint32_t deadline = args[2];
|
||||
if (!g_in_app_callback) {
|
||||
if (!syscall_get_context()->task.in_callback) {
|
||||
sysevents_poll__verified(awaited, signalled, deadline);
|
||||
}
|
||||
} break;
|
||||
|
@ -23,8 +23,7 @@
|
||||
|
||||
#include <sys/applet.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
#include "syscall_numbers.h"
|
||||
#include <sys/syscall_numbers.h>
|
||||
|
||||
#ifndef KERNEL_MODE
|
||||
|
||||
|
134
core/embed/sys/syscall/stm32/syscall_ipc.c
Normal file
134
core/embed/sys/syscall/stm32/syscall_ipc.c
Normal file
@ -0,0 +1,134 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef KERNEL
|
||||
|
||||
#include <trezor_rtl.h>
|
||||
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/syscall_ipc.h>
|
||||
#include <sys/sysevent_source.h>
|
||||
#include <sys/systask.h>
|
||||
|
||||
typedef struct {
|
||||
// Task that requested the syscall
|
||||
systask_t* task;
|
||||
// Syscall number
|
||||
syscall_number_t number;
|
||||
// Syscall arguments
|
||||
uint32_t args[6];
|
||||
} syscall_struct_t;
|
||||
|
||||
typedef struct {
|
||||
// Syscall to process
|
||||
syscall_struct_t syscall;
|
||||
|
||||
} syscall_ipc_t;
|
||||
|
||||
static syscall_ipc_t g_syscall_ipc = {0};
|
||||
|
||||
// forward declaration
|
||||
static const syshandle_vmt_t g_syscall_handle_vmt;
|
||||
|
||||
bool syscall_ipc_init(void) {
|
||||
syscall_ipc_t* ipc = &g_syscall_ipc;
|
||||
|
||||
memset(ipc, 0, sizeof(*ipc));
|
||||
|
||||
if (!syshandle_register(SYSHANDLE_SYSCALL, &g_syscall_handle_vmt, ipc)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void syscall_ipc_enqueue(uint32_t* args, syscall_number_t number) {
|
||||
syscall_ipc_t* ipc = &g_syscall_ipc;
|
||||
|
||||
// Enqueue the syscall
|
||||
syscall_struct_t* syscall = &ipc->syscall;
|
||||
syscall->task = systask_active();
|
||||
syscall->number = number;
|
||||
memcpy(syscall->args, args, sizeof(syscall->args));
|
||||
|
||||
// Switch to the kernel task to process the syscall
|
||||
systask_yield_to(systask_kernel());
|
||||
}
|
||||
|
||||
void syscall_ipc_dequeue(void) {
|
||||
syscall_ipc_t* ipc = &g_syscall_ipc;
|
||||
|
||||
syscall_struct_t* syscall = &ipc->syscall;
|
||||
|
||||
if (syscall->task != NULL) {
|
||||
// Process enqueued syscall
|
||||
syscall_handler(syscall->args, syscall->number, syscall->task->applet);
|
||||
// Copy return value back to the task's registers
|
||||
systask_set_r0r1(syscall->task, syscall->args[0], syscall->args[1]);
|
||||
|
||||
// Remove the syscall from the queue
|
||||
systask_t* task = syscall->task;
|
||||
memset(syscall, 0, sizeof(*syscall));
|
||||
|
||||
// Get back to the unprivileged task
|
||||
systask_yield_to(task);
|
||||
}
|
||||
}
|
||||
|
||||
static void on_task_killed(void* context, systask_id_t task_id) {
|
||||
syscall_ipc_t* ipc = (syscall_ipc_t*)context;
|
||||
|
||||
if (ipc->syscall.task != NULL && ipc->syscall.task->id == task_id) {
|
||||
memset(&ipc->syscall, 0, sizeof(ipc->syscall));
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool syscall_requested(syscall_ipc_t* ipc) {
|
||||
return (ipc->syscall.task != NULL);
|
||||
}
|
||||
|
||||
static void on_event_poll(void* context, bool read_awaited,
|
||||
bool write_awaited) {
|
||||
syscall_ipc_t* ipc = (syscall_ipc_t*)context;
|
||||
|
||||
UNUSED(write_awaited);
|
||||
|
||||
if (read_awaited && syscall_requested(ipc)) {
|
||||
syshandle_signal_read_ready(SYSHANDLE_SYSCALL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static bool on_check_read_ready(void* context, systask_id_t task_id,
|
||||
void* param) {
|
||||
syscall_ipc_t* ipc = (syscall_ipc_t*)context;
|
||||
|
||||
UNUSED(param);
|
||||
|
||||
return (task_id == 0) && syscall_requested(ipc);
|
||||
}
|
||||
|
||||
static const syshandle_vmt_t g_syscall_handle_vmt = {
|
||||
.task_created = NULL,
|
||||
.task_killed = on_task_killed,
|
||||
.check_read_ready = on_check_read_ready,
|
||||
.check_write_ready = NULL,
|
||||
.poll = on_event_poll,
|
||||
};
|
||||
|
||||
#endif // KERNEL
|
@ -22,6 +22,7 @@
|
||||
#pragma GCC optimize("no-stack-protector")
|
||||
|
||||
#include <trezor_model.h>
|
||||
#include <trezor_rtl.h>
|
||||
|
||||
#include <sys/applet.h>
|
||||
|
||||
@ -36,7 +37,7 @@ static inline bool inside_area(const void *addr, size_t len,
|
||||
}
|
||||
|
||||
bool probe_read_access(const void *addr, size_t len) {
|
||||
applet_t *applet = applet_active();
|
||||
applet_t *applet = syscall_get_context();
|
||||
|
||||
if (applet == NULL) {
|
||||
return false;
|
||||
@ -86,7 +87,7 @@ bool probe_read_access(const void *addr, size_t len) {
|
||||
}
|
||||
|
||||
bool probe_write_access(void *addr, size_t len) {
|
||||
applet_t *applet = applet_active();
|
||||
applet_t *applet = syscall_get_context();
|
||||
|
||||
if (applet == NULL) {
|
||||
return false;
|
||||
@ -118,4 +119,11 @@ bool probe_write_access(void *addr, size_t len) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void handle_access_violation(const char *file, int line) {
|
||||
static const char *msg = "Access violation";
|
||||
applet_t *applet = syscall_get_context();
|
||||
systask_t *task = applet != NULL ? &applet->task : systask_active();
|
||||
systask_exit_fatal(task, msg, strlen(msg), file, strlen(file), line);
|
||||
}
|
||||
|
||||
#endif // KERNEL
|
||||
|
@ -21,8 +21,11 @@
|
||||
|
||||
#include <trezor_types.h>
|
||||
|
||||
#include <sys/applet.h>
|
||||
#include <sys/system.h>
|
||||
|
||||
#include "syscall_context.h"
|
||||
|
||||
#ifdef KERNEL
|
||||
|
||||
// Checks if the current application task has read access to the
|
||||
@ -33,11 +36,15 @@ bool probe_read_access(const void *addr, size_t len);
|
||||
// given memory range.
|
||||
bool probe_write_access(void *addr, size_t len);
|
||||
|
||||
// Handles access violation by exiting the current application task
|
||||
// with a fatal error and the message "Access violation".
|
||||
void handle_access_violation(const char *file, int line);
|
||||
|
||||
// Exits the current application task with an fatal error
|
||||
// with the message "Access violation".
|
||||
#define apptask_access_violation() \
|
||||
do { \
|
||||
system_exit_fatal("Access violation", __FILE__, __LINE__); \
|
||||
#define apptask_access_violation() \
|
||||
do { \
|
||||
handle_access_violation(__FILE__, __LINE__); \
|
||||
} while (0)
|
||||
|
||||
#endif // KERNEL
|
||||
|
@ -495,7 +495,7 @@ static PIN_UI_WAIT_CALLBACK storage_init_callback = NULL;
|
||||
static void storage_init_callback_wrapper(uint32_t wait, uint32_t progress,
|
||||
enum storage_ui_message_t message) {
|
||||
secbool retval = storage_init_callback(wait, progress, message);
|
||||
syscall_return_from_callback(retval);
|
||||
syscall_invoke1(retval, SYSCALL_RETURN_FROM_CALLBACK);
|
||||
}
|
||||
|
||||
void storage_init(PIN_UI_WAIT_CALLBACK callback, const uint8_t *salt,
|
||||
|
@ -32,6 +32,7 @@ typedef enum {
|
||||
SYSHANDLE_TOUCH,
|
||||
SYSHANDLE_USB,
|
||||
SYSHANDLE_BLE,
|
||||
SYSHANDLE_SYSCALL,
|
||||
SYSHANDLE_COUNT,
|
||||
} syshandle_t;
|
||||
|
||||
|
@ -131,6 +131,9 @@ typedef struct {
|
||||
// Applet bound to the task
|
||||
void* applet;
|
||||
|
||||
// Set if the task is processing the kernel callback
|
||||
bool in_callback;
|
||||
|
||||
} systask_t;
|
||||
|
||||
// Initializes the scheduler for tasks
|
||||
@ -173,6 +176,17 @@ void systask_pop_data(systask_t* task, size_t size);
|
||||
bool systask_push_call(systask_t* task, void* fn, uint32_t arg1, uint32_t arg2,
|
||||
uint32_t arg3);
|
||||
|
||||
// Invokes the callback function in the context of the given task
|
||||
// uint32_t callback(uint32_t arg1, uint32_t arg2, uint32_t arg3);
|
||||
uint32_t systask_invoke_callback(systask_t* task, uint32_t arg1, uint32_t arg2,
|
||||
uint32_t arg3, void* callback);
|
||||
|
||||
// Sets R0 and R1 registers of the suspended task
|
||||
void systask_set_r0r1(systask_t* task, uint32_t r0, uint32_t r1);
|
||||
|
||||
// Gets R0 register value of the suspended task
|
||||
uint32_t systask_get_r0(systask_t* task);
|
||||
|
||||
// Gets the ID (zero-based index up SYSTASK_MAX_TASKS - 1) of the given task.
|
||||
systask_id_t systask_id(const systask_t* task);
|
||||
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include <sys/linker_utils.h>
|
||||
#include <sys/mpu.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/syscall_ipc.h>
|
||||
#include <sys/sysevent_source.h>
|
||||
#include <sys/systask.h>
|
||||
#include <sys/system.h>
|
||||
@ -245,6 +246,62 @@ cleanup:
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t systask_invoke_callback(systask_t* task, uint32_t arg1, uint32_t arg2,
|
||||
uint32_t arg3, void* callback) {
|
||||
uint32_t original_sp = task->sp;
|
||||
if (!systask_push_call(task, callback, arg1, arg2, arg3)) {
|
||||
// There is not enough space on the unprivileged stack
|
||||
error_shutdown("Callback stack low");
|
||||
}
|
||||
|
||||
// This flag signals that the task is currently executing a callback.
|
||||
// Is reset by proper return from the callback via
|
||||
// return_from_unprivileged_callback() function.
|
||||
task->in_callback = true;
|
||||
|
||||
systask_yield_to(task);
|
||||
|
||||
if (task->killed) {
|
||||
// Task was killed while executing the callback
|
||||
error_shutdown("Callback crashed");
|
||||
}
|
||||
|
||||
if (task->in_callback) {
|
||||
// Unprivileged stack pointer contains unexpected value.
|
||||
// This is likely a sign of a unexpected task switch during the
|
||||
// callback execution (e.g. by a system call).
|
||||
error_shutdown("Callback invalid op");
|
||||
}
|
||||
|
||||
uint32_t retval = systask_get_r0(task);
|
||||
|
||||
task->sp = original_sp;
|
||||
return retval;
|
||||
}
|
||||
|
||||
void systask_set_r0r1(systask_t* task, uint32_t r0, uint32_t r1) {
|
||||
uint32_t* stack = (uint32_t*)task->sp;
|
||||
|
||||
if ((task->exc_return & 0x10) == 0) {
|
||||
stack += 16; // Skip the FP context S16-S32
|
||||
stack += 8; // Skip R4-R11
|
||||
}
|
||||
|
||||
stack[STK_FRAME_R0] = r0;
|
||||
stack[STK_FRAME_R1] = r1;
|
||||
}
|
||||
|
||||
uint32_t systask_get_r0(systask_t* task) {
|
||||
uint32_t* stack = (uint32_t*)task->sp;
|
||||
|
||||
if ((task->exc_return & 0x10) == 0) {
|
||||
stack += 16; // Skip the FP context S16-S32
|
||||
stack += 8; // Skip R4-R11
|
||||
}
|
||||
|
||||
return stack[STK_FRAME_R0];
|
||||
}
|
||||
|
||||
static void systask_kill(systask_t* task) {
|
||||
systask_scheduler_t* scheduler = &g_systask_scheduler;
|
||||
|
||||
@ -554,15 +611,17 @@ __attribute__((no_stack_protector, used)) static uint32_t svc_handler(
|
||||
break;
|
||||
#ifdef KERNEL
|
||||
case SVC_SYSCALL:
|
||||
syscall_handler(args, r6);
|
||||
stack[0] = args[0];
|
||||
stack[1] = args[1];
|
||||
if ((r6 & SYSCALL_THREAD_MODE) != 0) {
|
||||
syscall_ipc_enqueue(args, r6);
|
||||
} else {
|
||||
syscall_handler(args, r6, systask_active()->applet);
|
||||
stack[0] = args[0];
|
||||
stack[1] = args[1];
|
||||
}
|
||||
break;
|
||||
case SVC_CALLBACK_RETURN:
|
||||
// g_return_value = args[0]
|
||||
// exc_return = return_from_callback;
|
||||
mpu_restore(mpu_mode);
|
||||
return_from_app_callback(args[0], msp);
|
||||
return_from_unpriv(args[0], msp);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include <sys/linker_utils.h>
|
||||
#include <sys/mpu.h>
|
||||
#include <sys/stack_utils.h>
|
||||
#include <sys/syscall_ipc.h>
|
||||
#include <sys/systask.h>
|
||||
#include <sys/system.h>
|
||||
#include <sys/systick.h>
|
||||
@ -55,6 +56,9 @@ void system_init(systask_error_handler_t error_handler) {
|
||||
systask_scheduler_init(error_handler);
|
||||
systick_init();
|
||||
systimer_init();
|
||||
#ifdef KERNEL
|
||||
syscall_ipc_init();
|
||||
#endif
|
||||
}
|
||||
|
||||
void system_deinit(void) {
|
||||
|
@ -81,7 +81,9 @@ def stm32f4_common_files(env, defines, sources, paths):
|
||||
"embed/sys/startup/stm32f4/startup_init.c",
|
||||
"embed/sys/startup/stm32f4/vectortable.S",
|
||||
"embed/sys/syscall/stm32/syscall.c",
|
||||
"embed/sys/syscall/stm32/syscall_context.c",
|
||||
"embed/sys/syscall/stm32/syscall_dispatch.c",
|
||||
"embed/sys/syscall/stm32/syscall_ipc.c",
|
||||
"embed/sys/syscall/stm32/syscall_probe.c",
|
||||
"embed/sys/syscall/stm32/syscall_stubs.c",
|
||||
"embed/sys/syscall/stm32/syscall_verifiers.c",
|
||||
|
@ -100,7 +100,9 @@ def stm32u5_common_files(env, features_wanted, defines, sources, paths):
|
||||
"embed/sys/startup/stm32u5/startup_init.c",
|
||||
"embed/sys/startup/stm32u5/vectortable.S",
|
||||
"embed/sys/syscall/stm32/syscall.c",
|
||||
"embed/sys/syscall/stm32/syscall_context.c",
|
||||
"embed/sys/syscall/stm32/syscall_dispatch.c",
|
||||
"embed/sys/syscall/stm32/syscall_ipc.c",
|
||||
"embed/sys/syscall/stm32/syscall_probe.c",
|
||||
"embed/sys/syscall/stm32/syscall_stubs.c",
|
||||
"embed/sys/syscall/stm32/syscall_verifiers.c",
|
||||
|
Loading…
Reference in New Issue
Block a user