import less(1)
[unleashed/tickless.git] / usr / src / psm / stand / bootblks / ufs / i386 / mboot.S
blob48afbae207c4a482d825771a7aed1c8dc1bc2b03
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
23  * Copyright 2012 OmniTI Computer Consulting, Inc.  All rights reserved.
24  *
25  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
26  * Use is subject to license terms.
27  */
30  * SOLARIS MASTER BOOT:
31  *
32  * PURPOSE: loads the primary boot from the active fdisk partition.
33  *          in effect, this routine mimics the functionality of INT 0x19.
34  *
35  * resides on the first physical sector of the hard drive media.
36  * loaded by INT 0x19 (ROM bootstrap loader) at address 0x7C00
37  * limited to 512 bytes total, including embedded fdisk table.
38  *
39  * for compatibility with the ROM BIOS, we contain standard DOS structures:
40  *
41  *      the fdisk partition table (at offset 0x1BE-0x1FE)
42  *      boot signature bytes (0x55, 0xAA at 0x1FE, 0x1FF)
43  *
44  * the above two entities are required in order to be compatible with
45  * the manner in which the DOS BIOS has always performed its boot operation.
46  * In the event that our master boot record is inadvertently replaced by
47  * a standard DOS boot sector, the booting operation will still succeed!
48  *
49  * This master boot record uses the relsect/numsect fields of the partition
50  * table entry, to compute the start of the active partition; therefore,
51  * it is geometry independent.  This means that the drive could be "built"
52  * on a system with a disk controller that uses a given disk geometry, but
53  * would run on any other controller.
54  *
55  * SYNOPSIS:
56  *     begins execution at 0:0x7C00
57  *     relocates to 0:0x600 (to get out of the way!)
58  *     reads fdisk table to locate bootable partition
59  *     load boot record from the active fdisk partition at 0x7C00
60  *     verify boot record signature bytes
61  *     jump to/execute the SOLARIS PARTITION PRIMARY BOOT
62  *     error handler - can either reboot, or invoke INT 0x18.
63  *
64  * interface from DOS INT 0x19:  BootDev in DL
65  * (this fails sometimes, so we look for a signature to determine whether
66  *  to rely on DL from the floppy boot, or if we should assume 0x80 from
67  *  the BIOS)
68  *
69  * interface to partition boot: BootDev in DL
70  *
71  *=============================================================================
72  * Master boot record: resides on first physical sector of device
73  */
76  * This file is written in GNU as syntax using Intel assembler syntax.  The
77  * startup label _start will be executed at address PBOOT_ADDR (0x7C00), but
78  * the text section must be set at address RELOC_ADDR (0x600).  With GNU ld
79  * this can be done using the "-Ttext 600" option.
80  */
83 #define PBOOT_ADDR      0x7C00
84 #define RELOC_ADDR      0x600
86 #define FDISK_START     0x1BE
87 #define BOOT_SIG        0xAA55
88 #define N_RETRIES       5
90 #define FD_NUMPART      4
91 #define FD_PTESIZE      0x10
92 #define ACTIVE          0x80
95  * A convenience macro for declaring a message string (using .ascii directive--
96  * NOT nul-terminated) surrounded by two labels, which can then be used with
97  * the SIZEOF() macro to get its length.
98  */
99 #define MSG(label, string)      label: .ascii string; label##_end:
102  * Returns the length of some consecutive bytes.  These bytes must be placed
103  * between two labels.  The ending label must be the same as the starting label
104  * but with a suffix "_end".
105  */
106 #define SIZEOF(label)   (label##_end - label)
109         .title  "Solaris_Master_Boot"
111         .intel_syntax noprefix          /* use Intel syntax */
112         .code16                         /* 16-bit mode (real mode) */
114         .text                           /* code segment begins here */
116         .global BootDev
117         .global _start
119 _start:                                 /* _start is loaded at PBOOT_ADDR */
120         jmp     bootrun
122 Version:
123         .ascii  "M3.0"                  /* ident string */
125 bootrun:
126         cli                             /* don't bother me now! */
128         /* prepare to relocate ourselves */
129         cld                             /* prepare for relocation */
130         mov     si, PBOOT_ADDR
131         mov     di, RELOC_ADDR
133         /* set up segment registers */
134         mov     ax, cs                  /* initialize segment registers */
135         mov     ss, ax
136         mov     sp, si                  /* stack starts down from 7C00 */
137         mov     es, ax
138         mov     ds, ax
140         push    cx                      /* save possible signature on stack */
141         mov     cx, 0x100
142         rep     movsw
143         pop     cx                      /* restore saved cx */
145         /* running at PBOOT_ADDR, jump to RELOC_ADDR-rel addr */
146         jmp     (new_home - PBOOT_ADDR + RELOC_ADDR)
148 new_home:
149         sti                             /* re-enable interrupts */
151         /*
152          * assuming boot device number is in dl has caused problems in the past
153          * since we still don't absolutely have to rely on it, I've just
154          * removed the now-pointless code to check for the FACE-CAFE signature
155          * from mdexec, which doesn't do anything anymore, but left the
156          * assumption that BootDev is 0x80 and nothing but.  If we ever need to
157          * have BIOS load us from a drive not numbered 0x80, we'll need to
158          * uncomment the following line; otherwise, the initialized value of
159          * BootDev, namely 0x80, will be used for disk accesses.
160          */
161         /* mov BootDev, dl */
163         /* set debug flag based on seeing "both shift down" */
164         mov     ah, 2           /* get shift state */
165         int     0x16
166         and     al, 3           /* isolate shift-key bits */
167         cmp     al, 3
168         jne     nodbg
169         mov     byte ptr [debugmode], 1         /* set to 1 */
171 nodbg:
172         /*
173          * Search the fdisk table sequentially to find a physical partition
174          * that is marked as "active" (bootable).
175          */
176         mov     bx, RELOC_ADDR + FDISK_START
177         mov     cx, FD_NUMPART
179 nxtpart:
180         cmp     byte ptr [bx], ACTIVE
181         je      got_active_part
182         add     bx, FD_PTESIZE
183         loop    nxtpart
185 noparts:
186         mov     bp, offset NoActiveErrMsg
187         mov     cx, SIZEOF(NoActiveErrMsg)
188         jmp     fatal_err
190 got_active_part:
191         mov     ah, 0           /* reset disk */
192         int     0x13
194         push    bx              /* save partition pointer */
196         /* Check for LBA BIOS */
197         mov     ah, 0x41        /* chkext function */
198         mov     bx, 0x55AA      /* signature to change */
199         mov     cx, 0
200         int     0x13
201         jc      noLBA           /* carry == failure */
202         cmp     bx, 0xAA55
203         jne     noLBA           /* bad signature in BX == failure */
204         test    cx, 1           /* cx & 1 must be true, or... */
205         jz      noLBA           /* ...no LBA */
207         mov     bp, offset lbastring
208         mov     cx, SIZEOF(lbastring)
209         call    debugout
211         /*
212          * LBA case: form a packet on the stack and call fn 0x42 to read
213          * packet, backwards (from hi to lo addresses):
214          * 8-byte LBA
215          * seg:ofs buffer address
216          * byte reserved
217          * byte nblocks
218          * byte reserved
219          * packet size in bytes (>= 0x10)
220          */
222         pop     bx              /* restore partition pointer */
223         push    bx              /* and save again */
224         mov     cx, N_RETRIES   /* retry count */
225 retryLBA:
226         pushd   0               /* hi 32 bits of 64-bit sector number */
227         push    dword ptr [bx+8]        /* relsect (lo 32 of 64-bit number) */
228         push    dword ptr [solaris_priboot]     /* seg:ofs of buffer */
229         push    1               /* reserved, one block */
230         push    0x10            /* reserved, size (0x10) */
231         mov     ah, 0x42        /* "read LBA" */
232         mov     si, sp          /* (ds already == ss) */
233         int     0x13
234         lahf                    /* save flags */
235         add     sp, 16          /* restore stack */
236         sahf                    /* restore flags */
237         jnc     readok          /* got it */
238         mov     ah, 0           /* reset disk */
239         int     0x13
240         loop    retryLBA        /* try again */
241         jmp     readerr         /* exhausted retries; give up */
243 noLBA:
244         mov     bp, offset chsstring
245         mov     cx, SIZEOF(chsstring)
246         call    debugout
248         pop     bx              /* restore partition pointer */
249         push    bx              /* and save again */
251         /* get BIOS disk parameters */
252         mov     dl, byte ptr [BootDev]
253         mov     ah, 0x8
254         int     0x13
256         jnc     geomok
258         /* error reading geom; die */
259         mov     bp, offset GeomErrMsg
260         mov     cx, SIZEOF(GeomErrMsg)
261         jmp     fatal_err
263 geomok:
264         /* calculate sectors per track */
265         mov     al, cl          /* ah doesn't matter; mul dh will set it */
266         and     al, 0x3F
267         mov     byte ptr [secPerTrk], al
269         /* calculate sectors per cylinder */
270         inc     dh
271         mul     dh
272         mov     word ptr [secPerCyl], ax
274         /* calculate cylinder # */
275         mov     ax, [bx+8]      /* ax = loword(relsect) */
276         mov     dx, [bx+10]     /* dx:ax = relsect */
277         div     word ptr [secPerCyl]    /* ax = cyl, */
278                                         /* dx = sect in cyl (0 - cylsize-1) */
279         mov     bx, ax          /* bx = cyl */
281         /* calculate head/sector # */
282         mov     ax, dx          /* ax = sect in cyl (0 - cylsize-1) */
283         div     byte ptr [secPerTrk]    /* al = head, */
284                                         /* ah = 0-rel sect in track */
285         inc     ah              /* ah = 1-rel sector */
287         xor     cl,cl           /* cl = 0 */
288         mov     ch, bh          /* ch = hi bits of cyl (if any) */
289         shr     cx, 2           /* cl{7:6} = cyl{9:8} (if any) */
290         and     cl, 0xC0        /* cl = cyl{9:8} to merge with sect (if any) */
292         or      cl, ah          /* cl{7:6} = cyl bits, cl{5:0} = sect */
293         mov     ch, bl          /* ch = lo cyl bits */
294         mov     dh, al          /* dh = head */
295         mov     dl, byte ptr [BootDev]          /* dl = drivenum */
296         les     bx, solaris_priboot             /* es:bx points to buffer */
298         mov     si, N_RETRIES
299 retry_noLBA:
300         mov     ax, 0x201       /* 02=read, sector count = 1 */
302         int     0x13
303         jnc     readok
304         mov     ah, 0           /* reset disk */
305         int     0x13
306         dec     si
307         cmp     si, 0
308         jne     retry_noLBA     /* retry, or fall through to read error */
310 readerr:
311         mov     bp, offset ReadErrMsg
312         mov     cx, SIZEOF(ReadErrMsg)
313         jmp     fatal_err
315 readok:
316         /* verify boot record signature */
317         mov     bx, PBOOT_ADDR
318         cmp     word ptr [bx+0x1FE], BOOT_SIG
319         je      sigok
321         mov     bp, offset SigErrMsg
322         mov     cx, SIZEOF(SigErrMsg)
323         jmp     fatal_err
325 sigok:
326         mov     dl, byte ptr [BootDev]  /* pass BootDev to next boot phase */
327         pop     si                      /* and pass partition pointer ds:si */
328         call    dword ptr [solaris_priboot]     /* call doesn't return! */
330         mov     bp, offset ReturnErrMsg
331         mov     cx, SIZEOF(ReturnErrMsg)
333 fatal_err:                      /* land of no return....... */
334         /*
335          * bp contains pointer to error message string,
336          * cx contains string length
337          */
338         mov     bx, 0x4F        /* video page, attribute */
339         call    msgout
340         int     0x18
342 debugout:
343         /* call with string pointer in es:bp, len in cx */
344         cmp     byte ptr [debugmode], 0
345         je      debugout_ret    /* skip if not in debug mode */
347         mov     bx, 0x1F        /* page, attr (white on blue) */
349         /* alternate entry for fatal_err */
350 msgout:
351         pusha
352         mov     ax, 0x1301
353         mov     dx, 0x1700      /* row, col */
354         int     0x10
356         mov     al, 7           /* BEL */
357         mov     cx, 1
358         int     0x10
360         mov     ah, 0           /* get key */
361         int     0x16
362         popa
364 debugout_ret:
365         ret
367 secPerTrk:
368         .byte   0
369 secPerCyl:
370         .word   0
371 solaris_priboot:
372         .long   PBOOT_ADDR
373 BootDev:
374         .byte   0x80            /* assumes drive 80 (see comment above) */
375 debugmode:
376         .byte   0
378 MSG(GeomErrMsg,         "Can't read geometry")
379 MSG(NoActiveErrMsg,     "No active partition")
380 MSG(ReadErrMsg,         "Can't read PBR")
381 MSG(SigErrMsg,          "Bad PBR sig")
382 MSG(ReturnErrMsg,       "!!!")
383 MSG(lbastring,          "LBA")
384 MSG(chsstring,          "CHS")
387  * For debugging:  Here's a representative FDISK table entry
389  * .org   0x1BE
390  * .byte  0x80,1,1,0,0x82,0xfe,0x7f,4,0x3f,0,0,0,0x86,0xfa,0x3f,0
391  */
392         .org    0x1FE
394         .word   BOOT_SIG