Phase 50
IPC Completion
m3OS gains the missing IPC and bulk-data pieces required for serious userspace services: safe capability transfer, practical large-payload transport, ring-3-safe service registration, and clear failure semantics for the canonical server loop.
Learning goal
Understand why control flow and bulk-data transport must be designed together in a microkernel-style system.
Category
infrastructure
Components touched
Builds on
Unlocked by this phase
Why this phase matters
m3OS gains the missing IPC and bulk-data pieces required for serious userspace services: safe capability transfer, practical large-payload transport, ring-3-safe service registration, and clear failure semantics for the canonical server loop.
How it works in m3OS
Phase 50 finishes the IPC transport model that Phase 6 introduced as a control-path-only design. The kernel now supports safe capability transfer between process capability tables, a two-tier bulk-data mechanism (validated copy for small payloads, page grants for large transfers), ring-3-safe service registration with owner tracking and re-registration, and documented server-loop failure semantics. These additions close the gap between the existing message-passing infrastructure and the requirements of real ring-3 services.
How it builds on earlier phases
This phase builds on Architectural Declaration and turns that foundation into IPC Completion.
Implementation outline
- Audit current IPC shortcuts and identify every service path that still depends on shared kernel addresses.
- Finish and document the capability-grant semantics.
- Implement the generic bulk-data transport model and its ownership rules.
- Remove kernel-only assumptions from the service registry and service-address paths.
- Standardize the canonical server loop and service-death semantics.
- Port at least one real service path to the new transport as proof.
- Extend validation so later extraction phases can depend on this transport with confidence.
Task progress snapshot
134 of 134 tracked tasks are complete.
Documentation targets
- Documentation deliverables have not been listed yet.
Deferred follow-on work
- Deep performance tuning of zero-copy paths
- Rich typed service IDLs or code-generated message bindings
- Advanced delegation patterns beyond the basic capability and buffer model
Source materials
Important code
Code spotlight cards
Code spotlight
Enumerate kernel-pointer shortcuts in IPC service syscalls
Enumerate kernel-pointer shortcuts in IPC service syscalls. Why it matters: The safety comments at ipc_register_service (line 229) and ipc_lookup_service (line 254) explicitly state that name pointers are dereferenced as raw kernel addresses because all callers are kernel tasks — this assumption must be catalogued before it can be removed. Focus on `ipc_register_service` and `ipc_lookup_service` in `kernel/src/ipc/mod.rs` while you trace the snippet.
/// Syscall 9: register a named endpoint in the service registry.
///
/// `name_ptr` is a userspace virtual address pointing to `name_len` bytes of
/// UTF-8. The name is safely copied from the caller's address space via
/// `copy_from_user`. Invalid or unmapped pointers return an error.
fn ipc_register_service(ep_id: EndpointId, name_ptr: u64, name_len: u64) -> u64 {
if name_ptr == 0 {
return u64::MAX;
}
if name_len > 32 {
return u64::MAX;
}
let name_len = name_len as usize;
let mut name_buf = [0u8; 32];
if crate::mm::user_mem::copy_from_user(&mut name_buf[..name_len], name_ptr).is_err() {
return u64::MAX;
}
let name = match core::str::from_utf8(&name_buf[..name_len]) {
Ok(s) => s,
Err(_) => return u64::MAX,
};
match registry::register(name, ep_id) {
Ok(()) => 0,
Err(_) => u64::MAX, Code spotlight
Write failing tests for capability grant through IPC messages
Write failing tests for capability grant through IPC messages. Why it matters: TDD requires failing tests before implementation — the grant path must verify that a capability can be atomically moved from one table to another without duplication or loss. Focus on `CapabilityTable::grant` and `kernel-core` in `kernel-core/src/ipc/capability.rs` while you trace the snippet.
/// Atomically transfer a capability from `self[source_handle]` to `dest_table`.
///
/// On success the source slot is cleared and the new handle in the
/// destination table is returned. On failure (invalid source handle or
/// destination table full) the source retains its capability and an error
/// is returned — no side effects.
pub fn grant(
&mut self,
source_handle: CapHandle,
dest_table: &mut CapabilityTable,
) -> Result<CapHandle, CapError> {
// Validate source handle first, without removing yet.
let cap = self.get(source_handle)?;
// Try to insert into destination — if it fails, source keeps the cap.
let dest_handle = dest_table.insert(cap)?;
// Destination succeeded — now remove from source (infallible since we
// already validated the handle above and hold &mut self).
let _ = self.remove(source_handle);
Ok(dest_handle)
} Code spotlight
Extend Message to carry a capability slot
Extend Message to carry a capability slot. Why it matters: The current Message struct has no field for capability transfer — services cannot exchange authorities through the existing message format. Focus on `Message` and `new` in `kernel-core/src/ipc/message.rs` while you trace the snippet.
/// A small, register-sized IPC message.
#[derive(Debug, Clone, Copy, Default)]
pub struct Message {
/// Operation identifier, chosen by convention between sender and receiver.
pub label: u64,
/// Inline data payload — up to 4 machine words.
pub data: [u64; 4],
/// Optional capability transferred with this message.
pub cap: Option<Capability>,
} Key files
- kernel/Cargo.toml — When the phase lands, bump kernel/Cargo.toml and any release/version references to 0.50.0.
- kernel/src/ipc/mod.rs — copy_from_user in register/lookup, sys_cap_grant
- kernel/src/main.rs — | console_server_task write payload | kernel/src/main.rs | 350–361 | Still uses copy_nonoverlapping — kernel-task shortcut; migration planned for ring-3 move |
- kernel/src/mm/user_mem.rs — copy_from_user / copy_to_user implementations
- kernel-core/src/ipc/capability.rs — CapabilityTable::grant, Capability::Grant variant
- kernel-core/src/ipc/message.rs — Message.cap field, updated constructors
- kernel-core/src/ipc/buffer.rs — validate_user_buffer pure-logic address checks
- kernel-core/src/ipc/registry.rs — Owner-tracked registry, replace_service, capacity 16
- kernel/src/ipc/endpoint.rs — Capability transfer during message delivery
- kernel/src/arch/x86_64/syscall/ipc.rs — IPC syscall dispatch module
How real OSes differ
- Mature microkernels often invest heavily in message layout, grant semantics, and zero-copy transport much earlier.
- Monolithic kernels avoid some of this design pressure by keeping drivers and services in one address space, at the cost of a larger TCB.
- m3OS should favor a clear, teachable, reusable transport contract over premature optimization.
Success criteria
- Capabilities can be granted safely and atomically between isolated processes.
- There is a documented and implemented bulk-data path suitable for storage, packet, and framebuffer-sized transfers.
- Core service registration no longer relies on kernel-task-only assumptions.
- At least one representative service path uses the new transport without kernel-pointer shortcuts.
- The IPC docs and validation coverage describe the same control flow and failure semantics the code actually implements.
Related phases
Keep exploring the roadmap
Phase 49
CompleteArchitectural Declaration
m3OS gains an explicit, enforceable architecture contract for what belongs in ring 0, what is transitional, and what must move to userspace over time. The phase also turns the giant syscall surface into a structure that can be unwound safely in later phases.
Phase 51
CompleteService Model Maturity
m3OS turns its new service-management baseline into a reliable lifecycle model: boot ordering is explicit, restart semantics are trustworthy, shutdown behavior is deterministic, logs are coherent, and extracted ring-3 services can plug into the same operator workflow instead of inventing their own.