Kernel
Main header file for the QRT kernel.
This file contains the main declarations for the QRT kernel. It includes function prototypes for initializing and starting the kernel, MPU configuration, as well as type definitions for integer types.
Typedefs
-
typedef unsigned long long int qrt_u64_t
-
typedef unsigned int qrt_u32_t
-
typedef unsigned short qrt_u16_t
-
typedef unsigned char qrt_u8_t
-
typedef signed long long int qrt_s64_t
-
typedef signed int qrt_s32_t
-
typedef signed short qrt_s16_t
-
typedef signed char qrt_s8_t
-
typedef unsigned long int qrt_uptr_t
-
typedef signed long int qrt_sptr_t
Functions
-
qrt_s32_t qrt_syscall_register(qrt_s32_t (*syscall)(void *args), qrt_u32_t *id)
Register a user-defined function as a System Call Extension and return its function ID via
id.At most QRT_CFG_SYSCALL_EXT_LIMIT extensions can be registered. Only available when MPU support and the syscall-extension feature are both compiled in; callers must be privileged.
The extension runs in privileged (kernel) context and its single argument is a pointer to the caller’s saved-register frame, not the
paramvalue handed to qrt_syscall_invoke. That value occupies the first slot of the frame, so an extension reads it asThe frame pointer is never NULL, even when the caller passed NULL. Whatever the caller put in the slot – an address or a plain integer – arrives unchanged and unchecked: the kernel neither dereferences nor validates it, so an extension must treat it as untrusted unprivileged input.qrt_s32_t extension(void *args) { qrt_uptr_t param = ((qrt_uptr_t *)args)[0u]; return (qrt_s32_t)param; }
Error numbers:
EPERM if the caller is not running with privileged access.
EINVAL if
syscalloridis NULL.ENOSPC if every extension slot is already occupied.
- Parameters:
syscall – Pointer to the System Call Extension.
id – Pointer to store the assigned function ID.
- Returns:
0 if success, error number otherwise. The example below registers an extension from the privileged startup thread; an unprivileged worker then invokes it with an index in the parameter slot.
#define DEVICE_BASE (0x40010000u) #define DEVICE_REGS (4u) static qrt_u32_t read_id; static qrt_s32_t value; qrt_s32_t read_extension(void *args) { qrt_uptr_t index = ((qrt_uptr_t *)args)[0u]; if (index >= DEVICE_REGS) { return -1; } return ((volatile qrt_s32_t *)DEVICE_BASE)[index]; } void *unprivileged_worker(void *arg) { (void)arg; value = qrt_syscall_invoke(read_id, (void *)2u); return NULL; } void *startup_thread(void *arg) { pthread_t worker_id; (void)arg; if (qrt_syscall_register(read_extension, &read_id) == 0) { (void)pthread_create(&worker_id, NULL, unprivileged_worker, NULL); } return NULL; }
-
qrt_s32_t qrt_syscall_invoke(qrt_u32_t f, void *param)
Invoke an extension previously installed with qrt_syscall_register through the kernel’s syscall path.
The extension runs in privileged context.
paramtravels unchanged in the first argument register of the system call; it may be an address or an integer cast to a pointer, and the kernel never dereferences it. The extension does not receiveparamitself but a pointer to the register frame that holds it – see qrt_syscall_register for how an extension reads it. The return value is whatever the extension returns.See also
qrt_syscall_register for the use of System Call Extensions.
- Parameters:
f – Function ID returned by qrt_syscall_register.
param – Parameter for the extension: an address, or an integer cast to a pointer. May be NULL.
- Returns:
Return value from the extension, or ENOSYS if
fnames no registered extension (a debug build asserts instead).
-
qrt_s32_t qrt_perf_read(char *buf, qrt_u32_t size)
Format the worst-case execution time (WCET) results into a caller-provided buffer.
Provided only when QRT_CFG_PERF_ENABLE is 1.
One
"<service> <cycles>\n"line per exercised call, thencontext_switch,irq_mask(worst-case interrupt masking) andsystimer_handling(worst-case System Timer handling) lines in the same format; NUL-terminated whensizeis not 0; stops when the table is exhausted orsizeis reached.- Parameters:
buf – Destination buffer, in the caller’s own memory.
size – Buffer size in bytes.
- Returns:
Number of bytes written (excluding the terminating NUL).
void perf_report(void) { static char report[1024]; (void)qrt_perf_read(report, (qrt_u32_t)sizeof(report)); (void)printf("%s", report); }
-
qrt_s32_t qrt_kernel_boot(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *arg), void *arg)
Bring the kernel up and hand control to a first thread.
Initializes the kernel and starts scheduling. On success the calling context becomes the main thread and runs
start_routine; the function does not return.Error numbers:
ENOMEM Not enough memory to start the kernel, increase the kernel heap size QRT_CFG_KERNEL_HEAP_SIZE or increase the thread stack pool size QRT_CFG_STACK_POOL_SIZE.
EINVAL if System Timer is not configured.
EINVAL if the MPU is enabled and a memory region defined in the linker script is not aligned to its size (ARMv6 and ARMv7) or to 32 bytes (ARMv8).
EINVAL if
start_routineis NULL or the thread attributes inattrare invalid.EIO if System Timer is stuck (its count does not advance).
EBUSY if the kernel is already running.
Note
This function must be called after all necessary system initialization is complete. Once the kernel is started, further modifications to system initialization should not be attempted.
#include <pthread.h> #include "bsp.h" #define TIMER_MAX_PERIOD (0xFFFFFFu) #define TIMER_HZ (48000000) void *worker(void *arg); void *startup_thread(void *arg) { pthread_t worker_id; (void)arg; (void)pthread_create(&worker_id, NULL, worker, NULL); return NULL; } int main(void) { bsp_init(); if (qrt_systimer_configure(bsp_systickreload, bsp_systickgetcount, TIMER_MAX_PERIOD, TIMER_HZ, BSP_SYSTICK_IRQN) != 0) { return -1; } return qrt_kernel_boot(NULL, NULL, startup_thread, NULL); }
- Parameters:
thread – Pointer to the thread handle. NULL if not needed.
attr – Pointer to the thread attributes. NULL for default attributes.
start_routine – Pointer to the function to be executed by the thread.
arg – Argument to be passed to the thread function.
- Returns:
0 if success, error number otherwise.
-
qrt_s32_t qrt_kernel_idlehookregister(void (*hook_function)(void))
Install (or clear) the function that runs whenever the kernel has no other runnable thread.
The hook runs in the idle thread whenever no other thread is runnable; when idle sleep is enabled (QRT_CFG_IDLE_SLEEP_ENABLE / QRT_CFG_IDLE_DEEP_SLEEP_ENABLE) the CPU enters sleep only after the hook returns. Pass NULL to remove the currently installed hook. Requires the caller to be privileged when the MPU is enabled.
Note
The idle hook function is called from privileged context which exposes an attack vector if untrusted code is executed. It is users responsibility to ensure the hook function does not compromise system security.
Note
System Calls from idle hook lead to undefined behavior.
- Parameters:
hook_function – Pointer to the idle hook function. NULL pointer to unregister the idle hook.
- Returns:
Returns 0 on success, EPERM if called from unprivileged thread when MPU is enabled, or ENOSYS if QRT_CFG_KERNEL_IDLE_HOOK_REGISTER_ENABLE is 0.
-
qrt_s32_t qrt_systimer_configure(void (*reload_ptr)(qrt_u64_t period), qrt_u64_t (*get_count_ptr)(void), qrt_u64_t max_period, qrt_s32_t frequency_hz, qrt_s32_t irqn)
Bind the kernel’s SysTimer to a hardware timer described by the supplied accessors. Must be called before qrt_kernel_boot.
The kernel uses
reload_ptrto program the next deadline andget_count_ptrto sample the current count. The suppliedirqnis configured and enabled in the interrupt controller.Error numbers:
- Parameters:
reload_ptr – Pointer to the function to reload the timer.
get_count_ptr – Pointer to the function to get the current timer count.
max_period – Maximum timer period in ticks.
frequency_hz – Timer frequency in Hz.
irqn – Interrupt request number for the timer.
- Returns:
Returns 0 on success, or an error number on failure.
-
qrt_s32_t qrt_systimer_getmonotonic(qrt_s64_t *ticks)
Sample the kernel’s monotonic tick counter.
The reading is the SysTimer’s accumulated tick count since the timer was configured at boot. It is unaffected by clock_settime(). A call made before qrt_kernel_boot has started the kernel fails with EINVAL and leaves
ticksunchanged. When QRT_CFG_DEFER_ENABLE is enabled the call may also be made from a deferred function or a timer callback (see qrt_defer_call()).- Parameters:
ticks – Pointer to store the current monotonic tick count.
- Returns:
0 on success, EINVAL if the kernel has not been started with qrt_kernel_boot or the System Timer has not been configured with qrt_systimer_configure, or ENOSYS if QRT_CFG_SYSTIMER_GET_MONOTONIC_ENABLE is 0.
-
void qrt_systimer_handler(void)
Service the SysTimer deadline interrupt and hand control to the scheduler.
QRT schedules to event deadlines rather than fixed periodic ticks: the SysTimer is armed to fire when the next scheduling decision is due. The application’s hardware timer ISR must invoke this handler when that interrupt fires; it reprograms the timer for the following deadline. Calling it from any other context is undefined behavior.
void SysTick_Handler(void) { qrt_systimer_handler(); }
-
qrt_s32_t qrt_defer_call(void (*deferred_function)(qrt_u32_t parameter), qrt_u32_t parameter)
Queue
deferred_functionto run in kernel context at the next dispatch opportunity, typically right after the ISR returns.The canonical way to escape from an ISR before issuing any kernel call: hardware interrupt service routines may not invoke kernel services directly. The deferred function does not run in a thread, no thread runs until it returns, and it must not block. It may call only these kernel services:
mq_send() and mq_timedsend(), on a descriptor with O_NONBLOCK set.
Deferred calls require QRT_CFG_DEFER_ENABLE, and QRT_CFG_DEFER_LIMIT sets how many calls the buffer holds. A timer callback (see timer_create()) runs in the same context: it may call the same services, and only when QRT_CFG_DEFER_ENABLE is enabled.
Error numbers:
ENOSPC Deferred call buffer is full.
EINVAL Invalid pointer to deferred function.
ENOSYS Deferred calls are disabled (QRT_CFG_DEFER_ENABLE is 0).
- Parameters:
deferred_function – Pointer to the deferred function.
parameter – Parameter to the deferred function.
- Returns:
0 on success, error number otherwise.
static sem_t event_sem; static qrt_u32_t events; void event_deferred(qrt_u32_t param) { (void)param; (void)sem_post(&event_sem); } void Device_IRQHandler(void) { (void)qrt_defer_call(event_deferred, 0u); } void *event_thread(void *arg) { (void)arg; (void)sem_init(&event_sem, 0, 0u); for (;;) { (void)sem_wait(&event_sem); events++; } return NULL; }