xref: /openbsd/sys/arch/amd64/stand/mbr/mbr.S (revision 4ed81583)
1*4ed81583Skrw/*	$OpenBSD: mbr.S,v 1.9 2022/09/02 07:46:03 krw Exp $	*/
2a47f7207Smickey
3a47f7207Smickey/*
4a47f7207Smickey * Copyright (c) 1997 Michael Shalayeff and Tobias Weingartner
5a47f7207Smickey * Copyright (c) 2003 Tom Cosgrove <tom.cosgrove@arches-consulting.com>
6a47f7207Smickey * All rights reserved.
7a47f7207Smickey *
8a47f7207Smickey * Redistribution and use in source and binary forms, with or without
9a47f7207Smickey * modification, are permitted provided that the following conditions
10a47f7207Smickey * are met:
11a47f7207Smickey * 1. Redistributions of source code must retain the above copyright
12a47f7207Smickey *    notice, this list of conditions and the following disclaimer.
13a47f7207Smickey * 2. Redistributions in binary form must reproduce the above copyright
14a47f7207Smickey *    notice, this list of conditions and the following disclaimer in the
15a47f7207Smickey *    documentation and/or other materials provided with the distribution.
16a47f7207Smickey *
17a47f7207Smickey * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18a47f7207Smickey * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19a47f7207Smickey * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20a47f7207Smickey * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21a47f7207Smickey * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22a47f7207Smickey * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23a47f7207Smickey * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24a47f7207Smickey * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25a47f7207Smickey * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26a47f7207Smickey * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27a47f7207Smickey * SUCH DAMAGE.
28a47f7207Smickey *
29a47f7207Smickey */
30a47f7207Smickey/* Copyright (c) 1996 VaX#n8 (vax@linkdead.paranoia.com)
31a47f7207Smickey * last edited 9 July 1996
32a47f7207Smickey * many thanks to Erich Boleyn (erich@uruk.org) for putting up with
33a47f7207Smickey * all my questions, and for his work on GRUB
34a47f7207Smickey * You may use this code or fragments thereof in a manner consistent
35a47f7207Smickey * with the other copyrights as long as you retain my pseudonym and
36a47f7207Smickey * this copyright notice in the file.
37a47f7207Smickey */
38a47f7207Smickey
39a47f7207Smickey	.file	"mbr.S"
40a47f7207Smickey
41a47f7207Smickey#include <machine/asm.h>
42a47f7207Smickey#include <assym.h>
43a47f7207Smickey
44a47f7207Smickey/*
45a47f7207Smickey * Memory layout:
46a47f7207Smickey *
47a47f7207Smickey * 0x07C00 -> 0x07DFF	BIOS loads us here	(at  31k)
48a47f7207Smickey * 0x07E00 -> 0x17BFC	our stack		(to  95k)
49a47f7207Smickey *
50a47f7207Smickey * 0x07A00 -> 0x07BFF	we relocate to here	(at  30k5)
51a47f7207Smickey *
52a47f7207Smickey * 0x07C00 -> 0x07DFF	we load PBR here	(at  31k)
53a47f7207Smickey *
54a47f7207Smickey * The BIOS loads us at physical address 0x07C00.  We use a long jmp to
55a47f7207Smickey * normalise our address to seg:offset 07C0:0000.  We then relocate to
56a47f7207Smickey * 0x07A00, seg:offset 07A0:0000.
57a47f7207Smickey *
58a47f7207Smickey * We use a long jmp to normalise our address to seg:offset 07A0:0000
59a47f7207Smickey * We set the stack to start at 07C0:FFFC (grows down on i386)
609676a180Stom * The partition boot record (PBR) loads /boot at seg:offset 4000:0000
61a47f7207Smickey */
62a47f7207Smickey#define BOOTSEG		0x7c0	/* segment where we are loaded */
63a47f7207Smickey#define BOOTRELOCSEG	0x7a0	/* segment where we relocate to */
64a47f7207Smickey#define BOOTSTACKOFF	0xfffc	/* stack starts here, grows down */
65a47f7207Smickey#define PARTSZ		16	/* each partition table entry is 16 bytes */
66a47f7207Smickey
67a47f7207Smickey#define CHAR_LBA_READ	'.'
68a47f7207Smickey#define CHAR_CHS_READ	';'
69a47f7207Smickey
70a47f7207Smickey#ifdef DEBUG
71a47f7207Smickey#define CHAR_S		'S'	/* started */
72a47f7207Smickey#define CHAR_R		'R'	/* relocated */
73a47f7207Smickey#define CHAR_L		'L'	/* looking for bootable partition */
74a47f7207Smickey#define CHAR_B		'B'	/* loading boot */
75a47f7207Smickey#define CHAR_G		'G'	/* jumping to boot */
76a47f7207Smickey
77a47f7207Smickey#define DBGMSG(c)	movb	$c, %al;	call	Lchr
78a47f7207Smickey#else /* !DEBUG */
79a47f7207Smickey#define DBGMSG(c)
80a47f7207Smickey#endif /* !DEBUG */
81a47f7207Smickey
82a47f7207Smickey/* Clobbers %al - maybe more */
83a47f7207Smickey#define	putc(c)		movb	$c, %al;	call	Lchr
84a47f7207Smickey
85a47f7207Smickey/* Clobbers %esi - maybe more */
86a47f7207Smickey#define	puts(s)		movw	$s, %si;	call	Lmessage
87a47f7207Smickey
88a47f7207Smickey
89a47f7207Smickey	.text
90a47f7207Smickey	.code16
91a47f7207Smickey
92a47f7207Smickey	.globl	start
93a47f7207Smickeystart:
94a47f7207Smickey	/* Adjust %cs to be right */
95a47f7207Smickey	ljmp 	$BOOTSEG, $1f
96a47f7207Smickey1:
97a47f7207Smickey	/* Set up stack */
98a47f7207Smickey	movw	%cs, %ax
99a47f7207Smickey
100a47f7207Smickey	/*
101a47f7207Smickey	 * We don't need to disable and re-enable interrupts around the
102a47f7207Smickey	 * the load of ss and sp.
103a47f7207Smickey	 *
104a47f7207Smickey	 * From 80386 Programmer's Reference Manual:
105a47f7207Smickey	 * "A MOV into SS inhibits all interrupts until after the execution
106a47f7207Smickey	 * of the next instruction (which is presumably a MOV into eSP)"
107a47f7207Smickey	 *
108a47f7207Smickey	 * According to Hamarsoft's 86BUGS list (which is distributed with
109a47f7207Smickey	 * Ralph Brown's Interrupt List), some early 8086/88 processors
110a47f7207Smickey	 * failed to disable interrupts following a load into a segment
111a47f7207Smickey	 * register, but this was fixed with later steppings.
112a47f7207Smickey	 *
113a47f7207Smickey	 * Accordingly, this code will fail on very early 8086/88s, but
114a47f7207Smickey	 * nick@ will just have to live with it.  Others will note that
1152a1e2e55Sdaniel	 * we require at least a Pentium compatible processor anyway.
116a47f7207Smickey	 */
117a47f7207Smickey	/* cli */
118a47f7207Smickey	movw	%ax, %ss
119a47f7207Smickey	movw	$BOOTSTACKOFF, %sp
120a47f7207Smickey	/* sti */			/* XXX not necessary; see above */
121a47f7207Smickey
122a47f7207Smickey	/* Set up data segment */
123a47f7207Smickey	movw	%ax, %ds
124a47f7207Smickey	DBGMSG(CHAR_S)
125a47f7207Smickey
126a47f7207Smickey	/*
127a47f7207Smickey	 * On the PC architecture, the boot record (originally on a floppy
128a47f7207Smickey	 * disk) is loaded at 0000:7C00 (hex) and execution starts at the
129a47f7207Smickey	 * beginning.
130a47f7207Smickey	 *
131a47f7207Smickey	 * When hard disk support was added, a scheme to partition disks into
132a47f7207Smickey	 * four separate partitions was used, to allow multiple operating
133a47f7207Smickey	 * systems to be installed on the one disk.  The boot sectors of the
134a47f7207Smickey	 * operating systems on each partition would of course expect to be
135a47f7207Smickey	 * loaded at 0000:7C00.
136a47f7207Smickey	 *
137a47f7207Smickey	 * The first sector of the hard disk is the master boot record (MBR).
138a47f7207Smickey	 * It is this which defines the partitions and says which one is
139a47f7207Smickey	 * bootable.  Of course, the BIOS loads the MBR at 0000:7C00, the
140a47f7207Smickey	 * same location where the MBR needs to load the partition boot
141a47f7207Smickey	 * record (PBR, called biosboot in OpenBSD).
142a47f7207Smickey	 *
143a47f7207Smickey	 * Therefore, the MBR needs to relocate itself before loading the PBR.
144a47f7207Smickey	 *
145a47f7207Smickey	 * Make it so.
146a47f7207Smickey	 */
147a47f7207Smickey	movw	$BOOTRELOCSEG, %ax
148a47f7207Smickey	movw	%ax, %es
149a47f7207Smickey	xorw	%si, %si
150a47f7207Smickey	xorw	%di, %di
151a47f7207Smickey	movw	$0x200, %cx		/* Bytes in MBR, relocate it all */
152a47f7207Smickey	cld
153a47f7207Smickey	rep
154a47f7207Smickey	movsb
155a47f7207Smickey
156a47f7207Smickey	/* Jump to relocated self */
157a47f7207Smickey	ljmp $BOOTRELOCSEG, $reloc
158a47f7207Smickeyreloc:
159a47f7207Smickey	DBGMSG(CHAR_R)
160a47f7207Smickey
161a47f7207Smickey	/* Set up %es and %ds */
162a47f7207Smickey	pushw	%ds
163a47f7207Smickey	popw	%es	/* next boot is at the same place as we were loaded */
164a47f7207Smickey	pushw	%cs
165a47f7207Smickey	popw	%ds	/* and %ds is at the %cs */
166a47f7207Smickey
167a47f7207Smickey#ifdef SERIAL
168a47f7207Smickey	/* Initialize the serial port to 9600 baud, 8N1.
169a47f7207Smickey	 */
170bd4e04c6Smglocker	pushw	%dx
171a47f7207Smickey	xorw	%ax, %ax
172a47f7207Smickey	movb	$0xe3, %ax
173a47f7207Smickey	movw	$SERIAL, %dx
174a47f7207Smickey	int	$0x14
175bd4e04c6Smglocker	popw	%dx
176a47f7207Smickey#endif
177a47f7207Smickey
178a47f7207Smickey	/* BIOS passes us drive number in %dl
179a47f7207Smickey	 *
180a47f7207Smickey	 * XXX - This is not always true.  We currently check if %dl
181a47f7207Smickey	 * points to a HD, and if not we complain, and set it to point
182a47f7207Smickey	 * to the first HDD.  Note, this is not 100% correct, since
183ef9decb1Stom	 * there is a possibility that you boot from HD #2, and still
184a47f7207Smickey	 * get (%dl & 0x80) == 0x00, these type of systems will lose.
185a47f7207Smickey	 */
186a47f7207Smickey	testb	$0x80, %dl
187a47f7207Smickey	jnz	drive_ok
188a47f7207Smickey
189a47f7207Smickey	/* MBR on floppy or old BIOS
190a47f7207Smickey	 * Note: MBR (this code) should never be on a floppy.  It does
191a47f7207Smickey	 * not belong there, so %dl should never be 0x00.
192a47f7207Smickey	 *
193a47f7207Smickey	 * Here we simply complain (should we?), and then hardcode the
194a47f7207Smickey	 * boot drive to 0x80.
195a47f7207Smickey	 */
196a47f7207Smickey	puts(efdmbr)
197a47f7207Smickey
198a47f7207Smickey	/* If we are passed bogus data, set it to HD #1
199a47f7207Smickey	 */
200a47f7207Smickey	movb	$0x80, %dl
201a47f7207Smickey
202a47f7207Smickeydrive_ok:
203a47f7207Smickey	/* Find the first active partition.
204a47f7207Smickey	 * Note: this should be the only active partition.  We currently
205a47f7207Smickey	 * don't check for that.
206a47f7207Smickey	 */
207a47f7207Smickey	movw	$pt, %si
208a47f7207Smickey
209a47f7207Smickey	movw	$NDOSPART, %cx
210a47f7207Smickeyfind_active:
211a47f7207Smickey	DBGMSG(CHAR_L)
212a47f7207Smickey	movb	(%si), %al
213a47f7207Smickey
214a47f7207Smickey	cmpb	$DOSACTIVE, %al
215a47f7207Smickey	je	found
216a47f7207Smickey
217a47f7207Smickey	addw	$PARTSZ, %si
218a47f7207Smickey	loop	find_active
219a47f7207Smickey
220a47f7207Smickey	/* No bootable partition */
221a47f7207Smickeyno_part:
222a47f7207Smickey	movw	$enoboot, %si
223a47f7207Smickey
224a47f7207Smickeyerr_stop:
225a47f7207Smickey	call	Lmessage
226a47f7207Smickey
227a47f7207Smickeystay_stopped:
2289676a180Stom	sti				/* Ensure Ctl-Alt-Del will work */
229a47f7207Smickey	hlt
230a47f7207Smickey	/* Just to make sure */
231a47f7207Smickey	jmp	stay_stopped
232a47f7207Smickey
233a47f7207Smickeyfound:
234a47f7207Smickey	/*
235a47f7207Smickey	 * Found bootable partition
236a47f7207Smickey	 */
237a47f7207Smickey
238a47f7207Smickey	DBGMSG(CHAR_B)
239a47f7207Smickey
240a47f7207Smickey	/* Store the drive number (from %dl) in decimal */
241a47f7207Smickey	movb	%dl, %al
242a47f7207Smickey	andb	$0x0F, %al
243a47f7207Smickey	addb	$'0', %al
244a47f7207Smickey	movb	%al, drive_num
245a47f7207Smickey
246a47f7207Smickey	/*
247a47f7207Smickey	 * Store the partition number, in decimal.
248a47f7207Smickey	 *
249a47f7207Smickey	 * We started with cx = 4; if found we want part '0'
250a47f7207Smickey	 *                 cx = 3;                  part '1'
251a47f7207Smickey	 *                 cx = 2;                  part '2'
252a47f7207Smickey	 *                 cx = 1;                  part '3'
253a47f7207Smickey	 *
254a47f7207Smickey	 * We'll come into this with no other values for cl.
255a47f7207Smickey	 */
256a47f7207Smickey	movb	$'0'+4, %al
257a47f7207Smickey	subb	%cl, %al
258a47f7207Smickey	movb	%al, part_num
259a47f7207Smickey
260a47f7207Smickey	/*
261a47f7207Smickey	 * Tell operator what partition we're trying to boot.
262a47f7207Smickey	 *
263a47f7207Smickey	 * Using drive X, partition Y
264a47f7207Smickey	 * - this used to be printed out after successfully loading the
265a47f7207Smickey	 *   partition boot record; we now print it out before
266a47f7207Smickey	 */
267a47f7207Smickey	pushw	%si
268a47f7207Smickey	movw	$info, %si
269a47f7207Smickey	call	Lmessage
270a47f7207Smickey	popw	%si
271a47f7207Smickey
272a47f7207Smickey	/*
273a47f7207Smickey	 * Partition table entry format:
274a47f7207Smickey	 *
275a47f7207Smickey	 * 0x00	BYTE boot indicator (0x80 = active, 0x00 = inactive)
276a47f7207Smickey	 * 0x01	BYTE start head
277a47f7207Smickey	 * 0x02	WORD start cylinder, sector
278a47f7207Smickey	 * 0x04	BYTE system type (0xA6 = OpenBSD)
279a47f7207Smickey	 * 0x05 BYTE end head
280a47f7207Smickey	 * 0x06	WORD end cylinder, sector
281a47f7207Smickey	 * 0x08	LONG start LBA sector
282a47f7207Smickey	 * 0x0C	LONG number of sectors in partition
283a47f7207Smickey	 *
284a47f7207Smickey	 * In the case of a partition that extends beyond the 8GB boundary,
285a47f7207Smickey	 * the LBA values will be correct, the CHS values will have their
286a47f7207Smickey	 * maximums (typically (C,H,S) = (1023,255,63)).
287a47f7207Smickey	 *
288a47f7207Smickey	 * %ds:%si points to the active partition table entry.
289a47f7207Smickey	 */
290a47f7207Smickey
291a47f7207Smickey	/* We will load the partition boot sector (biosboot) where we
292a47f7207Smickey	 * were originally loaded.  We'll check to make sure something
293a47f7207Smickey	 * valid comes in.  So that we don't find ourselves, zero out
294a47f7207Smickey	 * the signature at the end.
295a47f7207Smickey	 */
296a47f7207Smickey	movw	$0, %es:signature(,1)
297a47f7207Smickey
298a47f7207Smickey	/*
299a47f7207Smickey	 * We will use the LBA sector number if we have LBA support,
300a47f7207Smickey	 * so find out.
301a47f7207Smickey	 */
302a47f7207Smickey
303a47f7207Smickey	/*
304a47f7207Smickey	 * BIOS call "INT 0x13 Extensions Installation Check"
305a47f7207Smickey	 *	Call with	%ah = 0x41
306a47f7207Smickey	 *			%bx = 0x55AA
307a47f7207Smickey	 *			%dl = drive (0x80 for 1st hd, 0x81 for 2nd, etc)
308a47f7207Smickey	 *	Return:
309a47f7207Smickey	 *			carry set: failure
310a47f7207Smickey	 *				%ah = error code (0x01, invalid func)
311a47f7207Smickey	 *			carry clear: success
312a47f7207Smickey	 *				%bx = 0xAA55 (must verify)
313a47f7207Smickey	 *				%ah = major version of extensions
314a47f7207Smickey	 *				%al   (internal use)
315a47f7207Smickey	 *				%cx = capabilities bitmap
316a47f7207Smickey	 *					0x0001 - extnd disk access funcs
317a47f7207Smickey	 *					0x0002 - rem. drive ctrl funcs
318a47f7207Smickey	 *					0x0004 - EDD functions with EBP
319a47f7207Smickey	 *				%dx   (extension version?)
320a47f7207Smickey	 */
321a47f7207Smickey
322a47f7207Smickey	movb	%dl, (%si)		/* Store drive here temporarily */
323a47f7207Smickey					/* (This call trashes %dl) */
324a47f7207Smickey					/*
325a47f7207Smickey					 * XXX This is actually the correct
326a47f7207Smickey					 *     place to store this.  The 0x80
327a47f7207Smickey					 *     value used to indicate the
328a47f7207Smickey					 *     active partition is by intention
329a47f7207Smickey					 *     the same as the BIOS drive value
330a47f7207Smickey					 *     for the first hard disk (0x80).
331a47f7207Smickey					 *     At one point, 0x81 would go here
332a47f7207Smickey					 *     for the second hard disk; the
333a47f7207Smickey					 *     0x80 value is often used as a
334a47f7207Smickey					 *     bit flag for testing, rather
335a47f7207Smickey					 *     than an exact byte value.
336a47f7207Smickey					 */
337a47f7207Smickey	movw	$0x55AA, %bx
338a47f7207Smickey	movb	$0x41, %ah
339a47f7207Smickey	int	$0x13
340a47f7207Smickey
341a47f7207Smickey	movb	(%si), %dl		/* Get back drive number */
342a47f7207Smickey
343a47f7207Smickey	jc	do_chs			/* Did the command work? Jump if not */
344a47f7207Smickey	cmpw	$0xAA55, %bx		/* Check that bl, bh exchanged */
345a47f7207Smickey	jne	do_chs			/* If not, don't have EDD extensions */
346a47f7207Smickey	testb	$0x01, %cl		/* And do we have "read" available? */
347a47f7207Smickey	jz	do_chs			/* Again, use CHS if not */
348a47f7207Smickey
349a47f7207Smickeydo_lba:
350a47f7207Smickey	/*
351a47f7207Smickey	 * BIOS call "INT 0x13 Extensions Extended Read"
352a47f7207Smickey	 *	Call with	%ah = 0x42
353a47f7207Smickey	 *			%dl = drive (0x80 for 1st hd, 0x81 for 2nd, etc)
354a47f7207Smickey	 *			%ds:%si = segment:offset of command packet
355a47f7207Smickey	 *	Return:
356a47f7207Smickey	 *			carry set: failure
357a47f7207Smickey	 *				%ah = error code (0x01, invalid func)
358a47f7207Smickey	 *				command packet's sector count field set
359a47f7207Smickey	 *				to the number of sectors successfully
360a47f7207Smickey	 *				transferred
361a47f7207Smickey	 *			carry clear: success
362a47f7207Smickey	 *				%ah = 0 (success)
363a47f7207Smickey	 *	Command Packet:
364a47f7207Smickey	 *			0x0000	BYTE	packet size (0x10 or 0x18)
365a47f7207Smickey	 *			0x0001	BYTE	reserved (should be 0)
366a47f7207Smickey	 *			0x0002	WORD	sectors to transfer (max 127)
367a47f7207Smickey	 *			0x0004	DWORD	seg:offset of transfer buffer
368a47f7207Smickey	 *			0x0008	QWORD	starting sector number
369a47f7207Smickey	 */
370a47f7207Smickey	movb	$CHAR_LBA_READ, %al
371a47f7207Smickey	call	Lchr
372a47f7207Smickey
373a47f7207Smickey	/* Load LBA sector number from active partition table entry */
374a47f7207Smickey	movl	8(%si), %ecx
375a47f7207Smickey	movl	%ecx, lba_sector
376a47f7207Smickey
377a47f7207Smickey	pushw	%si			/* We'll need %si later */
378a47f7207Smickey
379a47f7207Smickey	movb	$0x42, %ah
380a47f7207Smickey	movw	$lba_command, %si
381a47f7207Smickey	int	$0x13
382a47f7207Smickey
38351249ee3Sderaadt	popw	%si			/* get back %si */
384a47f7207Smickey
385a47f7207Smickey	jnc	booting_os		/* If it worked, run the pbr we got */
386a47f7207Smickey
387a47f7207Smickey	/*
388a47f7207Smickey	 * LBA read failed, fall through to try CHS read
389a47f7207Smickey	 */
390a47f7207Smickey
391a47f7207Smickeydo_chs:
392a47f7207Smickey	/*
393a47f7207Smickey	 * BIOS call "INT 0x13 Function 0x2" to read sectors from disk into
394a47f7207Smickey	 * memory
395a47f7207Smickey	 *       Call with       %ah = 0x2
396a47f7207Smickey	 *                       %al = number of sectors
397a47f7207Smickey	 *                       %ch = cylinder & 0xFF
398a47f7207Smickey	 *                       %cl = sector (0-63) | rest of cylinder bits
399a47f7207Smickey	 *                       %dh = head
400a47f7207Smickey	 *                       %dl = drive (0x80 for hard disk)
401a47f7207Smickey	 *                       %es:%bx = segment:offset of buffer
402a47f7207Smickey	 *       Return:
403a47f7207Smickey	 *                       carry set: failure
404a47f7207Smickey	 *                           %ah = err code
405a47f7207Smickey	 *                           %al = number of sectors transferred
406a47f7207Smickey	 *                       carry clear: success
407a47f7207Smickey	 *                           %al = 0x0 OR number of sectors transferred
408a47f7207Smickey	 *                                 (depends on BIOS!)
409a47f7207Smickey	 *                                 (according to Ralph Brown Int List)
410a47f7207Smickey	 */
411a47f7207Smickey	movb	$CHAR_CHS_READ, %al
412a47f7207Smickey	call	Lchr
413a47f7207Smickey
414a47f7207Smickey	/* Load values from active partition table entry */
415a47f7207Smickey	movb	1(%si), %dh		/* head */
416a47f7207Smickey	movw	2(%si), %cx		/* sect, cyl */
417a47f7207Smickey	movw	$0x201, %ax		/* function and number of blocks */
418a47f7207Smickey	xorw	%bx, %bx		/* put it at %es:0 */
419a47f7207Smickey	int	$0x13
420a47f7207Smickey	jnc	booting_os
421a47f7207Smickey
422a47f7207Smickeyread_error:
423a47f7207Smickey	movw	$eread, %si
424a47f7207Smickey	jmp	err_stop
425a47f7207Smickey
426a47f7207Smickeybooting_os:
427a47f7207Smickey	puts(crlf)
428a47f7207Smickey	DBGMSG(CHAR_G)
429a47f7207Smickey
430a47f7207Smickey	/*
431a47f7207Smickey	 * Make sure the pbr we loaded has a valid signature at the end.
432a47f7207Smickey	 * This also ensures that something did load where we were expecting
433a47f7207Smickey	 * it, as there's still a copy of our code there...
434a47f7207Smickey	 */
435a47f7207Smickey	cmpw	$DOSMBR_SIGNATURE, %es:signature(,1)
436a47f7207Smickey	jne	missing_os
437a47f7207Smickey
438a47f7207Smickey	/* jump to the new code (%ds:%si is at the right point) */
439a47f7207Smickey	ljmp	$0, $BOOTSEG << 4
440a47f7207Smickey	/* not reached */
441a47f7207Smickey
442a47f7207Smickeymissing_os:
443a47f7207Smickey	movw	$enoos, %si
444a47f7207Smickey	jmp	err_stop
445a47f7207Smickey
446a47f7207Smickey/*
447a47f7207Smickey * Display string
448a47f7207Smickey */
449a47f7207SmickeyLmessage:
450a47f7207Smickey	pushw	%ax
451a47f7207Smickey	cld
452a47f7207Smickey1:
453a47f7207Smickey	lodsb			/* %al = *%si++ */
454a47f7207Smickey	testb	%al, %al
455a47f7207Smickey	jz	1f
456a47f7207Smickey	call    Lchr
457a47f7207Smickey	jmp	1b
458a47f7207Smickey
459a47f7207Smickey/*
460a47f7207Smickey *	Lchr: write the error message in %ds:%si to console
461a47f7207Smickey */
462a47f7207SmickeyLchr:
463a47f7207Smickey	pushw	%ax
464a47f7207Smickey
465a47f7207Smickey#ifdef SERIAL
466a47f7207Smickey	pushw	%dx
467a47f7207Smickey	movb	$0x01, %ah
468bd4e04c6Smglocker	movw	$SERIAL, %dx
469a47f7207Smickey	int	$0x14
470a47f7207Smickey	popw	%dx
471a47f7207Smickey#else
472a47f7207Smickey	pushw	%bx
473a47f7207Smickey	movb	$0x0e, %ah
474a47f7207Smickey	movw	$1, %bx
475a47f7207Smickey	int	$0x10
476a47f7207Smickey	popw	%bx
477a47f7207Smickey#endif
478a47f7207Smickey1:	popw	%ax
479a47f7207Smickey	ret
480a47f7207Smickey
481a47f7207Smickey/* command packet for LBA read of boot sector */
482a47f7207Smickeylba_command:
483a47f7207Smickey	.byte	0x10			/* size of command packet */
484a47f7207Smickey	.byte	0x00			/* reserved */
485a47f7207Smickey	.word	0x0001			/* sectors to transfer, just 1 */
486a47f7207Smickey	.word	0			/* target buffer, offset */
487a47f7207Smickey	.word	BOOTSEG			/* target buffer, segment */
488a47f7207Smickeylba_sector:
489a47f7207Smickey	.long	0, 0			/* sector number */
490a47f7207Smickey
491a47f7207Smickey/* Info messages */
49251249ee3Sderaadtinfo:	.ascii		"Using drive "
493a47f7207Smickeydrive_num:
494a47f7207Smickey	.byte		'X'
495a47f7207Smickey	.ascii		", partition "
496a47f7207Smickeypart_num:
497a47f7207Smickey	.asciz		"Y"
498a47f7207Smickey
499a47f7207Smickey/* Error messages */
500a47f7207Smickeyefdmbr:	.asciz		"MBR on floppy or old BIOS\r\n"
501a47f7207Smickeyeread:	.asciz		"\r\nRead error\r\n"
502a47f7207Smickeyenoos:	.asciz		"No O/S\r\n"
503a47f7207Smickeyenoboot: .ascii		"No active partition"	/* runs into crlf... */
504a47f7207Smickeycrlf:	.asciz		"\r\n"
505a47f7207Smickey
506a47f7207Smickeyendofcode:
507a47f7207Smickey	nop
508a47f7207Smickey
509a47f7207Smickey/* (MBR) NT disk signature offset */
510a47f7207Smickey	. = 0x1b8
511a47f7207Smickey	.space  4, 0
512a47f7207Smickey
513a47f7207Smickey/* partition table */
514a47f7207Smickey/* flag, head, sec, cyl, type, ehead, esect, ecyl, start, len */
515a47f7207Smickey	. = DOSPARTOFF	/* starting address of partition table */
516*4ed81583Skrwpt:	.fill	0x40,1,0
517a47f7207Smickey/* the last 2 bytes in the sector 0 contain the signature */
518a47f7207Smickey	. = 0x1fe
519a47f7207Smickeysignature:
520a47f7207Smickey	.short	DOSMBR_SIGNATURE
521a47f7207Smickey	. = 0x200
522