summaryrefslogtreecommitdiff
path: root/x86-bare-metal/mbr-e820/mbr.zig
blob: 3b6f71df6608176e64472895e41c88256bbedf1f (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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
const bios = @import("bios.zig");

// -- ENTRY POINT ---------------------------------------------------------------

export fn _entry() linksection(".boot") callconv(.Naked) noreturn {
    asm volatile (
        // Disable interrupts.
        \\cli
        // Clear segment selectors.
        \\xor %%ax, %%ax
        \\mov %%ax, %%ds
        \\mov %%ax, %%es
        \\mov %%ax, %%ss
        \\mov %%ax, %%fs
        \\mov %%ax, %%gs
        \\mov $0x7c00, %sp
        // Long jump to set cs to 0x0000, as some BIOSes load the MBR
        // to either 07c0:0000 or 0000:7c000.
        \\ljmp $0x0, $main
    );
}

// -- MAIN ----------------------------------------------------------------------

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

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

// -- UTILS ---------------------------------------------------------------------

fn dump_memmap() void {
    // Keep track of continuatation code.
    var off: u32 = 0;
    // Accumulated free/usable memory.
    var mem: u64 = 0;

    // Iterate over E820 entries.
    while (bios.e820(off)) |entry| : (off = entry.ebx) {
        puts_hex(entry.e820.base);
        bios.putc('-');
        puts_hex(entry.e820.size);
        bios.putc('-');
        puts_hex(entry.e820.kind);
        bios.putc('-');
        puts_hex(entry.e820.attr);
        bios.putc('\n');

        // Accumulate free, useable memory.
        if (entry.e820.kind == 1 and entry.e820.attr == 1) {
            mem += entry.e820.size;
        }

        // All E820 entries retrieved, continuing would start from the beginning.
        if (entry.ebx == 0) {
            break;
        }
    }

    // Report total free memory in MBs.
    bios.putc('m');
    bios.putc('=');
    puts_hex(mem / 1024 / 1024);
}

fn puts(str: []const u8) void {
    for (str) |c| {
        bios.putc(c);
    }
}

fn puts_hex(init_val: u64) void {
    if (init_val == 0) {
        bios.putc('0');
        return;
    }

    var val = init_val;
    var buf: [32]u8 = undefined;
    var idx = buf.len;

    while (val > 0 and idx != 0) : (val /= 16) {
        idx -= 1;
        const digit = switch (@as(u8, @truncate(val % 16))) {
            0...9 => |d| '0' + d,
            10...15 => |d| 'a' + d - 10,
            else => '?',
        };
        buf[idx] = digit;
    }
    puts(buf[idx..]);
}