summaryrefslogtreecommitdiff
path: root/boot/amd64/generic/mbr/mbr.S
diff options
context:
space:
mode:
Diffstat (limited to 'boot/amd64/generic/mbr/mbr.S')
-rw-r--r--boot/amd64/generic/mbr/mbr.S213
1 files changed, 213 insertions, 0 deletions
diff --git a/boot/amd64/generic/mbr/mbr.S b/boot/amd64/generic/mbr/mbr.S
new file mode 100644
index 0000000..7cd7484
--- /dev/null
+++ b/boot/amd64/generic/mbr/mbr.S
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 2026, Apollo Telephone Laboratories.
+ * Provided under the BSD-3 clause.
+ */
+
+#define BOOT_SEG 0x7C0 /* Segment we reside on startup */
+#define BOOT_RELOC_SEG 0x7A0 /* Relocation segment */
+#define RDAR_MAGIC ">RDAR!"
+#define RDAR_MAGIC_LEN 6
+#define BOOT_PATH "s2.bin"
+#define BOOT_PATH_LEN 6
+
+ .text
+ .code16
+_start:
+ ljmp $BOOT_SEG,$main
+main:
+ cli
+ cld
+
+ /* Set segment registers */
+ xor %ax, %ax
+ mov %ax, %fs
+ mov %ax, %gs
+ mov %ax, %ss
+ mov %ax, %es
+ mov $BOOT_SEG, %ax
+ mov %ax, %ds
+
+ /* Save the drive */
+ mov %dl, drive_num
+
+ /*
+ * The second stage bootloader expects to be loaded to 0x7C00 but since we are
+ * already executing at this address we'll need to relocate ourselves first before
+ * we clobber it.
+ */
+ mov $BOOT_SEG, %ax
+ mov %ax, %ds
+ mov $BOOT_RELOC_SEG, %ax
+ mov %ax, %es
+ xor %si, %si
+ xor %di, %di
+ mov $0x200, %cx
+ cld
+ rep movsb
+
+ jmp $BOOT_RELOC_SEG,$1f
+1: mov $0x7C00, %sp
+
+ /* Load two sectors */
+ movw $2, dap_blkcnt
+ movl $1, dap_lba_low
+ call disk_read_lba
+
+ mov $BOOT_RELOC_SEG, %ax
+ mov %ax, %ds
+
+ /* Get stage2 */
+ call find_stage2
+
+ /* Obtain the data offset */
+ mov $BOOT_SEG, %ax
+ mov %ax, %ds
+ add $40, %si
+ movw (%si), %si
+
+ mov $BOOT_SEG, %ax
+ mov %ax, %ds
+ mov %ax, %es
+ xor %di, %di
+ mov $0x200, %cx
+ cld
+ rep movsb
+
+ /* Jump to stage 2 */
+ xor %ax, %ax
+ mov %ax, %ds
+ ljmp $0x0000,$0x7C00
+
+/*
+ * Write a character to the boot console
+ *
+ * %al: Character to write
+ */
+putc:
+ mov $0x0E, %ah
+ xor %bh, %bh
+ int $0x10
+ ret
+
+/*
+ * Write a string to the boot console
+ *
+ * %si: Pointer to string to write
+ */
+puts:
+ lodsb
+ or %al, %al
+ jz 1f
+ call putc
+ jmp puts
+1: ret
+
+/*
+ * Locate stage2 on the disk
+ *
+ * Stage 2 data descriptor is returned in %SI
+ */
+find_stage2:
+ push %ds
+ push %es
+
+ /* Verify that magic is correct */
+ mov $BOOT_SEG, %ax
+ mov %ax, %ds
+ xor %bx, %bx /* Tracks %SI */
+ xor %si, %si
+ mov $BOOT_RELOC_SEG, %ax
+ mov %ax, %es
+ mov $rdar_magic, %di
+ mov $RDAR_MAGIC_LEN, %cx
+ rep cmpsb
+ jne .bad_magic
+
+ /* Iterate every data descriptor */
+ clc /* Carry set if found */
+1: movw %ds:6, %cx /* Add data descriptor size */
+ mov %bx, %si
+ mov %si, %dx
+ add %cx, %bx
+ mov $rdar_magic, %di
+ mov $RDAR_MAGIC_LEN, %cx
+ rep cmpsb
+ jne .not_found
+
+ /* Does the path match? */
+ mov %dx, %si
+ add $8, %si
+ mov $stage2_path, %di
+ mov $BOOT_PATH_LEN, %cx
+ rep cmpsb
+ jne 1b
+
+ mov %dx, %si
+ stc
+ pop %es
+ pop %ds
+ jnc .not_found
+ ret
+.not_found:
+ pop %ds
+ mov $not_found_msg, %si
+ call puts
+1: cli
+ hlt
+ jmp 1b
+
+.bad_magic:
+ /* Restore %DS */
+ mov $BOOT_RELOC_SEG, %ax
+ mov %ax, %ds
+
+ mov $bad_magic_msg, %si
+ call puts
+1: cli
+ hlt
+ jmp 1b
+
+/*
+ * Read sectors from the disk
+ */
+disk_read_lba:
+ pusha
+ mov $dap, %si
+ mov $0x42, %ah
+ mov drive_num, %dl
+ int $0x13
+ jc .error
+ popa
+ ret
+.error:
+ mov $disk_err_msg, %si
+ call puts
+1: cli
+ hlt
+ jmp 1b
+
+/* Global stores */
+rdar_magic: .ascii RDAR_MAGIC
+bad_magic_msg: .ascii "bad RDAR magic\r\n\0"
+not_found_msg: .ascii "stage 2 not found\r\n\0"
+disk_err_msg: .ascii "\r\n!!!disk error!!!\r\n\0"
+stage2_path: .ascii BOOT_PATH
+drive_num: .byte 0
+
+dap:
+ .byte 0x10
+ .byte 0x00
+dap_blkcnt:
+ .word 0
+dap_destptr:
+ .word 0x7C00
+dap_destseg:
+ .word 0x0000
+dap_lba_low:
+ .long 0
+dap_lba_high:
+ .long 0
+
+ .org 510
+ .byte 0x55
+ .byte 0xAA