λ

lumine

UEFI x86_64 bootloader for linux kernel images

settings

commit f35351f8

authordragsbruh <dragsbruh@protonmail.com>
date2026-07-22 21:14:49 +0530
committerdragsbruh <dragsbruh@protonmail.com> (2026-07-22 21:14:49 +0530)
tree8731bbba233827dce76df646d824f3cec0f0d711
parentfe567ee7

feat: multiple linux initrds

patch diff stats

+53 -18

res/lumine.zon modified +3 -1

diff --git a/res/lumine.zon b/res/lumine.zon
index cc3d07363bc1746edddff47b57bc9a9f1f260d59..41e24a873fb13a333003729ebcc6601a97b4361a 100644
--- a/res/lumine.zon
+++ b/res/lumine.zon
@@ -2,7 +2,9 @@ .{
     .boot = .{
         .linux = .{
             .kernel_path = .{ .boot = "/linux/vmlinuz" },
-            .initrd_path = .{ .boot = "/linux/initrd" },
+            .initrd_paths = .{
+                .{ .boot = "/linux/initrd" },
+            },
             .kernel_cmdline = "console=ttyS0",
         },
     },

src/Config.zig modified +1 -1

diff --git a/src/Config.zig b/src/Config.zig
index 374059b0757ece64fae0b068bf666643746bd07a..8a8621d87120818847817f3b187d64b1fc172f67 100644
--- a/src/Config.zig
+++ b/src/Config.zig
@@ -18,7 +18,7 @@     chainload: Path,
     linux: struct {
         kernel_path: Path,
         kernel_cmdline: []const u8 = &.{},
-        initrd_path: Path,
+        initrd_paths: []const Path = &.{},
     },
 };
 

src/boot/linux/Initrd.zig modified +46 -13

diff --git a/src/boot/linux/Initrd.zig b/src/boot/linux/Initrd.zig
index 8a5707cb51a64df1da28fab1b21978c2ef94f0de..f2e0fc75d1b06682fae29e34036d9d9f20e55a8a 100644
--- a/src/boot/linux/Initrd.zig
+++ b/src/boot/linux/Initrd.zig
@@ -1,5 +1,6 @@
 const std = @import("std");
 const uefi = std.os.uefi;
+const log = std.log;
 
 const luefi = @import("../../luefi.zig");
 const Path = @import("../../Config.zig").Path;
@@ -8,20 +9,52 @@ const Initrd = @This();
 
 protocol: LoadFile2 = .{},
 
-buffer: []align(4096) u8,
-pages: usize,
+initrd_buf: []align(4096) u8,
+initrd_pages: usize,
+
+pub fn load(paths: []const Path) !*Initrd {
+    const File = struct { file: *uefi.protocol.File, size: usize };
+
+    var files: std.ArrayList(File) = try .initCapacity(uefi.pool_allocator, paths.len);
+    defer files.deinit(uefi.pool_allocator);
+
+    defer for (files.items) |f| f.file.close() catch unreachable;
 
-pub fn load(path: Path) !*Initrd {
-    const buffer, const pages = blk: {
+    var total_size: usize = 0;
+    for (paths) |path| {
+        log.info("loading initrd {f}", .{path});
         const file = try luefi.fileOpen(path);
-        defer file.close() catch unreachable;
+        errdefer file.close() catch unreachable;
+
+        const size = try luefi.fileSize(file);
+        try files.append(uefi.pool_allocator, .{ .file = file, .size = size });
+
+        total_size += size;
+    }
+
+    const pages_count = try std.math.divCeil(usize, total_size, 4096);
+
+    const boot_svc = uefi.system_table.boot_services.?;
+
+    const initrd_pages = try boot_svc.allocatePages(.any, .loader_data, pages_count);
+    errdefer boot_svc.freePages(initrd_pages) catch unreachable;
 
-        break :blk try luefi.fileReadAlloc(file);
-    };
-    errdefer luefi.freePages(buffer, pages);
+    const initrd_buf_ptr: [*]align(4096) u8 = @ptrCast(initrd_pages);
+    const initrd_buf = initrd_buf_ptr[0..total_size];
+
+    var start_pos: usize = 0;
+    for (files.items) |file| {
+        const slice = initrd_buf[start_pos .. start_pos + file.size];
+        try luefi.fileReadSlice(file.file, slice);
+        start_pos += file.size;
+    }
 
     const self = try uefi.pool_allocator.create(Initrd);
-    self.* = .{ .buffer = buffer, .pages = pages };
+
+    self.* = .{
+        .initrd_buf = initrd_buf,
+        .initrd_pages = pages_count,
+    };
 
     try luefi.installProtocols(.{ &device_path, &self.protocol });
 
@@ -29,7 +62,7 @@     return self;
 }
 
 pub fn deinit(self: *Initrd) void {
-    luefi.freePages(self.buffer, self.pages);
+    luefi.freePages(self.initrd_buf, self.initrd_pages);
     uefi.pool_allocator.destroy(self);
 }
 
@@ -45,12 +78,12 @@         buf_out: ?[*]u8,
     ) callconv(uefi.cc) uefi.Status {
         const initrd: *Initrd = @fieldParentPtr("protocol", protocol);
 
-        if (buf_out == null or buf_size.* < initrd.buffer.len) {
-            buf_size.* = initrd.buffer.len;
+        if (buf_out == null or buf_size.* < initrd.initrd_buf.len) {
+            buf_size.* = initrd.initrd_buf.len;
             return .buffer_too_small;
         }
 
-        @memcpy(buf_out.?, initrd.buffer);
+        @memcpy(buf_out.?, initrd.initrd_buf);
 
         return .success;
     }

src/boot/linux/Kernel.zig modified +2 -0

diff --git a/src/boot/linux/Kernel.zig b/src/boot/linux/Kernel.zig
index 3b54c20e1c0099005e5039119e43dabcdf91b252..5401c04123dbd3cb37b6b8151e1c1bcd28be4184 100644
--- a/src/boot/linux/Kernel.zig
+++ b/src/boot/linux/Kernel.zig
@@ -1,5 +1,6 @@
 const std = @import("std");
 const uefi = std.os.uefi;
+const log = std.log;
 
 const Chainload = @import("../Chainload.zig");
 
@@ -11,6 +12,7 @@
 chainload: Chainload,
 
 pub fn load(path: Path) !Kernel {
+    log.info("loading kernel {f}", .{path});
     return .{ .chainload = try .load(path) };
 }
 

src/main.zig modified +1 -3

diff --git a/src/main.zig b/src/main.zig
index 638f39ad577a17641526348cff460cdf0dc5ee15..d736ad92c5ca902cae0f1d35f6aa989d1ecfd67d 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -49,12 +49,10 @@
             return chainload.start();
         },
         .linux => |linux_conf| {
-            log.info("loading kernel {f}", .{linux_conf.kernel_path});
             const kernel: linux.Kernel = try .load(linux_conf.kernel_path);
             defer kernel.deinit();
 
-            log.info("loading initrd {f}", .{linux_conf.initrd_path});
-            const initrd: *linux.Initrd = try .load(linux_conf.initrd_path);
+            const initrd: *linux.Initrd = try .load(linux_conf.initrd_paths);
             defer initrd.deinit();
 
             return kernel.start(linux_conf.kernel_cmdline);