Limine-zig

From FriendOS Wiki
Revision as of 00:48, 1 September 2023 by Veloya (talk | contribs) (Added basic info on code for getting x86 limine with zig working)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

Limine is a modern boot protocol developed with the Limine bootloader, this page covers how to take advantage of that protocol in a zig-based kernel. This does not cover making an ISO, just the code required, in the future this will change, but this is it for now.

Code

This code should work as long as you have zig 0.11.0 installed. As of writing this it is untested, but if you do test it out, and it works, remove this sentence, if it doesn't work please message me (veloya) on the discord server with the error message.

src/main.zig

const limine = @import("./limine.zig");

pub export var FRAMEBUF: limine.FramebufferRequest = .{};

export fn _start() void {
    // Get an array of framebuffer pointers
    const framebuffers = FRAMEBUF.response.?.framebuffers();

    // Get the first framebuffer provided
    const framebuffer = framebuffers[0];

    // Height is in pixels, convert it to bytes
    const byte_height = framebuffer.height * 4;

    // Get total byte size by multiplying the height by the stride (or pitch)
    const size = byte_height * framebuffer.pitch;

    // Fill the framebuffer with white
    for (0..size) |index| {
        framebuffer.address[index] = 0xff;
    }

    while (true) {}
}

src/limine.zig

The limine.zig file can be found here

config/linker.ld

TODO: Write a better linker script

ENTRY(_start)

SECTIONS
{
    . = 0xffffffff80000000;

    .text : ALIGN(4096) { *(.text .text.*) }
    .rodata : ALIGN(4096) { *(.rodata .rodata.*) }
    .data : ALIGN(4096) { *(.data .data.*) }
    .dynamic : ALIGN(4096) { *(.dynamic) }
    .bss : ALIGN(4096) {
        *(.bss .bss.*)
        *(COMMON)
    }
}

config/limine.cfg

boot "test-kern" {
    protocol = "limine";
    kernel-path = "boot:///boot/test-kern";
}

build.zig

A build.zig file is required to properly customize the target.

const std = @import("std");
const Target = @import("std").Target;
const CrossTarget = @import("std").zig.CrossTarget;
const Feature = @import("std").Target.Cpu.Feature;

pub fn build(b: *std.Build) !void {
    var stdout = std.io.getStdOut();

    const target = CrossTarget{
        .cpu_arch = Target.Cpu.Arch.x86_64,
        .os_tag = Target.Os.Tag.freestanding,
        .abi = Target.Abi.none,
    };
    const optimize = b.standardOptimizeOption(.{});

    const kernel = b.addExecutable(.{
        .name = "test-kern",
        .root_source_file = .{ .path = "src/main.zig" },
        .target = target,
        .optimize = optimize,
    });

    kernel.setLinkerScriptPath(.{ .path = "config/linker.ld" });
    kernel.code_model = .medium;
    kernel.rdynamic = true;
    kernel.pie = true;

    _ = try stdout.write("Building kernel\n");
    b.installArtifact(kernel);
}