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)
| Constraint | Rule |
|---|---|
| no_std, no libc, no alloc unless already present | Never use std::*, never println!, never thread::spawn |
| SASOS — single shared address space | No pointer is "foreign"; PKU enforces isolation, not page tables |
| PDX IPC only | Cross-PD calls via pdx_call(slot, opcode, arg0, arg1, arg2); replies via pdx_reply(caller_pd) |
| MPK/PKU isolation | Never touch another PD's pages without explicit PageHandover + pku_grant_temporary |
| Only the compositor writes the framebuffer | All other servers send PDX draw commands to sexdisplay |
No heap unless the server already uses Vec/Box | Prefer [T; N] arrays and AtomicU64 statics |
| No POSIX time / sleep / blocking syscalls | Spin on pdx_listen_raw(slot); use core::hint::spin_loop() |
| Deterministic, no UB, zero warnings | #[deny(warnings)] implied |
| PIE — no absolute symbol assumptions | Never hardcode VAs except documented constants (e.g. HHDM_OFFSET) |
Pre-Flight Checklist (Run Before Any Change)
- Understand the PD topology. Which PDs talk to which? Draw the PDX call graph.
- Verify PKU keys. Which PKEY owns which memory? Check
kernel/src/memory/pku.rs. - Check capability grants. Does the target PD already have the caps it needs?
- Read the relevant
lib.rs. Understand the existing PDX dispatch table before adding opcodes. - Confirm
no_stdcompatibility. Runcargo +nightly check --target x86_64-sex.json -Z build-std=core,alloc.
Patch Protocol
- One concern per patch. Never mix PDX opcode additions with rendering changes.
- Add opcodes at the end. Never renumber existing PDX opcodes — other PDs depend on them.
- Document the struct ABI. Every PDX call payload must have a
#[repr(C)]struct with explicit field sizes. - Test with QEMU.
make run-sasosbefore claiming completion. - 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.