Home | History | Annotate | Download | only in stage1
      1 /* -*-Asm-*- */
      2 /*
      3  *  GRUB  --  GRand Unified Bootloader
      4  *  Copyright (C) 1999,2000,2001,2002,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 #include <stage1.h>
     22 
     23 /*
     24  *  defines for the code go here
     25  */
     26 
     27 	/* Absolute addresses
     28 	   This makes the assembler generate the address without support
     29 	   from the linker. (ELF can't relocate 16-bit addresses!) */
     30 #define ABS(x) (x-_start+0x7c00)
     31 
     32 	/* Print message string */
     33 #define MSG(x)	movw $ABS(x), %si; call message
     34 
     35 	/* XXX:	binutils-2.9.1.0.x doesn't produce a short opcode for this. */
     36 #define	MOV_MEM_TO_AL(x)	.byte 0xa0;  .word x
     37 
     38 	.file	"stage1.S"
     39 
     40 	.text
     41 
     42 	/* Tell GAS to generate 16-bit instructions so that this code works
     43 	   in real mode. */
     44 	.code16
     45 
     46 .globl _start; _start:
     47 	/*
     48 	 * _start is loaded at 0x7c00 and is jumped to with CS:IP 0:0x7c00
     49 	 */
     50 
     51 	/*
     52 	 * Beginning of the sector is compatible with the FAT/HPFS BIOS
     53 	 * parameter block.
     54 	 */
     55 
     56 	jmp	after_BPB
     57 	nop	/* do I care about this ??? */
     58 
     59 	/*
     60 	 * This space is for the BIOS parameter block!!!!  Don't change
     61 	 * the first jump, nor start the code anywhere but right after
     62 	 * this area.
     63 	 */
     64 
     65 	. = _start + 4
     66 
     67 	/* scratch space */
     68 mode:
     69 	.byte	0
     70 disk_address_packet:
     71 sectors:
     72 	.long	0
     73 heads:
     74 	.long	0
     75 cylinders:
     76 	.word	0
     77 sector_start:
     78 	.byte	0
     79 head_start:
     80 	.byte	0
     81 cylinder_start:
     82 	.word	0
     83 	/* more space... */
     84 
     85 	. = _start + STAGE1_BPBEND
     86 
     87 	/*
     88 	 * End of BIOS parameter block.
     89 	 */
     90 
     91 stage1_version:
     92 	.byte	COMPAT_VERSION_MAJOR, COMPAT_VERSION_MINOR
     93 boot_drive:
     94 	.byte	GRUB_INVALID_DRIVE	/* the disk to load stage2 from */
     95 force_lba:
     96 	.byte	0
     97 stage2_address:
     98 	.word	0x8000
     99 stage2_sector:
    100 	.long	1
    101 stage2_segment:
    102 	.word	0x800
    103 
    104 after_BPB:
    105 
    106 /* general setup */
    107 	cli		/* we're not safe here! */
    108 
    109 	/*
    110 	 * This is a workaround for buggy BIOSes which don't pass boot
    111 	 * drive correctly. If GRUB is installed into a HDD, check if
    112 	 * DL is masked correctly. If not, assume that the BIOS passed
    113 	 * a bogus value and set DL to 0x80, since this is the only
    114 	 * possible boot drive. If GRUB is installed into a floppy,
    115 	 * this does nothing (only jump).
    116 	 */
    117 boot_drive_check:
    118 	jmp	1f
    119 	testb	$0x80, %dl
    120 	jnz	1f
    121 	movb	$0x80, %dl
    122 1:
    123 
    124 	/*
    125 	 * ljmp to the next instruction because some bogus BIOSes
    126 	 * jump to 07C0:0000 instead of 0000:7C00.
    127 	 */
    128 	ljmp	$0, $ABS(real_start)
    129 
    130 real_start:
    131 
    132 	/* set up %ds and %ss as offset from 0 */
    133 	xorw	%ax, %ax
    134 	movw	%ax, %ds
    135 	movw	%ax, %ss
    136 
    137 	/* set up the REAL stack */
    138 	movw	$STAGE1_STACKSEG, %sp
    139 
    140 	sti		/* we're safe again */
    141 
    142 	/*
    143 	 *  Check if we have a forced disk reference here
    144 	 */
    145 	MOV_MEM_TO_AL(ABS(boot_drive))	/* movb	ABS(boot_drive), %al */
    146 	cmpb	$GRUB_INVALID_DRIVE, %al
    147 	je	1f
    148 	movb	%al, %dl
    149 1:
    150 	/* save drive reference first thing! */
    151 	pushw	%dx
    152 
    153 	/* print a notification message on the screen */
    154 	MSG(notification_string)
    155 
    156 	/* do not probe LBA if the drive is a floppy */
    157 	testb	$STAGE1_BIOS_HD_FLAG, %dl
    158 	jz	chs_mode
    159 
    160 	/* check if LBA is supported */
    161 	movb	$0x41, %ah
    162 	movw	$0x55aa, %bx
    163 	int	$0x13
    164 
    165 	/*
    166 	 *  %dl may have been clobbered by INT 13, AH=41H.
    167 	 *  This happens, for example, with AST BIOS 1.04.
    168 	 */
    169 	popw	%dx
    170 	pushw	%dx
    171 
    172 	/* use CHS if fails */
    173 	jc	chs_mode
    174 	cmpw	$0xaa55, %bx
    175 	jne	chs_mode
    176 
    177 	/* check if AH=0x42 is supported if FORCE_LBA is zero */
    178 	MOV_MEM_TO_AL(ABS(force_lba))	/* movb	ABS(force_lba), %al */
    179 	testb	%al, %al
    180 	jnz	lba_mode
    181 	andw	$1, %cx
    182 	jz	chs_mode
    183 
    184 lba_mode:
    185 	/* save the total number of sectors */
    186 	movl	0x10(%si), %ecx
    187 
    188 	/* set %si to the disk address packet */
    189 	movw	$ABS(disk_address_packet), %si
    190 
    191 	/* set the mode to non-zero */
    192 	movb	$1, -1(%si)
    193 
    194 	movl	ABS(stage2_sector), %ebx
    195 
    196 	/* the size and the reserved byte */
    197 	movw	$0x0010, (%si)
    198 
    199 	/* the blocks */
    200 	movw	$1, 2(%si)
    201 
    202 	/* the absolute address (low 32 bits) */
    203 	movl	%ebx, 8(%si)
    204 
    205 	/* the segment of buffer address */
    206 	movw	$STAGE1_BUFFERSEG, 6(%si)
    207 
    208 	xorl	%eax, %eax
    209 	movw	%ax, 4(%si)
    210 	movl	%eax, 12(%si)
    211 
    212 /*
    213  * BIOS call "INT 0x13 Function 0x42" to read sectors from disk into memory
    214  *	Call with	%ah = 0x42
    215  *			%dl = drive number
    216  *			%ds:%si = segment:offset of disk address packet
    217  *	Return:
    218  *			%al = 0x0 on success; err code on failure
    219  */
    220 
    221 	movb	$0x42, %ah
    222 	int	$0x13
    223 
    224 	/* LBA read is not supported, so fallback to CHS.  */
    225 	jc	chs_mode
    226 
    227 	movw	$STAGE1_BUFFERSEG, %bx
    228 	jmp	copy_buffer
    229 
    230 chs_mode:
    231 	/*
    232 	 *  Determine the hard disk geometry from the BIOS!
    233 	 *  We do this first, so that LS-120 IDE floppies work correctly.
    234 	 */
    235 	movb	$8, %ah
    236 	int	$0x13
    237 	jnc	final_init
    238 
    239 	/*
    240 	 *  The call failed, so maybe use the floppy probe instead.
    241 	 */
    242 	testb	$STAGE1_BIOS_HD_FLAG, %dl
    243 	jz	floppy_probe
    244 
    245 	/* Nope, we definitely have a hard disk, and we're screwed. */
    246 	jmp	hd_probe_error
    247 
    248 final_init:
    249 
    250 	movw	$ABS(sectors), %si
    251 
    252 	/* set the mode to zero */
    253 	movb	$0, -1(%si)
    254 
    255 	/* save number of heads */
    256 	xorl	%eax, %eax
    257 	movb	%dh, %al
    258 	incw	%ax
    259 	movl	%eax, 4(%si)
    260 
    261 	xorw	%dx, %dx
    262 	movb	%cl, %dl
    263 	shlw	$2, %dx
    264 	movb	%ch, %al
    265 	movb	%dh, %ah
    266 
    267 	/* save number of cylinders */
    268 	incw	%ax
    269 	movw	%ax, 8(%si)
    270 
    271 	xorw	%ax, %ax
    272 	movb	%dl, %al
    273 	shrb	$2, %al
    274 
    275 	/* save number of sectors */
    276 	movl	%eax, (%si)
    277 
    278 setup_sectors:
    279 	/* load logical sector start (bottom half) */
    280 	movl	ABS(stage2_sector), %eax
    281 
    282 	/* zero %edx */
    283 	xorl	%edx, %edx
    284 
    285 	/* divide by number of sectors */
    286 	divl	(%si)
    287 
    288 	/* save sector start */
    289 	movb	%dl, 10(%si)
    290 
    291 	xorl	%edx, %edx	/* zero %edx */
    292 	divl	4(%si)		/* divide by number of heads */
    293 
    294 	/* save head start */
    295 	movb	%dl, 11(%si)
    296 
    297 	/* save cylinder start */
    298 	movw	%ax, 12(%si)
    299 
    300 	/* do we need too many cylinders? */
    301 	cmpw	8(%si), %ax
    302 	jge	geometry_error
    303 
    304 /*
    305  *  This is the loop for taking care of BIOS geometry translation (ugh!)
    306  */
    307 
    308 	/* get high bits of cylinder */
    309 	movb	13(%si), %dl
    310 
    311 	shlb	$6, %dl		/* shift left by 6 bits */
    312 	movb	10(%si), %cl	/* get sector */
    313 
    314 	incb	%cl		/* normalize sector (sectors go
    315 					from 1-N, not 0-(N-1) ) */
    316 	orb	%dl, %cl	/* composite together */
    317 	movb	12(%si), %ch	/* sector+hcyl in cl, cylinder in ch */
    318 
    319 	/* restore %dx */
    320 	popw	%dx
    321 
    322 	/* head number */
    323 	movb	11(%si), %dh
    324 
    325 /*
    326  * BIOS call "INT 0x13 Function 0x2" to read sectors from disk into memory
    327  *	Call with	%ah = 0x2
    328  *			%al = number of sectors
    329  *			%ch = cylinder
    330  *			%cl = sector (bits 6-7 are high bits of "cylinder")
    331  *			%dh = head
    332  *			%dl = drive (0x80 for hard disk, 0x0 for floppy disk)
    333  *			%es:%bx = segment:offset of buffer
    334  *	Return:
    335  *			%al = 0x0 on success; err code on failure
    336  */
    337 
    338 	movw	$STAGE1_BUFFERSEG, %bx
    339 	movw	%bx, %es	/* load %es segment with disk buffer */
    340 
    341 	xorw	%bx, %bx	/* %bx = 0, put it at 0 in the segment */
    342 	movw	$0x0201, %ax	/* function 2 */
    343 	int	$0x13
    344 
    345 	jc	read_error
    346 
    347 	movw	%es, %bx
    348 
    349 copy_buffer:
    350 	movw	ABS(stage2_segment), %es
    351 
    352 	/*
    353 	 * We need to save %cx and %si because the startup code in
    354 	 * stage2 uses them without initializing them.
    355 	 */
    356 	pusha
    357 	pushw	%ds
    358 
    359 	movw	$0x100, %cx
    360 	movw	%bx, %ds
    361 	xorw	%si, %si
    362 	xorw	%di, %di
    363 
    364 	cld
    365 
    366 	rep
    367 	movsw
    368 
    369 	popw	%ds
    370 	popa
    371 
    372 	/* boot stage2 */
    373 	jmp	*(stage2_address)
    374 
    375 /* END OF MAIN LOOP */
    376 
    377 /*
    378  * BIOS Geometry translation error (past the end of the disk geometry!).
    379  */
    380 geometry_error:
    381 	MSG(geometry_error_string)
    382 	jmp	general_error
    383 
    384 /*
    385  * Disk probe failure.
    386  */
    387 hd_probe_error:
    388 	MSG(hd_probe_error_string)
    389 	jmp	general_error
    390 
    391 /*
    392  * Read error on the disk.
    393  */
    394 read_error:
    395 	MSG(read_error_string)
    396 
    397 general_error:
    398 	MSG(general_error_string)
    399 
    400 /* go here when you need to stop the machine hard after an error condition */
    401 stop:	jmp	stop
    402 
    403 notification_string:	.string "GRUB "
    404 geometry_error_string:	.string "Geom"
    405 hd_probe_error_string:	.string "Hard Disk"
    406 read_error_string:	.string "Read"
    407 general_error_string:	.string " Error"
    408 
    409 /*
    410  * message: write the string pointed to by %si
    411  *
    412  *   WARNING: trashes %si, %ax, and %bx
    413  */
    414 
    415 	/*
    416 	 * Use BIOS "int 10H Function 0Eh" to write character in teletype mode
    417 	 *	%ah = 0xe	%al = character
    418 	 *	%bh = page	%bl = foreground color (graphics modes)
    419 	 */
    420 1:
    421 	movw	$0x0001, %bx
    422 	movb	$0xe, %ah
    423 	int	$0x10		/* display a byte */
    424 message:
    425 	lodsb
    426 	cmpb	$0, %al
    427 	jne	1b	/* if not end of string, jmp to display */
    428 	ret
    429 
    430 	/*
    431 	 *  Windows NT breaks compatibility by embedding a magic
    432 	 *  number here.
    433 	 */
    434 
    435 	. = _start + STAGE1_WINDOWS_NT_MAGIC
    436 nt_magic:
    437 	.long 0
    438 	.word 0
    439 
    440 	/*
    441 	 *  This is where an MBR would go if on a hard disk.  The code
    442 	 *  here isn't even referenced unless we're on a floppy.  Kinda
    443 	 *  sneaky, huh?
    444 	 */
    445 
    446 part_start:
    447 	. = _start + STAGE1_PARTSTART
    448 
    449 probe_values:
    450 	.byte	36, 18, 15, 9, 0
    451 
    452 floppy_probe:
    453 /*
    454  *  Perform floppy probe.
    455  */
    456 
    457 	movw	$ABS(probe_values-1), %si
    458 
    459 probe_loop:
    460 	/* reset floppy controller INT 13h AH=0 */
    461 	xorw	%ax, %ax
    462 	int	$0x13
    463 
    464 	incw	%si
    465 	movb	(%si), %cl
    466 
    467 	/* if number of sectors is 0, display error and die */
    468 	cmpb	$0, %cl
    469 	jne	1f
    470 
    471 /*
    472  * Floppy disk probe failure.
    473  */
    474 	MSG(fd_probe_error_string)
    475 	jmp	general_error
    476 
    477 fd_probe_error_string:	.string "Floppy"
    478 
    479 1:
    480 	/* perform read */
    481 	movw	$STAGE1_BUFFERSEG, %bx
    482 	movw	$0x201, %ax
    483 	movb	$0, %ch
    484 	movb	$0, %dh
    485 	int	$0x13
    486 
    487 	/* if error, jump to "probe_loop" */
    488 	jc	probe_loop
    489 
    490 	/* %cl is already the correct value! */
    491 	movb	$1, %dh
    492 	movb	$79, %ch
    493 
    494 	jmp	final_init
    495 
    496 	. = _start + STAGE1_PARTEND
    497 
    498 /* the last 2 bytes in the sector 0 contain the signature */
    499 	.word	STAGE1_SIGNATURE
    500