Split the system contract into boot-handoff / abi / device-abi
The `system` module (formerly `danos`) had become a grab-bag: it held the
loader<->kernel handoff *and* the kernel<->user ABI *and* the device wire types, in
one module three different audiences imported. Usage proved the seam — the
bootloader never touched the syscall/device ABI, and user space never touched the
boot handoff — so split it by audience, one module per contract:
system/boot-handoff.zig loader <-> kernel: BootInformation, Framebuffer,
MemoryMap, the VM layout + physicalToVirtual, kernel_abi
system/abi.zig kernel <-> user, core: SystemCall, mmap prot flags,
page_size, notify_badge_bit, ServiceId
system/devices/device-abi.zig kernel <-> user, devices: DeviceDescriptor,
DeviceClass, ResourceDescriptor, ResourceKind, ...
device-abi is the devices sub-project's public interface, exposed as its own module
the way vfs exposes vfs-protocol — importable by user space, unlike the
kernel-internal device model it also feeds. That collapses a real duplication:
DeviceClass and ResourceKind were defined twice (device-model.zig and the contract,
kept "in sync by hand"); device-model now re-exports them from device-abi, so the
enum a driver matches on and the one the kernel classifies with are one type.
Each import now declares which contract it speaks: the bootloader imports only
boot-handoff; a driver only abi + device-abi (via the runtime); the kernel all
three. This also retires the `system` / `runtime.system` name overlap. page_size
lands in abi (it's part of the mmap contract user space aligns to); the bootloader
keeps its own local 4 KiB constant so it depends on nothing but the handoff.
All 21 importers rewired, docs updated to keep /system mapping to source. Build,
host tests, and the QEMU suite (36/36) all green.
This commit is contained in:
@@ -3,13 +3,13 @@
|
||||
//! ownership of its hardware; the claim is the capability the kernel checks before
|
||||
//! mapping registers or routing an IRQ.
|
||||
|
||||
const system = @import("system");
|
||||
const device_abi = @import("device-abi");
|
||||
const sc = @import("system-call.zig");
|
||||
|
||||
pub const DeviceDescriptor = system.DeviceDescriptor;
|
||||
pub const ResourceDescriptor = system.ResourceDescriptor;
|
||||
pub const DeviceClass = system.DeviceClass;
|
||||
pub const ResourceKind = system.ResourceKind;
|
||||
pub const DeviceDescriptor = device_abi.DeviceDescriptor;
|
||||
pub const ResourceDescriptor = device_abi.ResourceDescriptor;
|
||||
pub const DeviceClass = device_abi.DeviceClass;
|
||||
pub const ResourceKind = device_abi.ResourceKind;
|
||||
|
||||
inline fn failed(r: usize) bool {
|
||||
return r > ~@as(usize, 0) - 4095;
|
||||
@@ -33,7 +33,7 @@ pub fn mmioMap(device_id: u64, resource_index: u64) ?usize {
|
||||
}
|
||||
|
||||
/// `DeviceDescriptor.parent` for a device with no parent.
|
||||
pub const no_parent = system.no_parent;
|
||||
pub const no_parent = device_abi.no_parent;
|
||||
|
||||
/// Publish `descriptor` as a child of `parent_id`, which this process must have claimed.
|
||||
/// Returns the new device id. The child is left unclaimed, so whichever driver owns
|
||||
|
||||
@@ -13,10 +13,10 @@
|
||||
//! lock and larger alignments come when user programs gain threads.
|
||||
|
||||
const std = @import("std");
|
||||
const system = @import("system");
|
||||
const abi = @import("abi");
|
||||
const system_calls = @import("system.zig");
|
||||
|
||||
const page_size = system.page_size;
|
||||
const page_size = abi.page_size;
|
||||
|
||||
/// A block header, at the start of every block; while free it also links the
|
||||
/// free list via `next`.
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
//! reached this way. The server side (`replyWait`, which returns two values) is
|
||||
//! added with the first server binary.
|
||||
|
||||
const system = @import("system");
|
||||
const abi = @import("abi");
|
||||
const sc = @import("system-call.zig");
|
||||
|
||||
/// A small-int handle into the calling process's handle table.
|
||||
@@ -30,13 +30,13 @@ pub fn createEndpoint() ?Handle {
|
||||
}
|
||||
|
||||
/// Publish endpoint `h` under a well-known service id so other processes find it.
|
||||
pub fn register(id: system.ServiceId, h: Handle) bool {
|
||||
pub fn register(id: abi.ServiceId, h: Handle) bool {
|
||||
return !failed(sc.systemCall2(.ipc_register, @intFromEnum(id), h));
|
||||
}
|
||||
|
||||
/// Find the endpoint published under `id`, installing a handle to it in this
|
||||
/// process.
|
||||
pub fn lookup(id: system.ServiceId) ?Handle {
|
||||
pub fn lookup(id: abi.ServiceId) ?Handle {
|
||||
const r = sc.systemCall1(.ipc_lookup, @intFromEnum(id));
|
||||
return if (failed(r)) null else r;
|
||||
}
|
||||
@@ -53,7 +53,7 @@ pub fn call(h: Handle, message: []const u8, reply: []u8) CallError!usize {
|
||||
/// Set in `Received.badge` when what arrived is an asynchronous notification — a
|
||||
/// bound device interrupt — rather than a client's message. The low bits carry the
|
||||
/// GSI. See `isNotification`.
|
||||
pub const notify_badge_bit: u64 = system.notify_badge_bit;
|
||||
pub const notify_badge_bit: u64 = abi.notify_badge_bit;
|
||||
|
||||
/// The result of a `replyWait`: the request length and the sender's badge (a
|
||||
/// task id, or an IRQ notification if the high bit is set).
|
||||
@@ -84,7 +84,7 @@ pub fn replyWait(h: Handle, reply: []const u8, receive: []u8) Received {
|
||||
asm volatile ("syscall"
|
||||
: [rax] "={rax}" (rax),
|
||||
[rdx] "+{rdx}" (rdx),
|
||||
: [n] "{rax}" (@intFromEnum(system.SystemCall.ipc_reply_wait)),
|
||||
: [n] "{rax}" (@intFromEnum(abi.SystemCall.ipc_reply_wait)),
|
||||
[a0] "{rdi}" (h),
|
||||
[a1] "{rsi}" (@intFromPtr(reply.ptr)),
|
||||
[a3] "{r10}" (@intFromPtr(receive.ptr)),
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
//! Note argument #3 goes in **r10, not rcx** — rcx is unavailable across the
|
||||
//! instruction, so the kernel reads the 4th argument from r10.
|
||||
|
||||
const system = @import("system");
|
||||
const SystemCall = system.SystemCall;
|
||||
const abi = @import("abi");
|
||||
const SystemCall = abi.SystemCall;
|
||||
|
||||
pub inline fn systemCall0(n: SystemCall) usize {
|
||||
return asm volatile ("syscall"
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
//! Typed system_call surface for user space — thin wrappers over the raw `system_call`
|
||||
//! stubs, one per kernel call. Numbers come from `system.SystemCall`, the single
|
||||
//! stubs, one per kernel call. Numbers come from `abi.SystemCall`, the single
|
||||
//! source of truth shared with the kernel dispatcher.
|
||||
|
||||
const system = @import("system");
|
||||
const abi = @import("abi");
|
||||
const sc = @import("system-call.zig");
|
||||
|
||||
/// `mmap` protection flags (matching the usual C bit values). Grants are always
|
||||
/// readable+writable today; the kernel does not yet honour finer prot.
|
||||
pub const PROT_READ: usize = system.prot_read;
|
||||
pub const PROT_WRITE: usize = system.prot_write;
|
||||
pub const PROT_EXEC: usize = system.prot_exec;
|
||||
pub const PROT_READ: usize = abi.prot_read;
|
||||
pub const PROT_WRITE: usize = abi.prot_write;
|
||||
pub const PROT_EXEC: usize = abi.prot_exec;
|
||||
|
||||
/// Give up the rest of this quantum.
|
||||
pub fn yield() void {
|
||||
|
||||
Reference in New Issue
Block a user