summaryrefslogtreecommitdiff
path: root/x86-bare-metal/mbr-pure-zig/mbr.zig
diff options
context:
space:
mode:
Diffstat (limited to 'x86-bare-metal/mbr-pure-zig/mbr.zig')
-rw-r--r--x86-bare-metal/mbr-pure-zig/mbr.zig106
1 files changed, 106 insertions, 0 deletions
diff --git a/x86-bare-metal/mbr-pure-zig/mbr.zig b/x86-bare-metal/mbr-pure-zig/mbr.zig
new file mode 100644
index 0000000..666aa6b
--- /dev/null
+++ b/x86-bare-metal/mbr-pure-zig/mbr.zig
@@ -0,0 +1,106 @@
+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 {
+ for (0..255) |i| {
+ if (i < bios.ROWS) {
+ bios.set_pos(@truncate(i));
+ } else {
+ // Once we reach the bottom of the screen start scrolling.
+ bios.scroll_up();
+ bios.set_pos(bios.ROWS - 1);
+ }
+ puts_dec(i + 1);
+ bios.putc(' ');
+ puts_hex(i + 1);
+ bios.putc(' ');
+ bios.putc(@truncate('a' + (i % 26)));
+ bios.putc(@truncate('a' + (i % 26)));
+ waste_time();
+ }
+ puts("\ndone");
+
+ while (true) {
+ asm volatile ("hlt");
+ }
+}
+
+// -- UTILS ---------------------------------------------------------------------
+
+fn puts(str: []const u8) void {
+ for (str) |c| {
+ bios.putc(c);
+ }
+}
+
+fn puts_dec(init_val: u32) void {
+ var val = init_val;
+ var buf: [32]u8 = undefined;
+ var idx = buf.len;
+
+ while (val > 0 and idx != 0) : (val /= 10) {
+ idx -= 1;
+ buf[idx] = @as(u8, @truncate(val % 10)) + '0';
+ }
+ puts(buf[idx..]);
+}
+
+fn puts_hex(init_val: u32) void {
+ 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..]);
+}
+
+fn rdtsc() u32 {
+ return asm volatile ("rdtsc"
+ : [eax] "={eax}" (-> u32),
+ :
+ : "edx"
+ );
+}
+
+fn waste_time() void {
+ const start = rdtsc();
+ var now = start;
+ var idx: usize = 0;
+ while (now - start < (1 << 28)) : (idx += 1) {
+ if (idx == 10_000) {
+ now = rdtsc();
+ idx = 0;
+ }
+ }
+}