xref: /haiku/src/bin/writembr/mbr.S (revision 11e8ecdd9488eee107d519d6ab8005af1017531d)
1*11e8ecddSJessica Hamilton/*
2*11e8ecddSJessica Hamilton * Partly from:
3*11e8ecddSJessica Hamilton * $FreeBSD: src/sys/boot/i386/pmbr/pmbr.s,v 1.2 2007/11/26 21:29:59 jhb Exp $
4*11e8ecddSJessica Hamilton *
5*11e8ecddSJessica Hamilton * Copyright (c) 2007 Yahoo!, Inc.
6*11e8ecddSJessica Hamilton * All rights reserved.
7*11e8ecddSJessica Hamilton * Written by: John Baldwin <jhb@FreeBSD.org>
8*11e8ecddSJessica Hamilton *
9*11e8ecddSJessica Hamilton * Redistribution and use in source and binary forms, with or without
10*11e8ecddSJessica Hamilton * modification, are permitted provided that the following conditions
11*11e8ecddSJessica Hamilton * are met:
12*11e8ecddSJessica Hamilton * 1. Redistributions of source code must retain the above copyright
13*11e8ecddSJessica Hamilton *    notice, this list of conditions and the following disclaimer.
14*11e8ecddSJessica Hamilton * 2. Redistributions in binary form must reproduce the above copyright
15*11e8ecddSJessica Hamilton *    notice, this list of conditions and the following disclaimer in the
16*11e8ecddSJessica Hamilton *    documentation and/or other materials provided with the distribution.
17*11e8ecddSJessica Hamilton * 3. Neither the name of the author nor the names of any co-contributors
18*11e8ecddSJessica Hamilton *    may be used to endorse or promote products derived from this software
19*11e8ecddSJessica Hamilton *    without specific prior written permission.
20*11e8ecddSJessica Hamilton *
21*11e8ecddSJessica Hamilton * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22*11e8ecddSJessica Hamilton * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23*11e8ecddSJessica Hamilton * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24*11e8ecddSJessica Hamilton * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
25*11e8ecddSJessica Hamilton * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26*11e8ecddSJessica Hamilton * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27*11e8ecddSJessica Hamilton * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28*11e8ecddSJessica Hamilton * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29*11e8ecddSJessica Hamilton * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30*11e8ecddSJessica Hamilton * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31*11e8ecddSJessica Hamilton * SUCH DAMAGE.
32*11e8ecddSJessica Hamilton *
33*11e8ecddSJessica Hamilton *
34*11e8ecddSJessica Hamilton * Partly from:
35*11e8ecddSJessica Hamilton * $FreeBSD: src/sys/boot/i386/mbr/mbr.s,v 1.7 2004/08/28 08:39:35 yar Exp $
36*11e8ecddSJessica Hamilton *
37*11e8ecddSJessica Hamilton * Copyright (c) 1999 Robert Nordier
38*11e8ecddSJessica Hamilton * All rights reserved.
39*11e8ecddSJessica Hamilton *
40*11e8ecddSJessica Hamilton * Redistribution and use in source and binary forms are freely
41*11e8ecddSJessica Hamilton * permitted provided that the above copyright notice and this
42*11e8ecddSJessica Hamilton * paragraph and the following disclaimer are duplicated in all
43*11e8ecddSJessica Hamilton * such forms.
44*11e8ecddSJessica Hamilton *
45*11e8ecddSJessica Hamilton * This software is provided "AS IS" and without any express or
46*11e8ecddSJessica Hamilton * implied warranties, including, without limitation, the implied
47*11e8ecddSJessica Hamilton * warranties of merchantability and fitness for a particular
48*11e8ecddSJessica Hamilton * purpose.
49*11e8ecddSJessica Hamilton *
50*11e8ecddSJessica Hamilton *
51*11e8ecddSJessica Hamilton * "Hybridisation" and modifications for booting Haiku by Andre' Braga
52*11e8ecddSJessica Hamilton * (me@andrebraga.com), with valuable input from Jean-Loïc Charroud
53*11e8ecddSJessica Hamilton * (jcharroud@free.fr). The modifications contained herein are released into
54*11e8ecddSJessica Hamilton * the Public Domain.
55*11e8ecddSJessica Hamilton *
56*11e8ecddSJessica Hamilton *
57*11e8ecddSJessica Hamilton * 		A 432 bytes MBR IPL (Initial Program Loader) that looks for the UUID of
58*11e8ecddSJessica Hamilton * a Haiku Boot GUID partition and boots it, falling back to MBR partitions if
59*11e8ecddSJessica Hamilton * said UUID isn't found or if the (primary) GPT is corrupted or non-existent.
60*11e8ecddSJessica Hamilton * 		Its usefulness is in being a versatile, "universal" IPL that supports
61*11e8ecddSJessica Hamilton * both partitioning styles, allowing it to be used transparently and even
62*11e8ecddSJessica Hamilton * facilitating the conversion between partitioning styles, should the need
63*11e8ecddSJessica Hamilton * for more partitions or volumes over 2TiB arise (for instance when cloning
64*11e8ecddSJessica Hamilton * an older disk to a newer, more capacious one).
65*11e8ecddSJessica Hamilton * 		It also paves the way for Haiku to create and support booting from
66*11e8ecddSJessica Hamilton * multiple volumes larger than 2TiB, which we're in the very privileged
67*11e8ecddSJessica Hamilton * position of enjoying efficiently in the near future due to BFS. Another use
68*11e8ecddSJessica Hamilton * case is taking a disk from a Intel EFI machine, plugging it on a BIOS
69*11e8ecddSJessica Hamilton * machine and boot just fine; and vice-versa.
70*11e8ecddSJessica Hamilton * 		As mentioned, if there are valid partitions defined in the MBR, and the
71*11e8ecddSJessica Hamilton * primary GPT becomes corrupt, it can fall back to loading the MBR partition
72*11e8ecddSJessica Hamilton * with the active flag set, if one is defined.
73*11e8ecddSJessica Hamilton * 		Currently there's no provision for falling back to the GPT copy that
74*11e8ecddSJessica Hamilton * lives in the end of the disk, due to the 512 bytes constraint; supporting
75*11e8ecddSJessica Hamilton * this is unlikely given that the code is packed tight. An alternative would be
76*11e8ecddSJessica Hamilton * disabling support for booting from MBR using BIOS calls other than Int13h
77*11e8ecddSJessica Hamilton * function 42h, "Extended Read From Disk" (i.e., LBA mode). It's unlikely that
78*11e8ecddSJessica Hamilton * any machine that Haiku supports won't have this BIOS function, but having an
79*11e8ecddSJessica Hamilton * "universal" IPL should be quite useful to, say, people using Haiku to
80*11e8ecddSJessica Hamilton * rewrite a corrupt MBR on another disk using the excellent DiskProbe.
81*11e8ecddSJessica Hamilton * 		The number of sectors loaded depends on the boot style. Booting from a
82*11e8ecddSJessica Hamilton * MBR partition assumes that the Partition Boot Record is one sector long,
83*11e8ecddSJessica Hamilton * whereas booting from a GPT partition assumes a partition exclusive for a
84*11e8ecddSJessica Hamilton * system loader and will either copy its entirety into memory starting from
85*11e8ecddSJessica Hamilton * address 0x7c00, or will copy up to circa 545KiB, whichever is smaller. Thus,
86*11e8ecddSJessica Hamilton * it remains compatible with the FreeBSD gptloader and should work for loading
87*11e8ecddSJessica Hamilton * Bootman from an exclusive Haiku boot manager partition as well.
88*11e8ecddSJessica Hamilton * 		It should be easy to adjust the UUID signature as needed. It lives at
89*11e8ecddSJessica Hamilton * offset 0x1a0 (416), leaving plenty of space before the 32-bit disk signature
90*11e8ecddSJessica Hamilton * at offset 0x1b8 (440), so compatibility with Microsoft Windows and other OSs
91*11e8ecddSJessica Hamilton * is maintained.
92*11e8ecddSJessica Hamilton */
93*11e8ecddSJessica Hamilton
94*11e8ecddSJessica Hamilton			.set LOAD,0x7c00
95*11e8ecddSJessica Hamilton			.set EXEC,0x600
96*11e8ecddSJessica Hamilton			.set MAGIC,0xaa55
97*11e8ecddSJessica Hamilton			.set HANDSHAKE,0x55aa
98*11e8ecddSJessica Hamilton			.set SECSIZE,0x200
99*11e8ecddSJessica Hamilton
100*11e8ecddSJessica Hamilton			/* data offsets */
101*11e8ecddSJessica Hamilton			.set UUID,0x1a0
102*11e8ecddSJessica Hamilton			.set DISKSIG,0x1b8
103*11e8ecddSJessica Hamilton			.set PT_OFF,0x1be
104*11e8ecddSJessica Hamilton
105*11e8ecddSJessica Hamilton			.set GPTSTACK,EXEC+SECSIZE*4-8	/* Stack address */
106*11e8ecddSJessica Hamilton			.set LBABUF,GPTSTACK			/* LBA address pointer buffer, */
107*11e8ecddSJessica Hamilton											/*  8 bytes long, after stack */
108*11e8ecddSJessica Hamilton
109*11e8ecddSJessica Hamilton			.set GPT_ADDR,LBABUF+8			/* GPT header address */
110*11e8ecddSJessica Hamilton			.set GPT_SIG,0					/* Signature offset from LBA 1 */
111*11e8ecddSJessica Hamilton			.set GPT_SIG_0,0x20494645		/* "EFI ", bswapped */
112*11e8ecddSJessica Hamilton			.set GPT_SIG_1,0x54524150		/* "PART", bswapped */
113*11e8ecddSJessica Hamilton			.set GPT_MYLBA,24				/* Offs of curr header copy addr */
114*11e8ecddSJessica Hamilton			.set GPT_PART_LBA,72			/* Offs of partitions start LBA */
115*11e8ecddSJessica Hamilton			.set GPT_NPART,80				/* Offs to number of partitions */
116*11e8ecddSJessica Hamilton			.set GPT_PART_SIZE,84			/* Offs to size of partition */
117*11e8ecddSJessica Hamilton			.set PART_ADDR,GPT_ADDR+SECSIZE	/* GPT partition array addr. */
118*11e8ecddSJessica Hamilton			.set PART_TYPE,0
119*11e8ecddSJessica Hamilton			.set PART_START_LBA,32			/* Offs to 1st LBA on part entry */
120*11e8ecddSJessica Hamilton			.set PART_END_LBA,40			/* Offs to last LBA */
121*11e8ecddSJessica Hamilton
122*11e8ecddSJessica Hamilton			.set NHRDRV,0x475				/* Number of hard drives */
123*11e8ecddSJessica Hamilton
124*11e8ecddSJessica Hamilton			.globl start					/* Entry point */
125*11e8ecddSJessica Hamilton			.code16
126*11e8ecddSJessica Hamilton
127*11e8ecddSJessica Hamilton/*
128*11e8ecddSJessica Hamilton * Setup the segment registers for flat addressing and setup the stack.
129*11e8ecddSJessica Hamilton */
130*11e8ecddSJessica Hamiltonstart:		cli								/* Clear interrupts before relocation */
131*11e8ecddSJessica Hamilton
132*11e8ecddSJessica Hamilton			xorw %ax,%ax					/* Zero */
133*11e8ecddSJessica Hamilton			movw %ax,%es					/* Address */
134*11e8ecddSJessica Hamilton			movw %ax,%ds					/*  data */
135*11e8ecddSJessica Hamilton
136*11e8ecddSJessica Hamilton			movw %ax,%ss					/* Set up */
137*11e8ecddSJessica Hamilton			movw $GPTSTACK,%sp				/*  stack */
138*11e8ecddSJessica Hamilton
139*11e8ecddSJessica Hamilton			std								/* String ops set to decrement */
140*11e8ecddSJessica Hamilton			movw $LOAD,%si					/* We'll clear working memory starting */
141*11e8ecddSJessica Hamilton			leaw -1(%si),%di				/*  from $LOAD-1 and stopping at EXEC. */
142*11e8ecddSJessica Hamilton			movw $(LOAD-EXEC-1),%cx			/*  In the end we have %si pointing */
143*11e8ecddSJessica Hamilton			rep stosb						/*  at LOAD and %di at EXEC. */
144*11e8ecddSJessica Hamilton
145*11e8ecddSJessica Hamilton
146*11e8ecddSJessica Hamilton/*
147*11e8ecddSJessica Hamilton * Relocate ourself to a lower address so that we have more room to load
148*11e8ecddSJessica Hamilton * other sectors.
149*11e8ecddSJessica Hamilton */
150*11e8ecddSJessica Hamiltonreloc:		cld								/* String ops set to increment */
151*11e8ecddSJessica Hamilton			movw $SECSIZE,%cx				/* Now we walk forward and relocate. */
152*11e8ecddSJessica Hamilton			rep	movsb						/*  Tricky, but works great! */
153*11e8ecddSJessica Hamilton
154*11e8ecddSJessica Hamilton/*
155*11e8ecddSJessica Hamilton * Jump to the relocated code.
156*11e8ecddSJessica Hamilton */
157*11e8ecddSJessica Hamilton			jmp $0,$main					/* Absolute address (far) jump */
158*11e8ecddSJessica Hamilton
159*11e8ecddSJessica Hamilton/*
160*11e8ecddSJessica Hamilton * Will land here; we're now at %cs = 0x0000 and %ip a little above 0x0600
161*11e8ecddSJessica Hamilton */
162*11e8ecddSJessica Hamiltonmain:		sti								/* Re-enable interrupts */
163*11e8ecddSJessica Hamilton
164*11e8ecddSJessica Hamilton#ifdef VALIDATE_DRV
165*11e8ecddSJessica Hamilton/*
166*11e8ecddSJessica Hamilton * Validate drive number in %dl. Certain BIOSes might not like it.
167*11e8ecddSJessica Hamilton */
168*11e8ecddSJessica Hamiltonvalidate_drv:
169*11e8ecddSJessica Hamilton			cmpb $0x80,%dl					/* Drive valid? (>= 0x80) */
170*11e8ecddSJessica Hamilton			jb validate_drv.1				/* No */
171*11e8ecddSJessica Hamilton			movb NHRDRV,%dh					/* Calculate the highest */
172*11e8ecddSJessica Hamilton			addb $0x80,%dh					/*  drive number available */
173*11e8ecddSJessica Hamilton			cmpb %dh,%dl					/* Within range? */
174*11e8ecddSJessica Hamilton			jb test_extensions				/* Yes, proceed */
175*11e8ecddSJessica Hamiltonvalidate_drv.1:
176*11e8ecddSJessica Hamilton			movb $0x80,%dl					/* Else, assume drive 0x80 */
177*11e8ecddSJessica Hamilton#endif
178*11e8ecddSJessica Hamilton
179*11e8ecddSJessica Hamilton/*
180*11e8ecddSJessica Hamilton * Test if BIOS supports Int13h extensions. If so, will try GPT scheme first.
181*11e8ecddSJessica Hamilton * Else, sets flag (%dh = 1) and goes straight to MBR code.
182*11e8ecddSJessica Hamilton * (%dl still contains the drive number from BIOS bootstrap)
183*11e8ecddSJessica Hamilton */
184*11e8ecddSJessica Hamiltontest_extensions:
185*11e8ecddSJessica Hamilton			movb $0,%dh						/* We'll test for EDD extensions. */
186*11e8ecddSJessica Hamilton											/*  LBA read (Int13,42) uses only */
187*11e8ecddSJessica Hamilton											/*  %dl to get drive number and if */
188*11e8ecddSJessica Hamilton											/*  we must fall back to CHS read */
189*11e8ecddSJessica Hamilton											/*  (Int13,02), %dh receives head */
190*11e8ecddSJessica Hamilton											/*  number, so it's clear to use */
191*11e8ecddSJessica Hamilton											/*  %dh to hold a "use CHS" flag */
192*11e8ecddSJessica Hamilton
193*11e8ecddSJessica Hamilton			movw $HANDSHAKE,%bx				/* EDD extensions magic number */
194*11e8ecddSJessica Hamilton			movb $0x41,%ah					/* BIOS:	EDD extensions */
195*11e8ecddSJessica Hamilton			int $0x13						/*  present? */
196*11e8ecddSJessica Hamilton			jc set_chs						/* No, fall back to CHS read */
197*11e8ecddSJessica Hamiltontest_magic:
198*11e8ecddSJessica Hamilton			cmpw $MAGIC,%bx					/* Magic ok? */
199*11e8ecddSJessica Hamilton			jne set_chs						/* No, fall back to CHS read */
200*11e8ecddSJessica Hamiltontest_packet:
201*11e8ecddSJessica Hamilton			testb $0x1,%cl					/* Packet mode present? */
202*11e8ecddSJessica Hamilton			jnz load_gpt_hdr				/* Yes! */
203*11e8ecddSJessica Hamiltonset_chs:
204*11e8ecddSJessica Hamilton			movb $1,%dh						/* read_chs overwrites this, and */
205*11e8ecddSJessica Hamilton											/*  Int13,42 only uses %dl, so */
206*11e8ecddSJessica Hamilton											/*  it's clear to use %dh as flag */
207*11e8ecddSJessica Hamilton			jmp try_mbr
208*11e8ecddSJessica Hamilton
209*11e8ecddSJessica Hamilton
210*11e8ecddSJessica Hamilton/*
211*11e8ecddSJessica Hamilton * If we reached here, drive is valid, LBA reads are available, will try GPT.
212*11e8ecddSJessica Hamilton * Load the primary GPT header from LBA 1 and verify signature.
213*11e8ecddSJessica Hamilton */
214*11e8ecddSJessica Hamiltonload_gpt_hdr:
215*11e8ecddSJessica Hamilton			movw $GPT_ADDR,%bx
216*11e8ecddSJessica Hamilton			movw $LBABUF,%si				/* Will load LBA sector 1 from disk */
217*11e8ecddSJessica Hamilton			movb $1,(%si)					/*  (64-bit value! Memory was zeroed so */
218*11e8ecddSJessica Hamilton											/*  it's OK to write only the LSB) */
219*11e8ecddSJessica Hamilton			call read
220*11e8ecddSJessica Hamilton			cmpl $GPT_SIG_0,GPT_ADDR+GPT_SIG
221*11e8ecddSJessica Hamilton			jnz try_mbr						/* If invalid GPT header */
222*11e8ecddSJessica Hamilton			cmpl $GPT_SIG_1,GPT_ADDR+GPT_SIG+4
223*11e8ecddSJessica Hamilton			jnz try_mbr						/* Fluke :( Try MBR now */
224*11e8ecddSJessica Hamilton
225*11e8ecddSJessica Hamilton/*
226*11e8ecddSJessica Hamilton * GPT is valid. Load a partition table sector from disk and look for a
227*11e8ecddSJessica Hamilton * partition matching the UUID found in boot_uuid.
228*11e8ecddSJessica Hamilton */
229*11e8ecddSJessica Hamiltonload_part:
230*11e8ecddSJessica Hamilton			movw $GPT_ADDR+GPT_PART_LBA,%si
231*11e8ecddSJessica Hamilton			movw $PART_ADDR,%bx
232*11e8ecddSJessica Hamilton			call read
233*11e8ecddSJessica Hamiltonscan:
234*11e8ecddSJessica Hamilton			movw %bx,%si					/* Compare partition UUID */
235*11e8ecddSJessica Hamilton			movw $boot_uuid,%di				/*  with Haiku boot UUID */
236*11e8ecddSJessica Hamilton			movb $0x10,%cl					/*  (16 bytes) */
237*11e8ecddSJessica Hamilton			repe cmpsb
238*11e8ecddSJessica Hamilton			jnz next_part					/* Didn't match, next partition */
239*11e8ecddSJessica Hamilton
240*11e8ecddSJessica Hamilton/*
241*11e8ecddSJessica Hamilton * We found a partition. Load it into RAM starting at 0x7c00.
242*11e8ecddSJessica Hamilton */
243*11e8ecddSJessica Hamilton			movw %bx,%di					/* Save partition pointer in %di */
244*11e8ecddSJessica Hamilton			leaw PART_START_LBA(%di),%si
245*11e8ecddSJessica Hamilton			movw $LOAD/16,%bx
246*11e8ecddSJessica Hamilton			movw %bx,%es
247*11e8ecddSJessica Hamilton			xorw %bx,%bx
248*11e8ecddSJessica Hamiltonload_bootcode:
249*11e8ecddSJessica Hamilton			push %si						/* Save %si */
250*11e8ecddSJessica Hamilton			call read
251*11e8ecddSJessica Hamilton			pop %si							/* Restore */
252*11e8ecddSJessica Hamilton			movl PART_END_LBA(%di),%eax		/* See if this was the last LBA */
253*11e8ecddSJessica Hamilton			cmpl (%si),%eax
254*11e8ecddSJessica Hamilton			jnz next_boot_lba
255*11e8ecddSJessica Hamilton			movl PART_END_LBA+4(%di),%eax
256*11e8ecddSJessica Hamilton			cmpl 4(%si),%eax
257*11e8ecddSJessica Hamilton			jnz next_boot_lba
258*11e8ecddSJessica Hamilton			jmp start_loader				/* Jump to boot code */
259*11e8ecddSJessica Hamilton
260*11e8ecddSJessica Hamiltonnext_boot_lba:
261*11e8ecddSJessica Hamilton			incl (%si)						/* Next LBA */
262*11e8ecddSJessica Hamilton			adcl $0,4(%si)
263*11e8ecddSJessica Hamilton			mov %es,%ax						/* Adjust segment for next */
264*11e8ecddSJessica Hamilton			addw $SECSIZE/16,%ax			/*  sector */
265*11e8ecddSJessica Hamilton			cmp $0x9000,%ax					/* Don't load past 0x90000, */
266*11e8ecddSJessica Hamilton			jae start_loader				/*  545k should be enough for */
267*11e8ecddSJessica Hamilton			mov %ax,%es						/*  any boot code. :) */
268*11e8ecddSJessica Hamilton			jmp load_bootcode
269*11e8ecddSJessica Hamilton
270*11e8ecddSJessica Hamilton/*
271*11e8ecddSJessica Hamilton * Move to the next partition. If we walk off the end of the sector, load
272*11e8ecddSJessica Hamilton * the next sector.
273*11e8ecddSJessica Hamilton */
274*11e8ecddSJessica Hamiltonnext_part:
275*11e8ecddSJessica Hamilton			decl GPT_ADDR+GPT_NPART			/* Was this the last partition? */
276*11e8ecddSJessica Hamilton			jz try_mbr						/* UUID boot signature not found */
277*11e8ecddSJessica Hamilton			movw GPT_ADDR+GPT_PART_SIZE,%ax
278*11e8ecddSJessica Hamilton			addw %ax,%bx					/* Next partition */
279*11e8ecddSJessica Hamilton			cmpw $PART_ADDR+0x200,%bx		/* Still in sector? */
280*11e8ecddSJessica Hamilton			jb scan
281*11e8ecddSJessica Hamilton			incl GPT_ADDR+GPT_PART_LBA		/* Next sector */
282*11e8ecddSJessica Hamilton			adcl $0,GPT_ADDR+GPT_PART_LBA+4
283*11e8ecddSJessica Hamilton			jmp load_part
284*11e8ecddSJessica Hamilton
285*11e8ecddSJessica Hamilton/*
286*11e8ecddSJessica Hamilton * If loading boot sectors from a GPT partition fails, try booting a MBR part.
287*11e8ecddSJessica Hamilton * Reset stack/segment. Could have been tainted by the GPT loading code.
288*11e8ecddSJessica Hamilton */
289*11e8ecddSJessica Hamiltontry_mbr:
290*11e8ecddSJessica Hamilton			xorw %ax,%ax					/* Zero */
291*11e8ecddSJessica Hamilton			movw %ax,%es					/*  extra segment */
292*11e8ecddSJessica Hamilton			movw $LOAD,%sp					/* Reset stack */
293*11e8ecddSJessica Hamilton
294*11e8ecddSJessica Hamilton			xorw %si,%si					/* Will point to active partition */
295*11e8ecddSJessica Hamilton			movw $(EXEC+PT_OFF),%bx			/* Point to partition table start */
296*11e8ecddSJessica Hamilton			movw $0x4,%cx					/* Tested entries counter (4 total) */
297*11e8ecddSJessica Hamiltonread_mbr_entry:
298*11e8ecddSJessica Hamilton			cmpb %ch,(%bx)					/* Null entry? (%ch just zeroed) */
299*11e8ecddSJessica Hamilton			je next_mbr_entry				/* Yes */
300*11e8ecddSJessica Hamilton			jg err_part_table				/* If 0x1..0x7f */
301*11e8ecddSJessica Hamilton			testw %si,%si					/* Active already found? */
302*11e8ecddSJessica Hamilton			jnz err_part_table				/* Yes */
303*11e8ecddSJessica Hamilton			movw %bx,%si					/* Point to active */
304*11e8ecddSJessica Hamiltonnext_mbr_entry:
305*11e8ecddSJessica Hamilton			addb $0x10,%bl					/* Till */
306*11e8ecddSJessica Hamilton			loop read_mbr_entry				/*  done */
307*11e8ecddSJessica Hamilton			testw %si,%si					/* Active found? */
308*11e8ecddSJessica Hamilton			jnz read_bootsect				/* Yes, read OS loader */
309*11e8ecddSJessica Hamiltontry_diskless:
310*11e8ecddSJessica Hamilton			int $0x18						/* Else, BIOS: Diskless boot */
311*11e8ecddSJessica Hamilton
312*11e8ecddSJessica Hamilton
313*11e8ecddSJessica Hamilton/*
314*11e8ecddSJessica Hamilton * Ok, now that we have a valid drive and partition entry, load either CHS
315*11e8ecddSJessica Hamilton * or LBA from the partition entry and read the boot sector from the partition.
316*11e8ecddSJessica Hamilton */
317*11e8ecddSJessica Hamiltonread_bootsect:
318*11e8ecddSJessica Hamilton			movw %sp,%bx					/* Write addr. (%sp points to LOAD) */
319*11e8ecddSJessica Hamilton			pushw %si						/* Points at active part. entry; */
320*11e8ecddSJessica Hamilton											/*  save, else 'read' will trash it */
321*11e8ecddSJessica Hamiltontest_flag:
322*11e8ecddSJessica Hamilton			cmpb $1,%dh						/* Test flag set by set_chs above */
323*11e8ecddSJessica Hamilton			jz read_chs						/* CHS read if set */
324*11e8ecddSJessica Hamiltonread_lba:
325*11e8ecddSJessica Hamilton			addw $0x8,%si					/* Start LBA of partition, 32-bit */
326*11e8ecddSJessica Hamilton			movw $LBABUF,%di				/* So far either QWORD 1 or 0, so */
327*11e8ecddSJessica Hamilton			movsl							/*  more significant bytes are all 0 */
328*11e8ecddSJessica Hamilton			xchg %di,%si					/*  Copy to buffer and swap pointers */
329*11e8ecddSJessica Hamilton			subw $0x4,%si					/* Adjust back to start of buffer */
330*11e8ecddSJessica Hamilton			call read
331*11e8ecddSJessica Hamilton			jmp finished_read				/* Skip the CHS setup */
332*11e8ecddSJessica Hamiltonread_chs:
333*11e8ecddSJessica Hamilton			movb 0x1(%si),%dh				/* Load head */
334*11e8ecddSJessica Hamilton			movw 0x2(%si),%cx				/* Load cylinder:sector */
335*11e8ecddSJessica Hamilton			movb $2,%al						/* Read two sectors */
336*11e8ecddSJessica Hamilton			movb $2,%ah						/* BIOS: Read sectors from disk */
337*11e8ecddSJessica Hamilton			int $0x13						/* Call the BIOS */
338*11e8ecddSJessica Hamiltonfinished_read:
339*11e8ecddSJessica Hamilton			jc err_reading					/* If error */
340*11e8ecddSJessica Hamilton
341*11e8ecddSJessica Hamilton
342*11e8ecddSJessica Hamilton/*
343*11e8ecddSJessica Hamilton * Now that we've loaded the bootstrap, check for the 0xaa55 signature. If it
344*11e8ecddSJessica Hamilton * is present, execute the bootstrap we just loaded.
345*11e8ecddSJessica Hamilton */
346*11e8ecddSJessica Hamilton			popw %si						/* Restore %si (active part entry) */
347*11e8ecddSJessica Hamilton			movb %dl,(%si)					/* Patch part record with drive num */
348*11e8ecddSJessica Hamilton			cmpw $MAGIC,0x1fe(%bx)			/* Bootable? */
349*11e8ecddSJessica Hamilton			jne err_noboot					/* No, error out. */
350*11e8ecddSJessica Hamilton											/*  Else, start loader */
351*11e8ecddSJessica Hamiltonstart_loader:
352*11e8ecddSJessica Hamilton			xorw %ax,%ax
353*11e8ecddSJessica Hamilton			movw %ax,%es					/* Reset %es to zero */
354*11e8ecddSJessica Hamilton			jmp $0,$LOAD					/* Jump to boot code */
355*11e8ecddSJessica Hamilton
356*11e8ecddSJessica Hamilton
357*11e8ecddSJessica Hamilton/* Auxiliary functions */
358*11e8ecddSJessica Hamilton
359*11e8ecddSJessica Hamilton
360*11e8ecddSJessica Hamilton/*
361*11e8ecddSJessica Hamilton * Load a sector (64-bit LBA at %si) from disk %dl into %es:%bx by creating
362*11e8ecddSJessica Hamilton * a EDD packet on the stack and passing it to the BIOS. Trashes %ax and %si.
363*11e8ecddSJessica Hamilton */
364*11e8ecddSJessica Hamiltonread:
365*11e8ecddSJessica Hamilton			pushl 0x4(%si)					/* Set the LBA */
366*11e8ecddSJessica Hamilton			pushl 0x0(%si)					/*  address */
367*11e8ecddSJessica Hamilton			pushw %es						/* Set the address of */
368*11e8ecddSJessica Hamilton			pushw %bx						/*  the transfer buffer */
369*11e8ecddSJessica Hamilton			pushw $0x1						/* Read 1 sector */
370*11e8ecddSJessica Hamilton			pushw $0x10						/* Packet length */
371*11e8ecddSJessica Hamilton			movw %sp,%si					/* Packet pointer */
372*11e8ecddSJessica Hamilton			movw $0x4200,%ax				/* BIOS:	LBA Read from disk */
373*11e8ecddSJessica Hamilton			int $0x13						/* Call the BIOS */
374*11e8ecddSJessica Hamilton			add $0x10,%sp					/* Restore stack */
375*11e8ecddSJessica Hamilton			jc err_reading					/* If error */
376*11e8ecddSJessica Hamilton			ret
377*11e8ecddSJessica Hamilton
378*11e8ecddSJessica Hamilton
379*11e8ecddSJessica Hamilton/*
380*11e8ecddSJessica Hamilton * Output an ASCIZ string pointed at by %si to the console via the BIOS.
381*11e8ecddSJessica Hamilton */
382*11e8ecddSJessica Hamiltonputstr.0:
383*11e8ecddSJessica Hamilton			movw $0x7,%bx					/* Page:attribute */
384*11e8ecddSJessica Hamilton			movb $0xe,%ah					/* BIOS: Display */
385*11e8ecddSJessica Hamilton			int $0x10						/*  character */
386*11e8ecddSJessica Hamiltonputstr:
387*11e8ecddSJessica Hamilton			lodsb							/* Get character */
388*11e8ecddSJessica Hamilton			testb %al,%al					/* End of string? */
389*11e8ecddSJessica Hamilton			jnz putstr.0					/* No */
390*11e8ecddSJessica Hamilton			ret
391*11e8ecddSJessica Hamilton
392*11e8ecddSJessica Hamilton
393*11e8ecddSJessica Hamilton/*
394*11e8ecddSJessica Hamilton * Various error message entry points.
395*11e8ecddSJessica Hamilton */
396*11e8ecddSJessica Hamiltonerr_part_table:
397*11e8ecddSJessica Hamilton			movw $msg_badtable,%si			/* "Bad Part. Table!" */
398*11e8ecddSJessica Hamilton			call putstr
399*11e8ecddSJessica Hamilton			jmp halt
400*11e8ecddSJessica Hamilton
401*11e8ecddSJessica Hamilton
402*11e8ecddSJessica Hamiltonerr_reading:
403*11e8ecddSJessica Hamilton			movw $msg_ioerror,%si			/* "Read Error!" */
404*11e8ecddSJessica Hamilton			call putstr
405*11e8ecddSJessica Hamilton			jmp halt
406*11e8ecddSJessica Hamilton
407*11e8ecddSJessica Hamilton
408*11e8ecddSJessica Hamiltonerr_noboot:
409*11e8ecddSJessica Hamilton			movw $msg_noloader,%si			/* "No Sys Loader!" */
410*11e8ecddSJessica Hamilton			call putstr
411*11e8ecddSJessica Hamilton			/* fall-through to halt */
412*11e8ecddSJessica Hamilton
413*11e8ecddSJessica Hamilton
414*11e8ecddSJessica Hamiltonhalt:
415*11e8ecddSJessica Hamilton			cli
416*11e8ecddSJessica Hamilton			hlt
417*11e8ecddSJessica Hamilton			jmp halt
418*11e8ecddSJessica Hamilton
419*11e8ecddSJessica Hamilton
420*11e8ecddSJessica Hamilton/* Data section */
421*11e8ecddSJessica Hamilton
422*11e8ecddSJessica Hamilton
423*11e8ecddSJessica Hamilton#ifdef VALIDATE_DRV
424*11e8ecddSJessica Hamilton/* Messages must be shortened so the code fits 440 bytes */
425*11e8ecddSJessica Hamiltonmsg_badtable:	.asciz "BadPTbl!"
426*11e8ecddSJessica Hamiltonmsg_ioerror:	.asciz "IOErr!"
427*11e8ecddSJessica Hamiltonmsg_noloader:	.asciz "NoSysLdr!"
428*11e8ecddSJessica Hamilton#else
429*11e8ecddSJessica Hamiltonmsg_badtable:	.asciz "Bad Part. Table!"
430*11e8ecddSJessica Hamiltonmsg_ioerror:	.asciz "Read Error!"
431*11e8ecddSJessica Hamiltonmsg_noloader:	.asciz "No Sys Loader!"
432*11e8ecddSJessica Hamilton#endif
433*11e8ecddSJessica Hamilton
434*11e8ecddSJessica Hamilton/* Boot partition UUID signature */
435*11e8ecddSJessica Hamilton			.org UUID,0x0					/* Zero-pad up to UUID offset */
436*11e8ecddSJessica Hamilton
437*11e8ecddSJessica Hamiltonboot_uuid:
438*11e8ecddSJessica Hamilton			.long 0x42465331				/* 'BFS1' (formally, UUID time-low) */
439*11e8ecddSJessica Hamilton			.word 0x3ba3					/* UUID time-mid */
440*11e8ecddSJessica Hamilton			.word 0x10f1					/* UUID time-high & version (v1) */
441*11e8ecddSJessica Hamilton			.byte 0x80						/* UUID DCE 1.1 variant */
442*11e8ecddSJessica Hamilton			.byte 0x2a						/* '*' (formally, UUID clock-seq-low) */
443*11e8ecddSJessica Hamilton			.byte 0x48						/* 'H' */
444*11e8ecddSJessica Hamilton			.byte 0x61						/* 'a' */
445*11e8ecddSJessica Hamilton			.byte 0x69						/* 'i' */
446*11e8ecddSJessica Hamilton			.byte 0x6b						/* 'k' */
447*11e8ecddSJessica Hamilton			.byte 0x75						/* 'u' */
448*11e8ecddSJessica Hamilton			.byte 0x21						/* '!' */
449*11e8ecddSJessica Hamilton
450*11e8ecddSJessica Hamilton#ifndef MBR_CODE_ONLY
451*11e8ecddSJessica Hamilton/* Disk signature */
452*11e8ecddSJessica Hamilton			.org DISKSIG,0x0				/* Zero-pad up to signature offset */
453*11e8ecddSJessica Hamilton
454*11e8ecddSJessica Hamiltonsig:
455*11e8ecddSJessica Hamilton			.long 0							/* OS Disk Signature */
456*11e8ecddSJessica Hamilton			.word 0							/* "Unknown" in PMBR */
457*11e8ecddSJessica Hamilton
458*11e8ecddSJessica Hamilton/* Partition table */
459*11e8ecddSJessica Hamilton			.org PT_OFF,0x0					/* Won't pad, just documenting */
460*11e8ecddSJessica Hamilton
461*11e8ecddSJessica Hamiltonpartbl:
462*11e8ecddSJessica Hamilton			.fill 0x10,0x4,0x0				/* Partition table */
463*11e8ecddSJessica Hamilton			.word MAGIC						/* Magic number */
464*11e8ecddSJessica Hamilton#endif
465