12#include "stk_config.h"
14#ifdef _STK_ARCH_ARM_CORTEX_M
16#ifdef _STK_CORTEX_M_TRUSTZONE
28#if !defined(_STK_CORTEX_M_TRUSTZONE_NON_SECURE)
33#error Expecting __CORTEX_M with value corresponding to Cortex-M model (0, 3, 4, ...)!
38 #error "SysTick peripheral definition is missing!"
42#if (__CORTEX_M > 1U) && STK_TICKLESS_USE_ARM_DWT && !defined(DWT)
43 #error "DWT peripheral definition is missing!"
47#define STK_CORTEX_M_FPU ((__FPU_PRESENT == 1U) && (__FPU_USED == 1U))
51 #define STK_CORTEX_M_MPU (__MPU_PRESENT == 1U)
53 #define STK_CORTEX_M_MPU (0)
57 #error "MPU is not present on this platform, STK_MPU feature is not supported!"
59 #if STK_MPU_STACK_GUARD
60 #error "MPU is not present on this platform, STK_MPU_STACK_GUARD feature is not supported!"
63#if STK_MPU_STACK_GUARD && !STK_MPU
64 #error "Enable MPU support (STK_MPU=1) to use per-task MPU feature (STK_MPU_STACK_GUARD=1)!"
79#ifndef STK_CORTEX_M_MPU_TASK_REGION_IDX
80 #define STK_CORTEX_M_MPU_TASK_REGION_IDX (STK_CORTEX_M_MPU_REGIONS_MAX - STK_MPU_TASK_REGIONS)
95#ifndef STK_CORTEX_M_MPU_TASK_REGION_IDX_NS
96 #define STK_CORTEX_M_MPU_TASK_REGION_IDX_NS (STK_CORTEX_M_MPU_REGIONS_MAX - STK_MPU_TASK_REGIONS_NS)
100#define STK_CORTEX_M_MANAGE_LR (__CORTEX_M >= 3U)
103#define STK_CORTEX_M_PAC (__ARM_FEATURE_PA_BITS && (__CORTEX_M >= 85U))
106#define STK_CORTEX_M_EXC_RETURN_THREAD_PSP (0xFFFFFFFDU)
109#define STK_CORTEX_M_ISR_PRIORITY_HIGHEST (0U)
110#define STK_CORTEX_M_ISR_PRIORITY_LOWEST (0xFFU)
113#if STK_CORTEX_M_MANAGE_LR
114 #define STK_CORTEX_M_REGISTER_COUNT (17U)
116 #define STK_CORTEX_M_REGISTER_COUNT (16U)
128#ifdef _STK_CORTEX_M_TRUSTZONE
129 #define STK_CORTEX_M_TZ_REGISTER_COUNT (4U)
131 #define STK_CORTEX_M_TZ_REGISTER_COUNT (0U)
142#ifdef CONTROL_nPRIV_Msk
143 #define STK_CORTEX_M_PRIVILEGE_FRAME (1)
145 #define STK_CORTEX_M_PRIVILEGE_FRAME (0)
149#if STK_CORTEX_M_PRIVILEGE_FRAME
150 #define STK_CORTEX_M_PRIV_REGISTER_COUNT (1U)
152 #define STK_CORTEX_M_PRIV_REGISTER_COUNT (0U)
156#define STK_CORTEX_M_TOTAL_REGISTER_COUNT \
157 (STK_CORTEX_M_REGISTER_COUNT + STK_CORTEX_M_TZ_REGISTER_COUNT + STK_CORTEX_M_PRIV_REGISTER_COUNT)
160#ifndef STK_SYSTICK_HANDLER
161 #define STK_SYSTICK_HANDLER SysTick_Handler
165#ifndef STK_PENDSV_HANDLER
166 #define STK_PENDSV_HANDLER PendSV_Handler
170#ifndef STK_SVC_HANDLER
171 #define STK_SVC_HANDLER SVC_Handler
175#ifndef STK_USE_MEMMANAGE_HANDLER
176#define STK_USE_MEMMANAGE_HANDLER (0)
178#if STK_USE_MEMMANAGE_HANDLER
179 #ifndef STK_MEMMANAGE_HANDLER
180 #define STK_MEMMANAGE_HANDLER MemManage_Handler
185#ifndef STK_USE_HARDFAULT_HANDLER
186#define STK_USE_HARDFAULT_HANDLER (0)
188#if STK_USE_HARDFAULT_HANDLER
189 #ifndef STK_HARDFAULT_HANDLER
190 #define STK_HARDFAULT_HANDLER HardFault_Handler
201#ifndef STK_SPINLOCK_TIMEOUT_US
202 #define STK_SPINLOCK_TIMEOUT_US (5U * 1000U * 1000U)
214#ifndef STK_SPINLOCK_MIN_CYCLES_PER_ITER
215 #define STK_SPINLOCK_MIN_CYCLES_PER_ITER (4U)
223#ifndef STK_CORTEX_M_FORCE_SWITCH
224 #define STK_CORTEX_M_FORCE_SWITCH (1)
233enum ESvcCommandId : uint8_t
235 SVC_START_SCHEDULING = 0U,
241#if STK_CORTEX_M_FORCE_SWITCH
259 MASK_THUMB_BIT = (1U << 0U)
263static inline Word ClearThumbBit(Word REG_PC)
noexcept
265 return (REG_PC & ~
static_cast<Word>(ERegMask::MASK_THUMB_BIT));
274constexpr Word DEFAULT_INIT = 0U;
279 MASK_T_BIT = (1U << 24U)
283static inline Word SetThumbExecution(Word REG_XPSR)
noexcept
285 return (REG_XPSR |
static_cast<Word>(ERegMask::MASK_T_BIT));
294constexpr Word DEFAULT_INIT = 0U;
299 MASK_nPRIV = (1U << 0),
300 MASK_SPSEL = (1U << 1),
301 MASK_FPCA = (1U << 2),
302 MASK_SFPA = (1U << 3)
308 return (REG_CONTROL |
static_cast<Word>(ERegMask::MASK_nPRIV));
314 return (REG_CONTROL & ~
static_cast<Word>(ERegMask::MASK_nPRIV));
320 return (REG_CONTROL |
static_cast<Word>(ERegMask::MASK_SPSEL));
349static inline RegionBounds GetRegionBounds(
const MpuRegionConfig &cfg)
351 RegionBounds result = { 0U, 0U,
false };
353 if ((cfg.size != 0U) && (cfg.access_perm != EMpuAccess::ACCESS_NONE))
357 result.start = cfg.addr & ~31U;
358 result.end = result.start + cfg.size - 1U;
361 result.start = cfg.addr & ~(cfg.size - 1U);
362 result.end = result.start + cfg.size - 1U;
365 result.valid = (result.start < result.end);
371static inline bool IsOverlapping(
const RegionBounds &a,
const RegionBounds &b)
375 return ((!a.valid || !b.valid) ?
false : (a.start <= b.end) && (b.start <= a.end));
384static void ValidateNoOverlaps(
const MpuRegionConfig dynamic_cfg_list[],
size_t dynamic_cfg_count,
385 const MpuRegionConfig static_cfg_list[],
size_t static_cfg_count)
388 for (
size_t i = 0U; i < dynamic_cfg_count; ++i)
390 const RegionBounds bounds_i = GetRegionBounds(dynamic_cfg_list[i]);
396 for (
size_t j = i + 1U; j < dynamic_cfg_count; ++j)
398 const RegionBounds bounds_j = GetRegionBounds(dynamic_cfg_list[j]);
405 if (IsOverlapping(bounds_i, bounds_j))
407 STK_KERNEL_PANIC(KERNEL_PANIC_BAD_MEMORY_REGION);
412 if (static_cfg_list !=
nullptr)
414 for (
size_t k = 0U; k < static_cfg_count; ++k)
416 const RegionBounds static_bounds = GetRegionBounds(static_cfg_list[k]);
417 if (!static_bounds.valid)
423 if (IsOverlapping(bounds_i, static_bounds))
425 STK_KERNEL_PANIC(KERNEL_PANIC_BAD_MEMORY_REGION);
442#if defined(_STK_CORTEX_M_TRUSTZONE) && (STK_CORTEX_M_TZ_REGISTER_COUNT != 0U)
471#define STK_CORTEX_M_TRUSTZONE_FRAME (1)
473#define STK_CORTEX_M_TRUSTZONE_FRAME (0)
476#if STK_CORTEX_M_PRIVILEGE_FRAME
503#if STK_CORTEX_M_MANAGE_LR
506 hw::ExceptionFrame exc;
510#define STK_ASM_EXIT_FROM_HANDLER "BX LR"
511#define STK_ASM_DISABLE_INTERRUPTS "CPSID i"
512#define STK_ASM_ENABLE_INTERRUPTS "CPSIE i"
516static void OnTaskRun(
ITask *runnable);
517static void OnTaskExit();
518static void OnSchedulerSleep();
519static void OnSchedulerSleepOverride();
520static void OnSchedulerExit();
521#if STK_SEGGER_SYSVIEW
522static void SendSysDesc()
524 SEGGER_SYSVIEW_SendSysDesc(
"SuperTinyKernel RTOS (STK)");
530#if STK_SEGGER_SYSVIEW
533 SEGGER_SYSVIEW_RecordEnterISR();
539#if STK_CORE_FREQ_UNIFIED
540static uint32_t s_StkSystemCoreClock[1U];
554static uint32_t s_StkSpinlockTimeoutIters = 0xFFFFFFFU;
558static volatile bool s_StkCortexmCsuLock =
false;
569 __asm
volatile(
"SVC %0"
571 :
"I"(SVC_START_SCHEDULING)
578#if STK_CORTEX_M_FORCE_SWITCH
586 "I" (SVC_FORCE_SWITCH)
603 __asm
volatile(
"SVC %0"
605 :
"I"(SVC_ENTER_CRITICAL)
621 __asm
volatile(
"SVC %0"
623 :
"I"(SVC_EXIT_CRITICAL)
632#if (defined(__clang__) && defined(__ARMCOMPILER_VERSION)) || defined(__ICCARM__)
633 __asm
volatile(STK_ASM_DISABLE_INTERRUPTS :::
"memory");
643#if (defined(__clang__) && defined(__ARMCOMPILER_VERSION)) || defined(__ICCARM__)
644 __asm
volatile(STK_ASM_ENABLE_INTERRUPTS :::
"memory");
656#if (defined(__clang__) && defined(__ARMCOMPILER_VERSION)) || defined(__ICCARM__)
658 __asm
volatile(
"MRS %0, primask" :
"=r"(primask));
659 return ((primask & 1U) != 0U);
661 return ((__get_PRIMASK() & 1U) != 0U);
670 const uint32_t ses = __get_PRIMASK();
671 HW_DisableInterrupts();
696 SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk;
705 #define __ATOMIC_RELAXED __MEMORY_ORDER_RELAXED__
706 #define __ATOMIC_CONSUME __MEMORY_ORDER_CONSUME__
707 #define __ATOMIC_ACQUIRE __MEMORY_ORDER_ACQUIRE__
708 #define __ATOMIC_RELEASE __MEMORY_ORDER_RELEASE__
709 #define __ATOMIC_ACQ_REL __MEMORY_ORDER_ACQ_REL__
710 #define __ATOMIC_SEQ_CST __MEMORY_ORDER_SEQ_CST__
712 static __stk_forceinline bool __atomic_test_and_set(
volatile bool *ptr,
int memorder)
718 return std::__iar_atomic_flag_test_and_set(ptr, memorder);
727 std::__iar_atomic_flag_clear(ptr, memorder);
731#ifdef CONTROL_nPRIV_Msk
746 return !__atomic_test_and_set(&lock, __ATOMIC_ACQUIRE);
773 __asm
volatile(
"dmb ishst" :::
"memory");
776 __atomic_clear(&lock, __ATOMIC_RELEASE);
778#elif defined(RP2040_H) || defined(RP2350_H)
780#define STK_SIO_SPINLOCK SIO->SPINLOCK31
799 bool success = (STK_SIO_SPINLOCK == 0 ? false : ((lock) =
true,
true));
828 STK_SIO_SPINLOCK = 1;
831#undef STK_SIO_SPINLOCK
850 const uint32_t ses = HW_CriticalSectionStart();
854 HW_CriticalSectionEnd(ses);
861 HW_CriticalSectionEnd(ses);
907 uint32_t timeout = s_StkSpinlockTimeoutIters;
908 while (!HW_SpinLockTryLock(lock))
959 Word R4, R5, R6, R7, R8, R9, R10, R11;
985int32_t SaveJmp(JmpFrame &)
990#if (__CORTEX_M >= 3U)
992 "STMIA r0, {r4-r11} \n"
993 "STR SP, [r0, #32] \n"
994 "STR LR, [r0, #36] \n"
997 "STR r4, [r0, #0] \n"
998 "STR r5, [r0, #4] \n"
999 "STR r6, [r0, #8] \n"
1000 "STR r7, [r0, #12] \n"
1002 "STR r1, [r0, #16] \n"
1004 "STR r1, [r0, #20] \n"
1006 "STR r1, [r0, #24] \n"
1008 "STR r1, [r0, #28] \n"
1010 "STR r1, [r0, #32] \n"
1012 "STR r1, [r0, #36] \n"
1017 "STR r1, [r0, #40] \n"
1021 "PAC r12, LR, SP \n"
1022 #if STK_CORTEX_M_FPU
1023 "STR r12, [r0, #44] \n"
1025 "STR r12, [r0, #40] \n"
1033#pragma diag_suppress=Pe940
1037#pragma diag_default=Pe940
1059void RestoreJmp(JmpFrame &, int32_t )
1064#if (__CORTEX_M >= 3U)
1066 "LDR sp, [r0, #32] \n"
1069 "LDR r2, [r0, #40] \n"
1074 #if STK_CORTEX_M_FPU
1075 "LDR r12, [r0, #44] \n"
1077 "LDR r12, [r0, #40] \n"
1081 "LDR r2, [r0, #36] \n"
1083 #if STK_CORTEX_M_PAC
1085 "AUT r12, LR, SP \n"
1089 "LDMIA r0, {r4-r11} \n"
1094 "LDR r2, [r0, #36] \n"
1096 "LDR r2, [r0, #32] \n"
1098 "LDR r2, [r0, #28] \n"
1100 "LDR r2, [r0, #24] \n"
1102 "LDR r2, [r0, #20] \n"
1104 "LDR r2, [r0, #16] \n"
1106 "LDR r4, [r0, #0] \n"
1107 "LDR r5, [r0, #4] \n"
1108 "LDR r6, [r0, #8] \n"
1109 "LDR r7, [r0, #12] \n"
1126 return __get_IPSR();
1133 return (HW_GetCurrentException() != 0U);
1141#ifdef CONTROL_nPRIV_Msk
1142 return ((__get_CONTROL() & CONTROL_nPRIV_Msk) == 0U);
1155 __asm
volatile(
"MOV %0, SP" :
"=r" (sp));
1163 SCB->ICSR = SCB_ICSR_PENDSVSET_Msk;
1171 __set_CONTROL(__get_CONTROL() & ~CONTROL_FPCA_Msk);
1184#if defined(STK_CORTEX_M_FPU) && (STK_CORTEX_M_FPU != 0)
1187 constexpr uint32_t SCB_CPACR_CP10_FULL_ACCESS = (3UL << 20U);
1188 constexpr uint32_t SCB_CPACR_CP11_FULL_ACCESS = (3UL << 22U);
1193 uint32_t cpacr_val = SCB->CPACR;
1194 cpacr_val |= (SCB_CPACR_CP10_FULL_ACCESS | SCB_CPACR_CP11_FULL_ACCESS);
1195 SCB->CPACR = cpacr_val;
1197#if defined(_STK_CORTEX_M_TRUSTZONE)
1198 constexpr uint32_t SCB_NSACR_CP10_ACCESS = (1UL << 10U);
1199 constexpr uint32_t SCB_NSACR_CP11_ACCESS = (1UL << 11U);
1206 uint32_t nsacr_val = SCB->NSACR;
1207 nsacr_val |= (SCB_NSACR_CP10_ACCESS | SCB_NSACR_CP11_ACCESS);
1208 SCB->NSACR = nsacr_val;
1211 uint32_t ns_cpacr_val = SCB_NS->CPACR;
1212 ns_cpacr_val |= (SCB_CPACR_CP10_FULL_ACCESS | SCB_CPACR_CP11_FULL_ACCESS);
1213 SCB_NS->CPACR = ns_cpacr_val;
1216 uint32_t fpccr_val = FPU->FPCCR;
1217 fpccr_val |= (
static_cast<uint32_t
>(FPU_FPCCR_ASPEN_Msk) |
static_cast<uint32_t
>(FPU_FPCCR_LSPEN_Msk));
1218 FPU->FPCCR = fpccr_val;
1220 uint32_t ns_fpccr_val = FPU_NS->FPCCR;
1221 ns_fpccr_val |= (
static_cast<uint32_t
>(FPU_FPCCR_ASPEN_Msk) |
static_cast<uint32_t
>(FPU_FPCCR_LSPEN_Msk));
1222 FPU_NS->FPCCR = ns_fpccr_val;
1228 uint32_t fpccr_val = FPU->FPCCR;
1229 fpccr_val |= (
static_cast<uint32_t
>(FPU_FPCCR_ASPEN_Msk) |
static_cast<uint32_t
>(FPU_FPCCR_LSPEN_Msk));
1230 FPU->FPCCR = fpccr_val;
1245#if STK_CORE_FREQ_UNIFIED
1246 return s_StkSystemCoreClock[0];
1256 SCB->ICSR = SCB_ICSR_PENDSVCLR_Msk;
1263 const uint32_t result = SysTick_Config(
static_cast<uint32_t
>(
ConvertTimeUsToClockCycles(HW_CoreClockFrequency(), period_ticks)));
1281 SCB->ICSR = SCB_ICSR_PENDSTCLR_Msk;
1289 SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;
1297 return SysTick->VAL;
1311 uint32_t val = HW_SysTickValue();
1314 val = SysTick->LOAD;
1326 return SysTick->LOAD - val;
1335 SysTick->LOAD = ticks - 1U;
1337 SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;
1345#if defined(CoreDebug)
1346 CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
1348 DCB->DEMCR |= DCB_DEMCR_TRCENA_Msk;
1354#if (__CORTEX_M == 7U)
1355 DWT->LAR = 0xC5ACCE55;
1361 if ((DWT->CTRL & DWT_CTRL_CYCCNTENA_Msk) != DWT_CTRL_CYCCNTENA_Msk)
1364 DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
1394static void HW_InitSpinlockTimeout()
1397 const Cycles iters = cycles_budget / STK_SPINLOCK_MIN_CYCLES_PER_ITER;
1401 s_StkSpinlockTimeoutIters =
static_cast<uint32_t
>(
1427struct ScopedPrivilegeBoost
1434 explicit ScopedPrivilegeBoost();
1442 ~ScopedPrivilegeBoost()
1445 __set_CONTROL(__get_CONTROL() | CONTROL_nPRIV_Msk);
1465ScopedPrivilegeBoost::ScopedPrivilegeBoost()
1471 :
"I"(SVC_BOOST_PRIV)
1502void ConfigureRegion(MpuRegion ®,
const struct MpuRegionConfig &cfg, uint32_t region_idx);
1515void ConfigureStatic(
const MpuRegionConfig cfg_list[],
size_t cfg_count, uint32_t control_flags,
1530void ConfigureDynamic(TaskMpu &task_mpu,
const struct MpuRegionConfig cfg_list[],
const size_t cfg_count,
1531 IPlatform::IEventOverrider *overrider,
bool non_secure);
1544void ApplyRegion(
const MpuRegion ®, uint32_t index,
bool non_secure);
1553void DisableRegion(uint32_t index,
bool non_secure);
1565void Enable(
bool enable, uint32_t control_flags,
bool non_secure);
1575static constexpr uint32_t MAIR0_PMSAV8_INIT = 0xFF440400U;
1581static constexpr uint32_t MAIR1_PMSAV8_INIT = 0x00000000U;
1587static constexpr Word RLAR_ENABLE_FLAG = (1U << 0U);
1608static constexpr Word RLAR_DISABLED_REGION = 0U;
1614static constexpr Word RASR_ENABLE_FLAG = (1U << 0U);
1624static constexpr Word RBAR_DISABLED_REGION(uint32_t region_idx) {
return (1U << 4U) | (region_idx & 0xFU); }
1631static constexpr Word RASR_DISABLED_REGION = 0U;
1659 extern char __stk_mpu_shared_code_start[];
1660 extern char __stk_mpu_shared_code_end[];
1661 #if defined(DEBUG) || defined(_DEBUG)
1662 extern char __stk_mpu_shared_data_start[];
1663 extern char __stk_mpu_shared_data_end[];
1673static constexpr MpuRegionConfig s_StkDisabledMpuRegion =
1677 .access_perm = hw::mpu::ACCESS_NONE,
1678 .mem_type = hw::mpu::TYPE_STRONGLY_ORDERED,
1679 .share = hw::mpu::SHARE_NON,
1680 .exec = hw::mpu::EXEC_ALLOWED
1689 typedef IPlatform::IEventOverrider eovrd_t;
1691 explicit Context() : PlatformContext(), m_exit_buf(), m_overrider(nullptr),
1692 #if STK_CORTEX_M_TRUSTZONE_FRAME
1693 m_overrider_ns(nullptr),
1695 #if STK_TICKLESS_IDLE
1696 m_sleep_ticks(0), m_sleep_error(0U),
1698 m_csu(0U), m_csu_nesting(0U), m_started(false), m_exiting(false)
1701 void Initialize(IPlatform::IEventHandler *handler, IKernelService *service, Stack *exit_trap,
1702 uint32_t resolution_us)
1704 InitializeBase(handler, service, exit_trap, resolution_us);
1707 "expect Stack::mode member at offset of 0 (first member)");
1712 : ((STK_CORTEX_M_MPU_TASK_REGION_IDX % 4U) == 0U),
1713 "STK_CORTEX_M_MPU_TASK_REGION_IDX is not aligned correctly for the RNR-relative "
1714 "alias burst write at the configured STK_MPU_TASK_REGIONS width");
1718 "STK_MPU_TASK_REGIONS must be defined as 2, 4, 6, 8, 12 or 16");
1719 #ifdef _STK_CORTEX_M_TRUSTZONE
1723 : ((STK_CORTEX_M_MPU_TASK_REGION_IDX_NS % 4U) == 0U),
1724 "STK_CORTEX_M_MPU_TASK_REGION_IDX_NS is not aligned correctly for the RNR-relative "
1725 "alias burst write at the configured STK_MPU_TASK_REGIONS_NS width");
1729 "STK_MPU_TASK_REGIONS_NS must be defined as 2, 4, 6, 8, 12 or 16");
1733 STK_ASSERT(hw::PtrToWord(__stk_mpu_shared_code_end) - hw::PtrToWord(__stk_mpu_shared_code_start) > 0U);
1734 STK_ASSERT(hw::PtrToWord(__stk_mpu_shared_data_end) - hw::PtrToWord(__stk_mpu_shared_data_start) > 0U);
1737 STK_ASSERT(g_StkLastPanicId == KERNEL_PANIC_NONE);
1743 #if STK_TICKLESS_IDLE
1749 if (s_StkSystemCoreClock[0] == 0U)
1753 s_StkSystemCoreClock[i] = SystemCoreClock;
1757 HW_InitSpinlockTimeout();
1759 #if (__CORTEX_M > 1) && STK_TICKLESS_USE_ARM_DWT
1760 HW_DWTEnableCounter();
1763 #if STK_SEGGER_SYSVIEW
1764 SEGGER_SYSVIEW_Init(
1765 HW_CoreClockFrequency(),
1766 HW_CoreClockFrequency(),
1772#if STK_TICKLESS_IDLE
1778 if (m_handler->OnTick(m_stack_idle, m_stack_active
1779 #
if STK_TICKLESS_IDLE
1784 HW_ScheduleContextSwitch();
1790 HW_DisableInterrupts();
1792 #if STK_TICKLESS_IDLE
1793 Timeout ticks = m_sleep_ticks;
1798 if (ticks != m_sleep_ticks)
1800 m_sleep_ticks = ReloadTickPeriod(ticks);
1806 HW_EnableInterrupts();
1811 if (m_handler->OnForceContextSwitch(
id, m_stack_idle, m_stack_active))
1813 HW_ScheduleContextSwitch();
1819 if (m_csu_nesting == 0U)
1822 HW_SpinLockLock(s_StkCortexmCsuLock);
1825 m_csu = current_ses;
1832 STK_KERNEL_PANIC(KERNEL_PANIC_CS_NESTING_OVERFLOW);
1838 bool released =
false;
1843 if (m_csu_nesting == 0U)
1846 restore_ses = m_csu;
1849 HW_SpinLockUnlock(s_StkCortexmCsuLock);
1859 const uint32_t current_ses = HW_CriticalSectionStart();
1861 OnEnterCriticalSection(current_ses);
1866 uint32_t restore_ses;
1867 if (OnExitCriticalSection(restore_ses))
1869 HW_CriticalSectionEnd(restore_ses);
1873 void StartTickTimer(Timeout elapsed_ticks)
1875 #if STK_TICKLESS_IDLE
1877 m_sleep_ticks = elapsed_ticks;
1883 HW_SysTickStart(m_tick_resolution);
1886 NVIC_SetPriority(SysTick_IRQn, STK_CORTEX_M_ISR_PRIORITY_LOWEST);
1889#if STK_TLS && !STK_INLINE_TLS
1892 hw::CriticalSection::ScopedLock cs_;
1896 return m_stack_active->tls;
1899 void SetTls(Word tp)
1901 hw::CriticalSection::ScopedLock cs_;
1905 m_stack_active->tls = tp;
1909 void OnSleepOverride()
1911 #if STK_TICKLESS_IDLE
1912 const Timeout sleep_ticks = m_sleep_ticks;
1914 const Timeout sleep_ticks = 1;
1917 if (!m_overrider->OnSleep(sleep_ticks))
1919 HW_EnterSleepMode();
1923 uint32_t GetTickResolutionInClockCycles()
1925 return static_cast<uint32_t
>(ConvertTimeUsToClockCycles(HW_CoreClockFrequency(),
static_cast<Ticks>(m_tick_resolution)));
1929 void ConfigureMpuInstance(eovrd_t *overrider,
bool non_secure)
1932 if (overrider !=
nullptr)
1934 const MpuConfig *
const cfg = overrider->OnConfigureMpu();
1940 #if STK_CORTEX_M_TRUSTZONE_FRAME
1945 STK_ASSERT(non_secure == ((cfg->mode & hw::mpu::MPU_CFG_NONSECURE_MPU) != 0U));
1948 if ((cfg->mode & hw::mpu::MPU_CFG_CLEAR_ON_INIT) != 0U)
1955 hw::mpu::DisableRegion(index, non_secure);
1959 uint32_t control_flags = 0U;
1961 if ((cfg->mode & hw::mpu::MPU_CFG_PRIVILEGED_BG_MEM) != 0U)
1963 control_flags |= MPU_CTRL_PRIVDEFENA_Msk;
1966 if ((cfg->mode & hw::mpu::MPU_CFG_IN_FAULTS) != 0U)
1968 control_flags |= MPU_CTRL_HFNMIENA_Msk;
1971 hw::mpu::ConfigureStatic(cfg->regions.GetPtr(), cfg->regions.GetSize(), control_flags, non_secure);
1975 hw::mpu::Enable(
false, 0, non_secure);
1985 ConfigureMpuInstance(m_overrider,
false);
1987 #if STK_CORTEX_M_TRUSTZONE_FRAME
1989 ConfigureMpuInstance(m_overrider_ns,
true);
1994 TId GetCurrentTId()
const
1996 #if STK_STACK_NEEDS_TASK_ID
1997 const TId tid = (m_stack_active !=
nullptr ? m_stack_active->tid : TID_NONE);
1999 const TId tid = TID_NONE;
2008#if STK_TICKLESS_IDLE
2009 Timeout ReloadTickPeriod(Timeout ticks_requested);
2011 void Resume(Timeout elapsed_ticks);
2014 JmpFrame m_exit_buf;
2015 eovrd_t *m_overrider;
2016#if STK_CORTEX_M_TRUSTZONE_FRAME
2017 eovrd_t *m_overrider_ns;
2019#if STK_TICKLESS_IDLE
2021 uint32_t m_sleep_error;
2024 uint8_t m_csu_nesting;
2025 volatile bool m_started;
2038 HiResClockDWT() : m_acc(0U), m_prev(0U)
2040 HW_DWTEnableCounter();
2042 m_prev = HW_DWTGetCounter();
2046 static HiResClockDWT *GetInstance();
2050 const uint32_t current = HW_DWTGetCounter();
2053 const uint32_t delta = current - m_prev;
2065 uint32_t GetFrequency()
2067 return HW_CoreClockFrequency();
2072HiResClockDWT *HiResClockDWT::GetInstance()
2084 static HiResClockM0 *GetInstance();
2089 const Cycles cycles = ConvertTimeUsToClockCycles(HW_CoreClockFrequency(),
2092 const uint32_t val = HW_SysTickValue();
2093 const uint32_t load = SysTick->LOAD;
2096 return cycles +
static_cast<Cycles>(load - val);
2099 uint32_t GetFrequency()
2101 return HW_CoreClockFrequency();
2106HiResClockM0 *HiResClockM0::GetInstance()
2114#if (__CORTEX_M >= 3U)
2115 typedef HiResClockDWT HiResClockImpl;
2117 typedef HiResClockM0 HiResClockImpl;
2124 g_StkLastPanicId = id;
2127 HW_DisableInterrupts();
2142#if STK_TICKLESS_IDLE
2145 const uint32_t SYSTICK_MAX_LOAD = 0x00FFFFFFU;
2146 const uint32_t tick_resolution = GetTickResolutionInClockCycles();
2147 if (tick_resolution == 0U)
2154 STK_ASSERT(
static_cast<uint64_t
>(ticks_requested) * tick_resolution <= UINT32_MAX);
2159 const Timeout max_ticks =
static_cast<Timeout>(SYSTICK_MAX_LOAD / tick_resolution);
2160 if (ticks_requested > max_ticks)
2162 ticks_requested = max_ticks;
2167#if (__CORTEX_M > 1) && STK_TICKLESS_USE_ARM_DWT
2168 const uint32_t error = HW_DWTGetCounter();
2169 __stk_compiler_barrier();
2173 HW_SysTickDisable();
2177 const uint32_t elapsed_till_stop = HW_SysTickElapsed(HW_SysTickValueAfterDisable());
2182 const uint32_t cpu_ticks_requested =
static_cast<uint32_t
>(ticks_requested) * tick_resolution;
2185 uint32_t new_load = cpu_ticks_requested - elapsed_till_stop - m_sleep_error;
2188 if (new_load > cpu_ticks_requested)
2190 new_load = cpu_ticks_requested;
2194 HW_SysTickRearm(new_load);
2196#if (__CORTEX_M > 1) && STK_TICKLESS_USE_ARM_DWT
2198 m_sleep_error = HW_DWTGetCounter() - error;
2202 return ticks_requested;
2206extern "C" void STK_SYSTICK_HANDLER()
2209#if STK_SEGGER_SYSVIEW
2210 SEGGER_SYSVIEW_RecordEnterISR();
2215#ifdef HAL_MODULE_ENABLED
2217#if STK_TICKLESS_IDLE
2218 uwTick +=
static_cast<uint32_t
>(ctx.m_sleep_ticks * ctx.m_tick_resolution);
2237#if STK_SEGGER_SYSVIEW
2238 SEGGER_SYSVIEW_RecordExitISR();
2239 SEGGER_SYSVIEW_IsStarted();
2243#if STK_SEGGER_SYSVIEW
2244 #define STK_SYSVIEW_CALL(func)\
2245 "PUSH {r0-r3, r7, r11, r12, LR} \n"\
2247 "POP {r0-r3, r7, r11, r12, LR} \n"
2250#if STK_SEGGER_SYSVIEW
2256 SEGGER_SYSVIEW_RecordExitISR();
2267 SEGGER_SYSVIEW_OnTaskStartExec(ctx.m_stack_active->tid);
2299#if (STK_MPU_TASK_REGIONS == 2U)
2300#define STK_ASM_BLOCK_MPU_S_STACK_GUARD\
2301 "LDR r0, =%[mpu_start_of] \n" \
2302 "ADD r12, r1, %[mpu_reg_of] \n" \
2303 "LDMIA r12, {r4-r7} \n" \
2304 "STMIA r0, {r4-r7} \n"
2305#elif (STK_MPU_TASK_REGIONS == 4U)
2306#define STK_ASM_BLOCK_MPU_S_STACK_GUARD\
2307 "LDR r0, =%[mpu_start_of] \n" \
2308 "ADD r12, r1, %[mpu_reg_of] \n" \
2309 "LDMIA r12, {r4-r11} \n" \
2310 "STMIA r0, {r4-r11} \n"
2311#elif (STK_MPU_TASK_REGIONS == 6U)
2312#define STK_ASM_BLOCK_MPU_S_STACK_GUARD\
2313 "LDR r0, =%[mpu_start_of] \n" \
2316 "ADD r12, r1, %[mpu_reg_of] \n" \
2317 "LDMIA r12, {r4-r11} \n" \
2318 "STMIA r0, {r4-r11} \n" \
2321 "LDR r12, =%[mpu_rnr_idx4] \n" \
2322 "STR r12, [r0, #-4] \n" \
2323 "ADD r12, r1, %[mpu_reg4_of] \n" \
2324 "LDMIA r12, {r4-r7} \n" \
2325 "STMIA r0, {r4-r7} \n" \
2328 "LDR r12, =%[mpu_rnr_idx] \n" \
2329 "STR r12, [r0, #-4] \n"
2330#elif (STK_MPU_TASK_REGIONS == 8U)
2331#define STK_ASM_BLOCK_MPU_S_STACK_GUARD\
2332 "LDR r0, =%[mpu_start_of] \n" \
2335 "ADD r12, r1, %[mpu_reg_of] \n" \
2336 "LDMIA r12, {r4-r11} \n" \
2337 "STMIA r0, {r4-r11} \n" \
2340 "LDR r12, =%[mpu_rnr_idx4] \n" \
2341 "STR r12, [r0, #-4] \n" \
2342 "ADD r12, r1, %[mpu_reg4_of] \n" \
2343 "LDMIA r12, {r4-r11} \n" \
2344 "STMIA r0, {r4-r11} \n" \
2347 "LDR r12, =%[mpu_rnr_idx] \n" \
2348 "STR r12, [r0, #-4] \n"
2349#elif (STK_MPU_TASK_REGIONS == 12U)
2350#define STK_ASM_BLOCK_MPU_S_STACK_GUARD\
2351 "LDR r0, =%[mpu_start_of] \n" \
2354 "ADD r12, r1, %[mpu_reg_of] \n" \
2355 "LDMIA r12, {r4-r11} \n" \
2356 "STMIA r0, {r4-r11} \n" \
2359 "LDR r12, =%[mpu_rnr_idx4] \n" \
2360 "STR r12, [r0, #-4] \n" \
2361 "ADD r12, r1, %[mpu_reg4_of] \n" \
2362 "LDMIA r12, {r4-r11} \n" \
2363 "STMIA r0, {r4-r11} \n" \
2366 "LDR r12, =%[mpu_rnr_idx8] \n" \
2367 "STR r12, [r0, #-4] \n" \
2368 "ADD r12, r1, %[mpu_reg8_of] \n" \
2369 "LDMIA r12, {r4-r11} \n" \
2370 "STMIA r0, {r4-r11} \n" \
2373 "LDR r12, =%[mpu_rnr_idx] \n" \
2374 "STR r12, [r0, #-4] \n"
2375#elif (STK_MPU_TASK_REGIONS == 16U)
2376#define STK_ASM_BLOCK_MPU_S_STACK_GUARD\
2377 "LDR r0, =%[mpu_start_of] \n" \
2380 "ADD r12, r1, %[mpu_reg_of] \n" \
2381 "LDMIA r12, {r4-r11} \n" \
2382 "STMIA r0, {r4-r11} \n" \
2385 "LDR r12, =%[mpu_rnr_idx4] \n" \
2386 "STR r12, [r0, #-4] \n" \
2387 "ADD r12, r1, %[mpu_reg4_of] \n" \
2388 "LDMIA r12, {r4-r11} \n" \
2389 "STMIA r0, {r4-r11} \n" \
2392 "LDR r12, =%[mpu_rnr_idx8] \n" \
2393 "STR r12, [r0, #-4] \n" \
2394 "ADD r12, r1, %[mpu_reg8_of] \n" \
2395 "LDMIA r12, {r4-r11} \n" \
2396 "STMIA r0, {r4-r11} \n" \
2399 "LDR r12, =%[mpu_rnr_idx12] \n" \
2400 "STR r12, [r0, #-4] \n" \
2401 "ADD r12, r1, %[mpu_reg12_of] \n" \
2402 "LDMIA r12, {r4-r11} \n" \
2403 "STMIA r0, {r4-r11} \n" \
2406 "LDR r12, =%[mpu_rnr_idx] \n" \
2407 "STR r12, [r0, #-4] \n"
2409 #error "Unsupported region count, allowed - 2, 4, 6, 8, 12, 16!"
2412#if STK_CORTEX_M_TRUSTZONE_FRAME
2413 #if (STK_MPU_TASK_REGIONS_NS == 2U)
2414 #define STK_ASM_BLOCK_MPU_NS_STACK_GUARD\
2417 "LDR r0, =%[mpu_ns_start_of] \n" \
2418 "ADD r12, r1, %[mpu_ns_reg_of] \n" \
2419 "LDMIA r12, {r4-r7} \n" \
2420 "STMIA r0, {r4-r7} \n"
2421 #elif (STK_MPU_TASK_REGIONS_NS == 4U)
2422 #define STK_ASM_BLOCK_MPU_NS_STACK_GUARD\
2425 "LDR r0, =%[mpu_ns_start_of] \n" \
2426 "ADD r12, r1, %[mpu_ns_reg_of] \n" \
2427 "LDMIA r12, {r4-r11} \n" \
2428 "STMIA r0, {r4-r11} \n"
2429 #elif (STK_MPU_TASK_REGIONS_NS == 6U)
2430 #define STK_ASM_BLOCK_MPU_NS_STACK_GUARD\
2433 "LDR r0, =%[mpu_ns_start_of] \n" \
2436 "ADD r12, r1, %[mpu_ns_reg_of] \n" \
2437 "LDMIA r12, {r4-r11} \n" \
2438 "STMIA r0, {r4-r11} \n" \
2441 "LDR r12, =%[mpu_ns_rnr_idx4] \n" \
2442 "STR r12, [r0, #-4] \n" \
2443 "ADD r12, r1, %[mpu_ns_reg4_of]\n" \
2444 "LDMIA r12, {r4-r7} \n" \
2445 "STMIA r0, {r4-r7} \n" \
2448 "LDR r12, =%[mpu_ns_rnr_idx] \n" \
2449 "STR r12, [r0, #-4] \n"
2450 #elif (STK_MPU_TASK_REGIONS_NS == 8U)
2451 #define STK_ASM_BLOCK_MPU_NS_STACK_GUARD\
2454 "LDR r0, =%[mpu_ns_start_of] \n" \
2457 "ADD r12, r1, %[mpu_ns_reg_of] \n" \
2458 "LDMIA r12, {r4-r11} \n" \
2459 "STMIA r0, {r4-r11} \n" \
2462 "LDR r12, =%[mpu_ns_rnr_idx4] \n" \
2463 "STR r12, [r0, #-4] \n" \
2464 "ADD r12, r1, %[mpu_ns_reg4_of]\n" \
2465 "LDMIA r12, {r4-r11} \n" \
2466 "STMIA r0, {r4-r11} \n" \
2469 "LDR r12, =%[mpu_ns_rnr_idx] \n" \
2470 "STR r12, [r0, #-4] \n"
2471 #elif (STK_MPU_TASK_REGIONS_NS == 12U)
2472 #define STK_ASM_BLOCK_MPU_NS_STACK_GUARD\
2475 "LDR r0, =%[mpu_ns_start_of] \n" \
2478 "ADD r12, r1, %[mpu_ns_reg_of] \n" \
2479 "LDMIA r12, {r4-r11} \n" \
2480 "STMIA r0, {r4-r11} \n" \
2483 "LDR r12, =%[mpu_ns_rnr_idx4] \n" \
2484 "STR r12, [r0, #-4] \n" \
2485 "ADD r12, r1, %[mpu_ns_reg4_of]\n" \
2486 "LDMIA r12, {r4-r11} \n" \
2487 "STMIA r0, {r4-r11} \n" \
2490 "LDR r12, =%[mpu_ns_rnr_idx8] \n" \
2491 "STR r12, [r0, #-4] \n" \
2492 "ADD r12, r1, %[mpu_ns_reg8_of]\n" \
2493 "LDMIA r12, {r4-r11} \n" \
2494 "STMIA r0, {r4-r11} \n" \
2497 "LDR r12, =%[mpu_ns_rnr_idx] \n" \
2498 "STR r12, [r0, #-4] \n"
2499 #elif (STK_MPU_TASK_REGIONS_NS == 16U)
2500 #define STK_ASM_BLOCK_MPU_NS_STACK_GUARD\
2503 "LDR r0, =%[mpu_ns_start_of] \n" \
2506 "ADD r12, r1, %[mpu_ns_reg_of] \n" \
2507 "LDMIA r12, {r4-r11} \n" \
2508 "STMIA r0, {r4-r11} \n" \
2511 "LDR r12, =%[mpu_ns_rnr_idx4] \n" \
2512 "STR r12, [r0, #-4] \n" \
2513 "ADD r12, r1, %[mpu_ns_reg4_of]\n" \
2514 "LDMIA r12, {r4-r11} \n" \
2515 "STMIA r0, {r4-r11} \n" \
2518 "LDR r12, =%[mpu_ns_rnr_idx8] \n" \
2519 "STR r12, [r0, #-4] \n" \
2520 "ADD r12, r1, %[mpu_ns_reg8_of]\n" \
2521 "LDMIA r12, {r4-r11} \n" \
2522 "STMIA r0, {r4-r11} \n" \
2525 "LDR r12, =%[mpu_ns_rnr_idx12] \n" \
2526 "STR r12, [r0, #-4] \n" \
2527 "ADD r12, r1, %[mpu_ns_reg12_of]\n" \
2528 "LDMIA r12, {r4-r11} \n" \
2529 "STMIA r0, {r4-r11} \n" \
2532 "LDR r12, =%[mpu_ns_rnr_idx] \n" \
2533 "STR r12, [r0, #-4] \n"
2535 #error "Unsupported region count, allowed - 2, 4, 6, 8, 12, 16!"
2539#if STK_CORTEX_M_TRUSTZONE_FRAME
2540 #define STK_ASM_BLOCK_MPU_STACK_GUARD\
2541 "MOV r1, %[st_active] \n" \
2542 STK_ASM_BLOCK_MPU_S_STACK_GUARD\
2543 STK_ASM_BLOCK_MPU_NS_STACK_GUARD
2545 #define STK_ASM_BLOCK_MPU_STACK_GUARD\
2546 "MOV r1, %[st_active] \n" \
2547 STK_ASM_BLOCK_MPU_S_STACK_GUARD
2552#if (STK_ARCH_CPU_COUNT > 1U)
2559 register Stack *p_st_idle = p_ctx->m_stack_idle;
2560 register Stack *p_st_active = p_ctx->m_stack_active;
2562 register Context *p_ctx __asm(
"r12") = &
GetContext();
2563 register Stack *p_st_idle __asm(
"r3") = p_ctx->m_stack_idle;
2564 register Stack *p_st_active __asm(
"r2") = p_ctx->m_stack_active;
2571 STK_ASM_DISABLE_INTERRUPTS
" \n"
2574#if STK_SEGGER_SYSVIEW
2575 STK_SYSVIEW_CALL(StkSystemView_RecordEnterISR)
2591 "VMOVEQ.F32 s0, s0 \n"
2594 "VSTMDBEQ r0!, {s16-s31} \n"
2599#if STK_CORTEX_M_MANAGE_LR
2603 "STMDB r0!, {r4-r11, LR}\n"
2606 "SUBS r0, r0, #16 \n"
2607 "STMIA r0!, {r4-r7} \n"
2612 "SUBS r0, r0, #32 \n"
2613 "STMIA r0!, {r4-r7} \n"
2614 "SUBS r0, r0, #16 \n"
2622#if STK_CORTEX_M_TRUSTZONE_FRAME
2624 "MRS r12, PSPLIM_NS \n"
2625 "STR r12, [r0, #-4]! \n"
2626 "MRS r12, PSPLIM \n"
2627 "STR r12, [r0, #-4]! \n"
2630 "MRS r12, CONTROL_NS \n"
2631 "STR r12, [r0, #-4]! \n"
2632 "MRS r12, PSP_NS \n"
2633 "STR r12, [r0, #-4]! \n"
2638#if STK_CORTEX_M_PRIVILEGE_FRAME
2639 "MRS r12, CONTROL \n"
2640 "STR r12, [r0, #-4]! \n"
2644 "STR r0, [%[st_idle]] \n"
2647#if STK_MPU_STACK_GUARD
2648 STK_ASM_BLOCK_MPU_STACK_GUARD
2653 "LDR r0, [%[st_active]]\n"
2659#if STK_CORTEX_M_PRIVILEGE_FRAME
2660 "LDR r12, [r0], %[access_mode_of] \n"
2661 "MSR CONTROL, r12 \n"
2672#if STK_CORTEX_M_TRUSTZONE_FRAME
2673 "LDR r12, [r0], #4 \n"
2674 "MSR PSP_NS, r12 \n"
2675 "LDR r12, [r0], #4 \n"
2676 "MSR CONTROL_NS, r12 \n"
2678 "LDR r12, [r0], #4 \n"
2679 "MSR PSPLIM, r12 \n"
2680 "LDR r12, [r0], #4 \n"
2681 "MSR PSPLIM_NS, r12 \n"
2686#if STK_CORTEX_M_MANAGE_LR
2688 "LDMIA r0!, {r4-r11, LR}\n"
2691 "LDMIA r0!, {r4-r7} \n"
2696 "LDMIA r0!, {r4-r7} \n"
2703 "VLDMIAEQ r0!, {s16-s31} \n"
2710#if STK_SEGGER_SYSVIEW
2711 STK_SYSVIEW_CALL(StkSystemView_OnContextSwitch)
2714 STK_ASM_ENABLE_INTERRUPTS
" \n"
2716 STK_ASM_EXIT_FROM_HANDLER
" \n"
2719 : [access_mode_of]
"i" (offsetof(
Stack, access_mode))
2722 , [st_idle]
"r3" (p_st_idle)
2723 , [st_active]
"r2" (p_st_active)
2725 , [st_idle]
"r" (p_st_idle)
2726 , [st_active]
"r" (p_st_active)
2730 , [st_active]
"r" (
GetContext().m_stack_active)
2732#if STK_MPU_STACK_GUARD
2733 , [mpu_start_of]
"i" (&MPU->RBAR)
2734 , [mpu_reg_of]
"i" (offsetof(
Stack, mpu.region[0].addr))
2735 #if (STK_MPU_TASK_REGIONS > 4U)
2736 , [mpu_rnr_idx]
"i" (STK_CORTEX_M_MPU_TASK_REGION_IDX)
2737 , [mpu_reg4_of]
"i" (offsetof(
Stack, mpu.region[4].addr))
2738 , [mpu_rnr_idx4]
"i" (STK_CORTEX_M_MPU_TASK_REGION_IDX + 4U)
2741 , [mpu_reg8_of]
"i" (offsetof(
Stack, mpu.region[8].addr))
2742 , [mpu_rnr_idx8]
"i" (STK_CORTEX_M_MPU_TASK_REGION_IDX + 8U)
2744 #if (STK_MPU_TASK_REGIONS > 12U)
2745 , [mpu_reg12_of]
"i" (offsetof(
Stack, mpu.region[12].addr))
2746 , [mpu_rnr_idx12]
"i" (STK_CORTEX_M_MPU_TASK_REGION_IDX + 12U)
2748 #if STK_CORTEX_M_TRUSTZONE_FRAME
2749 , [mpu_ns_start_of]
"i" (&MPU_NS->RBAR)
2750 , [mpu_ns_reg_of]
"i" (offsetof(
Stack, mpu_ns.region[0].addr))
2751 #if (STK_MPU_TASK_REGIONS_NS > 4U)
2752 , [mpu_ns_rnr_idx]
"i" (STK_CORTEX_M_MPU_TASK_REGION_IDX_NS)
2753 , [mpu_ns_reg4_of]
"i" (offsetof(
Stack, mpu_ns.region[4].addr))
2754 , [mpu_ns_rnr_idx4]
"i" (STK_CORTEX_M_MPU_TASK_REGION_IDX_NS + 4U)
2757 , [mpu_ns_reg8_of]
"i" (offsetof(
Stack, mpu_ns.region[8].addr))
2758 , [mpu_ns_rnr_idx8]
"i" (STK_CORTEX_M_MPU_TASK_REGION_IDX_NS + 8U)
2760 #if (STK_MPU_TASK_REGIONS_NS > 12U)
2761 , [mpu_ns_reg12_of]
"i" (offsetof(
Stack, mpu_ns.region[12].addr))
2762 , [mpu_ns_rnr_idx12]
"i" (STK_CORTEX_M_MPU_TASK_REGION_IDX_NS + 12U)
2767#if STK_MPU_STACK_GUARD
2771#if (STK_CORTEX_M_TRUSTZONE_FRAME || STK_MPU_STACK_GUARD || STK_CORTEX_M_PRIVILEGE_FRAME)
2789#if STK_MPU_STACK_GUARD
2790 STK_ASM_BLOCK_MPU_STACK_GUARD
2795 "LDR r0, [%[st_active]]\n"
2799#if STK_CORTEX_M_PRIVILEGE_FRAME
2800 "LDR r12, [r0], %[access_mode_of] \n"
2801 "MSR CONTROL, r12 \n"
2806#if STK_CORTEX_M_TRUSTZONE_FRAME
2807 "LDR r12, [r0], #4 \n"
2808 "MSR PSP_NS, r12 \n"
2809 "LDR r12, [r0], #4 \n"
2810 "MSR CONTROL_NS, r12 \n"
2812 "LDR r12, [r0], #4 \n"
2813 "MSR PSPLIM, r12 \n"
2814 "LDR r12, [r0], #4 \n"
2815 "MSR PSPLIM_NS, r12 \n"
2820#if STK_CORTEX_M_MANAGE_LR
2822 "LDMIA r0!, {r4-r11, LR}\n"
2825 "LDMIA r0!, {r4-r7} \n"
2830 "LDMIA r0!, {r4-r7} \n"
2837 "VLDMIAEQ r0!, {s16-s31} \n"
2843#if !STK_CORTEX_M_MANAGE_LR
2845 "LDR r0, =%[exc_ret] \n"
2849 STK_ASM_ENABLE_INTERRUPTS
" \n"
2851 STK_ASM_EXIT_FROM_HANDLER
" \n"
2854 : [access_mode_of]
"i" (offsetof(
Stack, access_mode))
2855 , [st_active]
"r" (
GetContext().m_stack_active)
2856#if !STK_CORTEX_M_MANAGE_LR
2857 , [exc_ret]
"i" (STK_CORTEX_M_EXC_RETURN_THREAD_PSP)
2859#if STK_MPU_STACK_GUARD
2860 , [mpu_start_of]
"i" (&MPU->RBAR)
2861 , [mpu_reg_of]
"i" (offsetof(
Stack, mpu.region[0].addr))
2862 #if (STK_MPU_TASK_REGIONS > 4U)
2863 , [mpu_rnr_idx]
"i" (STK_CORTEX_M_MPU_TASK_REGION_IDX)
2864 , [mpu_reg4_of]
"i" (offsetof(
Stack, mpu.region[4].addr))
2865 , [mpu_rnr_idx4]
"i" (STK_CORTEX_M_MPU_TASK_REGION_IDX + 4U)
2867 #if (STK_MPU_TASK_REGIONS > 8U)
2868 , [mpu_reg8_of]
"i" (offsetof(
Stack, mpu.region[8].addr))
2869 , [mpu_rnr_idx8]
"i" (STK_CORTEX_M_MPU_TASK_REGION_IDX + 8U)
2871 #if (STK_MPU_TASK_REGIONS > 12U)
2872 , [mpu_reg12_of]
"i" (offsetof(
Stack, mpu.region[12].addr))
2873 , [mpu_rnr_idx12]
"i" (STK_CORTEX_M_MPU_TASK_REGION_IDX + 12U)
2875 #if STK_CORTEX_M_TRUSTZONE_FRAME
2876 , [mpu_ns_start_of]
"i" (&MPU_NS->RBAR)
2877 , [mpu_ns_reg_of]
"i" (offsetof(
Stack, mpu_ns.region[0].addr))
2878 #if (STK_MPU_TASK_REGIONS_NS > 4U)
2879 , [mpu_ns_rnr_idx]
"i" (STK_CORTEX_M_MPU_TASK_REGION_IDX_NS)
2880 , [mpu_ns_reg4_of]
"i" (offsetof(
Stack, mpu_ns.region[4].addr))
2881 , [mpu_ns_rnr_idx4]
"i" (STK_CORTEX_M_MPU_TASK_REGION_IDX_NS + 4U)
2883 #if (STK_MPU_TASK_REGIONS_NS > 8U)
2884 , [mpu_ns_reg8_of]
"i" (offsetof(
Stack, mpu_ns.region[8].addr))
2885 , [mpu_ns_rnr_idx8]
"i" (STK_CORTEX_M_MPU_TASK_REGION_IDX_NS + 8U)
2887 #if (STK_MPU_TASK_REGIONS_NS > 12U)
2888 , [mpu_ns_reg12_of]
"i" (offsetof(
Stack, mpu_ns.region[12].addr))
2889 , [mpu_ns_rnr_idx12]
"i" (STK_CORTEX_M_MPU_TASK_REGION_IDX_NS + 12U)
2894#if STK_MPU_STACK_GUARD
2898#if (STK_CORTEX_M_TRUSTZONE_FRAME || STK_MPU_STACK_GUARD || STK_CORTEX_M_PRIVILEGE_FRAME)
2908void Context::Start()
2913 HW_EnableFullFpuAccess();
2920 m_handler->OnStop();
2924 HW_StartScheduler();
2928void Context::OnStart()
2937 m_handler->OnStart(m_stack_active);
2945 NVIC_SetPriority(PendSV_IRQn, STK_CORTEX_M_ISR_PRIORITY_LOWEST);
2947#ifdef CONTROL_nPRIV_Msk
2954#if STK_SEGGER_SYSVIEW
2955 SEGGER_SYSVIEW_OnTaskStartExec(m_stack_active->tid);
2963#if STK_TICKLESS_IDLE
2966 const uint32_t tick_resolution = GetTickResolutionInClockCycles();
2967 if (tick_resolution == 0U)
2973 HW_DisableInterrupts();
2976 HW_SysTickDisable();
2980 const uint32_t elapsed = HW_SysTickElapsed(HW_SysTickValueAfterDisable());
2986 HW_ClearPendingSwitch();
2989 m_handler->OnSuspend(
true);
2998 const Timeout elapsed_ticks =
static_cast<Timeout>(elapsed / tick_resolution);
2999 const Timeout sleep_ticks =
Max(m_sleep_ticks - elapsed_ticks,
static_cast<Timeout>(0));
3001 HW_EnableInterrupts();
3007#if STK_TICKLESS_IDLE
3008void Context::Resume(
Timeout elapsed_ticks)
3010 HW_DisableInterrupts();
3013 m_handler->OnSuspend(
false);
3016 StartTickTimer(elapsed_ticks + 1);
3018 HW_EnableInterrupts();
3026#if STK_SEGGER_SYSVIEW
3027 SEGGER_SYSVIEW_RecordEnterISR();
3033 "Word must be uintptr_t width for safe pointer round-trip via frame->PC");
3038 "NVIC priority bit width exceeds safe shift range");
3047 const ESvcCommandId command =
static_cast<ESvcCommandId
>(*insn_ptr);
3051 case SVC_START_SCHEDULING: {
3059 HW_DisableInterrupts();
3068#if STK_CORTEX_M_FORCE_SWITCH
3069 case SVC_FORCE_SWITCH: {
3074 ctx.OnForceContextSwitch(frame->
R0);
3079 case SVC_BOOST_PRIV: {
3085 __set_CONTROL(__get_CONTROL() & ~CONTROL_nPRIV_Msk);
3094#ifdef CONTROL_nPRIV_Msk
3095 case SVC_ENTER_CRITICAL: {
3096 const uint32_t saved_basepri = __get_BASEPRI();
3097 __set_BASEPRI(
static_cast<uint32_t
>(1U) << __NVIC_PRIO_BITS);
3101 GetContext().OnEnterCriticalSection(saved_basepri);
3104 case SVC_EXIT_CRITICAL: {
3105 uint32_t saved_basepri;
3106 if (
GetContext().OnExitCriticalSection(saved_basepri))
3109 __set_BASEPRI(saved_basepri);
3122#if STK_SEGGER_SYSVIEW
3123 SEGGER_SYSVIEW_RecordExitISR();
3139 "LDR r1, =StkSVCHandlerMain \n"
3147#if (STK_USE_MEMMANAGE_HANDLER && defined(STK_MEMMANAGE_HANDLER)) ||\
3148 (STK_USE_HARDFAULT_HANDLER && defined(STK_HARDFAULT_HANDLER))
3150void StkExceptionHandlerMain(
const Word *stacked_regs,
Word exc_id)
3153 __asm
volatile (
"MOV %0, LR" :
"=r" (exc_return) ::
"memory");
3155 bool handled =
false;
3158 if (ctx.m_overrider !=
nullptr)
3161 fault_ctx.
Fill(stacked_regs, exc_return);
3163 handled = ctx.m_overrider->OnException(
static_cast<EHwException>(exc_id), ctx.GetCurrentTId(),
3180#if STK_USE_MEMMANAGE_HANDLER && defined(STK_MEMMANAGE_HANDLER)
3191 "LDR r2, =StkExceptionHandlerMain \n"
3203#if STK_USE_HARDFAULT_HANDLER && defined(STK_HARDFAULT_HANDLER)
3214 "LDR r2, =StkExceptionHandlerMain \n"
3227void stk::OnTaskRun(
ITask *runnable)
3234void stk::OnTaskExit()
3238 const uint32_t cs = HW_CriticalSectionStart();
3240 ctx.m_handler->OnTaskExit(ctx.m_stack_active);
3242 HW_CriticalSectionEnd(cs);
3244 if (HW_IsPrivilegedContext())
3249 HW_EnterSleepMode();
3263void stk::OnSchedulerSleep()
3271 #if STK_SEGGER_SYSVIEW
3272 SEGGER_SYSVIEW_OnIdle();
3275 HW_EnterSleepMode();
3280void stk::OnSchedulerSleepOverride()
3288 #if STK_SEGGER_SYSVIEW
3289 SEGGER_SYSVIEW_OnIdle();
3297void stk::OnSchedulerExit()
3309 GetContext().Initialize(event_handler, service, exit_trap, resolution_us);
3317#if STK_MPU_STACK_GUARD
3319 ITask *user_task,
bool non_secure)
3321#if !STK_CORTEX_M_TRUSTZONE_FRAME
3325 MpuRegionConfig task_mpu_cfg[TaskMpu::NUM_REGIONS];
3326 size_t cfg_count = 0U;
3331 if (user_task !=
nullptr)
3335 const MpuRegionList *
const regions = user_task->GetMpuRegions();
3336 if (regions !=
nullptr)
3339 const MpuRegionConfig stack_guard_cfg =
3343 .access_perm = hw::mpu::EMpuAccess::ACCESS_FULL,
3344 .mem_type = hw::mpu::EMpuType::TYPE_NORMAL_CACHEABLE,
3345 .share = hw::mpu::EMpuShare::SHARE_NON,
3346 .exec = hw::mpu::EMpuExec::EXEC_NEVER
3349 const hw::mpu::RegionBounds bounds_s = hw::mpu::GetRegionBounds(stack_guard_cfg);
3351 size_t regions_count = regions->GetSize();
3352 bool stack_guard_canceled =
false;
3354 for (
size_t i = 0U; i < regions_count; ++i)
3356 const hw::mpu::RegionBounds bounds_i = hw::mpu::GetRegionBounds((*regions)[i]);
3359 if (hw::mpu::IsOverlapping(bounds_s, bounds_i))
3361 stack_guard_canceled =
true;
3367 const size_t max_user_regions = stack_guard_canceled ? TaskMpu::NUM_REGIONS : (TaskMpu::NUM_REGIONS - 1U);
3369 STK_ASSERT(regions_count <= max_user_regions);
3370 if (regions_count > max_user_regions)
3372 regions_count = max_user_regions;
3376 for (
size_t i = 0U; i < regions_count; ++i)
3378 task_mpu_cfg[cfg_count++] = (*regions)[i];
3382 if (!stack_guard_canceled)
3384 task_mpu_cfg[cfg_count++] = stack_guard_cfg;
3389#if STK_CORTEX_M_TRUSTZONE_FRAME
3390 TaskMpu &task_mpu = (non_secure ? stack->mpu_ns : stack->mpu);
3392 TaskMpu &task_mpu = stack->mpu;
3396 hw::mpu::ConfigureDynamic(task_mpu, task_mpu_cfg, cfg_count, overrider, non_secure);
3400#if STK_CORTEX_M_TRUSTZONE_FRAME
3401static void ConfigureTaskTrustZone(
Stack *stack,
IStackMemory *stack_memory,
ITask *user_task,
bool non_secure)
3412 tz_frame->PSP_NS = 0U;
3413 tz_frame->CONTROL_NS = hw::reg::CONTROL::DEFAULT_INIT;
3414 tz_frame->PSPLIM = 0U;
3415 tz_frame->PSPLIM_NS = 0U;
3423 const Word ns_stack_top = Context::InitStackMemory(ns_stack_memory);
3427 hw::reg::CONTROL::SetPrivileged(tz_frame->CONTROL_NS) :
3428 hw::reg::CONTROL::SetUnprivileged(tz_frame->CONTROL_NS));
3431 tz_frame->CONTROL_NS = hw::reg::CONTROL::SetSPSelectionToPSP(tz_frame->CONTROL_NS);
3435 tz_frame->PSP_NS = ns_stack_top;
3456 "ExceptionFrame layout must match the ARMv7-M hardware exception frame exactly");
3461#ifdef _STK_CORTEX_M_TRUSTZONE
3462 bool is_non_secure_task =
false;
3466 if ((user_task !=
nullptr) && (user_task->GetSecureStackMemory() !=
nullptr))
3468 stack_memory = user_task->GetSecureStackMemory();
3469 is_non_secure_task =
true;
3476 const Word stack_top = Context::InitStackMemory(stack_memory);
3479 stack->
SP = stack_top - (STK_CORTEX_M_TOTAL_REGISTER_COUNT *
sizeof(
Word));
3497 task_frame->exc.PC =
hw::PtrToWord(ctx.m_overrider !=
nullptr ? &OnSchedulerSleepOverride : &OnSchedulerSleep);
3499 task_frame->exc.R0 = 0U;
3505 task_frame->exc.R0 = 0U;
3515 task_frame->exc.PC = hw::reg::PC::ClearThumbBit(task_frame->exc.PC);
3519 task_frame->exc.xPSR = hw::reg::XPSR::SetThumbExecution(hw::reg::XPSR::DEFAULT_INIT);
3521#if STK_CORTEX_M_MANAGE_LR
3526 task_frame->EXC_RETURN = STK_CORTEX_M_EXC_RETURN_THREAD_PSP;
3529#if STK_CORTEX_M_PRIVILEGE_FRAME
3539 hw::reg::CONTROL::SetPrivileged(hw::reg::CONTROL::DEFAULT_INIT) :
3540 hw::reg::CONTROL::SetUnprivileged(
hw::reg::CONTROL::DEFAULT_INIT));
3545#if STK_CORTEX_M_TRUSTZONE_FRAME
3546 ConfigureTaskTrustZone(stack, stack_memory, user_task, is_non_secure_task);
3550#if STK_MPU_STACK_GUARD
3551 ConfigureTaskMpu(ctx.m_overrider, stack, stack_memory, user_task,
false);
3552 #if STK_CORTEX_M_TRUSTZONE_FRAME
3553 if (is_non_secure_task)
3555 ConfigureTaskMpu(ctx.m_overrider_ns, stack, user_task, user_task,
true);
3566#ifdef _STK_CORTEX_M_TRUSTZONE
3590 if ((sl !=
nullptr) && (cmse_check_pointed_object(sl, CMSE_NONSECURE) !=
nullptr))
3601 if ((sl !=
nullptr) && (cmse_check_pointed_object(sl, CMSE_NONSECURE) !=
nullptr))
3614 if ((sl !=
nullptr) && (cmse_check_pointed_object(sl, CMSE_NONSECURE) !=
nullptr))
3629uint32_t NSC_stk_hw_HiResClock_GetFrequency()
3645bool NSC_stk_hw_IsInsideISR()
3653TId NSC_stk_debug_GetCurrentTId()
3662void Context::OnStop()
3664#if STK_SEGGER_SYSVIEW
3665 SEGGER_SYSVIEW_Stop();
3672 HW_ClearPendingSwitch();
3687 HW_DisableInterrupts();
3698 return static_cast<Cycles>(HW_SysTickValue());
3703 return HW_CoreClockFrequency();
3708 GetContext().m_handler->OnTaskSwitch(HW_GetCallerSP());
3713 HW_ForceContextSwitch(
id);
3718 GetContext().m_handler->OnTaskSleep(HW_GetCallerSP(), ticks);
3723 return GetContext().m_handler->OnTaskSleepUntil(HW_GetCallerSP(), timestamp);
3728 return GetContext().m_handler->OnTaskWait(HW_GetCallerSP(), sync_obj, mutex, timeout);
3734 const Word isr = HW_GetCurrentException();
3749 result = ctx.m_handler->OnGetTid(HW_GetCallerSP());
3762 bool is_handled =
false;
3765 if (ctx.m_overrider !=
nullptr)
3767 is_handled = ctx.m_overrider->OnHardFault();
3782#if STK_CORTEX_M_TRUSTZONE_FRAME
3785 ctx.m_overrider_ns = overrider;
3792 ctx.m_overrider = overrider;
3798 return HW_GetCallerSP();
3803#if STK_TICKLESS_IDLE
3812#if STK_TICKLESS_IDLE
3823 if (core_id == 0xFFU)
3827 s_StkSystemCoreClock[i] = frequency;
3836 s_StkSystemCoreClock[core_id] = frequency;
3860 explicit KernelServiceSvcProxy() : IKernelService()
3879 void Wake(stk::ISyncObject *sobj,
bool all);
3888s_StkKernelServiceUnprivProxy;
3891stk::TId KernelServiceSvcProxy::GetTid()
const
3893 const ScopedPrivilegeBoost pb;
3898stk::Ticks KernelServiceSvcProxy::GetTicks()
const
3900 const ScopedPrivilegeBoost pb;
3905uint32_t KernelServiceSvcProxy::GetTickResolution()
const
3907 const ScopedPrivilegeBoost pb;
3912stk::Cycles KernelServiceSvcProxy::GetSysTimerCount()
const
3914 const ScopedPrivilegeBoost pb;
3915 return GetContext().m_service->GetSysTimerCount();
3919uint32_t KernelServiceSvcProxy::GetSysTimerFrequency()
const
3921 const ScopedPrivilegeBoost pb;
3922 return GetContext().m_service->GetSysTimerFrequency();
3928 const ScopedPrivilegeBoost pb;
3935 const ScopedPrivilegeBoost pb;
3940bool KernelServiceSvcProxy::SleepUntil(
stk::Ticks timestamp)
3942 const ScopedPrivilegeBoost pb;
3943 return GetContext().m_service->SleepUntil(timestamp);
3947void KernelServiceSvcProxy::SleepCancel(
stk::TId task_id)
3949 const ScopedPrivilegeBoost pb;
3950 GetContext().m_service->SleepCancel(task_id);
3954void KernelServiceSvcProxy::SwitchToNext()
3956 const ScopedPrivilegeBoost pb;
3963 const ScopedPrivilegeBoost pb;
3964 return GetContext().m_service->Wait(sobj, mutex, timeout);
3970 const ScopedPrivilegeBoost pb;
3981void KernelServiceSvcProxy::Resume(
stk::Timeout elapsed_ticks)
3990 const ScopedPrivilegeBoost pb;
3991 GetContext().m_service->InheritWeight(tid, weight);
3997 const ScopedPrivilegeBoost pb;
3998 GetContext().m_service->RestoreWeight(tid, sobj);
4007 if (HW_IsPrivilegedContext() || HW_IsHandlerMode())
4013 service = &s_StkKernelServiceUnprivProxy;
4027 const bool is_priv = ((ses &
SESSION_FLAG_NPRIV) == 0U) && (HW_IsPrivilegedContext() || HW_IsHandlerMode());
4036 HW_UnprivEnterCriticalSection();
4046 if ((ses & SESSION_FLAG_NPRIV) == 0U)
4052 HW_UnprivExitCriticalSection();
4059 HW_SpinLockLock(m_lock);
4065 HW_SpinLockUnlock(m_lock);
4071 return HW_SpinLockTryLock(m_lock);
4077 return HW_IsHandlerMode();
4083 return HW_IsPrivilegedContext();
4089 return HiResClockImpl::GetInstance()->GetCycles();
4095 const uint32_t freq = HiResClockImpl::GetInstance()->GetFrequency();
4100#if STK_TLS && !STK_INLINE_TLS
4101Word stk::hw::GetTls()
4106void stk::hw::SetTls(
Word tp)
4120void hw::mpu::ConfigureRegion(MpuRegion ®,
const struct MpuRegionConfig &cfg, uint32_t region_idx)
4123 if ((cfg.size != 0U) && (cfg.access_perm != EMpuAccess::ACCESS_NONE))
4130 reg.addr = (cfg.addr & ~31U) |
4131 static_cast<uint32_t
>(cfg.share) |
4132 static_cast<uint32_t
>(cfg.access_perm) |
4133 static_cast<uint32_t
>(cfg.exec);
4137 const uint32_t end_byte_addr = cfg.addr + cfg.size - 1U;
4139 const uint32_t limit_addr = end_byte_addr & ~31U;
4140 reg.attr = limit_addr | (
static_cast<uint32_t
>(cfg.mem_type) << 1U) | hw::mpu::RLAR_ENABLE_FLAG;
4145 reg.addr = hw::mpu::RBAR_DISABLED_REGION(region_idx);
4146 reg.attr = hw::mpu::RLAR_DISABLED_REGION;
4150 if ((cfg.size != 0U) && (cfg.access_perm != EMpuAccess::ACCESS_NONE))
4153 STK_ASSERT((cfg.size & (cfg.size - 1U)) == 0U);
4154 STK_ASSERT((cfg.addr & (cfg.size - 1U)) == 0U);
4157 reg.addr = (cfg.addr & ~(cfg.size - 1U)) | (1U << 4U) | (region_idx & 0xFU);
4160 const uint32_t size_field =
static_cast<uint32_t
>(31U -
CountLeadingZeros(cfg.size)) - 1U;
4163 const uint32_t ap_bits =
static_cast<uint32_t
>(cfg.access_perm) & 0x07000000U;
4165 const uint32_t attr = (ap_bits |
4166 static_cast<uint32_t
>(cfg.share) |
4167 static_cast<uint32_t
>(cfg.mem_type) |
4168 static_cast<uint32_t
>(cfg.exec));
4170 reg.attr = attr | (size_field << 1U) | hw::mpu::RASR_ENABLE_FLAG;
4176 reg.addr = hw::mpu::RBAR_DISABLED_REGION(region_idx);
4177 reg.attr = hw::mpu::RASR_DISABLED_REGION;
4182void hw::mpu::ApplyRegion(
const MpuRegion ®, uint32_t index,
bool non_secure)
4184#if STK_ARCH_ARMV8_M && !STK_TZ_NON_SECURE
4185 MPU_Type *
const MPU_ptr = (non_secure ? MPU_NS : MPU);
4187 MPU_Type *
const MPU_ptr = MPU;
4191 MPU_ptr->RNR = index;
4195 MPU_ptr->RBAR = reg.addr;
4197 MPU_ptr->RLAR = reg.attr;
4199 MPU_ptr->RASR = reg.attr;
4203void hw::mpu::Enable(
bool enable, uint32_t control_flags,
bool non_secure)
4207#if STK_ARCH_ARMV8_M && !STK_TZ_NON_SECURE
4208 MPU_Type *
const MPU_ptr = (non_secure ? MPU_NS : MPU);
4209 SCB_Type *
const SCB_ptr = (non_secure ? SCB_NS : SCB);
4211 MPU_Type *
const MPU_ptr = MPU;
4212 SCB_Type *
const SCB_ptr = SCB;
4218 #ifdef SCB_SHCSR_MEMFAULTENA_Msk
4219 SCB_ptr->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk;
4221 MPU_ptr->CTRL = control_flags | MPU_CTRL_ENABLE_Msk;
4225 #ifdef SCB_SHCSR_MEMFAULTENA_Msk
4226 SCB_ptr->SHCSR &= ~SCB_SHCSR_MEMFAULTENA_Msk;
4228 MPU_ptr->CTRL &= ~MPU_CTRL_ENABLE_Msk;
4235void hw::mpu::DisableRegion(uint32_t index,
bool non_secure)
4237#if STK_ARCH_ARMV8_M && !STK_TZ_NON_SECURE
4238 MPU_Type *
const MPU_ptr = (non_secure ? MPU_NS : MPU);
4240 MPU_Type *
const MPU_ptr = MPU;
4244 MPU_ptr->RNR = index;
4247 MPU_ptr->RLAR = hw::mpu::RLAR_DISABLED_REGION;
4249 MPU_ptr->RASR = hw::mpu::RASR_DISABLED_REGION;
4253void hw::mpu::ConfigureStatic(
const MpuRegionConfig cfg_list[],
size_t cfg_count, uint32_t control_flags,
4256 STK_ASSERT((cfg_list !=
nullptr) || (cfg_count == 0U));
4258 const size_t region_idx = (non_secure ? STK_CORTEX_M_MPU_TASK_REGION_IDX_NS : STK_CORTEX_M_MPU_TASK_REGION_IDX);
4259 STK_ASSERT((cfg_count <= region_idx) || (region_idx == 0U));
4262 ValidateNoOverlaps(
nullptr, 0U, cfg_list, cfg_count);
4264 Enable(
false, 0U, non_secure);
4270 for (; index < cfg_count; ++index)
4272 const MpuRegionConfig &cfg = cfg_list[index];
4275 ConfigureRegion(reg, cfg,
static_cast<uint32_t
>(index));
4276 ApplyRegion(reg,
static_cast<uint32_t
>(index), non_secure);
4282 for (; index < region_idx; ++index)
4285 ConfigureRegion(reg, s_StkDisabledMpuRegion,
static_cast<uint32_t
>(index));
4286 ApplyRegion(reg,
static_cast<uint32_t
>(index), non_secure);
4293 #if STK_ARCH_ARMV8_M && STK_TZ_SECURE
4294 MPU_Type *
const MPU_ptr = (non_secure ? MPU_NS : MPU);
4296 MPU_Type *
const MPU_ptr = MPU;
4300 #if STK_ARCH_ARMV8_M
4302 MPU_ptr->MAIR0 = MAIR0_PMSAV8_INIT;
4303 MPU_ptr->MAIR1 = MAIR1_PMSAV8_INIT;
4307 MPU_ptr->RNR = region_idx;
4310 Enable(
true, control_flags, non_secure);
4313void hw::mpu::ConfigureDynamic(TaskMpu &task_mpu,
const struct MpuRegionConfig cfg_list[],
4314 const size_t cfg_count, IPlatform::IEventOverrider *overrider,
bool non_secure)
4316 STK_ASSERT((cfg_list !=
nullptr) || (cfg_count == 0U));
4318 const size_t region_idx = (non_secure ? STK_CORTEX_M_MPU_TASK_REGION_IDX_NS : STK_CORTEX_M_MPU_TASK_REGION_IDX);
4319 const size_t task_mpu_regions = (non_secure ? TaskMpuNs::NUM_REGIONS : TaskMpu::NUM_REGIONS);
4322 const size_t clamped_count =
Min(cfg_count, task_mpu_regions);
4325 MpuRegionList static_regions(
nullptr, 0);
4326 if (overrider !=
nullptr)
4328 const MpuConfig *
const cfg = overrider->OnConfigureMpu();
4331 static_regions = cfg->regions;
4336 ValidateNoOverlaps(static_regions.GetPtr(), static_regions.GetSize(), cfg_list, clamped_count);
4340 size_t task_idx = 0U;
4341 for (; task_idx < clamped_count; ++task_idx)
4343 ConfigureRegion(task_mpu.region[task_idx], cfg_list[task_idx],
4344 static_cast<uint32_t
>(region_idx + task_idx));
4351 for (; task_idx < task_mpu_regions; ++task_idx)
4353 ConfigureRegion(task_mpu.region[task_idx], s_StkDisabledMpuRegion,
4354 static_cast<uint32_t
>(region_idx + task_idx));
4367static void FaultContext_FillMpu(FaultContext::Mpu &mpu_ctx, MPU_Type *mpu_inst)
4369 mpu_ctx.
CTRL = mpu_inst->CTRL;
4371 mpu_ctx.MAIR0 = mpu_inst->MAIR0;
4372 mpu_ctx.MAIR1 = mpu_inst->MAIR1;
4375 const Word saved_rnr = mpu_inst->RNR;
4378 mpu_inst->RNR =
static_cast<Word>(i);
4383 #if STK_ARCH_ARMV8_M
4389 mpu_inst->RNR = saved_rnr;
4395 this->frame.
R0 = stacked_regs[0];
4396 this->frame.
R1 = stacked_regs[1];
4397 this->frame.
R2 = stacked_regs[2];
4398 this->frame.
R3 = stacked_regs[3];
4399 this->frame.
R12 = stacked_regs[4];
4400 this->frame.
LR = stacked_regs[5];
4401 this->frame.
PC = stacked_regs[6];
4402 this->frame.
xPSR = stacked_regs[7];
4404 this->EXC_RETURN = exc_return;
4405 this->CONTROL = __get_CONTROL();
4412 this->mmfar_valid =
false;
4413 this->bfar_valid =
false;
4418 this->CFSR = SCB->CFSR;
4419 this->HFSR = SCB->HFSR;
4420 this->AFSR = SCB->AFSR;
4421 this->mmfar_valid = ((this->CFSR & SCB_CFSR_MMARVALID_Msk) != 0U);
4422 this->bfar_valid = ((this->CFSR & SCB_CFSR_BFARVALID_Msk) != 0U);
4423 this->MMFAR = (this->mmfar_valid ? SCB->MMFAR : 0U);
4424 this->BFAR = (this->bfar_valid ? SCB->BFAR : 0U);
4428 FaultContext_FillMpu(this->mpu, MPU);
4429 #if STK_ARCH_ARMV8_M && STK_TZ_SECURE
4430 FaultContext_FillMpu(this->mpu_ns, MPU_NS);
#define STK_ASM_SYNTAX_UNIFIED
#define STK_ASM_EXTRACT_STACK_POINTER_TO_R0
#define STK_ASM_GLOBAL_SYMBOL(name)
Generates a toolchain-agnostic assembly directive to declare a global symbol.
static void __stk_dmb()
Hardware memory barrier: ensures visibility across cores and bus masters.
#define STK_TZ_NSC_GATEWAY
#define STK_CORTEX_M_MPU_REGIONS_MAX
Number of MPU regions supported by MPU peripheral.
#define STK_CORTEX_M_SVCALL_ISR_PRIORITY
Max SVCall ISR priority.
Contains common inventory for platform implementation.
#define STK_ARCH_GET_CPU_ID()
Get CPU core id of the caller, e.g. if called while running on core 0 then returned value must be 0.
#define GetContext()
Get platform's context.
Top-level STK include. Provides the Kernel class template and all built-in task-switching strategies.
Hardware Abstraction Layer (HAL) declarations for the stk::hw namespace.
void STK_PANIC_HANDLER_DEFAULT(stk::EKernelPanicId id)
Default panic handler: disable interrupts, record the id, and spin in a tight loop - a defined,...
#define STK_MPU_SHARED_CODE_SECTION
#define STK_MPU_KERNEL_DATA_SECTION
#define STK_MPU_KERNEL_BSS_SECTION
#define STK_MPU_KERNEL_CODE_SECTION
#define STK_MPU_SHARED_DATA_SECTION
#define STK_UNUSED(X)
Explicitly marks a variable as unused to suppress compiler warnings.
#define __stk_attr_used
Marks a symbol as used, preventing the linker from discarding it even if no references are visible (d...
#define __stk_forceinline
Forces compiler to always inline the decorated function, regardless of optimisation level.
#define STK_SLEEP_TRAP_STACK_SIZE
Stack size for the sleep trap in elements of Word (default: STK_STACK_SIZE_MIN).
#define STK_CS_NESTINGS_MAX
Maximum allowable recursion depth for critical section entry (default: 16).
#define STK_ASSERT(e)
Runtime assertion. Halts execution if the expression e evaluates to false.
#define STK_STACK_SIZE_MIN
Minimum stack size in elements of Word, shared by all stack allocation lower-bound checks.
#define STK_MPU_TASK_REGIONS
Number of hardware MPU region slots reserved per task (stk::TaskMpu::NUM_REGIONS).
#define __stk_attr_noinline
Prevents compiler from inlining the decorated function (function prefix).
#define STK_STATIC_ASSERT_DESC_N(NAME, X, DESC)
Compile-time assertion with a user-defined name suffix and a custom error description.
#define STK_ARCH_CPU_COUNT
Number of physical CPU cores available to the scheduler (default: 1).
#define __stk_attr_naked
Suppresses compiler-generated function prologue and epilogue (function prefix).
#define STK_MPU_TASK_REGIONS_NS
#define STK_STACK_MEMORY_FILLER
Sentinel value written to the entire stack region at initialization (stack watermark pattern).
#define __stk_attr_unused
Suppresses compiler warnings about an unused type, variable, or function (declaration prefix).
#define __stk_attr_noreturn
Declares that function never returns to its caller (function prefix).
static void __stk_debug_break()
#define STK_STATIC_ARRAY_SIZE(ARRAY)
Get size of the static array.
#define STK_STATIC_ASSERT(X)
Compile-time assertion. Produces a compilation error if X is false.
#define STK_VIRT_DTOR
Makes destructors virtual and compliant to strict rules if STK_STRICT_COMPLIANCY=0.
Namespace of STK package.
uintptr_t Word
Native processor word type.
static uint32_t CountLeadingZeros(const uint32_t value) noexcept
Count leading zeros.
static constexpr TId TID_ISR_N
Bitmask sentinel for ISR-context task identifiers.
@ ACCESS_PRIVILEGED
Privileged access mode (access to hardware is fully unrestricted).
@ ACCESS_SECURE
Secure access mode (ARM TrustZone, Secure binary).
static constexpr Timeout NO_WAIT
Timeout value: return immediately if the synchronization object is not yet signaled (non-blocking pol...
EWaitResult
Wait result (see IKernelService::Wait).
static __stk_forceinline Cycles ConvertTimeUsToClockCycles(uint32_t clock_freq, Ticks time_us)
Convert time (microseconds) to core clock cycles.
int64_t Ticks
Ticks value.
EKernelPanicId
Identifies the source of a kernel panic.
@ KERNEL_PANIC_UNKNOWN_SVC
Unknown service command received by SVC handler.
@ KERNEL_PANIC_BAD_STACK_TYPE
Stack type is unknown.
@ KERNEL_PANIC_NS_ACCESS
Non-secure access to protected resource.
@ KERNEL_PANIC_HRT_HARD_FAULT
Kernel running in KERNEL_HRT mode reported deadline failure of the task.
@ KERNEL_PANIC_NONE
Panic is absent (no fault).
@ KERNEL_PANIC_SPINLOCK_DEADLOCK
Spin-lock timeout expired: lock owner never released.
int32_t Timeout
Timeout time (ticks).
static bool IsIsrTid(TId id)
Test whether a task identifier represents an ISR context.
static void STK_KERNEL_PANIC(stk::EKernelPanicId id)
Called when the kernel detects an unrecoverable internal fault.
@ SYS_TASK_ID_SLEEP
Sleep trap.
static constexpr T Max(T a, T b) noexcept
Compile-time maximum of two values.
static Ticks GetTicks()
Get number of ticks elapsed since kernel start.
static constexpr TId TID_NONE
Reserved task/thread id representing zero/none thread id.
static constexpr T Min(T a, T b) noexcept
Compile-time minimum of two values.
@ TRACE_EVENT_SWITCH
Task blocked by the context switch.
@ STACK_SLEEP_TRAP
Stack of the Sleep trap.
@ STACK_USER_TASK
Stack of the user task.
@ STACK_EXIT_TRAP
Stack of the Exit trap.
uint64_t Cycles
Cycles value.
EHwException
Hardware exception id (see IPlatform::IEventOverrider::OnException).
@ HW_EXCEPT_MEMACCESS
MemManage on ARM / Page Fault or PMP violation on RISC-V.
@ HW_EXCEPT_FATAL
HardFault on ARM / Unhandled Fatal Trap on RISC-V.
Word TId
Task (thread) id.
int32_t Weight
Weight value (aka priority).
Hardware Abstraction Layer (HAL) for architecture-specific operations.
bool IsPrivilegedContext()
Check if caller context is Privileged.
static constexpr T * WordToPtr(Word value) noexcept
Cast a CPU register-width integer back to a pointer.
static constexpr Word PtrToWord(T *const ptr) noexcept
Cast a pointer to a CPU register-width integer.
bool IsInsideISR()
Check whether the CPU is currently executing inside a hardware interrupt service routine (ISR).
void SwitchToNext() override
Switch to a next task.
void Sleep(Timeout ticks) override
Put calling process into a sleep state.
void ProcessTick() override
Process one tick.
Word GetCallerSP() const override
Get caller's Stack Pointer (SP).
void ProcessHardFault() override
Cause a hard fault of the system.
void ForceContextSwitch(TId id) override
Force context switch.
uint32_t GetTickResolution() const override
Get resolution of the system tick timer in microseconds. Resolution means a number of microseconds be...
Timeout Suspend() override
Suspend scheduling.
void Start() override
Start scheduling.
void SetCpuFrequency(uint8_t core_id, uint32_t frequency) override
Notify the scheduler of a CPU core's operating frequency.
void Stop() override
Stop scheduling.
TId GetTid() const override
Get thread Id.
void SetEventOverrider(IEventOverrider *overrider, bool non_secure) override
Set platform event overrider.
uint32_t GetSysTimerFrequency() const override
Get system timer frequency.
Cycles GetSysTimerCount() const override
Get system timer count value.
void InitStack(EStackType stack_type, Stack *stack, IStackMemory *stack_memory, ITask *user_task) override
Initialize stack memory of the user task.
EWaitResult Wait(ISyncObject *sync_obj, IMutex *mutex, Timeout timeout) override
Put calling process into a waiting state until synchronization object is signaled or timeout occurs.
void Resume(Timeout elapsed_ticks) override
Resume scheduling after a prior Suspend() call.
void Initialize(IEventHandler *event_handler, IKernelService *service, uint32_t resolution_us, Stack *exit_trap) override
Initialize scheduler's context.
bool SleepUntil(Ticks timestamp) override
Put calling process into a sleep state until the specified timestamp.
ARMv7-M/ARMv8-M hardware exception frame (8 words, highest address on the stack).
ARMv7-M/ARMv8-M system fault exception context state capture.
void Fill(const Word *stacked_regs, Word exc_return)
Populate fault context registers and hardware MPU state from an exception stack frame.
Region regions[(8U)]
Active hardware MPU region register state table.
Word CTRL
MPU Control Register (MPU_CTRL).
Word RNR
Region Number Register (RNR).
Word ATTR
Region Attribute and Size Register (RASR / RLAR / MPU_RLAR).
Word RBAR
Region Base Address Register (RBAR).
Base platform context for all platform implementations.
static Session Enter(const Session ses=DEFAULT_SESSION)
Enter a critical section.
uint8_t Session
Opaque session token returned by Enter() and consumed by Exit().
static void Exit(const Session ses=DEFAULT_SESSION)
Exit a critical section.
@ SESSION_FLAG_NPRIV
Calling context is non-Privileged.
RAII instance that enters the critical section on construction and exits it on destruction.
Atomic busy-wait lock used as the global cross-core synchronisation primitive inside CriticalSection.
bool TryLock()
Attempt to acquire SpinLock in a single non-blocking attempt.
void Lock()
Acquire SpinLock, blocking until it is available.
void Unlock()
Release SpinLock, allowing another thread or core to acquire it.
static uint32_t GetFrequency()
Get clock frequency.
static Cycles GetCycles()
Get number of clock cycles elapsed.
uint32_t access_mode
Bitfield with hardware access mode of the task (see EAccessMode).
Word SP
Offset 0: Stack Pointer (SP) register (note: must always be at offset 0).
Interface for a stack memory region.
virtual size_t GetStackSize() const =0
Get number of elements of the stack memory array.
virtual const Word * GetStack() const =0
Get pointer to the stack memory.
Synchronization object interface.
Interface for mutex synchronization primitive.
Interface for a user task.
virtual void Run()=0
Entry point of the user task.
Interface for a platform event overrider.
Interface for the kernel services exposed to the user processes during run-time when Kernel started s...
virtual TId GetTid() const =0
Get thread Id of the currently running task.
virtual void Wake(ISyncObject *sobj, bool all)=0
Wake one or all tasks currently waiting on a synchronization object.
virtual void SleepCancel(TId task_id)=0
Cancel sleep of the task.
virtual void InheritWeight(TId tid, Weight weight)=0
Inherit weight for the task.
static IKernelService * GetInstance()
Get CPU-local instance of the kernel service.
virtual uint32_t GetTickResolution() const =0
Get number of microseconds in one tick.
virtual bool SleepUntil(Ticks timestamp)=0
Put calling process into a sleep state until the specified timestamp.
virtual Ticks GetTicks() const =0
Get number of ticks elapsed since kernel start.
virtual void SwitchToNext()=0
Notify scheduler to switch to the next task (yield).
virtual void Resume(Timeout elapsed_ticks)=0
Resume scheduling after a prior Suspend() call.
virtual void Sleep(Timeout ticks)=0
Put calling process into a sleep state.
virtual EWaitResult Wait(ISyncObject *sobj, IMutex *mutex, Timeout timeout)=0
Put calling process into a waiting state until synchronization object is signaled or timeout occurs.
virtual Cycles GetSysTimerCount() const =0
Get system timer count value.
virtual uint32_t GetSysTimerFrequency() const =0
Get system timer frequency.
virtual Timeout Suspend()=0
Suspend scheduling.
virtual void RestoreWeight(TId tid, ISyncObject *sobj=nullptr)=0
Restore weight of the task to the original value.
virtual void Delay(Timeout ticks)=0
Delay calling process.
RISC-V specific event handler.
MPU descriptor of the task.