17c478bd9Sstevel@tonic-gate/*
27c478bd9Sstevel@tonic-gate *  GRUB  --  GRand Unified Bootloader
37c478bd9Sstevel@tonic-gate *  Copyright (C) 1994-2002  H. Peter Anvin
47c478bd9Sstevel@tonic-gate *  Copyright (C) 1999,2000,2001,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
227c478bd9Sstevel@tonic-gate/*
237c478bd9Sstevel@tonic-gate Most of this file was originally "isolinux.asm" from SYSLINUX package.
247c478bd9Sstevel@tonic-gate It has been very heavily modified.
257c478bd9Sstevel@tonic-gate*/
267c478bd9Sstevel@tonic-gate
277c478bd9Sstevel@tonic-gate#define ASM_FILE
287c478bd9Sstevel@tonic-gate#include "stage1.h"
297c478bd9Sstevel@tonic-gate#include "shared.h"
307c478bd9Sstevel@tonic-gate#include "iso9660.h"
317c478bd9Sstevel@tonic-gate
327c478bd9Sstevel@tonic-gate#ifndef STAGE1_5
337c478bd9Sstevel@tonic-gate#include "stage2_size.h"
347c478bd9Sstevel@tonic-gate#endif
357c478bd9Sstevel@tonic-gate
367c478bd9Sstevel@tonic-gate
377c478bd9Sstevel@tonic-gate	/* Absolute addresses
387c478bd9Sstevel@tonic-gate	   This makes the assembler generate the address without support
397c478bd9Sstevel@tonic-gate	   from the linker. (ELF can't relocate 16-bit addresses!) */
407c478bd9Sstevel@tonic-gate#define ABS(x)			(x-_start+BOOTSEC_LOCATION)
417c478bd9Sstevel@tonic-gate
427c478bd9Sstevel@tonic-gate#ifdef STAGE1_5
437c478bd9Sstevel@tonic-gate# define STAGE_ADDR		0x2000
447c478bd9Sstevel@tonic-gate#else
457c478bd9Sstevel@tonic-gate# define STAGE_ADDR		0x8000
467c478bd9Sstevel@tonic-gate#endif /* STAGE1_5 */
477c478bd9Sstevel@tonic-gate
487c478bd9Sstevel@tonic-gate	/* Print message string */
497c478bd9Sstevel@tonic-gate#define MSG(x)			mov $ABS(x), %si; call message;
507c478bd9Sstevel@tonic-gate
517c478bd9Sstevel@tonic-gate	.file	"start_eltorito.S"
527c478bd9Sstevel@tonic-gate
537c478bd9Sstevel@tonic-gate	.text
547c478bd9Sstevel@tonic-gate
557c478bd9Sstevel@tonic-gate	/* Tell GAS to generate 16-bit instructions so that this code works
567c478bd9Sstevel@tonic-gate	   in real mode. */
577c478bd9Sstevel@tonic-gate	.code16
587c478bd9Sstevel@tonic-gate
597c478bd9Sstevel@tonic-gate	.globl	start, _start
607c478bd9Sstevel@tonic-gate
617c478bd9Sstevel@tonic-gate/*
627c478bd9Sstevel@tonic-gate * Primary entry point.	 Because BIOSes are buggy, we only load the first
637c478bd9Sstevel@tonic-gate * CD-ROM sector (2K) of the file, so the number one priority is actually
647c478bd9Sstevel@tonic-gate * loading the rest.
657c478bd9Sstevel@tonic-gate */
667c478bd9Sstevel@tonic-gatestart:
677c478bd9Sstevel@tonic-gate_start:
687c478bd9Sstevel@tonic-gate	cli
697c478bd9Sstevel@tonic-gate	ljmp	$0, $ABS(real_start)
707c478bd9Sstevel@tonic-gate
717c478bd9Sstevel@tonic-gate	. = _start + 8			    /* Pad to file offset 8 */
727c478bd9Sstevel@tonic-gate
737c478bd9Sstevel@tonic-gate		/* This table gets filled in by mkisofs using the
747c478bd9Sstevel@tonic-gate		   -boot-info-table option */
757c478bd9Sstevel@tonic-gatebi_pvd:		.long 0xDEADBEEF	    /* LBA of primary volume descript */
767c478bd9Sstevel@tonic-gatebi_file:	.long 0xDEADBEEF	    /* LBA of boot file */
777c478bd9Sstevel@tonic-gatebi_length:	.long 0xDEADBEEF	    /* Length of boot file */
787c478bd9Sstevel@tonic-gatebi_csum:	.long 0xDEADBEEF	    /* Checksum of boot file */
797c478bd9Sstevel@tonic-gatebi_reserved:	.space (10*4)		    /* Reserved */
807c478bd9Sstevel@tonic-gate
817c478bd9Sstevel@tonic-gatereal_start:
827c478bd9Sstevel@tonic-gate	xor	%ax, %ax
837c478bd9Sstevel@tonic-gate	mov	%ax, %ss
847c478bd9Sstevel@tonic-gate	mov	%ax, %ds
857c478bd9Sstevel@tonic-gate	mov	%ax, %es
867c478bd9Sstevel@tonic-gate	mov	%ax, %fs
877c478bd9Sstevel@tonic-gate	mov	%ax, %gs
887c478bd9Sstevel@tonic-gate	mov	$STAGE1_STACKSEG, %sp	    /* set up the REAL stack */
897c478bd9Sstevel@tonic-gate	sti
907c478bd9Sstevel@tonic-gate	cld
917c478bd9Sstevel@tonic-gate
927c478bd9Sstevel@tonic-gate	/* save drive reference first thing! */
937c478bd9Sstevel@tonic-gate	mov	%dl, ABS(BootDrive)
947c478bd9Sstevel@tonic-gate
957c478bd9Sstevel@tonic-gate	/* print a notification message on the screen */
967c478bd9Sstevel@tonic-gate	MSG(notification_string)
977c478bd9Sstevel@tonic-gate
987c478bd9Sstevel@tonic-gateload_image:
997c478bd9Sstevel@tonic-gate	/* Set up boot file sector, size, load address */
1007c478bd9Sstevel@tonic-gate	mov	ABS(bi_length), %eax
1017c478bd9Sstevel@tonic-gate	add	$(ISO_SECTOR_SIZE-1), %eax
1027c478bd9Sstevel@tonic-gate	shr	$ISO_SECTOR_BITS, %eax	    /* dwords->sectors */
1037c478bd9Sstevel@tonic-gate	mov	%ax, %bp		    /* boot file sectors */
1047c478bd9Sstevel@tonic-gate	mov	$(STAGE_ADDR >> 4), %bx
1057c478bd9Sstevel@tonic-gate	mov	%bx, %es
1067c478bd9Sstevel@tonic-gate	xor	%bx, %bx
1077c478bd9Sstevel@tonic-gate	mov	ABS(bi_file), %eax
1087c478bd9Sstevel@tonic-gate	call	getlinsec
1097c478bd9Sstevel@tonic-gate	mov	%ds, %ax
1107c478bd9Sstevel@tonic-gate	mov	%ax, %es
1117c478bd9Sstevel@tonic-gate
1127c478bd9Sstevel@tonic-gate	MSG(notification_done)
1137c478bd9Sstevel@tonic-gatebootit:
1147c478bd9Sstevel@tonic-gate	/* save the sector number of the second sector in %ebp */
1157c478bd9Sstevel@tonic-gate	mov	$ABS(firstlist - BOOTSEC_LISTSIZE), %si
1167c478bd9Sstevel@tonic-gate	mov	(%si), %ebp
1177c478bd9Sstevel@tonic-gate	mov	ABS(BootDrive), %dl	    /* this makes sure %dl is our "boot" drive */
1187c478bd9Sstevel@tonic-gate	ljmp	$0, $(STAGE_ADDR+SECTOR_SIZE)  /* jump to main() in asm.S */
1197c478bd9Sstevel@tonic-gate
1207c478bd9Sstevel@tonic-gate/* go here when you need to stop the machine hard after an error condition */
1217c478bd9Sstevel@tonic-gatestop:	jmp	stop
1227c478bd9Sstevel@tonic-gate
1237c478bd9Sstevel@tonic-gate
1247c478bd9Sstevel@tonic-gate/*
1257c478bd9Sstevel@tonic-gate * Get linear sectors - EBIOS LBA addressing, 2048-byte sectors.
1267c478bd9Sstevel@tonic-gate *
1277c478bd9Sstevel@tonic-gate * Note that we can't always do this as a single request, because at least
1287c478bd9Sstevel@tonic-gate * Phoenix BIOSes has a 127-sector limit.  To be on the safe side, stick
1297c478bd9Sstevel@tonic-gate * to 16 sectors (32K) per request.
1307c478bd9Sstevel@tonic-gate *
1317c478bd9Sstevel@tonic-gate * Input:
1327c478bd9Sstevel@tonic-gate *	 EAX	 - Linear sector number
1337c478bd9Sstevel@tonic-gate *	 ES:BX	 - Target buffer
1347c478bd9Sstevel@tonic-gate *	 BP	 - Sector count
1357c478bd9Sstevel@tonic-gate */
1367c478bd9Sstevel@tonic-gategetlinsec:
1377c478bd9Sstevel@tonic-gate	mov	$ABS(dapa), %si		   /* Load up the DAPA */
1387c478bd9Sstevel@tonic-gate	mov	%bx, 4(%si)
1397c478bd9Sstevel@tonic-gate	mov	%es, %bx
1407c478bd9Sstevel@tonic-gate	mov	%bx, 6(%si)
1417c478bd9Sstevel@tonic-gate	mov	%eax, 8(%si)
1427c478bd9Sstevel@tonic-gate1:
1437c478bd9Sstevel@tonic-gate	push	%bp
1447c478bd9Sstevel@tonic-gate	push	%si
1457c478bd9Sstevel@tonic-gate	cmp	ABS(MaxTransfer), %bp
1467c478bd9Sstevel@tonic-gate	jbe	2f
1477c478bd9Sstevel@tonic-gate	mov	ABS(MaxTransfer), %bp
1487c478bd9Sstevel@tonic-gate2:
1497c478bd9Sstevel@tonic-gate	mov	%bp, 2(%si)
1507c478bd9Sstevel@tonic-gate	mov	ABS(BootDrive), %dl
1517c478bd9Sstevel@tonic-gate	mov	$0x42, %ah		    /* Extended Read */
1527c478bd9Sstevel@tonic-gate	call	xint13
1537c478bd9Sstevel@tonic-gate	pop	%si
1547c478bd9Sstevel@tonic-gate	pop	%bp
1557c478bd9Sstevel@tonic-gate	movzwl	2(%si), %eax		    /* Sectors we read */
1567c478bd9Sstevel@tonic-gate	add	%eax, 8(%si)		    /* Advance sector pointer */
1577c478bd9Sstevel@tonic-gate	sub	%ax, %bp		    /* Sectors left */
1587c478bd9Sstevel@tonic-gate	shl	$(ISO_SECTOR_BITS-4), %ax   /* 2048-byte sectors -> segment */
1597c478bd9Sstevel@tonic-gate	add	%ax, 6(%si)		    /* Advance buffer pointer */
1607c478bd9Sstevel@tonic-gate
1617c478bd9Sstevel@tonic-gate	pushal
1627c478bd9Sstevel@tonic-gate	MSG(notification_step)
1637c478bd9Sstevel@tonic-gate	popal
1647c478bd9Sstevel@tonic-gate	cmp	$0, %bp
1657c478bd9Sstevel@tonic-gate	ja	1b
1667c478bd9Sstevel@tonic-gate	mov	8(%si), %eax		    /* Return next sector */
1677c478bd9Sstevel@tonic-gate	ret
1687c478bd9Sstevel@tonic-gate
1697c478bd9Sstevel@tonic-gate/*
1707c478bd9Sstevel@tonic-gate * INT 13h with retry
1717c478bd9Sstevel@tonic-gate */
1727c478bd9Sstevel@tonic-gatexint13:
1737c478bd9Sstevel@tonic-gate	movb	$6, ABS(RetryCount)
1747c478bd9Sstevel@tonic-gate.try:
17535497fcdSsetje	pushal
1767c478bd9Sstevel@tonic-gate	int	$0x13
1777c478bd9Sstevel@tonic-gate	jc	1f
1787c478bd9Sstevel@tonic-gate	add	$(8*4), %sp		    /* Clean up stack */
1797c478bd9Sstevel@tonic-gate	ret
1807c478bd9Sstevel@tonic-gate1:
1817c478bd9Sstevel@tonic-gate	mov	%ah, %dl		    /* Save error code */
1827c478bd9Sstevel@tonic-gate	decb	ABS(RetryCount)
1837c478bd9Sstevel@tonic-gate	jz	.real_error
1847c478bd9Sstevel@tonic-gate	mov	ABS(RetryCount), %al
1857c478bd9Sstevel@tonic-gate	mov	ABS(dapa+2), %ah	    /* Sector transfer count */
1867c478bd9Sstevel@tonic-gate	cmp	$2, %al			    /* Only 2 attempts left */
1877c478bd9Sstevel@tonic-gate	ja	2f
1887c478bd9Sstevel@tonic-gate	mov	$1, %ah			    /* Drop transfer size to 1 */
1897c478bd9Sstevel@tonic-gate	jmp	.setmaxtr
1907c478bd9Sstevel@tonic-gate2:
1917c478bd9Sstevel@tonic-gate	cmp	$3, %al
1927c478bd9Sstevel@tonic-gate	ja	3f			    /* First time, just try again */
1937c478bd9Sstevel@tonic-gate	shr	$1, %ah			    /* Otherwise, try to reduce */
1947c478bd9Sstevel@tonic-gate	adc	$0, %ah			    /* the max transfer size, but not */
1957c478bd9Sstevel@tonic-gate.setmaxtr:
1967c478bd9Sstevel@tonic-gate	mov	%ah, ABS(MaxTransfer)
1977c478bd9Sstevel@tonic-gate	mov	%ah, ABS(dapa+2)
1987c478bd9Sstevel@tonic-gate3:
1997c478bd9Sstevel@tonic-gate	popal
2007c478bd9Sstevel@tonic-gate	jmp	.try
2017c478bd9Sstevel@tonic-gate
2027c478bd9Sstevel@tonic-gate.real_error:
2037c478bd9Sstevel@tonic-gate	MSG(read_error_string)
2047c478bd9Sstevel@tonic-gate	mov	%dl, %al
2057c478bd9Sstevel@tonic-gate	call	printhex2
2067c478bd9Sstevel@tonic-gate	popal
2077c478bd9Sstevel@tonic-gate	jmp	stop
2087c478bd9Sstevel@tonic-gate
2097c478bd9Sstevel@tonic-gate
2107c478bd9Sstevel@tonic-gate
2117c478bd9Sstevel@tonic-gate/*
2127c478bd9Sstevel@tonic-gate * message: write the string pointed to by %si
2137c478bd9Sstevel@tonic-gate *
2147c478bd9Sstevel@tonic-gate *   WARNING: trashes %si, %ax, and %bx
2157c478bd9Sstevel@tonic-gate */
2167c478bd9Sstevel@tonic-gate
2177c478bd9Sstevel@tonic-gate	/*
2187c478bd9Sstevel@tonic-gate	 * Use BIOS "int 10H Function 0Eh" to write character in teletype mode
2197c478bd9Sstevel@tonic-gate	 *	%ah = 0xe	%al = character
2207c478bd9Sstevel@tonic-gate	 *	%bh = page	%bl = foreground color (graphics modes)
2217c478bd9Sstevel@tonic-gate	 */
2227c478bd9Sstevel@tonic-gate1:
2237c478bd9Sstevel@tonic-gate	mov	$0x0001, %bx
2247c478bd9Sstevel@tonic-gate	mov	$0x0E, %ah
2257c478bd9Sstevel@tonic-gate	int	$0x10		/* display a byte */
2267c478bd9Sstevel@tonic-gate
2277c478bd9Sstevel@tonic-gatemessage:
2287c478bd9Sstevel@tonic-gate	lodsb
2297c478bd9Sstevel@tonic-gate	or	%al, %al
2307c478bd9Sstevel@tonic-gate	jne	1b		/* if not end of string, jmp to display */
2317c478bd9Sstevel@tonic-gate	ret
2327c478bd9Sstevel@tonic-gate
2337c478bd9Sstevel@tonic-gate/*
2347c478bd9Sstevel@tonic-gate * printhex[248]: Write a hex number in (AL, AX, EAX) to the console
2357c478bd9Sstevel@tonic-gate */
2367c478bd9Sstevel@tonic-gateprinthex2:
2377c478bd9Sstevel@tonic-gate	pushal
2387c478bd9Sstevel@tonic-gate	rol	$24, %eax
2397c478bd9Sstevel@tonic-gate	mov	$2, %cx
2407c478bd9Sstevel@tonic-gate	jmp	1f
2417c478bd9Sstevel@tonic-gateprinthex4:
2427c478bd9Sstevel@tonic-gate	pushal
2437c478bd9Sstevel@tonic-gate	rol	$16, %eax
2447c478bd9Sstevel@tonic-gate	mov	$4, %cx
2457c478bd9Sstevel@tonic-gate	jmp	1f
2467c478bd9Sstevel@tonic-gateprinthex8:
2477c478bd9Sstevel@tonic-gate	pushal
2487c478bd9Sstevel@tonic-gate	mov	$8, %cx
2497c478bd9Sstevel@tonic-gate1:
2507c478bd9Sstevel@tonic-gate	rol	$4, %eax
2517c478bd9Sstevel@tonic-gate	push	%eax
2527c478bd9Sstevel@tonic-gate	and	$0x0F, %al
2537c478bd9Sstevel@tonic-gate	cmp	$10, %al
2547c478bd9Sstevel@tonic-gate	jae	.high
2557c478bd9Sstevel@tonic-gate.low:	add	$('0'), %al
2567c478bd9Sstevel@tonic-gate	jmp	2f
2577c478bd9Sstevel@tonic-gate.high:	add	$('A'-10), %al
2587c478bd9Sstevel@tonic-gate2:
2597c478bd9Sstevel@tonic-gate	mov	$0x0001, %bx
2607c478bd9Sstevel@tonic-gate	mov	$0x0E, %ah
2617c478bd9Sstevel@tonic-gate	int	$0x10		/* display a char */
2627c478bd9Sstevel@tonic-gate	pop	%eax
2637c478bd9Sstevel@tonic-gate	loop	1b
2647c478bd9Sstevel@tonic-gate	popal
2657c478bd9Sstevel@tonic-gate	ret
2667c478bd9Sstevel@tonic-gate
2677c478bd9Sstevel@tonic-gate/**************************************************************************/
2687c478bd9Sstevel@tonic-gate#ifdef STAGE1_5
2697c478bd9Sstevel@tonic-gatenotification_string:	.string "Loading stage1.5 "
2707c478bd9Sstevel@tonic-gate#else
2717c478bd9Sstevel@tonic-gatenotification_string:	.string "Loading stage2 "
2727c478bd9Sstevel@tonic-gate#endif
2737c478bd9Sstevel@tonic-gate
2747c478bd9Sstevel@tonic-gatenotification_step:	.string "."
2757c478bd9Sstevel@tonic-gatenotification_done:	.string "\r\n"
2767c478bd9Sstevel@tonic-gate
2777c478bd9Sstevel@tonic-gateread_error_string:	.string "Read error 0x"
2787c478bd9Sstevel@tonic-gate
2797c478bd9Sstevel@tonic-gate/*
2807c478bd9Sstevel@tonic-gate * EBIOS disk address packet
2817c478bd9Sstevel@tonic-gate */
2827c478bd9Sstevel@tonic-gate		.align 8
2837c478bd9Sstevel@tonic-gatedapa:		.byte 16		   /* Packet size */
2847c478bd9Sstevel@tonic-gate		.byte 0			   /* reserved */
2857c478bd9Sstevel@tonic-gate		.word 0			   /* +2 Block count */
2867c478bd9Sstevel@tonic-gate		.word 0			   /* +4 Offset of buffer */
2877c478bd9Sstevel@tonic-gate		.word 0			   /* +6 Segment of buffer */
2887c478bd9Sstevel@tonic-gate		.long 0			   /* +8 LBA (LSW) */
2897c478bd9Sstevel@tonic-gate		.long 0			   /* +C LBA (MSW) */
2907c478bd9Sstevel@tonic-gate
2917c478bd9Sstevel@tonic-gateVARIABLE(BootDrive)
2927c478bd9Sstevel@tonic-gate	.byte 0xFF
2937c478bd9Sstevel@tonic-gateVARIABLE(MaxTransfer)
2947c478bd9Sstevel@tonic-gate	.word 16			   /* Max sectors per transfer (32Kb) */
2957c478bd9Sstevel@tonic-gateVARIABLE(RetryCount)
2967c478bd9Sstevel@tonic-gate	.byte 0
2977c478bd9Sstevel@tonic-gate
2987c478bd9Sstevel@tonic-gate
2997c478bd9Sstevel@tonic-gate/*
3007c478bd9Sstevel@tonic-gate *  This area is an empty space between the main body of code below which
3017c478bd9Sstevel@tonic-gate *  grows up (fixed after compilation, but between releases it may change
3027c478bd9Sstevel@tonic-gate *  in size easily), and the lists of sectors to read, which grows down
3037c478bd9Sstevel@tonic-gate *  from a fixed top location.
3047c478bd9Sstevel@tonic-gate */
3057c478bd9Sstevel@tonic-gate
3067c478bd9Sstevel@tonic-gate	.word 0
3077c478bd9Sstevel@tonic-gate	.word 0
3087c478bd9Sstevel@tonic-gate
3097c478bd9Sstevel@tonic-gate	. = _start + SECTOR_SIZE - BOOTSEC_LISTSIZE
3107c478bd9Sstevel@tonic-gate
3117c478bd9Sstevel@tonic-gate	/* fill the first data listing with the default */
3127c478bd9Sstevel@tonic-gateblocklist_default_start:/* this is the sector start parameter, in logical
3137c478bd9Sstevel@tonic-gate			   sectors from the start of the disk, sector 0 */
3147c478bd9Sstevel@tonic-gate	.long 0
3157c478bd9Sstevel@tonic-gate
3167c478bd9Sstevel@tonic-gateblocklist_default_len:	/* this is the number of sectors to read */
3177c478bd9Sstevel@tonic-gate#ifdef STAGE1_5
3187c478bd9Sstevel@tonic-gate	.word 0
3197c478bd9Sstevel@tonic-gate#else
3207c478bd9Sstevel@tonic-gate	.word (STAGE2_SIZE + ISO_SECTOR_SIZE - 1) >> ISO_SECTOR_BITS
3217c478bd9Sstevel@tonic-gate#endif
3227c478bd9Sstevel@tonic-gateblocklist_default_seg:	/* this is the segment of the starting address
3237c478bd9Sstevel@tonic-gate			   to load the data into */
3247c478bd9Sstevel@tonic-gate	.word (STAGE_ADDR + SECTOR_SIZE) >> 4
3257c478bd9Sstevel@tonic-gate
3267c478bd9Sstevel@tonic-gatefirstlist:	/* this label has to be after the list data!!! */
327