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
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.
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]
23 * Copyright 2012 OmniTI Computer Consulting, Inc. All rights reserved.
25 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
26 * Use is subject to license terms.
30 * SOLARIS MASTER BOOT:
32 * PURPOSE: loads the primary boot from the active fdisk partition.
33 * in effect, this routine mimics the functionality of INT 0x19.
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.
39 * for compatibility with the ROM BIOS, we contain standard DOS structures:
41 * the fdisk partition table (at offset 0x1BE-0x1FE)
42 * boot signature bytes (0x55, 0xAA at 0x1FE, 0x1FF)
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!
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.
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.
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
69 * interface to partition boot: BootDev in DL
71 *=============================================================================
72 * Master boot record: resides on first physical sector of device
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.
83 #define PBOOT_ADDR 0x7C00
84 #define RELOC_ADDR 0x600
86 #define FDISK_START 0x1BE
87 #define BOOT_SIG 0xAA55
91 #define FD_PTESIZE 0x10
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.
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".
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 */
119 _start: /* _start is loaded at PBOOT_ADDR */
123 .ascii "M3.0" /* ident string */
126 cli /* don't bother me now! */
128 /* prepare to relocate ourselves */
129 cld /* prepare for relocation */
133 /* set up segment registers */
134 mov ax, cs /* initialize segment registers */
136 mov sp, si /* stack starts down from 7C00 */
140 push cx /* save possible signature on stack */
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)
149 sti /* re-enable interrupts */
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.
161 /* mov BootDev, dl */
163 /* set debug flag based on seeing "both shift down" */
164 mov ah, 2 /* get shift state */
166 and al, 3 /* isolate shift-key bits */
169 mov byte ptr [debugmode], 1 /* set to 1 */
173 * Search the fdisk table sequentially to find a physical partition
174 * that is marked as "active" (bootable).
176 mov bx, RELOC_ADDR + FDISK_START
180 cmp byte ptr [bx], ACTIVE
186 mov bp, offset NoActiveErrMsg
187 mov cx, SIZEOF(NoActiveErrMsg)
191 mov ah, 0 /* reset disk */
194 push bx /* save partition pointer */
196 /* Check for LBA BIOS */
197 mov ah, 0x41 /* chkext function */
198 mov bx, 0x55AA /* signature to change */
201 jc noLBA /* carry == failure */
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)
212 * LBA case: form a packet on the stack and call fn 0x42 to read
213 * packet, backwards (from hi to lo addresses):
215 * seg:ofs buffer address
219 * packet size in bytes (>= 0x10)
222 pop bx /* restore partition pointer */
223 push bx /* and save again */
224 mov cx, N_RETRIES /* retry count */
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) */
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 */
240 loop retryLBA /* try again */
241 jmp readerr /* exhausted retries; give up */
244 mov bp, offset chsstring
245 mov cx, SIZEOF(chsstring)
248 pop bx /* restore partition pointer */
249 push bx /* and save again */
251 /* get BIOS disk parameters */
252 mov dl, byte ptr [BootDev]
258 /* error reading geom; die */
259 mov bp, offset GeomErrMsg
260 mov cx, SIZEOF(GeomErrMsg)
264 /* calculate sectors per track */
265 mov al, cl /* ah doesn't matter; mul dh will set it */
267 mov byte ptr [secPerTrk], al
269 /* calculate sectors per cylinder */
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 */
300 mov ax, 0x201 /* 02=read, sector count = 1 */
304 mov ah, 0 /* reset disk */
308 jne retry_noLBA /* retry, or fall through to read error */
311 mov bp, offset ReadErrMsg
312 mov cx, SIZEOF(ReadErrMsg)
316 /* verify boot record signature */
318 cmp word ptr [bx+0x1FE], BOOT_SIG
321 mov bp, offset SigErrMsg
322 mov cx, SIZEOF(SigErrMsg)
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....... */
335 * bp contains pointer to error message string,
336 * cx contains string length
338 mov bx, 0x4F /* video page, attribute */
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 */
353 mov dx, 0x1700 /* row, col */
360 mov ah, 0 /* get key */
374 .byte 0x80 /* assumes drive 80 (see comment above) */
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
390 * .byte 0x80,1,1,0,0x82,0xfe,0x7f,4,0x3f,0,0,0,0x86,0xfa,0x3f,0