17c478bd9Sstevel@tonic-gate/* -*-Asm-*- */
27c478bd9Sstevel@tonic-gate/*
37c478bd9Sstevel@tonic-gate *  GRUB  --  GRand Unified Bootloader
47c478bd9Sstevel@tonic-gate *  Copyright (C) 1999,2000,2001,2002,2004   Free Software Foundation, Inc.
57c478bd9Sstevel@tonic-gate *
67c478bd9Sstevel@tonic-gate *  This program is free software; you can redistribute it and/or modify
77c478bd9Sstevel@tonic-gate *  it under the terms of the GNU General Public License as published by
87c478bd9Sstevel@tonic-gate *  the Free Software Foundation; either version 2 of the License, or
97c478bd9Sstevel@tonic-gate *  (at your option) any later version.
107c478bd9Sstevel@tonic-gate *
117c478bd9Sstevel@tonic-gate *  This program is distributed in the hope that it will be useful,
127c478bd9Sstevel@tonic-gate *  but WITHOUT ANY WARRANTY; without even the implied warranty of
137c478bd9Sstevel@tonic-gate *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
147c478bd9Sstevel@tonic-gate *  GNU General Public License for more details.
157c478bd9Sstevel@tonic-gate *
167c478bd9Sstevel@tonic-gate *  You should have received a copy of the GNU General Public License
177c478bd9Sstevel@tonic-gate *  along with this program; if not, write to the Free Software
187c478bd9Sstevel@tonic-gate *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
197c478bd9Sstevel@tonic-gate */
207c478bd9Sstevel@tonic-gate
217c478bd9Sstevel@tonic-gate#include <stage1.h>
227c478bd9Sstevel@tonic-gate
237c478bd9Sstevel@tonic-gate/*
247c478bd9Sstevel@tonic-gate *  defines for the code go here
257c478bd9Sstevel@tonic-gate */
267c478bd9Sstevel@tonic-gate
277c478bd9Sstevel@tonic-gate	/* Absolute addresses
287c478bd9Sstevel@tonic-gate	   This makes the assembler generate the address without support
297c478bd9Sstevel@tonic-gate	   from the linker. (ELF can't relocate 16-bit addresses!) */
307c478bd9Sstevel@tonic-gate#define ABS(x) (x-_start+0x7c00)
317c478bd9Sstevel@tonic-gate
327c478bd9Sstevel@tonic-gate	/* Print message string */
337c478bd9Sstevel@tonic-gate#define MSG(x)	movw $ABS(x), %si; call message
347c478bd9Sstevel@tonic-gate
357c478bd9Sstevel@tonic-gate	/* XXX:	binutils-2.9.1.0.x doesn't produce a short opcode for this. */
367c478bd9Sstevel@tonic-gate#define	MOV_MEM_TO_AL(x)	.byte 0xa0;  .word x
377c478bd9Sstevel@tonic-gate
387c478bd9Sstevel@tonic-gate	.file	"stage1.S"
397c478bd9Sstevel@tonic-gate
407c478bd9Sstevel@tonic-gate	.text
417c478bd9Sstevel@tonic-gate
427c478bd9Sstevel@tonic-gate	/* Tell GAS to generate 16-bit instructions so that this code works
437c478bd9Sstevel@tonic-gate	   in real mode. */
447c478bd9Sstevel@tonic-gate	.code16
457c478bd9Sstevel@tonic-gate
467c478bd9Sstevel@tonic-gate.globl _start; _start:
477c478bd9Sstevel@tonic-gate	/*
487c478bd9Sstevel@tonic-gate	 * _start is loaded at 0x7c00 and is jumped to with CS:IP 0:0x7c00
497c478bd9Sstevel@tonic-gate	 */
507c478bd9Sstevel@tonic-gate
517c478bd9Sstevel@tonic-gate	/*
527c478bd9Sstevel@tonic-gate	 * Beginning of the sector is compatible with the FAT/HPFS BIOS
537c478bd9Sstevel@tonic-gate	 * parameter block.
547c478bd9Sstevel@tonic-gate	 */
557c478bd9Sstevel@tonic-gate
567c478bd9Sstevel@tonic-gate	jmp	after_BPB
577c478bd9Sstevel@tonic-gate	nop	/* do I care about this ??? */
587c478bd9Sstevel@tonic-gate
597c478bd9Sstevel@tonic-gate	/*
607c478bd9Sstevel@tonic-gate	 * This space is for the BIOS parameter block!!!!  Don't change
617c478bd9Sstevel@tonic-gate	 * the first jump, nor start the code anywhere but right after
627c478bd9Sstevel@tonic-gate	 * this area.
637c478bd9Sstevel@tonic-gate	 */
647c478bd9Sstevel@tonic-gate
657c478bd9Sstevel@tonic-gate	. = _start + 4
667c478bd9Sstevel@tonic-gate
677c478bd9Sstevel@tonic-gate	/* scratch space */
687c478bd9Sstevel@tonic-gatemode:
697c478bd9Sstevel@tonic-gate	.byte	0
707c478bd9Sstevel@tonic-gatedisk_address_packet:
717c478bd9Sstevel@tonic-gatesectors:
727c478bd9Sstevel@tonic-gate	.long	0
737c478bd9Sstevel@tonic-gateheads:
747c478bd9Sstevel@tonic-gate	.long	0
757c478bd9Sstevel@tonic-gatecylinders:
767c478bd9Sstevel@tonic-gate	.word	0
777c478bd9Sstevel@tonic-gatesector_start:
787c478bd9Sstevel@tonic-gate	.byte	0
797c478bd9Sstevel@tonic-gatehead_start:
807c478bd9Sstevel@tonic-gate	.byte	0
817c478bd9Sstevel@tonic-gatecylinder_start:
827c478bd9Sstevel@tonic-gate	.word	0
837c478bd9Sstevel@tonic-gate	/* more space... */
847c478bd9Sstevel@tonic-gate
857c478bd9Sstevel@tonic-gate	. = _start + STAGE1_BPBEND
867c478bd9Sstevel@tonic-gate
877c478bd9Sstevel@tonic-gate	/*
887c478bd9Sstevel@tonic-gate	 * End of BIOS parameter block.
897c478bd9Sstevel@tonic-gate	 */
907c478bd9Sstevel@tonic-gate
917c478bd9Sstevel@tonic-gatestage1_version:
927c478bd9Sstevel@tonic-gate	.byte	COMPAT_VERSION_MAJOR, COMPAT_VERSION_MINOR
937c478bd9Sstevel@tonic-gateboot_drive:
947c478bd9Sstevel@tonic-gate	.byte	GRUB_INVALID_DRIVE	/* the disk to load stage2 from */
957c478bd9Sstevel@tonic-gateforce_lba:
967c478bd9Sstevel@tonic-gate	.byte	0
977c478bd9Sstevel@tonic-gatestage2_address:
987c478bd9Sstevel@tonic-gate	.word	0x8000
997c478bd9Sstevel@tonic-gatestage2_sector:
1007c478bd9Sstevel@tonic-gate	.long	1
1017c478bd9Sstevel@tonic-gatestage2_segment:
1027c478bd9Sstevel@tonic-gate	.word	0x800
1037c478bd9Sstevel@tonic-gate
1047c478bd9Sstevel@tonic-gateafter_BPB:
1057c478bd9Sstevel@tonic-gate
1067c478bd9Sstevel@tonic-gate/* general setup */
1077c478bd9Sstevel@tonic-gate	cli		/* we're not safe here! */
1087c478bd9Sstevel@tonic-gate
1097c478bd9Sstevel@tonic-gate	/*
1107c478bd9Sstevel@tonic-gate	 * This is a workaround for buggy BIOSes which don't pass boot
111*1b8adde7SWilliam Kucharski	 * drive correctly. If GRUB is installed into a HDD, check if
112*1b8adde7SWilliam Kucharski	 * DL is masked correctly. If not, assume that the BIOS passed
113*1b8adde7SWilliam Kucharski	 * a bogus value and set DL to 0x80, since this is the only
114*1b8adde7SWilliam Kucharski	 * possible boot drive. If GRUB is installed into a floppy,
115*1b8adde7SWilliam Kucharski	 * this does nothing (only jump).
1167c478bd9Sstevel@tonic-gate	 */
117*1b8adde7SWilliam Kucharskiboot_drive_check:
118*1b8adde7SWilliam Kucharski	jmp	1f
119*1b8adde7SWilliam Kucharski	testb	$0x80, %dl
120*1b8adde7SWilliam Kucharski	jnz	1f
121*1b8adde7SWilliam Kucharski	movb	$0x80, %dl
122*1b8adde7SWilliam Kucharski1:
1237c478bd9Sstevel@tonic-gate
1247c478bd9Sstevel@tonic-gate	/*
1257c478bd9Sstevel@tonic-gate	 * ljmp to the next instruction because some bogus BIOSes
1267c478bd9Sstevel@tonic-gate	 * jump to 07C0:0000 instead of 0000:7C00.
1277c478bd9Sstevel@tonic-gate	 */
1287c478bd9Sstevel@tonic-gate	ljmp	$0, $ABS(real_start)
1297c478bd9Sstevel@tonic-gate
1307c478bd9Sstevel@tonic-gatereal_start:
1317c478bd9Sstevel@tonic-gate
1327c478bd9Sstevel@tonic-gate	/* set up %ds and %ss as offset from 0 */
1337c478bd9Sstevel@tonic-gate	xorw	%ax, %ax
1347c478bd9Sstevel@tonic-gate	movw	%ax, %ds
1357c478bd9Sstevel@tonic-gate	movw	%ax, %ss
1367c478bd9Sstevel@tonic-gate
1377c478bd9Sstevel@tonic-gate	/* set up the REAL stack */
1387c478bd9Sstevel@tonic-gate	movw	$STAGE1_STACKSEG, %sp
1397c478bd9Sstevel@tonic-gate
1407c478bd9Sstevel@tonic-gate	sti		/* we're safe again */
1417c478bd9Sstevel@tonic-gate
1427c478bd9Sstevel@tonic-gate	/*
1437c478bd9Sstevel@tonic-gate	 *  Check if we have a forced disk reference here
1447c478bd9Sstevel@tonic-gate	 */
1457c478bd9Sstevel@tonic-gate	MOV_MEM_TO_AL(ABS(boot_drive))	/* movb	ABS(boot_drive), %al */
1467c478bd9Sstevel@tonic-gate	cmpb	$GRUB_INVALID_DRIVE, %al
1477c478bd9Sstevel@tonic-gate	je	1f
1487c478bd9Sstevel@tonic-gate	movb	%al, %dl
1497c478bd9Sstevel@tonic-gate1:
1507c478bd9Sstevel@tonic-gate	/* save drive reference first thing! */
1517c478bd9Sstevel@tonic-gate	pushw	%dx
1527c478bd9Sstevel@tonic-gate
1537c478bd9Sstevel@tonic-gate	/* print a notification message on the screen */
1547c478bd9Sstevel@tonic-gate	MSG(notification_string)
1557c478bd9Sstevel@tonic-gate
1567c478bd9Sstevel@tonic-gate	/* do not probe LBA if the drive is a floppy */
1577c478bd9Sstevel@tonic-gate	testb	$STAGE1_BIOS_HD_FLAG, %dl
1587c478bd9Sstevel@tonic-gate	jz	chs_mode
1597c478bd9Sstevel@tonic-gate
1607c478bd9Sstevel@tonic-gate	/* check if LBA is supported */
1617c478bd9Sstevel@tonic-gate	movb	$0x41, %ah
1627c478bd9Sstevel@tonic-gate	movw	$0x55aa, %bx
1637c478bd9Sstevel@tonic-gate	int	$0x13
1647c478bd9Sstevel@tonic-gate
1657c478bd9Sstevel@tonic-gate	/*
1667c478bd9Sstevel@tonic-gate	 *  %dl may have been clobbered by INT 13, AH=41H.
1677c478bd9Sstevel@tonic-gate	 *  This happens, for example, with AST BIOS 1.04.
1687c478bd9Sstevel@tonic-gate	 */
1697c478bd9Sstevel@tonic-gate	popw	%dx
1707c478bd9Sstevel@tonic-gate	pushw	%dx
1717c478bd9Sstevel@tonic-gate
1727c478bd9Sstevel@tonic-gate	/* use CHS if fails */
1737c478bd9Sstevel@tonic-gate	jc	chs_mode
1747c478bd9Sstevel@tonic-gate	cmpw	$0xaa55, %bx
1757c478bd9Sstevel@tonic-gate	jne	chs_mode
1767c478bd9Sstevel@tonic-gate
1777c478bd9Sstevel@tonic-gate	/* check if AH=0x42 is supported if FORCE_LBA is zero */
1787c478bd9Sstevel@tonic-gate	MOV_MEM_TO_AL(ABS(force_lba))	/* movb	ABS(force_lba), %al */
1797c478bd9Sstevel@tonic-gate	testb	%al, %al
1807c478bd9Sstevel@tonic-gate	jnz	lba_mode
1817c478bd9Sstevel@tonic-gate	andw	$1, %cx
1827c478bd9Sstevel@tonic-gate	jz	chs_mode
1837c478bd9Sstevel@tonic-gate
1847c478bd9Sstevel@tonic-gatelba_mode:
1857c478bd9Sstevel@tonic-gate	/* save the total number of sectors */
1867c478bd9Sstevel@tonic-gate	movl	0x10(%si), %ecx
1877c478bd9Sstevel@tonic-gate
1887c478bd9Sstevel@tonic-gate	/* set %si to the disk address packet */
1897c478bd9Sstevel@tonic-gate	movw	$ABS(disk_address_packet), %si
1907c478bd9Sstevel@tonic-gate
1917c478bd9Sstevel@tonic-gate	/* set the mode to non-zero */
1927c478bd9Sstevel@tonic-gate	movb	$1, -1(%si)
1937c478bd9Sstevel@tonic-gate
1947c478bd9Sstevel@tonic-gate	movl	ABS(stage2_sector), %ebx
1957c478bd9Sstevel@tonic-gate
1967c478bd9Sstevel@tonic-gate	/* the size and the reserved byte */
1977c478bd9Sstevel@tonic-gate	movw	$0x0010, (%si)
1987c478bd9Sstevel@tonic-gate
1997c478bd9Sstevel@tonic-gate	/* the blocks */
2007c478bd9Sstevel@tonic-gate	movw	$1, 2(%si)
2017c478bd9Sstevel@tonic-gate
2027c478bd9Sstevel@tonic-gate	/* the absolute address (low 32 bits) */
2037c478bd9Sstevel@tonic-gate	movl	%ebx, 8(%si)
2047c478bd9Sstevel@tonic-gate
2057c478bd9Sstevel@tonic-gate	/* the segment of buffer address */
2067c478bd9Sstevel@tonic-gate	movw	$STAGE1_BUFFERSEG, 6(%si)
2077c478bd9Sstevel@tonic-gate
2087c478bd9Sstevel@tonic-gate	xorl	%eax, %eax
2097c478bd9Sstevel@tonic-gate	movw	%ax, 4(%si)
2107c478bd9Sstevel@tonic-gate	movl	%eax, 12(%si)
2117c478bd9Sstevel@tonic-gate
2127c478bd9Sstevel@tonic-gate/*
2137c478bd9Sstevel@tonic-gate * BIOS call "INT 0x13 Function 0x42" to read sectors from disk into memory
2147c478bd9Sstevel@tonic-gate *	Call with	%ah = 0x42
2157c478bd9Sstevel@tonic-gate *			%dl = drive number
2167c478bd9Sstevel@tonic-gate *			%ds:%si = segment:offset of disk address packet
2177c478bd9Sstevel@tonic-gate *	Return:
2187c478bd9Sstevel@tonic-gate *			%al = 0x0 on success; err code on failure
2197c478bd9Sstevel@tonic-gate */
2207c478bd9Sstevel@tonic-gate
2217c478bd9Sstevel@tonic-gate	movb	$0x42, %ah
2227c478bd9Sstevel@tonic-gate	int	$0x13
2237c478bd9Sstevel@tonic-gate
2247c478bd9Sstevel@tonic-gate	/* LBA read is not supported, so fallback to CHS.  */
2257c478bd9Sstevel@tonic-gate	jc	chs_mode
2267c478bd9Sstevel@tonic-gate
2277c478bd9Sstevel@tonic-gate	movw	$STAGE1_BUFFERSEG, %bx
2287c478bd9Sstevel@tonic-gate	jmp	copy_buffer
2297c478bd9Sstevel@tonic-gate
2307c478bd9Sstevel@tonic-gatechs_mode:
2317c478bd9Sstevel@tonic-gate	/*
2327c478bd9Sstevel@tonic-gate	 *  Determine the hard disk geometry from the BIOS!
2337c478bd9Sstevel@tonic-gate	 *  We do this first, so that LS-120 IDE floppies work correctly.
2347c478bd9Sstevel@tonic-gate	 */
2357c478bd9Sstevel@tonic-gate	movb	$8, %ah
2367c478bd9Sstevel@tonic-gate	int	$0x13
2377c478bd9Sstevel@tonic-gate	jnc	final_init
2387c478bd9Sstevel@tonic-gate
2397c478bd9Sstevel@tonic-gate	/*
2407c478bd9Sstevel@tonic-gate	 *  The call failed, so maybe use the floppy probe instead.
2417c478bd9Sstevel@tonic-gate	 */
2427c478bd9Sstevel@tonic-gate	testb	$STAGE1_BIOS_HD_FLAG, %dl
2437c478bd9Sstevel@tonic-gate	jz	floppy_probe
2447c478bd9Sstevel@tonic-gate
2457c478bd9Sstevel@tonic-gate	/* Nope, we definitely have a hard disk, and we're screwed. */
2467c478bd9Sstevel@tonic-gate	jmp	hd_probe_error
2477c478bd9Sstevel@tonic-gate
2487c478bd9Sstevel@tonic-gatefinal_init:
2497c478bd9Sstevel@tonic-gate
2507c478bd9Sstevel@tonic-gate	movw	$ABS(sectors), %si
2517c478bd9Sstevel@tonic-gate
2527c478bd9Sstevel@tonic-gate	/* set the mode to zero */
2537c478bd9Sstevel@tonic-gate	movb	$0, -1(%si)
2547c478bd9Sstevel@tonic-gate
2557c478bd9Sstevel@tonic-gate	/* save number of heads */
2567c478bd9Sstevel@tonic-gate	xorl	%eax, %eax
2577c478bd9Sstevel@tonic-gate	movb	%dh, %al
2587c478bd9Sstevel@tonic-gate	incw	%ax
2597c478bd9Sstevel@tonic-gate	movl	%eax, 4(%si)
2607c478bd9Sstevel@tonic-gate
2617c478bd9Sstevel@tonic-gate	xorw	%dx, %dx
2627c478bd9Sstevel@tonic-gate	movb	%cl, %dl
2637c478bd9Sstevel@tonic-gate	shlw	$2, %dx
2647c478bd9Sstevel@tonic-gate	movb	%ch, %al
2657c478bd9Sstevel@tonic-gate	movb	%dh, %ah
2667c478bd9Sstevel@tonic-gate
2677c478bd9Sstevel@tonic-gate	/* save number of cylinders */
2687c478bd9Sstevel@tonic-gate	incw	%ax
2697c478bd9Sstevel@tonic-gate	movw	%ax, 8(%si)
2707c478bd9Sstevel@tonic-gate
2717c478bd9Sstevel@tonic-gate	xorw	%ax, %ax
2727c478bd9Sstevel@tonic-gate	movb	%dl, %al
2737c478bd9Sstevel@tonic-gate	shrb	$2, %al
2747c478bd9Sstevel@tonic-gate
2757c478bd9Sstevel@tonic-gate	/* save number of sectors */
2767c478bd9Sstevel@tonic-gate	movl	%eax, (%si)
2777c478bd9Sstevel@tonic-gate
2787c478bd9Sstevel@tonic-gatesetup_sectors:
2797c478bd9Sstevel@tonic-gate	/* load logical sector start (bottom half) */
2807c478bd9Sstevel@tonic-gate	movl	ABS(stage2_sector), %eax
2817c478bd9Sstevel@tonic-gate
2827c478bd9Sstevel@tonic-gate	/* zero %edx */
2837c478bd9Sstevel@tonic-gate	xorl	%edx, %edx
2847c478bd9Sstevel@tonic-gate
2857c478bd9Sstevel@tonic-gate	/* divide by number of sectors */
2867c478bd9Sstevel@tonic-gate	divl	(%si)
2877c478bd9Sstevel@tonic-gate
2887c478bd9Sstevel@tonic-gate	/* save sector start */
2897c478bd9Sstevel@tonic-gate	movb	%dl, 10(%si)
2907c478bd9Sstevel@tonic-gate
2917c478bd9Sstevel@tonic-gate	xorl	%edx, %edx	/* zero %edx */
2927c478bd9Sstevel@tonic-gate	divl	4(%si)		/* divide by number of heads */
2937c478bd9Sstevel@tonic-gate
2947c478bd9Sstevel@tonic-gate	/* save head start */
2957c478bd9Sstevel@tonic-gate	movb	%dl, 11(%si)
2967c478bd9Sstevel@tonic-gate
2977c478bd9Sstevel@tonic-gate	/* save cylinder start */
2987c478bd9Sstevel@tonic-gate	movw	%ax, 12(%si)
2997c478bd9Sstevel@tonic-gate
3007c478bd9Sstevel@tonic-gate	/* do we need too many cylinders? */
3017c478bd9Sstevel@tonic-gate	cmpw	8(%si), %ax
3027c478bd9Sstevel@tonic-gate	jge	geometry_error
3037c478bd9Sstevel@tonic-gate
3047c478bd9Sstevel@tonic-gate/*
3057c478bd9Sstevel@tonic-gate *  This is the loop for taking care of BIOS geometry translation (ugh!)
3067c478bd9Sstevel@tonic-gate */
3077c478bd9Sstevel@tonic-gate
3087c478bd9Sstevel@tonic-gate	/* get high bits of cylinder */
3097c478bd9Sstevel@tonic-gate	movb	13(%si), %dl
3107c478bd9Sstevel@tonic-gate
3117c478bd9Sstevel@tonic-gate	shlb	$6, %dl		/* shift left by 6 bits */
3127c478bd9Sstevel@tonic-gate	movb	10(%si), %cl	/* get sector */
3137c478bd9Sstevel@tonic-gate
3147c478bd9Sstevel@tonic-gate	incb	%cl		/* normalize sector (sectors go
3157c478bd9Sstevel@tonic-gate					from 1-N, not 0-(N-1) ) */
3167c478bd9Sstevel@tonic-gate	orb	%dl, %cl	/* composite together */
3177c478bd9Sstevel@tonic-gate	movb	12(%si), %ch	/* sector+hcyl in cl, cylinder in ch */
3187c478bd9Sstevel@tonic-gate
3197c478bd9Sstevel@tonic-gate	/* restore %dx */
3207c478bd9Sstevel@tonic-gate	popw	%dx
3217c478bd9Sstevel@tonic-gate
3227c478bd9Sstevel@tonic-gate	/* head number */
3237c478bd9Sstevel@tonic-gate	movb	11(%si), %dh
3247c478bd9Sstevel@tonic-gate
3257c478bd9Sstevel@tonic-gate/*
3267c478bd9Sstevel@tonic-gate * BIOS call "INT 0x13 Function 0x2" to read sectors from disk into memory
3277c478bd9Sstevel@tonic-gate *	Call with	%ah = 0x2
3287c478bd9Sstevel@tonic-gate *			%al = number of sectors
3297c478bd9Sstevel@tonic-gate *			%ch = cylinder
3307c478bd9Sstevel@tonic-gate *			%cl = sector (bits 6-7 are high bits of "cylinder")
3317c478bd9Sstevel@tonic-gate *			%dh = head
3327c478bd9Sstevel@tonic-gate *			%dl = drive (0x80 for hard disk, 0x0 for floppy disk)
3337c478bd9Sstevel@tonic-gate *			%es:%bx = segment:offset of buffer
3347c478bd9Sstevel@tonic-gate *	Return:
3357c478bd9Sstevel@tonic-gate *			%al = 0x0 on success; err code on failure
3367c478bd9Sstevel@tonic-gate */
3377c478bd9Sstevel@tonic-gate
3387c478bd9Sstevel@tonic-gate	movw	$STAGE1_BUFFERSEG, %bx
3397c478bd9Sstevel@tonic-gate	movw	%bx, %es	/* load %es segment with disk buffer */
3407c478bd9Sstevel@tonic-gate
3417c478bd9Sstevel@tonic-gate	xorw	%bx, %bx	/* %bx = 0, put it at 0 in the segment */
3427c478bd9Sstevel@tonic-gate	movw	$0x0201, %ax	/* function 2 */
3437c478bd9Sstevel@tonic-gate	int	$0x13
3447c478bd9Sstevel@tonic-gate
3457c478bd9Sstevel@tonic-gate	jc	read_error
3467c478bd9Sstevel@tonic-gate
3477c478bd9Sstevel@tonic-gate	movw	%es, %bx
3487c478bd9Sstevel@tonic-gate
3497c478bd9Sstevel@tonic-gatecopy_buffer:
3507c478bd9Sstevel@tonic-gate	movw	ABS(stage2_segment), %es
3517c478bd9Sstevel@tonic-gate
3527c478bd9Sstevel@tonic-gate	/*
3537c478bd9Sstevel@tonic-gate	 * We need to save %cx and %si because the startup code in
3547c478bd9Sstevel@tonic-gate	 * stage2 uses them without initializing them.
3557c478bd9Sstevel@tonic-gate	 */
3567c478bd9Sstevel@tonic-gate	pusha
3577c478bd9Sstevel@tonic-gate	pushw	%ds
3587c478bd9Sstevel@tonic-gate
3597c478bd9Sstevel@tonic-gate	movw	$0x100, %cx
3607c478bd9Sstevel@tonic-gate	movw	%bx, %ds
3617c478bd9Sstevel@tonic-gate	xorw	%si, %si
3627c478bd9Sstevel@tonic-gate	xorw	%di, %di
3637c478bd9Sstevel@tonic-gate
3647c478bd9Sstevel@tonic-gate	cld
3657c478bd9Sstevel@tonic-gate
3667c478bd9Sstevel@tonic-gate	rep
3677c478bd9Sstevel@tonic-gate	movsw
3687c478bd9Sstevel@tonic-gate
3697c478bd9Sstevel@tonic-gate	popw	%ds
3707c478bd9Sstevel@tonic-gate	popa
3717c478bd9Sstevel@tonic-gate
3727c478bd9Sstevel@tonic-gate	/* boot stage2 */
3737c478bd9Sstevel@tonic-gate	jmp	*(stage2_address)
3747c478bd9Sstevel@tonic-gate
3757c478bd9Sstevel@tonic-gate/* END OF MAIN LOOP */
3767c478bd9Sstevel@tonic-gate
3777c478bd9Sstevel@tonic-gate/*
3787c478bd9Sstevel@tonic-gate * BIOS Geometry translation error (past the end of the disk geometry!).
3797c478bd9Sstevel@tonic-gate */
3807c478bd9Sstevel@tonic-gategeometry_error:
3817c478bd9Sstevel@tonic-gate	MSG(geometry_error_string)
3827c478bd9Sstevel@tonic-gate	jmp	general_error
3837c478bd9Sstevel@tonic-gate
3847c478bd9Sstevel@tonic-gate/*
3857c478bd9Sstevel@tonic-gate * Disk probe failure.
3867c478bd9Sstevel@tonic-gate */
3877c478bd9Sstevel@tonic-gatehd_probe_error:
3887c478bd9Sstevel@tonic-gate	MSG(hd_probe_error_string)
3897c478bd9Sstevel@tonic-gate	jmp	general_error
3907c478bd9Sstevel@tonic-gate
3917c478bd9Sstevel@tonic-gate/*
3927c478bd9Sstevel@tonic-gate * Read error on the disk.
3937c478bd9Sstevel@tonic-gate */
3947c478bd9Sstevel@tonic-gateread_error:
3957c478bd9Sstevel@tonic-gate	MSG(read_error_string)
3967c478bd9Sstevel@tonic-gate
3977c478bd9Sstevel@tonic-gategeneral_error:
3987c478bd9Sstevel@tonic-gate	MSG(general_error_string)
3997c478bd9Sstevel@tonic-gate
4007c478bd9Sstevel@tonic-gate/* go here when you need to stop the machine hard after an error condition */
4017c478bd9Sstevel@tonic-gatestop:	jmp	stop
4027c478bd9Sstevel@tonic-gate
4037c478bd9Sstevel@tonic-gatenotification_string:	.string "GRUB "
4047c478bd9Sstevel@tonic-gategeometry_error_string:	.string "Geom"
4057c478bd9Sstevel@tonic-gatehd_probe_error_string:	.string "Hard Disk"
4067c478bd9Sstevel@tonic-gateread_error_string:	.string "Read"
4077c478bd9Sstevel@tonic-gategeneral_error_string:	.string " Error"
4087c478bd9Sstevel@tonic-gate
4097c478bd9Sstevel@tonic-gate/*
4107c478bd9Sstevel@tonic-gate * message: write the string pointed to by %si
4117c478bd9Sstevel@tonic-gate *
4127c478bd9Sstevel@tonic-gate *   WARNING: trashes %si, %ax, and %bx
4137c478bd9Sstevel@tonic-gate */
4147c478bd9Sstevel@tonic-gate
4157c478bd9Sstevel@tonic-gate	/*
4167c478bd9Sstevel@tonic-gate	 * Use BIOS "int 10H Function 0Eh" to write character in teletype mode
4177c478bd9Sstevel@tonic-gate	 *	%ah = 0xe	%al = character
4187c478bd9Sstevel@tonic-gate	 *	%bh = page	%bl = foreground color (graphics modes)
4197c478bd9Sstevel@tonic-gate	 */
4207c478bd9Sstevel@tonic-gate1:
4217c478bd9Sstevel@tonic-gate	movw	$0x0001, %bx
4227c478bd9Sstevel@tonic-gate	movb	$0xe, %ah
4237c478bd9Sstevel@tonic-gate	int	$0x10		/* display a byte */
4247c478bd9Sstevel@tonic-gatemessage:
4257c478bd9Sstevel@tonic-gate	lodsb
4267c478bd9Sstevel@tonic-gate	cmpb	$0, %al
4277c478bd9Sstevel@tonic-gate	jne	1b	/* if not end of string, jmp to display */
4287c478bd9Sstevel@tonic-gate	ret
4297c478bd9Sstevel@tonic-gate
4307c478bd9Sstevel@tonic-gate	/*
4317c478bd9Sstevel@tonic-gate	 *  Windows NT breaks compatibility by embedding a magic
4327c478bd9Sstevel@tonic-gate	 *  number here.
4337c478bd9Sstevel@tonic-gate	 */
4347c478bd9Sstevel@tonic-gate
4357c478bd9Sstevel@tonic-gate	. = _start + STAGE1_WINDOWS_NT_MAGIC
4367c478bd9Sstevel@tonic-gatent_magic:
4377c478bd9Sstevel@tonic-gate	.long 0
4387c478bd9Sstevel@tonic-gate	.word 0
4397c478bd9Sstevel@tonic-gate
4407c478bd9Sstevel@tonic-gate	/*
4417c478bd9Sstevel@tonic-gate	 *  This is where an MBR would go if on a hard disk.  The code
4427c478bd9Sstevel@tonic-gate	 *  here isn't even referenced unless we're on a floppy.  Kinda
4437c478bd9Sstevel@tonic-gate	 *  sneaky, huh?
4447c478bd9Sstevel@tonic-gate	 */
4457c478bd9Sstevel@tonic-gate
4467c478bd9Sstevel@tonic-gatepart_start:
4477c478bd9Sstevel@tonic-gate	. = _start + STAGE1_PARTSTART
4487c478bd9Sstevel@tonic-gate
4497c478bd9Sstevel@tonic-gateprobe_values:
4507c478bd9Sstevel@tonic-gate	.byte	36, 18, 15, 9, 0
4517c478bd9Sstevel@tonic-gate
4527c478bd9Sstevel@tonic-gatefloppy_probe:
4537c478bd9Sstevel@tonic-gate/*
4547c478bd9Sstevel@tonic-gate *  Perform floppy probe.
4557c478bd9Sstevel@tonic-gate */
4567c478bd9Sstevel@tonic-gate
4577c478bd9Sstevel@tonic-gate	movw	$ABS(probe_values-1), %si
4587c478bd9Sstevel@tonic-gate
4597c478bd9Sstevel@tonic-gateprobe_loop:
4607c478bd9Sstevel@tonic-gate	/* reset floppy controller INT 13h AH=0 */
4617c478bd9Sstevel@tonic-gate	xorw	%ax, %ax
4627c478bd9Sstevel@tonic-gate	int	$0x13
4637c478bd9Sstevel@tonic-gate
4647c478bd9Sstevel@tonic-gate	incw	%si
4657c478bd9Sstevel@tonic-gate	movb	(%si), %cl
4667c478bd9Sstevel@tonic-gate
4677c478bd9Sstevel@tonic-gate	/* if number of sectors is 0, display error and die */
4687c478bd9Sstevel@tonic-gate	cmpb	$0, %cl
4697c478bd9Sstevel@tonic-gate	jne	1f
4707c478bd9Sstevel@tonic-gate
4717c478bd9Sstevel@tonic-gate/*
4727c478bd9Sstevel@tonic-gate * Floppy disk probe failure.
4737c478bd9Sstevel@tonic-gate */
4747c478bd9Sstevel@tonic-gate	MSG(fd_probe_error_string)
4757c478bd9Sstevel@tonic-gate	jmp	general_error
4767c478bd9Sstevel@tonic-gate
4777c478bd9Sstevel@tonic-gatefd_probe_error_string:	.string "Floppy"
4787c478bd9Sstevel@tonic-gate
4797c478bd9Sstevel@tonic-gate1:
4807c478bd9Sstevel@tonic-gate	/* perform read */
4817c478bd9Sstevel@tonic-gate	movw	$STAGE1_BUFFERSEG, %bx
4827c478bd9Sstevel@tonic-gate	movw	$0x201, %ax
4837c478bd9Sstevel@tonic-gate	movb	$0, %ch
4847c478bd9Sstevel@tonic-gate	movb	$0, %dh
4857c478bd9Sstevel@tonic-gate	int	$0x13
4867c478bd9Sstevel@tonic-gate
4877c478bd9Sstevel@tonic-gate	/* if error, jump to "probe_loop" */
4887c478bd9Sstevel@tonic-gate	jc	probe_loop
4897c478bd9Sstevel@tonic-gate
4907c478bd9Sstevel@tonic-gate	/* %cl is already the correct value! */
4917c478bd9Sstevel@tonic-gate	movb	$1, %dh
4927c478bd9Sstevel@tonic-gate	movb	$79, %ch
4937c478bd9Sstevel@tonic-gate
4947c478bd9Sstevel@tonic-gate	jmp	final_init
4957c478bd9Sstevel@tonic-gate
4967c478bd9Sstevel@tonic-gate	. = _start + STAGE1_PARTEND
4977c478bd9Sstevel@tonic-gate
4987c478bd9Sstevel@tonic-gate/* the last 2 bytes in the sector 0 contain the signature */
4997c478bd9Sstevel@tonic-gate	.word	STAGE1_SIGNATURE
500