Home | History | Annotate | Download | only in stage2
      1 /*
      2  *  GRUB  --  GRand Unified Bootloader
      3  *  Copyright (C) 1994-2002  H. Peter Anvin
      4  *  Copyright (C) 1999,2000,2001,2004	Free Software Foundation, Inc.
      5  *
      6  *  This program is free software; you can redistribute it and/or modify
      7  *  it under the terms of the GNU General Public License as published by
      8  *  the Free Software Foundation; either version 2 of the License, or
      9  *  (at your option) any later version.
     10  *
     11  *  This program is distributed in the hope that it will be useful,
     12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14  *  GNU General Public License for more details.
     15  *
     16  *  You should have received a copy of the GNU General Public License
     17  *  along with this program; if not, write to the Free Software
     18  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
     19  *
     20  */
     21 
     22 /*
     23  Most of this file was originally "isolinux.asm" from SYSLINUX package.
     24  It has been very heavily modified.
     25 */
     26 
     27 #define ASM_FILE
     28 #include "stage1.h"
     29 #include "shared.h"
     30 #include "iso9660.h"
     31 
     32 #ifndef STAGE1_5
     33 #include "stage2_size.h"
     34 #endif
     35 
     36 
     37 	/* Absolute addresses
     38 	   This makes the assembler generate the address without support
     39 	   from the linker. (ELF can't relocate 16-bit addresses!) */
     40 #define ABS(x)			(x-_start+BOOTSEC_LOCATION)
     41 
     42 #ifdef STAGE1_5
     43 # define STAGE_ADDR		0x2000
     44 #else
     45 # define STAGE_ADDR		0x8000
     46 #endif /* STAGE1_5 */
     47 
     48 	/* Print message string */
     49 #define MSG(x)			mov $ABS(x), %si; call message;
     50 
     51 	.file	"start_eltorito.S"
     52 
     53 	.text
     54 
     55 	/* Tell GAS to generate 16-bit instructions so that this code works
     56 	   in real mode. */
     57 	.code16
     58 
     59 	.globl	start, _start
     60 
     61 /*
     62  * Primary entry point.	 Because BIOSes are buggy, we only load the first
     63  * CD-ROM sector (2K) of the file, so the number one priority is actually
     64  * loading the rest.
     65  */
     66 start:
     67 _start:
     68 	cli
     69 	ljmp	$0, $ABS(real_start)
     70 
     71 	. = _start + 8			    /* Pad to file offset 8 */
     72 
     73 		/* This table gets filled in by mkisofs using the
     74 		   -boot-info-table option */
     75 bi_pvd:		.long 0xDEADBEEF	    /* LBA of primary volume descript */
     76 bi_file:	.long 0xDEADBEEF	    /* LBA of boot file */
     77 bi_length:	.long 0xDEADBEEF	    /* Length of boot file */
     78 bi_csum:	.long 0xDEADBEEF	    /* Checksum of boot file */
     79 bi_reserved:	.space (10*4)		    /* Reserved */
     80 
     81 real_start:
     82 	xor	%ax, %ax
     83 	mov	%ax, %ss
     84 	mov	%ax, %ds
     85 	mov	%ax, %es
     86 	mov	%ax, %fs
     87 	mov	%ax, %gs
     88 	mov	$STAGE1_STACKSEG, %sp	    /* set up the REAL stack */
     89 	sti
     90 	cld
     91 
     92 	/* save drive reference first thing! */
     93 	mov	%dl, ABS(BootDrive)
     94 
     95 	/* print a notification message on the screen */
     96 	MSG(notification_string)
     97 
     98 load_image:
     99 	/* Set up boot file sector, size, load address */
    100 	mov	ABS(bi_length), %eax
    101 	add	$(ISO_SECTOR_SIZE-1), %eax
    102 	shr	$ISO_SECTOR_BITS, %eax	    /* dwords->sectors */
    103 	mov	%ax, %bp		    /* boot file sectors */
    104 	mov	$(STAGE_ADDR >> 4), %bx
    105 	mov	%bx, %es
    106 	xor	%bx, %bx
    107 	mov	ABS(bi_file), %eax
    108 	call	getlinsec
    109 	mov	%ds, %ax
    110 	mov	%ax, %es
    111 
    112 	MSG(notification_done)
    113 bootit:
    114 	/* save the sector number of the second sector in %ebp */
    115 	mov	$ABS(firstlist - BOOTSEC_LISTSIZE), %si
    116 	mov	(%si), %ebp
    117 	mov	ABS(BootDrive), %dl	    /* this makes sure %dl is our "boot" drive */
    118 	ljmp	$0, $(STAGE_ADDR+SECTOR_SIZE)  /* jump to main() in asm.S */
    119 
    120 /* go here when you need to stop the machine hard after an error condition */
    121 stop:	jmp	stop
    122 
    123 
    124 /*
    125  * Get linear sectors - EBIOS LBA addressing, 2048-byte sectors.
    126  *
    127  * Note that we can't always do this as a single request, because at least
    128  * Phoenix BIOSes has a 127-sector limit.  To be on the safe side, stick
    129  * to 16 sectors (32K) per request.
    130  *
    131  * Input:
    132  *	 EAX	 - Linear sector number
    133  *	 ES:BX	 - Target buffer
    134  *	 BP	 - Sector count
    135  */
    136 getlinsec:
    137 	mov	$ABS(dapa), %si		   /* Load up the DAPA */
    138 	mov	%bx, 4(%si)
    139 	mov	%es, %bx
    140 	mov	%bx, 6(%si)
    141 	mov	%eax, 8(%si)
    142 1:
    143 	push	%bp
    144 	push	%si
    145 	cmp	ABS(MaxTransfer), %bp
    146 	jbe	2f
    147 	mov	ABS(MaxTransfer), %bp
    148 2:
    149 	mov	%bp, 2(%si)
    150 	mov	ABS(BootDrive), %dl
    151 	mov	$0x42, %ah		    /* Extended Read */
    152 	call	xint13
    153 	pop	%si
    154 	pop	%bp
    155 	movzwl	2(%si), %eax		    /* Sectors we read */
    156 	add	%eax, 8(%si)		    /* Advance sector pointer */
    157 	sub	%ax, %bp		    /* Sectors left */
    158 	shl	$(ISO_SECTOR_BITS-4), %ax   /* 2048-byte sectors -> segment */
    159 	add	%ax, 6(%si)		    /* Advance buffer pointer */
    160 
    161 	pushal
    162 	MSG(notification_step)
    163 	popal
    164 	cmp	$0, %bp
    165 	ja	1b
    166 	mov	8(%si), %eax		    /* Return next sector */
    167 	ret
    168 
    169 /*
    170  * INT 13h with retry
    171  */
    172 xint13:
    173 	movb	$6, ABS(RetryCount)
    174 	pushal
    175 .try:
    176 	int	$0x13
    177 	jc	1f
    178 	add	$(8*4), %sp		    /* Clean up stack */
    179 	ret
    180 1:
    181 	mov	%ah, %dl		    /* Save error code */
    182 	decb	ABS(RetryCount)
    183 	jz	.real_error
    184 	mov	ABS(RetryCount), %al
    185 	mov	ABS(dapa+2), %ah	    /* Sector transfer count */
    186 	cmp	$2, %al			    /* Only 2 attempts left */
    187 	ja	2f
    188 	mov	$1, %ah			    /* Drop transfer size to 1 */
    189 	jmp	.setmaxtr
    190 2:
    191 	cmp	$3, %al
    192 	ja	3f			    /* First time, just try again */
    193 	shr	$1, %ah			    /* Otherwise, try to reduce */
    194 	adc	$0, %ah			    /* the max transfer size, but not */
    195 .setmaxtr:
    196 	mov	%ah, ABS(MaxTransfer)
    197 	mov	%ah, ABS(dapa+2)
    198 3:
    199 	popal
    200 	jmp	.try
    201 
    202 .real_error:
    203 	MSG(read_error_string)
    204 	mov	%dl, %al
    205 	call	printhex2
    206 	popal
    207 	jmp	stop
    208 
    209 
    210 
    211 /*
    212  * message: write the string pointed to by %si
    213  *
    214  *   WARNING: trashes %si, %ax, and %bx
    215  */
    216 
    217 	/*
    218 	 * Use BIOS "int 10H Function 0Eh" to write character in teletype mode
    219 	 *	%ah = 0xe	%al = character
    220 	 *	%bh = page	%bl = foreground color (graphics modes)
    221 	 */
    222 1:
    223 	mov	$0x0001, %bx
    224 	mov	$0x0E, %ah
    225 	int	$0x10		/* display a byte */
    226 
    227 message:
    228 	lodsb
    229 	or	%al, %al
    230 	jne	1b		/* if not end of string, jmp to display */
    231 	ret
    232 
    233 /*
    234  * printhex[248]: Write a hex number in (AL, AX, EAX) to the console
    235  */
    236 printhex2:
    237 	pushal
    238 	rol	$24, %eax
    239 	mov	$2, %cx
    240 	jmp	1f
    241 printhex4:
    242 	pushal
    243 	rol	$16, %eax
    244 	mov	$4, %cx
    245 	jmp	1f
    246 printhex8:
    247 	pushal
    248 	mov	$8, %cx
    249 1:
    250 	rol	$4, %eax
    251 	push	%eax
    252 	and	$0x0F, %al
    253 	cmp	$10, %al
    254 	jae	.high
    255 .low:	add	$('0'), %al
    256 	jmp	2f
    257 .high:	add	$('A'-10), %al
    258 2:
    259 	mov	$0x0001, %bx
    260 	mov	$0x0E, %ah
    261 	int	$0x10		/* display a char */
    262 	pop	%eax
    263 	loop	1b
    264 	popal
    265 	ret
    266 
    267 /**************************************************************************/
    268 #ifdef STAGE1_5
    269 notification_string:	.string "Loading stage1.5 "
    270 #else
    271 notification_string:	.string "Loading stage2 "
    272 #endif
    273 
    274 notification_step:	.string "."
    275 notification_done:	.string "\r\n"
    276 
    277 read_error_string:	.string "Read error 0x"
    278 
    279 /*
    280  * EBIOS disk address packet
    281  */
    282 		.align 8
    283 dapa:		.byte 16		   /* Packet size */
    284 		.byte 0			   /* reserved */
    285 		.word 0			   /* +2 Block count */
    286 		.word 0			   /* +4 Offset of buffer */
    287 		.word 0			   /* +6 Segment of buffer */
    288 		.long 0			   /* +8 LBA (LSW) */
    289 		.long 0			   /* +C LBA (MSW) */
    290 
    291 VARIABLE(BootDrive)
    292 	.byte 0xFF
    293 VARIABLE(MaxTransfer)
    294 	.word 16			   /* Max sectors per transfer (32Kb) */
    295 VARIABLE(RetryCount)
    296 	.byte 0
    297 
    298 
    299 /*
    300  *  This area is an empty space between the main body of code below which
    301  *  grows up (fixed after compilation, but between releases it may change
    302  *  in size easily), and the lists of sectors to read, which grows down
    303  *  from a fixed top location.
    304  */
    305 
    306 	.word 0
    307 	.word 0
    308 
    309 	. = _start + SECTOR_SIZE - BOOTSEC_LISTSIZE
    310 
    311 	/* fill the first data listing with the default */
    312 blocklist_default_start:/* this is the sector start parameter, in logical
    313 			   sectors from the start of the disk, sector 0 */
    314 	.long 0
    315 
    316 blocklist_default_len:	/* this is the number of sectors to read */
    317 #ifdef STAGE1_5
    318 	.word 0
    319 #else
    320 	.word (STAGE2_SIZE + ISO_SECTOR_SIZE - 1) >> ISO_SECTOR_BITS
    321 #endif
    322 blocklist_default_seg:	/* this is the segment of the starting address
    323 			   to load the data into */
    324 	.word (STAGE_ADDR + SECTOR_SIZE) >> 4
    325 
    326 firstlist:	/* this label has to be after the list data!!! */
    327