From 267bb0d3d2b7ba892f8f5d88f14f1be1aac0df11 Mon Sep 17 00:00:00 2001
From: johannst <johannst@users.noreply.github.com>
Date: Sat, 21 Dec 2024 21:02:11 +0000
Subject: deploy: f8221e81b9752548d26675111cffca1947c46b68

---
 arch/x86/mbr/Makefile |  19 ++++++++
 arch/x86/mbr/mbr.S    | 117 ++++++++++++++++++++++++++++++++++++++++++++++++++
 arch/x86/mbr/mbr.ld   |  11 +++++
 3 files changed, 147 insertions(+)
 create mode 100644 arch/x86/mbr/Makefile
 create mode 100644 arch/x86/mbr/mbr.S
 create mode 100644 arch/x86/mbr/mbr.ld

(limited to 'arch/x86')

diff --git a/arch/x86/mbr/Makefile b/arch/x86/mbr/Makefile
new file mode 100644
index 0000000..bcecb76
--- /dev/null
+++ b/arch/x86/mbr/Makefile
@@ -0,0 +1,19 @@
+mbr: mbr.ld mbr.o
+	ld -o $@.elf -nostdlib -T $^
+	objcopy -O binary $@.elf $@
+
+mbr.o: mbr.S
+	gcc -c -o $@ -m32 -ffreestanding $^
+
+clean:
+	$(RM) mbr.o mbr.elf mbr
+
+run: mbr
+	qemu-system-i386 -hda mbr $(QEMU_ARGS)
+
+debug:
+	make run QEMU_ARGS="-s -S"
+
+gdb:
+	gdb -ex 'target remote :1234' mbr.elf -ex 'layout asm' -ex 'b entry_pm32' -ex 'c'
+
diff --git a/arch/x86/mbr/mbr.S b/arch/x86/mbr/mbr.S
new file mode 100644
index 0000000..b74bae5
--- /dev/null
+++ b/arch/x86/mbr/mbr.S
@@ -0,0 +1,117 @@
+.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 3, see [1].
+    //   * 80x25 text mode
+    //   * 640x200 pixel resolution (8x8 pixel per char)
+    //   * 16 colors (4bit)
+    //   * 4 pages
+    //   * 0xB800 screen address
+    //
+    // [1] http://www.ctyme.com/intr/rb-0069.htm
+    mov ax, 0x3
+    int 0x10
+
+    // Move cursor to second row.
+    // http://www.ctyme.com/intr/rb-0087.htm
+    mov ah, 0x02
+    mov bh, 0  // page
+    mov dh, 1  // row
+    mov dl, 0  // col
+    int 0x10
+
+    // Clear direction flag for lodsb below.
+    cld
+
+    // Load pointer to msg_rm string (null terminated).
+    lea si, [msg_rm]
+
+    // Teletype output char at current cursor position.
+    // http://www.ctyme.com/intr/rb-0106.htm
+    mov ah, 0x0e
+1:
+    lodsb         // al <- ds:si ; si+=1 ; (al char to write)
+    test al,al    // test for null terminator
+    jz 2f
+    int 0x10
+    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
+
+    // Write through VGA interface (video memory).
+    // Each character is represented by 2 bytes.
+    //   4 bit bg | 4 bit fg | 8 bit ascii char
+    //
+    // Start writing at third line.
+    mov edi, 0xb8000 + (80 * 2 * 2) //
+
+    lea esi, [msg_pm]
+1:
+    lodsb           // al <- ds:esi ; esi+=1
+    test al, al     // test for null terminator
+    jz 2f
+    or eax, 0x1f00  // blue bg, white fg
+    stosw           // ds:[edi] <- ax; edi+=2
+    jmp 1b
+2:
+    hlt
+    jmp 2b
+
+// For simplicity keep data used by boot sector in the same section.
+.balign 8
+msg_rm:
+    .asciz "Hello from Real Mode!"
+msg_pm:
+    .asciz "Hello from Protected Mode!"
+
+.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
+
+// Write MBR boot magic value.
+.fill 510 - (. - .boot), 1, 0x00
+.2byte 0xaa55
diff --git a/arch/x86/mbr/mbr.ld b/arch/x86/mbr/mbr.ld
new file mode 100644
index 0000000..46d8a14
--- /dev/null
+++ b/arch/x86/mbr/mbr.ld
@@ -0,0 +1,11 @@
+OUTPUT_FORMAT(elf32-i386)
+OUTPUT_ARCH(i386)
+
+SECTIONS {
+    . = 0x7c00;
+    .boot     : { *(.boot) }
+    _boot_end = .;
+    /DISCARD/ : { *(.*) }
+
+    ASSERT(_boot_end - 0x7c00 == 512, "boot sector must be exact 512 bytes")
+}
-- 
cgit v1.2.3