universalisos/docs/rtos-audit-chibios-rtthread-contiki-rodos.md
Fábio Coutada 47f5885da6 docs: add RTOS audit, bibliography, PikeOS audit
- RTOS audit: ChibiOS, RT-Thread, Contiki, RODOS comparison
- PikeOS x86 audit report
- Bibliography for safety-critical hypervisor research
2026-07-15 15:32:04 +01:00

784 lines
31 KiB
Markdown

# Deep Audit: ChibiOS, RT-Thread, Contiki, RODOS
## Source locations
- ChibiOS: `/home/fabiorafaelcoutada/portugalfuturista/rtos_ref/ChibiOS/`
- RT-Thread: `/home/fabiorafaelcoutada/portugalfuturista/rtos_ref/rt-thread/`
- Contiki: `/home/fabiorafaelcoutada/portugalfuturista/rtos_ref/contiki/`
- RODOS: `/home/fabiorafaelcoutada/portugalfuturista/rtos_ref/rodos/`
---
# 1. ChibiOS/RT v8.0.0
## 1.1 Architecture Support
**Port layers** in `os/common/ports/`:
- ARM, ARM-common, ARMv6-M, ARMv7-M, ARMv7-M-ALT, ARMv7-R, ARMv8-M-ML, ARMv8-M-ML-ALT, ARMv8-M-ML-TZ, ARMvx-M-SB
- AVR, e200 (PowerPC NXP), SIMIA32, SIMX86_64
**HAL ports** in `os/hal/ports/`:
- ADUCM (Analog Devices), AVR, LPC (NXP), MAX32, RP (Raspberry Pi RP2040), SPC5 (ST PowerPC), STM32 (C0/F0/F1/F3/F4/F7/G0/G4/H5/H7/L0/L1/L4/L5/MP1/U0/U3/U5/WB/WL), simulator
**Demo BSPs** in `demos/`:
- ADUCM, AVR (Arduino UNO/MEGA/MINI/NANO/Leonardo, DigiSpark ATTiny, MT-DB-X4), LPC21xx, MAX32, RP, SPC5, STM32, various
**Key takeaway**: Broad ARM Cortex-M coverage (M0/M0+/M3/M4/M7/M23/M33/M55/M85 with TrustZone), AVR, PPC e200, simulator (x86/x86_64).
## 1.2 Memory Model
**No MMU required.** Flat memory model with static allocation as primary pattern.
File: `os/rt/include/chmem.h`
- **Static working areas**: `THD_WORKING_AREA(s, n)` allocates thread stack + `thread_t` struct in BSS
- **NUMA memory classes**: `CH_MEM_GLOBAL_BSS`, `CH_MEM_LOCAL_BSS(c)`, `CH_MEM_PRIVATE_BSS(c)`, plus coherent variants for SMP cache management
- **No heap allocator in kernel**: ChibiOS relies on statically allocated pools. Dynamic allocation is optional via `oslib/` (heap, mempool, mailbox abstractions)
- Stack guard via MPU (`PORT_ENABLE_GUARD_PAGES` on ARMv7-M)
**Design pattern**: Pre-allocated working areas, no `malloc()` in kernel. Thread stacks are compile-time sized arrays.
## 1.3 Kernel Primitives
### Threads (`os/rt/include/chthreads.h`, `os/rt/src/chthreads.c`)
```c
typedef void (*tfunc_t)(void *p);
// Static creation
thread_t *chThdCreateStatic(void *wsp, size_t size, tprio_t prio, tfunc_t tp, void *arg);
thread_t *chThdCreateI(...); // from ISR context
// Dynamic creation (requires CH_CFG_USE_DYNAMIC)
thread_t *chThdCreate(...);
// Control
void chThdExit(msg_t msg);
void chThdTerminate(thread_t *tp);
msg_t chThdWait(thread_t *tp); // join
void chThdSleep(sysinterval_t ticks);
void chThdSleepUntil(systime_t time);
void chThdYield(void);
void chThdSuspendS(thread_t *tpp);
void chThdResumeI(thread_t *tp, msg_t msg);
```
**Thread states** (16 states, `chschd.h`):
```
READY, CURRENT, WTSTART, SUSPENDED, QUEUED, WTSEM, WTMTX,
WTCOND, SLEEPING, WTEXIT, WTOREVT, WTANDEVT, SNDMSGQ, SNDMSG, WTMSG, FINAL
```
### Scheduler (`os/rt/include/chschd.h`, `os/rt/src/chschd.c`)
```c
void chSchReadyI(thread_t *tp); // insert in ready list
void chSchGoSleepS(tstate_t newstate); // sleep
msg_t chSchGoSleepTimeoutS(tstate_t, sysinterval_t);
void chSchWakeupS(thread_t *ntp, msg_t msg);
void chSchRescheduleS(void);
void chSchDoPreemption(void);
void chSchDoYieldS(void);
thread_t *chSchSelectFirst(void);
```
**Priority-based preemptive** ready list. Priorities 1-255 (IDLE=1, LOW=2, NORMAL=128, HIGH=255). `ch_sch_prio_insert()` walks sorted doubly-linked list. Supports `CH_CFG_TIME_QUANTUM` for round-robin among equal-priority threads.
### IPC Primitives
**Semaphores** (`chsem.h`):
```c
void chSemObjectInit(semaphore_t *sp, cnt_t n);
msg_t chSemWait(semaphore_t *sp);
msg_t chSemWaitTimeout(semaphore_t *sp, sysinterval_t timeout);
void chSemSignal(semaphore_t *sp);
void chSemSignalI(semaphore_t *sp); // ISR-safe
msg_t chSemSignalWait(semaphore_t *sps, semaphore_t *spw); // atomic signal+wait
```
**Mutexes** (`chmtx.h`) with **priority inheritance**:
```c
void chMtxLock(mutex_t *mp);
bool chMtxTryLock(mutex_t *mp);
void chMtxUnlock(mutex_t *mp);
void chMtxUnlockAll(void); // unlock all mutexes held by current thread
```
Mutex structure has `owner`, `next` (linked list on thread), optional `cnt` for recursive.
**Condition Variables** (`chcond.h`):
```c
void chCondSignal(condition_variable_t *cp);
void chCondBroadcast(condition_variable_t *cp);
msg_t chCondWait(condition_variable_t *cp);
```
**Events** (`chevents.h`) - event flags model:
```c
void chEvtRegisterMaskWithFlags(event_source_t *esp, event_listener_t *elp, eventmask_t events, eventflags_t wflags);
void chEvtSignal(thread_t *tp, eventmask_t events);
eventmask_t chEvtWaitAny(eventmask_t events);
eventmask_t chEvtWaitAll(eventmask_t events);
void chEvtDispatch(const evhandler_t *handlers, eventmask_t events);
```
Event listeners link to event sources. Uses bitmask model (eventmask_t + eventflags_t).
**Synchronous Messages** (`chmsg.h`) - rendezvous-style:
```c
msg_t chMsgSend(thread_t *tp, msg_t msg); // blocking send, returns reply
thread_t *chMsgWait(void); // blocking receive
void chMsgRelease(thread_t *tp, msg_t msg); // reply
```
### ChibiOS/NIL (ultra-lightweight variant, `os/nil/`)
- Only 4 source files: `ch.c`, `chevt.c`, `chmsg.c`, `chsem.c`
- Cooperative only, no preemption
- Fixed number of threads (compile-time)
- Minimal states: WTSTART, READY, SLEEPING, SUSPENDED, WTEXIT, WTQUEUE, WTOREVT, WTANDEVT, SNDMSGQ, SNDMSG, WTMSG
- ~1KB footprint, ideal for 8-bit MCUs
## 1.4 API Surface
Single include: `#include "ch.h"` → pulls all kernel headers:
```
chearly.h → chrfcu.h → chdebug.h → chtime.h → chalign.h → chtrace.h →
chport.h → chsafety.h → chlists.h → chtmm → chstats.h → chobjects.h →
chmem.h → chsys.h → chinstances.h → chvt.h → chschd.h → chthreads.h →
chregistry.h → chsem.h → chmtx.h → chcond.h → chevents.h → chmsg.h →
chlib.h (OSLIB) → chdynamic.h
```
**Locking model**: Three-class API with `S` suffix (caller must hold system lock), `I` suffix (caller must be in ISR), no suffix (API-level, acquires lock internally):
```c
chSysLock(); // enter critical section
chSysUnlock(); // exit critical
```
## 1.5 Hardware Abstraction
Port layer contract (`os/rt/include/chport.h`) requires every port to define:
```c
PORT_COMPILER_NAME, PORT_IDLE_THREAD_STACK_SIZE, PORT_INT_REQUIRED_STACK,
PORT_SUPPORTS_RT, PORT_NATURAL_ALIGN, PORT_STACK_ALIGN, PORT_WORKING_AREA_ALIGN,
PORT_ARCHITECTURE_NAME, PORT_CORE_VARIANT_NAME, PORT_INFO,
PORT_IRQ_IS_VALID_PRIORITY, PORT_IRQ_IS_VALID_KERNEL_PRIORITY,
PORT_SETUP_CONTEXT, PORT_WA_SIZE, PORT_IRQ_PROLOGUE, PORT_IRQ_EPILOGUE,
PORT_IRQ_HANDLER, PORT_FAST_IRQ_HANDLER
```
HAL layer (`os/hal/`): Full driver abstraction for ADC, CAN, DAC, EXT, GPT, I2C, ICU, MAC, PAL (GPIO), PWM, RTC, SDC, SERIAL, SIO, SPI, UART, USB, WDG. Each has a `hal_xxx_lld.h` low-level driver per port.
## 1.6 Tick/Timer Infrastructure
File: `os/rt/include/chvt.h`, `os/rt/src/chvt.c`
**Two modes**:
1. **Tick mode** (`CH_CFG_ST_TIMEDELTA == 0`): Regular SysTick interrupt increments `currcore->vtlist.systime`. Virtual timers stored in delta list.
2. **Tickless mode** (`CH_CFG_ST_TIMEDELTA > 0`): Hardware timer programmed for exact next wakeup. `port_timer_get_time()` returns current time.
```c
void chVTDoSetI(virtual_timer_t *vtp, sysinterval_t delay, vtfunc_t vtfunc, void *par);
void chVTDoSetContinuousI(virtual_timer_t *vtp, sysinterval_t delay, vtfunc_t vtfunc, void *par);
void chVTDoResetI(virtual_timer_t *vtp);
void chVTDoTickI(void); // called from tick ISR or timer ISR
systime_t chVTGetSystemTimeX(void);
```
Virtual timer is a delta-list node with callback. Supports one-shot and continuous (auto-reload).
## 1.7 Cooperative vs Preemptive
**ChibiOS/RT**: Fully **preemptive** by default. Priority-based preemption. Optional time quantum for round-robin at same priority (`CH_CFG_TIME_QUANTUM > 0`). No cooperative-only mode.
**ChibiOS/NIL**: **Cooperative only**. Threads yield explicitly. No preemption. Ultra-minimal for deeply constrained targets.
---
# 2. RT-Thread v5.3.0
## 2.1 Architecture Support
**libcpu/** supports 21 architecture families:
- aarch64, arc, arm (23 sub-ports: am335x, arm926, armv6, AT91SAM7S/X, cortex-a/m0/m23/m3/m33/m4/m7/m85/r4/r52, dm36x, lpc214x/lpc24xx, s3c24x0/s3c44b0, sep4020, zynqmp-r5)
- avr32, blackfin, c-sky, ia32, m16c, mips, nios, ppc, risc-v, rx, sim, sparc-v8, ti-dsp, unicore32, v850, xilinx
**BSP/**: 107 board support packages including STM32 (full range), GD32, Infineon, Renesas, NXP, Allwinner, Raspberry Pi, QEMU (aarch64, riscv, virt64), RISC-V (hifive1, rv32m1_vega), x86, simulator, and many Chinese MCU vendors.
## 2.2 Memory Model
**No MMU required.** Three memory allocation strategies (compile-time selectable):
1. **Small Memory** (`src/mem.c`, `RT_USING_SMALL_MEM`): First-fit allocator from contiguous heap. `rt_smem_init()` takes a begin address + size. Items linked via `next`/`prev` offsets. Coalescing on free. O(n) worst-case.
2. **SLAB allocator** (`src/slab.c`, `RT_USING_SLAB`): Derived from DragonFly BSD. 72 zones, chunk sizes 8B to 16KB. Page-based backing. O(1) alloc/free for common sizes.
3. **Memory heap** (`src/memheap.c`, `RT_USING_MEMHEAP`): Multiple disjoint memory regions managed as a single logical heap. Good for systems with non-contiguous RAM (e.g., SRAM + external SDRAM).
4. **Memory pool** (`src/mempool.c`): Fixed-size block pool, O(1) alloc/free.
**Key API**:
```c
void *rt_malloc(rt_size_t nbytes);
void rt_free(void *ptr);
void *rt_realloc(void *ptr, rt_size_t nbytes);
void *rt_calloc(rt_size_t count, rt_size_t size);
rt_smem_t rt_smem_init(const char *name, void *begin_addr, rt_size_t size);
```
## 2.3 Kernel Primitives
### Threads (`src/thread.c`, `include/rtdef.h`)
```c
// Static creation
rt_err_t rt_thread_init(struct rt_thread *thread, const char *name,
void (*entry)(void *parameter), void *parameter,
void *stack_start, rt_uint32_t stack_size, rt_uint8_t priority, rt_uint32_t tick);
// Dynamic creation
rt_thread_t rt_thread_create(const char *name, void (*entry)(void *parameter),
void *parameter, rt_uint32_t stack_size, rt_uint8_t priority, rt_uint32_t tick);
rt_err_t rt_thread_startup(rt_thread_t thread);
rt_err_t rt_thread_delay(rt_tick_t tick);
rt_err_t rt_thread_yield(void);
rt_err_t rt_thread_suspend(rt_thread_t thread);
rt_err_t rt_thread_resume(rt_thread_t thread);
rt_err_t rt_thread_control(rt_thread_t thread, int cmd, void *arg);
rt_thread_t rt_thread_self(void);
```
**Thread control block** (`rtdef.h:852`):
```c
struct rt_thread {
struct rt_object parent; // inherit from kernel object
void *sp, *entry, *parameter, *stack_addr;
rt_uint32_t stack_size;
rt_err_t error;
RT_SCHED_THREAD_CTX; // scheduler-specific context
struct rt_timer thread_timer; // built-in thread timer
rt_thread_cleanup_t cleanup;
rt_list_t taken_object_list; // mutex tracking for priority inheritance
rt_object_t pending_object;
rt_uint32_t event_set;
rt_uint8_t event_info;
// ... signals, pthreads, LWP fields
};
```
### Scheduler (`src/scheduler_comm.c`, `src/scheduler_up.c`, `src/scheduler_mp.c`)
**Two scheduler variants**:
1. **UP (uniprocessor)**: Bit-map priority scheduler. `priority_group` + `ready_table[32]` for O(1) highest-priority lookup. Up to 256 priority levels.
2. **MP (multiprocessor/SMP)**: Per-CPU ready queues, IPI-based preemption, CPU affinity binding.
```c
void rt_sched_thread_init_ctx(struct rt_thread *thread, rt_uint32_t tick, rt_uint8_t priority);
rt_err_t rt_sched_thread_ready(struct rt_thread *thread);
```
### IPC (`src/ipc.c`)
**Semaphores**:
```c
rt_err_t rt_sem_init(rt_sem_t sem, const char *name, rt_uint32_t value, rt_uint8_t flag);
rt_err_t rt_sem_take(rt_sem_t sem, rt_int32_t timeout);
rt_err_t rt_sem_release(rt_sem_t sem);
```
**Mutexes** with priority inheritance + priority ceiling:
```c
rt_err_t rt_mutex_init(rt_mutex_t mutex, const char *name, rt_uint8_t flag);
rt_err_t rt_mutex_take(rt_mutex_t mutex, rt_int32_t timeout);
rt_err_t rt_mutex_release(rt_mutex_t mutex);
```
**Events** (32-bit bitmask):
```c
rt_err_t rt_event_init(rt_event_t event, const char *name, rt_uint8_t flag);
rt_err_t rt_event_recv(rt_event_t event, rt_uint32_t set, rt_uint8_t option, rt_int32_t timeout, rt_uint32_t *recved);
rt_err_t rt_event_send(rt_event_t event, rt_uint32_t set);
```
**Mailbox** (fixed-size message slots):
```c
rt_err_t rt_mb_init(rt_mailbox_t mb, const char *name, void *msgpool, rt_size_t size, rt_uint8_t flag);
rt_err_t rt_mb_send(rt_mailbox_t mb, rt_ubase_t value);
rt_err_t rt_mb_recv(rt_mailbox_t mb, rt_ubase_t *value, rt_int32_t timeout);
```
**Message Queue** (variable-size messages):
```c
rt_err_t rt_mq_init(rt_mq_t mq, const char *name, void *msgpool, rt_size_t msg_size, rt_size_t pool_size, rt_uint8_t flag);
rt_err_t rt_mq_send(rt_mq_t mq, const void *buffer, rt_size_t size);
rt_err_t rt_mq_recv(rt_mq_t mq, void *buffer, rt_size_t size, rt_int32_t timeout);
```
IPC flags: `RT_IPC_FLAG_PRIO` (priority-ordered waiters) or `RT_IPC_FLAG_FIFO`.
## 2.4 API Surface
Single include: `#include <rtthread.h>``rtdef.h`, `rtservice.h`, `rtm.h`, `rtatomic.h`, `rtklibc.h`
**Object system**: All kernel objects inherit from `struct rt_object` with name, type, flag, list node. Enables runtime object discovery via `rt_object_find()`.
**Initialization export macros** for component init ordering:
```c
INIT_BOARD_EXPORT(fn) // level "1"
INIT_DEVICE_EXPORT(fn) // level "3"
INIT_COMPONENT_EXPORT(fn)// level "4"
INIT_APP_EXPORT(fn) // level "6"
```
**Hook system**: Per-operation hooks (`rt_thread_suspend_sethook`, `rt_timer_enter_sethook`, etc.) plus hook lists for multiple subscribers.
## 2.5 Hardware Abstraction
**libcpu/** per-arch provides:
```c
rt_uint8_t *rt_hw_stack_init(void *entry, void *parameter, rt_uint8_t *stack_addr, void *exit);
void rt_hw_context_switch(rt_ubase_t from, rt_ubase_t to);
void rt_hw_context_switch_interrupt(rt_ubase_t from, rt_ubase_t to, rt_thread_t from_thread, rt_thread_t to_thread);
rt_base_t rt_hw_interrupt_disable(void);
void rt_hw_interrupt_enable(rt_base_t level);
void rt_hw_cpu_reset(void);
void rt_hw_cpu_shutdown(void);
```
**BSP/** per-board provides system clock, peripheral init, linker script, console.
**Device framework** (`include/rtdef.h`): `struct rt_device` with `rt_device_ops` (init, open, close, read, write, control).
## 2.6 Tick/Timer Infrastructure
File: `src/clock.c`, `src/timer.c`
```c
rt_tick_t rt_tick_get(void);
void rt_tick_increase(void); // called from SysTick ISR
void rt_tick_increase_tick(rt_tick_t tick); // multi-tick advance
void rt_timer_init(rt_timer_t timer, const char *name,
void (*timeout)(void *parameter), void *parameter,
rt_tick_t time, rt_uint8_t flag);
rt_err_t rt_timer_start(rt_timer_t timer);
rt_err_t rt_timer_stop(rt_timer_t timer);
rt_err_t rt_timer_control(rt_timer_t timer, int cmd, void *arg);
```
Timer flags: `RT_TIMER_FLAG_ONE_SHOT` / `RT_TIMER_FLAG_PERIODIC`, `RT_TIMER_FLAG_HARD_TIMER` (callback in ISR) / `RT_TIMER_FLAG_SOFT_TIMER` (callback in timer thread). Uses **skip list** for O(log n) timer insertion (`RT_TIMER_SKIP_LIST_LEVEL`).
## 2.7 Cooperative vs Preemptive
**Fully preemptive** by default. Priority-based preemption with optional time-slice round-robin (`tick` parameter per thread). SMP variant adds per-CPU scheduling with IPI-triggered rescheduling.
No explicit cooperative mode, but a thread can yield voluntarily with `rt_thread_yield()`.
---
# 3. Contiki OS (v3.x)
## 3.1 Architecture Support
**Platform directory** (`platform/`) with 33 platforms:
- AVR: atmega128rfa1, raven, ravenlcd, ravenusb, rcb, rss2, zigbit
- ARM: cc2538dk, nrf52dk, openmote-cc2538, srf06-cc26xx, stm32nucleo-spirit1, stm32test, zoul
- MSP430: exp5438, sky, wismote, z1
- x86: native (Linux host), win32, galileo, minimal-net
- Simulators: cooja, cooja-ip64
- Other: cc2530dk, econotag, ev-aducrf101mkxz, jn516x, mbxxx, micaz, seedeye
**No libcpu separation** — each platform provides its own clock, rtimer, and radio drivers directly.
## 3.2 Memory Model
**No MMU. No dynamic memory allocation in the kernel.**
Contiki uses **no heap at all** by default. Everything is statically allocated:
- Process structures are compile-time macros
- Event queue is a fixed-size array: `static struct event_data events[PROCESS_CONF_NUMEVENTS]` (default 32)
- Protothread state is a single `char` in the process struct (local continuation)
- No thread stacks — protothreads share the main stack
**This is the most memory-efficient model of all four RTOSes.** A protothread is literally a single byte of state.
## 3.3 Kernel Primitives
### Protothreads (`core/sys/pt.h`)
Protothreads are **stackless threads** implemented as C macros using Duff's device (local continuations):
```c
struct pt { lc_t lc; }; // lc_t is typically a char
PT_THREAD(my_thread(struct pt *pt, process_event_t ev, process_data_t data));
#define PT_BEGIN(pt) // start
#define PT_END(pt) // end
#define PT_WAIT_UNTIL(pt, condition) // block until condition
#define PT_WAIT_WHILE(pt, condition) // block while condition
#define PT_YIELD(pt) // yield to scheduler
#define PT_SPAWN(pt, child, thread) // spawn child protothread
```
**No per-thread stack.** Each protothread is a function that returns `PT_WAITING`, `PT_YIELDED`, `PT_EXITED`, or `PT_ENDED`. The continuation point is stored in `lc_t` (typically 1 byte using GCC computed goto labels, or 2 bytes using switch-based Duff's device).
### Processes (`core/sys/process.h`, `core/sys/process.c`)
```c
PROCESS_THREAD(name, ev, data); // declare process
PROCESS_NAME(name); // get process name
void process_start(struct process *p, process_data_t data);
void process_exit(struct process *p);
int process_post(struct process *p, process_event_t ev, process_data_t data);
void process_poll(struct process *p);
process_event_t process_alloc_event(void);
```
Each process wraps a protothread:
```c
struct process {
struct process *next;
const char *name;
PT_THREAD((*thread)(struct pt *, process_event_t, process_data_t));
struct pt pt;
unsigned char state, needspoll;
};
```
### Event System
**Synchronous event dispatch** via `process_run()`:
```c
// In main loop:
while(1) {
do {} while(process_run() > 0); // dispatch events
// low-power sleep if no events
}
```
Events are posted to a **fixed-size circular queue** (`events[PROCESS_CONF_NUMEVENTS]`). Pre-defined events: `PROCESS_EVENT_INIT`, `PROCESS_EVENT_POLL`, `PROCESS_EVENT_EXIT`, `PROCESS_EVENT_TIMER`, `PROCESS_EVENT_CONTINUE`, etc.
### No mutexes, semaphores, or message queues
Contiki has **none of these**. Synchronization is entirely event-driven + protothread blocking conditions. `core/sys/pt-sem.h` provides a minimal counting semaphore for protothreads.
## 3.4 API Surface
Main includes: `contiki.h`, `contiki-net.h`, `contiki-lib.h`
```c
// Process macros
PROCESS_THREAD(), PROCESS_BEGIN(), PROCESS_END(), PROCESS_YIELD()
PROCESS_WAIT_EVENT(), PROCESS_WAIT_EVENT_UNTIL()
PROCESS_POLL_AND_EXIT()
// Timer APIs
timer_set(), timer_reset(), timer_expired()
etimer_set(), etimer_reset(), etimer_expired()
ctimer_set(), ctimer_reset(), ctimer_expired()
stimer_set(), stimer_expired()
rtimer_set()
// Event APIs
process_post(), process_poll()
```
## 3.5 Hardware Abstraction
Each platform provides:
- `clock.c` / `clock.h`: System tick
- `rtimer-arch.c`: Real-time timer
- `*contiki-conf.h`: Platform configuration
- Radio driver (for networking)
No unified HAL layer — each platform is self-contained.
## 3.6 Tick/Timer Infrastructure
**Four timer layers** (coexisting):
1. **timer** (`core/sys/timer.h`): Simple interval timer, checked by polling `timer_expired()`. Uses `clock_time_t` (typically 16-bit).
2. **etimer** (`core/sys/etimer.h`): Event timer — posts `PROCESS_EVENT_TIMER` to the owning process when expired. Linked list managed by `etimer_request_poll()`.
3. **ctimer** (`core/sys/ctimer.h`): Callback timer — calls a function pointer on expiry.
4. **rtimer** (`core/sys/rtimer.h`): Real-time timer with **microsecond precision**, runs from ISR context. Used for time-critical radio operations.
```c
// Clock layer
void clock_init(void);
clock_time_t clock_time(void); // typically 32 ticks/sec
unsigned long clock_seconds(void);
#define CLOCK_SECOND (clock_time_t)32
// rtimer
void rtimer_set(struct rtimer *rt, rtimer_clock_t time, rtimer_clock_t duration,
rtimer_callback_t func, void *ptr);
```
## 3.7 Cooperative vs Preemptive
**Purely cooperative.** Protothreads yield explicitly via `PT_YIELD()`, `PT_WAIT_UNTIL()`, etc. No preemption. The main loop runs `process_run()` which dispatches one event at a time.
The only "preemption" is ISR-level rtimer callbacks, which run in interrupt context and must not block.
---
# 4. RODOS (Realtime Onboard Dependable Operating System) v2.x
## 4.1 Architecture Support
**Bare-metal ports** (`src/bare-metal/`):
- **Cortex-M** (`src/bare-metal-cortex-m/`): Generic Cortex-M port with PendSV-based context switch
- **STM32F4**: STM32F4xx (F407, F411 discovery boards)
- **STM32H7**: STM32H7xx (H723, H735, H745, H753 — Nucleo, Discovery, custom boards)
- **STM32L4**: STM32L431, L432, L475, L496 (Nucleo L432KC, L496ZG, Discovery L475)
- **STM32WB**: STM32WB55 Nucleo (BLE-capable)
- **EFR32FG1P**: Silicon Labs EFR32 Flex Gecko (Thunderboard)
- **VA41620**: Vorago VA41620 (radiation-hardened Cortex-M4)
- **SF2**: Microsemi SmartFusion2 (Cortex-M3 + FPGA)
- **Raspberry Pi 3**: Bare-metal AArch64
- **Linux x86**: Linux-hosted with makecontext/setcontext
- **Template**: Porting template
**POSIX simulation** (`src/on-posix/`, `src/on-posix-mac/`): Run as Linux/macOS process using POSIX threads.
## 4.2 Memory Model
**No MMU required.** Fully static memory model in C++.
- **Threads** use either static stacks (via template) or dynamic `new` (deprecated):
```cpp
template <size_t STACK_SIZE>
Thread(char (&stack)[STACK_SIZE], const char* name, const int32_t priority);
// deprecated: Thread(const char* name, int32_t priority, size_t stackSize);
```
- **StaticThread<STACK_SIZE>** is the recommended pattern (compile-time sized stack array).
- No heap allocator in kernel. All kernel objects (`Thread`, `Semaphore`, `TimeEvent`, `Topic`, `Subscriber`) are statically constructed C++ objects created before `main()`.
- Stack grows downward. Sentinel value `0xdeaddead` placed at stack base for overflow detection.
## 4.3 Kernel Primitives
### Threads (`api/thread.h`, `src/independent/thread.cpp`)
C++ class with virtual `run()` method:
```cpp
class Thread : public ListElement {
public:
Thread(const char* name, int32_t priority, size_t stackSize);
template <size_t STACK_SIZE>
Thread(char (&stack)[STACK_SIZE], const char* name, int32_t priority);
virtual void run() = 0; // user implements
virtual void init() {} // called before run()
static bool suspendCallerUntil(int64_t reactivationTime = END_OF_TIME, void* signaler = 0);
void suspendUntilNextBeat();
void setPeriodicBeat(int64_t begin, int64_t period);
void resume();
void resumeAndYield();
static void yield();
static Thread* getCurrentThread();
static Thread* findNextToRun(int64_t& selectedEarliestSuspendedUntil);
static Thread* findNextWaitingFor(void* signaler);
};
```
Thread state tracked via:
```cpp
Atomic<long*> context{nullptr}; // saved stack pointer
Atomic<int32_t> priority{};
Atomic<int64_t> suspendedUntil{0}; // wake time
Atomic<void*> waitingFor{nullptr}; // synchronization target
Atomic<uint64_t> lastActivation{0};
```
### Scheduler
**Priority-based preemptive** scheduler using PendSV on Cortex-M:
- `Thread::findNextToRun()` iterates all threads, selects highest-priority ready thread
- Context switch via PendSV interrupt: save R4-R11 + EXC_RETURN to PSP, call `schedulerWrapper()`, restore next thread's context
- SVC handler for first thread start (idle thread)
- Time-driven: scheduler triggered by `TimeEvent::propagate()` in SysTick
```cpp
// Context switch chain (Cortex-M):
__asmSaveContextAndCallScheduler() SCB->ICSR |= PENDSVSET
PendSV_Handler: save regs schedulerWrapper() restore next thread regs
```
### Semaphore (`api/rodos-semaphore.h`)
**Mutex semaphore** with priority ceiling:
```cpp
class Semaphore {
Atomic<Thread*> owner;
Atomic<int32_t> ownerEnterCnt; // reentrant lock count
Atomic<int32_t> ownerPriority;
public:
void enter(); // blocking lock
void leave(); // unlock + resume highest-priority waiter
};
// RAII guard
class ScopeProtector { ... };
#define PROTECT_IN_SCOPE(_sema)
```
### Barrier (`api/barrier.h`)
```cpp
class Barrier {
Thread* volatile owner;
public:
bool waitForSignal(bool condition = true, int64_t timeOutAt = END_OF_TIME);
bool unblock();
};
```
### Event (`api/event.h`)
```cpp
class Event {
bool state_;
Thread *waiter_; // only ONE waiter!
public:
bool set(void); // trigger + optionally resume waiter
bool suspendUntilTriggered(int64_t timeout = END_OF_TIME);
void reset(void);
};
```
### Topic/Subscriber (Publish-Subscribe middleware, `api/topic.h`)
```cpp
template <class Type>
class Topic : public TopicInterface {
public:
Topic(int64_t id, const char* name, bool onlyLocal = false);
uint32_t publish(Type &msg, bool shallSendToNetwork = true);
};
class Subscriber : public SubscriberInterface {
public:
Subscriber(TopicInterface &topic, const char* name = "Subscriber");
virtual void put(uint32_t topicId, size_t len, void *msg, ...) = 0;
};
```
### Gateway (inter-node communication, `api/gateway/`)
```cpp
class Gateway : public ListElement {
virtual bool sendNetworkMessage(NetworkMessage &msg);
virtual void onIncomingMessage(NetworkMessage &msg);
};
```
Link interfaces: CAN, UART, UDP, Shared Memory.
### CommBuffer (`api/commbuffer.h`)
```cpp
template <class Type>
class CommBuffer { ... }; // lock-free single-producer/single-consumer buffer
```
## 4.4 API Surface
Language: **C++ (C++11 minimum)**. Single master header: `#include <rodos.h>``api/rodos.h`
Key headers:
```
thread.h, rodos-semaphore.h, barrier.h, event.h, topic.h, subscriber.h,
timeevent.h, timemodel.h, hal.h, gateway.h, commbuffer.h, application.h,
fifo.h, putter.h
```
**Application model**:
```cpp
class Application : public ListElement {
virtual long init() { return 0; }
virtual void run() { }
};
```
All `Application` and `Thread` instances are global objects. `main()` calls `initSystem()``initAllThreads()``startIdleThread()`.
## 4.5 Hardware Abstraction
File: `api/hal.h`, `api/hal/hal_*.h`
```cpp
class HW_HAL { /* base for all HW peripherals */ };
class GPIO : public HW_HAL { ... };
class UART : public HW_HAL { ... };
class SPI : public HW_HAL { ... };
class I2C : public HW_HAL { ... };
class ADC : public HW_HAL { ... };
class PWM : public HW_HAL { ... };
class CAN : public HW_HAL { ... };
class Ethernet : public HW_HAL { ... };
class SharedMemory : public HW_HAL { ... };
```
Each port implements the HAL classes. Platform-specific code in `src/bare-metal/<platform>/hal/`.
## 4.6 Tick/Timer Infrastructure
File: `api/timeevent.h`, `src/independent/timeevent.cpp`, `src/independent/timemodel.cpp`
```cpp
class TimeEvent : public ListElement {
static List timeEventList;
Atomic<int64_t> eventAt;
Atomic<int64_t> eventPeriod;
public:
virtual void handle(void) {} // override for custom handling
void activateAt(int64_t time);
void activatePeriodic(int64_t startAt, int64_t period);
static int32_t propagate(int64_t timeNow); // called from tick ISR
static int64_t getNextTriggerTime();
};
```
**Time model**: Uses nanosecond-precision `int64_t` time (`Nanoseconds`, `Microseconds`, `Milliseconds`, `Seconds` are all int64_t aliases). `NOW()` returns current time. `TimeModel::computeNextBeat()` handles period computation.
Tick ISR calls `TimeEvent::propagate(NOW())` which:
1. Iterates all TimeEvents
2. Fires handlers where `eventAt < now`
3. Updates `eventAt` for periodic events
4. Triggers scheduler if a thread became ready
## 4.7 Cooperative vs Preemptive
**Fully preemptive** via PendSV on Cortex-M:
- `TimeEvent::propagate()` runs in SysTick ISR
- When a higher-priority thread becomes ready, `__asmSaveContextAndCallScheduler()` triggers PendSV
- PendSV performs full context switch (R4-R11 + EXC_RETURN, optionally S16-S31 for FPU)
- `Thread::yield()` calls `resume()` + triggers reschedule
On POSIX platforms: preemption via POSIX signals (`SIGALRM` or timer threads).
---
# Comparative Summary for UniversalisOS
| Feature | ChibiOS/RT | RT-Thread | Contiki | RODOS |
|---------|-----------|-----------|---------|-------|
| **Language** | C | C | C | C++ |
| **Arch support** | ARM, AVR, PPC, x86 | 21 families, 107 BSPs | 33 platforms (sensor nodes) | ARM Cortex-M, RPi3, POSIX |
| **MMU needed** | No | No (optional RT-Smart uses it) | No | No |
| **Memory model** | Static working areas | Heap (small/slab/mempool) | Zero-allocation | Static C++ objects |
| **Thread model** | Preemptive, priority | Preemptive, priority | Stackless protothreads | Preemptive, priority |
| **Context switch** | SVC/PendSV (ARM) | arch-specific | None (continuation) | PendSV (ARM) |
| **IPC** | Sem, Mutex, CondVar, Events, Msg | Sem, Mutex, Event, MB, MQ | Event queue only | Sem, Barrier, Event, Topic/Subscriber |
| **Priority inherit.** | Yes (mutex) | Yes (mutex + ceiling) | N/A | Yes (semaphore) |
| **SMP** | Yes (CH_CFG_SMP_MODE) | Yes (RT_USING_SMP) | No | No (single-core) |
| **Timer** | Virtual timer delta list | Skip-list timer | 4-layer (timer/etimer/ctimer/rtimer) | TimeEvent list |
| **Tickless** | Yes (CH_CFG_ST_TIMEDELTA) | No (tick-based) | rtimer is real-time | Yes (nanosecond time) |
| **Min footprint** | ~1KB (NIL), ~5KB (RT) | ~3KB (nano mode) | ~1KB (protothreads) | ~2KB (Cortex-M) |
| **Scheduling** | Preemptive + round-robin | Preemptive + round-robin | Cooperative only | Preemptive |
## Key Design Patterns for UniversalisOS
1. **ChibiOS port contract** (`chcore.h`): Excellent model for hypervisor port layer. Defines exact macros every port must export (stack init, IRQ prologue/epilogue, context setup, priority validation).
2. **RT-Thread object system**: Uniform kernel object model with name, type, list node. Enables `rt_object_find()` for runtime discovery. Good pattern for hypervisor resource management.
3. **Contiki protothreads**: Zero-overhead "threads" for monitoring/management tasks that never need to block on hardware. Could be used for hypervisor event handlers.
4. **RODOS Topic/Subscriber**: Built-in publish-subscribe middleware for inter-partition communication in a hypervisor. The Gateway/LinkInterface pattern maps directly to inter-VM communication.
5. **ChibiOS SMP memory classes**: `CH_MEM_GLOBAL_COHERENT_BSS`, `CH_MEM_PRIVATE_BSS(c)` — directly applicable to hypervisor memory partitioning for cache-coherent shared regions.
6. **RT-Thread skip-list timers**: O(log n) timer insertion vs O(n) delta lists. Better for large numbers of virtual timers.
7. **RODOS nanosecond time**: `int64_t` nanoseconds avoids 32-bit wrap issues. Better for hypervisor wall-clock management than tick-based models.