hachem.wtf
aboutsummaryrefslogtreecommitdiff
path: root/build.zig
blob: 469d51326e2f41714bd2ced860ae88c58cd4d1e9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
const std = @import("std");

// the gils coreutils
const gils_tools = .{ "gils", "ls", "tree", "cat", "rm", "mkdir", "touch", "cp", "mv", "wc", "head", "tail", "ed" };

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;

    // 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
    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(@intFromEnum(Feature.mmx));
    query.cpu_features_sub.addFeature(@intFromEnum(Feature.avx));
    query.cpu_features_sub.addFeature(@intFromEnum(Feature.avx2));

    const target = b.resolveTargetQuery(query);

    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,
        }),
    });
    kernel.entry = .{ .symbol_name = "_start" };
    kernel.pie = false;
    kernel.setLinkerScript(b.path("boot/linker.ld"));

    // the big guns
    const revo_dep = b.dependency("revo", .{ .target = target, .optimize = optimize });
    const revo_mod = revo_dep.module("revo");

    var visited: std.AutoHashMap(*std.Build.Module, void) = .init(b.allocator);
    defer visited.deinit();
    kernelize(revo_mod, &visited);

    // 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_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]) });
    }

    // load gils
    inline for (gils_tools) |g| {
        bridge_mod.addAnonymousImport("k_gils_" ++ g, .{ .root_source_file = b.path("gils/" ++ g ++ ".rv") });
    }

    kernel.root_module.addImport("bridge", bridge_mod);

    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]) });
    }

    inline for (.{ "hexview", "calc", "primes", "save" }) |prog| {
        const cc = b.addSystemCommand(&.{
            "zig",                  "cc",
            "-target",              "x86_64-freestanding",
            "-ffreestanding",       "-nostdlib",
            "-static",              "-no-pie",
            "-fno-stack-protector", "-fno-sanitize=all",
            "-Wl,-T,user/link.ld",  "-Wl,--build-id=none",
            "-o",
        });
        const prog_elf = cc.addOutputFileArg(prog ++ ".elf");
        cc.addFileArg(b.path("user/" ++ prog ++ ".c"));
        kernel.root_module.addAnonymousImport("user_" ++ prog, .{ .root_source_file = prog_elf });
    }

    b.installArtifact(kernel);
}

// 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");

    mod.code_model = .kernel;
    mod.red_zone = false;
    mod.single_threaded = true;

    var it = mod.import_table.iterator();
    while (it.next()) |entry| kernelize(entry.value_ptr.*, visited);
}