lumine
UEFI x86_64 bootloader for linux kernel images
build.zig
3878 bytes raw
1const std = @import("std");
2
3const Arch = enum {
4 x86_64,
5 aarch64,
6
7 pub fn target(self: Arch) std.Target.Cpu.Arch {
8 return switch (self) {
9 .x86_64 => .x86_64,
10 .aarch64 => .aarch64,
11 };
12 }
13
14 pub const EfiName = enum { X64, AA64 };
15
16 pub fn efi(self: Arch) EfiName {
17 return switch (self) {
18 .x86_64 => .X64,
19 .aarch64 => .AA64,
20 };
21 }
22};
23
24fn lumineExecutable(b: *std.Build, cpu_arch: Arch, optimize: std.builtin.OptimizeMode) *std.Build.Step.Compile {
25 const target = b.resolveTargetQuery(.{
26 .cpu_arch = cpu_arch.target(),
27 .cpu_model = .baseline,
28 .os_tag = .uefi,
29 });
30
31 return b.addExecutable(.{
32 .name = b.fmt("BOOT{t}", .{cpu_arch.efi()}),
33 .root_module = b.createModule(.{
34 .target = target,
35 .optimize = optimize,
36 .root_source_file = b.path("src/main.zig"),
37 }),
38 });
39}
40
41pub fn build(b: *std.Build) void {
42 const optimize = b.standardOptimizeOption(.{});
43
44 const cpu_arch = b.option(Arch, "arch", "cpu architecture") orelse .x86_64;
45
46 const install_step = b.getInstallStep();
47
48 const lumine_exe = lumineExecutable(b, cpu_arch, optimize);
49 const lumine_install = b.addInstallArtifact(lumine_exe, .{});
50 install_step.dependOn(&lumine_install.step);
51
52 const all_step = b.step("all", "build for all supported architectures");
53
54 inline for (@typeInfo(Arch).@"enum".fields) |field| {
55 const arch_exe = lumineExecutable(b, @field(Arch, field.name), optimize);
56
57 const arch_install = b.addInstallArtifact(arch_exe, .{});
58 all_step.dependOn(&arch_install.step);
59 }
60
61 const qemu_exe = b.option([]const u8, "qemu", "ovveride qemu executable") orelse b.fmt("qemu-system-{t}", .{cpu_arch});
62 const qemu_cmd = b.addSystemCommand(&.{ qemu_exe, "-m", "512M", "-no-reboot", "-no-shutdown", "-serial", "mon:stdio", "-nographic" });
63
64 switch (cpu_arch) {
65 .aarch64 => qemu_cmd.addArgs(&.{ "-M", "virt", "-cpu", "cortex-a57" }),
66 .x86_64 => {},
67 }
68
69 const ovmf_override = b.option(std.Build.LazyPath, "ovmf", "override ovmf firmware dependency");
70 const ovmf_use_dep = b.option(bool, "ovmf-dep", "use ovmf dependency instead") orelse false;
71
72 if (ovmf_use_dep) {
73 if (b.lazyDependency("ovmf", .{})) |ovmf_dep| {
74 const ovmf_code = ovmf_dep.path(b.fmt("ovmf-code-{t}.fd", .{cpu_arch}));
75
76 qemu_cmd.addArg("-bios");
77 qemu_cmd.addFileArg(ovmf_code);
78 }
79 } else if (ovmf_override) |override| {
80 qemu_cmd.addArg("-bios");
81 qemu_cmd.addFileArg(override);
82 } else {
83 const fail = b.addFail("ovmf not specified, either use -Dovmf=PATH_TO_OVMF_CODE_BIN or use -Dovmf-dep to download as dependency");
84 qemu_cmd.step.dependOn(&fail.step);
85 }
86
87 {
88 const boot_dir = b.addTempFiles();
89 _ = boot_dir.addCopyFile(lumine_exe.getEmittedBin(), b.fmt("EFI/BOOT/BOOT{t}.EFI", .{cpu_arch.efi()}));
90
91 const config_file = b.option([]const u8, "config", "path to config file") orelse "res/lumine.zon";
92
93 _ = boot_dir.addCopyFile(b.path(config_file), "lumine.zon");
94
95 // https://codeberg.org/ziglang/zig/issues/32041
96 // https://codeberg.org/dragsbruh/minimux/releases
97 const linux_dir = b.option([]const u8, "linux", "dir containing `vmlinuz` and `initrd.xz`") orelse b.fmt("res/{t}", .{cpu_arch});
98
99 _ = boot_dir.addCopyFile(b.path(linux_dir).path(b, "vmlinuz"), "linux/vmlinuz");
100 _ = boot_dir.addCopyFile(b.path(linux_dir).path(b, "initrd.xz"), "linux/initrd.xz");
101
102 qemu_cmd.addArg("-drive");
103 qemu_cmd.addPrefixedDirectoryArg("format=raw,file=fat:rw:", boot_dir.getDirectory());
104 }
105
106 const run_step = b.step("run", "run in qemu");
107 run_step.dependOn(&qemu_cmd.step);
108}