- Rust 99.7%
- Linker Script 0.3%
| 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-driver-capcheck.ld | ||
| linker-driver-hold.ld | ||
| linker.ld | ||
| README.md | ||
| ROADMAP.md | ||
| rustfmt.toml | ||
| SECURITY.md | ||
deviced
deviced is the device manager daemon for EriX.
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
This repository implements the EriX device service daemon. Its purpose in EriX is to provide the device service role through explicit IPC and startup authority.
Functionally, it implements the daemon runtime, state model, IPC handling, and validation tests. The repository keeps the implementation, interface contracts, tests, and documentation for that behavior in one reviewable ownership boundary.
The maintained responsibilities are:
- implement the device service runtime and state model
- validate startup authority before accepting IPC requests
- handle validated service operations through the assigned endpoint set
- materialize and run the private one-shot CMOS RTC driver through an exact
RTC-only
loaderdroute and the ordinary driver-lifecycleprocdroute - keep service behavior, tests, and authority invariants documented
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.
Runtime model
- Registry state:
unsealed->sealed. - Binding records, their reconcile/log state, and HAL registrations are carved
from one deployment-sized arena authenticated in the packaged executable.
Runtime configuration selects both record counts; page padding remains
unusable and
devicedreceives no allocator authority. - BootConfig is parsed by
rootd;devicedremains BootConfig-agnostic and receives lifecycle intent only through RPCs. - Seed operation is idempotent for exact tuple matches.
- Drivers are not auto-started at seal/startup.
- The signed RTC binding is explicit-start and one-shot. It carries no generic executable bounds: deviced asks its dedicated RTC-only loader endpoint for the canonical ext4 image, installs only RTC I/O and timed-provider send authority, starts it through procd, waits for clean exit, and returns zero persistent process and endpoint identity.
- Seeded bindings for non-service-managed driver roles are rejected. Current
supported
drv-*roles are all expected to beprocd-managed. - The internal lifecycle fixture drivers used by the device-manager-only scenario
are seeded as already discovered so that start/stop verification can run
without bringing up the separate probe/hotplug stack. Those fixture bindings
do not inherit auto-start activation flags, so runtime reconciliation cannot
spawn them behind
rootd's explicit lifecycle checks. Their live endpoint aliases use dedicated slots after the deployed role windows and therefore cannot replace deviced's ACPI or i8042 authority sources. - Both lifecycle fixture binaries share the same retained-call runtime. It accepts the complete IPC transport shape, rejects and retires unwanted authority, keeps each accepted caller through its reply, mirrors the result in the envelope and typed body, and requests process teardown when receive, live-caller reply, or cleanup state becomes terminal. An already absent caller needs no reply retention; a valid stop reply precedes fixture process exit.
- Activation is reconciled from:
- discovery state (
REPORT_DEVICE,REPORT_HOTPLUG) - HAL readiness (
REGISTER_HAL) - provider visibility (
REGISTER_PROVIDERfor registration-based providers, or an authenticated successful driver start for per-device block providers)
- discovery state (
drv-serialkeepsSERIALDas the consumer-scoping role for provider resolution, but driver process startup itself no longer waits for theREGISTER_HALround trip; that avoids a circular boot dependency while preserving the explicit consumer contract.- Storage mediation uses dedicated runtime peers rather than broad device
authority.
drv-virtio-blockreceives a transferredDEVICE_FRAMEplus explicitmemdandvspacedpeers, whileblockdreceives separateREGISTER_HALandRESOLVE_PROVIDERsurfaces. - Virtio PCI capability traversal has no independent record cap: it follows the format-defined list while rejecting misaligned, out-of-range, overflowing, or cyclic records before deriving device authority.
- HAL/provider registration and resolution derive caller identity from the dedicated endpoint used for the call; their request bodies carry no caller-selected role identifier.
- The BAR-derivation path uses a scratch local
DEVICE_FRAMEslot insidedeviced: the service validates the derived frame before startup-cap installation and drops that scratch slot on both success and failure paths so residual MMIO authority is not left behind locally. - The serial launch path creates a fresh private IRQ event endpoint in a transaction-local scratch slot. It installs separate receive-only and registration-only aliases into drv-serial, then drops the launcher alias on both success and failure paths; the public provider endpoint is never reused as an event channel.
- Driver startup-transfer descriptors are encoded directly into the canonical transport-sized envelope and validated from those bytes. Deviced's client and server buffers expose the shared transport maximum, so neither the producer nor the caller imposes an independent descriptor or message-size ceiling.
- Each discovered virtio-block PCI function clones the sealed activation policy
into a binding keyed by its location-derived physical identity. Deviced starts
one process per physical disk; an authenticated successful
DRIVER_STARTreply is the readiness proof. Deviced retains that instance's service endpoint in its per-device alias interval, andblockdwalks providers through the dedicated cursor-based resolution endpoint. Rootd never receives or retains a live driver endpoint. - Driver-start and provider-triggered ready logs stay queued until the outer
service loop reaches its normal flush point, so synchronous log mirroring does
not block concurrent control RPCs from
rootd. Each housekeeping pass tries each pending role once; a failed append stays pending for the next pass rather than entering a service-local immediate-retry batch. - The queued
logdsubmit path useslib-logRust-string submission helpers and logicalLogSubmitResponseV1results rather than deviced-localLogdSubmitStringRequestV1frame construction, buffer sizing, or NUL scratch storage. Runtime log helpers no longer carry the primary-control slot as a hidden logging authority or enforce the retired fixed 96-byte kernel log-message cap beforelib-logchunking. - Packaged release runtime builds select
deviced-runtime-release-image, which suppressesERIX_DEVICED:READY:*console stamps while still treating those internal lifecycle notifications as completed. - The runtime service loop rotates fairly across the split admin and public endpoint families. Multiplexed receives remain nonblocking, idle passes yield, and a deployment with only one live receive endpoint waits without a service-local deadline. Startup and validation fixtures likewise wait for their required messages without fixed tick ceilings. Each completed request advances the deployment-owned reconciliation batch. There is no report-stream follow-on polling budget or unreachable zero-length burst loop. Successful provider registration still publishes readiness and gives one waiting admin request priority before more driver work.
- Every typed deviced response mirrors its operation result in the outer IPC envelope. Clients validate request correlation and envelope/body agreement before applying operation-specific policy; a contradiction is a contract failure.
READ_DRIVERreconciles pending startup work before forming its reply and only re-delegates a runtime endpoint once provider visibility is established for roles such asdrv-serial.RESOLVE_PROVIDERuses the same targeted reconciliation for the requested provider binding before it scans unrelated pending work, lettingblockdreceive the block provider endpoint without routing that driver authority throughrootd. Post-reply readiness publication and admin draining are registration completion work only; a provider lookup returns directly to the receive loop and cannot recursively generate registration diagnostics.- The dynamic-link VM profile can enable
deviced-integration-defer-background-reconcile, which lets public discovery, HAL, and provider reports update state without arming autonomous driver activation. In that profile, driver launch remains tied to rootd's explicit adminREAD_DRIVER/START_DRIVERverification path. - Dynamically packaged drivers are created with
procd's staged-create ABI.devicedderives the executable identity from the driver role, sends only the explicit child endpoint and install grant, and does not reuse boot-module-table authority for those dynamic driver launches. - Procd calls expose deviced's complete writable IPC buffer, then enforce the
exact typed response size. Ordinary start, abort, stop, and logging replies
must be authority-free. A successful staged create must carry exactly two
kernel-normalized receipts, in order: the request-selected generic child
endpoint with exact
SEND | RECV | GRANTrights and the request-selected install grant with exactGRANT | MINTrights. Deviced queries both installed aliases before retaining them and drops every unexpected, mismatched, negative-reply, or parse-failure receipt. - Required procd and driver calls retain the one caller-owned buffer after kernel acceptance and wait for the authoritative reply without duplicate submission or a service-local timeout ceiling. Reply delivery follows the same retained-buffer rule through transient kernel backpressure.
- Startup and runtime callers must send authority-free request envelopes. Deviced retires every unexpected receipt with the shared complete-drop policy before rejecting the request, and process teardown closes the whole CSpace whenever receipt cleanup or accepted reply delivery is uncertain.
- Runtime request preservation and capability-bearing replies use separate full-transport static buffers. Their capacities therefore follow the IPC transport contract instead of imposing private 128-byte request or 512-byte transfer-reply ceilings.
- Informational
logdwork makes one nonblocking pre-acceptance attempt. A busy endpoint defers the log to existing housekeeping policy; an accepted request retains its buffer until completion and is never abandoned. - The storage/filesystem dynamic-port profile extends that driver
path to
drv-virtio-block. The virtio-block driver executable identity is derived from the sealed driver role, and the staged child receives only its explicit primary-control endpoint, physical device authority, required memory peers, and install grant. The block provider has no deviced registration peer; successful authenticated driver start is the readiness and visibility transition for that physical instance. - Start is denied for unknown/unsealed/running bindings.
- Stop is denied for unknown/non-running bindings.
- Responses are deterministic and panic-free.
- Driver start/stop goes through
procdin the current slice:- start uses
CREATE_STAGED_DYNAMIC_PROCESS, install-grant materialization, andSTART_STAGED_PROCESS - stop uses
STOP_PROCESSwith the exact nonzero staged generation returned by create, so delayed cleanup cannot stop a reused process id
- start uses
devicednow reachesprocdfor driver lifecycle through the dedicated local endpoint slotSLOT_PROCD_DRIVER_ENDPOINT (2112), validated via local capability introspection, instead of resolving the genericprocdservice endpoint throughnamed.deviced's primary local control slot is now the dedicated kernel query-only endpointSLOT_KERNEL_QUERY_ENDPOINT, which is limited to startup validation.devicedno longer receives kernel log output authority, and durable driver-ready and integration-proof records are submitted tologd.devicednow stagesprobedfrom the explicit kernel platform-discovery-read endpoint and stagesdrv-acpi,drv-serial, anddrv-i8042from dedicated localAcpiRsdpRead,Com1Io, andI8042Iosource endpoints.- Shared platform/device-I/O startup source slots are no longer part of the runtime driver contract.
devicedreceives only the grant-bearing IRQD COM1 handler endpoint sodrv-serialcan receive that line-bound registration/ACK object through the staged child install-grant path. Deviced receives no IRQD registry, seal, or mask-control authority.- Driver startup peers are validated from delegated fixed slots, not from
ambient slot occupancy or synthetic
namedidentity.drv-serialreceives only its authenticated log producer client; each PS/2 driver receives only its event-kind-specific input producer client and matching i8042 stream-read client. - The i8042 keyboard and mouse endpoint sources are retained solely for managed
child creation and restart.
devicedinstalls receive-only aliases indrv-i8042and send-only aliases in the matching translator, never includes those source slots in its RPC receive scan, and no longer serves PS/2READ_DRIVERdiscovery. - The staged-driver constructor compares selected peer destinations and primary-control sources with their declared role routes before using the install grant. Omitted or substituted routes are rejected before unintended authority can enter the child.
- Optional
logduse validates the delegated slot through an explicit caller-local query operation before every submission. Deviced validates this fixed client directly and has no service-directory dependency. devicedno longer advertises or receives delegated CNode/TCB/VSpace management caps in the current runtime slice; driver lifecycle authority is reduced to the dedicatedprocddriver endpoint plus device-side authority.- Seeded driver metadata no longer includes a scalar device-cap source slot.
Driver hardware authority is expressed only through explicit transferred
startup caps;
deviceddoes not rely on unrelated boot metadata as a placeholder device cap. - Driver spawn requests now carry
procd's explicit local image-frame slot instead of reusing the canonical boot-module-table slot value. - Startup ready-state now uses caller-local
QUERY_LOCAL_CAPon bare metal, withQUERY_CAPretained for host/test scaffolding, to validate the actual local control slot, service endpoint slot, and every declared transferred slot. - The dedicated local driver-lifecycle and primary-control slots are now real
copied endpoint aliases materialized by
rootd, not implicit conventions. - Legacy synthetic direct-process-management fallbacks have been removed from
deviced; unsupported driver roles are denied at seed/start/stop time. - Startup-failure cleanup for supported service-managed drivers now also goes
back through
procdSTOP_PROCESS, not a direct kernel destroy path. - Service-driver startup uses one synchronous RPC per process instance. Transport failure and terminal endpoint retirement proceed directly to cleanup instead of retrying the same request an arbitrary number of times.
- Every driver-start failure runs all independent cleanup operations. A failed
staged abort, process stop, grant revocation, endpoint revocation, or scratch
device-frame revocation quarantines
deviced; the service exits before accepting another request so kernel process teardown removes authority whose lifetime can no longer be proven. - Deviced drops its own grants, endpoint aliases, and scratch capabilities with the local CSpace syscall. The child-population control endpoint remains necessary only for capability copy and staged-child installation.
- The helper driver binaries used by integration/validation also fail closed if bootstrap omits the startup endpoint argument; they no longer bind to conventional driver-window slots or abandon a required startup receive after a fixed tick budget.
Build
cargo build --all-targets --all-features
Test
cargo test --all-targets --all-features
cargo clippy --all-targets --all-features -- -D warnings
Build and Test Modes
This repository supports additive runtime and integration feature gates.
deviced-runtimeanddeviced-runtime-release-imageselect production bootstrap/runtime behavior.*-integration-smokeremains available for synthetic end-to-end validation paths.*-integration-force-failremains test-only and MUST NOT be enabled for runtime appliance builds.- explicit driver primary-control omission/misroute features remain integration-only; they exist solely to prove fail-closed startup when staged driver authority is the wrong shape
- the drv-serial log-peer misroute feature remains integration-only and proves that a generic log slot cannot replace the authenticated fixed client
- integration evidence uses deviced's ordinary authenticated
logdroute and requests no explicit sink-routing authority; production logging policy remains unchanged
The smoke-only READ_DEVICE reply markers remain cfg-scoped to
deviced-integration-smoke, so runtime/release appliance builds keep the
provider-registration reply path warning-free. The reply-path request-op decode
is now shared by runtime and smoke builds so the provider-registration fast path
compiles identically in appliance and integration configurations. Stale
smoke-only debug shim functions for legacy serial/logd marker emission have
been removed; remaining lifecycle diagnostics use the real queued logd
submission path.
Dynamic Boot Artifact Evidence
The image build packages deviced as a dynamic boot artifact: an ELF64 x86_64
ET_DYN executable with
.erix_dynlink metadata in the signed dynlink-store and mirrors it under
/lib/erix/dynlink with its required shared objects.
Startup remains rootd through procd staged dynamic creation before dynlinkd;
authority remains rootd-admin RPC, the dedicated query-only endpoint, and
explicit child-populate/lifecycle peers. Dynamic packaging and filesystem
mirror records are evidence and launch inputs only; they do not grant
filesystem, loader, object-store, service-discovery, provider-bypass, block-
device, or dynlinkd authority. deviced receives only the documented
startup endpoints, peers, and capabilities for its role.
Governance Principles
deviced governance is scoped to device discovery, driver matching, and
provider publication.
The scoped governance rules are:
- It owns device-to-driver matching policy while drivers own hardware-specific behavior.
- It must start driver services only through
procdand transfer only the matched device authority. - It keeps provider publication explicit: registration-based providers must authenticate a registration call, while per-device block providers must complete authenticated startup and can be resolved only through the caller-scoped cursor API.
- It rejects malformed manifests, duplicate providers, and unauthorized driver starts.
Authority Boundaries
devicedoperates only through startup-assigned service capabilities.- New authority must be represented in bootstrap/capability validation and integration tests before use.
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.