lumine
UEFI x86_64 bootloader for linux kernel images
src/boot/linux/Initrd.zig
3673 bytes raw
1const std = @import("std");
2const uefi = std.os.uefi;
3const log = std.log;
4
5const luefi = @import("../../luefi.zig");
6const Path = @import("../../Config.zig").Path;
7
8const Initrd = @This();
9
10protocol: LoadFile2 = .{},
11
12initrd_buf: []align(4096) u8,
13initrd_pages: usize,
14
15pub fn load(paths: []const Path) !*Initrd {
16 const File = struct { file: *uefi.protocol.File, size: usize };
17
18 var files: std.ArrayList(File) = try .initCapacity(uefi.pool_allocator, paths.len);
19 defer files.deinit(uefi.pool_allocator);
20
21 defer for (files.items) |f| f.file.close() catch unreachable;
22
23 var total_size: usize = 0;
24 for (paths) |path| {
25 log.info("loading initrd {f}", .{path});
26 const file = try luefi.fileOpen(path);
27 errdefer file.close() catch unreachable;
28
29 const size = try luefi.fileSize(file);
30 try files.append(uefi.pool_allocator, .{ .file = file, .size = size });
31
32 total_size += size;
33 }
34
35 const pages_count = try std.math.divCeil(usize, total_size, 4096);
36
37 const boot_svc = uefi.system_table.boot_services.?;
38
39 const initrd_pages = try boot_svc.allocatePages(.any, .loader_data, pages_count);
40 errdefer boot_svc.freePages(initrd_pages) catch unreachable;
41
42 const initrd_buf_ptr: [*]align(4096) u8 = @ptrCast(initrd_pages);
43 const initrd_buf = initrd_buf_ptr[0..total_size];
44
45 var start_pos: usize = 0;
46 for (files.items) |file| {
47 const slice = initrd_buf[start_pos .. start_pos + file.size];
48 try luefi.fileReadSlice(file.file, slice);
49 start_pos += file.size;
50 }
51
52 const self = try uefi.pool_allocator.create(Initrd);
53
54 self.* = .{
55 .initrd_buf = initrd_buf,
56 .initrd_pages = pages_count,
57 };
58
59 try luefi.installProtocols(.{ &device_path, &self.protocol });
60
61 return self;
62}
63
64pub fn deinit(self: *Initrd) void {
65 luefi.freePages(self.initrd_buf, self.initrd_pages);
66 uefi.pool_allocator.destroy(self);
67}
68
69pub const LoadFile2 = extern struct {
70 loadFile: *const @TypeOf(impl) = impl,
71
72 pub fn impl(
73 protocol: *LoadFile2,
74 _: *uefi.protocol.DevicePath,
75 _: bool,
76 buf_size: *usize,
77 buf_out: ?[*]u8,
78 ) callconv(uefi.cc) uefi.Status {
79 const initrd: *Initrd = @fieldParentPtr("protocol", protocol);
80
81 if (buf_out == null or buf_size.* < initrd.initrd_buf.len) {
82 buf_size.* = initrd.initrd_buf.len;
83 return .buffer_too_small;
84 }
85
86 @memcpy(buf_out.?, initrd.initrd_buf);
87
88 return .success;
89 }
90
91 pub const guid: uefi.Guid = .{
92 .time_low = 0x4006c0c1,
93 .time_mid = 0xfcb3,
94 .time_high_and_version = 0x403e,
95 .clock_seq_high_and_reserved = 0x99,
96 .clock_seq_low = 0x6d,
97 .node = [_]u8{ 0x4a, 0x6c, 0x87, 0x24, 0xe0, 0x6d },
98 };
99};
100
101pub var device_path = struct {
102 vendor: uefi.DevicePath.Media.VendorDevicePath,
103 end: uefi.DevicePath.End.EndEntireDevicePath,
104
105 pub const guid = uefi.protocol.DevicePath.guid;
106}{
107 .vendor = uefi.DevicePath.Media.VendorDevicePath{
108 .type = .media,
109 .subtype = .vendor,
110 .length = @sizeOf(uefi.DevicePath.Media.VendorDevicePath),
111 .guid = .{
112 .time_low = 0x5568e427,
113 .time_mid = 0x68fc,
114 .time_high_and_version = 0x4f3d,
115 .clock_seq_high_and_reserved = 0xac,
116 .clock_seq_low = 0x74,
117 .node = [_]u8{ 0xca, 0x55, 0x52, 0x31, 0xcc, 0x68 },
118 },
119 },
120 .end = uefi.DevicePath.End.EndEntireDevicePath{
121 .type = .end,
122 .subtype = .end_entire,
123 .length = @sizeOf(uefi.DevicePath.End.EndEntireDevicePath),
124 },
125};