xref: /openbsd/sys/arch/i386/stand/mbr/mbr.S (revision 610f49f8)
1/*	$OpenBSD: mbr.S,v 1.16 2002/01/08 23:14:51 kjell Exp $	*/
2
3/*
4 * Copyright (c) 1997 Michael Shalayeff and Tobias Weingartner
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 *    must display the following acknowledgement:
17 *	This product includes software developed by Michael Shalayeff.
18 * 4. The name of the author may not be used to endorse or promote products
19 *    derived from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 */
34/* Copyright (c) 1996 VaX#n8 (vax@linkdead.paranoia.com)
35 * last edited 9 July 1996
36 * many thanks to Erich Boleyn (erich@uruk.org) for putting up with
37 * all my questions, and for his work on GRUB
38 * You may use this code or fragments thereof in a manner consistent
39 * with the other copyrights as long as you retain my pseudonym and
40 * this copyright notice in the file.
41 */
42
43	.file	"mbr.S"
44
45#include <machine/asm.h>
46#include <assym.h>
47
48#define data32	.byte 0x66
49#define addr32	.byte 0x67
50
51#define BOOTBIOS	0x7c0	/* segment where we are loaded */
52#define BOOTRELOC	0x7a0	/* segment where to relocate */
53#define PARTSZ		16	/* each partition table entry is 16 bytes */
54
55#ifdef DEBUG
56#define CHAR_S		'S'	/* started */
57#define CHAR_R		'R'	/* relocated */
58#define CHAR_L		'L'	/* looking for bootable partition */
59#define CHAR_B		'B'	/* loading boot */
60#define CHAR_G		'G'	/* jumping to boot */
61
62#define DBGMSG(msg)		\
63	movb    $msg, %al;	\
64	/* call    Lchr */;	\
65	.byte	0xe8;		\
66	.word	Lchr - . - 2
67#else /* !DEBUG */
68#define DBGMSG(msg)
69#endif /* !DEBUG */
70#define	puts(s)			\
71	data32;			\
72	movl	$s, %esi;	\
73	/* call Lmessage */;	\
74	.byte	0xe8;		\
75	.word	Lmessage - . - 2
76
77	.text
78
79	.globl	start
80start:
81	/* Adjust %cs to be right */
82	data32
83	ljmp 	$BOOTBIOS, $1f
841:
85	/* Set up stack */
86	movl	%cs, %ax
87	cli
88	movl	%ax, %ss
89	data32
90	movl	$0xfffc, %esp
91	sti
92
93	/* Set up data segment */
94	movl	%ax, %ds
95	DBGMSG(CHAR_S)
96
97	/* Relocate 512 bytes so we can load PBS here  */
98	data32
99	movl	$BOOTRELOC, %eax
100	movl	%ax, %es
101	data32
102	xorl	%esi, %esi
103	data32
104	xorl	%edi, %edi
105	data32
106	movl	$0x200, %ecx
107	cld
108	rep
109	movsb
110
111	/* Jump to relocated self */
112	data32
113	ljmp $BOOTRELOC, $reloc
114reloc:
115	DBGMSG(CHAR_R)
116
117	/* Set up %es and %ds */
118	pushl	%ds
119	popl	%es	/* next boot is at the same place as we were loaded */
120	pushl	%cs
121	popl	%ds	/* and %ds is at the %cs */
122
123#ifdef SERIAL
124	/* Initialize the serial port to 9600 baud, 8N1.
125	 * Do we need to do this?  Most things at this level
126	 * do not know or care (on a PC) where the output is
127	 * happening to go.  I think if we are headless,
128	 * /boot should figure (as it does now) that out.
129	 *
130	 * If there is a problem with this stage of the boot
131	 * process, connect up a monitor and kbd, and see what
132	 * is going on.  Left here for the time being.
133	 *
134	 * --Toby.
135	 */
136	xorl	%ax, %ax
137	movb	$0xe3, %ax
138	data32
139	movl	$SERIAL, %dx
140	int	$0x14
141#endif
142
143	/* bootstrap passes us drive number in %dl
144	 *
145	 * XXX - This is not always true.  We currently
146	 * check if %dl points to a HD, and if not we
147	 * complain, and set it to point to the first
148	 * HDD.  Note, this is not 100% correct, since
149	 * there is a possibility that you boot of of
150	 * HD #2, and still get (%dl & 0x80) == 0x00,
151	 * these type of systems will loose.  I don't
152	 * know of any like this, but I've come to the
153	 * conclusion, that if it can exist, it will,
154	 * someplace in the PC world.  If anyone knows
155	 * how to fix this, speak up!
156	 *
157	 * Toby - Thu Jul 31 21:01:00 CDT 1997
158	 */
159	testb	$0x80, %dl
160	jnz	1f
161
162	/* MBR on floppy or old BIOS
163	 * Note: MBR (this code) should never
164	 * be on a floppy.  It does not belong
165	 * there, so %dl should never be 0x00.
166	 *
167	 * Here we simply complain (should we?),
168	 * and then hardcode the boot drive to
169	 * 0x80.
170	 */
171	puts(fdmbr)
172
173	/* If we are passed bogus data, set it to HD #1.
174	 * We should load the value from a hard coded
175	 * location in this sector.  Maybe I'll write
176	 * that next, since my machines seem to be one
177	 * of the weird ones...
178	 */
179	movb	$0x80, %dl
180
181	/* Do we need to check our signature?  The BIOS will
182	 * check it for us, I doubt there is a need for us to
183	 * do the same thing over again.  If we fail here,
184	 * something terrible is wrong.  However, I doubt we
185	 * can recover anyways.  The message might be nice
186	 * for the (l)user though.
187	 */
1881:	xorl	%bx, %bx
189	# cmpw	$DOSMBR_SIGNATURE, (%bx)
190	.byte	0x81, 0xbf
191	.word	signature
192	.word	DOSMBR_SIGNATURE
193	je	sigok
194	puts(esig)
195
196	/* find the first active partition
197	 * Note: this should be the only active
198	 * partition.  We currently don't check
199	 * for that, but we really should.  If
200	 * and when I feel up to it, I'll add
201	 * that code.
202	 */
203sigok:
204	data32
205	movl	$pt, %esi
206	data32
207	movl	$NDOSPART, %ecx
2081:
209	DBGMSG(CHAR_L)
210	# movb	(%si), %al
211	.byte	0x8a, 0x44, 0x00
212	cmpb	$DOSACTIVE, %al
213	je	found
214	data32
215	addl	$PARTSZ, %esi
216	loop	1b
217
218	/* No bootable partition */
219no_part:
220	puts(noboot)
221err_stop:
222	cli
223	hlt
224	/* Just to make sure */
225	jmp	err_stop
226
227	/* Found bootable partition */
228found:
229	DBGMSG(CHAR_B)
230	pushl	%ax
231	/* Save drive and partition */
232	movl	%dx, %ax
233	andl	$0x0F, %ax
234	orl	$0x30, %ax
235	#movb	%al, adrive
236	.byte	0xA2
237	.word	adrive
238
239	movl	%cx, %ax
240	decl	%ax
241	xor	$0x03, %ax
242	andl	$0x0F, %ax
243	orl	$0x30, %ax
244	#movb	%al, aprtn
245	.byte	0xA2
246	.word	aprtn
247
248	popl	%ax
249
250	/* Load values from active partition table entry */
251	# movb	1(%si), %dh	# head
252	.byte   0x8a, 0x74, 0x01
253	# movw	2(%si), %cx	# sect, cyl
254	.byte   0x8b, 0x4c, 0x02
255	# movb	4(%si), %al	# partition type
256	.byte   0x8a, 0x44, 0x04
257
258/*
259# BIOS call "INT 0x13 Function 0x2" to read sectors from disk into memory
260#       Call with       %ah = 0x2
261#                       %al = number of sectors
262#                       %ch = cylinder
263#                       %cl = sector
264#                       %dh = head
265#                       %dl = drive (0x80 for hard disk, 0x0 for floppy disk)
266#                       %es:%bx = segment:offset of buffer
267#       Return:
268#                       %al = 0x0 on success; err code on failure
269*/
270	data32
271	movl	$0x200 | 1, %eax	/* number of blocks */
272	xorl	%bx, %bx		/* put it at %es:0 */
273	int	$0x13
274	jnc	1f
275	puts(eread)
276	jmp	err_stop
277
2781:
279	DBGMSG(CHAR_G)
280	puts(info)
281
282	# jump to the new code (%ds:%si is at the right point)
283	data32
284	ljmp	$0, $BOOTBIOS << 4
285	/* not reached */
286
287/*
288 * Display string
289 */
290Lmessage:
291	pushl	%eax
292	cld
2931:
294	lodsb			# load a byte into %al
295	testb	%al, %al
296	jz	1f
297	/* call	Lchr */
298	.byte	0xe8
299	.word	Lchr - . - 2
300	jmp	1b
301
302#
303#	Lchr: write the error message in %ds:%si to console
304#
305Lchr:
306	pushl	%eax
307
308#ifndef SERIAL
309	pushl	%ebx
310	movb	$0x0e, %ah
311	xorl	%bx, %bx
312	incl	%bx		/* movw $0x01, %bx */
313	int	$0x10
314	popl	%ebx
315#else
316	pushl	%edx
317	movb	$0x01, %ah
318	data32
319	movl	SERIAL, %dx
320	int	$0x14
321	popl	%edx
322#endif
3231:	popl	%eax
324	ret
325
326/* Info messages */
327info:	.ascii		"Using Drive: "
328adrive:	.byte		'X'
329	.ascii		" Partition: "
330aprtn:	.byte		'Y'
331	.asciz		"\r\n"
332
333/* Error messages */
334fdmbr:	.asciz		"MBR on floppy or old BIOS\r\n"
335eread:	.asciz		"Read error\r\n"
336noboot: .asciz		"No active partition\r\n"
337esig:	.asciz		"Invalid Signature\r\n"
338
339endofcode:
340	nop
341
342/* (MBR) NT registry offset */
343	. = 0x1b8
344	.space  4, 0
345
346/* partition table */
347/* flag, head, sec, cyl, type, ehead, esect, ecyl, start, len */
348	. = DOSPARTOFF	# starting address of partition table
349pt:
350	.byte	0x0,0,0,0,0,0,0,0
351	.long	0,0
352	.byte	0x0,0,0,0,0,0,0,0
353	.long	0,0
354	.byte	0x0,0,0,0,0,0,0,0
355	.long	0,0
356	.byte	DOSACTIVE,0,1,0,DOSPTYP_OPENBSD,255,255,255
357	.long	0,0x7FFFFFFF
358/* the last 2 bytes in the sector 0 contain the signature */
359	. = 0x1fe
360signature:
361	.short	DOSMBR_SIGNATURE
362	. = 0x200
363
364