1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-12-22 14:28:07 +00:00

feat(core/embed): introduce systick and systimer drivers

[no changelog]
This commit is contained in:
cepetr 2024-07-12 11:35:49 +02:00 committed by cepetr
parent 58d9f6115e
commit 1443f86983
36 changed files with 864 additions and 177 deletions

View File

@ -154,6 +154,8 @@ SOURCE_TREZORHAL = [
'embed/trezorhal/unix/random_delays.c',
'embed/trezorhal/unix/rng.c',
'embed/trezorhal/unix/secret.c',
'embed/trezorhal/unix/systick.c',
'embed/trezorhal/unix/systimer.c',
'embed/trezorhal/unix/usb.c',
]

View File

@ -424,6 +424,8 @@ SOURCE_UNIX = [
'embed/trezorhal/unix/flash.c',
'embed/trezorhal/unix/random_delays.c',
'embed/trezorhal/unix/rng.c',
'embed/trezorhal/unix/systick.c',
'embed/trezorhal/unix/systimer.c',
'embed/trezorhal/unix/time_estimate.c',
'embed/trezorhal/unix/usb.c',
'embed/unix/main_main.c',

View File

@ -32,6 +32,7 @@
#include "model.h"
#include "mpu.h"
#include "rng.h"
#include "systimer.h"
#include "terminal.h"
#ifdef USE_SD_CARD
@ -232,6 +233,9 @@ static secbool copy_sdcard(void) {
#endif
int main(void) {
systick_init();
systimer_init();
reset_flags_reset();
// need the systick timer running before many HAL operations.

View File

@ -33,6 +33,7 @@
#include "random_delays.h"
#include "secbool.h"
#include "secret.h"
#include "systimer.h"
#ifdef USE_DMA2D
#ifdef NEW_RENDERING
@ -359,7 +360,10 @@ int bootloader_main(void) {
#endif
secbool stay_in_bootloader = secfalse;
random_delays_init();
systick_init();
systimer_init();
rdi_init();
#if defined TREZOR_MODEL_T
set_core_clock(CLOCK_180_MHZ);

View File

@ -176,7 +176,10 @@ static secbool check_vendor_header_lock(const vendor_header *const vhdr) {
}
int main(void) {
random_delays_init();
systick_init();
systimer_init();
rdi_init();
#ifdef USE_TOUCH
touch_init();
#endif

View File

@ -48,27 +48,10 @@
#include "py/runtime.h"
#include "py/mphal.h"
#include "irq.h"
#include "systick.h"
extern __IO uint32_t uwTick;
// We provide our own version of HAL_Delay that calls __WFI while waiting,
// and works when interrupts are disabled. This function is intended to be
// used only by the ST HAL functions.
void HAL_Delay(uint32_t Delay) {
if (IS_IRQ_ENABLED(query_irq())) {
// IRQs enabled, so can use systick counter to do the delay
uint32_t start = uwTick;
// Wraparound of tick is taken care of by 2's complement arithmetic.
while (uwTick - start < Delay) {
// Enter sleep mode, waiting for (at least) the SysTick interrupt.
__WFI();
}
} else {
// IRQs disabled, use mp_hal_delay_ms routine.
mp_hal_delay_ms(Delay);
}
}
// Core delay function that does an efficient sleep and may switch thread context.
// If IRQs are enabled then we must have the GIL.
void mp_hal_delay_ms(mp_uint_t Delay) {
@ -110,9 +93,9 @@ void mp_hal_delay_us(mp_uint_t usec) {
}
mp_uint_t mp_hal_ticks_ms(void) {
return uwTick;
return systick_ms();
}
mp_uint_t mp_hal_ticks_us(void) {
return uwTick * 1000;
return systick_ms() * 1000;
}

View File

@ -51,6 +51,7 @@
#include "random_delays.h"
#include "rust_ui.h"
#include "secure_aes.h"
#include "systimer.h"
#include TREZOR_BOARD
@ -132,8 +133,10 @@ static void optiga_log_hex(const char *prefix, const uint8_t *data,
int main(void) {
svc_init();
systick_init();
systimer_init();
random_delays_init();
rdi_init();
#ifdef RDI
rdi_start();

View File

@ -42,6 +42,7 @@
#include "sdcard.h"
#include "secbool.h"
#include "supervise.h"
#include "systimer.h"
#include "touch.h"
#include "usb.h"
#include "version.h"
@ -777,8 +778,11 @@ void cpuid_read(void) {
int main(void) {
svc_init();
systick_init();
systimer_init();
rdi_init();
display_init(DISPLAY_RETAIN_CONTENT);
random_delays_init();
#ifdef STM32U5
secure_aes_init();
#endif

View File

@ -33,6 +33,7 @@
#include "sbu.h"
#include "sdcard.h"
#include "secbool.h"
#include "systimer.h"
#include "terminal.h"
#include "touch.h"
@ -68,6 +69,9 @@ static void flash_from_sdcard(const flash_area_t* area, uint32_t source,
}
int main(void) {
systick_init();
systimer_init();
sdcard_init();
touch_init();

View File

@ -399,9 +399,9 @@ fn generate_trezorhal_bindings() {
.allowlist_function("random_uniform")
// rgb led
.allowlist_function("rgb_led_set_color")
// time
.allowlist_function("hal_delay")
.allowlist_function("hal_ticks_ms")
// systick
.allowlist_function("systick_delay_ms")
.allowlist_function("systick_ms")
// toif
.allowlist_type("toif_format_t")
// dma2d

View File

@ -3,11 +3,11 @@ use crate::time::Duration;
use super::ffi;
pub fn ticks_ms() -> u32 {
unsafe { ffi::hal_ticks_ms() as _ }
unsafe { ffi::systick_ms() as _ }
}
pub fn sleep(delay: Duration) {
unsafe {
ffi::hal_delay(delay.to_millis() as _);
ffi::systick_delay_ms(delay.to_millis() as _);
}
}

View File

@ -26,6 +26,7 @@
#include "error_handling.h"
#include "platform.h"
#include "systick.h"
#ifndef MIN_8bits
#define MIN_8bits(a, b) \
@ -54,10 +55,6 @@
void __attribute__((noreturn)) trezor_shutdown(void);
void hal_delay(uint32_t ms);
uint32_t hal_ticks_ms();
void hal_delay_us(uint16_t delay_us);
// Invalidates firmware on the device
// Note: only works when write access to firmware area is enabled by MPU
void invalidate_firmware(void);

View File

@ -22,12 +22,11 @@
#include <stdint.h>
void random_delays_init(void);
void rdi_init(void);
void rdi_start(void);
void rdi_stop(void);
void rdi_refresh_session_delay(void);
void rdi_handler(uint32_t uw_tick);
void wait_random(void);
#endif

View File

@ -36,8 +36,6 @@
#include "backlight_pwm.h"
#endif
uint32_t systick_val_copy = 0;
// from util.s
extern void shutdown_privileged(void);
@ -54,20 +52,6 @@ void __attribute__((noreturn)) trezor_shutdown(void) {
;
}
void hal_delay(uint32_t ms) { HAL_Delay(ms); }
uint32_t hal_ticks_ms() { return HAL_GetTick(); }
void hal_delay_us(uint16_t delay_us) {
uint32_t val = svc_get_systick_val();
uint32_t t = hal_ticks_ms() * 1000 +
(((SystemCoreClock / 1000) - val) / (SystemCoreClock / 1000000));
uint32_t t2 = t;
do {
val = svc_get_systick_val();
t2 = hal_ticks_ms() * 1000 +
(((SystemCoreClock / 1000) - val) / (SystemCoreClock / 1000000));
} while ((t2 - t) < delay_us);
}
// reference RM0090 section 35.12.1 Figure 413
#define USB_OTG_HS_DATA_FIFO_RAM (USB_OTG_HS_PERIPH_BASE + 0x20000U)
#define USB_OTG_HS_DATA_FIFO_SIZE (4096U)

View File

@ -21,6 +21,7 @@
#include "platform.h"
#include "rng.h"
#include "systick.h"
#include TREZOR_BOARD
const uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0,
@ -193,7 +194,7 @@ void set_core_clock(clock_settings_t settings) {
/* Enable PLL as main clock */
RCC->CFGR = (RCC->CFGR & ~(RCC_CFGR_SW)) | RCC_CFGR_SW_PLL;
HAL_InitTick(TICK_INT_PRIORITY);
systick_update_freq();
// turn off the HSI as it is now unused (it will be turned on again
// automatically if a clock security failure occurs)

View File

@ -44,6 +44,7 @@ https://link.springer.com/content/pdf/10.1007%2F978-3-540-72354-7_3.pdf
#include "common.h"
#include "memzero.h"
#include "rand.h"
#include "systimer.h"
// from util.s
extern void shutdown_privileged(void);
@ -151,7 +152,16 @@ static void wait(uint32_t delay) {
: "r0", "r1");
}
void random_delays_init() { drbg_init(); }
// forward declaration
static void rdi_handler(void *context);
void rdi_init() {
drbg_init();
systimer_t *timer = systimer_create(rdi_handler, NULL);
ensure(sectrue * (timer != NULL), "rdi_init failed");
systimer_set_periodic(timer, 1);
}
void rdi_start(void) {
ensure(drbg_initialized, NULL);
@ -174,7 +184,7 @@ void rdi_refresh_session_delay(void) {
refresh_session_delay = true;
}
void rdi_handler(uint32_t uw_tick) {
static void rdi_handler(void *context) {
if (rdi_disabled == secfalse) { // if rdi enabled
if (refresh_session_delay) {
session_delay = drbg_random8();

View File

@ -102,9 +102,6 @@ void SVC_C_Handler(uint32_t *stack) {
// raising privileges.
stack[6] = (uintptr_t)_reboot_to_bootloader;
return;
case SVC_GET_SYSTICK_VAL:
systick_val_copy = SysTick->VAL;
break;
case SVC_REBOOT:
NVIC_SystemReset();
break;

View File

@ -5,17 +5,13 @@
#define SVC_SET_PRIORITY 2
#define SVC_SHUTDOWN 4
#define SVC_REBOOT_TO_BOOTLOADER 5
#define SVC_GET_SYSTICK_VAL 6
#define SVC_REBOOT 7
#define SVC_REBOOT 6
#include <string.h>
#include "boot_args.h"
#include "common.h"
#include "image.h"
// from common.c
extern uint32_t systick_val_copy;
// from util.s
extern void shutdown_privileged(void);
@ -76,13 +72,3 @@ static inline void svc_shutdown(void) {
void svc_reboot_to_bootloader(void);
void svc_reboot(void);
static inline uint32_t svc_get_systick_val(void) {
if (is_mode_unprivileged() && !is_mode_handler()) {
__asm__ __volatile__("svc %0" ::"i"(SVC_GET_SYSTICK_VAL) : "memory");
return systick_val_copy;
} else {
systick_val_copy = SysTick->VAL;
return systick_val_copy;
}
}

View File

@ -1,5 +1,3 @@
// clang-format off
/*
* This file is part of the Trezor project, https://trezor.io/
*
@ -19,52 +17,194 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2013, 2014 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <stdbool.h>
#include <stddef.h>
#include "irq.h"
#include "systick.h"
#ifdef RDI
#include "random_delays.h"
#endif
#include "platform.h"
#include "systemview.h"
extern __IO uint32_t uwTick;
#include "systick.h"
#include "systick_internal.h"
#include "systimer.h"
// SysTick driver state
typedef struct {
// Set if the driver is initialized
bool initialized;
// Number of hw cycles per millisecond (tick period)
uint32_t cycles_per_ms;
// Number of hw cycles per microsecond
uint32_t cycles_per_us;
// Current tick value in hardware cycles
volatile uint64_t cycles;
// Number of ticks (ms) since the system start
volatile uint32_t ticks;
} systick_driver_t;
static systick_driver_t g_systick_driver = {
.initialized = false,
};
void systick_init(void) {
systick_driver_t* drv = &g_systick_driver;
if (drv->initialized) {
return;
}
drv->cycles = 0;
drv->ticks = 0;
// Set 1ms tick period
drv->cycles_per_ms = HAL_RCC_GetSysClockFreq() / 1000;
drv->cycles_per_us = drv->cycles_per_ms / 1000;
// Initialize and enable SysTick timer
SysTick_Config(drv->cycles_per_ms);
// We need to ensure that SysTick has the expected priority.
// The SysTick priority is configured in the boardloader,
// and some early versions didn't set this properly.
NVIC_SetPriority(SysTick_IRQn, IRQ_PRI_NORMAL);
drv->initialized = true;
}
void systick_deinit(void) {
systick_driver_t* drv = &g_systick_driver;
if (!drv->initialized) {
return;
}
NVIC_DisableIRQ(SysTick_IRQn);
SysTick->CTRL = 0;
NVIC_ClearPendingIRQ(SysTick_IRQn);
drv->initialized = false;
}
void systick_update_freq(void) {
systick_driver_t* drv = &g_systick_driver;
if (!drv->initialized) {
return;
}
uint32_t clock_freq = HAL_RCC_GetSysClockFreq();
drv->cycles_per_ms = clock_freq / 1000;
drv->cycles_per_us = drv->cycles_per_ms / 1000;
SysTick_Config(drv->cycles_per_ms);
// We need to ensure that SysTick has the expected priority.
// The SysTick priority is configured in the boardloader,
// and some early versions didn't set this properly.
NVIC_SetPriority(SysTick_IRQn, IRQ_PRI_NORMAL);
}
uint64_t systick_cycles(void) {
systick_driver_t* drv = &g_systick_driver;
uint32_t irq_state = disable_irq();
// Current value of the SysTick counter
uint32_t val = SysTick->VAL;
// Check if the SysTick has already counted down to 0 or wrapped around
// Reading CTRL register automatically clears COUNTFLAG
if ((SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk) != 0) {
// Re-read the current value of the SysTick counter
val = SysTick->VAL;
// Update the hardware cycles counter
// Since we have cleared COUNTFLAG, SysTick_Handler will not increment
drv->cycles += drv->cycles_per_ms;
// Increment regular ticks counter
drv->ticks++;
}
uint64_t cycles = drv->cycles + ((val > 0) ? (drv->cycles_per_ms - val) : 0);
enable_irq(irq_state);
return cycles;
}
uint64_t systick_us_to_cycles(uint64_t us) {
systick_driver_t* drv = &g_systick_driver;
return us * drv->cycles_per_us;
}
uint32_t systick_ms(void) {
systick_driver_t* drv = &g_systick_driver;
return drv->ticks;
}
uint64_t systick_us(void) {
systick_driver_t* drv = &g_systick_driver;
if (drv->cycles_per_us == 0) {
// The driver was not initialized yet - this could happen
// only if the function is called from the early initialization
// stage, before the `systick_init()` was called. In this case,
// we can't provide the correct value, so we return 0.
return 0;
}
return systick_cycles() / drv->cycles_per_us;
}
void SysTick_Handler(void) {
SEGGER_SYSVIEW_RecordEnterISR();
// this is a millisecond tick counter that wraps after approximately
// 49.71 days = (0xffffffff / (24 * 60 * 60 * 1000))
uint32_t uw_tick = uwTick + 1;
uwTick = uw_tick;
#ifdef RDI
rdi_handler(uw_tick);
#endif
systick_driver_t* drv = &g_systick_driver;
if (drv->initialized) {
// Increment `cycles` counter if COUNTFLAG is set.
// If COUNTFLAG is not set, `cycles` were already incremented
// in `systick_cycles()` that also cleared the COUNTFLAG.
if ((SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk) != 0) {
// Clear COUNTFLAG by reading VAL
(void)SysTick->VAL;
// Increment cycles counter by SysTick period
drv->cycles += drv->cycles_per_ms;
// Increment regular ticks counter
drv->ticks++;
}
// Invoke callbacks of expired timers
systimer_dispatch_expired_timers(drv->cycles);
}
SEGGER_SYSVIEW_RecordExitISR();
}
void systick_delay_us(uint64_t us) {
uint64_t delay_cycles = systick_us_to_cycles(us);
int64_t cycles_per_ms = systick_us_to_cycles(1000);
uint64_t end = systick_cycles() + delay_cycles;
bool irq_enabled = IS_IRQ_ENABLED(query_irq());
int64_t diff;
while ((diff = end - systick_cycles()) > 0) {
if (irq_enabled && (diff > cycles_per_ms)) {
// Enter sleep mode and wait for (at least)
// the SysTick interrupt.
__WFI();
}
}
}
void systick_delay_ms(uint32_t ms) { systick_delay_us((uint64_t)ms * 1000); }
// We provide our own version of HAL_Delay that calls __WFI while waiting,
// and works when interrupts are disabled. This function is intended to be
// used only by the ST HAL functions.
void HAL_Delay(uint32_t ms) { systick_delay_ms(ms); }
// We provide our own version of HAL_GetTick that replaces the default
// ST HAL function reading uwTick global variable.
uint32_t HAL_GetTick(void) { return systick_ms(); }

View File

@ -1,37 +0,0 @@
// clang-format off
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2013, 2014 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef MICROPY_INCLUDED_STM32_SYSTICK_H
#define MICROPY_INCLUDED_STM32_SYSTICK_H
#include <stdint.h>
#include <stddef.h>
// Works for x between 0 and 16 inclusive
#define POW2_CEIL(x) ((((x) - 1) | ((x) - 1) >> 1 | ((x) - 1) >> 2 | ((x) - 1) >> 3) + 1)
#endif // MICROPY_INCLUDED_STM32_SYSTICK_H

View File

@ -0,0 +1,12 @@
#ifndef TREZORHAL_SYSTICK_INTERNAL_H
#define TREZORHAL_SYSTICK_INTERNAL_H
#include <stdint.h>
#include "systick.h"
// Internal function called from interrupt context.
// Handles expired timers and invoked their callbacks.
void systimer_dispatch_expired_timers(uint64_t cycles);
#endif // TREZORHAL_SYSTICK_INTERNAL_H

View File

@ -0,0 +1,237 @@
/*
* 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 <stddef.h>
#include <string.h>
#include "irq.h"
#include "platform.h"
#include "systick_internal.h"
#include "systimer.h"
// Maximum number of registered user timer
//
// Consider different implementation (i.e. priority queue
// using binary heap if MAX_SYSTIMERS exceeds 10 or more)
#define MAX_SYSTIMERS 4
// User timer instance
struct systimer {
// User callback function
// Non-NULL if the timer entry is valid
volatile systimer_callback_t callback;
// User callback context
void* context;
// Set if the timer is suspended
volatile bool suspended;
// Set if the timer is scheduled
volatile bool scheduled;
// Expiration time (valid if scheduled is set)
volatile uint64_t expiration;
// Period (= 0 for non-periodic timers)
volatile uint64_t period;
};
// systimer driver state
typedef struct {
// Set if the driver is initialized
bool initialized;
// Registered timers
// (unused slots have callback field set to NULL)
systimer_t timers[MAX_SYSTIMERS];
} systimer_driver_t;
static systimer_driver_t g_systimer_driver = {
.initialized = false,
};
void systimer_init(void) {
systimer_driver_t* drv = &g_systimer_driver;
if (drv->initialized) {
return;
}
memset(drv, 0, sizeof(systimer_driver_t));
drv->initialized = true;
}
void systimer_deinit(void) {
systimer_driver_t* drv = &g_systimer_driver;
drv->initialized = false;
}
static inline bool timer_valid(const systimer_driver_t* drv,
const systimer_t* timer) {
return drv->initialized && (timer >= &drv->timers[0]) &&
(timer < &drv->timers[MAX_SYSTIMERS]);
}
systimer_t* systimer_create(systimer_callback_t callback, void* context) {
systimer_driver_t* drv = &g_systimer_driver;
if (!drv->initialized) {
return NULL;
}
if (callback == NULL) {
// Since the callback is used to determine if the
// timer is valid, it must be non-NULL.
return NULL;
}
uint32_t irq_state = disable_irq();
// Find a free timer entry
for (int i = 0; i < MAX_SYSTIMERS; i++) {
systimer_t* timer = &drv->timers[i];
if (timer->callback == NULL) {
timer->scheduled = false;
timer->suspended = false;
timer->context = context;
timer->callback = callback;
enable_irq(irq_state);
return timer;
}
}
// No free timer entry found
enable_irq(irq_state);
return NULL;
}
void systimer_delete(systimer_t* timer) {
systimer_driver_t* drv = &g_systimer_driver;
if (!timer_valid(drv, timer)) {
return;
}
timer->callback = NULL;
}
void systimer_set(systimer_t* timer, uint32_t delay_ms) {
systimer_driver_t* drv = &g_systimer_driver;
if (!timer_valid(drv, timer)) {
return;
}
uint64_t delay = systick_us_to_cycles((uint64_t)delay_ms * 1000);
uint64_t expiration = systick_cycles() + delay;
uint32_t irq_state = disable_irq();
timer->expiration = expiration;
timer->period = 0;
timer->scheduled = true;
enable_irq(irq_state);
}
void systimer_set_periodic(systimer_t* timer, uint32_t period_ms) {
systimer_driver_t* drv = &g_systimer_driver;
if (!timer_valid(drv, timer)) {
return;
}
uint64_t period = systick_us_to_cycles((uint64_t)period_ms * 1000);
uint64_t expiration = systick_cycles() + period;
uint32_t irq_state = disable_irq();
timer->expiration = expiration;
timer->period = period;
timer->scheduled = true;
enable_irq(irq_state);
}
bool systimer_unset(systimer_t* timer) {
systimer_driver_t* drv = &g_systimer_driver;
if (!timer_valid(drv, timer)) {
return false;
}
uint32_t irq_state = disable_irq();
bool was_scheduled = timer->scheduled;
timer->scheduled = false;
enable_irq(irq_state);
return was_scheduled;
}
systimer_key_t systimer_suspend(systimer_t* timer) {
systimer_driver_t* drv = &g_systimer_driver;
if (!timer_valid(drv, timer)) {
return false;
}
uint32_t irq_state = disable_irq();
bool was_suspended = timer->suspended;
timer->suspended = true;
enable_irq(irq_state);
return was_suspended;
}
void systimer_resume(systimer_t* timer, systimer_key_t key) {
systimer_driver_t* drv = &g_systimer_driver;
if (!timer_valid(drv, timer)) {
return;
}
timer->suspended = key;
}
// Called from interrupt context
void systimer_dispatch_expired_timers(uint64_t cycles) {
systimer_driver_t* drv = &g_systimer_driver;
if (!drv->initialized) {
return;
}
// Go through all timer slots and invoke callbacks of expired timers
// This algorithm is not efficient for large number of timers
// but it is good enough if MAX_SYSTIMERS ~ 10
for (int i = 0; i < MAX_SYSTIMERS; i++) {
systimer_t* timer = &drv->timers[i];
if (timer->callback == NULL || timer->suspended || !timer->scheduled) {
continue;
}
if (cycles < timer->expiration) {
continue;
}
if (timer->period > 0) {
// Reschedule periodic timer
timer->expiration = cycles + timer->period;
} else {
// Stop one-shot timer
timer->scheduled = false;
}
// Callback is invoked from interrupt context
timer->callback(timer->context);
}
}

View File

@ -32,8 +32,6 @@
#include "stm32u5xx_ll_utils.h"
uint32_t systick_val_copy = 0;
// from util.s
extern void shutdown_privileged(void);
@ -55,20 +53,6 @@ void __attribute__((noreturn)) trezor_shutdown(void) {
;
}
void hal_delay(uint32_t ms) { HAL_Delay(ms); }
uint32_t hal_ticks_ms() { return HAL_GetTick(); }
void hal_delay_us(uint16_t delay_us) {
uint32_t val = svc_get_systick_val();
uint32_t t = hal_ticks_ms() * 1000 +
(((SystemCoreClock / 1000) - val) / (SystemCoreClock / 1000000));
uint32_t t2 = t;
do {
val = svc_get_systick_val();
t2 = hal_ticks_ms() * 1000 +
(((SystemCoreClock / 1000) - val) / (SystemCoreClock / 1000000));
} while ((t2 - t) < delay_us);
}
uint32_t __stack_chk_guard = 0;
void __attribute__((noreturn)) __stack_chk_fail(void) {

View File

@ -1 +0,0 @@
../stm32f4/systick.h

View File

@ -0,0 +1 @@
../stm32f4/systick_internal.h

View File

@ -0,0 +1 @@
../stm32f4/systimer.c

View File

@ -0,0 +1,96 @@
/*
* 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/>.
*/
#ifndef TREZORHAL_SYSTICK_H
#define TREZORHAL_SYSTICK_H
#include <stdbool.h>
#include <stdint.h>
// Initializes systick subsystem
//
// Before calling this function, none of the other functions
// from this module should be called.
void systick_init(void);
// Deinitialize systick subsystem
//
// The function should be called before jumping to the
// next bootloader stage or firmware.
void systick_deinit(void);
// Updates systick subsystem with new system clock frequency
//
// The function should be called after the system clock frequency
// has been changed.
void systick_update_freq(void);
// ----------------------------------------------------------------------------
// Tick functions
// Returns number of system clock cycles since the system start.
//
// Read monotonic counter with high resolution (Cortex-M SysTick clock)
// (On 160MHz CPU, 1 cycles is 1 / 160MHz = 6.25ns)
uint64_t systick_cycles(void);
// Returns number of microseconds since the system start.
uint64_t systick_us(void);
// Returns number of ticks (milliseconds) since the system start.
//
// The returned value is a 32-bit unsigned integer that wraps
// around every 49.7 days.
uint32_t systick_ms(void);
// Converts microseconds to system clock cycles
uint64_t systick_us_to_cycles(uint64_t us);
// Number of ticks (milliseconds)
typedef uint32_t ticks_t;
//
#define ticks() systick_ms()
// Helper function for building expiration time
#define ticks_timeout(timeout) (systick_ms() + (timeout))
// Helper function for checking ticks expiration
//
// It copes with the wrap-around of the `ticks_t` type but
// still assumes that the difference between the two ticks
// is less than half of the `ticks_t` range.
#define ticks_expired(ticks) ((int32_t)(systick_ms() - (ticks)) >= 0)
// ----------------------------------------------------------------------------
// Delay functions
// Waits for at least `ms` milliseconds
void systick_delay_ms(uint32_t ms);
// Waits for at least `us` microseconds
void systick_delay_us(uint64_t us);
// legacy functions
static inline uint32_t hal_ticks_ms(void) { return systick_ms(); }
static inline void hal_delay(uint32_t ms) { systick_delay_ms(ms); }
static inline void hal_delay_us(uint64_t us) { systick_delay_us(us); }
#endif // TREZORHAL_SYSTICK_H

View File

@ -0,0 +1,93 @@
/*
* 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/>.
*/
#ifndef TREZORHAL_SYSTIMER_H
#define TREZORHAL_SYSTIMER_H
#include <stdbool.h>
#include <stdint.h>
// Initializes systimer subsystem
//
// Before calling this function, none of the other functions
// from this module should be called.
void systimer_init(void);
// Deinitialize sytimer subsystem
void systimer_deinit(void);
// Timer handle
typedef struct systimer systimer_t;
// Timer callback routine invoked when timer expires
//
// The callback should be as short as possible and should not
// block. It is invoked from the timer interrupt context.
//
// `context` is the pointer passed to `timer_create`
typedef void (*systimer_callback_t)(void* context);
// Initializes the timer and returns its handle.
//
// There a limited number of timers and `NULL` is returned
// if no timer is available.
systimer_t* systimer_create(systimer_callback_t callback, void* context);
// Deletes the timer
//
// Timer is unset and its resources are released.
void systimer_delete(systimer_t* timer);
// Sets the timer to expire in `delay_ms` milliseconds
//
// If the timer is already set, it will be rescheduled.
void systimer_set(systimer_t* timer, uint32_t delay_ms);
// Sets the timer to expire periodically every `period_ms` milliseconds
//
// If the timer is already set, it will be rescheduled.
void systimer_set_periodic(systimer_t* timer, uint32_t period_ms);
// Unsets the timer (cancels the expiration)
//
// Timer is not deleted and can be set again.
//
// Returns `true` if the timer was unset before its expiration
// so the callback will not be invoked.
bool systimer_unset(systimer_t* timer);
// Timer suspension state (opaque type).
// Allows to recursively suspend/resume timer.
typedef bool systimer_key_t;
// Suspends timer callback invocation
//
// The purpose of this function is to prevent the timer callback
// from being invoked for synchronization purposes. The function
// returns a lock that should be passed to `systimer_resume()` to
// resume the timer callback invocation.
systimer_key_t systimer_suspend(systimer_t* timer);
// Resumes timer callback invocation
//
// The timer callback invocation is resumed. The `key` should
// be the same as returned by `timer_suspend()`.
void systimer_resume(systimer_t* timer, systimer_key_t key);
#endif // TREZORHAL_SYSTIMER_H

View File

@ -40,14 +40,6 @@ void __attribute__((noreturn)) trezor_shutdown(void) {
exit(3);
}
void hal_delay(uint32_t ms) { usleep(1000 * ms); }
uint32_t hal_ticks_ms() {
struct timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_sec * 1000 + tv.tv_usec / 1000;
}
static int SDLCALL emulator_event_filter(void *userdata, SDL_Event *event) {
switch (event->type) {
case SDL_QUIT:

View File

@ -21,4 +21,4 @@
void wait_random(void) {}
void random_delays_init(void) {}
void rdi_init(void) {}

View File

@ -20,7 +20,7 @@
#ifndef __TREZORHAL_RANDOM_DELAYS_H__
#define __TREZORHAL_RANDOM_DELAYS_H__
void random_delays_init(void);
void rdi_init(void);
void wait_random(void);
#endif

View File

@ -0,0 +1,128 @@
/*
* 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 <stdbool.h>
#include <stddef.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "systick.h"
// Systick driver state
typedef struct {
// Set if the driver is initialized
bool initialized;
// Instant time [us] of driver initialization
uint64_t initial_time;
// Instant time [us] of driver deinitialization
uint64_t final_time;
} systick_driver_t;
static systick_driver_t g_systick_driver = {
.initialized = false,
};
// Returns number of microseconds since the os started
static uint64_t get_monotonic_clock(void) {
struct timespec tp;
clock_gettime(CLOCK_MONOTONIC, &tp);
return tp.tv_sec * 1000000UL + tp.tv_nsec / 1000;
}
void systick_init(void) {
systick_driver_t* drv = &g_systick_driver;
if (drv->initialized) {
return;
}
memset(drv, 0, sizeof(systick_driver_t));
drv->initial_time = get_monotonic_clock();
drv->initialized = true;
}
void systick_deinit(void) {
systick_driver_t* drv = &g_systick_driver;
if (!drv->initialized) {
return;
}
// This will ensure that the time return by `systick_ms()` and
// `systick_us()` will not be reset to 0 after the `systick_deinit()` call.
drv->final_time = get_monotonic_clock();
drv->initialized = false;
}
void systick_update_freq(void){};
uint32_t systick_ms() {
systick_driver_t* drv = &g_systick_driver;
if (!drv->initialized) {
systick_init(); // temporary workaround required by rust unit tests
// return drv->final_time / 1000;
}
return (get_monotonic_clock() - drv->initial_time) / 1000;
}
uint64_t systick_us(void) {
systick_driver_t* drv = &g_systick_driver;
if (!drv->initialized) {
systick_init(); // temporary workaround required by rust unit tests
// return drv->final_time;
}
return get_monotonic_clock() - drv->initial_time;
}
void systick_delay_us(uint64_t us) {
systick_driver_t* drv = &g_systick_driver;
if (!drv->initialized) {
systick_init(); // temporary workaround required by rust unit tests
// return;
}
struct timespec tp;
tp.tv_sec = us / 1000000;
tp.tv_nsec = (us % 1000000) * 1000;
nanosleep(&tp, NULL);
}
void systick_delay_ms(uint32_t ms) {
systick_driver_t* drv = &g_systick_driver;
if (!drv->initialized) {
systick_init(); // temporary workaround required by rust unit tests
// return;
}
struct timespec tp;
tp.tv_sec = ms / 1000;
tp.tv_nsec = (ms % 1000) * 1000000;
nanosleep(&tp, NULL);
}

View File

@ -0,0 +1,52 @@
/*
* 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 <string.h>
#include "systimer.h"
// systimer driver state
typedef struct {
// Set if the driver is initialized
bool initialized;
} systimer_driver_t;
static systimer_driver_t g_systimer_driver = {
.initialized = false,
};
void systimer_init(void) {
systimer_driver_t* drv = &g_systimer_driver;
if (drv->initialized) {
return;
}
memset(&drv, 0, sizeof(systimer_driver_t));
drv->initialized = true;
}
void systimer_deinit(void) {
systimer_driver_t* drv = &g_systimer_driver;
drv->initialized = false;
}
// Timer driver is not fully implemented for unix platform
// since not neeeded for the emulator

View File

@ -53,6 +53,7 @@
#include "py/repl.h"
#include "py/runtime.h"
#include "py/stackctrl.h"
#include "systimer.h"
#include "touch.h"
#include "common.h"
@ -486,6 +487,9 @@ MP_NOINLINE int main_(int argc, char **argv) {
pre_process_options(argc, argv);
systick_init();
systimer_init();
display_init(DISPLAY_RESET_CONTENT);
#if USE_TOUCH

View File

@ -53,6 +53,7 @@ def stm32f4_common_files(env, defines, sources, paths):
"embed/trezorhal/stm32f4/platform.c",
"embed/trezorhal/stm32f4/secret.c",
"embed/trezorhal/stm32f4/systick.c",
"embed/trezorhal/stm32f4/systimer.c",
"embed/trezorhal/stm32f4/supervise.c",
"embed/trezorhal/stm32f4/time_estimate.c",
"embed/trezorhal/stm32f4/random_delays.c",

View File

@ -64,6 +64,7 @@ def stm32u5_common_files(env, defines, sources, paths):
"embed/trezorhal/stm32u5/secret.c",
"embed/trezorhal/stm32u5/secure_aes.c",
"embed/trezorhal/stm32u5/systick.c",
"embed/trezorhal/stm32f4/systimer.c",
"embed/trezorhal/stm32f4/supervise.c",
"embed/trezorhal/stm32u5/random_delays.c",
"embed/trezorhal/stm32u5/rng.c",