SexOS · Standard Operating Procedure

Server Refactor Template

Canonical procedure for modifying SexOS server processes. Follow this exactly. Deviations cause kernel panics.

MISSION

Describe the task — e.g., "add blur support to sexdisplay", "wire silknet tray applet", "implement PDX_GET_CPU_USAGE".

Environment (Never Violate)

ConstraintRule
no_std, no libc, no alloc unless already presentNever use std::*, never println!, never thread::spawn
SASOS — single shared address spaceNo pointer is "foreign"; PKU enforces isolation, not page tables
PDX IPC onlyCross-PD calls via pdx_call(slot, opcode, arg0, arg1, arg2); replies via pdx_reply(caller_pd)
MPK/PKU isolationNever touch another PD's pages without explicit PageHandover + pku_grant_temporary
Only the compositor writes the framebufferAll other servers send PDX draw commands to sexdisplay
No heap unless the server already uses Vec/BoxPrefer [T; N] arrays and AtomicU64 statics
No POSIX time / sleep / blocking syscallsSpin on pdx_listen_raw(slot); use core::hint::spin_loop()
Deterministic, no UB, zero warnings#[deny(warnings)] implied
PIE — no absolute symbol assumptionsNever hardcode VAs except documented constants (e.g. HHDM_OFFSET)

Pre-Flight Checklist (Run Before Any Change)

  1. Understand the PD topology. Which PDs talk to which? Draw the PDX call graph.
  2. Verify PKU keys. Which PKEY owns which memory? Check kernel/src/memory/pku.rs.
  3. Check capability grants. Does the target PD already have the caps it needs?
  4. Read the relevant lib.rs. Understand the existing PDX dispatch table before adding opcodes.
  5. Confirm no_std compatibility. Run cargo +nightly check --target x86_64-sex.json -Z build-std=core,alloc.

Patch Protocol

  1. One concern per patch. Never mix PDX opcode additions with rendering changes.
  2. Add opcodes at the end. Never renumber existing PDX opcodes — other PDs depend on them.
  3. Document the struct ABI. Every PDX call payload must have a #[repr(C)] struct with explicit field sizes.
  4. Test with QEMU. make run-sasos before claiming completion.
  5. Preserve PKU invariants. After your change, sexdisplay must still be write-locked from kernel (PKEY 1).

Common Patterns

Adding a PDX Opcode

// 1. Define the opcode constant
pub const PDX_MY_NEW_FEATURE: u64 = 0x50;

// 2. Define the request/response structs
#[repr(C)]
pub struct MyFeatureRequest {
    pub param1: u64,
    pub param2: u32,
}

#[repr(C)]
pub struct MyFeatureResponse {
    pub result: u64,
}

// 3. Add to the dispatch table in handle_pdx_call()
match opcode {
    // ... existing opcodes ...
    PDX_MY_NEW_FEATURE => {
        let req: &MyFeatureRequest = unsafe { &*(arg0 as *const _) };
        let resp = MyFeatureResponse { result: do_work(req) };
        pdx_reply(caller_pd, &resp);
    }
    _ => { /* unknown opcode */ }
}

Lending Memory Between PDs

// NEVER: direct pointer sharing
// let ptr = some_other_pd_address; // ← KERNEL PANIC

// ALWAYS: explicit PageHandover
let cap = PageHandover::new(source_pd, dest_pd, phys_addr, num_pages);
capability_table.grant(dest_pd, cap);
pdx_call(dest_slot, PDX_MEMORY_LENT, &cap);

Event Loop Template

#![no_std]
#![no_main]

use sex_pdx::{pdx_listen_raw, pdx_reply};
use core::hint::spin_loop;

#[no_mangle]
pub extern "C" fn _start() -> ! {
    // Register with kernel
    let slot = pdx_register(PD_ID, PKEY);

    loop {
        match pdx_listen_raw(slot) {
            Some(msg) => {
                handle_message(msg);
            }
            None => {
                spin_loop(); // Yield without blocking
            }
        }
    }
}
Remember

SexOS is a Single Address Space. All pointers are valid everywhere. PKU, not page tables, enforces isolation. The compositor owns the framebuffer. PDX is the only IPC mechanism. There is no std, no libc, and no POSIX. You are programming bare metal.