hachem.wtf
aboutsummaryrefslogtreecommitdiff
path: root/bridge/hosts.zig
diff options
context:
space:
mode:
Diffstat (limited to 'bridge/hosts.zig')
-rw-r--r--bridge/hosts.zig380
1 files changed, 380 insertions, 0 deletions
diff --git a/bridge/hosts.zig b/bridge/hosts.zig
new file mode 100644
index 0000000..e329316
--- /dev/null
+++ b/bridge/hosts.zig
@@ -0,0 +1,380 @@
+const std = @import("std");
+const revo = @import("revo");
+const serial = @import("serial.zig");
+const convert = @import("convert.zig");
+
+const HostResult = convert.HostResult;
+const Data = convert.Data;
+const argInt = convert.argInt;
+const emit = serial.emit;
+
+// the actual framebuffer, the data layout feels pretty self explanatory
+pub const Fb = struct {
+ ptr: [*]u8,
+ width: usize,
+ height: usize,
+ pitch: usize,
+};
+var g_fb: ?Fb = null;
+
+pub fn setFb(fb: ?Fb) void {
+ g_fb = fb;
+}
+
+pub const KernelOps = struct {
+ phys_to_virt: *const fn (u64) u64,
+ alloc_frame: *const fn () u64, // 0 on failure
+ create_addrspace: *const fn () u64, // pml4 phys, 0 on failure (raw 64 bit entry copy incl. possible nx bit -> not f64 representable)
+ spawn: *const fn (u64, u64, u64, u64, u64) void, // pml4, entry, ustack, arg_ptr, arg_len -> queue a ring 3 task
+ deliver_input: *const fn (u8) bool, // hand a byte to a read()-blocked task, false if none
+ proc_exited: *const fn () bool, // true once after a process exits (consumed)
+ serial_next: *const fn () i64, // next mirrored serial byte, or -1 if empty
+
+ // read only state for revo to present (mem/uptime/ps/dump_memmap):
+ memmap_count: *const fn () u64,
+ memmap_base: *const fn (u64) u64,
+ memmap_len: *const fn (u64) u64,
+ memmap_kind: *const fn (u64) u64,
+ mem_free: *const fn () u64,
+ mem_total: *const fn () u64,
+
+ uptime: *const fn () u64,
+ proc_count: *const fn () u64,
+ prog_count: *const fn () u64,
+ prog_phys: *const fn (u64) u64,
+ prog_name: *const fn (u64) []const u8,
+ prog_size: *const fn (u64) u64,
+ task_max: *const fn () u64,
+ task_state: *const fn (u64) u64,
+
+ disk_sectors: *const fn () u64,
+ disk_read: *const fn (u64, u64) u64, // lba, phys buf -> 1 ok / 0 fail
+ disk_write: *const fn (u64, u64) u64, // lba, phys buf -> 1 ok / 0 fail
+};
+var g_kops: ?KernelOps = null;
+
+pub fn setKops(ops: ?KernelOps) void {
+ g_kops = ops;
+}
+
+fn kops() KernelOps {
+ return g_kops.?;
+}
+
+// pass shit to revo
+fn hostOutb(args: []const revo.Value, _: *revo.VM) anyerror!HostResult {
+ const port = argInt(u16, args, 0) orelse return HostResult.other("outb: port out of range");
+ const val = argInt(u8, args, 1) orelse return HostResult.other("outb: value out of range");
+ asm volatile ("outb %[v], %[p]"
+ :
+ : [v] "{al}" (val),
+ [p] "N{dx}" (port),
+ );
+ return HostResult.data(Data.new.nil());
+}
+
+// pass shit to revo
+fn hostInb(args: []const revo.Value, _: *revo.VM) anyerror!HostResult {
+ const port = argInt(u16, args, 0) orelse return HostResult.other("inb: port out of range");
+ const val = asm volatile ("inb %[p], %[r]"
+ : [r] "={al}" (-> u8),
+ : [p] "N{dx}" (port),
+ );
+ return HostResult.data(Data.new.num(val));
+}
+
+// pass shit to revo
+fn hostPuts(args: []const revo.Value, vm: *revo.VM) anyerror!HostResult {
+ const string_id = args[0].asString() orelse return HostResult.other("puts: not a string");
+ emit(vm.stringValue(string_id));
+ return HostResult.data(Data.new.nil());
+}
+
+// pass shit to revo
+fn hostFbWidth(_: []const revo.Value, _: *revo.VM) anyerror!HostResult {
+ return HostResult.data(Data.new.num(if (g_fb) |fb| fb.width else 0));
+}
+
+// pass shit to revo
+fn hostFbHeight(_: []const revo.Value, _: *revo.VM) anyerror!HostResult {
+ return HostResult.data(Data.new.num(if (g_fb) |fb| fb.height else 0));
+}
+
+// color is 0xrrggbb in the usual limine 32 bpp layout
+// pass shit to revo
+fn hostFillRect(args: []const revo.Value, _: *revo.VM) anyerror!HostResult {
+ const fb = g_fb orelse return HostResult.data(Data.new.nil()); // no screen, no op
+ const x = argInt(usize, args, 0) orelse return HostResult.other("fill_rect: bad x");
+ const y = argInt(usize, args, 1) orelse return HostResult.other("fill_rect: bad y");
+ const w = argInt(usize, args, 2) orelse return HostResult.other("fill_rect: bad w");
+ const h = argInt(usize, args, 3) orelse return HostResult.other("fill_rect: bad h");
+ const color = argInt(u32, args, 4) orelse return HostResult.other("fill_rect: bad color");
+
+ var yy = y;
+ const y_end = @min(y + h, fb.height);
+ const x_end = @min(x + w, fb.width);
+ while (yy < y_end) : (yy += 1) {
+ const row = fb.ptr + yy * fb.pitch;
+ var xx = x;
+ while (xx < x_end) : (xx += 1) {
+ const px: *align(1) u32 = @ptrCast(row + xx * 4);
+ px.* = color;
+ }
+ }
+ return HostResult.data(Data.new.nil());
+}
+
+// pass shit to revo
+fn hostFbScroll(args: []const revo.Value, _: *revo.VM) anyerror!HostResult {
+ const fb = g_fb orelse return HostResult.data(Data.new.nil());
+ const dy = argInt(usize, args, 0) orelse return HostResult.other("fb_scroll: bad dy");
+ const color = argInt(u32, args, 1) orelse return HostResult.other("fb_scroll: bad color");
+ if (dy == 0 or dy >= fb.height) return HostResult.data(Data.new.nil());
+ const move_bytes = dy * fb.pitch;
+ const total = fb.height * fb.pitch;
+ std.mem.copyForwards(u8, fb.ptr[0 .. total - move_bytes], fb.ptr[move_bytes..total]);
+ var y: usize = fb.height - dy;
+ while (y < fb.height) : (y += 1) {
+ const line = fb.ptr + y * fb.pitch;
+ var x: usize = 0;
+ while (x < fb.width) : (x += 1) {
+ const px: *align(1) u32 = @ptrCast(line + x * 4);
+ px.* = color;
+ }
+ }
+ return HostResult.data(Data.new.nil());
+}
+
+// pass shit to revo
+fn hostMemRead(args: []const revo.Value, _: *revo.VM) anyerror!HostResult {
+ const phys = argInt(u64, args, 0) orelse return HostResult.other("mem_read: bad addr");
+ const size = argInt(u64, args, 1) orelse return HostResult.other("mem_read: bad size");
+ const virt = kops().phys_to_virt(phys);
+ const val: u64 = switch (size) {
+ 1 => @as(*const u8, @ptrFromInt(virt)).*,
+ 2 => @as(*align(1) const u16, @ptrFromInt(virt)).*,
+ 4 => @as(*align(1) const u32, @ptrFromInt(virt)).*,
+ 8 => @as(*align(1) const u64, @ptrFromInt(virt)).*,
+ else => return HostResult.other("mem_read: size must be 1/2/4/8"),
+ };
+ return HostResult.data(Data.new.num(val));
+}
+
+// pass shit to revo
+fn hostMemCopy(args: []const revo.Value, _: *revo.VM) anyerror!HostResult {
+ const dst = kops().phys_to_virt(argInt(u64, args, 0) orelse return HostResult.other("mem_copy: bad dst"));
+ const src = kops().phys_to_virt(argInt(u64, args, 1) orelse return HostResult.other("mem_copy: bad src"));
+ const len = argInt(usize, args, 2) orelse return HostResult.other("mem_copy: bad len");
+ @memcpy(@as([*]u8, @ptrFromInt(dst))[0..len], @as([*]const u8, @ptrFromInt(src))[0..len]);
+ return HostResult.data(Data.new.nil());
+}
+
+// pass shit to revo
+fn hostMemZero(args: []const revo.Value, _: *revo.VM) anyerror!HostResult {
+ const dst = kops().phys_to_virt(argInt(u64, args, 0) orelse return HostResult.other("mem_zero: bad addr"));
+ const len = argInt(usize, args, 1) orelse return HostResult.other("mem_zero: bad len");
+ @memset(@as([*]u8, @ptrFromInt(dst))[0..len], 0);
+ return HostResult.data(Data.new.nil());
+}
+
+// pass shit to revo
+fn hostMemWrite(args: []const revo.Value, _: *revo.VM) anyerror!HostResult {
+ const phys = argInt(u64, args, 0) orelse return HostResult.other("mem_write: bad addr");
+ const val = argInt(u64, args, 1) orelse return HostResult.other("mem_write: bad val");
+ const size = argInt(u64, args, 2) orelse return HostResult.other("mem_write: bad size");
+ const virt = kops().phys_to_virt(phys);
+ switch (size) {
+ 1 => @as(*u8, @ptrFromInt(virt)).* = @truncate(val),
+ 2 => @as(*align(1) u16, @ptrFromInt(virt)).* = @truncate(val),
+ 4 => @as(*align(1) u32, @ptrFromInt(virt)).* = @truncate(val),
+ 8 => @as(*align(1) u64, @ptrFromInt(virt)).* = val,
+ else => return HostResult.other("mem_write: size must be 1/2/4/8"),
+ }
+ return HostResult.data(Data.new.nil());
+}
+
+// pass shit to revo
+fn hostInvlpg(args: []const revo.Value, _: *revo.VM) anyerror!HostResult {
+ const virt = argInt(u64, args, 0) orelse return HostResult.other("invlpg: bad addr");
+ asm volatile ("invlpg (%[v])"
+ :
+ : [v] "r" (virt),
+ : .{ .memory = true });
+ return HostResult.data(Data.new.nil());
+}
+
+// pass shit to revo
+fn hostFrameAlloc(_: []const revo.Value, _: *revo.VM) anyerror!HostResult {
+ return HostResult.data(Data.new.num(kops().alloc_frame()));
+}
+
+// pass shit to revo
+fn hostAsCreate(_: []const revo.Value, _: *revo.VM) anyerror!HostResult {
+ return HostResult.data(Data.new.num(kops().create_addrspace()));
+}
+
+// pass shit to revo
+fn hostProcRun(args: []const revo.Value, _: *revo.VM) anyerror!HostResult {
+ const as = argInt(u64, args, 0) orelse return HostResult.other("proc_run: bad as");
+ const entry = argInt(u64, args, 1) orelse return HostResult.other("proc_run: bad entry");
+ const ustack = argInt(u64, args, 2) orelse return HostResult.other("proc_run: bad ustack");
+ const arg = argInt(u64, args, 3) orelse return HostResult.other("proc_run: bad arg");
+ const arglen = argInt(u64, args, 4) orelse return HostResult.other("proc_run: bad arglen");
+ kops().spawn(as, entry, ustack, arg, arglen);
+ return HostResult.data(Data.new.nil());
+}
+
+// pass shit to revo
+fn hostStdinDeliver(args: []const revo.Value, _: *revo.VM) anyerror!HostResult {
+ const ch = argInt(u8, args, 0) orelse return HostResult.other("stdin_deliver: bad char");
+ return HostResult.data(Data.new.num(if (kops().deliver_input(ch)) @as(f64, 1) else 0));
+}
+
+// pass shit to revo
+fn hostProcExited(_: []const revo.Value, _: *revo.VM) anyerror!HostResult {
+ return HostResult.data(Data.new.num(if (kops().proc_exited()) @as(f64, 1) else 0));
+}
+
+// pass shit to revo
+fn hostSerialNext(_: []const revo.Value, _: *revo.VM) anyerror!HostResult {
+ return HostResult.data(Data.new.num(kops().serial_next()));
+}
+
+// pass shit to revo
+fn hostProgCount(_: []const revo.Value, _: *revo.VM) anyerror!HostResult {
+ return HostResult.data(Data.new.num(kops().prog_count()));
+}
+
+// pass shit to revo
+fn hostProgPhys(args: []const revo.Value, _: *revo.VM) anyerror!HostResult {
+ const i = argInt(u64, args, 0) orelse return HostResult.other("prog_phys: bad index");
+ return HostResult.data(Data.new.num(kops().prog_phys(i)));
+}
+
+// pass shit to revo
+fn hostProgName(args: []const revo.Value, vm: *revo.VM) anyerror!HostResult {
+ const i = argInt(u64, args, 0) orelse return HostResult.other("prog_name: bad index");
+ return HostResult.data(try vm.ownValueString(kops().prog_name(i)));
+}
+
+// pass shit to revo
+fn hostProgSize(args: []const revo.Value, _: *revo.VM) anyerror!HostResult {
+ const i = argInt(u64, args, 0) orelse return HostResult.other("prog_size: bad index");
+ return HostResult.data(Data.new.num(kops().prog_size(i)));
+}
+
+// pass shit to revo
+fn hostTaskMax(_: []const revo.Value, _: *revo.VM) anyerror!HostResult {
+ return HostResult.data(Data.new.num(kops().task_max()));
+}
+
+// pass shit to revo
+fn hostTaskState(args: []const revo.Value, _: *revo.VM) anyerror!HostResult {
+ const i = argInt(u64, args, 0) orelse return HostResult.other("task_state: bad index");
+ return HostResult.data(Data.new.num(kops().task_state(i)));
+}
+
+// pass shit to revo
+fn hostMemmapCount(_: []const revo.Value, _: *revo.VM) anyerror!HostResult {
+ return HostResult.data(Data.new.num(kops().memmap_count()));
+}
+
+// pass shit to revo
+fn hostMemmapBase(args: []const revo.Value, _: *revo.VM) anyerror!HostResult {
+ const index = argInt(u64, args, 0) orelse return HostResult.other("memmap_base: bad index");
+ return HostResult.data(Data.new.num(kops().memmap_base(index)));
+}
+
+// pass shit to revo
+fn hostMemmapLen(args: []const revo.Value, _: *revo.VM) anyerror!HostResult {
+ const index = argInt(u64, args, 0) orelse return HostResult.other("memmap_len: bad index");
+ return HostResult.data(Data.new.num(kops().memmap_len(index)));
+}
+
+// pass shit to revo
+fn hostMemmapKind(args: []const revo.Value, _: *revo.VM) anyerror!HostResult {
+ const index = argInt(u64, args, 0) orelse return HostResult.other("memmap_kind: bad index");
+ return HostResult.data(Data.new.num(kops().memmap_kind(index)));
+}
+
+// pass shit to revo
+fn hostMemFree(_: []const revo.Value, _: *revo.VM) anyerror!HostResult {
+ return HostResult.data(Data.new.num(kops().mem_free()));
+}
+
+// pass shit to revo
+fn hostMemTotal(_: []const revo.Value, _: *revo.VM) anyerror!HostResult {
+ return HostResult.data(Data.new.num(kops().mem_total()));
+}
+
+// pass shit to revo
+fn hostUptime(_: []const revo.Value, _: *revo.VM) anyerror!HostResult {
+ return HostResult.data(Data.new.num(kops().uptime()));
+}
+
+// pass shit to revo
+fn hostProcCount(_: []const revo.Value, _: *revo.VM) anyerror!HostResult {
+ return HostResult.data(Data.new.num(kops().proc_count()));
+}
+
+// pass shit to revo
+fn hostDiskSectors(_: []const revo.Value, _: *revo.VM) anyerror!HostResult {
+ return HostResult.data(Data.new.num(kops().disk_sectors()));
+}
+
+// pass shit to revo
+fn hostDiskRead(args: []const revo.Value, _: *revo.VM) anyerror!HostResult {
+ const lba = argInt(u64, args, 0) orelse return HostResult.other("disk_read: bad lba");
+ const phys = argInt(u64, args, 1) orelse return HostResult.other("disk_read: bad phys");
+ return HostResult.data(Data.new.num(kops().disk_read(lba, phys)));
+}
+
+// pass shit to revo
+fn hostDiskWrite(args: []const revo.Value, _: *revo.VM) anyerror!HostResult {
+ const lba = argInt(u64, args, 0) orelse return HostResult.other("disk_write: bad lba");
+ const phys = argInt(u64, args, 1) orelse return HostResult.other("disk_write: bad phys");
+ return HostResult.data(Data.new.num(kops().disk_write(lba, phys)));
+}
+
+// pass shit to revo
+pub fn registerPrimitives(vm: *revo.VM) !void {
+ const define = revo.baselib.host.define;
+ const T = revo.baselib.host.ParamType;
+ try vm.registerGlobal("outb", try vm.installHost("outb", define(&[_]T{ .number, .number }, hostOutb)));
+ try vm.registerGlobal("inb", try vm.installHost("inb", define(&[_]T{.number}, hostInb)));
+ try vm.registerGlobal("serial_puts", try vm.installHost("serial_puts", define(&[_]T{.string}, hostPuts)));
+ try vm.registerGlobal("fb_width", try vm.installHost("fb_width", define(&[_]T{}, hostFbWidth)));
+ try vm.registerGlobal("fb_height", try vm.installHost("fb_height", define(&[_]T{}, hostFbHeight)));
+ try vm.registerGlobal("fill_rect", try vm.installHost("fill_rect", define(&[_]T{ .number, .number, .number, .number, .number }, hostFillRect)));
+ try vm.registerGlobal("fb_scroll", try vm.installHost("fb_scroll", define(&[_]T{ .number, .number }, hostFbScroll)));
+
+ try vm.registerGlobal("mem_read", try vm.installHost("mem_read", define(&[_]T{ .number, .number }, hostMemRead)));
+ try vm.registerGlobal("mem_copy", try vm.installHost("mem_copy", define(&[_]T{ .number, .number, .number }, hostMemCopy)));
+ try vm.registerGlobal("mem_zero", try vm.installHost("mem_zero", define(&[_]T{ .number, .number }, hostMemZero)));
+ try vm.registerGlobal("mem_write", try vm.installHost("mem_write", define(&[_]T{ .number, .number, .number }, hostMemWrite)));
+ try vm.registerGlobal("invlpg", try vm.installHost("invlpg", define(&[_]T{.number}, hostInvlpg)));
+ try vm.registerGlobal("frame_alloc", try vm.installHost("frame_alloc", define(&[_]T{}, hostFrameAlloc)));
+ try vm.registerGlobal("as_create", try vm.installHost("as_create", define(&[_]T{}, hostAsCreate)));
+ try vm.registerGlobal("proc_run", try vm.installHost("proc_run", define(&[_]T{ .number, .number, .number, .number, .number }, hostProcRun)));
+ try vm.registerGlobal("stdin_deliver", try vm.installHost("stdin_deliver", define(&[_]T{.number}, hostStdinDeliver)));
+ try vm.registerGlobal("proc_exited", try vm.installHost("proc_exited", define(&[_]T{}, hostProcExited)));
+ try vm.registerGlobal("serial_next", try vm.installHost("serial_next", define(&[_]T{}, hostSerialNext)));
+ try vm.registerGlobal("prog_count", try vm.installHost("prog_count", define(&[_]T{}, hostProgCount)));
+ try vm.registerGlobal("prog_phys", try vm.installHost("prog_phys", define(&[_]T{.number}, hostProgPhys)));
+ try vm.registerGlobal("prog_name", try vm.installHost("prog_name", define(&[_]T{.number}, hostProgName)));
+ try vm.registerGlobal("prog_size", try vm.installHost("prog_size", define(&[_]T{.number}, hostProgSize)));
+ try vm.registerGlobal("task_max", try vm.installHost("task_max", define(&[_]T{}, hostTaskMax)));
+ try vm.registerGlobal("task_state", try vm.installHost("task_state", define(&[_]T{.number}, hostTaskState)));
+ try vm.registerGlobal("memmap_count", try vm.installHost("memmap_count", define(&[_]T{}, hostMemmapCount)));
+ try vm.registerGlobal("memmap_base", try vm.installHost("memmap_base", define(&[_]T{.number}, hostMemmapBase)));
+ try vm.registerGlobal("memmap_len", try vm.installHost("memmap_len", define(&[_]T{.number}, hostMemmapLen)));
+ try vm.registerGlobal("memmap_kind", try vm.installHost("memmap_kind", define(&[_]T{.number}, hostMemmapKind)));
+ try vm.registerGlobal("mem_free", try vm.installHost("mem_free", define(&[_]T{}, hostMemFree)));
+ try vm.registerGlobal("mem_total", try vm.installHost("mem_total", define(&[_]T{}, hostMemTotal)));
+ try vm.registerGlobal("uptime", try vm.installHost("uptime", define(&[_]T{}, hostUptime)));
+ try vm.registerGlobal("proc_count", try vm.installHost("proc_count", define(&[_]T{}, hostProcCount)));
+
+ try vm.registerGlobal("disk_sectors", try vm.installHost("disk_sectors", define(&[_]T{}, hostDiskSectors)));
+ try vm.registerGlobal("disk_read", try vm.installHost("disk_read", define(&[_]T{ .number, .number }, hostDiskRead)));
+ try vm.registerGlobal("disk_write", try vm.installHost("disk_write", define(&[_]T{ .number, .number }, hostDiskWrite)));
+}