Architecture
The trona tree at a glance
| Directory | Lines | Role |
|---|---|---|
|
8,875 |
|
|
2,475 |
Shared kernel↔userland sources (no crate; included via |
|
6,927 |
|
|
2,679 |
|
|
2,417 |
|
|
4,209 |
Two freestanding C dynamic linkers — |
|
56 |
|
Three of those directories produce Rust crates that get merged into libtrona.so; the rest produce independent binaries (ld-trona.so, ld-trona-pe.so, kernel32.dll) or are consumed verbatim via include!.
The three crates that make libtrona.so
┌──────────────────────────────────┐
│ libtrona.so (PIC DSO) │
│ │
│ libtrona.o ← trona │
│ libtrona_posix.o ← trona_posix │
│ libtrona_loader.o ← trona_loader│
│ fork.o ← fork.S │
│ libcore.o ← Rust core │
│ libcompiler_builtins.o │
└──────────────────────────────────┘
▲
│ include! (verbatim)
│
┌──────────────────────────────────┐
│ lib/trona/uapi/ │
│ consts/ protocol/ types/ │
└──────────────────────────────────┘
The dependency direction inside libtrona.so is strict:
uapi ──include!──> trona (substrate)
▲
│ extern crate
│
├── trona_posix
│
└── trona_loader
-
trona_posixdeclaresextern crate trona;and consumes substrate’s IPC, invoke, and types modules. -
trona_loaderdeclaresextern crate trona;andextern crate trona_posix;because parts of the loader (notably the scratch-map strategy) callposix_mmapvia substrate IPC. -
Nothing in substrate depends on
trona_posixortrona_loader. Substrate is the leaf.
substrate — the 18 modules
substrate/lib.rs declares exactly 18 pub mod:
| Module | Lines | Purpose |
|---|---|---|
|
196 |
Inline-assembly syscall wrapper. Single polymorphic |
|
483 |
The nine IPC primitives ( |
|
689 |
Typed capability invocation helpers grouped by object type (CNode, Untyped, TCB, VSpace, IRQ, IoPort, SchedContext, MemoryObject). Every helper calls |
|
17 |
Pure re-export shim: |
|
40 |
Pure re-export shim: |
|
16 |
Pure re-export shim: |
|
260 |
Diagnostic serial output. |
|
729 |
Multi-segment bump allocator for CNode slots, with a global spinlock, |
|
59 |
One function — |
|
456 |
Child process VA and CSpace layout planner. Computes |
|
312 |
Startup capability table. Builder used by procmgr; reader used by rtld to walk the role → slot table from |
|
126 |
Safe getters ( |
|
1,150 |
Futex-based synchronization primitives — |
|
788 |
Thread-local storage and thread identity. |
|
1,094 |
Worker thread pool and event loop used by every SaltyOS server — |
|
206 |
|
|
84 |
Character case folding entry points used by basaltc’s locale layer. |
|
1,471 |
Unicode case folding lookup table. Generated from |
Module groupings
The 18 modules cluster into seven logical groups. The groups match the page layout of the substrate Overview and the rest of the substrate section.
| Group | Modules |
|---|---|
Kernel entry (syscall + IPC + invoke) |
|
UAPI shims |
|
Capability allocation and lookup |
|
Synchronization |
|
Threads, TLS, server event loop |
|
Layout and environment |
|
Diagnostics and data tables |
|
Everything that is not a shim produces a clear artifact in the _trona* C ABI surface exported by substrate/lib.rs, which is how C code (basaltc, rtld’s own symbol exports, and freestanding init tasks) talks to substrate.
trona_posix — 13 files that delegate to substrate
trona_posix is a flat crate — no subdirectories beyond arch/ for the per-architecture fork.S.
| File | Lines | Purpose |
|---|---|---|
|
644 |
Module declarations, global signal state ( |
|
965 |
POSIX thread lifecycle — |
|
892 |
Process management — |
|
753 |
File I/O — |
|
731 |
Sockets — |
|
587 |
Miscellaneous — |
|
441 |
|
|
394 |
DNS client — |
|
386 |
POSIX signals — |
|
207 |
Multiplexing — |
|
206 |
Internal-only bulk SHM transfer path used by |
|
190 |
Memory management — |
|
123 |
Pipes and descriptor duplication — |
|
110 |
POSIX-facing TLS accessors — |
Plus posix/arch/x86_64/fork.S (154 lines) and posix/arch/aarch64/fork.S (129 lines) — the assembly fork trampolines covered in fork.S and Linker Scripts.
trona_loader — six files
| File | Lines | Purpose |
|---|---|---|
|
21 |
Module declarations and |
|
753 |
ELF64 loader — scratch-map strategy, ET_EXEC and ET_DYN (PIE) support, in-place RELATIVE relocations, frame allocation by scanning untyped capabilities. |
|
434 |
Helpers to inspect PT_INTERP and DT_NEEDED, plus |
|
1,067 |
PE32+ loader — DOS / PE / optional header validation, section loading, |
|
10 |
Re-exports |
|
394 |
CPIO newc (magic |
A second CPIO parser lives in kernite (kernite/src/cpio.rs).
The two are intentionally separate: the kernel parser runs before memory management is initialized and cannot share code with userspace, while the loader parser runs in a normal userland context and uses u64 / usize from core.
rtld — two freestanding C linkers
lib/trona/rtld/ contains two completely independent dynamic linkers.
Neither one links against libtrona.so (they are what actually loads libtrona), so both are built freestanding — no libc, inline syscalls, and their own self-contained ELF or PE parsers.
| Subtree | Contents |
|---|---|
|
Five C source files ( |
|
|
The ELF rtld page walks through the full initialization sequence; the PE rtld page does the same for the shorter PE path.
kernel32.dll and the trona_win32 Rust source
The lib/trona/win32/ directory contains two kinds of code that are easy to confuse:
kernel32_pe.c(1,503 lines, C)-
A real PE/COFF Windows DLL built by
clang --target=<arch>-w64-windows-gnuand linked withlld-link -dll -def:kernel32_pe.def. It exports the Win32 API surface (CreateFileA,ReadFile,WriteFile,GetStdHandle,WriteConsoleA/WriteConsoleW,ExitProcess,GetLastError, …) that PE binaries import. This is the single artifact that PE binaries on SaltyOS actually link against at runtime. lib.rs,console.rs,handle.rs,error.rs,process.rs,crt.rs,paths.rs,protocol.rs(914 lines, Rust)-
A Rust crate declared as
trona_win32with a complete module tree and detailed doc comments. It is not currently built by anymeson.buildtarget — neitherlib/trona/meson.buildnor any userlandmeson.buildcompiles these files. The code is present as design intent for a future Rust-side Win32 layer and is documented on the trona_win32 overview page under that framing.
For the currently shipping PE pipeline, the only code that matters is kernel32_pe.c + kernel32_pe.def, which is documented in kernel32.dll PE Stub.
uapi — the kernel↔userland contract
lib/trona/uapi/ is not a crate.
It is a tree of .rs files pulled into substrate verbatim by substrate/consts.rs, substrate/protocol.rs, and substrate/types.rs using the include! macro.
uapi/
├── README.md ← stability notes
├── meson.build ← install-only, no compilation
├── consts/
│ ├── kernel.rs ← syscall numbers, invoke labels, error codes, auxv tags, roles, object types
│ ├── posix.rs ← O_*, S_*, AF_*, POLL*, SIG*, etc.
│ └── server.rs ← server-side extended errors, spawn policy flags
├── protocol/
│ ├── vfs.rs ← VFS server IPC labels
│ ├── procmgr.rs ← Process manager IPC labels
│ ├── mmsrv.rs ← Memory manager IPC labels
│ ├── namesrv.rs ← Name service IPC labels (currently minimal)
│ ├── posix.rs ← POSIX personality shared labels
│ ├── win32.rs ← Win32 personality labels
│ ├── server.rs ← Generic server / driver labels
│ └── rsrcsrv.rs ← Resource server labels
└── types/
├── core.rs ← TronaResult, TronaMsg, IpcBuffer, cap layout descriptors, ELF types
├── posix.rs ← POSIX-facing #[repr(C)] types (PosixStat, SigAction, SockAddr, RLimit, …)
└── pe.rs ← PE/COFF headers used by the loader and PE rtld
Because uapi is not compiled on its own, its headers never produce object files: every uapi definition that matters is baked into libtrona.o via the substrate include! shims.
This means adding a syscall number only touches uapi/consts/kernel.rs and the kernite side — substrate picks it up on the next build automatically.
The Syscall ABI, Invoke Labels, IPC Protocol Labels, and Error Codes pages are the reader-facing references over this tree.
Architecture-specific pieces
The substrate crate has no architecture subdirectories at all.
Every arch-specific decision (register assignment for syscalls, size of the fork-trampoline save area, SIMD feature flags) is made by inline cfg(target_arch = "x86_64") / cfg(target_arch = "aarch64") blocks or by the build system passing different --cfg flags.
The only files that are physically per-architecture are:
-
lib/trona/posix/arch/x86_64/fork.S(154 lines) andlib/trona/posix/arch/aarch64/fork.S(129 lines) — the fork trampoline, documented in fork.S and Linker Scripts. -
lib/trona/arch/x86_64/libtrona.ldandlib/trona/arch/aarch64/libtrona.ld— the linker scripts used when producinglibtrona.so. -
lib/trona/rtld/elf/arch/x86_64/andlib/trona/rtld/elf/arch/aarch64/— the per-arch rtld helpers (rtld.ld,rtld_reloc_types.h,rtld_syscall.h,rtld_resolve.S). -
lib/trona/rtld/pe/arch/x86_64/andlib/trona/rtld/pe/arch/aarch64/— the matching linker scripts for the PE rtld.
Everything else is architecture-neutral Rust, branched inline via cfg.
Related pages
-
Build System — how the three crates,
fork.o, the rtld binaries, andkernel32.dllall get produced. -
substrate Overview — module-by-module walk through the 18 files in
substrate/. -
Reading the trona Tree — a source-tree tour aimed at first-time contributors.