Add support for --mbr-manager
[grml2usb.git] / mbr / mbr.S
1 /* $MirOS: src/sys/arch/i386/stand/mbr/mbr.S,v 1.12 2009/01/31 23:39:55 tg Exp $ */
2
3 /*-
4  * Copyright (c) 2009
5  *      Thorsten Glaser <tg@mirbsd.org>
6  *
7  * Provided that these terms and disclaimer and all copyright notices
8  * are retained or reproduced in an accompanying document, permission
9  * is granted to deal in this work without restriction, including un-
10  * limited rights to use, publicly perform, distribute, sell, modify,
11  * merge, give away, or sublicence.
12  *
13  * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
14  * the utmost extent permitted by applicable law, neither express nor
15  * implied; without malicious intent or gross negligence. In no event
16  * may a licensor, author or contributor be held liable for indirect,
17  * direct, other damage, loss, or other issues arising in any way out
18  * of dealing in the work, even if advised of the possibility of such
19  * damage or existence of a defect, except proven that it results out
20  * of said person's immediate fault when using the work as intended.
21  *-
22  * Compile commands:
23  *      $ gcc -D_ASM_SOURCE -DBOOTMANAGER -D__BOOT_VER=\"0AA6\" -c mbr.S
24  *      $ ld -nostdlib -Ttext 0x0600 -N -Bstatic -e _start -o mbrmgr.elf mbr.o
25  *      $ objcopy -O binary mbrmgr.elf mbrmgr
26  */
27
28         .intel_syntax noprefix
29         .code16
30         .text
31
32         .globl  _start
33 _start: xor     eax,eax
34         mov     ss,ax
35         mov     sp,offset Lstack
36         push    eax
37         popfd
38         mov     ds,ax
39         mov     es,ax
40         mov     si,offset Lbadr
41         mov     di,offset _start
42         mov     cx,0x0200       /* size of one sector */
43         push    si              /* load / return address */
44         push    ax
45         push    offset Lmain
46         rep     movsb
47         lret
48
49         /* entry message */
50 Lemsg:  .ascii  "Mir-"
51         .ascii  __BOOT_VER
52 #ifdef BOOTMANAGER
53         /* Lem<nn> are patch points */
54         .ascii  ": 0="
55 Lem00:  .ascii  "00 1="
56 Lem01:  .ascii  "00 2="
57 Lem02:  .ascii  "00 3="
58 Lem03:  .ascii  "00 4=hd0 5=fd0  Enter=default (timeout)\r\n"
59 #endif
60         .asciz  ">"
61
62         /* failure message */
63 Lfmsg:  .asciz  "bad magic\r\n"
64
65 #if 1
66         /* okay boot message */
67 Lbmsg:  .asciz  " OK\r"
68 #endif
69
70         /* output NUL-terminated string from ds:si */
71 Lotxt0: mov     ah,0x0E
72         mov     bx,7
73         int     0x10
74 Lotxt:  lodsb
75         or      al,al
76         jnz     Lotxt0
77         ret
78
79 Lmain:  sti
80 #ifdef BOOTMANAGER
81         /* patch the partition type values into the message */
82         mov     di,offset Lem00
83         mov     al,ds:[Lptab + 0x04]
84         call    LpBY
85         mov     di,offset Lem01
86         mov     al,ds:[Lptab + 0x14]
87         call    LpBY
88         mov     di,offset Lem02
89         mov     al,ds:[Lptab + 0x24]
90         call    LpBY
91         mov     di,offset Lem03
92         mov     al,ds:[Lptab + 0x34]
93         call    LpBY
94         mov     si,offset Lemsg
95         call    Lotxt
96 #endif
97
98         /* fake invalid partition entry for MBR/FDD boot */
99         mov     di,offset Lptab + 0x40
100         xor     eax,eax
101         stosw
102         inc     ax
103         stosw
104         dec     ax
105         stosd
106         stosd
107
108         /* force bad magic if sector load fails */
109         mov     ds:[Lbmag],al
110
111 #ifdef BOOTMANAGER
112 #if 0 /* see above, eax is already zero here */
113         xor     ax,ax           /* read CMOS clock ticks since midnight */
114 #endif
115         int     0x1A            /* 32-bit result in cx:dx */
116         mov     di,cx           /* save it in edi for later */
117         shl     edi,16
118         mov     di,dx
119         add     edi,183         /* 10 seconds, rounded up one tick */
120         Lptmo = . - 4           /* offset of the "183" above */
121
122         /* input loop with timeout */
123 Lwkey:  mov     ah,1
124         int     0x16            /* check if a key was pressed */
125         jnz     Lgkey           /* yeap */
126         /* delay loop */
127         xor     ax,ax
128         int     0x1A
129         shl     ecx,16
130         mov     cx,dx
131         or      al,al           /* past midnight? */
132         jz      Lsday           /* no */
133         add     ecx,1573040     /* should be 1572480, but according to RBIL… */
134 Lsday:  cmp     ecx,edi         /* time is over? */
135         mov     al,13
136         ja      Lfkey           /* yep, fake a return keypress */
137         jmp     Lwkey
138
139         /* input loop without timeout */
140 Lgkey:  mov     ah,1
141         int     0x16            /* check if a key was pressed */
142         jz      Lgkey
143         mov     ah,0
144         int     0x16
145 #endif /* BOOTMANAGER */
146 Lfkey:  mov     bx,offset Lptab
147         mov     dl,0x80         /* drive to load from */
148 #ifndef BOOTMANAGER
149         jmp     Lscan
150 #else
151         sub     al,13
152         je      Lscan           /* CR / Return / Enter */
153         jb      Lgkey           /* invalid input */
154         sub     al,('0' - 13)
155         jb      Lgkey           /* invalid input */
156         cmp     al,5            /* floppy */
157         ja      Lgkey           /* invalid input */
158         jb      LdoHD           /* hard disc */
159         mov     dl,0            /* drive to load from */
160         dec     ax              /* 5 -> 4 */
161 #endif
162 LdoHD:  shl     al,4            /* 0..4 where 4 is virtual partition */
163         add     bl,al           /* we boot this one */
164         jmp     Lboot
165
166         /* scan the partition table for an active partition */
167 Lscan:  mov     al,[dpart]      /* try hard-coded by fdisk(8) 'fdef' first */
168         cmp     al,3
169         jbe     LdoHD
170 Lspar:  cmp     byte ptr [bx],0x80
171         je      Lboot           /* found an active partition */
172         add     bl,0x10
173         cmp     bl,0xFE         /* BX = 0x07FE = Lptab + 0x40 */
174         jb      Lspar
175         /* boot the virtual partition #4 (MBR) */
176
177 Lboot:  /* try to boot, first LBA (we're on a HDD) then CHS */
178         mov     [bx],dl         /* drive (0x80 or 0x00) */
179         mov     si,offset Lpblk /* LBA parameter block */
180         mov     di,si
181         mov     ax,0x0010
182         stosw                   /* size of LBA parameter block */
183         mov     al,1
184         stosw                   /* number of sectors to load */
185         pop     ax
186         push    ax
187         push    bx
188         stosw                   /* load address offset */
189         xor     ax,ax
190         stosw                   /* load address segment */
191         mov     eax,[bx+8]
192         stosd                   /* LBA offset of start sector (low 32 bit) */
193         xor     ax,ax
194         stosw                   /* high 32 bit */
195         stosw                   /* high 32 bit */
196         mov     ah,0x42         /* LBA extended read */
197         call    Lload           /* try to boot that */
198         pop     si              /* edited partition table entry */
199         pop     bx              /* load offset (ES=CS=SS=DS=0000h) */
200         push    bx
201         push    si
202         mov     ax,0x0201       /* CHS read 0x01 sectors */
203         mov     cx,[si+2]       /* cylinder; sector number */
204         mov     dx,[si]         /* head; drive number */
205         call    Lload
206         mov     si,offset Lfmsg
207         call    Lotxt
208 #if 0
209 Lfail:  jmp     Lfail
210 #else
211         xor     ax,ax
212         int     0x16
213         ljmp    0xF000,0xFFF0
214 #endif
215
216 Lload:  mov     bp,4            /* number of tries */
217 Lldlp:  pusha
218         int     0x13
219         popa
220         jc      Lldre           /* error, try again */
221         cmp     word ptr ds:[Lbmag],0xAA55
222         jne     Lldre           /* bad magic, try again */
223 #if 0
224         mov     ax,0x0E0D       /* output a carriage return */
225         xor     bx,bx
226         int     0x10
227 #else
228         mov     si,offset Lbmsg
229         call    Lotxt
230 #endif
231         pop     si              /* Lload return address */
232         pop     si              /* partition table entry */
233         mov     dl,[si]
234         /* DS:SI point to partition table entry, DL is set */
235         cli                     /* be nice :) */
236         ret                     /* jump to 0000:7C00h */
237 Lldre:  pusha
238         xor     ax,ax           /* reset drive */
239         int     0x13
240         popa
241         dec     bp              /* another try left? */
242         jnz     Lldlp
243         ret
244
245 #ifdef BOOTMANAGER
246 LpBY:   mov     ah,al
247         shr     al,4
248         and     ah,0x0F
249         add     ax,0x3030
250         cmp     al,0x39
251         jbe     LpBY1
252         add     al,7
253 LpBY1:  cmp     ah,0x39
254         jbe     LpBY2
255         add     ah,7
256 LpBY2:  stosw
257         ret
258 #endif
259
260         . = _start + 0x01B7
261         .globl  dpart
262         .size   dpart,1
263 dpart:  .byte   0xFF            /* default partition [0..3] or none */
264
265         . = _start + 0x01B8
266 Lntid:  .long   0               /* Microsoft® NT® volume identifier */
267 Lpad1:  .byte   0, 0
268
269         . = _start + 0x01BE
270         /* partition table */
271 Lptab:  .long   0, 0, 0, 0      /* partition entry #0 */
272         .long   0, 0, 0, 0      /* partition entry #1 */
273         .long   0, 0, 0, 0      /* partition entry #2 */
274         /* partition entry #3 + pre-installation hint */
275         .word   0, 0, 0, 0, 0
276         . = _start + 0x01F8
277         .size   Lhint,2
278 #ifdef BOOTMANAGER
279 Lhint:  .word   (Lptmo - _start)
280 #else
281 Lhint:  .word   0xFFFF
282 #endif
283 Lpad2:  .word   0, 0
284
285         . = _start + 0x01FE
286 Lpmag:  .word   0xAA55          /* BIOS boot magic */
287
288         Lstack = 0x4000
289         Lpblk = 0x5000
290
291         Lbadr = 0x7C00
292         Lbmag = Lbadr + 0x01FE