hachem.wtf
aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorhachem <im@hachem.wtf>2026-10-12 23:08:48 +0200
committerhachem <im@hachem.wtf>2026-10-12 23:08:48 +0200
commit6a5543bb8f1f535ca49737bcd7be0cafca3b2a08 (patch)
treebb137b732a1d122aeace46c550733f4793d84601
parent59794d0b999e544a94230d9562bf2b99d2ed74c7 (diff)
feat: lib seaHEADmain
-rw-r--r--boot/boot.zig5
-rw-r--r--boot/elf.zig9
-rw-r--r--boot/fonts.zig11
-rw-r--r--bridge/hosts.zig50
-rw-r--r--build.zig319
-rw-r--r--kernel/seed.rv10
-rw-r--r--sysroot/etc/lung (renamed from etc/lung)0
-rw-r--r--sysroot/etc/motd (renamed from etc/motd)0
-rw-r--r--sysroot/etc/profile (renamed from etc/profile)0
-rw-r--r--sysroot/usr/include/fcntl.h12
-rw-r--r--sysroot/usr/include/stddef.h9
-rw-r--r--sysroot/usr/include/stdint.h10
-rw-r--r--sysroot/usr/include/stdio.h15
-rw-r--r--sysroot/usr/include/stdlib.h17
-rw-r--r--sysroot/usr/include/string.h17
-rw-r--r--sysroot/usr/include/sys/syscall.h34
-rw-r--r--sysroot/usr/include/unistd.h18
-rw-r--r--sysroot/usr/lib/libc/crt0.c28
-rw-r--r--sysroot/usr/lib/libc/stdio.c211
-rw-r--r--sysroot/usr/lib/libc/stdlib.c185
-rw-r--r--sysroot/usr/lib/libc/string.c92
-rw-r--r--sysroot/usr/lib/libc/syscalls.c38
-rw-r--r--sysroot/usr/share/acorn8.psf (renamed from fonts/acorn8.psf)bin2052 -> 2052 bytes
-rw-r--r--sysroot/usr/share/dejavu.ttf (renamed from fonts/dejavu.ttf)bin8488 -> 8488 bytes
-rw-r--r--sysroot/usr/share/pearl8.psf (renamed from fonts/pearl8.psf)bin2052 -> 2052 bytes
-rw-r--r--sysroot/usr/share/sun16.psf (renamed from fonts/sun16.psf)bin4100 -> 4100 bytes
-rw-r--r--sysroot/usr/share/terminess.ttf (renamed from fonts/terminess.ttf)bin9496 -> 9496 bytes
-rw-r--r--sysroot/usr/share/vga16.psf (renamed from fonts/vga16.psf)bin4100 -> 4100 bytes
-rw-r--r--sysroot/usr/share/vga8.psf (renamed from fonts/vga8.psf)bin2052 -> 2052 bytes
-rw-r--r--user/calc.c24
-rw-r--r--user/chat.c36
-rw-r--r--user/hexview.c93
-rw-r--r--user/membrk.c51
-rw-r--r--user/primes.c28
-rw-r--r--user/save.c46
-rw-r--r--user/user.h309
36 files changed, 1065 insertions, 612 deletions
diff --git a/boot/boot.zig b/boot/boot.zig
index 6ead044..891def7 100644
--- a/boot/boot.zig
+++ b/boot/boot.zig
@@ -8,8 +8,9 @@ const pmm = @import("pmm.zig");
const heap = @import("heap.zig");
const vmm = @import("vmm.zig");
const user = @import("user.zig");
-const elf = @import("elf.zig");
-const fontdata = @import("fonts.zig");
+// fonts + compiled programs, generated from the filesystem by build.zig
+const elf = @import("kasset");
+const fontdata = @import("kasset");
const keyboard = @import("keyboard.zig");
const timer = @import("timer.zig");
const sched = @import("sched.zig");
diff --git a/boot/elf.zig b/boot/elf.zig
deleted file mode 100644
index 32acbfe..0000000
--- a/boot/elf.zig
+++ /dev/null
@@ -1,9 +0,0 @@
-pub const Program = struct { name: []const u8, bytes: []const u8 };
-pub const programs = [_]Program{
- .{ .name = "hexview", .bytes = @embedFile("user_hexview") },
- .{ .name = "calc", .bytes = @embedFile("user_calc") },
- .{ .name = "primes", .bytes = @embedFile("user_primes") },
- .{ .name = "save", .bytes = @embedFile("user_save") },
- .{ .name = "chat", .bytes = @embedFile("user_chat") },
- .{ .name = "membrk", .bytes = @embedFile("user_membrk") },
-};
diff --git a/boot/fonts.zig b/boot/fonts.zig
deleted file mode 100644
index 5db8123..0000000
--- a/boot/fonts.zig
+++ /dev/null
@@ -1,11 +0,0 @@
-// js loading fonts from host disk
-pub const Font = struct { name: []const u8, bytes: []const u8 };
-pub const fonts = [_]Font{
- .{ .name = "vga16.psf", .bytes = @embedFile("font_vga16") },
- .{ .name = "vga8.psf", .bytes = @embedFile("font_vga8") },
- .{ .name = "sun16.psf", .bytes = @embedFile("font_sun16") },
- .{ .name = "acorn8.psf", .bytes = @embedFile("font_acorn8") },
- .{ .name = "pearl8.psf", .bytes = @embedFile("font_pearl8") },
- .{ .name = "dejavu.ttf", .bytes = @embedFile("font_dejavu") },
- .{ .name = "terminess.ttf", .bytes = @embedFile("font_terminess") },
-};
diff --git a/bridge/hosts.zig b/bridge/hosts.zig
index caf8b0d..5148ca8 100644
--- a/bridge/hosts.zig
+++ b/bridge/hosts.zig
@@ -8,31 +8,11 @@ const Data = convert.Data;
const argInt = convert.argInt;
const emit = serial.emit;
-// gils shit
-const Script = struct { name: []const u8, src: []const u8 };
-const scripts = [_]Script{
- .{ .name = "ls", .src = @embedFile("k_gils_ls") },
- .{ .name = "tree", .src = @embedFile("k_gils_tree") },
- .{ .name = "cat", .src = @embedFile("k_gils_cat") },
- .{ .name = "rm", .src = @embedFile("k_gils_rm") },
- .{ .name = "mkdir", .src = @embedFile("k_gils_mkdir") },
- .{ .name = "touch", .src = @embedFile("k_gils_touch") },
- .{ .name = "cp", .src = @embedFile("k_gils_cp") },
- .{ .name = "mv", .src = @embedFile("k_gils_mv") },
- .{ .name = "wc", .src = @embedFile("k_gils_wc") },
- .{ .name = "head", .src = @embedFile("k_gils_head") },
- .{ .name = "tail", .src = @embedFile("k_gils_tail") },
-};
-
-// /etc/ shit
-const EtcFile = struct { name: []const u8, src: []const u8 };
-const etc_files = [_]EtcFile{
- .{ .name = "motd", .src = @embedFile("k_etc_motd") },
- .{ .name = "profile", .src = @embedFile("k_etc_profile") },
- .{ .name = "lung", .src = @embedFile("k_etc_lung") },
-};
+const basset = @import("basset");
+const scripts = basset.gils;
+const etc_files = basset.etc;
+const include_files = basset.include;
-// the actual framebuffer, the data layout feels pretty self explanatory
pub const Fb = struct {
ptr: [*]u8,
width: usize,
@@ -452,6 +432,25 @@ fn hostEtcSrc(args: []const revo.Value, vm: *revo.VM) anyerror!HostResult {
}
// pass shit to revo
+fn hostIncCount(_: []const revo.Value, _: *revo.VM) anyerror!HostResult {
+ return HostResult.data(Data.new.num(include_files.len));
+}
+
+// pass shit to revo
+fn hostIncName(args: []const revo.Value, vm: *revo.VM) anyerror!HostResult {
+ const i = argInt(usize, args, 0) orelse return HostResult.other("inc_name: bad index");
+ if (i >= include_files.len) return HostResult.other("inc_name: out of range");
+ return HostResult.data(try vm.ownValueString(include_files[i].name));
+}
+
+// pass shit to revo
+fn hostIncSrc(args: []const revo.Value, vm: *revo.VM) anyerror!HostResult {
+ const i = argInt(usize, args, 0) orelse return HostResult.other("inc_src: bad index");
+ if (i >= include_files.len) return HostResult.other("inc_src: out of range");
+ return HostResult.data(try vm.ownValueString(include_files[i].src));
+}
+
+// pass shit to revo
fn hostEvalScript(args: []const revo.Value, vm: *revo.VM) anyerror!HostResult {
const sid = args[0].asString() orelse return HostResult.other("eval_script: not a string");
const src = vm.stringValue(sid);
@@ -517,6 +516,9 @@ pub fn passShitToRevo(vm: *revo.VM) !void {
try vm.registerGlobal("etc_count", try vm.installHost("etc_count", define(&[_]T{}, hostEtcCount)));
try vm.registerGlobal("etc_name", try vm.installHost("etc_name", define(&[_]T{.number}, hostEtcName)));
try vm.registerGlobal("etc_src", try vm.installHost("etc_src", define(&[_]T{.number}, hostEtcSrc)));
+ try vm.registerGlobal("inc_count", try vm.installHost("inc_count", define(&[_]T{}, hostIncCount)));
+ try vm.registerGlobal("inc_name", try vm.installHost("inc_name", define(&[_]T{.number}, hostIncName)));
+ try vm.registerGlobal("inc_src", try vm.installHost("inc_src", define(&[_]T{.number}, hostIncSrc)));
try vm.registerGlobal("alloc_contig", try vm.installHost("alloc_contig", define(&[_]T{.number}, hostAllocContig)));
try vm.registerGlobal("blit_str", try vm.installHost("blit_str", define(&[_]T{ .number, .string }, hostBlitStr)));
try vm.registerGlobal("phys_to_str", try vm.installHost("phys_to_str", define(&[_]T{ .number, .number }, hostPhysToStr)));
diff --git a/build.zig b/build.zig
index e625977..4978296 100644
--- a/build.zig
+++ b/build.zig
@@ -1,136 +1,275 @@
const std = @import("std");
-// the gils coreutils
-const gils_tools = .{ "gils", "ls", "tree", "cat", "rm", "mkdir", "touch", "cp", "mv", "wc", "head", "tail", "ed" };
+const boot_gils = [_][]const u8{ "gils", "ed" };
+
+const user_cc = [_][]const u8{
+ "zig", "cc",
+ "-target", "x86_64-freestanding",
+ "-ffreestanding", "-nostdlib",
+ "-static", "-no-pie",
+ "-fno-stack-protector", "-fno-sanitize=all",
+ "-Wall", "-Wextra",
+ "-Werror", "-Wpedantic",
+ "-I", "sysroot/usr/include",
+ "-Wl,-T,user/link.ld", "-Wl,--build-id=none",
+ "-o",
+};
pub fn build(b: *std.Build) void {
- // Default to ReleaseSafe because Debug pulls Zig's UBSan runtime and other
- // sanitization, which needs f128/SSE ops, which i don't provide.
const optimize = b.option(std.builtin.OptimizeMode, "optimize", "optimize mode") orelse .safe;
+ const target = kernelTarget(b);
+
+ const kernel = buildKernel(b, target, optimize);
+ kernel.root_module.addImport("kasset", buildKernelAssets(b, target, optimize));
+ kernel.root_module.addImport("bridge", buildBridge(b, target, optimize));
+
+ b.installArtifact(kernel);
+}
- // The kernel must NOT touch SSE/MMX/AVX until it has enabled them itself, so
- // I strip those features and let the compiler use a soft-float ABI
- // `code_model = .kernel` keeps relocations valid for the higher-half load
- // address in boot/linker.ld.
- //
- // In other words. Going raw baby
+fn kernelTarget(b: *std.Build) std.Build.ResolvedTarget {
var query: std.Target.Query = .{
.cpu_arch = .x86_64,
.os_tag = .freestanding,
.abi = .none,
};
-
const Feature = std.Target.x86.Feature;
query.cpu_features_sub.addFeature(@backingInt(Feature.mmx));
query.cpu_features_sub.addFeature(@backingInt(Feature.avx));
query.cpu_features_sub.addFeature(@backingInt(Feature.avx2));
+ return b.resolveTargetQuery(query);
+}
- const target = b.resolveTargetQuery(query);
+fn kernelModule(
+ b: *std.Build,
+ target: std.Build.ResolvedTarget,
+ optimize: std.builtin.OptimizeMode,
+ root: std.Build.LazyPath,
+) *std.Build.Module {
+ return b.createModule(.{
+ .root_source_file = root,
+ .target = target,
+ .optimize = optimize,
+ .code_model = .kernel,
+ .red_zone = false,
+ .single_threaded = true,
+ .link_libc = false,
+ });
+}
+fn buildKernel(
+ b: *std.Build,
+ target: std.Build.ResolvedTarget,
+ optimize: std.builtin.OptimizeMode,
+) *std.Build.Step.Compile {
const kernel = b.addExecutable(.{
.name = "revel",
- .root_module = b.createModule(.{
- .root_source_file = b.path("boot/boot.zig"),
- .target = target,
- .optimize = optimize,
- .code_model = .kernel,
- .red_zone = false,
- .single_threaded = true,
- .link_libc = false,
- }),
+ .root_module = kernelModule(b, target, optimize, b.path("boot/boot.zig")),
});
kernel.entry = .{ .symbol_name = "_start" };
kernel.pie = false;
kernel.setLinkerScript(b.path("boot/linker.ld"));
+ return kernel;
+}
+
+fn buildBridge(
+ b: *std.Build,
+ target: std.Build.ResolvedTarget,
+ optimize: std.builtin.OptimizeMode,
+) *std.Build.Module {
+ const bridge = kernelModule(b, target, optimize, b.path("bridge/bridge.zig"));
- // the big guns
- const revo_dep = b.dependency("revo", .{
+ const revo = b.dependency("revo", .{
.target = target,
.optimize = optimize,
.features = "regex",
- });
- const revo_mod = revo_dep.module("revo");
-
+ }).module("revo");
var visited: std.AutoHashMap(*std.Build.Module, void) = .init(b.allocator);
defer visited.deinit();
- kernelize(revo_mod, &visited);
+ kernelize(revo, &visited);
+ bridge.addImport("revo", revo);
- // the thin guns
- const bridge_mod = b.createModule(.{
- .root_source_file = b.path("bridge/bridge.zig"),
- .target = target,
- .optimize = optimize,
- .code_model = .kernel,
- .red_zone = false,
- .single_threaded = true,
- .link_libc = false,
- });
- bridge_mod.addImport("revo", revo_mod);
- inline for (.{
- .{ "k_font", "kernel/font.rv" },
- .{ "k_console", "kernel/console.rv" },
- .{ "k_vmm", "kernel/vmm.rv" },
- .{ "k_fs", "kernel/fs.rv" },
- .{ "k_io", "kernel/io.rv" },
- .{ "k_vfs", "kernel/vfs.rv" },
- .{ "k_seed", "kernel/seed.rv" },
- .{ "k_proc", "kernel/proc.rv" },
- .{ "k_ttf", "kernel/ttf.rv" },
- .{ "k_shell", "kernel/shell.rv" },
- .{ "k_tty", "kernel/tty.rv" },
- .{ "k_input", "kernel/input.rv" },
- .{ "k_main", "kernel/main.rv" },
- }) |e| {
- bridge_mod.addAnonymousImport(e[0], .{ .root_source_file = b.path(e[1]) });
+ for (scan(b, "kernel", ".rv")) |file| {
+ const name = stripExt(file);
+ bridge.addAnonymousImport(b.fmt("k_{s}", .{name}), .{
+ .root_source_file = b.path(b.fmt("kernel/{s}", .{file})),
+ });
+ }
+ for (boot_gils) |name| {
+ bridge.addAnonymousImport(b.fmt("k_gils_{s}", .{name}), .{
+ .root_source_file = b.path(b.fmt("gils/{s}.rv", .{name})),
+ });
}
- // load gils
- inline for (gils_tools) |g| {
- bridge_mod.addAnonymousImport("k_gils_" ++ g, .{ .root_source_file = b.path("gils/" ++ g ++ ".rv") });
+ bridge.addImport("basset", buildBridgeAssets(b, target, optimize));
+ return bridge;
+}
+
+fn buildBridgeAssets(
+ b: *std.Build,
+ target: std.Build.ResolvedTarget,
+ optimize: std.builtin.OptimizeMode,
+) *std.Build.Module {
+ var embeds = Embeds{ .b = b };
+ var src: []const u8 =
+ \\// generated by build.zig
+ \\pub const Blob = struct { name: []const u8, src: []const u8 };
+ \\
+ \\
+ ;
+
+ src = b.fmt("{s}pub const gils = [_]Blob{{\n", .{src});
+ for (scan(b, "gils", ".rv")) |file| {
+ const name = stripExt(file);
+ if (contains(&boot_gils, name)) continue;
+ const key = b.fmt("k_gils_{s}", .{name});
+ embeds.add(key, b.path(b.fmt("gils/{s}", .{file})));
+ src = b.fmt("{s} .{{ .name = \"{s}\", .src = @embedFile(\"{s}\") }},\n", .{ src, name, key });
}
- // /etc/ bullshit
- inline for (.{ "motd", "profile", "lung" }) |name| {
- bridge_mod.addAnonymousImport("k_etc_" ++ name, .{ .root_source_file = b.path("etc/" ++ name) });
+ src = b.fmt("{s}}};\n\npub const etc = [_]Blob{{\n", .{src});
+ for (scan(b, "sysroot/etc", "")) |file| {
+ const key = b.fmt("k_etc_{s}", .{sanitize(b, file)});
+ embeds.add(key, b.path(b.fmt("sysroot/etc/{s}", .{file})));
+ src = b.fmt("{s} .{{ .name = \"{s}\", .src = @embedFile(\"{s}\") }},\n", .{ src, file, key });
}
- kernel.root_module.addImport("bridge", bridge_mod);
+ src = b.fmt("{s}}};\n\npub const include = [_]Blob{{\n", .{src});
+ for (headers(b)) |path| {
+ const key = b.fmt("k_inc_{s}", .{sanitize(b, path)});
+ embeds.add(key, b.path(b.fmt("sysroot/usr/include/{s}", .{path})));
+ src = b.fmt("{s} .{{ .name = \"{s}\", .src = @embedFile(\"{s}\") }},\n", .{ src, path, key });
+ }
- inline for (.{
- .{ "font_vga16", "fonts/vga16.psf" },
- .{ "font_vga8", "fonts/vga8.psf" },
- .{ "font_sun16", "fonts/sun16.psf" },
- .{ "font_acorn8", "fonts/acorn8.psf" },
- .{ "font_pearl8", "fonts/pearl8.psf" },
- .{ "font_dejavu", "fonts/dejavu.ttf" },
- .{ "font_terminess", "fonts/terminess.ttf" },
- }) |e| {
- kernel.root_module.addAnonymousImport(e[0], .{ .root_source_file = b.path(e[1]) });
+ src = b.fmt("{s}}};\n", .{src});
+ const mod = kernelModule(b, target, optimize, b.addWriteFiles().add("basset.zig", src));
+ embeds.apply(mod);
+ return mod;
+}
+
+fn buildKernelAssets(
+ b: *std.Build,
+ target: std.Build.ResolvedTarget,
+ optimize: std.builtin.OptimizeMode,
+) *std.Build.Module {
+ var embeds = Embeds{ .b = b };
+ var src: []const u8 =
+ \\// generated by build.zig
+ \\pub const Blob = struct { name: []const u8, bytes: []const u8 };
+ \\
+ \\
+ ;
+
+ src = b.fmt("{s}pub const fonts = [_]Blob{{\n", .{src});
+ for (scan(b, "sysroot/usr/share", "")) |file| {
+ const key = b.fmt("font_{s}", .{sanitize(b, file)});
+ embeds.add(key, b.path(b.fmt("sysroot/usr/share/{s}", .{file})));
+ src = b.fmt("{s} .{{ .name = \"{s}\", .bytes = @embedFile(\"{s}\") }},\n", .{ src, file, key });
+ }
+ src = b.fmt("{s}}};\n\npub const programs = [_]Blob{{\n", .{src});
+ for (scan(b, "user", ".c")) |file| {
+ const name = stripExt(file);
+ const key = b.fmt("user_{s}", .{name});
+ embeds.add(key, compileProgram(b, name));
+ src = b.fmt("{s} .{{ .name = \"{s}\", .bytes = @embedFile(\"{s}\") }},\n", .{ src, name, key });
}
+ src = b.fmt("{s}}};\n", .{src});
- inline for (.{ "hexview", "calc", "primes", "save", "chat", "membrk" }) |prog| {
- const cc = b.addSystemCommand(&.{
- "zig", "cc",
- "-target", "x86_64-freestanding",
- "-ffreestanding", "-nostdlib",
- "-static", "-no-pie",
- "-fno-stack-protector", "-fno-sanitize=all",
- "-Wall", "-Wextra",
- "-Werror", "-Wpedantic",
- "-Wl,-T,user/link.ld", "-Wl,--build-id=none",
- "-o",
- });
- const prog_elf = cc.addOutputFileArg(prog ++ ".elf");
- cc.addFileArg(b.path("user/" ++ prog ++ ".c"));
- cc.addFileInput(b.path("user/user.h"));
- cc.addFileInput(b.path("user/link.ld"));
- kernel.root_module.addAnonymousImport("user_" ++ prog, .{ .root_source_file = prog_elf });
+ const mod = kernelModule(b, target, optimize, b.addWriteFiles().add("kasset.zig", src));
+ embeds.apply(mod);
+ return mod;
+}
+
+fn compileProgram(b: *std.Build, name: []const u8) std.Build.LazyPath {
+ const cc = b.addSystemCommand(&user_cc);
+ const elf = cc.addOutputFileArg(b.fmt("{s}.elf", .{name}));
+
+ cc.addFileArg(b.path(b.fmt("user/{s}.c", .{name})));
+ for (scan(b, "sysroot/usr/lib/libc", ".c")) |unit|
+ cc.addFileArg(b.path(b.fmt("sysroot/usr/lib/libc/{s}", .{unit})));
+
+ for (headers(b)) |path|
+ cc.addFileInput(b.path(b.fmt("sysroot/usr/include/{s}", .{path})));
+ cc.addFileInput(b.path("user/link.ld"));
+
+ return elf;
+}
+
+fn scan(b: *std.Build, dir_path: []const u8, ext: []const u8) [][]const u8 {
+ const io = b.graph.io;
+ var dir = std.Io.Dir.cwd().openDir(io, dir_path, .{ .iterate = true }) catch |err|
+ std.debug.panic("build: cannot scan {s}: {s}", .{ dir_path, @errorName(err) });
+ defer dir.close(io);
+
+ var buf: [128][]const u8 = undefined;
+ var count: usize = 0;
+ var it = dir.iterate();
+ while (it.next(io) catch @panic("build: dir iterate failed")) |entry| {
+ if (entry.kind != .file) continue;
+ if (!std.mem.endsWith(u8, entry.name, ext)) continue;
+ buf[count] = b.allocator.dupe(u8, entry.name) catch @panic("OOM");
+ count += 1;
}
- b.installArtifact(kernel);
+ const names = b.allocator.dupe([]const u8, buf[0..count]) catch @panic("OOM");
+ std.mem.sort([]const u8, names, {}, lessThan);
+ return names;
+}
+
+fn headers(b: *std.Build) [][]const u8 {
+ var buf: [128][]const u8 = undefined;
+ var count: usize = 0;
+ for (scan(b, "sysroot/usr/include", ".h")) |name| {
+ buf[count] = name;
+ count += 1;
+ }
+ for (scan(b, "sysroot/usr/include/sys", ".h")) |name| {
+ buf[count] = b.fmt("sys/{s}", .{name});
+ count += 1;
+ }
+ return b.allocator.dupe([]const u8, buf[0..count]) catch @panic("OOM");
+}
+
+fn lessThan(_: void, a: []const u8, c: []const u8) bool {
+ return std.mem.lessThan(u8, a, c);
+}
+
+fn stripExt(name: []const u8) []const u8 {
+ const dot = std.mem.lastIndexOfScalar(u8, name, '.') orelse return name;
+ return name[0..dot];
+}
+
+fn sanitize(b: *std.Build, name: []const u8) []const u8 {
+ const out = b.allocator.dupe(u8, name) catch @panic("OOM");
+ for (out) |*ch| {
+ if (!std.ascii.isAlphanumeric(ch.*)) ch.* = '_';
+ }
+ return out;
+}
+
+const Embeds = struct {
+ b: *std.Build,
+ keys: [128][]const u8 = undefined,
+ paths: [128]std.Build.LazyPath = undefined,
+ count: usize = 0,
+
+ fn add(self: *Embeds, key: []const u8, path: std.Build.LazyPath) void {
+ self.keys[self.count] = key;
+ self.paths[self.count] = path;
+ self.count += 1;
+ }
+
+ fn apply(self: *Embeds, module: *std.Build.Module) void {
+ for (0..self.count) |i|
+ module.addAnonymousImport(self.keys[i], .{ .root_source_file = self.paths[i] });
+ }
+};
+
+fn contains(haystack: []const []const u8, needle: []const u8) bool {
+ for (haystack) |item|
+ if (std.mem.eql(u8, item, needle)) return true;
+ return false;
}
-// force a module and everything it imports to the kernel's codegen settings
fn kernelize(mod: *std.Build.Module, visited: *std.AutoHashMap(*std.Build.Module, void)) void {
if (visited.contains(mod)) return;
visited.put(mod, {}) catch @panic("OOM building module graph");
diff --git a/kernel/seed.rv b/kernel/seed.rv
index 95ed632..e4ffa9b 100644
--- a/kernel/seed.rv
+++ b/kernel/seed.rv
@@ -18,6 +18,15 @@ fn seed_fonts() do
end
end
+# libc bullshitery
+fn seed_include() do
+ fs:mkdir("/usr/include")
+ fs:mkdir("/usr/include/sys")
+ for index in 0..inc_count() do
+ fs:store("/usr/include/#{inc_name(index)}", inc_src(index))
+ end
+end
+
fn seed_fs() do
fs:mkdir("/usr")
fs:mkdir("/etc")
@@ -31,4 +40,5 @@ fn seed_fs() do
seed_bin()
seed_fonts()
+ seed_include()
end
diff --git a/etc/lung b/sysroot/etc/lung
index 54c10ab..54c10ab 100644
--- a/etc/lung
+++ b/sysroot/etc/lung
diff --git a/etc/motd b/sysroot/etc/motd
index f252b8e..f252b8e 100644
--- a/etc/motd
+++ b/sysroot/etc/motd
diff --git a/etc/profile b/sysroot/etc/profile
index 7cd7a19..7cd7a19 100644
--- a/etc/profile
+++ b/sysroot/etc/profile
diff --git a/sysroot/usr/include/fcntl.h b/sysroot/usr/include/fcntl.h
new file mode 100644
index 0000000..4c9dc07
--- /dev/null
+++ b/sysroot/usr/include/fcntl.h
@@ -0,0 +1,12 @@
+#ifndef _FCNTL_H
+#define _FCNTL_H
+
+#define O_RDONLY 0
+#define O_WRONLY 1
+#define O_CREAT 0x40
+#define O_TRUNC 0x200
+#define O_APPEND 0x400
+
+int open(const char* path, int flags);
+
+#endif
diff --git a/sysroot/usr/include/stddef.h b/sysroot/usr/include/stddef.h
new file mode 100644
index 0000000..0fe5f56
--- /dev/null
+++ b/sysroot/usr/include/stddef.h
@@ -0,0 +1,9 @@
+#ifndef _STDDEF_H
+#define _STDDEF_H
+
+typedef unsigned long size_t;
+typedef long ptrdiff_t;
+
+#define NULL ((void*)0)
+
+#endif
diff --git a/sysroot/usr/include/stdint.h b/sysroot/usr/include/stdint.h
new file mode 100644
index 0000000..d3da3d2
--- /dev/null
+++ b/sysroot/usr/include/stdint.h
@@ -0,0 +1,10 @@
+#ifndef _STDINT_H
+#define _STDINT_H
+
+typedef unsigned char uint8_t; typedef signed char int8_t;
+typedef unsigned short uint16_t; typedef short int16_t;
+typedef unsigned int uint32_t; typedef int int32_t;
+typedef unsigned long uint64_t; typedef long int64_t;
+typedef unsigned long uintptr_t; typedef long intptr_t;
+
+#endif
diff --git a/sysroot/usr/include/stdio.h b/sysroot/usr/include/stdio.h
new file mode 100644
index 0000000..9f6929e
--- /dev/null
+++ b/sysroot/usr/include/stdio.h
@@ -0,0 +1,15 @@
+#ifndef _STDIO_H
+#define _STDIO_H
+
+#define EOF (-1)
+
+int putchar(int character);
+int getchar(void);
+int puts(const char* string);
+int printf(const char* format, ...);
+
+// revel only, not part of stdc
+// read a line from stdin -> returns length
+int readline(char* buffer, int max_length);
+
+#endif
diff --git a/sysroot/usr/include/stdlib.h b/sysroot/usr/include/stdlib.h
new file mode 100644
index 0000000..7950258
--- /dev/null
+++ b/sysroot/usr/include/stdlib.h
@@ -0,0 +1,17 @@
+#ifndef _STDLIB_H
+#define _STDLIB_H
+
+#include <stddef.h>
+
+void* malloc(size_t length);
+void free(void* pointer);
+void* calloc(size_t count, size_t size);
+void* realloc(void* pointer, size_t length);
+
+void exit(int code) __attribute__((noreturn));
+
+int atoi(const char* string);
+long atol(const char* string);
+int abs(int value);
+
+#endif
diff --git a/sysroot/usr/include/string.h b/sysroot/usr/include/string.h
new file mode 100644
index 0000000..2177ad6
--- /dev/null
+++ b/sysroot/usr/include/string.h
@@ -0,0 +1,17 @@
+#ifndef _STRING_H
+#define _STRING_H
+
+#include <stddef.h>
+
+size_t strlen(const char* string);
+int strcmp(const char* a, const char* b);
+int strncmp(const char* a, const char* b, size_t length);
+char* strcpy(char* destination, const char* source);
+char* strncpy(char* destination, const char* source, size_t length);
+
+void* memcpy(void* destination, const void* source, size_t length);
+void* memmove(void* destination, const void* source, size_t length);
+void* memset(void* destination, int value, size_t length);
+int memcmp(const void* a, const void* b, size_t length);
+
+#endif
diff --git a/sysroot/usr/include/sys/syscall.h b/sysroot/usr/include/sys/syscall.h
new file mode 100644
index 0000000..4a23a53
--- /dev/null
+++ b/sysroot/usr/include/sys/syscall.h
@@ -0,0 +1,34 @@
+#ifndef _SYS_SYSCALL_H
+#define _SYS_SYSCALL_H
+
+#define SYS_exit 0
+#define SYS_write 1
+#define SYS_read 2
+#define SYS_open 7
+#define SYS_close 8
+#define SYS_lseek 9
+#define SYS_brk 10
+#define SYS_sbrk 11
+
+static inline long __syscall1(long number, long a1)
+{
+ long result;
+ __asm__ volatile("int $0x80" : "=a"(result) : "a"(number), "D"(a1) : "memory");
+ return result;
+}
+
+static inline long __syscall2(long number, long a1, long a2)
+{
+ long result;
+ __asm__ volatile("int $0x80" : "=a"(result) : "a"(number), "D"(a1), "S"(a2) : "memory");
+ return result;
+}
+
+static inline long __syscall3(long number, long a1, long a2, long a3)
+{
+ long result;
+ __asm__ volatile("int $0x80" : "=a"(result) : "a"(number), "D"(a1), "S"(a2), "d"(a3) : "memory");
+ return result;
+}
+
+#endif
diff --git a/sysroot/usr/include/unistd.h b/sysroot/usr/include/unistd.h
new file mode 100644
index 0000000..f5a67ab
--- /dev/null
+++ b/sysroot/usr/include/unistd.h
@@ -0,0 +1,18 @@
+#ifndef _UNISTD_H
+#define _UNISTD_H
+
+#include <stddef.h>
+
+#define SEEK_SET 0
+#define SEEK_CUR 1
+#define SEEK_END 2
+
+long read(int fd, void* buffer, size_t length);
+long write(int fd, const void* buffer, size_t length);
+int close(int fd);
+long lseek(int fd, long offset, int whence);
+
+void* sbrk(long increment);
+int brk(void* address);
+
+#endif
diff --git a/sysroot/usr/lib/libc/crt0.c b/sysroot/usr/lib/libc/crt0.c
new file mode 100644
index 0000000..16c3a94
--- /dev/null
+++ b/sysroot/usr/lib/libc/crt0.c
@@ -0,0 +1,28 @@
+#include <stdlib.h>
+
+extern int main(int argc, char** argv);
+
+void _start(const char* arg, unsigned long arglen)
+{
+ static char arg_buffer[256];
+ char* argv[3];
+ int argc = 1;
+ argv[0] = "";
+
+ if (arglen > 0)
+ {
+ unsigned long count = arglen;
+ if (count > sizeof(arg_buffer) - 1)
+ count = sizeof(arg_buffer) - 1;
+ for (unsigned long i = 0; i < count; i++)
+ arg_buffer[i] = arg[i];
+ arg_buffer[count] = 0;
+ argv[1] = arg_buffer;
+ argc = 2;
+ }
+ else
+ argv[1] = NULL;
+
+ argv[argc] = NULL;
+ exit(main(argc, argv));
+}
diff --git a/sysroot/usr/lib/libc/stdio.c b/sysroot/usr/lib/libc/stdio.c
new file mode 100644
index 0000000..d0e7ad7
--- /dev/null
+++ b/sysroot/usr/lib/libc/stdio.c
@@ -0,0 +1,211 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdarg.h>
+
+int putchar(int character)
+{
+ char byte = (char)character;
+ if (write(1, &byte, 1) != 1)
+ return EOF;
+ return (unsigned char)byte;
+}
+
+int getchar(void)
+{
+ char byte;
+ if (read(0, &byte, 1) <= 0)
+ return EOF;
+ return (unsigned char)byte;
+}
+
+int puts(const char* string)
+{
+ (void)write(1, string, strlen(string));
+ (void)write(1, "\n", 1);
+ return 0;
+}
+
+static int format_unsigned(char* buffer, unsigned long value, int base, int upper)
+{
+ const char* digits = upper ? "0123456789ABCDEF" : "0123456789abcdef";
+ char temp[32];
+ int count = 0;
+ if (value == 0)
+ temp[count++] = '0';
+ while (value > 0)
+ {
+ temp[count++] = digits[value % (unsigned)base];
+ value /= (unsigned)base;
+ }
+ for (int i = 0; i < count; i++)
+ buffer[i] = temp[count - 1 - i];
+ return count;
+}
+
+static int format_signed(char* buffer, long value)
+{
+ int negative = value < 0;
+ unsigned long magnitude = negative ? (unsigned long)(-value) : (unsigned long)value;
+ int count = 0;
+ if (negative)
+ buffer[count++] = '-';
+ return count + format_unsigned(buffer + count, magnitude, 10, 0);
+}
+
+#define PRINTF_BUFFER 256
+
+// yoinked straight off open source
+int printf(const char* format, ...)
+{
+ char out[PRINTF_BUFFER];
+ int filled = 0;
+ int total = 0;
+ va_list args;
+ va_start(args, format);
+
+#define FLUSH() \
+ do { \
+ if (filled > 0) \
+ { \
+ (void)write(1, out, filled); \
+ filled = 0; \
+ } \
+ } while (0)
+#define EMIT(ch) \
+ do { \
+ if (filled == PRINTF_BUFFER) \
+ FLUSH(); \
+ out[filled++] = (char)(ch); \
+ total++; \
+ } while (0)
+
+ for (const char* cursor = format; *cursor; cursor++)
+ {
+ if (*cursor != '%')
+ {
+ EMIT(*cursor);
+ continue;
+ }
+
+ cursor++;
+ if (*cursor == '%')
+ {
+ EMIT('%');
+ continue;
+ }
+
+ int zero_pad = 0;
+ if (*cursor == '0')
+ {
+ zero_pad = 1;
+ cursor++;
+ }
+ int width = 0;
+ while (*cursor >= '0' && *cursor <= '9')
+ {
+ width = width * 10 + (*cursor - '0');
+ cursor++;
+ }
+ int is_long = 0;
+ while (*cursor == 'l')
+ {
+ is_long = 1;
+ cursor++;
+ }
+
+ char conversion = *cursor;
+ if (conversion == 's')
+ {
+ const char* string = va_arg(args, const char*);
+ if (!string)
+ string = "(null)";
+ int length = (int)strlen(string);
+ for (int i = length; i < width; i++)
+ EMIT(' ');
+ for (int i = 0; i < length; i++)
+ EMIT(string[i]);
+ continue;
+ }
+ if (conversion == 'c')
+ {
+ int character = va_arg(args, int);
+ for (int i = 1; i < width; i++)
+ EMIT(' ');
+ EMIT(character);
+ continue;
+ }
+
+ char number[34];
+ int length = 0;
+ if (conversion == 'd' || conversion == 'i')
+ {
+ long value = is_long ? va_arg(args, long) : (long)va_arg(args, int);
+ length = format_signed(number, value);
+ }
+ else if (conversion == 'u')
+ {
+ unsigned long value = is_long ? va_arg(args, unsigned long) : (unsigned long)va_arg(args, unsigned int);
+ length = format_unsigned(number, value, 10, 0);
+ }
+ else if (conversion == 'x' || conversion == 'X')
+ {
+ unsigned long value = is_long ? va_arg(args, unsigned long) : (unsigned long)va_arg(args, unsigned int);
+ length = format_unsigned(number, value, 16, conversion == 'X');
+ }
+ else if (conversion == 'p')
+ {
+ unsigned long value = (unsigned long)va_arg(args, void*);
+ EMIT('0');
+ EMIT('x');
+ length = format_unsigned(number, value, 16, 0);
+ }
+ else
+ {
+ EMIT('%');
+ EMIT(conversion);
+ continue;
+ }
+
+ for (int i = length; i < width; i++)
+ EMIT(zero_pad ? '0' : ' ');
+ for (int i = 0; i < length; i++)
+ EMIT(number[i]);
+ }
+
+ FLUSH();
+ va_end(args);
+ return total;
+
+#undef EMIT
+#undef FLUSH
+}
+
+int readline(char* buffer, int max_length)
+{
+ int length = 0;
+ for (;;)
+ {
+ char character;
+ if (read(0, &character, 1) <= 0)
+ break;
+ if (character == '\n')
+ break;
+ if (character == '\b')
+ {
+ if (length > 0)
+ {
+ length--;
+ (void)write(1, "\b \b", 3);
+ }
+ continue;
+ }
+ if (length < max_length - 1)
+ {
+ buffer[length++] = character;
+ (void)write(1, &character, 1);
+ }
+ }
+ buffer[length] = 0;
+ return length;
+}
diff --git a/sysroot/usr/lib/libc/stdlib.c b/sysroot/usr/lib/libc/stdlib.c
new file mode 100644
index 0000000..a0a86b9
--- /dev/null
+++ b/sysroot/usr/lib/libc/stdlib.c
@@ -0,0 +1,185 @@
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+
+#define HEAP_HEADER 16UL
+#define HEAP_ALIGN 16UL
+#define HEAP_MIN 32UL
+#define HEAP_CHUNK (64UL * 1024UL)
+
+static unsigned long heap_start = 0;
+static unsigned long heap_end = 0;
+static unsigned long heap_rover = 0;
+
+static unsigned long heap_block_size(unsigned long block)
+{
+ return *(unsigned long*)block & ~15UL;
+}
+
+static int heap_block_used(unsigned long block)
+{
+ return (int)(*(unsigned long*)block & 1UL);
+}
+
+static void heap_set(unsigned long block, unsigned long size, int used)
+{
+ *(unsigned long*)block = size | (used ? 1UL : 0UL);
+}
+
+static unsigned long heap_align(unsigned long value)
+{
+ return (value + HEAP_ALIGN - 1UL) & ~(HEAP_ALIGN - 1UL);
+}
+
+// pull another hunk off sbrk and drop a free block over it
+static int heap_grow(unsigned long need)
+{
+ unsigned long want = heap_align(need);
+ if (want < HEAP_CHUNK)
+ want = HEAP_CHUNK;
+ unsigned long got = (unsigned long)sbrk((long)want);
+ if ((long)got < 0)
+ return 0;
+ if (heap_start == 0)
+ {
+ heap_start = got;
+ heap_end = got;
+ heap_rover = got;
+ }
+ heap_set(heap_end, want, 0);
+ heap_end += want;
+ return 1;
+}
+
+// fire O(n) malloc implementation frfr
+void* malloc(size_t length)
+{
+ if (length == 0)
+ return NULL;
+ unsigned long need = heap_align(HEAP_HEADER + length);
+ if (need < HEAP_MIN)
+ need = HEAP_MIN;
+
+ for (;;)
+ {
+ if (heap_rover < heap_start || heap_rover >= heap_end)
+ heap_rover = heap_start;
+ unsigned long block = heap_rover;
+ unsigned long limit = heap_end;
+ for (int pass = 0; pass < 2; pass++)
+ {
+ while (block < limit)
+ {
+ if (!heap_block_used(block))
+ {
+ // lazily coalesce the free run starting here
+ unsigned long size = heap_block_size(block);
+ while (block + size < heap_end && !heap_block_used(block + size))
+ size += heap_block_size(block + size);
+ heap_set(block, size, 0);
+ if (size >= need)
+ {
+ if (size >= need + HEAP_MIN)
+ {
+ heap_set(block, need, 1);
+ heap_set(block + need, size - need, 0);
+ heap_rover = block + need;
+ }
+ else
+ {
+ heap_set(block, size, 1);
+ heap_rover = block + size;
+ }
+ if (heap_rover >= heap_end)
+ heap_rover = heap_start;
+ return (void*)(block + HEAP_HEADER);
+ }
+ }
+ block += heap_block_size(block);
+ }
+ block = heap_start;
+ limit = heap_rover;
+ }
+ if (!heap_grow(need))
+ return NULL;
+ }
+}
+
+void free(void* pointer)
+{
+ if (pointer == NULL)
+ return;
+ unsigned long block = (unsigned long)pointer - HEAP_HEADER;
+ heap_set(block, heap_block_size(block), 0);
+}
+
+void* calloc(size_t count, size_t size)
+{
+ unsigned long total = (unsigned long)count * (unsigned long)size;
+ unsigned char* bytes = malloc(total);
+ if (bytes)
+ for (unsigned long i = 0; i < total; i++)
+ bytes[i] = 0;
+ return bytes;
+}
+
+void* realloc(void* pointer, size_t length)
+{
+ if (pointer == NULL)
+ return malloc(length);
+ if (length == 0)
+ {
+ free(pointer);
+ return NULL;
+ }
+ unsigned long block = (unsigned long)pointer - HEAP_HEADER;
+ unsigned long have = heap_block_size(block) - HEAP_HEADER;
+ if (length <= have)
+ return pointer;
+ unsigned char* grown = malloc(length);
+ if (!grown)
+ return NULL;
+ unsigned char* source = pointer;
+ for (unsigned long i = 0; i < have; i++)
+ grown[i] = source[i];
+ free(pointer);
+ return grown;
+}
+
+void exit(int code)
+{
+ __syscall1(SYS_exit, code);
+ for (;;)
+ ;
+}
+
+long atol(const char* string)
+{
+ while (*string == ' ' || *string == '\t')
+ string++;
+ int negative = 0;
+ if (*string == '-')
+ {
+ negative = 1;
+ string++;
+ }
+ else if (*string == '+')
+ string++;
+ long value = 0;
+ while (*string >= '0' && *string <= '9')
+ {
+ value = value * 10 + (*string - '0');
+ string++;
+ }
+ return negative ? -value : value;
+}
+
+int atoi(const char* string)
+{
+ return (int)atol(string);
+}
+
+int abs(int value)
+{
+ return value < 0 ? -value : value;
+}
diff --git a/sysroot/usr/lib/libc/string.c b/sysroot/usr/lib/libc/string.c
new file mode 100644
index 0000000..7bbc0c2
--- /dev/null
+++ b/sysroot/usr/lib/libc/string.c
@@ -0,0 +1,92 @@
+#include <string.h>
+
+size_t strlen(const char* string)
+{
+ size_t length = 0;
+ while (string[length])
+ length++;
+ return length;
+}
+
+int strcmp(const char* a, const char* b)
+{
+ while (*a && *a == *b)
+ {
+ a++;
+ b++;
+ }
+
+ return (int)(unsigned char)*a - (int)(unsigned char)*b;
+}
+
+int strncmp(const char* a, const char* b, size_t length)
+{
+ for (size_t i = 0; i < length; i++)
+ {
+ unsigned char ca = (unsigned char)a[i];
+ unsigned char cb = (unsigned char)b[i];
+ if (ca != cb)
+ return (int)ca - (int)cb;
+ if (ca == 0)
+ return 0;
+ }
+ return 0;
+}
+
+char* strcpy(char* destination, const char* source)
+{
+ char* out = destination;
+ while ((*out++ = *source++))
+ ;
+ return destination;
+}
+
+char* strncpy(char* destination, const char* source, size_t length)
+{
+ size_t i = 0;
+ for (; i < length && source[i]; i++)
+ destination[i] = source[i];
+ for (; i < length; i++)
+ destination[i] = 0;
+ return destination;
+}
+
+void* memcpy(void* destination, const void* source, size_t length)
+{
+ unsigned char* out = destination;
+ const unsigned char* in = source;
+ for (size_t i = 0; i < length; i++)
+ out[i] = in[i];
+ return destination;
+}
+
+void* memmove(void* destination, const void* source, size_t length)
+{
+ unsigned char* out = destination;
+ const unsigned char* in = source;
+ if (out < in)
+ for (size_t i = 0; i < length; i++)
+ out[i] = in[i];
+ else
+ for (size_t i = length; i > 0; i--)
+ out[i - 1] = in[i - 1];
+ return destination;
+}
+
+void* memset(void* destination, int value, size_t length)
+{
+ unsigned char* out = destination;
+ for (size_t i = 0; i < length; i++)
+ out[i] = (unsigned char)value;
+ return destination;
+}
+
+int memcmp(const void* a, const void* b, size_t length)
+{
+ const unsigned char* aa = a;
+ const unsigned char* bb = b;
+ for (size_t i = 0; i < length; i++)
+ if (aa[i] != bb[i])
+ return (int)aa[i] - (int)bb[i];
+ return 0;
+}
diff --git a/sysroot/usr/lib/libc/syscalls.c b/sysroot/usr/lib/libc/syscalls.c
new file mode 100644
index 0000000..ad959b9
--- /dev/null
+++ b/sysroot/usr/lib/libc/syscalls.c
@@ -0,0 +1,38 @@
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/syscall.h>
+
+long read(int fd, void* buffer, size_t length)
+{
+ return __syscall3(SYS_read, fd, (long)buffer, (long)length);
+}
+
+long write(int fd, const void* buffer, size_t length)
+{
+ return __syscall3(SYS_write, fd, (long)buffer, (long)length);
+}
+
+int open(const char* path, int flags)
+{
+ return (int)__syscall2(SYS_open, (long)path, flags);
+}
+
+int close(int fd)
+{
+ return (int)__syscall1(SYS_close, fd);
+}
+
+long lseek(int fd, long offset, int whence)
+{
+ return __syscall3(SYS_lseek, fd, offset, whence);
+}
+
+void* sbrk(long increment)
+{
+ return (void*)__syscall1(SYS_sbrk, increment);
+}
+
+int brk(void* address)
+{
+ return (int)__syscall1(SYS_brk, (long)address);
+}
diff --git a/fonts/acorn8.psf b/sysroot/usr/share/acorn8.psf
index 57bc46b..57bc46b 100644
--- a/fonts/acorn8.psf
+++ b/sysroot/usr/share/acorn8.psf
Binary files differ
diff --git a/fonts/dejavu.ttf b/sysroot/usr/share/dejavu.ttf
index 597b2e0..597b2e0 100644
--- a/fonts/dejavu.ttf
+++ b/sysroot/usr/share/dejavu.ttf
Binary files differ
diff --git a/fonts/pearl8.psf b/sysroot/usr/share/pearl8.psf
index acf7939..acf7939 100644
--- a/fonts/pearl8.psf
+++ b/sysroot/usr/share/pearl8.psf
Binary files differ
diff --git a/fonts/sun16.psf b/sysroot/usr/share/sun16.psf
index 8042ba3..8042ba3 100644
--- a/fonts/sun16.psf
+++ b/sysroot/usr/share/sun16.psf
Binary files differ
diff --git a/fonts/terminess.ttf b/sysroot/usr/share/terminess.ttf
index 0055a2c..0055a2c 100644
--- a/fonts/terminess.ttf
+++ b/sysroot/usr/share/terminess.ttf
Binary files differ
diff --git a/fonts/vga16.psf b/sysroot/usr/share/vga16.psf
index 652b07b..652b07b 100644
--- a/fonts/vga16.psf
+++ b/sysroot/usr/share/vga16.psf
Binary files differ
diff --git a/fonts/vga8.psf b/sysroot/usr/share/vga8.psf
index 3fcce09..3fcce09 100644
--- a/fonts/vga8.psf
+++ b/sysroot/usr/share/vga8.psf
Binary files differ
diff --git a/user/calc.c b/user/calc.c
index cf5b1d2..63fa9c6 100644
--- a/user/calc.c
+++ b/user/calc.c
@@ -1,20 +1,20 @@
-#include "user.h"
+#include <stdio.h>
static int is_digit(char character)
{
return character >= '0' && character <= '9';
}
-void _start(void)
+int main(void)
{
- put("calc, e.g. 3 + 4 * 2 (left to right), empty line quits\n");
+ printf("calc, e.g. 3 + 4 * 2 (left to right), empty line quits\n");
char line[128];
for (;;)
{
- put("> ");
- int length = read_line(line, 128);
- put("\n");
+ printf("> ");
+ int length = readline(line, 128);
+ printf("\n");
if (length == 0)
break;
@@ -49,7 +49,7 @@ void _start(void)
{
if (value == 0)
{
- put("divide by zero\n");
+ printf("divide by zero\n");
valid = 0;
break;
}
@@ -66,19 +66,15 @@ void _start(void)
}
else
{
- put("bad character\n");
+ printf("bad character\n");
valid = 0;
break;
}
}
if (valid && saw_number)
- {
- put("= ");
- put_int(accumulator);
- put("\n");
- }
+ printf("= %ld\n", accumulator);
}
- sys_exit(0);
+ return 0;
}
diff --git a/user/chat.c b/user/chat.c
index 1657c73..7a1d5c8 100644
--- a/user/chat.c
+++ b/user/chat.c
@@ -1,32 +1,28 @@
-#include "user.h"
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
-void _start(const char* arg, unsigned long arglen)
+int main(int argc, char** argv)
{
- if (arglen == 0)
+ if (argc < 2)
{
- put("usage: run chat <path>\n");
- sys_exit(1);
+ printf("usage: run chat <path>\n");
+ return 1;
}
- char path[128];
- unsigned long i = 0;
- for (; i < arglen && i < sizeof(path) - 1; i++)
- path[i] = arg[i];
- path[i] = 0;
-
- long fd = sys_open(path, 0);
+ const char* path = argv[1];
+ int fd = open(path, O_RDONLY);
if (fd < 0)
{
- put("chat: ");
- put(path);
- put(": cannot open\n");
- sys_exit(1);
+ printf("chat: %s: cannot open\n", path);
+ return 1;
}
char buffer[256];
long bytes_read;
- while ((bytes_read = sys_read(fd, buffer, sizeof(buffer))) > 0)
- (void)sys_write(1, buffer, (unsigned long)bytes_read);
- (void)sys_close(fd);
- sys_exit(0);
+ while ((bytes_read = read(fd, buffer, sizeof(buffer))) > 0)
+ write(1, buffer, (unsigned long)bytes_read);
+
+ close(fd);
+ return 0;
}
diff --git a/user/hexview.c b/user/hexview.c
index 5d21711..44bbe38 100644
--- a/user/hexview.c
+++ b/user/hexview.c
@@ -1,103 +1,75 @@
-#include "user.h"
-
-static const char HEX[] = "0123456789abcdef";
-
-static void put_hex8(unsigned char byte)
-{
- char digits[2] = { HEX[byte >> 4], HEX[byte & 15] };
- (void)sys_write(1, digits, 2);
-}
-
-static void put_hex32(unsigned long value)
-{
- char digits[8];
- for (int nibble = 0; nibble < 8; nibble++)
- digits[nibble] = HEX[(value >> ((7 - nibble) * 4)) & 15];
- (void)sys_write(1, digits, 8);
-}
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
#define PAGE 256
#define COLS 16
-void _start(const char* arg, unsigned long arglen)
+int main(int argc, char** argv)
{
- char name[64];
-
- if (arglen > 0 && arglen < 64)
- {
- for (unsigned long i = 0; i < arglen; i++)
- name[i] = arg[i];
- name[arglen] = 0;
- }
+ char prompt_name[64];
+ const char* name;
+ if (argc >= 2)
+ name = argv[1];
else
{
- put("hexview, type a filename\nfile: ");
- (void)read_line(name, 64);
- put("\n");
+ printf("hexview, type a filename\nfile: ");
+ readline(prompt_name, 64);
+ printf("\n");
+ name = prompt_name;
}
- long size = sys_fs_size(name);
- if (size < 0)
+ int fd = open(name, O_RDONLY);
+ if (fd < 0)
{
- put("no such file\n");
- sys_exit(1);
+ printf("no such file\n");
+ return 1;
}
+ long size = lseek(fd, 0, SEEK_END);
unsigned long offset = 0;
char buffer[PAGE];
for (;;)
{
- long count = sys_fs_read(name, offset, buffer, PAGE);
+ lseek(fd, (long)offset, SEEK_SET);
+ long count = read(fd, buffer, PAGE);
- put("--- ");
- put(name);
- put(" @ 0x");
- put_hex32(offset);
- put(" / 0x");
- put_hex32((unsigned long)size);
- put(" ---\n");
+ printf("--- %s @ 0x%08lx / 0x%08lx ---\n", name, offset, (unsigned long)size);
for (long row = 0; row < count; row += COLS)
{
- put_hex32(offset + (unsigned long)row);
- put(": ");
+ printf("%08lx: ", offset + (unsigned long)row);
for (int column = 0; column < COLS; column++)
{
if (row + column < count)
- {
- put_hex8((unsigned char)buffer[row + column]);
- (void)sys_write(1, " ", 1);
- }
+ printf("%02x ", (unsigned char)buffer[row + column]);
else
- put(" ");
+ printf(" ");
}
- put(" ");
+ printf(" ");
for (int column = 0; column < COLS && row + column < count; column++)
{
char character = buffer[row + column];
- if (character >= 32 && character < 127)
- (void)sys_write(1, &character, 1);
- else
- (void)sys_write(1, ".", 1);
+ putchar((character >= 32 && character < 127) ? character : '.');
}
- put("\n");
+ printf("\n");
}
- put("[n]ext [p]rev [q]uit (or up/down arrows) > ");
- char key = (char)get_char();
+ printf("[n]ext [p]rev [q]uit (or up/down arrows) > ");
+ int key = getchar();
if (key == 27) // ESC
{
- (void)get_char();
- char final = (char)get_char();
+ getchar();
+ int final = getchar();
if (final == 'A')
key = 'p';
else if (final == 'B')
key = 'n';
}
- put("\n");
+ printf("\n");
if (key == 'q')
break;
if (key == 'n' && offset + PAGE < (unsigned long)size)
@@ -106,5 +78,6 @@ void _start(const char* arg, unsigned long arglen)
offset -= PAGE;
}
- sys_exit(0);
+ close(fd);
+ return 0;
}
diff --git a/user/membrk.c b/user/membrk.c
index f1949cc..7d73adf 100644
--- a/user/membrk.c
+++ b/user/membrk.c
@@ -1,31 +1,26 @@
-#include "user.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
static void check(const char* name, int ok)
{
- put(ok ? "ok " : "FAIL ");
- put(name);
- put("\n");
+ printf("%s%s\n", ok ? "ok " : "FAIL ", name);
}
-void _start(const char* arg, unsigned long arglen)
+int main(void)
{
- (void)arg;
- (void)arglen;
-
- long start = (long)sys_sbrk(0);
- put("heap base: ");
- put_int(start);
- put("\n");
+ long start = (long)sbrk(0);
+ printf("heap base: %ld\n", start);
// obese alloc test
char* run[80];
for (int i = 0; i < 80; i++)
- run[i] = (char*)malloc(4000);
- long run_after = (long)sys_sbrk(0);
+ run[i] = malloc(4000);
+ long run_after = (long)sbrk(0);
for (int i = 0; i < 80; i++)
free(run[i]);
- char* merged = (char*)malloc(80 * 4000 - 8000);
- long merge_after = (long)sys_sbrk(0);
+ char* merged = malloc(80 * 4000 - 8000);
+ long merge_after = (long)sbrk(0);
check("freed neighbours coalesce", merged != 0 && merge_after <= run_after);
free(merged);
@@ -33,7 +28,7 @@ void _start(const char* arg, unsigned long arglen)
char* blocks[16];
for (int i = 0; i < 16; i++)
{
- blocks[i] = (char*)malloc(64);
+ blocks[i] = malloc(64);
for (int j = 0; j < 64; j++)
blocks[i][j] = (char)(i * 7 + j);
}
@@ -46,7 +41,7 @@ void _start(const char* arg, unsigned long arglen)
// a big block spanning several pages written edge to edge
unsigned long big = 20000;
- unsigned char* buffer = (unsigned char*)malloc(big);
+ unsigned char* buffer = malloc(big);
for (unsigned long k = 0; k < big; k++)
buffer[k] = (unsigned char)(k & 0xff);
int big_ok = 1;
@@ -55,18 +50,18 @@ void _start(const char* arg, unsigned long arglen)
big_ok = 0;
check("big multi page alloc", big_ok);
- // testing that the the heap must doesnt grow across the loop
- long churn_before = (long)sys_sbrk(0);
+ // testing that the heap doesnt grow across the loop
+ long churn_before = (long)sbrk(0);
for (int i = 0; i < 2000; i++)
{
void* pointer = malloc(500);
free(pointer);
}
- long churn_after = (long)sys_sbrk(0);
+ long churn_after = (long)sbrk(0);
check("alloc/free churn reclaims (no growth)", churn_before == churn_after);
// calloc dirty test
- unsigned char* zeroed = (unsigned char*)calloc(200, 1);
+ unsigned char* zeroed = calloc(200, 1);
int zero_ok = 1;
for (int i = 0; i < 200; i++)
if (zeroed[i] != 0)
@@ -74,20 +69,18 @@ void _start(const char* arg, unsigned long arglen)
check("calloc is zeroed", zero_ok);
// realloc test
- char* grown = (char*)malloc(32);
+ char* grown = malloc(32);
for (int i = 0; i < 32; i++)
grown[i] = (char)(i + 1);
- grown = (char*)realloc(grown, 500);
+ grown = realloc(grown, 500);
int grow_ok = 1;
for (int i = 0; i < 32; i++)
if (grown[i] != (char)(i + 1))
grow_ok = 0;
check("realloc grows and preserves data", grow_ok);
- long end = (long)sys_sbrk(0);
- put("heap high water: ");
- put_int(end - start);
- put(" bytes\n");
+ long end = (long)sbrk(0);
+ printf("heap high water: %ld bytes\n", end - start);
- sys_exit(0);
+ return 0;
}
diff --git a/user/primes.c b/user/primes.c
index 49c545a..5501c32 100644
--- a/user/primes.c
+++ b/user/primes.c
@@ -1,22 +1,19 @@
-#include "user.h"
+#include <stdio.h>
+#include <stdlib.h>
-void _start(void)
+int main(void)
{
- put("primes up to N, enter N (empty line quits)\n");
+ printf("primes up to N, enter N (empty line quits)\n");
char line[32];
for (;;)
{
- put("> ");
- int length = read_line(line, 32);
- put("\n");
+ printf("> ");
+ int length = readline(line, 32);
+ printf("\n");
if (length == 0)
break;
- long limit = 0;
- for (int position = 0; position < length; position++)
- if (line[position] >= '0' && line[position] <= '9')
- limit = limit * 10 + (line[position] - '0');
-
+ long limit = atol(line);
int count = 0;
for (long candidate = 2; candidate <= limit; candidate++)
{
@@ -29,14 +26,11 @@ void _start(void)
}
if (prime)
{
- put_int(candidate);
- put(" ");
+ printf("%ld ", candidate);
count++;
}
}
- put("\n");
- put_int(count);
- put(" primes\n");
+ printf("\n%d primes\n", count);
}
- sys_exit(0);
+ return 0;
}
diff --git a/user/save.c b/user/save.c
index 2ac065f..056e160 100644
--- a/user/save.c
+++ b/user/save.c
@@ -1,45 +1,37 @@
-#include "user.h"
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
-void _start(const char* arg, unsigned long arglen)
+int main(int argc, char** argv)
{
- if (arglen == 0 || arglen >= 120)
+ if (argc < 2)
{
- put("usage: run save <path>\n");
- sys_exit(1);
+ printf("usage: run save <path>\n");
+ return 1;
}
- char name[128];
- for (unsigned long i = 0; i < arglen; i++)
- name[i] = arg[i];
- name[arglen] = 0;
-
- long fd = sys_open(name, O_CREAT | O_TRUNC | O_WRONLY);
+ const char* name = argv[1];
+ int fd = open(name, O_CREAT | O_TRUNC | O_WRONLY);
if (fd < 0)
{
- put("save: ");
- put(name);
- put(": cannot open\n");
- sys_exit(1);
+ printf("save: %s: cannot open\n", name);
+ return 1;
}
- put("saving to ");
- put(name);
- put(" -- type lines, a single . saves\n");
+ printf("saving to %s -- type lines, a single . saves\n", name);
for (;;)
{
char line[256];
- int bytes_read = read_line(line, 256);
- put("\n");
+ int bytes_read = readline(line, 256);
+ printf("\n");
if (bytes_read == 1 && line[0] == '.')
break;
- (void)sys_write(fd, line, (unsigned long)bytes_read);
- (void)sys_write(fd, "\n", 1);
+ write(fd, line, (unsigned long)bytes_read);
+ write(fd, "\n", 1);
}
- (void)sys_close(fd);
- put("saved ");
- put(name);
- put("\n");
- sys_exit(0);
+ close(fd);
+ printf("saved %s\n", name);
+ return 0;
}
diff --git a/user/user.h b/user/user.h
deleted file mode 100644
index 58a1bc5..0000000
--- a/user/user.h
+++ /dev/null
@@ -1,309 +0,0 @@
-#define SEEK_SET 0
-#define SEEK_CUR 1
-#define SEEK_END 2
-
-#define O_WRONLY 1
-#define O_CREAT 0x40
-#define O_TRUNC 0x200
-#define O_APPEND 0x400
-
-static inline __attribute__((warn_unused_result)) long sys_write(long fd, const char* buffer, unsigned long length)
-{
- long result;
- __asm__ volatile("int $0x80" : "=a"(result) : "a"(1L), "D"(fd), "S"(buffer), "d"(length) : "memory");
- return result;
-}
-
-static inline __attribute__((warn_unused_result)) long sys_read(long fd, char* buffer, unsigned long length)
-{
- long result;
- __asm__ volatile("int $0x80" : "=a"(result) : "a"(2L), "D"(fd), "S"(buffer), "d"(length) : "memory");
- return result;
-}
-
-static inline __attribute__((warn_unused_result)) long sys_open(const char* path, long flags)
-{
- long result;
- __asm__ volatile("int $0x80" : "=a"(result) : "a"(7L), "D"(path), "S"(flags) : "memory");
- return result;
-}
-
-static inline __attribute__((warn_unused_result)) long sys_close(long fd)
-{
- long result;
- __asm__ volatile("int $0x80" : "=a"(result) : "a"(8L), "D"(fd) : "memory");
- return result;
-}
-
-static inline __attribute__((warn_unused_result)) long sys_lseek(long fd, long offset, long whence)
-{
- long result;
- __asm__ volatile("int $0x80" : "=a"(result) : "a"(9L), "D"(fd), "S"(offset), "d"(whence) : "memory");
- return result;
-}
-
-static inline void sys_exit(long code)
-{
- __asm__ volatile("int $0x80" : : "a"(0L), "D"(code) : "memory");
- for (;;);
-}
-
-static inline __attribute__((warn_unused_result)) long sys_fs_size(const char* name)
-{
- long result;
- __asm__ volatile("int $0x80" : "=a"(result) : "a"(4L), "D"(name) : "memory");
- return result;
-}
-
-static inline __attribute__((warn_unused_result)) long sys_fs_read(const char* name, unsigned long offset, char* buffer, unsigned long length)
-{
- long result;
- __asm__ volatile("int $0x80"
- : "=a"(result)
- : "a"(5L), "D"(name), "S"(offset), "d"(buffer), "c"(length)
- : "memory");
- return result;
-}
-
-static inline __attribute__((warn_unused_result)) long sys_fs_write(const char* name, const char* buffer, unsigned long length)
-{
- long result;
- __asm__ volatile("int $0x80"
- : "=a"(result)
- : "a"(6L), "D"(name), "S"(buffer), "d"(length)
- : "memory");
- return result;
-}
-
-static inline __attribute__((warn_unused_result)) long sys_brk(void* address)
-{
- long result;
- __asm__ volatile("int $0x80" : "=a"(result) : "a"(10L), "D"(address) : "memory");
- return result;
-}
-
-static inline __attribute__((warn_unused_result)) void* sys_sbrk(long increment)
-{
- long result;
- __asm__ volatile("int $0x80" : "=a"(result) : "a"(11L), "D"(increment) : "memory");
- return (void*)result;
-}
-
-// shitty heap implementation
-// temporary af this will be in its own libc
-#define HEAP_HEADER 16UL
-#define HEAP_ALIGN 16UL
-#define HEAP_MIN 32UL
-#define HEAP_CHUNK (64UL * 1024UL)
-
-static unsigned long heap_start = 0;
-static unsigned long heap_end = 0;
-static unsigned long heap_rover = 0;
-
-static inline __attribute__((warn_unused_result)) unsigned long heap_block_size(unsigned long block)
-{
- return *(unsigned long*)block & ~15UL;
-}
-
-static inline __attribute__((warn_unused_result)) int heap_block_used(unsigned long block)
-{
- return (int)(*(unsigned long*)block & 1UL);
-}
-
-static inline void heap_set(unsigned long block, unsigned long size, int used)
-{
- *(unsigned long*)block = size | (used ? 1UL : 0UL);
-}
-
-static inline __attribute__((warn_unused_result)) unsigned long heap_align(unsigned long value)
-{
- return (value + HEAP_ALIGN - 1UL) & ~(HEAP_ALIGN - 1UL);
-}
-
-// pull another hunk off sbrk and drop a free block over it
-static inline __attribute__((warn_unused_result)) int heap_grow(unsigned long need)
-{
- unsigned long want = heap_align(need);
- if (want < HEAP_CHUNK)
- want = HEAP_CHUNK;
- unsigned long got = (unsigned long)sys_sbrk((long)want);
- if ((long)got < 0)
- return 0;
- if (heap_start == 0)
- {
- heap_start = got;
- heap_end = got;
- heap_rover = got;
- }
- heap_set(heap_end, want, 0);
- heap_end += want;
- return 1;
-}
-
-// yummy O(n) malloc implementation
-static inline __attribute__((warn_unused_result)) void* malloc(unsigned long length)
-{
- if (length == 0)
- return 0;
- unsigned long need = heap_align(HEAP_HEADER + length);
- if (need < HEAP_MIN)
- need = HEAP_MIN;
-
- for (;;)
- {
- if (heap_rover < heap_start || heap_rover >= heap_end)
- heap_rover = heap_start;
- unsigned long block = heap_rover;
- unsigned long limit = heap_end;
- for (int pass = 0; pass < 2; pass++)
- {
- while (block < limit)
- {
- if (!heap_block_used(block))
- {
- unsigned long size = heap_block_size(block);
- while (block + size < heap_end && !heap_block_used(block + size))
- size += heap_block_size(block + size);
- heap_set(block, size, 0);
- if (size >= need)
- {
- if (size >= need + HEAP_MIN)
- {
- heap_set(block, need, 1);
- heap_set(block + need, size - need, 0);
- heap_rover = block + need;
- }
- else
- {
- heap_set(block, size, 1);
- heap_rover = block + size;
- }
- if (heap_rover >= heap_end)
- heap_rover = heap_start;
- return (void*)(block + HEAP_HEADER);
- }
- }
- block += heap_block_size(block);
- }
- block = heap_start;
- limit = heap_rover;
- }
- if (!heap_grow(need))
- return 0;
- }
-}
-
-static inline void free(void* pointer)
-{
- if (pointer == 0)
- return;
- unsigned long block = (unsigned long)pointer - HEAP_HEADER;
- heap_set(block, heap_block_size(block), 0);
-}
-
-static inline __attribute__((warn_unused_result)) void* calloc(unsigned long count, unsigned long size)
-{
- unsigned long total = count * size;
- unsigned char* bytes = (unsigned char*)malloc(total);
- if (bytes)
- for (unsigned long i = 0; i < total; i++)
- bytes[i] = 0;
- return bytes;
-}
-
-static inline __attribute__((warn_unused_result)) void* realloc(void* pointer, unsigned long length)
-{
- if (pointer == 0)
- return malloc(length);
- if (length == 0)
- {
- free(pointer);
- return 0;
- }
- unsigned long block = (unsigned long)pointer - HEAP_HEADER;
- unsigned long have = heap_block_size(block) - HEAP_HEADER;
- if (length <= have)
- return pointer;
- unsigned char* new_block = (unsigned char*)malloc(length);
- if (!new_block)
- return 0;
- unsigned char* source = (unsigned char*)pointer;
- for (unsigned long i = 0; i < have; i++)
- new_block[i] = source[i];
- free(pointer);
- return new_block;
-}
-
-static inline void put(const char* string)
-{
- unsigned long length = 0;
- while (string[length])
- length++;
- (void)sys_write(1, string, length);
-}
-
-static inline __attribute__((warn_unused_result)) int get_char(void)
-{
- char character;
- if (sys_read(0, &character, 1) <= 0)
- return -1;
- return (unsigned char)character;
-}
-
-static inline __attribute__((warn_unused_result)) int read_line(char* buffer, int max_length)
-{
- int length = 0;
- for (;;)
- {
- char character;
- if (sys_read(0, &character, 1) <= 0)
- break;
- if (character == '\n')
- break;
- if (character == '\b')
- {
- if (length > 0)
- {
- length--;
- (void)sys_write(1, "\b \b", 3);
- }
- continue;
- }
- if (length < max_length - 1)
- {
- buffer[length++] = character;
- (void)sys_write(1, &character, 1);
- }
- }
- buffer[length] = 0;
- return length;
-}
-
-static inline void put_int(long value)
-{
- char buffer[21];
- int length = 0;
- int negative = value < 0;
- unsigned long magnitude = negative ? (unsigned long)(-value) : (unsigned long)value;
-
- if (magnitude == 0)
- buffer[length++] = '0';
-
- while (magnitude > 0)
- {
- buffer[length++] = (char)('0' + magnitude % 10);
- magnitude /= 10;
- }
-
- if (negative)
- buffer[length++] = '-';
-
- for (int left = 0, right = length - 1; left < right; left++, right--)
- {
- char swap = buffer[left];
- buffer[left] = buffer[right];
- buffer[right] = swap;
- }
-
- (void)sys_write(1, buffer, length);
-}