xmclib/CMSIS/RTOS2/RTX/Source/rtx_kernel.c
2024-10-17 17:09:59 +02:00

626 lines
18 KiB
C

/*
* Copyright (c) 2013-2017 ARM Limited. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* -----------------------------------------------------------------------------
*
* Project: CMSIS-RTOS RTX
* Title: Kernel functions
*
* -----------------------------------------------------------------------------
*/
#include "rtx_lib.h"
// OS Runtime Information
osRtxInfo_t osRtxInfo __attribute__((section(".data.os"))) =
{ .os_id = osRtxKernelId, .version = osRtxVersionKernel, .kernel.state = osRtxKernelInactive };
// Library reference to irq module
extern uint8_t irqRtxLib;
extern const uint8_t *irqRtxLibRef __attribute__((weak));
const uint8_t* irqRtxLibRef = &irqRtxLib;
// ==== Helper functions ====
/// Block Kernel (disable: thread switching, time tick, post ISR processing).
static void KernelBlock (void) {
if (osRtxInfo.tick_irqn >= 0) {
ExtTick_DisableIRQ(osRtxInfo.tick_irqn);
}
osRtxSysTimerDisable();
osRtxInfo.kernel.blocked = 1U;
__DSB();
if (osRtxInfo.tick_irqn < 0) {
osRtxInfo.kernel.pendISR = GetPendSV_ST();
ClrPendSV_ST();
} else {
osRtxInfo.kernel.pendISR = GetPendSV();
ClrPendSV();
}
}
/// Unblock Kernel
static void KernelUnblock (void) {
osRtxInfo.kernel.blocked = 0U;
__DSB();
if (osRtxInfo.kernel.pendSV != 0U) {
osRtxInfo.kernel.pendSV = 0U;
SetPendSV();
}
if (osRtxInfo.kernel.pendISR != 0U) {
SetPendFlags(osRtxInfo.kernel.pendISR);
}
if (osRtxInfo.tick_irqn >= 0) {
ExtTick_EnableIRQ(osRtxInfo.tick_irqn);
}
osRtxSysTimerEnable();
}
// ==== Service Calls ====
// Service Calls definitions
SVC0_0M(KernelInitialize, osStatus_t)
SVC0_3 (KernelGetInfo, osStatus_t, osVersion_t *, char *, uint32_t)
SVC0_0M(KernelStart, osStatus_t)
SVC0_0 (KernelLock, int32_t)
SVC0_0 (KernelUnlock, int32_t)
SVC0_1 (KernelRestoreLock, int32_t, int32_t)
SVC0_0 (KernelSuspend, uint32_t)
SVC0_1N(KernelResume, void, uint32_t)
SVC0_0 (KernelGetState, osKernelState_t)
SVC0_0D(KernelGetTickCount, uint64_t)
SVC0_0 (KernelGetTickFreq, uint32_t)
SVC0_0 (KernelGetSysTimerCount, uint32_t)
SVC0_0 (KernelGetSysTimerFreq, uint32_t)
/// Initialize the RTOS Kernel.
/// \note API identical to osKernelInitialize
osStatus_t svcRtxKernelInitialize (void) {
if (osRtxInfo.kernel.state == osRtxKernelReady) {
EvrRtxKernelInitializeCompleted();
return osOK;
}
if (osRtxInfo.kernel.state != osKernelInactive) {
EvrRtxKernelError(osError);
return osError;
}
// Initialize osRtxInfo
memset(&osRtxInfo.kernel, 0, sizeof(osRtxInfo) - offsetof(osRtxInfo_t, kernel));
if (osRtxConfig.thread_stack_size < (64U + 8U)) {
EvrRtxKernelError(osRtxErrorInvalidThreadStack);
return osError;
}
if ((osRtxConfig.isr_queue.data == NULL) || (osRtxConfig.isr_queue.max == 0U)) {
EvrRtxKernelError(osError);
return osError;
}
osRtxInfo.isr_queue.data = osRtxConfig.isr_queue.data;
osRtxInfo.isr_queue.max = osRtxConfig.isr_queue.max;
osRtxInfo.thread.robin.timeout = osRtxConfig.robin_timeout;
// Initialize Memory Pools (Variable Block Size)
if (osRtxMemoryInit(osRtxConfig.mem.common_addr, osRtxConfig.mem.common_size) != 0U) {
osRtxInfo.mem.common = osRtxConfig.mem.common_addr;
}
if (osRtxMemoryInit(osRtxConfig.mem.stack_addr, osRtxConfig.mem.stack_size) != 0U) {
osRtxInfo.mem.stack = osRtxConfig.mem.stack_addr;
} else {
osRtxInfo.mem.stack = osRtxInfo.mem.common;
}
if (osRtxMemoryInit(osRtxConfig.mem.mp_data_addr, osRtxConfig.mem.mp_data_size) != 0U) {
osRtxInfo.mem.mp_data = osRtxConfig.mem.mp_data_addr;
} else {
osRtxInfo.mem.mp_data = osRtxInfo.mem.common;
}
if (osRtxMemoryInit(osRtxConfig.mem.mq_data_addr, osRtxConfig.mem.mq_data_size) != 0U) {
osRtxInfo.mem.mq_data = osRtxConfig.mem.mq_data_addr;
} else {
osRtxInfo.mem.mq_data = osRtxInfo.mem.common;
}
// Initialize Memory Pools (Fixed Block Size)
if ((osRtxConfig.mpi.stack != NULL) &&
(osRtxMemoryPoolInit(osRtxConfig.mpi.stack,
osRtxConfig.mpi.stack->max_blocks,
osRtxConfig.mpi.stack->block_size,
osRtxConfig.mpi.stack->block_base) != 0U)) {
osRtxInfo.mpi.stack = osRtxConfig.mpi.stack;
}
if ((osRtxConfig.mpi.thread != NULL) &&
(osRtxMemoryPoolInit(osRtxConfig.mpi.thread,
osRtxConfig.mpi.thread->max_blocks,
osRtxConfig.mpi.thread->block_size,
osRtxConfig.mpi.thread->block_base) != 0U)) {
osRtxInfo.mpi.thread = osRtxConfig.mpi.thread;
}
if ((osRtxConfig.mpi.timer != NULL) &&
(osRtxMemoryPoolInit(osRtxConfig.mpi.timer,
osRtxConfig.mpi.timer->max_blocks,
osRtxConfig.mpi.timer->block_size,
osRtxConfig.mpi.timer->block_base) != 0U)) {
osRtxInfo.mpi.timer = osRtxConfig.mpi.timer;
}
if ((osRtxConfig.mpi.event_flags != NULL) &&
(osRtxMemoryPoolInit(osRtxConfig.mpi.event_flags,
osRtxConfig.mpi.event_flags->max_blocks,
osRtxConfig.mpi.event_flags->block_size,
osRtxConfig.mpi.event_flags->block_base) != 0U)) {
osRtxInfo.mpi.event_flags = osRtxConfig.mpi.event_flags;
}
if ((osRtxConfig.mpi.mutex != NULL) &&
(osRtxMemoryPoolInit(osRtxConfig.mpi.mutex,
osRtxConfig.mpi.mutex->max_blocks,
osRtxConfig.mpi.mutex->block_size,
osRtxConfig.mpi.mutex->block_base) != 0U)) {
osRtxInfo.mpi.mutex = osRtxConfig.mpi.mutex;
}
if ((osRtxConfig.mpi.semaphore != NULL) &&
(osRtxMemoryPoolInit(osRtxConfig.mpi.semaphore,
osRtxConfig.mpi.semaphore->max_blocks,
osRtxConfig.mpi.semaphore->block_size,
osRtxConfig.mpi.semaphore->block_base) != 0U)) {
osRtxInfo.mpi.semaphore = osRtxConfig.mpi.semaphore;
}
if ((osRtxConfig.mpi.memory_pool != NULL) &&
(osRtxMemoryPoolInit(osRtxConfig.mpi.memory_pool,
osRtxConfig.mpi.memory_pool->max_blocks,
osRtxConfig.mpi.memory_pool->block_size,
osRtxConfig.mpi.memory_pool->block_base) != 0U)) {
osRtxInfo.mpi.memory_pool = osRtxConfig.mpi.memory_pool;
}
if ((osRtxConfig.mpi.message_queue != NULL) &&
(osRtxMemoryPoolInit(osRtxConfig.mpi.message_queue,
osRtxConfig.mpi.message_queue->max_blocks,
osRtxConfig.mpi.message_queue->block_size,
osRtxConfig.mpi.message_queue->block_base) != 0U)) {
osRtxInfo.mpi.message_queue = osRtxConfig.mpi.message_queue;
}
#if (__DOMAIN_NS == 1U)
// Initialize Secure Process Stack
if (TZ_InitContextSystem_S() == 0U) {
EvrRtxKernelError(osRtxErrorTZ_InitContext_S);
return osError;
}
#endif
// Initialize SVC and PendSV System Service Calls
SVC_Initialize();
osRtxInfo.kernel.state = osRtxKernelReady;
EvrRtxKernelInitializeCompleted();
return osOK;
}
/// Get RTOS Kernel Information.
/// \note API identical to osKernelGetInfo
osStatus_t svcRtxKernelGetInfo (osVersion_t *version, char *id_buf, uint32_t id_size) {
if (version != NULL) {
version->api = osRtxVersionAPI;
version->kernel = osRtxVersionKernel;
}
if ((id_buf != NULL) && (id_size != 0U)) {
if (id_size > sizeof(osRtxKernelId)) {
id_size = sizeof(osRtxKernelId);
}
memcpy(id_buf, osRtxKernelId, id_size);
}
EvrRtxKernelInfoRetrieved(version, id_buf);
return osOK;
}
/// Get the current RTOS Kernel state.
/// \note API identical to osKernelGetState
osKernelState_t svcRtxKernelGetState (void) {
EvrRtxKernelGetState((osKernelState_t)(osRtxInfo.kernel.state));
return ((osKernelState_t)(osRtxInfo.kernel.state));
}
/// Start the RTOS Kernel scheduler.
/// \note API identical to osKernelStart
osStatus_t svcRtxKernelStart (void) {
os_thread_t *thread;
if (osRtxInfo.kernel.state != osRtxKernelReady) {
EvrRtxKernelError(osRtxErrorKernelNotReady);
return osError;
}
// Create Idle Thread
if (osRtxInfo.thread.idle == NULL) {
osRtxInfo.thread.idle = svcRtxThreadNew(osRtxIdleThread, NULL, osRtxConfig.idle_thread_attr);
if (osRtxInfo.thread.idle == NULL) {
EvrRtxKernelError(osError);
return osError;
}
}
// Switch to Ready Thread with highest Priority
thread = osRtxThreadListGet(&osRtxInfo.thread.ready);
if (thread == NULL) {
EvrRtxKernelError(osError);
return osError;
}
osRtxThreadSwitch(thread);
if ((osRtxConfig.flags & osRtxConfigPrivilegedMode) != 0U) {
// Privileged Thread mode & PSP
__set_CONTROL(0x02U);
} else {
// Unprivileged Thread mode & PSP
__set_CONTROL(0x03U);
}
osRtxInfo.kernel.sys_freq = SystemCoreClock;
// Setup and Enable System Timer
osRtxInfo.tick_irqn = osRtxSysTimerSetup();
if (osRtxInfo.tick_irqn >= 0) {
ExtTick_EnableIRQ(osRtxInfo.tick_irqn);
}
osRtxSysTimerEnable();
osRtxInfo.kernel.state = osRtxKernelRunning;
EvrRtxKernelStarted();
return osOK;
}
/// Lock the RTOS Kernel scheduler.
/// \note API identical to osKernelLock
int32_t svcRtxKernelLock (void) {
if (osRtxInfo.kernel.state == osRtxKernelLocked) {
EvrRtxKernelLocked(1);
return 1;
}
if (osRtxInfo.kernel.state == osRtxKernelRunning) {
osRtxInfo.kernel.state = osRtxKernelLocked;
EvrRtxKernelLocked(0);
return 0;
}
EvrRtxKernelError(osError);
return osError;
}
/// Unlock the RTOS Kernel scheduler.
/// \note API identical to osKernelUnlock
int32_t svcRtxKernelUnlock (void) {
if (osRtxInfo.kernel.state == osRtxKernelLocked) {
osRtxInfo.kernel.state = osRtxKernelRunning;
EvrRtxKernelUnlocked(1);
return 1;
}
if (osRtxInfo.kernel.state == osRtxKernelRunning) {
EvrRtxKernelUnlocked(0);
return 0;
}
EvrRtxKernelError(osError);
return osError;
}
/// Restore the RTOS Kernel scheduler lock state.
/// \note API identical to osKernelRestoreLock
int32_t svcRtxKernelRestoreLock (int32_t lock) {
if ((osRtxInfo.kernel.state == osRtxKernelRunning) ||
(osRtxInfo.kernel.state == osRtxKernelLocked)) {
switch (lock) {
case 1:
osRtxInfo.kernel.state = osRtxKernelLocked;
EvrRtxKernelLockRestored(1);
return 1;
case 0:
osRtxInfo.kernel.state = osRtxKernelRunning;
EvrRtxKernelLockRestored(0);
return 0;
default:
break;
}
}
EvrRtxKernelError(osError);
return osError;
}
/// Suspend the RTOS Kernel scheduler.
/// \note API identical to osKernelSuspend
uint32_t svcRtxKernelSuspend (void) {
os_thread_t *thread;
os_timer_t *timer;
uint32_t delay;
if (osRtxInfo.kernel.state != osRtxKernelRunning) {
EvrRtxKernelError(osRtxErrorKernelNotRunning);
return 0U;
}
KernelBlock();
delay = osWaitForever;
// Check Thread Delay list
thread = osRtxInfo.thread.delay_list;
if (thread != NULL) {
delay = thread->delay;
}
// Check Active Timer list
timer = osRtxInfo.timer.list;
if (timer != NULL) {
if (timer->tick < delay) {
delay = timer->tick;
}
}
osRtxInfo.kernel.state = osRtxKernelSuspended;
EvrRtxKernelSuspended(delay);
return delay;
}
/// Resume the RTOS Kernel scheduler.
/// \note API identical to osKernelResume
void svcRtxKernelResume (uint32_t sleep_ticks) {
os_thread_t *thread;
os_timer_t *timer;
uint32_t delay;
if (osRtxInfo.kernel.state != osRtxKernelSuspended) {
EvrRtxKernelResumed();
return;
}
// Process Thread Delay list
thread = osRtxInfo.thread.delay_list;
if (thread != NULL) {
delay = sleep_ticks;
if (delay >= thread->delay) {
delay -= thread->delay;
osRtxInfo.kernel.tick += thread->delay;
thread->delay = 1U;
do {
osRtxThreadDelayTick();
if (delay == 0U) {
break;
}
delay--;
osRtxInfo.kernel.tick++;
} while (osRtxInfo.thread.delay_list != NULL);
} else {
thread->delay -= delay;
osRtxInfo.kernel.tick += delay;
}
} else {
osRtxInfo.kernel.tick += sleep_ticks;
}
// Process Active Timer list
timer = osRtxInfo.timer.list;
if (timer != NULL) {
if (sleep_ticks >= timer->tick) {
sleep_ticks -= timer->tick;
timer->tick = 1U;
do {
osRtxTimerTick();
if (sleep_ticks == 0U) {
break;
}
sleep_ticks--;
} while (osRtxInfo.timer.list != NULL);
} else {
timer->tick -= sleep_ticks;
}
}
osRtxInfo.kernel.state = osRtxKernelRunning;
osRtxThreadDispatch(NULL);
KernelUnblock();
EvrRtxKernelResumed();
}
/// Get the RTOS kernel tick count.
/// \note API identical to osKernelGetTickCount
uint64_t svcRtxKernelGetTickCount (void) {
EvrRtxKernelGetTickCount(osRtxInfo.kernel.tick);
return osRtxInfo.kernel.tick;
}
/// Get the RTOS kernel tick frequency.
/// \note API identical to osKernelGetTickFreq
uint32_t svcRtxKernelGetTickFreq (void) {
EvrRtxKernelGetTickFreq(osRtxConfig.tick_freq);
return osRtxConfig.tick_freq;
}
/// Get the RTOS kernel system timer count.
/// \note API identical to osKernelGetSysTimerCount
uint32_t svcRtxKernelGetSysTimerCount (void) {
uint32_t count = osRtxSysTimerGetCount();
EvrRtxKernelGetSysTimerCount(count);
return count;
}
/// Get the RTOS kernel system timer frequency.
/// \note API identical to osKernelGetSysTimerFreq
uint32_t svcRtxKernelGetSysTimerFreq (void) {
uint32_t freq = osRtxSysTimerGetFreq();
EvrRtxKernelGetSysTimerFreq(freq);
return freq;
}
// ==== Public API ====
/// Initialize the RTOS Kernel.
osStatus_t osKernelInitialize (void) {
EvrRtxKernelInitialize();
if (IS_IRQ_MODE() || IS_IRQ_MASKED()) {
EvrRtxKernelError(osErrorISR);
return osErrorISR;
}
return __svcKernelInitialize();
}
/// Get RTOS Kernel Information.
osStatus_t osKernelGetInfo (osVersion_t *version, char *id_buf, uint32_t id_size) {
EvrRtxKernelGetInfo(version, id_buf, id_size);
if (IS_IRQ_MODE() || IS_IRQ_MASKED()) {
EvrRtxKernelError(osErrorISR);
return osErrorISR;
}
if (IS_PRIVILEGED()) {
return svcRtxKernelGetInfo(version, id_buf, id_size);
} else {
return __svcKernelGetInfo(version, id_buf, id_size);
}
}
/// Get the current RTOS Kernel state.
osKernelState_t osKernelGetState (void) {
if (IS_IRQ_MODE() || IS_IRQ_MASKED()) {
EvrRtxKernelGetState(osKernelError);
return osKernelError;
}
if (IS_PRIVILEGED()) {
return svcRtxKernelGetState();
} else {
return __svcKernelGetState();
}
}
/// Start the RTOS Kernel scheduler.
osStatus_t osKernelStart (void) {
EvrRtxKernelStart();
if (IS_IRQ_MODE() || IS_IRQ_MASKED()) {
EvrRtxKernelError(osErrorISR);
return osErrorISR;
}
return __svcKernelStart();
}
/// Lock the RTOS Kernel scheduler.
int32_t osKernelLock (void) {
EvrRtxKernelLock();
if (IS_IRQ_MODE() || IS_IRQ_MASKED()) {
EvrRtxKernelError(osErrorISR);
return osErrorISR;
}
return __svcKernelLock();
}
/// Unlock the RTOS Kernel scheduler.
int32_t osKernelUnlock (void) {
EvrRtxKernelUnlock();
if (IS_IRQ_MODE() || IS_IRQ_MASKED()) {
EvrRtxKernelError(osErrorISR);
return osErrorISR;
}
return __svcKernelUnlock();
}
/// Restore the RTOS Kernel scheduler lock state.
int32_t osKernelRestoreLock (int32_t lock) {
EvrRtxKernelRestoreLock(lock);
if (IS_IRQ_MODE() || IS_IRQ_MASKED()) {
EvrRtxKernelError(osErrorISR);
return osErrorISR;
}
return __svcKernelRestoreLock(lock);
}
/// Suspend the RTOS Kernel scheduler.
uint32_t osKernelSuspend (void) {
EvrRtxKernelSuspend();
if (IS_IRQ_MODE() || IS_IRQ_MASKED()) {
EvrRtxKernelError(osErrorISR);
return 0U;
}
return __svcKernelSuspend();
}
/// Resume the RTOS Kernel scheduler.
void osKernelResume (uint32_t sleep_ticks) {
EvrRtxKernelResume(sleep_ticks);
if (IS_IRQ_MODE() || IS_IRQ_MASKED()) {
EvrRtxKernelError(osErrorISR);
return;
}
__svcKernelResume(sleep_ticks);
}
/// Get the RTOS kernel tick count.
uint64_t osKernelGetTickCount (void) {
if (IS_IRQ_MODE() || IS_IRQ_MASKED()) {
EvrRtxKernelGetTickCount(0U);
return 0U;
} else {
return __svcKernelGetTickCount();
}
}
/// Get the RTOS kernel tick frequency.
uint32_t osKernelGetTickFreq (void) {
if (IS_IRQ_MODE() || IS_IRQ_MASKED()) {
EvrRtxKernelGetTickFreq(0U);
return 0U;
} else {
return __svcKernelGetTickFreq();
}
}
/// Get the RTOS kernel system timer count.
uint32_t osKernelGetSysTimerCount (void) {
if (IS_IRQ_MODE() || IS_IRQ_MASKED()) {
return svcRtxKernelGetSysTimerCount();
} else {
return __svcKernelGetSysTimerCount();
}
}
/// Get the RTOS kernel system timer frequency.
uint32_t osKernelGetSysTimerFreq (void) {
if (IS_IRQ_MODE() || IS_IRQ_MASKED()) {
return svcRtxKernelGetSysTimerFreq();
} else {
return __svcKernelGetSysTimerFreq();
}
}