diff options
author | Johannes Stoelp <johannes.stoelp@gmail.com> | 2024-12-23 22:51:52 +0100 |
---|---|---|
committer | Johannes Stoelp <johannes.stoelp@gmail.com> | 2024-12-25 21:25:16 +0100 |
commit | 14845124cf5d4fb42a04cb1262b32bd3d00f45f8 (patch) | |
tree | 13162d26afeb49a9c9b8d9d31049066c0f4b2998 | |
parent | 42b6f9d23ab0f94744a90edb6fd74450f589ca14 (diff) | |
download | zig-playground-14845124cf5d4fb42a04cb1262b32bd3d00f45f8.tar.gz zig-playground-14845124cf5d4fb42a04cb1262b32bd3d00f45f8.zip |
mbr: rm->pm, then jump into zig
-rw-r--r-- | x86-bare-metal/mbr-palette/.gitignore | 1 | ||||
-rw-r--r-- | x86-bare-metal/mbr-palette/Makefile | 28 | ||||
-rw-r--r-- | x86-bare-metal/mbr-palette/mbr.S | 89 | ||||
-rw-r--r-- | x86-bare-metal/mbr-palette/mbr.ld | 25 | ||||
-rw-r--r-- | x86-bare-metal/mbr-palette/x220.png | bin | 0 -> 376638 bytes | |||
-rw-r--r-- | x86-bare-metal/mbr-palette/zmbr.zig | 29 |
6 files changed, 172 insertions, 0 deletions
diff --git a/x86-bare-metal/mbr-palette/.gitignore b/x86-bare-metal/mbr-palette/.gitignore new file mode 100644 index 0000000..a92a67f --- /dev/null +++ b/x86-bare-metal/mbr-palette/.gitignore @@ -0,0 +1 @@ +BUILD/
\ No newline at end of file diff --git a/x86-bare-metal/mbr-palette/Makefile b/x86-bare-metal/mbr-palette/Makefile new file mode 100644 index 0000000..7642791 --- /dev/null +++ b/x86-bare-metal/mbr-palette/Makefile @@ -0,0 +1,28 @@ +O := BUILD + +$(O)/boot: $(O)/boot.elf | dump_info + objcopy -O binary $< $@ + +$(O)/boot.elf: mbr.ld $(O)/mbr.o $(O)/zmbr.o + ld -o $@ -nostdlib -T $^ + +$(O)/mbr.o: mbr.S | $(O) + gcc -m32 -c -o $@ -ffreestanding mbr.S + +$(O)/zmbr.o: zmbr.zig | $(O) + zig build-obj -femit-bin=$@ -target x86-freestanding-none -O ReleaseSmall $< + +clean: + $(RM) -r $(O) + +$(O): + mkdir -p $(O) + +dump_info: $(O)/boot.elf + objdump -Mintel --disassemble=kmain --visualize-jumps=extended-color $< + readelf -W -l $< + size $< + size $< | awk '/$(notdir $<)/ { print "MBR utilization " $$1/512 "%" }' + +run: $(O)/boot + qemu-system-i386 -hda $< $(QEMU_ARGS) diff --git a/x86-bare-metal/mbr-palette/mbr.S b/x86-bare-metal/mbr-palette/mbr.S new file mode 100644 index 0000000..858f3f8 --- /dev/null +++ b/x86-bare-metal/mbr-palette/mbr.S @@ -0,0 +1,89 @@ +// -- BOOT TEXT SECTION --------------------------------------------------------- + +.code16 +.intel_syntax noprefix + +.section .boot, "ax", @progbits + // Disable interrupts. + cli + + // Clear segment selectors. + xor ax, ax + mov ds, ax + mov es, ax + mov ss, ax + mov fs, ax + mov gs, ax + + // Set cs to 0x0000, as some BIOSes load the MBR to either 07c0:0000 or 0000:7c000. + jmp 0x0000:entry_rm16 + +entry_rm16: + // Set video mode 13h, see [1]. + // * 320x200 graphic mode + // * 256 colors (8bit per pixel) + // * 0xA0000 screen address + // + // [1] http://www.ctyme.com/intr/rb-0069.htm + // [2] https://en.wikipedia.org/wiki/Mode_13h (shows color palette) + mov ax, 0x13 + int 0x10 + + // Set blue screen and halt if setting video mode failed. + jnc 2f + mov ah, 0xb + mov bx, 1 + int 0x10 +1: + hlt + jmp 1b +2: + + // Enable A20 address line. + in al, 0x92 + or al, 2 + out 0x92, al + + // Load GDT descriptor. + lgdt [gdt_desc] + + // Enable protected mode (set CR0.PE bit). + mov eax, cr0 + or eax, (1 << 0) + mov cr0, eax + + // Far jump which loads segment selector (0x0008) into cs. + // 0x0008 -> RPL=0, TI=0(GDT), I=1 + jmp 0x0008:entry_pm32 + +.code32 +entry_pm32: + // Select data segment selector (0x0010) for ds. + mov ax, gdt_data - gdt + mov ds, ax + + // Initialize stack pointer. + // Real Mode memory (https://wiki.osdev.org/Memory_Map_(x86) + // 0x00000500 - 0x00007BFF | 29.75 KiB | conventional memory + mov esp, 0x7c00 + + // Enter zmbr.zig:kmain. + // Should not return, but for safety we emit a call rather than a jmp. + call kmain + +1: + hlt + jmp 1b + +// -- RODATA SECTION ------------------------------------------------------------ + +.section .rodata, "a", @progbits +.balign 8 +gdt: + .8byte 0x0000000000000000 // 0x00 | null descriptor + .8byte 0x00cf9a000000ffff // 0x08 | 32 bit, code (rx), present, dpl=0, g=4K, base=0, limit=fffff +gdt_data: + .8byte 0x00cf92000000ffff // 0x10 | 32 bit, data (rw), present, dpl=0, g=4K, base=0, limit=fffff +gdt_desc: + .2byte (. - gdt - 1) // size + .4byte gdt // address diff --git a/x86-bare-metal/mbr-palette/mbr.ld b/x86-bare-metal/mbr-palette/mbr.ld new file mode 100644 index 0000000..372ea42 --- /dev/null +++ b/x86-bare-metal/mbr-palette/mbr.ld @@ -0,0 +1,25 @@ +/*OUTPUT_FORMAT(binary)*/ +OUTPUT_FORMAT(elf32-i386) +OUTPUT_ARCH(i386) + +SECTIONS { + . = 0x7c00; + .boot : { + *(.boot) + } + .text : { *(.text) } + .data : { *(.data) } + .rodata : { *(.rodata) } + _boot_end = .; + + . = 0x7c00 + 510; + .mbr.magic : { + BYTE(0x55); + BYTE(0xaa); + } + + /*/DISCARD/ : { *(.*) }*/ + /*rest : { *(.*) }*/ + + ASSERT(_boot_end - 0x7c00 < 510, "boot sector must fit in 510 bytes") +} diff --git a/x86-bare-metal/mbr-palette/x220.png b/x86-bare-metal/mbr-palette/x220.png Binary files differnew file mode 100644 index 0000000..d3b6cc7 --- /dev/null +++ b/x86-bare-metal/mbr-palette/x220.png diff --git a/x86-bare-metal/mbr-palette/zmbr.zig b/x86-bare-metal/mbr-palette/zmbr.zig new file mode 100644 index 0000000..947cd06 --- /dev/null +++ b/x86-bare-metal/mbr-palette/zmbr.zig @@ -0,0 +1,29 @@ +const COLS = 320; +const ROWS = 200; + +/// Draw the color palette. +/// One color per column, remaining columns are drawn black. +fn draw_palette(video: []u8) void { + for (0..ROWS) |r| { + for (0..COLS) |c| { + if (c < 256) { + video[COLS * r + c] = @truncate(c); + } else { + video[COLS * r + c] = 0; + } + } + } +} + +// kmain should be "callconv(.naked)", once issue is fixed. +// https://github.com/ziglang/zig/issues/18183 +export fn kmain() noreturn { + // Take a slice to 256-color VGA video memory (mode 13h graphic mode). + const video: []u8 = @as([*]u8, @ptrFromInt(0xA0000))[0 .. COLS * ROWS]; + + draw_palette(video); + + while (true) { + asm volatile ("hlt"); + } +} |