lumine
UEFI x86_64 bootloader for linux kernel images
src/main.zig
2943 bytes raw
1const std = @import("std");
2const uefi = std.os.uefi;
3const log = std.log;
4const Io = std.Io;
5
6const Chainload = @import("./boot/Chainload.zig");
7const linux = @import("./boot/linux.zig");
8const Config = @import("./Config.zig");
9const Console = @import("./Console.zig");
10const luefi = @import("./luefi.zig");
11
12// TODO: relative to EFI
13const config_paths: []const Config.Path = &.{
14 .{ .boot = "/lumine/config.zon" },
15 .{ .boot = "/lumine/lumine.zon" },
16 .{ .boot = "/lumine.zon" },
17};
18
19pub fn bmain() !uefi.Status {
20 const allocator = uefi.pool_allocator;
21
22 const config: Config = try config: {
23 var file = reader: {
24 for (config_paths) |path| {
25 break :reader luefi.fileOpen(path) catch continue;
26 }
27
28 log.err("failed to detect config, tried paths:", .{});
29 for (config_paths) |path| log.err("\t{f}", .{path});
30 return error.NoConfig;
31 };
32 defer file.close() catch unreachable;
33
34 const source = try allocator.allocSentinel(u8, try luefi.fileSize(file), 0);
35 defer allocator.free(source);
36
37 try luefi.fileReadSlice(file, source);
38
39 break :config std.zon.parse.fromSliceAlloc(Config, allocator, source, null, .{});
40 };
41 defer std.zon.parse.free(allocator, config);
42
43 switch (config.boot) {
44 .chainload => |efi_path| {
45 log.info("loading efi {f}", .{efi_path});
46 const chainload: Chainload = try .load(efi_path);
47 defer chainload.deinit();
48
49 return chainload.start();
50 },
51 .linux => |linux_conf| {
52 log.info("loading kernel {f}", .{linux_conf.kernel_path});
53 const kernel: linux.Kernel = try .load(linux_conf.kernel_path);
54 defer kernel.deinit();
55
56 log.info("loading initrd {f}", .{linux_conf.initrd_path});
57 const initrd: *linux.Initrd = try .load(linux_conf.initrd_path);
58 defer initrd.deinit();
59
60 return kernel.start(linux_conf.kernel_cmdline);
61 },
62 }
63}
64
65pub fn main() uefi.Status {
66 return bmain() catch |err| {
67 log.err("unrecoverable error in bmain: {}", .{err});
68 return .aborted;
69 };
70}
71
72pub fn logFn(
73 comptime level: log.Level,
74 comptime scope: @EnumLiteral(),
75 comptime format: []const u8,
76 args: anytype,
77) void {
78 // stderr should be equivalent to stdout?
79 // but i dont see logs on my hardware if i use stderr
80 var stderr_buf: [512]u8 = undefined;
81 var stderr: Console = .stdout(&stderr_buf);
82 stderr.interface.print("{t}({}): ", .{ level, scope }) catch return;
83 stderr.interface.print(format ++ "\r\n", args) catch return;
84 stderr.interface.flush() catch return;
85}
86
87pub fn panicFn(msg: []const u8, _: ?usize) noreturn {
88 logFn(.err, .panic, "{s}", .{msg});
89 @trap();
90}
91
92pub const panic = std.debug.FullPanic(panicFn);
93pub const std_options: std.Options = .{ .logFn = logFn };