lumine
UEFI x86_64 bootloader for linux kernel images
diff
+78 -41
build.zig modified +1 -1
diff --git a/build.zig b/build.zig index bf43280d96546f26553649860471c4dea86a4145..cea0536f7c90a2686f7d717078419ac7e7f93ce5 100644 --- a/build.zig +++ b/build.zig @@ -67,7 +67,7 @@ qemu_cmd.addArgs(&.{ "-serial", "mon:stdio", "-nographic" }); } switch (cpu_arch) { - .aarch64 => qemu_cmd.addArgs(&.{ "-M", "virt", "-cpu", "cortex-a57" }), + .aarch64 => qemu_cmd.addArgs(&.{ "-M", "virt", "-cpu", "cortex-a57", "-device", "ramfb" }), .x86_64 => {}, }
src/boot/Chainload.zig modified +8 -15
diff --git a/src/boot/Chainload.zig b/src/boot/Chainload.zig index dff377991104e3c37c5ecdcc3e5b9d62a26ff3cb..f1372716bd437fc1837245c950a6302e6103fafb 100644 --- a/src/boot/Chainload.zig +++ b/src/boot/Chainload.zig @@ -4,40 +4,33 @@ const Path = @import("../Config.zig").Path; const luefi = @import("../luefi.zig"); +const log = std.log.scoped(.chainload); + const Chainload = @This(); - -img_handle: uefi.Handle, -img_loaded: *uefi.protocol.LoadedImage, img_buffer: []align(4096) u8, img_pages: usize, pub fn load(path: Path) !Chainload { - const buffer, const pages = blk: { - const file = try luefi.fileOpen(path); - defer file.close() catch unreachable; - - break :blk try luefi.fileReadAlloc(file); - }; + const buffer, const pages = try luefi.pathReadAlloc(path); errdefer luefi.freePages(buffer, pages); - const handle, const loaded = try luefi.loadImage(buffer); - return .{ .img_buffer = buffer, .img_pages = pages, - .img_handle = handle, - .img_loaded = loaded, }; } pub fn deinit(self: Chainload) void { - luefi.unloadImage(self.img_handle); luefi.freePages(self.img_buffer, self.img_pages); } pub fn start(self: Chainload) !uefi.Status { const boot_svc = uefi.system_table.boot_services.?; - const exit_data = try boot_svc.startImage(self.img_handle); + + const handle, _ = try luefi.loadImage(self.img_buffer); + defer luefi.unloadImage(handle); + + const exit_data = try boot_svc.startImage(handle); return exit_data.code; }
src/boot/linux.zig modified +1 -1
diff --git a/src/boot/linux.zig b/src/boot/linux.zig index c285e0caf611c42048b90c3ed5aa35084232f5aa..7f83d9995b046ddb04d1fdef2f1be04d891eca19 100644 --- a/src/boot/linux.zig +++ b/src/boot/linux.zig @@ -1,2 +1,2 @@ -pub const Kernel = @import("./linux/Kernel.zig"); pub const Initrd = @import("./linux/Initrd.zig"); +pub const Kernel = @import("./linux/Kernel.zig");
src/boot/linux/Initrd.zig modified +6 -2
diff --git a/src/boot/linux/Initrd.zig b/src/boot/linux/Initrd.zig index f2e0fc75d1b06682fae29e34036d9d9f20e55a8a..00e791528a3b2aba78e6a1072aac43a38a09577a 100644 --- a/src/boot/linux/Initrd.zig +++ b/src/boot/linux/Initrd.zig @@ -2,8 +2,8 @@ const std = @import("std"); const uefi = std.os.uefi; const log = std.log; -const luefi = @import("../../luefi.zig"); const Path = @import("../../Config.zig").Path; +const luefi = @import("../../luefi.zig"); const Initrd = @This(); @@ -11,6 +11,8 @@ protocol: LoadFile2 = .{}, initrd_buf: []align(4096) u8, initrd_pages: usize, + +handle: uefi.Handle, pub fn load(paths: []const Path) !*Initrd { const File = struct { file: *uefi.protocol.File, size: usize }; @@ -54,14 +56,16 @@ self.* = .{ .initrd_buf = initrd_buf, .initrd_pages = pages_count, + .handle = undefined, }; - try luefi.installProtocols(.{ &device_path, &self.protocol }); + self.handle = try luefi.installProtocols(.{ &device_path, &self.protocol }); return self; } pub fn deinit(self: *Initrd) void { + luefi.uninstallProtocols(self.handle, .{ &device_path, &self.protocol }); luefi.freePages(self.initrd_buf, self.initrd_pages); uefi.pool_allocator.destroy(self); }
src/boot/linux/Kernel.zig modified +26 -11
diff --git a/src/boot/linux/Kernel.zig b/src/boot/linux/Kernel.zig index 5401c04123dbd3cb37b6b8151e1c1bcd28be4184..aa81937646b142858473612e5447d953d530b419 100644 --- a/src/boot/linux/Kernel.zig +++ b/src/boot/linux/Kernel.zig @@ -1,33 +1,48 @@ const std = @import("std"); const uefi = std.os.uefi; -const log = std.log; +const builtin = @import("builtin"); +const Path = @import("../../Config.zig").Path; +const luefi = @import("../../luefi.zig"); const Chainload = @import("../Chainload.zig"); -const luefi = @import("../../luefi.zig"); -const Path = @import("../../Config.zig").Path; +const log = std.log.scoped(.linux); const Kernel = @This(); -chainload: Chainload, +img_buffer: []align(4096) u8, +img_pages: usize, pub fn load(path: Path) !Kernel { log.info("loading kernel {f}", .{path}); - return .{ .chainload = try .load(path) }; + + const buffer, const pages = try luefi.pathReadAlloc(path); + return .{ .img_buffer = buffer, .img_pages = pages }; } pub fn deinit(self: Kernel) void { - self.chainload.deinit(); + luefi.freePages(self.img_buffer, self.img_pages); } pub fn start(self: Kernel, cmdline: []const u8) !uefi.Status { const allocator = uefi.pool_allocator; + const boot_svc = uefi.system_table.boot_services.?; - const cmdline_utf16 = try std.unicode.utf8ToUtf16LeAllocZ(allocator, cmdline); - defer allocator.free(cmdline_utf16); + if (builtin.target.cpu.arch == .x86_64) { + const cmdline_utf16 = try std.unicode.utf8ToUtf16LeAllocZ(allocator, cmdline); + defer allocator.free(cmdline_utf16); - self.chainload.img_loaded.load_options = @ptrCast(cmdline_utf16); - self.chainload.img_loaded.load_options_size = @intCast(cmdline_utf16.len * @sizeOf(u16)); + const handle, const loaded = try luefi.loadImage(self.img_buffer); + defer luefi.unloadImage(handle); - return self.chainload.start(); + loaded.load_options = @ptrCast(cmdline_utf16); + loaded.load_options_size = @intCast(cmdline_utf16.len * @sizeOf(u16)); + + const exit_data = try boot_svc.startImage(handle); + try exit_data.code.err(); + return .aborted; + } else { + log.err("this architecture doesnt support linux boot", .{}); + return error.UnsupportedArchitecture; + } }
src/luefi.zig modified +35 -10
diff --git a/src/luefi.zig b/src/luefi.zig index 9f3640b3c8d19454e2b9e087b60ad2a7f2ffdd1d..3158d9994bd03d6db8b49976ddb0a9097dd124a0 100644 --- a/src/luefi.zig +++ b/src/luefi.zig @@ -87,6 +87,13 @@ const slice_ptr: [*]align(4096) [4096]u8 = @ptrCast(buf); boot_svc.freePages(slice_ptr[0..page_count]) catch unreachable; } +pub fn pathReadAlloc(path: Path) !struct { []align(4096) u8, usize } { + const file = try fileOpen(path); + defer file.close() catch unreachable; + + return fileReadAlloc(file); +} + pub fn loadImage(buf: []u8) !struct { uefi.Handle, *uefi.protocol.LoadedImage } { const boot_svc = uefi.system_table.boot_services.?; @@ -105,35 +112,53 @@ const boot_svc = uefi.system_table.boot_services.?; _ = boot_svc.unloadImage(handle) catch unreachable; } -// https://codeberg.org/ziglang/zig/pulls/31934 -pub fn installProtocols(interfaces: anytype) !void { - const fields = @typeInfo(@TypeOf(interfaces)).@"struct".fields; - comptime var tuple_types: [fields.len * 2 + 1]type = undefined; +fn ProtocolInterfaceArgs(Handle: type, Interfaces: type) type { + const fields = @typeInfo(Interfaces).@"struct".fields; + comptime var tuple_types: [fields.len * 2 + 2]type = undefined; inline for (0..fields.len) |i| { tuple_types[i * 2 + 1] = *const uefi.Guid; tuple_types[i * 2 + 2] = *const anyopaque; } - tuple_types[0] = *?uefi.Handle; + tuple_types[0] = Handle; + tuple_types[tuple_types.len - 1] = ?*anyopaque; + return @Tuple(tuple_types[0..]); +} - var args_tuple: @Tuple(tuple_types[0..]) = undefined; +fn protocolInterfaceArgs(handle: anytype, interfaces: anytype) ProtocolInterfaceArgs(@TypeOf(handle), @TypeOf(interfaces)) { + var args_tuple: ProtocolInterfaceArgs(@TypeOf(handle), @TypeOf(interfaces)) = undefined; inline for (interfaces, 0..) |iface, i| { const child = @typeInfo(@TypeOf(iface)).pointer.child; args_tuple[i * 2 + 1] = &@field(child, "guid"); args_tuple[i * 2 + 2] = @ptrCast(iface); } - var handle: ?uefi.Handle = null; - args_tuple[0] = &handle; + args_tuple[0] = handle; + args_tuple[@typeInfo(@TypeOf(args_tuple)).@"struct".fields.len - 1] = @as(?*anyopaque, null); + return args_tuple; +} +// https://codeberg.org/ziglang/zig/pulls/31934 +pub fn installProtocols(interfaces: anytype) !uefi.Handle { const boot_svc = uefi.system_table.boot_services.?; const InstallFn = *const fn (handle: *?uefi.Handle, ...) callconv(uefi.cc) uefi.Status; const installFn: InstallFn = @ptrCast(boot_svc._installMultipleProtocolInterfaces); - const status = @call(.auto, installFn, args_tuple); + var hdl: ?uefi.Handle = null; + + const status = @call(.auto, installFn, protocolInterfaceArgs(&hdl, interfaces)); return switch (status) { - .success => return, + .success => return hdl.?, .already_started => return error.AlreadyStarted, .out_of_resources => return error.OutOfResources, .invalid_parameter => return error.InvalidParameter, else => return uefi.unexpectedStatus(status), }; } + +pub fn uninstallProtocols(handle: uefi.Handle, interfaces: anytype) void { + const boot_svc = uefi.system_table.boot_services.?; + const UninstallFn = *const fn (handle: uefi.Handle, ...) callconv(uefi.cc) uefi.Status; + const uninstallFn: UninstallFn = @ptrCast(boot_svc._uninstallMultipleProtocolInterfaces); + + const status = @call(.auto, uninstallFn, protocolInterfaceArgs(handle, interfaces)); + if (status != .success) unreachable; +}
src/main.zig modified +1 -1
diff --git a/src/main.zig b/src/main.zig index d736ad92c5ca902cae0f1d35f6aa989d1ecfd67d..6a39a35035156c53c1be9a612f00ce9b008d9ff3 100644 --- a/src/main.zig +++ b/src/main.zig @@ -62,7 +62,7 @@ } pub fn main() uefi.Status { return bmain() catch |err| { - log.err("unrecoverable error in bmain: {}", .{err}); + log.err("unrecoverable error: {}", .{err}); return .aborted; }; }