M11–M12: IRQ-as-IPC and bus drivers; expand names tree-wide
Two driver-model milestones plus a tree-wide naming pass. Suite 35/35 (QEMU) + host tests green. M11 — IRQ-as-IPC. A ring-3 driver now sleeps until its device interrupts it. New src/kernel/irq.zig: per-GSI endpoint bindings, comptime per-vector trampolines, dispatch = mask GSI -> LAPIC EOI -> notifyLocked, all under one lock region. irq_bind/irq_ack syscalls, gated by the device claim like mmio_map. interruptDispatch no longer EOIs — each handler owns its EOI, because a level line must be masked before it is acknowledged (irq_ack is the unmask). Bindings are keyed on the owning task and released on exit (a shared endpoint's siblings survive). hpetd rewritten interrupt-driven. Tests: hpet (rewritten, reads back the I/O APIC routing) and irqfree. M12 — bus drivers. DeviceDesc gains a parent, making the device table a tree. dev_register (device_register) lets a process publish children below a device it claimed; the kernel enforces resource containment (a child's resources must nest in its parent's), so a descriptor can't fabricate a window over kernel RAM. Descriptor copied in via copyFromUser (physmap walk — an unmapped user pointer fails the call instead of faulting the kernel). Per-parent child cap bounds table exhaustion. sbin/busd.zig is a worked bus driver. Test: bus. Naming — per docs/coding-standards.md: non-acronym abbreviations spelled out (message, descriptor, device_service, scheduler, runtime, physical, interpreter, ...); acronyms kept (IPC, MMIO, DMA, HCD, ...); files are kebab-case (ipc-synchronous.zig, device-service.zig, vfs-protocol.zig, ...). Exceptions: POSIX/C ABI names and Zig idioms (init/len/ptr) kept. Module collisions resolved by specific naming (config -> parameters, device.zig alias -> device_model). AML op/Op disambiguated: op = opcode, Op = operation; per-opcode parse handlers renamed opX -> parseX. New driver docs: drivers.md, driver-model.md (bus/class/HCD shapes + the proposed M13–M16 ABI), coding-standards.md.
This commit is contained in:
+38
-38
@@ -4,13 +4,13 @@
|
||||
//! kernel knows nothing of files or fds — the fd table lives here, per process.
|
||||
|
||||
const std = @import("std");
|
||||
const proto = @import("vfs_proto.zig");
|
||||
const protocol = @import("vfs-protocol.zig");
|
||||
const ipc = @import("ipc.zig");
|
||||
const danos = @import("danos");
|
||||
|
||||
pub const O_CREAT = proto.O_CREAT;
|
||||
pub const O_CREAT = protocol.O_CREAT;
|
||||
pub const SEEK_SET: u32 = 0;
|
||||
pub const SEEK_CUR: u32 = 1;
|
||||
pub const SEEK_CURRENT: u32 = 1;
|
||||
pub const SEEK_END: u32 = 2;
|
||||
|
||||
// Resolve (and cache) the VFS server endpoint, looked up by well-known id.
|
||||
@@ -24,9 +24,9 @@ fn vfs() ?usize {
|
||||
return vfs_handle;
|
||||
}
|
||||
|
||||
const max_fds = 32;
|
||||
const maximum_fds = 32;
|
||||
const Fd = struct { used: bool = false, node: u64 = 0, offset: u64 = 0 };
|
||||
var fds = [_]Fd{.{}} ** max_fds;
|
||||
var fds = [_]Fd{.{}} ** maximum_fds;
|
||||
|
||||
fn allocFd() ?usize {
|
||||
for (&fds, 0..) |*f, i| {
|
||||
@@ -38,30 +38,30 @@ fn allocFd() ?usize {
|
||||
return null;
|
||||
}
|
||||
|
||||
const Result = struct { reply: proto.Reply, payload: []u8 };
|
||||
const Result = struct { reply: protocol.Reply, payload: []u8 };
|
||||
|
||||
/// One request/reply round trip: [Request header][send payload] -> VFS ->
|
||||
/// [Reply header][recv payload]. The recv payload is written into `out`.
|
||||
fn transact(req: proto.Request, send: []const u8, out: []u8) ?Result {
|
||||
/// [Reply header][receive payload]. The receive payload is written into `out`.
|
||||
fn transact(req: protocol.Request, send: []const u8, out: []u8) ?Result {
|
||||
const h = vfs() orelse return null;
|
||||
var msg: [proto.msg_max]u8 = undefined;
|
||||
@memcpy(msg[0..proto.req_size], std.mem.asBytes(&req));
|
||||
const slen = @min(send.len, proto.max_payload);
|
||||
@memcpy(msg[proto.req_size..][0..slen], send[0..slen]);
|
||||
var message: [protocol.message_maximum]u8 = undefined;
|
||||
@memcpy(message[0..protocol.req_size], std.mem.asBytes(&req));
|
||||
const slen = @min(send.len, protocol.maximum_payload);
|
||||
@memcpy(message[protocol.req_size..][0..slen], send[0..slen]);
|
||||
|
||||
var rbuf: [proto.msg_max]u8 = undefined;
|
||||
const n = ipc.call(h, msg[0 .. proto.req_size + slen], &rbuf) catch return null;
|
||||
if (n < proto.reply_size) return null;
|
||||
const reply = std.mem.bytesToValue(proto.Reply, rbuf[0..proto.reply_size]);
|
||||
const rpl = @min(n - proto.reply_size, out.len);
|
||||
@memcpy(out[0..rpl], rbuf[proto.reply_size..][0..rpl]);
|
||||
var rbuf: [protocol.message_maximum]u8 = undefined;
|
||||
const n = ipc.call(h, message[0 .. protocol.req_size + slen], &rbuf) catch return null;
|
||||
if (n < protocol.reply_size) return null;
|
||||
const reply = std.mem.bytesToValue(protocol.Reply, rbuf[0..protocol.reply_size]);
|
||||
const rpl = @min(n - protocol.reply_size, out.len);
|
||||
@memcpy(out[0..rpl], rbuf[protocol.reply_size..][0..rpl]);
|
||||
return .{ .reply = reply, .payload = out[0..rpl] };
|
||||
}
|
||||
|
||||
/// Open (or create, with O_CREAT) `path`; returns an fd or -1.
|
||||
pub fn open(path: []const u8, flags: u32) i32 {
|
||||
const fd = allocFd() orelse return -1;
|
||||
const req = proto.Request{ .op = .open, .node = 0, .offset = 0, .len = @intCast(path.len), .flags = flags };
|
||||
const req = protocol.Request{ .op = .open, .node = 0, .offset = 0, .len = @intCast(path.len), .flags = flags };
|
||||
const r = transact(req, path, &.{}) orelse {
|
||||
fds[fd].used = false;
|
||||
return -1;
|
||||
@@ -75,17 +75,17 @@ pub fn open(path: []const u8, flags: u32) i32 {
|
||||
}
|
||||
|
||||
fn fdPtr(fd: i32) ?*Fd {
|
||||
if (fd < 0 or fd >= max_fds) return null;
|
||||
if (fd < 0 or fd >= maximum_fds) return null;
|
||||
const f = &fds[@intCast(fd)];
|
||||
return if (f.used) f else null;
|
||||
}
|
||||
|
||||
/// Read up to `buf.len` bytes at the current offset; returns the count or -1.
|
||||
pub fn read(fd: i32, buf: []u8) isize {
|
||||
/// Read up to `buffer.len` bytes at the current offset; returns the count or -1.
|
||||
pub fn read(fd: i32, buffer: []u8) isize {
|
||||
const f = fdPtr(fd) orelse return -1;
|
||||
const want: u32 = @intCast(@min(buf.len, proto.max_payload));
|
||||
const req = proto.Request{ .op = .read, .node = f.node, .offset = f.offset, .len = want, .flags = 0 };
|
||||
const r = transact(req, &.{}, buf) orelse return -1;
|
||||
const want: u32 = @intCast(@min(buffer.len, protocol.maximum_payload));
|
||||
const req = protocol.Request{ .op = .read, .node = f.node, .offset = f.offset, .len = want, .flags = 0 };
|
||||
const r = transact(req, &.{}, buffer) orelse return -1;
|
||||
if (r.reply.status != 0) return -1;
|
||||
f.offset += r.reply.len;
|
||||
return @intCast(r.reply.len);
|
||||
@@ -94,8 +94,8 @@ pub fn read(fd: i32, buf: []u8) isize {
|
||||
/// Write `data` at the current offset; returns the count or -1.
|
||||
pub fn write(fd: i32, data: []const u8) isize {
|
||||
const f = fdPtr(fd) orelse return -1;
|
||||
const want: u32 = @intCast(@min(data.len, proto.max_payload));
|
||||
const req = proto.Request{ .op = .write, .node = f.node, .offset = f.offset, .len = want, .flags = 0 };
|
||||
const want: u32 = @intCast(@min(data.len, protocol.maximum_payload));
|
||||
const req = protocol.Request{ .op = .write, .node = f.node, .offset = f.offset, .len = want, .flags = 0 };
|
||||
const r = transact(req, data[0..want], &.{}) orelse return -1;
|
||||
if (r.reply.status != 0) return -1;
|
||||
f.offset += r.reply.len;
|
||||
@@ -108,13 +108,13 @@ pub fn lseek(fd: i32, off: i64, whence: u32) i64 {
|
||||
const f = fdPtr(fd) orelse return -1;
|
||||
const base: i64 = switch (whence) {
|
||||
SEEK_SET => 0,
|
||||
SEEK_CUR => @intCast(f.offset),
|
||||
SEEK_CURRENT => @intCast(f.offset),
|
||||
SEEK_END => blk: {
|
||||
const req = proto.Request{ .op = .stat, .node = f.node, .offset = 0, .len = 0, .flags = 0 };
|
||||
var sbuf: [@sizeOf(proto.Stat)]u8 = undefined;
|
||||
const req = protocol.Request{ .op = .stat, .node = f.node, .offset = 0, .len = 0, .flags = 0 };
|
||||
var sbuf: [@sizeOf(protocol.Stat)]u8 = undefined;
|
||||
const r = transact(req, &.{}, &sbuf) orelse return -1;
|
||||
if (r.reply.status != 0 or r.payload.len < @sizeOf(proto.Stat)) return -1;
|
||||
const st = std.mem.bytesToValue(proto.Stat, sbuf[0..@sizeOf(proto.Stat)]);
|
||||
if (r.reply.status != 0 or r.payload.len < @sizeOf(protocol.Stat)) return -1;
|
||||
const st = std.mem.bytesToValue(protocol.Stat, sbuf[0..@sizeOf(protocol.Stat)]);
|
||||
break :blk @intCast(st.size);
|
||||
},
|
||||
else => return -1,
|
||||
@@ -126,24 +126,24 @@ pub fn lseek(fd: i32, off: i64, whence: u32) i64 {
|
||||
}
|
||||
|
||||
/// Stat `path`. Returns 0 or -1.
|
||||
pub fn stat(path: []const u8, out: *proto.Stat) i32 {
|
||||
pub fn stat(path: []const u8, out: *protocol.Stat) i32 {
|
||||
// Open, stat by node, close — simple and enough for now.
|
||||
const fd = open(path, 0);
|
||||
if (fd < 0) return -1;
|
||||
defer close(fd);
|
||||
const f = fdPtr(fd).?;
|
||||
const req = proto.Request{ .op = .stat, .node = f.node, .offset = 0, .len = 0, .flags = 0 };
|
||||
var sbuf: [@sizeOf(proto.Stat)]u8 = undefined;
|
||||
const req = protocol.Request{ .op = .stat, .node = f.node, .offset = 0, .len = 0, .flags = 0 };
|
||||
var sbuf: [@sizeOf(protocol.Stat)]u8 = undefined;
|
||||
const r = transact(req, &.{}, &sbuf) orelse return -1;
|
||||
if (r.reply.status != 0 or r.payload.len < @sizeOf(proto.Stat)) return -1;
|
||||
out.* = std.mem.bytesToValue(proto.Stat, sbuf[0..@sizeOf(proto.Stat)]);
|
||||
if (r.reply.status != 0 or r.payload.len < @sizeOf(protocol.Stat)) return -1;
|
||||
out.* = std.mem.bytesToValue(protocol.Stat, sbuf[0..@sizeOf(protocol.Stat)]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// Close an fd (best effort — tells the VFS to release the open file).
|
||||
pub fn close(fd: i32) void {
|
||||
const f = fdPtr(fd) orelse return;
|
||||
const req = proto.Request{ .op = .close, .node = f.node, .offset = 0, .len = 0, .flags = 0 };
|
||||
const req = protocol.Request{ .op = .close, .node = f.node, .offset = 0, .len = 0, .flags = 0 };
|
||||
_ = transact(req, &.{}, &.{});
|
||||
f.used = false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user