summaryrefslogtreecommitdiff
path: root/x86-bare-metal/mbr-disk-lba/zmbr.zig
blob: e5b06ea0dca11c96eee0192be0b4ee59ac401ee7 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
// Frambuffer limits.
const COLS = 80;
const ROWS = 25;

// Frambuffer cursor.
var col: u16 = 0;
var row: u16 = 0;

// Frambuffer.
const fb: []u16 = @as([*]u16, @ptrFromInt(0xB8000))[0 .. COLS * ROWS];

/// Clear screen (all black).
fn clear_screen() void {
    for (fb) |*ch| {
        ch.* = 0;
    }
}

/// Draw string to current cursor position.
fn puts(str: []const u8) void {
    // Each framebuffer entry in text mode is 16bit wide.
    //      [15] blink
    //   [14:12] bg color (3 bit)
    //   [11: 8] fg color (4 bit)
    //   [ 7: 0] ascii character
    // https://en.wikipedia.org/wiki/VGA_text_mode
    for (str) |ch| {
        if (ch == '\n') {
            col = 0;
            row += 1;
        } else {
            const pos = (row * COLS + col);
            // bg - black; fg - white;
            fb[pos] = @as(u16, 15) << 8 | ch;
            col += 1;
        }
        if (col == COLS) {
            row += 1;
            if (row == ROWS) {
                row = 0;
            }
        }
    }
}

// kmain should be "callconv(.naked)", once issue is fixed.
// https://github.com/ziglang/zig/issues/18183
export fn kmain() noreturn {
    clear_screen();

    // Print first bytes of LBA block 1 we loaded from disk (sector 2).
    const lba1: []const u8 = @as([*]const u8, @ptrFromInt(0x7e00))[0..4];
    puts("lba1: ");
    puts(lba1);
    puts("\n");

    // Print first bytes of LBA block 2 we loaded from disk (sector 3).
    const lba2: []const u8 = @as([*]const u8, @ptrFromInt(0x8000))[0..4];
    puts("lba2: ");
    puts(lba2);
    puts("\n");

    while (true) {
        asm volatile ("hlt");
    }
}