universalisos/docs/rtos_ref_deep_audit.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

930 lines
37 KiB
Markdown

# RTOS Reference Deep Audit: seL4, ThreadX, NuttX, RTEMS
**Purpose:** Extract architecture abstraction patterns, no-MMU handling, kernel primitives, context switch, and isolation mechanisms to inform UniversalisOS microkernel design.
---
## 1. seL4
### 1.1 Architecture Support
**Architectures:** ARM (32/64), RISC-V (32/64), x86 (32/64)
| seL4 arch | Directory | Sub-variants |
|-----------|-----------|-------------|
| ARM 32 | `src/arch/arm/32/` | armv7-a, armv8-a/32 |
| ARM 64 | `src/arch/arm/64/` | armv8-a/64 (AArch64) |
| RISC-V | `src/arch/riscv/` | riscv32, riscv64 |
| x86 32 | `src/arch/x86/32/` | ia32 |
| x86 64 | `src/arch/x86/64/` | x86_64 |
**Platforms:** allwinnerA20, am335x, apq8064, ariane, bcm2711, bcm2712, bcm2837, cheshire, eswin, exynos4/5, fvp, hifive, hikey, imx6/7/8m/93, maaxboard, odroidc2/c4, omap3, pc99, qemu-arm-virt, qemu-riscv-virt, rk3399, spike, tk1, tx1, tx2, zynqmp, xilinx-versal, zcu102
**Key files:**
- `src/arch/arm/32/traps.S` — ARM32 vector table + trap handlers
- `src/arch/arm/64/traps.S` — AArch64 vector table (EL1/EL2)
- `src/arch/riscv/traps.S` — RISC-V trap entry
- `src/arch/x86/32/traps.S` / `src/arch/x86/64/traps.S` — x86 IDT-based traps
- `libsel4/sel4_arch_include/` — per-arch API headers: aarch32, aarch64, ia32, riscv32, riscv64, x86_64
**Critical observation:** seL4 does NOT support ARMv-M (Cortex-M). It requires an MMU. No MPU-only support.
### 1.2 Memory Model
**MMU-only.** seL4 is a capability-based microkernel that REQUIRES an MMU for its fundamental isolation model.
- `include/kernel/vspace.h` — architecture-abstracted virtual space management
- `src/arch/arm/32/kernel/vspace.c` — ARM32 page table manipulation (L1/L2)
- `src/arch/arm/64/kernel/vspace.c` — AArch64 translation tables
- Capabilities: `cap_page_table_cap`, `cap_page_directory_cap`, `cap_frame_cap` — all MMU-dependent
**How isolation works:** Capability-based access control. Each object (TCB, Endpoint, Page Table, etc.) is accessed only through capabilities held in CNodes. No process can access kernel memory or another process's memory without the appropriate capability. The MMU enforces address space separation between threads in different PDs.
**No-MMU strategy:** None. seL4 fundamentally requires MMU. There is no MPU path.
### 1.3 Kernel Primitives
**Kernel Objects** (`src/object/`):
| Object | File | Purpose |
|--------|------|---------|
| TCB | `tcb.c` | Thread Control Block — the schedulable entity |
| Endpoint | `endpoint.c` | Synchronous IPC rendezvous point |
| Notification | `notification.c` | Async signal / event flag |
| CNode | `cnode.c` | Capability table node |
| Untyped | `untyped.c` | Raw memory for retype into kernel objects |
| Reply | `reply.c` | MCS scheduling reply object |
| SchedContext | `schedcontext.c` | MCS budget/timeslice |
| SchedControl | `schedcontrol.c` | CPU scheduling control |
| Domain | `domain.c` | Scheduling domain (ARINC-like) |
**Scheduling** (`include/kernel/thread.h`):
- Bitmap priority scheduler with L1/L2 bitmaps: `getHighestPrio()` uses `clzl`
- Up to `CONFIG_NUM_PRIORITIES` priority levels
- Domain support: multiple scheduling domains with time-slicing
- MCS kernel: CBS (Constant Bandwidth Server) / sporadic server scheduling
- Key functions: `schedule()`, `chooseThread()`, `switchToThread()`, `switchToIdleThread()`
**IPC** (`src/object/endpoint.c`):
- Synchronous rendezvous: `sendIPC()` / `recvIPC()`
- Message passing via IPC buffer in user space (registers: `msgInfoRegister`, `capRegister`)
- Badge-based capability transfer over endpoints
- Syscall dispatch: `SysSend`, `SysNBSend`, `SysCall`, `SysRecv`, `SysReply`, `SysReplyRecv`, `SysWait`, `SysNBWait`
- Fastpath for `Call`/`ReplyRecv` in `src/fastpath/fastpath.c`
**Synchronization:**
- Notifications: binary event-like primitive (`sendSignal()`, `wait()`, `tryWait()`)
- No mutexes/semaphores — IPC IS the synchronization mechanism
**Memory management:**
- All memory created from Untyped objects via `seL4_Untyped_Retype()`
- Capabilities control access to all objects including page tables and frames
- Kernel does not allocate memory after boot — all created from initial untypeds
### 1.4 API Surface
**Public API** defined in `libsel4/`:
- `include/interfaces/sel4.xml` — formal IDL defining all system calls
- `include/interfaces/object-api.xml` — object method API
**System calls** (from `src/api/syscall.c`):
```c
exception_t handleSyscall(syscall_t syscall);
// SysCall, SysSend, SysNBSend, SysRecv, SysReply, SysReplyRecv, SysWait, SysNBWait
```
**API functions** (from `libsel4/sel4_arch_include/*/sel4/sel4_arch/`):
- `seL4_Untyped_Retype()` — create new kernel objects
- `seL4_TCB_*` — thread control (Configure, SetPriority, SetIPCBuffer, WriteRegisters, ReadRegisters, Suspend, Resume)
- `seL4_Endpoint_Send/Recv/Call()` — synchronous IPC
- `seL4_Signal/Wait()` on Notification objects
- `seL4_CNode_*` — capability space manipulation
- `seL4_VSpace_*` — virtual address space management
- `seL4_IRQControl/Handler_*` — interrupt management
- `seL4_SchedControl_*` — MCS scheduling control
### 1.5 Hardware Abstraction
**Three-layer architecture:**
1. **`arch/`** — architecture-specific code: ARM, RISC-V, x86
2. **`machine/`** — machine-level (common within arch): `registerset.h`, `fpu.c`, `hardware.h`
3. **`plat/`** — platform-specific: per-SoC timer, IRQ controller, serial
**Key HAL interfaces** (`include/arch/machine.h`):
```c
void init_cpu(void);
void init_drivers(void); // platform-level
void ackInterrupt(irq_t irq);
irq_t getActiveIRQ(void);
bool_t isIRQPending(void);
void setNextPC(tcb_t *tcb, word_t v);
word_t getRestartPC(tcb_t *tcb);
void switchToThread(tcb_t *tcb); // architecture-level
void Arch_switchToThread(tcb_t *tcb); // arch-specific (setVMRoot + clearExMonitor)
```
**Register abstraction** (`include/machine/registerset.h` → per-arch):
```c
enum _register { R0, ..., R14, SP=13, LR=14, NextIP=15, CPSR=16, FaultIP=17, TPIDRURW=18, TPIDRURO=19, n_contextRegisters=20 };
```
**Pattern:** `Arch_*()` prefix for architecture-specific functions; `arch_*` directories per arch; `mode/` subdirectories for 32/64-bit variants.
### 1.6 Partition/Isolation Mechanisms
- **Capability-based:** All access mediated by capabilities in CNodes. No global names.
- **Address space isolation:** Each thread can be in a different VSpace (page directory). `setVMRoot()` switches page tables.
- **Scheduling domains:** `CONFIG_NUM_DOMAINS > 1` enables ARINC-653-like temporal partitioning
- **MCS scheduling:** Budget-based isolation prevents starvation/budget-exhaustion attacks
- **No no-MMU path:** seL4 REQUIRES MMU. The capability system IS the isolation mechanism.
### 1.7 Context Switch
**ARM32 context** (`src/arch/arm/32/traps.S`):
```asm
arm_swi_syscall:
srsia #PMODE_SUPERVISOR @ Save CPSR + LR to SVC stack
sub lr, lr, #4 @ FaultIP = NextIP - 4
str lr, [sp, #(PT_FaultIP - PT_NextIP)]
stmdb sp, {r0-lr}^ @ Save all user regs (r0-r14)
mrc p15, 0, sp, c13, c0, 4 @ Load kernel stack from TPIDRPRW
```
**Saved state:** 20 words per thread — R0-R14, NextIP, CPSR, FaultIP, TPIDRURW, TPIDRURO
- FPU state saved lazily (optional `CONFIG_HAVE_FPU`)
- `Arch_switchToThread()`: `setVMRoot(tcb)` + `clearExMonitor()`
- No explicit register save/restore in switch — the trap handler saves everything on entry, the scheduler just swaps the kernel stack pointer
**AArch64 context** (`src/arch/arm/64/traps.S`):
```asm
@ Vector table with 128-byte aligned entries per ARM D1-7
@ Uses TPIDR_EL1/EL2 for kernel stack pointer
@ Saves: X0-X30, SPSR, ELR, TPIDR to kernel stack
```
**Fastpath** (`src/fastpath/fastpath.c`):
```c
void NORETURN fastpath_call(word_t cptr, word_t msgInfo);
void NORETURN fastpath_reply_recv(word_t cptr, word_t msgInfo);
```
Optimized path that avoids full save/restore when only message registers change. Directly switches TCB and address space.
---
## 2. ThreadX (Eclipse ThreadX)
### 2.1 Architecture Support
**Broadest port coverage of any RTOS in the audit.**
**ARM Cortex-A:** cortex_a5, a7, a8, a9, a12, a15, a17, a34, a35, a53, a55, a57, a65, a72, a73, a75, a76, a77, a5x, a65ae, a76ae
**ARM Cortex-R:** cortex_r4, r5, r7
**ARM Cortex-M:** cortex_m0, m23, m3, m4, m7, m33, m55, m85
**ARM legacy:** arm9, arm11
**RISC-V:** risc-v32, risc-v64, risc-v_common
**ARC:** arc_em, arc_hs
**Renesas RX:** rxv1, rxv2, rxv3
**TI DSP:** c667x
**Xtensa:** xtensa
**Linux user-space:** linux (gnu)
**Windows:** win32, win64
**Architecture-grouped ports** (`ports_arch/`):
- ARMv7-A, ARMv7-M, ARMv8-A, ARMv8-M
**Key files per port:**
- `ports/cortex_m0/gnu/src/tx_thread_context_save.S`
- `ports/cortex_m0/gnu/src/tx_thread_context_restore.S`
- `ports/cortex_m0/gnu/src/tx_thread_schedule.S`
- `ports/cortex_m0/gnu/src/tx_thread_system_return.S`
- `ports/cortex_m0/gnu/src/tx_thread_stack_build.S`
- `ports/cortex_m0/gnu/inc/tx_port.h` — port-specific type definitions + inline optimizations
### 2.2 Memory Model
**No MMU/MPU required.** ThreadX runs on flat memory model by default.
- **No-MMU (Cortex-M0/M3/M4):** Single address space, no protection between threads
- **With MPU (Cortex-M33/M85):** Optional MPU support via ThreadX Modules (separate product)
- **With MMU (Cortex-A):** Flat model or optional virtual memory
**Isolation without MMU:** ThreadX provides NONE by default. All threads share the same address space. The `tx_thread_system_state` variable tracks ISR nesting but doesn't protect memory.
**Memory management:**
- `tx_byte_pool` — variable-size memory allocator (malloc-like)
- `tx_block_pool` — fixed-size block allocator (pool-based)
- Both are user-space objects, not kernel-managed pages
### 2.3 Kernel Primitives
**Threads** (`common/src/tx_thread_*.c`):
- `tx_thread_create()`, `tx_thread_delete()`, `tx_thread_suspend()`, `tx_thread_resume()`
- Priority-based preemptive scheduling (0 = highest, up to `TX_MAX_PRIORITIES` = 32-1024)
- Round-robin time-slicing within same priority
- Preemption-threshold: disable preemption for priorities below threshold
**Synchronization:**
- `tx_mutex_create/get/put/delete` — mutex with priority inheritance
- `tx_semaphore_create/get/put/delete` — counting semaphore
- `tx_event_flags_create/get/set/delete` — event flags (AND/OR)
**Communication:**
- `tx_queue_create/send/receive/delete` — fixed-size message queues
- No IPC/message passing between address spaces (single address space)
**Timers:**
- `tx_timer_create/activate/deactivate/delete` — software timers
- Tick-based: `tx_timer_interrupt` increments system tick
**Memory:**
- `tx_byte_pool_create/allocate/release/delete` — dynamic memory pools
- `tx_block_pool_create/allocate/release/delete` — fixed-block pools
### 2.4 API Surface
**Header:** `common/inc/tx_api.h` — single monolithic API header
**Function naming:** All public functions prefixed `tx_`:
```c
UINT tx_thread_create(TX_THREAD *thread_ptr, CHAR *name_ptr, VOID (*entry)(ULONG), ULONG entry_input,
VOID *stack_start, ULONG stack_size, UINT priority, UINT preempt_threshold,
ULONG time_slice, UINT auto_start);
UINT tx_thread_delete(TX_THREAD *thread_ptr);
UINT tx_thread_suspend(TX_THREAD *thread_ptr);
UINT tx_thread_resume(TX_THREAD *thread_ptr);
UINT tx_thread_relinquish(void);
UINT tx_thread_sleep(ULONG timer_ticks);
UINT tx_mutex_create(TX_MUTEX *mutex_ptr, CHAR *name_ptr, UINT inherit);
UINT tx_mutex_get(TX_MUTEX *mutex_ptr, ULONG wait_option);
UINT tx_mutex_put(TX_MUTEX *mutex_ptr);
UINT tx_semaphore_create(TX_SEMAPHORE *sem_ptr, CHAR *name_ptr, ULONG initial_count);
UINT tx_semaphore_get(TX_SEMAPHORE *sem_ptr, ULONG wait_option);
UINT tx_semaphore_put(TX_SEMAPHORE *sem_ptr);
UINT tx_queue_create(TX_QUEUE *queue_ptr, CHAR *name_ptr, UINT message_size, VOID *queue_start, ULONG queue_size);
UINT tx_queue_send(TX_QUEUE *queue_ptr, VOID *source_ptr, ULONG wait_option);
UINT tx_queue_receive(TX_QUEUE *queue_ptr, VOID *destination_ptr, ULONG wait_option);
```
**Error-checked variants:** `_txe_*` prefix (with parameter validation)
**MISRA variants:** `_txr_*` prefix
### 2.5 Hardware Abstraction
**Port-based abstraction:** Each target gets a complete port directory:
```
ports/<cpu>/<compiler>/
inc/tx_port.h — type definitions, macros, inline optimizations
src/
tx_thread_context_save.S
tx_thread_context_restore.S
tx_thread_schedule.S
tx_thread_system_return.S
tx_thread_stack_build.S
tx_thread_interrupt_control.S
tx_thread_interrupt_disable.S
tx_thread_interrupt_restore.S
tx_timer_interrupt.S
```
**`tx_port.h` pattern** (Cortex-M0 example):
```c
#define TX_INT_DISABLE 1
#define TX_INT_ENABLE 0
#define TX_MINIMUM_STACK 200
// Inline interrupt control:
static inline unsigned int __disable_interrupts(void) { ... MRS PRIMASK; CPSID i ... }
static inline void __restore_interrupts(unsigned int primask_value) { ... MSR PRIMASK ... }
// Inline system return (PendSV-based):
static inline void _tx_thread_system_return_inline(void) {
*((volatile ULONG *) 0xE000ED04) = ((ULONG) 0x10000000); // Set PendSV
// DSB + ISB
}
#define TX_DISABLE interrupt_save = __disable_interrupts();
#define TX_RESTORE __restore_interrupts(interrupt_save);
```
**Key pattern:** The C kernel code (`common/src/`) is 100% portable. All arch-specific behavior is in the port `.S` files and `tx_port.h`. The common code calls `_tx_thread_context_save()`, `_tx_thread_schedule()`, `_tx_thread_system_return()` which are entirely implemented in the port assembly.
### 2.6 Partition/Isolation Mechanisms
**None in base ThreadX.** Single flat address space, no protection.
**ThreadX Modules** (`ports_module/`): Optional module that provides memory-isolated modules using MPU/MMU when available. This is a separate add-on, not part of core ThreadX.
### 2.7 Context Switch
**Cortex-M0** (`ports/cortex_m0/gnu/src/tx_thread_schedule.S`):
```asm
_tx_thread_schedule:
MOVS r0, #0
LDR r2, =_tx_thread_preempt_disable
STR r0, [r2, #0] @ Clear preempt disable
CPSIE i @ Enable interrupts
LDR r0, =#0x10000000 @ PENDSVSET bit
LDR r1, =#0xE000ED04 @ NVIC ICSR
STR r0, [r1] @ Trigger PendSV
...PendSV handler does the actual switch...
```
**Cortex-M PendSV context switch** (in `tx_thread_context_restore.S`):
```asm
_tx_thread_context_restore:
@ PendSV handler - hardware saves R0-R3, R12, LR, PC, xPSR automatically
@ Save remaining: R4-R11, optionally S16-S31 (FPU)
@ Load new thread's R4-R11 from its stack
@ Hardware restores R0-R3, R12, LR, PC, xPSR on exception return
```
**Cortex-A** (`ports/cortex_a9/gnu/src/tx_thread_context_save.S`):
```asm
@ Saves R0-R12, LR, CPSR, SPSR to thread's stack
@ IRQ/FIQ nesting support: tx_thread_irq_nesting_start/end
```
**Cortex-A scheduler** (`tx_thread_schedule.S`):
```asm
@ Load _tx_thread_execute_ptr, compare with current
@ If different: save full context (R0-R12, SP, LR, CPSR) to old TCB stack
@ restore from new TCB stack
@ Handle FPU context (VFP D0-D31, FPEXC, FPSCR)
```
**Stack building** (`tx_thread_stack_build.S`):
```asm
@ Builds initial stack frame for new thread:
@ Pushes: CPSR, PC (entry), LR (thread shell), R12, R3-R0 (entry_input)
@ Sets SP to top of stack
```
---
## 3. NuttX
### 3.1 Architecture Support
**Most architectures of any RTOS in the audit.** NuttX is a POSIX-like RTOS.
**Architectures** (`arch/`):
| Arch | Directory | Sub-variants |
|------|-----------|-------------|
| ARM | `arch/arm/` | arm, armv6-m, armv7-a, armv7-m, armv7-r, armv8-m, armv8-r |
| ARM64 | `arch/arm64/` | AArch64 |
| AVR | `arch/avr/` | ATmega |
| CEVA | `arch/ceva/` | DSP |
| HC | `arch/hc/` | HCS12 |
| MIPS | `arch/mips/` | PIC32, MIPS32 |
| MISC | `arch/misoc/` | MiSoC |
| OpenRISC | `arch/or1k/` | or1k |
| Renesas | `arch/renesas/` | SH-1, M16C, RX |
| RISC-V | `arch/risc-v/` | RV32, RV64 |
| Simulator | `arch/sim/` | Linux/macOS user-space |
| SPARC | `arch/sparc/` | LEON |
| TriCore | `arch/tricore/` | Infineon |
| x86 | `arch/x86/` | i486, QEMU |
| x86_64 | `arch/x86_64/` | Intel |
| Xtensa | `arch/xtensa/` | ESP32 |
| Z16 | `arch/z16/` | Zilog |
| Z80 | `arch/z80/` | Z80, eZ80, Z180 |
**ARM sub-architectures in `arch/arm/src/`:**
- armv6-m (Cortex-M0/M0+)
- armv7-a (Cortex-A5/A7/A8/A9/A53 with MMU)
- armv7-m (Cortex-M3/M4/M7 — no MMU, optional MPU)
- armv7-r (Cortex-R4/R5/R7 — MPU)
- armv8-m (Cortex-M23/M33/M55/M85 — TrustZone-M + MPU)
- armv8-r (Cortex-R52/R82)
**Board support:** Hundreds of BSPs under `boards/` — STM32, NRF52, RP2040, ESP32, SAM, i.MX, Kinetis, etc.
### 3.2 Memory Model
**Adaptive — supports no-MMU, MPU, and MMU.**
**No-MMU (Cortex-M, most MCUs):**
- Flat address space, all tasks in single memory map
- `CONFIG_ARCH_NO_INTERRUPT_STACK` — uses thread stack for ISR
- Protection: stack canary checking (`CONFIG_STACK_CANARIES`)
- No memory isolation between tasks
**MPU (Cortex-M with MPU, Cortex-R):**
- `CONFIG_ARCH_USE_MPU` — enables MPU support
- `CONFIG_BUILD_PROTECTED` — kernel/user separation using MPU
- Kernel runs privileged, user runs unprivileged
- `syscall/` directory: system call table (`syscall.csv`) with auto-generated proxies/stubs
- `arch/arm/src/armv7-m/arm_dispatch_syscall.S` — SVC-based syscall entry
- `CONFIG_MM_KERNEL_HEAP` — separate kernel heap
**MMU (Cortex-A, x86, etc.):**
- `CONFIG_BUILD_KERNEL` — full virtual memory isolation
- `arch/arm/src/armv7-a/` — full MMU page table management
- `sched/addrenv/` — address environment management
- `mm/kmap/` — kernel memory mapping
**Memory management (`mm/`):**
- `mm_heap/` — general heap allocator
- `mm/tlsf/` — TLSF (Two-Level Segregated Fit) allocator
- `mm/mempool/` — fixed-size memory pool
- `mm/mm_gran/` — granule allocator (for DMA, etc.)
- `mm/umm_heap/` — user memory heap
- `mm/kmm_heap/` — kernel memory heap
- `mm/shm/` — shared memory
### 3.3 Kernel Primitives
**Tasks** (`sched/task/`):
- `task_create()`, `task_spawn()`, `task_delete()`, `task_exit()`
- POSIX-like: `nxtask_create()` internal, `task_create()` public
- Priority-based preemptive scheduling (FIFO, Round-Robin, Sporadic)
**Pthreads** (`sched/pthread/`):
- Full POSIX threads: `pthread_create()`, `pthread_join()`, `pthread_detach()`
- `pthread_mutex_*`, `pthread_cond_*`, `pthread_rwlock_*`
- `pthread_attr_*` — full attribute support
**Semaphores** (`sched/semaphore/`):
- `nxsem_wait()`, `nxsem_post()`, `nxsem_trywait()`
- Binary and counting semaphores
**Message queues** (`sched/mqueue/`):
- POSIX mqueue: `mq_open()`, `mq_send()`, `mq_receive()`
**Signals** (`sched/signal/`):
- Full POSIX signals: `kill()`, `sigaction()`, `sigwait()`, `pthread_sigmask()`
**Events** (`sched/event/`):
- NuttX-specific event flags
**Scheduling** (`sched/sched/`):
- `sched_addreadytorun()` — core scheduling logic
- `nxsched_process_timer()` — tick processing
- SMP support: per-CPU ready queues
- `CONFIG_SCHED_INSTRUMENTATION` — trace hooks
### 3.4 API Surface
**POSIX-compliant API.** The public API IS POSIX:
```c
// Task management
int task_create(const char *name, int priority, int stack_size, main_t entry, char *const argv[]);
int task_delete(pid_t pid);
int task_setpriority(pid_t pid, int sched_priority);
// POSIX threads
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, pthread_startroutine_t start_routine, void *arg);
int pthread_join(pthread_t thread, void **value_ptr);
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);
int pthread_mutex_lock(pthread_mutex_t *mutex);
// Semaphores
int sem_init(sem_t *sem, int pshared, unsigned int value);
int sem_wait(sem_t *sem);
int sem_post(sem_t *sem);
// POSIX I/O
int open(const char *path, int oflags, ...);
ssize_t read(int fd, void *buf, size_t nbytes);
ssize_t write(int fd, const void *buf, size_t nbytes);
// Sockets
int socket(int domain, int type, int protocol);
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
```
**System call table** (`syscall/syscall.csv`):
```
"task_create","nuttx/task.h","","int","FAR const char *","int","int","main_t","FAR char * const *"
"task_delete","unistd.h","","int","pid_t"
"pthread_create","pthread.h","","int","FAR pthread_t *","FAR const pthread_attr_t *","FAR pthread_startroutine_t","FAR void *"
```
**Auto-generated syscall mechanism:** The CSV file drives code generation for:
- User-space proxies (in `syscall/proxies/`)
- Kernel-space stubs (in `syscall/stubs/`)
- SVC/SWI dispatch (in `arch/*/arm_dispatch_syscall.S`)
### 3.5 Hardware Abstraction
**Three-layer architecture:**
1. **`arch/<arch>/`** — architecture-level
- `src/common/` — shared across sub-architectures (e.g., `arm_dataabort.c`, `arm_vectors.S`)
- `src/<subarch>/` — sub-architecture (e.g., `armv7-m/`, `armv7-a/`)
- `src/<chip>/` — chip-specific (e.g., `stm32/`, `nrf52/`)
- `include/` — headers per chip/subarch
2. **`boards/<arch>/<chip>/<board>/`** — board-level configuration and drivers
3. **`drivers/`** — portable device drivers (serial, SPI, I2C, GPIO, etc.)
**Key HAL functions** (`include/nuttx/arch.h`):
```c
void up_initialize(void); // Architecture init
int up_saveusercontext(void *saveregs); // Save CPU context
void up_initial_state(struct tcb_s *tcb); // Initialize new task context
void up_switch_context(struct tcb_s *tcb, struct tcb_s *rtcb); // Context switch
void up_irqinitialize(void); // IRQ controller init
int up_enable_irq(int irq); // Enable interrupt
int up_disable_irq(int irq); // Disable interrupt
```
**IRQ abstraction** (`include/nuttx/irq.h`):
```c
int irq_attach(int irq, xcpt_t isr, xcpt_t isrthread, FAR void *arg, FAR const char *name);
// Supports: ISR handlers, threaded IRQ handlers, work-queue-based IRQ handlers
```
**Architecture-specific context** (ARM, `arch/arm/include/armv7-m/irq.h`):
```c
struct xcptcontext {
uint32_t regs[XCPTCONTEXT_REGS]; // R0-R15, xPSR, BASEPRI, EXC_RETURN
// FPU: S0-S31, FPSCR
// Signal context overlay
};
```
### 3.6 Partition/Isolation Mechanisms
**`CONFIG_BUILD_PROTECTED`** — NuttX's primary no-MMU isolation mechanism:
- Kernel runs in privileged mode (Handler mode or privileged Thread mode)
- User tasks run unprivileged (Thread mode, PSP stack)
- System calls via SVC instruction
- MPU regions protect kernel memory from user access
- Separate kernel/user heaps
**`CONFIG_BUILD_KERNEL`** — Full MMU isolation:
- Per-process address spaces
- `sched/addrenv/` — address environment switching on context switch
- `mm/kmap/` — kernel virtual memory management
**Key files:**
- `arch/arm/src/armv7-m/arm_dispatch_syscall.S` — SVC handler for protected mode
- `syscall/` — auto-generated syscall proxy/stub pairs
- `mm/umm_heap/` vs `mm/kmm_heap/` — separate user/kernel heaps
### 3.7 Context Switch
**ARMv7-M context save** (`arch/arm/src/armv7-m/arm_saveusercontext.S`):
```asm
up_saveusercontext:
str r0, [r0, #(4*REG_R0)] @ Save R0-R3, R12, R14, R15
str r1, [r0, #(4*REG_R1)]
...
mrs r1, XPSR
str r1, [r0, #(4*REG_XPSR)]
@ FPU: vstmia r1!, {s0-s15}; vmrs fpscr
mov r2, sp
mrs r3, basepri
stmia r0!, {r2-r11} @ SP, BASEPRI, R4-R11
mov r1, #-1
stmia r0!, {r1} @ EXC_RETURN = 0xffffffff
@ FPU: vstmia r0!, {s16-s31}
```
**ARMv7-M exception entry** (`arch/arm/src/armv7-m/arm_exception.S`):
```asm
exception_common:
mrs r0, ipsr @ IRQ number
mrs r12, control
tst r14, #EXC_RETURN_PROCESS_STACK @ PSP or MSP?
beq 1f
mrs r1, psp @ Context on PSP
b 2f
1: mrs r1, msp @ Context on MSP
sub r2, r1, #SW_XCPT_SIZE
msr msp, r2
2: @ Complete save: R2-R12, R14, BASEPRI, SP
@ FPU: vstmdbeq r1!, {s16-s31}
stmdb r1!, {r2-r12,r14}
@ Call arm_doirq(irq_number, saved_context)
```
**Context switch:** On Cortex-M, NuttX uses the hardware PendSV mechanism:
- `up_switch_context()` triggers PendSV
- PendSV handler saves R4-R11 (hardware saves R0-R3, R12, LR, PC, xPSR)
- Loads new thread's registers
- Hardware restores on exception return
---
## 4. RTEMS
### 4.1 Architecture Support
**14 CPU architectures** (`cpukit/score/cpu/`):
| Architecture | Directory | BSP Variants |
|-------------|-----------|-------------|
| AArch64 | `score/cpu/aarch64/` | a53, a72, raspberrypi5, rk3399, xilinx-zynqmp, xen, frdm-imx93, xilinx-versal |
| ARM | `score/cpu/arm/` | beagle, stm32f4/h7/u5, atsam, lpc, imx, imxrt, raspberrypi, tms570, xen, fvp, efm32, lpc176x |
| i386 | `score/cpu/i386/` | pc386, pc486 |
| x86_64 | `score/cpu/x86_64/` | amd64 |
| M68k | `score/cpu/m68k/` | mcf5206, mcf52235, mcf5225x, mcf5329, mrm332 |
| MicroBlaze | `score/cpu/microblaze/` | Xilinx |
| MIPS | `score/cpu/mips/` | Malta, JMR3904, RBtx4938 |
| Moxie | `score/cpu/moxie/` | moxiesim |
| Nios II | `score/cpu/nios2/` | Altera |
| OpenRISC 1000 | `score/cpu/or1k/` | or1ksim |
| PowerPC | `score/cpu/powerpc/` | MPC5xx, MPC8xx, MPC8260, MPC83xx, MPC85xx, QorIQ, mvme3100, beatnik |
| RISC-V | `score/cpu/riscv/` | rv32/rv64, generic, spike, frdm-k28f |
| SPARC | `score/cpu/sparc/` | ERC32, LEON2, LEON3, LEON4 |
| no_cpu | `score/cpu/no_cpu/` | Template/porting guide |
### 4.2 Memory Model
**Adaptive — supports no-MMU, MPU, and MMU.**
**No-MMU (ARM Cortex-M, SPARC ERC32):**
- Flat address space
- Stack-based protection (stack bounds checking via guard patterns)
**MPU (ARMv7-M/R):**
- `score/cpu/arm/include/rtems/score/armv7-pmsa.h` — full PMSAv7 MPU support
- Region-based protection with `_ARMV7_PMSA_Write_region()`, `_ARMV7_PMSA_Add_regions()`
- Supports up to 16 MPU regions (or more with sub-region disable)
- Access control: read-only/read-write, cached/uncached, shared/non-shared
**MMU (AArch64, PowerPC, x86_64):**
- Full virtual memory support via BSP-specific MMU drivers
- `score/cpu/aarch64/` — EL1 page table management
**Memory management:**
- Workspace allocator (kernel heap) — configured at link time
- `cpukit/libcsupport/src/` — POSIX malloc/free
- `cpukit/libblock/` — block device cache
### 4.3 Kernel Primitives
**Classic RTEMS API** (`cpukit/include/rtems/rtems/`):
| Manager | Header | Functions |
|---------|--------|-----------|
| Tasks | `tasks.h` | `rtems_task_create/delete/start/restart/suspend/resume/wake_when/set_priority` |
| Semaphores | `sem.h` | `rtems_semaphore_create/delete/obtain/release/release_count` |
| Message Queues | `message.h` | `rtems_message_queue_create/delete/send/receive/broadcast/urgent` |
| Events | `event.h` | `rtems_event_send/receive` |
| Barriers | `barrier.h` | `rtems_barrier_create/delete/wait/release` |
| Partitions | `part.h` | `rtems_partition_create/delete/get/release` |
| Regions | `region.h` | `rtems_region_create/delete/get/return_segment` |
| Timers | `timer.h` | `rtems_timer_create/delete/server_fire_when/fire_after/reset/cancel` |
| Rate Monotonic | `ratemon.h` | `rtems_rate_monotonic/create/delete/period/cancel/get_status` |
| Dual-Port Memory | `dpmem.h` | `rtems_port_create/delete/external2internal/internal2external` |
| Signals | `signal.h` | `rtems_signal_send/catch` |
| Clock | `clock.h` | `rtems_clock_set/get/get_tod/get_seconds_since_epoch/tick` |
**POSIX API** (via `cpukit/posix/`):
- Full POSIX threads, mutexes, condition variables, semaphores, mqueues, timers
**Super Core (score)** (`cpukit/score/src/`):
- `corebarrier.c`, `coremsg.c`, `coremutexseize.c`, `coresem.c` — internal implementations
- `thread*.c` — thread management
- `scheduler*.c` — pluggable scheduler framework
- `smp.c` — SMP management
### 4.4 API Surface
**Classic RTEMS API:**
```c
rtems_task_create(name, initial_priority, stack_size, modes, attributes, &id);
rtems_task_start(id, entry_point, argument);
rtems_task_suspend(id);
rtems_task_resume(id);
rtems_semaphore_create(name, count, attributes, priority, &id);
rtems_semaphore_obtain(id, options, timeout);
rtems_semaphore_release(id);
rtems_message_queue_create(name, count, max_size, attributes, &id);
rtems_message_queue_send(id, buffer, size);
rtems_message_queue_receive(id, buffer, &size, options, timeout);
rtems_event_send(task_id, event_in);
rtems_event_receive(event_in, options, ticks, &event_out);
```
**POSIX API:**
```c
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg);
int sem_init(sem_t *sem, int pshared, unsigned int value);
int mq_send(mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned msg_prio);
```
### 4.5 Hardware Abstraction
**Score CPU layer** (`cpukit/score/cpu/<arch>/`):
```
include/rtems/score/cpu.h — CPU-level type definitions, macros, inline functions
include/rtems/score/cpuimpl.h — implementation details
include/rtems/score/cpu_asm.h — assembly prototypes
```
**Key CPU interface** (from `cpu.h`):
```c
#define CPU_STACK_MINIMUM_SIZE (1024 * 4)
#define CPU_SIZEOF_POINTER 4
#define CPU_STRUCTURE_ALIGNMENT RTEMS_ALIGNED(32)
void _CPU_Context_switch(Context_Control *run, Context_Control *heir);
void _CPU_Context_restore(Context_Control *new_context);
void _CPU_Context_Initialize(Context_Control *context, void *stack_area_begin,
size_t stack_area_size, uint32_t new_level,
void (*entry_point)(void), bool is_fp, void *tls_area);
```
**BSP layer** (`bsps/<arch>/<bsp>/`):
```
include/bsp.h — BSP configuration
start/ — startup code
console/ — UART driver
clock/ — timer driver
irq/ — interrupt controller
```
**Pattern:** CPU layer provides `_CPU_*()` functions. BSP provides `_BSP_*()` functions. The score (super core) is arch-independent and calls only `_CPU_*()` and `_BSP_*()`.
### 4.6 Partition/Isolation Mechanisms
**MPU-based protection:**
- `score/cpu/arm/include/rtems/score/armv7-pmsa.h` — comprehensive MPU management
- `_ARMV7_PMSA_Write_region()` — write MPU region (base, size, attributes, sub-region disable)
- `_ARMV7_PMSA_Add_regions()` — add memory region to MPU (handles power-of-2 alignment)
- `_ARMV7_PMSA_Find_region()` — search for region containing address
- `_ARMV7_PMSA_Find_available_region()` — find free MPU slot
- Supports data and instruction regions separately (DRBAR/IRBAR)
- Region attributes: cached/uncached, read-only/read-write, shareable, device
**ARINC 653 partitioning:**
- RTEMS has an ARINC 653 API layer for safety-critical partitioning
- Rate Monotonic scheduling provides temporal isolation
### 4.7 Context Switch
**ARMv7-M context switch** (`score/cpu/arm/armv7m-context-switch.c`):
```c
void __attribute__((naked)) _CPU_Context_switch(
Context_Control *executing,
Context_Control *heir
) {
__asm__ volatile (
"movw r2, #:lower16:_Per_CPU_Information\n"
"movt r2, #:upper16:_Per_CPU_Information\n"
"ldr r3, [r2, %[isrpcpuoff]]\n"
"stm r0, {r4-r11, lr}\n" // Save callee-saved regs
#ifdef ARM_MULTILIB_VFP
"add r4, r0, %[d8off]\n"
"vstm r4, {d8-d15}\n" // Save FPU D8-D15
#endif
"str sp, [r0, %[spctxoff]]\n" // Save SP
"str r3, [r0, %[isrctxoff]]\n" // Save ISR nest level
"ldr r3, [r1, %[isrctxoff]]\n" // Load new ISR nest level
"ldr sp, [r1, %[spctxoff]]\n" // Load new SP
#ifdef ARM_MULTILIB_VFP
"add r4, r1, %[d8off]\n"
"vldm r4, {d8-d15}\n" // Restore FPU D8-D15
#endif
"ldm r1, {r4-r11, lr}\n" // Restore callee-saved regs
"str r3, [r2, %[isrpcpuoff]]\n"// Store ISR nest level
"bx lr\n"
);
}
```
**`Context_Control` structure** (ARM, from `cpu.h`):
```c
typedef struct {
uint32_t register_r4;
uint32_t register_r5;
uint32_t register_r6;
uint32_t register_r7;
uint32_t register_r8;
uint32_t register_r9;
uint32_t register_r10;
uint32_t register_r11;
uint32_t register_lr;
uint32_t register_sp;
uint32_t isr_nest_level;
uint32_t thread_id; // TLS
#ifdef ARM_MULTILIB_VFP
uint64_t register_d8;
...
uint64_t register_d15;
#endif
} Context_Control;
```
**Key pattern:** RTEMS uses `naked` functions with inline assembly, directly manipulating the SP. Unlike ThreadX (which uses PendSV on Cortex-M), RTEMS performs the context switch in the calling function itself. The `isr_nest_level` is stored per-context to handle nested interrupts correctly.
---
## 5. Cross-RTOS Comparison Matrix
| Feature | seL4 | ThreadX | NuttX | RTEMS |
|---------|------|---------|-------|-------|
| **Arch count** | 3 (ARM, RISC-V, x86) | 10+ (ARM-M/A/R, RISC-V, ARC, RX, Xtensa, Win, Linux) | 18 (ARM, AVR, MIPS, RISC-V, x86, SPARC, Z80...) | 14 (ARM, AArch64, x86, PPC, MIPS, SPARC, M68k, RISC-V...) |
| **Cortex-M support** | NO | YES (M0 to M85) | YES (M0 to M85) | YES (M3/M4/M7/M33) |
| **No-MMU support** | NO | YES (flat) | YES (flat + MPU + protected) | YES (flat + MPU) |
| **MPU support** | NO | Modules (optional) | CONFIG_BUILD_PROTECTED | armv7-pmsa.h |
| **MMU support** | REQUIRED | Optional | CONFIG_BUILD_KERNEL | Per-arch |
| **API style** | Capability IPC | tx_*() proprietary | POSIX | Classic RTEMS + POSIX |
| **Scheduling** | Priority bitmap + MCS | Priority + preemption-threshold | Priority FIFO/RR/Sporadic | Pluggable scheduler |
| **IPC** | Synchronous endpoints | Message queues | POSIX mqueue/signals | Message queues/events |
| **Context switch** | Trap handler saves all | PendSV (Cortex-M) / IRQ | PendSV (Cortex-M) / IRQ | Direct (naked function) |
| **Isolation model** | Capabilities | None (flat) | MPU protected / MMU | MPU regions |
| **Naming convention** | `seL4_*` | `tx_*` / `_tx_*` | POSIX (`task_create`, etc.) | `rtems_*` |
## 6. Design Patterns for UniversalisOS
### 6.1 Architecture Abstraction Pattern
**Best model: NuttX's 3-layer + RTEMS's CPU interface**
```
include/uos_arch.h — arch-independent interface (like RTEMS score/cpu.h)
arch/<arch>/include/ — arch-specific type definitions
arch/<arch>/src/<subarch>/ — sub-arch implementation (like NuttX)
arch/<arch>/src/<chip>/ — chip-specific (like NuttX)
```
**Key functions to abstract:**
```c
void uos_context_switch(uos_context_t *from, uos_context_t *to); // RTEMS pattern
void uos_context_save(uos_context_t *ctx); // ThreadX pattern
void uos_context_restore(uos_context_t *ctx); // ThreadX pattern
void uos_context_init(uos_context_t *ctx, void *sp, void *entry); // RTEMS pattern
void uos_irq_disable(void); // ThreadX inline pattern
void uos_irq_enable(void);
```
### 6.2 No-MMU Strategy
**Layer 1 (always):** Flat memory, stack canaries, cooperative/idle-hooks (ThreadX baseline)
**Layer 2 (MPU available):** Kernel/user separation via MPU (NuttX CONFIG_BUILD_PROTECTED pattern)
**Layer 3 (MMU available):** Full process isolation (seL4 capability pattern)
**MPU abstraction** should follow RTEMS `armv7-pmsa.h` pattern:
```c
void uos_mpu_write_region(uint32_t index, uintptr_t base, size_t size, uint32_t attrs);
void uos_mpu_enable(void);
void uos_mpu_disable(void);
uint32_t uos_mpu_find_region(uintptr_t addr, uint32_t start);
```
### 6.3 Context Switch Pattern
**For Cortex-M (no MMU, PendSV):** Use ThreadX/NuttX PendSV pattern — hardware saves half the context automatically.
**For Cortex-A/R (MMU/MPU, IRQ):** Use seL4/NuttX trap handler pattern — save all registers on kernel stack, switch stack pointer + page tables.
**For RISC-V (all modes):** Follow seL4's `src/arch/riscv/traps.S` pattern — save all CSRs + registers.
**Minimal context (Cortex-M):** ~68 bytes (17 words) — R4-R11, SP, LR, PC, xPSR, BASEPRI, EXC_RETURN + optional FPU (132 bytes for S0-S31+FPSCR)
**Full context (Cortex-A):** ~72 bytes (18 words) + FPU (256 bytes for D0-D31) + VFP regs
### 6.4 Kernel Primitive Naming Convention
Based on the audit, the `uos_*` naming should follow this pattern:
```c
// Tasks/Threads
uos_task_create(), uos_task_delete(), uos_task_suspend(), uos_task_resume()
uos_thread_create() (for pthread-like)
// Scheduling
uos_sched_yield(), uos_sched_set_priority()
// Synchronization
uos_sem_create(), uos_sem_wait(), uos_sem_post()
uos_mutex_create(), uos_mutex_lock(), uos_mutex_unlock()
uos_event_create(), uos_event_wait(), uos_event_set()
// IPC
uos_mq_create(), uos_mq_send(), uos_mq_receive()
uos_endpoint_send(), uos_endpoint_recv() // seL4-style synchronous
// Memory
uos_mem_alloc(), uos_mem_free()
uos_mpu_set_region(), uos_mpu_enable()
// Context
uos_context_switch(), uos_context_init()
```
### 6.5 Guest RTOS Personality Layer
To host FreeRTOS, ThreadX, Zephyr, Mbed as guests, create thin wrappers:
```c
// FreeRTOS personality: wraps uos_task_create -> xTaskCreate
// ThreadX personality: wraps uos_task_create -> tx_thread_create
// Each personality provides the exact API the guest expects
// All call uos_* primitives underneath
```
---
*Generated from deep audit of `/home/fabiorafaelcoutada/portugalfuturista/rtos_ref/{seL4,threadx,nuttx,rtems}/`*