Developer Guide
This page provides concrete procedures for extending the kernel. Each section lists every file that must be modified, in the order modifications should be applied.
Adding a New System Call
Syscall numbers are sequential.
The next available number follows the last entry in the Syscall enum.
Files to Modify
-
kernite/src/syscall/mod.rs-
Check the
Syscallenum inkernite/src/syscall/mod.rsfor the next available slot, then add a variant with that number. -
Add the variant to the
TryFrom<u64>implementation. -
Add a dispatch arm in
syscall_handle_rust()that handles the new number.
-
-
lib/trona/uapi/consts/kernel.rs-
Add a matching constant (e.g.,
pub const SYS_MY_NEW_CALL: u64 = N;whereNis the slot identified above).
-
-
lib/trona/substrate/syscall.rs-
Add a raw inline-assembly syscall wrapper function that userspace calls.
-
-
docs/spec/syscalls.md-
Document the syscall number, arguments, return values, and error codes.
-
-
docs/spec/abi.md(if the ABI changes)-
Update register conventions if the new syscall uses a non-standard argument layout.
-
Checklist
-
Enum variant and
TryFrominsyscall/mod.rs -
Dispatch arm in
syscall_handle_rust() -
Matching constant in
uapi/consts/kernel.rs -
Raw wrapper in
substrate/syscall.rs -
Spec documentation updated
-
just buildsucceeds -
just run— new syscall reachable and returns expected results -
just run --smp 2— verify no SMP regression
Adding a New Capability Invocation
Invoke labels are grouped by object type.
Each group has a reserved range (e.g., CNode 0x10-0x18, TCB 0x40-0x4F).
Files to Modify
-
lib/trona/uapi/consts/kernel.rs-
Add the invoke label constant in the appropriate group (e.g.,
pub const TCB_MY_OP: u64 = 0x50;). -
Ensure the label does not collide with existing labels in the same range.
-
-
kernite/src/syscall/mod.rs-
Add a dispatch arm in
handle_invoke()under the matchingObjectTypecase. -
Implement the operation logic (or call a helper function in the object’s module).
-
-
lib/trona/substrate/invoke.rs-
Add a typed wrapper function that constructs the IPC message and calls
sys_invoke().
-
-
Protocol file (if the invocation is a server-facing IPC label, not a kernel object operation):
-
Add the label to the appropriate
lib/trona/uapi/protocol/*.rsfile.
-
Label Range Conventions
| Object Type | Range |
|---|---|
CNode |
|
Untyped |
|
SchedContext |
|
TCB |
|
VSpace |
|
IRQ |
|
IoPort |
|
MemoryObject |
|
VSpace MO mapping |
|
Label 0x97 is a shared dispatch point: when invoked on a MemoryObject cap it dispatches as MO_HAS_PAGE; when invoked on a VSpace cap it dispatches as VSPACE_MAP_MO. Type-based dispatch is the mechanism — the label value alone does not determine the operation.
|
Adding a New Kernel Object Type
This is a rare, high-impact change.
Files to Modify
-
kernite/src/cap/object.rs-
Add a variant to
ObjectTypewith the next available discriminant.
-
-
kernite/src/cap/refcount.rs-
Add a destruction case in
destroy_object()for the new type.
-
-
kernite/src/cap/untyped.rs-
Add a size computation case in
object_size(). -
Add an initialization case in
init_object(). -
If the object needs metadata arrays (like Frame, VSpace, Untyped), add array allocation in
init_metadata().
-
-
lib/trona/uapi/consts/kernel.rs-
Add
pub const OBJ_MY_TYPE: u64 = N;matching the discriminant.
-
-
kernite/src/syscall/mod.rs-
Add invoke dispatch cases for the new object’s operations.
-
Adding a New Userland Program
Subsystem-specific services use dedicated paths. POSIX services go under servers/posix/; Win32 services go under servers/win32/. The userland/<domain>/<name>/ layout below applies to subsystem-agnostic or test programs.
|
Files to Create
-
userland/<domain>/<name>/src/main.rs-
![no_std]and![no_main]. -
Entry point via trona substrate (
_start→main).
-
-
userland/<domain>/<name>/arch/x86_64/link.ldandarch/aarch64/link.ld-
Linker scripts (copy from an existing program like
test_runner).
-
-
userland/<domain>/<name>/meson.build-
Build definition (copy pattern from
userland/tests/test_runner/meson.build).
-
-
userland/services/<name>.service-
Service descriptor:
[Service](name, binary, type, restart policy) and[Dependencies](After/Before ordering).
-
Files to Modify
-
userland/meson.build-
Add
subdir('<domain>/<name>').
-
-
tools/mkcpio.py-
Add the ELF binary and service file entries to the initrd manifest.
-
Build
After adding all files:
just distclean && just setup && just build
The find command in kernite/meson.build auto-discovers .rs source files only during meson setup.
New source files require a full reconfigure.
Adding a New Subsystem Personality Server
A subsystem personality server provides the runtime environment for a specific ABI family (e.g., POSIX, Win32).
-
Choose the placement path. POSIX personality servers go under
servers/posix/. Win32 personality servers go underservers/win32/. -
Register the subsystem ID. Add the subsystem ID constant to
lib/trona/uapi/consts/kernel.rs(e.g.,pub const SUBSYSTEM_MY_PERSONALITY: u64 = N;). The kernel’s procmgr uses this ID to select the personality server for new processes. -
Create the service file. Add a
.servicedescriptor underuserland/services/that declares the server’s binary, type, and a[Dependencies]block withAfter=procmgr.service(and any other personality-specific prerequisites). -
Wire into procmgr dispatch. In the procmgr server, add a dispatch arm that routes new-process requests carrying the subsystem ID to this server.
Adding a New Kernel Source File
-
Create the
.rsfile in the appropriatekernite/src/subdirectory. -
Add
mod my_module;to the parent module’smod.rsorlib.rs. -
Reconfigure:
just distclean && just setup && just build.
No Cargo.toml modifications — this project does not use Cargo.
Adding Architecture-Specific Code
Pattern
Architecture-specific code lives under kernite/src/arch/x86_64/ and kernite/src/arch/aarch64/.
Generic code consumes it through re-exports in arch/mod.rs.
To add a new architecture-specific function:
-
Implement in both
arch/x86_64/<module>.rsandarch/aarch64/<module>.rs. -
Add
pub usere-exports inarch/mod.rsunder the appropriate#[cfg(target_arch)]blocks. -
Generic code calls
crate::arch::my_function().
Build System Notes
-
All Rust code is compiled via Meson with direct
rustcinvocation — no Cargo. -
Rust flags live in
meson.build, not.cargo/config.toml. -
Kernel uses custom JSON target specs (
kernite/x86_64-saltyos.json,kernite/aarch64-saltyos.json). -
Userland uses built-in rustc targets (
x86_64-unknown-saltyos,aarch64-unknown-saltyos) from the custom toolchain. -
Clang is enforced — gcc will not work.
Related Pages
-
Syscall ABI — syscall numbers and register conventions
-
Capability Invocations — invoke label ranges
-
Object Model — kernel object types and lifecycle
-
Architecture — module map and architecture abstraction