UEFI bootloader correct types?

I started using zig some months ago and now I wanted to program a bootloader. I already read pretty much in general about bootloaders and I already have a good idea what I want to do.

The only problem is that I don’t know enough about the language to create a const with type **const os.uefi.protocols.file.File (as argument for function) while being able to call functions from there.
Also, looking forwards, how could I make the kernel pointer (kernel entry point) from the image buffer?

It would be really great if anyone could help me.

Please excuse me if my English is not perfect, I’m a german student.

Hi Samuel. I would suggest you post snippets of any language you are familiar with (most likely C in this case), so that it provides a bit more context when trying to come up with zig equivalents.

Cheers!

Hi gonzo,

I personally think that the const type problem can be solved without C. My actual code for loading the image into a buffer is the following (I will change the terrible 3 "if"s right after I got it building).

fn loadKernel(path: []const u8, image: *[]const u8, file_size: *u64) uefi.Status {
    const boot_services = uefi.system_table.boot_services.?;
    var file_system_protocol: ?*uefi.protocol.SimpleFileSystem = undefined;
    if (boot_services.locateProtocol(&uefi.protocol.SimpleFileSystem.guid, null, @as(*?*anyopaque, @ptrCast(&file_system_protocol))) == uefi.Status.Success) {
        // open file system root
        const root: ?*const uefi.protocol.File = undefined;
        if (file_system_protocol.?.openVolume(&root) == uefi.Status.Success) {
            // locate file
            const file: ?*const uefi.protocol.File = undefined;
            if (root.?.open(path, &file, uefi.FileMode.Read, uefi.FileMode.ReadOnly) == uefi.Status.Success) {
                const file_info = file.?.getInfo();
                const image_buffer: [*]u8 = null;
                // allocate space
                boot_services.allocatePool(uefi.AllocateType.LoaderData, @as(u64, @intCast(file_info.FileSize)), &image_buffer);
                // read file
                file.read(&image_buffer, file_info.FileSize);
                // save in pointers
                image.* = image_buffer;
                file_size.* = @as(u64, @intCast(file_info.FileSize));
            }
        }
    }

    return uefi.Status.Success;
}

Regarding the memory loading thing: I personally do not have much experience in writing C, but I found https://github.com/ajxs/uefi-elf-bootloader/blob/master/src/bootloader/src/loader.c#L297. I think, for simplicity, a raw kernel format would be easier to implement, but we just have a C example for ELF files.
It would be cool if we could try it first with raw binaries, but first of all it would be cool to solve the first problem.

Keep in mind that I READ much about bootloaders and I understand how they work, but I never implemented one by myself.

Looking forwards,
Samuel

This line:

Needs to be:

var root: ?*const uefi.protocol.File = undefined;

Otherwise, root will be stuck forever being undefined, annd openVolume won’t be able to update it. Same goes for for file and image_buffer.
There’s an idiom if you want a variable to have some initialization logic, but be const after that:

const variable = blk:{
    var result: T = undefined;
    // initialize result
    break :blk result;
};
1 Like

Hello Lucas,

Thank you for the thing with var root instead of const root. The wrong type problems are solved now, and I think I should be able to do the rest by reading the std lib and some examples in other languages.

By the way, is there any bootloader written in ZIG?

Looking forwards,
Samuel