λ

lumine

UEFI x86_64 bootloader for linux kernel images

settings

src/Console.zig

1737 bytes raw

const std = @import("std");
const Io = std.Io;
const uefi = std.os.uefi;

const Console = @This();

interface: Io.Writer,
protocol: *uefi.protocol.SimpleTextOutput,

pub fn init(buffer: []u8, protocol: *uefi.protocol.SimpleTextOutput) Console {
    return .{
        .protocol = protocol,
        .interface = .{
            .buffer = buffer,
            .vtable = &.{ .drain = drainFn },
        },
    };
}

pub fn stdout(buffer: []u8) Console {
    return .init(buffer, uefi.system_table.con_out.?);
}

pub fn stderr(buffer: []u8) Console {
    return .init(buffer, uefi.system_table.std_err.?);
}

pub fn write(self: *Console, data: []const u8) !void {
    var buffer: [64:0]u16 = @splat(undefined);
    var buflen: usize = 0;
    for (data) |b| {
        buffer[buflen] = @intCast(b);
        buflen += 1;
        if (buflen == buffer.len) {
            _ = self.protocol.outputString(&buffer) catch unreachable;
            buflen = 0;
        }
    }
    if (buflen > 0) {
        buffer[buflen] = 0;
        _ = self.protocol.outputString(buffer[0..buflen :0]) catch unreachable;
    }
}

fn drainFn(io_w: *Io.Writer, data: []const []const u8, splat: usize) Io.Writer.Error!usize {
    const self: *Console = @fieldParentPtr("interface", io_w);

    {
        const buf = io_w.buffered();
        if (buf.len > 0) {
            try self.write(buf);
            _ = io_w.consumeAll();
        }
    }

    var written: usize = 0;

    if (data.len > 1) {
        for (data[0 .. data.len - 1]) |buf| {
            try self.write(buf);
            written += buf.len;
        }
    }

    const buf = data[data.len - 1];
    for (0..splat) |_| {
        try self.write(buf);
        written += buf.len;
    }

    return written;
}