- Rust 100%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
Merge the selected feature/native-cli history with an explicit two-parent commit so main retains the development lineage and the validated source snapshot. The resulting tree is identical to the selected feature commit; no dependency pins or runtime behavior are changed by this merge. Previous main: |
||
| .github | ||
| src | ||
| .editorconfig | ||
| .gitignore | ||
| .markdownlint-cli2.yaml | ||
| ARCHITECTURE.md | ||
| Cargo.toml | ||
| CODE_OF_CONDUCT.md | ||
| CONTRIBUTING.md | ||
| LICENSE | ||
| linker.ld | ||
| README.md | ||
| ROADMAP.md | ||
| rustfmt.toml | ||
| SECURITY.md | ||
EriX Kernel
kernel is the policy-minimal microkernel core in the EriX boot chain.
EriX is a clean-room, capability-based microkernel operating system written entirely in Rust.
Technical requirements are tracked in the EriX requirements, conventions, and project documentation.
See:
- docs for design documents, specifications, and development plans.
- Related architecture repositories for kernel, services, libraries, drivers, and integration tooling.
Purpose of This Repository
The existing time-control endpoint returns boot-calibrated processor elapsed time in nanosecond ticks, never query-count progress. Its source is anchored once on the bootstrap CPU; unsynchronized AP reads, missing calibration, counter reversal and conversion overflow fail with zero response metadata. This does not add time authority or widen the current BSP-local userspace scheduling domain.
Caller-local syscall 0x49 derives a revocable SEND-only endpoint alias from
an already-owned exact SEND endpoint. It accepts only two distinct empty local
destinations, never a target process or foreign CSpace. The revoker follows
the derived alias through normal copies and IPC replies, but cannot revoke
the original source. Existing staged install and staged revocation guards
continue to reject started targets.
Read-only syscall 0x4A exposes only the live actual caller of a delivered
pending CALL to its authenticated recorded receiver with local RECV authority.
Its process ID and generation match staged-process creation evidence; forwarded
SEND aliases do not impersonate their original holders. The query consumes no
pending state and grants no capability or process-discovery authority.
This repository implements the EriX kernel component. Its purpose in EriX is to provide the minimal capability kernel substrate for user-space services.
Functionally, it owns kernel memory, scheduling, interrupt, and capability primitives while keeping policy in user space. The repository keeps the implementation, interface contracts, tests, and documentation for that behavior in one reviewable ownership boundary.
The maintained responsibilities are:
- provide process, memory, interrupt, IPC, and capability primitives
- keep policy in user-space services wherever possible
- maintain the system-call and authority boundaries used by the rest of EriX
Clean-Room Policy
EriX follows a strict clean-room philosophy:
- No external source code may be copied.
- No external Rust crates are allowed.
- No code generation tools that embed third-party code.
- All code must be authored within the project.
Violations will result in rejection of the contribution.
License
All EriX repositories are licensed under the ISC License.
Development Model
EriX development is modular, deterministic, reproducible, authority-explicit, security-first, and self-hosting oriented.
This repository follows the project roadmap and the validation rules documented in its own roadmap.
Build Status
Current implementation status:
- strict
bl -> kernelingress wrapper and deterministic kernel markers - length-delimited bootloader handoff ingress whose externally supplied byte length must equal the serialized header length before variable tables are parsed
- memory reservation extraction and usable-RAM extent derivation
- bootstrap object/capability setup for root CSpace/VSpace/TCB/endpoint and the single RAM allocator domain
kernel -> roothandoff builder withlib-handoffvalidation roundtrip- default kernel bootstrap path selects required root module and attempts CPL3 root launch
- root launch records required boot-provided metadata blobs as read-only root
VSpace grants so
rootdcan validateboot-config, dynamic-link manifests, and early dynamic object bundles before filesystem services exist - a dedicated, non-delegatable root endpoint performs one no-input retirement of that exact kernel-recorded boot-blob set: all page-table preparation precedes PTE retirement and TLB invalidation, while rootd's executable image remains mapped and catalog/table/endpoint sources are consumed. The dedicated console endpoint may transfer exact read-only font backing to fbcond; root access is still removed and no unrelated VSpace inherits that backing
- bootloader dynamic catalog ingress validation enumerates signed boot-image executables, shared objects, segment permissions, source ranges, hashes, and dependency edges before root startup; catalog and mapping records grow from reclaiming kernel-reserved memory instead of imposing parallel object, segment, shared-backing, or process-mapping caps
- early ELF graph discovery also stores program-load records, dependency offsets, and discovered objects in fallible heap collections, so valid dependency graphs are constrained only by explicit identifier/address-space bounds and available kernel-owned memory
- root handoff bytes are copied into a zeroed, page-aligned, exact-span heap allocation rather than a fixed 64 KiB static buffer; root receives read-only access to those pages, while its independently allocated bootstrap stack is the only writable launch region; both grants are represented in VSpace metadata, nested syscall pointers are accepted only through those explicit rights, and launch failure revokes every registered range before releasing storage; serialization checks every wire-width conversion and reserves the complete output fallibly
- memory-map reservations and RAM extent subtraction grow through checked kernel-heap reservations, so valid firmware maps neither reach allocation abort paths nor disappear behind an implementation-specific record ceiling
- production catalog installation is one-shot, mapping storage is reserved before page/backing mutation, relocation metadata commits only after its VSpace write, and process cleanup revokes mapped pages before forgetting their records or shared-backing references
- VSpace objects, aliases, explicit user/physical ranges, and device-frame bindings all grow fallibly from reclaiming kernel memory; released VSpace identifiers are reused, and record/capability creation rolls back atomically on failure instead of imposing bootstrap-era table ceilings; mapping, kernel-owned user-range, and physical-range authority cannot overlap
- per-page VSpace mapping records use dense 256-entry chunks rather than a geometrically growing flat allocation, so staging large ext4-backed dynamic executables never requires old and doubled mapping tables to coexist in the kernel heap; each mapping-data allocation is bounded to 20 KiB and teardown still retires every exact page record and backing reference
- activation/restoration traverse read-only chunk slices directly, retaining pending updates across storage chunks and ignoring reserved empty chunks. Every live mapping check, permission barrier, 64-update boundary and error remains ordered; neither chunk boundaries nor traversal create authority, additional flushes or persistent mapping state
- mapping tables retain one last-full-search index for fresh validation/copy cursors, checked against the live bound and exact page under the existing VSpace lock. Only a first-match scan replaces this table-owned hint; mutable record access, removal, and clear invalidate it, while local/neighbor cursor hits retain their original behavior. New/cloned tables start cold, and rights, ownership, and backing are never cached. Host lookup tests and an explicit bounded cost experiment do not establish a guest speedup
- managed frames of at most 64 aligned pages select their lowest unused page in the same current-mapping pass that searches for an existing exact virtual address, using a temporary occupancy bitmap. An existing address retains first-match priority; a new-page selection error remains deferred until the original overlap and storage-reservation checks. Exact frame identity and physical address remain authoritative; aliases share occupancy, holes are reused, and no bitmap survives the call. Larger or noncanonical allocations retain the original selection/error path; device frames, rights checks, backing retention, and page-table policy are unchanged. The allocator-domain selftest adds a private 64-page alias/full/ hole-reuse proof with physical byte readback and exact cleanup before its managed-frame success marker. Host tests are not a VM speedup claim
- physical-page and anonymous-shadow VSpace switches apply up to 64 exact mappings
per interrupt-masked page-table batch, with local TLB flushing even on
preparation failure and explicit invalidation of GLOBAL translations. Aliases
preserve their original flag/backing policy; dependent backing translations
or repeated targets start a new flushed group to retain sequential semantics.
Exact group-local target lookup and borrowed prepared leaves avoid repeated
prefix scans and whole-array copies without caching authority.
Strictly ascending targets, including gaps, avoid hashing: contiguous prior
addresses use an exact interval; in-range backings after a gap use binary
search of the actual prior targets. Duplicate/decreasing targets retain the
original lookup path, without changing any dependency or flush boundary.
Activation/restoration builders select their constant mode once while still
reading every live mapping's rights, backing and saved entry.
Inlined hardware preparation removes per-leaf aggregate return shuffling
while preserving the same live reads, group boundaries, and flushes.
Bounded staging initializes only the used prefix of
Copyleaves and reads it only after every preparation succeeds, removing redundant empty tags. Partial failure never reads that prefix and retains the existing flush; host trace/codegen evidence is not matching-image performance acceptance. A staged leaf keeps its complete entry and exact target address, using only the validated address's zero bit 0 for old-or-new GLOBAL invalidation. The hardware key is checked non-null when resolving a new PT span; neither pointer bits nor authority are encoded in the address flag. Independent untagged-oracle tests cover address/entry integrity and ordered failures. Group-local target and non-huge backing PT-span hints avoid repeated ancestor walks while every leaf and alias backing remains live and exact; each flush discards both hints. The immutable update slice is validated once before entering the lock, with no skipped per-record permission or backing checks - permission-only ranges resolve one PT span per pass instead of one ancestor walk per leaf, preserving whole-range preflight and sparse absent mappings. Success/error synchronization finishes before lock/interrupt restoration; visited GLOBAL leaves are invalidated even after ancestor-only promotion
- the opt-in
kernel-mapping-batch-selftestverifies actual scratch-page remapping, read/write flags, GLOBAL-cache replacement, and complete backing restoration plus anonymous alias dependencies before its kernel-only VM exit. Permission probes cover PT boundaries, absent leaves, and a real GLOBAL write after parent permission promotion under CR0.WP - its sparse-target extension checks actual alias reads/writes, unchanged gap
pages, GLOBAL replacement, user-access revocation and exact restoration;
ERIX_KERNEL:MAPPING_BATCH_SPARSE_OKfollows private scratch cleanup. These bounded cost refinements have host-oracle and generated-code coverage; rebuilt-image hardware/performance acceptance remains separate and pending - multi-page mapping validation and copying use operation-local index hints with exact page/rights/backing revalidation under the VSpace lock; sequential forward or backward pages avoid repeated full-table scans without caching authority or changing whole-range preflight and overlapping-copy behavior. Successful preflight retains its first page index for copying, avoiding a duplicate initial scan. The copy pass reacquires the lock and authorizes every live page again; no mapping, rights or backing result survives the lock
- the physically ordered managed-frame registry uses fallibly allocated 256-entry chunks as well, so crossing 32,768 ext4-executable pages cannot demand a contiguous doubled frame table from a fragmented kernel heap; alias, mapping-reference, exact-range reuse, and cleanup rules are unchanged
- multi-page user-permission changes prepare page-table structure in one locked pass and apply leaf flags in a second locked pass, so switching a large process never allocates rollback storage proportional to its image span
- early dynamic mapping now reuses immutable shared-object backing by object
hash and segment identity, keeps writable/zero-fill relocation state private
per process, preserves exact ELF segment virtual starts even when a segment
begins inside an aligned page, rejects text relocations, and exposes only
process-control kernel ops
39..41for manifest-bounded map/apply/seal requests; each VSpace grows its mapping metadata from kernel-reserved memory instead of rejecting a valid image at a per-address-space page ceiling, and anonymous backing pages return to the reclaiming kernel heap on unmap, aborted launch, final-capability drop, or process teardown - dynamic
rootdbootstrap can create the initial root address space from the signed boot dynamic catalog, materialize executable and dependencyPT_LOADpages in the root VSpace, map and relocate required shared objects before root entry, seal the mappings, and clean up all partial user mappings on bootstrap failure without granting object-store authority - pre-
procddynamic service launch now uses the same catalog-bound mapping surface formemd,vspaced,pagerd, andprocd, with kernel-owned child mappings, private relocation state, explicit endpoint authority, and cleanup of partial process/VSpace state on failure; duplicate inactive cleanup is a no-op, and inactive VSpace teardown cannot clear the active root VSpace's overlapping user leaves - operator evidence records the kernel as a dynamic
ET_DYNartifact entered aterix_dynlink_entry, validates the boot catalog handoff before root startup, and keeps early service dynamic-link failures separate from bootloader kernel-link, bootloader catalog,dynlinkd, and ordinary service failures - runtime replies to pending calls are written through the caller TCB's tracked VSpace, so service replies to dynamically spawned processes do not depend on the current server address space
- a runtime reply may write that VSpace only while the exact caller generation
remains nonterminal. A killed, exited, missing, or recycled caller retires
the stale call with
NOT_FOUNDbefore caller-buffer sizing, payload writes, or caller wakeup. A terminal caller therefore cannot strand an accepted call merely because its response is larger than the retired request buffer; only a caller still blocked on that call is woken - capability-transfer, process-creation, device-frame, VSpace, and dynamic-map rollbacks revoke every derived authority before returning; an impossible rollback failure is a kernel invariant violation and therefore fail-stops instead of continuing with residual authority
- x86_64 user-permission changes split inherited huge mappings before touching a leaf, enforce read-only versus writable intent at that leaf, and allocate required page-table pages fallibly instead of using fixed split pools; this prevents a narrow launch range from exposing neighboring kernel pages
- capability-transfer delivery preserves a kernel-normalized receipt table,
rejects destinations outside the receiver's immutable CSpace window, and
records the rights actually installed so services can reject and revoke
every unwanted alias; occupied destinations return terminal
CONFLICTwithout consuming the live receive rendezvous, while rendezvous backpressure remains retryableBUSY - the memory-control endpoint may drop caps in the caller's allowed local slot
range, enabling
memdto release allocator-owned frame caps without gaining broader kernel-control authority - RAM-frame allocation atomically selects a page-granular, caller-constrained subrange inside any extent of the delegated allocator domain, installs a frame with the requested attenuated rights, and returns the kernel-selected physical range; callers cannot nominate physical addresses or create unbacked ordinary frames
- before installing the new frame capability, allocation clears the complete selected RAM range through a transaction-local, supervisor-only mapping. The mapping borrows one page from the reclaiming kernel heap, restores that page's original backing before release, and exposes neither stale bytes nor a fixed scratch virtual-address reservation to the recipient
- ordinary frame aliases and VSpace mappings share one kernel-tracked backing
identity; each mapping is an explicit lifetime reference, so deleting the
final frame alias cannot invalidate a live mapping. The exact physical
subrange returns to the allocator domain only after both aliases and mappings
are gone, while
DEVICE_FRAMEmappings remain a separate explicit path - the focused RAM allocator-domain VM self-test proves that every authenticated extent names one exact manage-only capability, then exercises a three-page alignment, copied-alias lifetime, final-alias deletion, and exact physical-range reuse before root launch without leaving test capabilities installed
- the kernel binary now exports
erix_dynlink_entryas the stable dynamic entry symbol for the generated kernelET_DYNartifact; its SysV64 v2 contract receives the handoff pointer inrdiand exact byte length inrsi, and the keep marker lives in data so the true dynamic relink does not need text relocations whilekernel_entryremains the internal implementation entry - runtime endpoint path no longer synthesizes non-root service replies in normal builds; service interactions use endpoint queue/call-recv-reply mechanics
- runtime replies prefer their completed blocked caller when no follow-up call remains; only an actual queued call defers that caller so the replying server can drain the endpoint, and application payloads do not alter this rule
- transfer-bearing runtime replies now also require
GRANTon the replying endpoint slot itself, so capability materialization stays explicit in the sender's local policy instead of being inferred from endpoint receipt - page-fault delivery now targets a kernel-retained endpoint object whose sole
userspace receive binding is moved to
pagerd; process registration carries no endpoint slot, and faulting children receive no pager endpoint capability - a queued page-fault notification revalidates that endpoint's recorded
receive binding and immediately prefers its live pager. If the pager is
blocked on a separate empty receive, the kernel cancels only that receive and
wakes it with
RETRY; endpoint identities and capability inventories do not change - page-fault delivery is limited to non-present user accesses and contains one architecture-independent read, write, or execute value; protection, reserved-bit, protection-key, shadow-stack, SGX, supervisor, contradictory, and unknown fault classes are terminated in the kernel
- process-event delivery now targets the stable endpoint identity that procd
explicitly registers through its process-control endpoint; registration
requires the caller's TCB-bound
RECVcapability, so an exiting child's CSpace is never consulted for wake authority - terminal process cleanup and explicit removal of a recorded receiver's final
live receive binding retire that exact endpoint, complete outstanding callers
with
NOT_FOUND, and clear queued state so neither IPC work nor reply authority survives the receiver - exit and kill are a single-winner TCB transition: the first terminal action
publishes the generation's only process event, while a later managed kill
returns
NOT_FOUNDwithout changing the original state or status - root-process
process_exitexhaustively clears the complete root CSpace after retiring its recorded receiver and before publishing the terminal event; a focused kernel test proves both an empty capability snapshot andNOT_FOUNDwakeup of a caller blocked on that receiver - transfer-bearing runtime calls still require a live receive rendezvous for
capability materialization; if a sender reaches the endpoint first, the
endpoint retains only the waiting sender identity and first prefers its
already-bound receiver so that the exact receive can be armed, never a
residual cap or queued transfer table; non-blocking
RECVreportsBUSYwhile this rendezvous is pending, and the timed receive then prefers the sender to complete delivery - a non-blocking
RECVthat cannot dequeue observes transfer-waiter liveness under that same endpoint lock, avoiding a second capability/binding lookup solely for advisoryBUSYversusRETRY. Existing generation/liveness checks still clear stale waiters. Blocking registration retains its second live lookup; no endpoint hint, epoch, cache, or new authority is retained - reply scheduling makes completed callers runnable without preempting the replying process; within the handoff quantum, a sole completed caller is next at the server's cooperative boundary while previously committed work remains deferred, and an actual queued endpoint call keeps the server's drain work ahead without decoding service-specific results
- additional callers queued behind an outstanding auxiliary-endpoint call
retain its recorded receiver preference, just like the first queued call;
live generation, CSpace, endpoint binding, and
RECVrights are revalidated without changing receive retirement or capability-transfer rendezvous - preferential CALL, exact reply, and pending-wake selections share a budget of eight handoffs across blocking and voluntary-yield boundaries; a CALL/reply pair uses two. The next selection follows the persistent round-robin cursor without losing pending work. Only a successful ordinary selection resets this budget, including when the exact caller is the only runnable peer. Short RPC chains avoid unrelated address-space switches, while other tasks receive a bounded cooperative fairness turn, not a wall-clock guarantee
- voluntary yields honor existing receiver and pending-wake preferences too,
including a transfer-bearing caller retrying
BUSYbefore its receiver arms a rendezvous. Exact replies remain first; absent or ineligible pending work falls back to ordinary selection, and all paths share the same eight budget - calls through send aliases whose receiver has retired fail with
NOT_FOUNDuntil a nonterminal replacement explicitly holds the endpoint's receive authority; a live receiver blocked on an outbound RPC remains a valid queue owner, while stale aliases cannot accumulate unserviceable work - x86_64 syscall entry now switches to a kernel-owned stack before saving the full resume frame, copies blocked-task frames into per-TCB kernel storage, and records the return user RSP explicitly so user-stack page faults cannot turn syscall delivery or trap-side scheduler switches into residual stack authority; TCB identifiers, runtime records, saved frames, process events, scheduler contexts, and runnable entries grow fallibly from reclaiming kernel memory instead of imposing bootstrap-era object or queue ceilings
- ACPI LAPIC discovery, SMP bring-up records, AP bootstrap stacks, and scheduler per-CPU state follow the same topology-sized fallible policy. Duplicate LAPIC identities are rejected, the actual BSP is normalized to slot zero, and sparse failed/offline slots remain explicit so AP trampoline indices cannot acquire another CPU's scheduler state; xAPIC IPI destinations are width-checked so x2APIC IDs cannot silently alias low-numbered CPUs
- runtime preemption keeps the raw LAPIC one-shot interval separate from the scheduler accounting-tick quantum. AP accounting workers use calibrated processor-clock deadlines instead of polling the global scheduler lock without a bound
- INIT/SIPI spacing, ICR dispatch, AP-online observation, scheduler attachment, and development UART polling use elapsed processor-clock deadlines derived from the bootloader's explicitly firmware-calibrated handoff value. Their behavior no longer changes with host CPU speed, and missing or conflicting clock metadata is an explicit failure instead of an undocumented spin ceiling or an implicit kernel timer-device acquisition
- endpoint objects, capability aliases, queued messages, pending callers, and install-grant records likewise grow fallibly from reclaiming kernel memory; queued payloads reserve only their actual byte length, released endpoint and grant identifiers are reusable, and partial allocation or cap-install failures leave neither a runtime record nor residual capability authority
- CSpace records also grow from reclaiming kernel memory and allocate slot
storage only through their highest installed capability;
lib_capabi::CSPACE_SLOT_COUNT_V1defines the addressable CSpace ABI namespace, not a global object-table reservation - every authenticated usable-RAM extent belongs to one manage-only capability
at
SLOT_RAM_ALLOCATOR; extent count is bounded only by reclaiming kernel memory, and MMIO authority remains on the separate device-frame path CAP_TYPE_DEVICE_FRAMEis now a first-class capability type distinct from ordinary RAM frames, and the kernel-control path can derive one validated BAR-backed MMIO frame fordevicedwithout exposing a generic device-memory escape hatch- feature-gated, root-only host-report kernel-control endpoint
(
kernel-rootd-runtime) for deterministic VM completion:- accepts only
IPC_KERNEL_CONTROL_OP_REPORT_HOST_EVENTon its dedicated endpoint object - the endpoint is installed only in rootd's initial CSpace; ordinary processes receive neither this endpoint nor an ambient reporting syscall
- accepts
ROOTD_STAGE:*progress events and emits deterministic stage markers without exiting - rootd ready ->
0x10 - rootd internal failure/unknown status ->
0x13 - downstream service bootstrap failure ->
0x14
- accepts only
kernel-rootd-smoke-testadds the VM-only debug-exit terminal to the same explicit endpoint path used by smoke and negative integration scenarios; when combined withkernel-runtime-image, it does not disable normal runtime SMP discovery, AP bring-up, or per-processor scheduler counterskernel-integration-runtime-quietis a VM-fixture-only refinement of that smoke build. It suppresses repetitive successful demand-fault, process-exit, event-queue, endpoint-retirement, lifecycle-wake, and rootd/logd reply debug projection while leaving process state, event delivery, cleanup, selected focused evidence, and the final host-report terminal unchanged.kernel-integration-stress-quietis the compatibility alias used by older exact-lifecycle fixture builders; it implies the general runtime-quiet refinement and grants no behavior or authority of its own.- rootd host events include a failure-only
ERIX_KERNEL:ROOTD_WARN:*diagnostic family for late bootstrap triage; these markers do not authorize extra kernel output paths and remain gated by the runtime-report surface - pre-module rootd failures decode a stable numeric boundary step through that same diagnostic family; the decoder does not add a route or capability
- runtime/appliance kernel builds enable
kernel-runtime-imagewithoutkernel-rootd-smoke-test; deterministic debug-exit remains an integration harness opt-in, not part of packaged runtime images - normal runtime builds seed only the narrow preinstalled runtime endpoints; the generic procd driver-lifecycle and loader-materialization routes are distinct endpoint objects, and no broad compatibility endpoint or reserved root slot exists
- dev-profile early console feature (
kernel-dev-console) validates and caches one PF2 index, then mirrors kernel markers to the framebuffer vialib-consoleuntil rootd submitsROOTD_REPORT_STAGE_FBCOND_READYthrough its host-report endpoint - the capability-gated console mapping records the exact boot framebuffer range and applies an explicit x86_64 write-combining PAT policy; ordinary physical mappings retain write-back semantics
- runtime can retire the kernel framebuffer mirror separately at fbcond handoff, then disable early kernel serial/log output after direct userspace sinks are available
- disabled kernel direct-log IPC requests are denied and retained as in-memory warning records without reusing the retired serial/framebuffer output path; the kernel control ABI has no raw serial-write operation, and remaining COM1 writes are internal debug-serial mirroring behind retained-log control markers
- retained early kernel logs split messages longer than one IPC log chunk into
sequential in-memory records instead of truncating the tail before
logdtakes them; the single-consumer queue grows fallibly from kernel-owned memory, has no fixed record ceiling, and releases its allocation when drained - centralized-process-authority deep runtime trace families stay smoke-only, so ordinary appliance dev/release images do not emit ad-hoc staged lifecycle or capability-trace chatter
- direct syscall/save/switch, IPC call/reply, process-yield, and
memory-provider trace probes sit behind the opt-in
kernel-verbose-tracefeature, keeping default VM images on readiness/failure evidence instead of staged-create, capability-copy, demand-fault, and hot-path serial chatter - the narrow integration-only
kernel-rtc-startup-tracereports whether an RTC startup call was delivered directly to an already blocked receiver or queued for the bound child; it observes scheduling without changing delivery order or adding an endpoint, capability, or runtime input, and it does not enable the broader IPC-block trace families - the completed call-first scheduling fixture is absent: retained serial evidence proves ordinary queued CALL admission, reply, provider exit, and subsequent rootd progress, so every kernel build keeps normal scheduler policy and the remaining RTC trace is observation-only
- successful rootd transport polling and procd receive/reply iterations emit no boot-report code; terminal transport and reply failures remain observable
- bootstrap pager faults emit
ERIX_KERNEL:BOOTSTRAP:FAULT_*diagnostics only when resolution fails; successfully delegated and resolved demand faults stay silent - runtime images suppress successful per-block virtio-block read trace chatter while preserving request/status failures and higher-level storage readiness evidence
- runtime IPC reply sizing is derived only from the generic IPC envelope and caller buffer; the kernel does not decode service-specific reply bodies
- completed
CALLsyscalls return the exact encoded reply length inrdxfor both queued service replies and immediately dispatched kernel-control replies, so callers can validate only initialized response bytes - rootd stage-marker mapping includes input readiness stages (
DRV_I8042_READY,DRV_PS2_KEYBOARD_READY,DRV_PS2_MOUSE_READY,INPUTD_READY,INPUT_ROUTING_READY,CONSOLE_INPUT_READY) - rootd stage-marker mapping now also includes the current filesystem slice
(
MEMORY_PROVIDER_READY,VFSD_READY,VFS_MOUNT_READY,VFS_IO_READY) - rootd runtime report decoding recognizes the expanded VFS backend operation
debug family (
rename,truncate,symlink,readlink,link, and metadata update) so diagnostics remain non-terminal during filesystem API verification - rootd stage-marker mapping now also includes storage bring-up (
BLOCKD_READY,STORAGE_READY) - rootd stage-marker mapping now also includes Filesystem provider work
filesystem providers, private key service, and program-loader service
(
KEYD_READY,E2FSD_READY,FATD_READY,LOADERD_READY,DYNLINKD_READY) - Phase 5 post-mount reporting recognizes
POWERBOXD_READY,TTYD_READY,LAUNCHD_READY, andRTC_PROVIDER_COMPLETE; these remain explicit root-only host-report events and do not grant runtime services kernel-report authority - kernel-control op
READ_PLATFORM_CAPS(26) exposes deterministic platform-presence bits for probe-gated driver activation - kernel-origin failure class is
0x12in kernel binary integration flow - scheduler, SMP, exception, and simultaneous interrupt-line delivery and acknowledgement selftests remain behind explicit integration-only feature flags
- scheduler/SMP selftests cross the retired 64-LAPIC, 64-CPU, 16-stack, and 16-scheduler-slot ceilings and verify sparse online topology indexing
- the online-topology helper is compiled only for its global-scheduler selftest or production runtime SMP callers; CI separately builds coherent bring-up, failed-AP, global-scheduler and runtime profiles with warnings denied
- runtime IPC dispatch now enforces endpoint send/recv rights:
CALL/NOTIFYrequireSENDRECV/REPLYrequireRECV
- timed runtime
CALLs remember the exact TCB that last received or polled each endpoint, allowing a multi-endpoint server to wake while blocked on a different endpoint without inferring a receiver by scanning CSpaces; the recorded stage generation and live receive capability are revalidated before every wake - syscall return now preserves the user return RIP/RFLAGS on the kernel syscall stack across dispatch and trace hooks, and last-binding endpoint teardown drops heap-backed queued message and caller state without constructing large transient endpoint objects or retaining payload storage
- kernel-control slot arguments used by process/capability operations are now constrained to the caller-visible process window
- kernel-control op
QUERY_CAP(29) now exposes local capability type/rights for startup-time authority inventory checks without opening foreign-slot visibility - kernel-control op
QUERY_CAP(29) now also supports opt-in endpoint-kind reporting viaIPC_KERNEL_CONTROL_QUERY_CAP_FLAG_INCLUDE_ENDPOINT_KIND, with the upper 32 bits ofvalue1carrying endpoint kind while non-endpoint caps reportGENERIC/0 - kernel-control op
CREATE_ENDPOINT(30) now materializes a fresh send/recv generic IPC endpoint in one caller-local slot; bootstrap uses the dedicatedCHILD_POPULATEfamily, while vfsd receives a distinctENDPOINT_FACTORYfamily that permits only creation and attenuated copying. Callers cannot select or mint a kernel-control endpoint family - caller-local syscall
SAME_ENDPOINT_OBJECT(0x48) compares two endpoint capabilities already visible to the current process and returns only one boolean. It exposes no kernel endpoint identifier and creates no authority - controlled user page aliases now allocate missing x86_64 page-table levels for anonymous materialized child mappings, so filesystem-backed dynamic images are not constrained to virtual ranges already covered by the kernel identity map
- x86_64 page-table walkers use a supervisor-only recursive PML4 window rather than dereferencing physical frame addresses through an assumed low-memory identity mapping, including when runtime table pools reside above 1 GiB
- kernel-control fast-path dispatch is now keyed by the endpoint object's stored
family kind rather than by canonical slot numbers: the optional test-only root
endpoint retains the full kernel-operation surface when enabled, while normal
runtime boot seeds
rootdwith the dedicated log endpoint plus the narrow runtime endpoint inventory: the dedicatedtimedendpoint at slot2128accepts onlyREAD_MONOTONIC_CLOCKand localQUERY_CAP - the dedicated
irqdendpoint at slot2144accepts only interrupt wait, acknowledgement, and line configuration; capability inspection uses the caller-local syscall instead of widening this endpoint - kernel interrupt events carry line, CPU, and a nonzero per-line sequence only; the kernel retains no unused timestamp, and pending lines are selected in round-robin order so repeated timer delivery cannot starve COM1
- the dedicated
hotplugdendpoint at slot2160accepts only hotplug-event wait plus localQUERY_CAP - hotplug event retention grows fallibly from kernel-owned heap memory and reports storage or sequence-namespace exhaustion; it no longer silently drops events after an eight-record implementation limit
- the dedicated platform-discovery-read endpoint at slot
2176accepts onlyREAD_PLATFORM_CAPSandREAD_PCI_CONFIG_DWORD; it carries no local capability-query authority - the dedicated console endpoint at slot
2192accepts only framebuffer/font query/map operations, the fbcond probe verifier, and localQUERY_CAP - the dedicated COM1 endpoint at slot
2208accepts onlyIOPORT_READ8,IOPORT_WRITE8, and localQUERY_CAP, with hardware-port policy restricted to0x3F8..=0x3FF - the private RTC endpoint at slot
3000is narrower than generic byte I/O: it reads only data port0x71and writes only an NMI-preserving, closed set of wall-clock/status register selectors to index port0x70; writes to CMOS data and reads of unrelated CMOS storage cannot be expressed - the dedicated memory endpoint at slot
2224accepts onlyALLOCATE_RAM_FRAMEand localQUERY_CAP; allocation accepts an explicit RAM allocator cap, destination slot, size, alignment, and frame rights, while the kernel alone selects the physical subrange. Transient scheduler or rendezvous backpressure remainsBUSY/RETRY, while permanent RAM-domain or kernel-heap exhaustion isRESOURCE_EXHAUSTED; development runtime images also retain the exact kernel error marker for allocator-failure diagnosis, without exposing another endpoint operation or capability. The managed-frame registry remains ordered by physical address, so first-fit selection scans it directly and does not require heap-backed transaction scratch storage. After the development console is ready, an actual kernel-heap allocation failure reports the requested size/alignment and total/largest free block internally.ERIX_KERNEL_RESERVED_HEAP_BYTESselects page-aligned kernel-private storage at build time; the selected extent is part of the authenticated kernel image, not a service record limit or authority delegated from usable RAM - the dedicated vspace endpoint at slot
2240accepts onlyMAP_FRAME,UNMAP_FRAME, and localQUERY_CAP - the dedicated pager endpoint at slot
2256accepts onlyRESOLVE_FAULTand localQUERY_CAP. Smoke-test images retain the faulting TCB, pending/requested pages, run state, and saved instruction/stack pointers when resolution fails, without widening the pager endpoint or exposing those diagnostics in a runtime image - the dedicated log/query endpoint at slot
2272accepts onlyQUERY_CAP,LOG_STRING, andTAKE_EARLY_LOG, which narrows runtime logging to the generic retained-log path. Each successful take consumes the oldest record, so no cursor retains already-transferred kernel storage. Long messages are committed atomically across sequential records. Nested log input/output pointers are validated across the complete current-VSpace range for their exact read or write rights before dereference. No raw serial-write IPC path exists, and the internal debug COM1 mirror is not service-callable.LOG_STRINGacknowledgesOKonly after that bounded mirror commits the complete line; transient UART backpressure returnsRETRY - the dedicated query endpoint accepts only
QUERY_CAP, which lets services validate caller-local caps without inheritingLOG_STRINGor early-log reads - the endpoint-factory endpoint at slot
2400accepts onlyCREATE_ENDPOINTandCAP_COPY_ATTENUATED; it cannot inspect foreign slots, populate a staged child, install a grant, or drop unrelated capabilities - the dedicated process-control endpoint at slot
2288accepts only the bounded process and attenuated-capability lifecycle operations thatprocduses, including an exact process/generation CPU-time query; unrestricted local copy and move operations are absent, and returned nanoseconds carry no authority - the dedicated ACPI RSDP endpoint at slot
2320accepts onlyGET_ACPI_RSDP; platform-capability, table-memory, and local-capability reads are not bundled into that authority - the dedicated i8042 endpoint at slot
2336accepts onlyIOPORT_READ8,IOPORT_WRITE8, and localQUERY_CAP, with hardware-port policy restricted to0x60and0x64 - canonical boot-root slot numbers no longer imply authority in non-root CSpaces; runtime policy follows the endpoint kind or cap actually installed in the caller's local slot, and services consume only their explicit local startup transfers instead of inferring access from slot numbers
- syscall
QUERY_LOCAL_CAP(0x45) now exposes the same caller-local slot type/rights introspection path to peer-only services that do not carry a kernel-control endpoint, and on x86_64 it now returns additive endpoint-kind metadata inr8 - syscall
DROP_LOCAL_CAP(0x47) now lets callers clear one caller-local slot directly so fixed-slot peer bindings can be dropped before retrying late rematerialization - syscall slot checks now require a valid current TCB; absent or invalid caller attribution is denied instead of falling back to root CSpace authority
- syscall dispatch rejects every non-zero reserved register; reply and notify reject the unused timeout position, and cooperative yield also requires an attributable current TCB
- bootstrap/root CSpace capacity is now
4096slots so explicit local slots in the extended startup-transfer range remain representable without falling back to shared canonical windows - runtime TCB records now carry private CSpace/VSpace identities, and kernel slot lookup resolves against the current process CSpace rather than a single shared runtime slot table; each registered TCB retains only its VSpace lifetime, not map or management authority, until terminal process teardown
- endpoint capability copy/move/drop now preserves endpoint-object identity
across multiple local slots:
- copied endpoint caps alias the same endpoint runtime queue
- dropping one alias removes only that slot binding
- kernel-control family dispatch follows the endpoint object, so a copied local control slot keeps the same bounded policy surface as the canonical control endpoint it aliases
- kernel-control op
CAP_COPY_ATTENUATED(31) now installs explicit rights-reduced local aliases, whichrootduses to materialize startup control, driver-lifecycle, and loader-materialization slots instead of treating transfer descriptors as metadata only - runtime IPC now supports explicit capability transfer tables on
CALL,REPLY, andNOTIFYmessages when the sender's endpoint cap carriesGRANT - IPC syscalls take one exact-size, fallibly allocated snapshot of caller bytes before parsing or transfer application. They no longer construct a maximum-envelope scratch array on the kernel stack or duplicate that snapshot during preparation
- the syscall boundary checks the caller's current VSpace over the full buffer
capacity:
CALLrequires read/write,RECVwrite, andREPLY/NOTIFYread access. Root and ordinary users follow the same policy before endpoint or control handling. Snapshot creation copies the 40-byte generic header once and only its declared body for valid envelopes; malformed and raw messages retain their full-buffer fallback, with unchanged capability checks - delayed reply/receive delivery rechecks live target write authority for the exact payload before copying. A raw root-bootstrap fallback additionally requires registered writable user ranges; a failed tracked-backing lookup never grants raw access, and no unused response-capacity tail is exposed
CAP_TYPE_INSTALL_GRANTis now implemented in-kernel for staged child population, andSTART_PROCESSis denied while live grants still target the child stageCAP_TYPE_REVOCATION_GRANTis a distinct manage-only, move-only kernel object. It follows every kernel-derived alias of one installed child capability, revokes all surviving aliases when deleted, and cannot revoke a later same-slot replacement after the original lineage disappears- kernel-control ops
CREATE_STAGED_PROCESS (32),DERIVE_INSTALL_GRANT (33),INSTALL_WITH_GRANT (34), andABORT_STAGED_PROCESS (35)now provide private-child creation and scoped startup-cap installation - kernel-control op
INSTALL_WITH_REVOCATION_GRANT (45)atomically installs one attenuated child capability and creates its separate revocation grant; failure leaves both destination slots empty - staged child creation now emits the same
ERIX_KERNEL:HARDWARE:CSPACE_WINDOW_SETsmoke marker as the explicit window-setting control path, so integration validation observes child-window establishment independent of which kernel entrypoint performed it - the obsolete direct process-creation operation has been removed; staged child creation is the only process-construction path
- TCB endpoint and pager registration now validate the target process's private CSpace instead of assuming the caller's current CSpace
- kernel-control op
KILL_PROCESS(28) provides explicit managed-stop support forprocd; an already-terminal target returnsNOT_FOUNDand cannot acquire a second terminal event - kernel-control op
WRITE_PROCESS_MEMORY(38) copies caller bytes only into already mapped anonymous child process pages, allowingprocdto populate file-backed loader images without accepting caller-selected frame or VSPACE authority; it validates the complete readable caller range and complete anonymous child range before streaming, with no page-sized call ceiling or partial destination write when a later page is absent - default smoke images suppress successful per-chunk process-memory and
per-page VSPACE mapping traces;
kernel-verbose-traceretains those diagnostics without making large filesystem-launched services miss the VM readiness deadline - inactive staged anonymous mappings may be sealed from writable staging rights to final executable rights before first activation; live mappings still reject execute upgrades, and every mapping rejects simultaneous writable and executable rights
- obsolete pager/process image-frame slots are no longer special-cased; executable mappings are staged anonymously before activation and the boot-module frame remains the only non-anonymous bootstrap frame
- initial syscall-resume frames are written into the target VSpace's anonymous stack backing before first activation, so materialized file-backed children do not depend on the caller's currently active page mapping
- process-control operation
CONFIGURE_PROCESS_STARTUP (46)binds an exact staged generation to one complete readable process-owned image range, accepts only an identical retry while the child remains created, places its address and length in initialrdi/rsi, preserves the bound receive endpoint inrdx, and retires the retained register data after constructing the frame - process-control operation
QUERY_PROCESS_CPU_TIME (47)returns saturating user and system nanoseconds for one live or terminal exact TCB generation. Accounting closes intervals at initial user entry and syscall/user-fault boundaries, stale or malformed identities return no values, and no timing or process capability is created by the reply - process-control operations
READ_PROCESSOR_TOPOLOGY (48)andREAD_PROCESSOR_COUNTERS (49)expose explicit indexed online state plus monotonic total/non-idle scheduler ticks; the memory-onlyREAD_ALLOCATOR_TOTALS (50)reports usable and live managed-frame bytes. All three are read-only service-owner inputs and are never delegated to an application process.
Governance Principles
kernel governance is scoped to minimal mechanism: scheduling, memory, IPC,
interrupts, and capability enforcement.
The scoped governance rules are:
- Policy belongs in user-space services unless enforcing it in the kernel is necessary for isolation.
- Capability checks must be explicit and auditable at every authority boundary.
- Unsafe Rust and architecture-specific code must stay narrow, documented, and covered by invariants.
- Kernel ABI changes require matching updates in libraries, services, and integration validation.
Authority Boundaries
- The kernel creates and enforces capabilities; it does not grant ambient service authority.
- New kernel mechanisms must preserve deterministic startup and fail-closed behavior.
Contact
Development occurs in EriX organization and discussions happen in issues and design documents.
No decisions are considered valid without documented rationale.
Maintainers can be reached via email: admin@erikinkinen.fi.