Add mbr/ - update --grub handling
[grml2usb.git] / mbr / mbr.S
diff --git a/mbr/mbr.S b/mbr/mbr.S
new file mode 100644 (file)
index 0000000..fc0400b
--- /dev/null
+++ b/mbr/mbr.S
@@ -0,0 +1,292 @@
+/* $MirOS: src/sys/arch/i386/stand/mbr/mbr.S,v 1.12 2009/01/31 23:39:55 tg Exp $ */
+
+/*-
+ * Copyright (c) 2009
+ *     Thorsten Glaser <tg@mirbsd.org>
+ *
+ * Provided that these terms and disclaimer and all copyright notices
+ * are retained or reproduced in an accompanying document, permission
+ * is granted to deal in this work without restriction, including un-
+ * limited rights to use, publicly perform, distribute, sell, modify,
+ * merge, give away, or sublicence.
+ *
+ * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
+ * the utmost extent permitted by applicable law, neither express nor
+ * implied; without malicious intent or gross negligence. In no event
+ * may a licensor, author or contributor be held liable for indirect,
+ * direct, other damage, loss, or other issues arising in any way out
+ * of dealing in the work, even if advised of the possibility of such
+ * damage or existence of a defect, except proven that it results out
+ * of said person's immediate fault when using the work as intended.
+ *-
+ * Compile commands:
+ *     $ gcc -D_ASM_SOURCE -DBOOTMANAGER -D__BOOT_VER=\"0AA6\" -c mbr.S
+ *     $ ld -nostdlib -Ttext 0x0600 -N -Bstatic -e _start -o mbrmgr.elf mbr.o
+ *     $ objcopy -O binary mbrmgr.elf mbrmgr
+ */
+
+       .intel_syntax noprefix
+       .code16
+       .text
+
+       .globl  _start
+_start:        xor     eax,eax
+       mov     ss,ax
+       mov     sp,offset Lstack
+       push    eax
+       popfd
+       mov     ds,ax
+       mov     es,ax
+       mov     si,offset Lbadr
+       mov     di,offset _start
+       mov     cx,0x0200       /* size of one sector */
+       push    si              /* load / return address */
+       push    ax
+       push    offset Lmain
+       rep     movsb
+       lret
+
+       /* entry message */
+Lemsg: .ascii  "Mir-"
+       .ascii  __BOOT_VER
+#ifdef BOOTMANAGER
+       /* Lem<nn> are patch points */
+       .ascii  ": 0="
+Lem00: .ascii  "00 1="
+Lem01: .ascii  "00 2="
+Lem02: .ascii  "00 3="
+Lem03: .ascii  "00 4=hd0 5=fd0  Enter=default (timeout)\r\n"
+#endif
+       .asciz  ">"
+
+       /* failure message */
+Lfmsg: .asciz  "bad magic\r\n"
+
+#if 1
+       /* okay boot message */
+Lbmsg: .asciz  " OK\r"
+#endif
+
+       /* output NUL-terminated string from ds:si */
+Lotxt0:        mov     ah,0x0E
+       mov     bx,7
+       int     0x10
+Lotxt: lodsb
+       or      al,al
+       jnz     Lotxt0
+       ret
+
+Lmain: sti
+#ifdef BOOTMANAGER
+       /* patch the partition type values into the message */
+       mov     di,offset Lem00
+       mov     al,ds:[Lptab + 0x04]
+       call    LpBY
+       mov     di,offset Lem01
+       mov     al,ds:[Lptab + 0x14]
+       call    LpBY
+       mov     di,offset Lem02
+       mov     al,ds:[Lptab + 0x24]
+       call    LpBY
+       mov     di,offset Lem03
+       mov     al,ds:[Lptab + 0x34]
+       call    LpBY
+       mov     si,offset Lemsg
+       call    Lotxt
+#endif
+
+       /* fake invalid partition entry for MBR/FDD boot */
+       mov     di,offset Lptab + 0x40
+       xor     eax,eax
+       stosw
+       inc     ax
+       stosw
+       dec     ax
+       stosd
+       stosd
+
+       /* force bad magic if sector load fails */
+       mov     ds:[Lbmag],al
+
+#ifdef BOOTMANAGER
+#if 0 /* see above, eax is already zero here */
+       xor     ax,ax           /* read CMOS clock ticks since midnight */
+#endif
+       int     0x1A            /* 32-bit result in cx:dx */
+       mov     di,cx           /* save it in edi for later */
+       shl     edi,16
+       mov     di,dx
+       add     edi,183         /* 10 seconds, rounded up one tick */
+       Lptmo = . - 4           /* offset of the "183" above */
+
+       /* input loop with timeout */
+Lwkey: mov     ah,1
+       int     0x16            /* check if a key was pressed */
+       jnz     Lgkey           /* yeap */
+       /* delay loop */
+       xor     ax,ax
+       int     0x1A
+       shl     ecx,16
+       mov     cx,dx
+       or      al,al           /* past midnight? */
+       jz      Lsday           /* no */
+       add     ecx,1573040     /* should be 1572480, but according to RBIL… */
+Lsday: cmp     ecx,edi         /* time is over? */
+       mov     al,13
+       ja      Lfkey           /* yep, fake a return keypress */
+       jmp     Lwkey
+
+       /* input loop without timeout */
+Lgkey: mov     ah,1
+       int     0x16            /* check if a key was pressed */
+       jz      Lgkey
+       mov     ah,0
+       int     0x16
+#endif /* BOOTMANAGER */
+Lfkey: mov     bx,offset Lptab
+       mov     dl,0x80         /* drive to load from */
+#ifndef BOOTMANAGER
+       jmp     Lscan
+#else
+       sub     al,13
+       je      Lscan           /* CR / Return / Enter */
+       jb      Lgkey           /* invalid input */
+       sub     al,('0' - 13)
+       jb      Lgkey           /* invalid input */
+       cmp     al,5            /* floppy */
+       ja      Lgkey           /* invalid input */
+       jb      LdoHD           /* hard disc */
+       mov     dl,0            /* drive to load from */
+       dec     ax              /* 5 -> 4 */
+#endif
+LdoHD: shl     al,4            /* 0..4 where 4 is virtual partition */
+       add     bl,al           /* we boot this one */
+       jmp     Lboot
+
+       /* scan the partition table for an active partition */
+Lscan: mov     al,[dpart]      /* try hard-coded by fdisk(8) 'fdef' first */
+       cmp     al,3
+       jbe     LdoHD
+Lspar: cmp     byte ptr [bx],0x80
+       je      Lboot           /* found an active partition */
+       add     bl,0x10
+       cmp     bl,0xFE         /* BX = 0x07FE = Lptab + 0x40 */
+       jb      Lspar
+       /* boot the virtual partition #4 (MBR) */
+
+Lboot: /* try to boot, first LBA (we're on a HDD) then CHS */
+       mov     [bx],dl         /* drive (0x80 or 0x00) */
+       mov     si,offset Lpblk /* LBA parameter block */
+       mov     di,si
+       mov     ax,0x0010
+       stosw                   /* size of LBA parameter block */
+       mov     al,1
+       stosw                   /* number of sectors to load */
+       pop     ax
+       push    ax
+       push    bx
+       stosw                   /* load address offset */
+       xor     ax,ax
+       stosw                   /* load address segment */
+       mov     eax,[bx+8]
+       stosd                   /* LBA offset of start sector (low 32 bit) */
+       xor     ax,ax
+       stosw                   /* high 32 bit */
+       stosw                   /* high 32 bit */
+       mov     ah,0x42         /* LBA extended read */
+       call    Lload           /* try to boot that */
+       pop     si              /* edited partition table entry */
+       pop     bx              /* load offset (ES=CS=SS=DS=0000h) */
+       push    bx
+       push    si
+       mov     ax,0x0201       /* CHS read 0x01 sectors */
+       mov     cx,[si+2]       /* cylinder; sector number */
+       mov     dx,[si]         /* head; drive number */
+       call    Lload
+       mov     si,offset Lfmsg
+       call    Lotxt
+#if 0
+Lfail: jmp     Lfail
+#else
+       xor     ax,ax
+       int     0x16
+       ljmp    0xF000,0xFFF0
+#endif
+
+Lload: mov     bp,4            /* number of tries */
+Lldlp: pusha
+       int     0x13
+       popa
+       jc      Lldre           /* error, try again */
+       cmp     word ptr ds:[Lbmag],0xAA55
+       jne     Lldre           /* bad magic, try again */
+#if 0
+       mov     ax,0x0E0D       /* output a carriage return */
+       xor     bx,bx
+       int     0x10
+#else
+       mov     si,offset Lbmsg
+       call    Lotxt
+#endif
+       pop     si              /* Lload return address */
+       pop     si              /* partition table entry */
+       mov     dl,[si]
+       /* DS:SI point to partition table entry, DL is set */
+       cli                     /* be nice :) */
+       ret                     /* jump to 0000:7C00h */
+Lldre: pusha
+       xor     ax,ax           /* reset drive */
+       int     0x13
+       popa
+       dec     bp              /* another try left? */
+       jnz     Lldlp
+       ret
+
+#ifdef BOOTMANAGER
+LpBY:  mov     ah,al
+       shr     al,4
+       and     ah,0x0F
+       add     ax,0x3030
+       cmp     al,0x39
+       jbe     LpBY1
+       add     al,7
+LpBY1: cmp     ah,0x39
+       jbe     LpBY2
+       add     ah,7
+LpBY2: stosw
+       ret
+#endif
+
+       . = _start + 0x01B7
+       .globl  dpart
+       .size   dpart,1
+dpart: .byte   0xFF            /* default partition [0..3] or none */
+
+       . = _start + 0x01B8
+Lntid: .long   0               /* Microsoft® NT® volume identifier */
+Lpad1: .byte   0, 0
+
+       . = _start + 0x01BE
+       /* partition table */
+Lptab: .long   0, 0, 0, 0      /* partition entry #0 */
+       .long   0, 0, 0, 0      /* partition entry #1 */
+       .long   0, 0, 0, 0      /* partition entry #2 */
+       /* partition entry #3 + pre-installation hint */
+       .word   0, 0, 0, 0, 0
+       . = _start + 0x01F8
+       .size   Lhint,2
+#ifdef BOOTMANAGER
+Lhint: .word   (Lptmo - _start)
+#else
+Lhint: .word   0xFFFF
+#endif
+Lpad2: .word   0, 0
+
+       . = _start + 0x01FE
+Lpmag: .word   0xAA55          /* BIOS boot magic */
+
+       Lstack = 0x4000
+       Lpblk = 0x5000
+
+       Lbadr = 0x7C00
+       Lbmag = Lbadr + 0x01FE