First Contribution

This page walks you through a small, self-contained change to the kernel: adding a new debug syscall that returns the number of free physical frames. By the end, you will have modified the kernel, the userland library, and verified the result.

What We Will Build

A new syscall SYS_DEBUG_FREE_FRAMES (number 31, the next unused slot in the Syscall enum) that returns the current count of free physical frames. This is a read-only, side-effect-free operation — safe to add and easy to verify.

Step 1: Add the Syscall to the Kernel

1a. Add the enum variant

Open kernite/src/syscall/mod.rs and find the Syscall enum. Add a new variant at the end:

pub enum Syscall {
    // ... existing variants ...
    NotifReturn = 27,
    ThreadExit = 28,
    SysInfo = 29,
    SysMemInfo = 30,
    DebugFreeFrames = 31,  // ← add this
}

1b. Add the TryFrom mapping

In the same file, find the TryFrom<u64> for Syscall implementation. Add the new mapping:

31 => Ok(Syscall::DebugFreeFrames),

1c. Add the dispatch handler

In syscall_handle_rust(), add a match arm:

Syscall::DebugFreeFrames => {
    let free = crate::mm::pmm_free_count() as u64;
    SyscallResult { error: 0, value: free }
}

That is the entire kernel change. Three lines of new code.

Step 2: Add the Userland Constant

Open lib/trona/uapi/consts/kernel.rs and add:

pub const SYS_DEBUG_FREE_FRAMES: u64 = 31;

Step 3: Add the Userland Wrapper

Open lib/trona/substrate/syscall.rs and add a wrapper function:

pub fn sys_debug_free_frames() -> u64 {
    let result = syscall0(SYS_DEBUG_FREE_FRAMES);
    result.value
}

syscall0 is the existing helper that invokes a syscall with no arguments.

Step 4: Build and Test

# Rebuild (kernel source file already exists, no distclean needed)
just build

# Run
just run

To test, you can add a call in the test runner or any userland program:

let free = trona::syscall::sys_debug_free_frames();
trona::println!("Free frames: {}", free);

The output should show a number like 12345 (depending on your system’s RAM and current usage).

What You Just Learned

This small exercise touched every layer of the kernel:

  1. Syscall dispatch (syscall/mod.rs) — how the kernel routes syscall numbers to handlers.

  2. PMM API (mm/) — how the kernel queries internal state.

  3. UAPI constants (lib/trona/uapi/) — how kernel and userland agree on syscall numbers.

  4. Trona substrate (lib/trona/substrate/) — how userland invokes raw syscalls.

Next Steps: Bigger Contributions

Now that you understand the flow, here are ideas for more substantial contributions:

Add a capability invocation

Follow the Developer Guide to add a new invoke label. For example: TCB_GET_STATE that returns the current thread state.

Add a test module

The test runner (userland/tests/test_runner/) has 16 test modules. Add a new module that tests your new syscall or exercises an existing feature.

Fix a bug

Look at the serial output during boot. If you see warnings or unexpected behavior, investigate:

  1. Read the relevant source code.

  2. Add DebugPutStr calls to trace execution.

  3. Use just run --gdb to attach a debugger.

Port a library

The Developer Guide explains how to add new userland programs. The ports system (ports/) can build third-party software for SaltyOS.

Code Style Reminders

Before submitting:

  • just fmt-check passes.

  • just build succeeds with no new warnings.

  • just run boots without panics.

  • just run --smp 2 does not deadlock.

  • Every unsafe {} block has a // SAFETY: comment.

  • New constants are defined in both kernel and lib/trona/uapi/consts/kernel.rs.

  • Commit message follows conventional commits: feat(syscall): add DebugFreeFrames syscall.

Where to Get Help

  • Read the Architecture page for the module map.

  • Read the Glossary for unfamiliar terms.

  • Read the source code — it is well-commented with // SAFETY: and doc comments.

  • Check the Developer Guide for step-by-step procedures.