lumine
UEFI x86_64 bootloader for linux kernel images
src/luefi.zig
1943 bytes raw
1//! lumine uefi abstractions
2const std = @import("std");
3const uefi = std.os.uefi;
4
5const Path = @import("./Config.zig").Path;
6
7pub fn posixPathToUefi(path: []u16) void {
8 for (0..path.len) |i|
9 switch (path[i]) {
10 '/' => path[i] = '\\',
11 else => {},
12 };
13}
14
15pub fn fileOpenBoot(path: []const u8) !*uefi.protocol.File {
16 const boot_svc = uefi.system_table.boot_services.?;
17 const allocator = uefi.pool_allocator;
18
19 const loaded_img = try boot_svc.openProtocol(uefi.protocol.LoadedImage, uefi.handle, .{
20 .get_protocol = .{ .agent = uefi.handle },
21 }) orelse unreachable;
22
23 const device_handle = loaded_img.device_handle orelse unreachable;
24 const simple_fs = try boot_svc.openProtocol(uefi.protocol.SimpleFileSystem, device_handle, .{
25 .get_protocol = .{ .agent = uefi.handle },
26 }) orelse unreachable;
27
28 const root_fs = try simple_fs.openVolume();
29 defer root_fs.close() catch unreachable;
30
31 // is allocating a good idea?
32 const utf16_path = try std.unicode.utf8ToUtf16LeAllocZ(allocator, path);
33 defer allocator.free(utf16_path);
34
35 posixPathToUefi(utf16_path);
36
37 return root_fs.open(utf16_path, .read, .{});
38}
39
40pub fn fileOpen(path: Path) !*uefi.protocol.File {
41 return switch (path) {
42 .boot => |boot_path| fileOpenBoot(boot_path),
43 };
44}
45
46pub fn fileSize(file: *uefi.protocol.File) !usize {
47 const allocator = uefi.pool_allocator;
48
49 const info_size = try file.getInfoSize(.file);
50 const info_buf = try allocator.alignedAlloc(u8, .@"8", info_size);
51 defer allocator.free(info_buf);
52
53 const info = try file.getInfo(.file, info_buf);
54 return info.file_size;
55}
56
57pub fn fileReadSlice(file: *uefi.protocol.File, slice: []u8) !void {
58 var read: usize = 0;
59
60 while (read < slice.len) {
61 const chunk = try file.read(slice[read..]);
62 if (chunk == 0) return error.ReadShort;
63 read += chunk;
64 }
65}