p1, p2) scheduled by a round-robin IRQ-driven scheduler alongside the OS process (p0).
Layers
The system is organized into three layers that map directly to the source tree:| Layer | Source | Role |
|---|---|---|
| Boot / low-level | root.s | Vector table, _start, IRQ handler, context save/restore, yield, PUT32/GET32 |
| OS kernel | os.c, scheduler.c, process.c | Process initialization, round-robin scheduler, main() loop |
| Platform drivers | uart.c, timer.c, watchdog.c | Hardware peripherals, abstracted via plataform.h |
| User processes | User/p1/, User/p2/ | Application code linked into separate RAM regions |
Component diagram
Memory spaces
Each entity in the system has its own RAM region enforced by the linker script. There is no MMU — isolation is purely by convention.BeagleBone Black
| Region | Origin | Length | Purpose |
|---|---|---|---|
os_ram | 0x82000000 | 256 KB | OS .text, .data, .bss, IRQ stack, OS SVC stack |
p1_ram | 0x82100000 | 64 KB | P1 .p1_text, .p1_data, .p1_bss |
p1_stack | 0x82110000 | 4 KB | P1 SVC stack |
p2_ram | 0x82200000 | 64 KB | P2 .p2_text, .p2_data, .p2_bss |
p2_stack | 0x82210000 | 4 KB | P2 SVC stack |
QEMU (versatilepb)
| Region | Origin | Length | Purpose |
|---|---|---|---|
os_ram | 0x00010000 | 64 KB | OS .text, .data, .bss, IRQ stack, OS SVC stack |
p1_ram | 0x00060000 | 64 KB | P1 code and data |
p1_stack | 0x00070000 | 4 KB | P1 SVC stack |
p2_ram | 0x00080000 | 64 KB | P2 code and data |
p2_stack | 0x00090000 | 4 KB | P2 SVC stack |
The IRQ stack (4096 bytes, defined in
root.s as irq_stack: .space 4096) lives inside os_ram in .bss. It is separate from the SVC stack used by the OS main loop.Execution flow
Key design decisions
No MMU / no virtual memory
No MMU / no virtual memory
The Cortex-A8 MMU is never enabled. Each process runs in its physical address region established by the linker. There is no page table, no TLB management, and no fault handler beyond a hang loop.
No system calls (SWI unused)
No system calls (SWI unused)
The
swi_handler in root.s simply branches to hang. Processes do not call into the OS through a syscall gate. The yield function is a direct call from user code — compiled into the same flat binary — that manually saves context and invokes schedule().Flat address space with linker-enforced separation
Flat address space with linker-enforced separation
All code — OS, p1, p2 — lives in a single ELF binary linked together. Separation is enforced entirely by the linker script: p1 code must be placed in
.p1_text sections, p2 code in .p2_text sections. KEEP() directives prevent the linker from discarding these sections during dead-code elimination.Platform abstraction via compile-time defines
Platform abstraction via compile-time defines
Hardware base addresses (UART0, timer, interrupt controller) are not hardcoded in driver source. They are injected as
-D flags at compile time. The Makefile reads .venv.beagle or .venv.qemu depending on the TARGET variable and passes every address as a PLATFORM_* define consumed by plataform.h.Two ARM mode stacks
Two ARM mode stacks
ARM banked registers mean IRQ mode and SVC mode each have their own
sp and lr. root.s initializes both: _irq_stack_top for IRQ mode and _stack_top for SVC mode. Context save/restore must temporarily switch to SVC mode to read or write sp_svc and lr_svc of the interrupted process.Hardware peripheral addresses
The following addresses are injected as compile-time defines by the Makefile from the platform.venv files.
BeagleBone Black
| Peripheral | Address | Define |
|---|---|---|
| UART0 | 0x44E09000 | PLATFORM_UART0_BASE |
| DMTimer2 | 0x48040000 | PLATFORM_TIMER_BASE |
| INTC | 0x48200000 | PLATFORM_INTC_BASE |
| CM_PER | 0x44E00000 | PLATFORM_CM_PER_BASE |
QEMU (versatilepb)
| Peripheral | Address | Define |
|---|---|---|
| UART0 | 0x101f1000 | PLATFORM_UART0_BASE |
| SP804 Timer | 0x101e2000 | PLATFORM_TIMER_BASE |
| VIC | 0x10140000 | PLATFORM_INTC_BASE |
| CM_PER | 0x00000000 | PLATFORM_CM_PER_BASE (unused) |