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 */ 68mode: 69 .byte 0 70disk_address_packet: 71sectors: 72 .long 0 73heads: 74 .long 0 75cylinders: 76 .word 0 77sector_start: 78 .byte 0 79head_start: 80 .byte 0 81cylinder_start: 82 .word 0 83 /* more space... */ 84 85 . = _start + STAGE1_BPBEND 86 87 /* 88 * End of BIOS parameter block. 89 */ 90 91stage1_version: 92 .byte COMPAT_VERSION_MAJOR, COMPAT_VERSION_MINOR 93boot_drive: 94 .byte GRUB_INVALID_DRIVE /* the disk to load stage2 from */ 95force_lba: 96 .byte 0 97stage2_address: 98 .word 0x8000 99stage2_sector: 100 .long 1 101stage2_segment: 102 .word 0x800 103 104after_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 */ 117boot_drive_check: 118 jmp 1f 119 testb $0x80, %dl 120 jnz 1f 121 movb $0x80, %dl 1221: 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 130real_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 1491: 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 184lba_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 230chs_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 248final_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 278setup_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 349copy_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 */ 380geometry_error: 381 MSG(geometry_error_string) 382 jmp general_error 383 384/* 385 * Disk probe failure. 386 */ 387hd_probe_error: 388 MSG(hd_probe_error_string) 389 jmp general_error 390 391/* 392 * Read error on the disk. 393 */ 394read_error: 395 MSG(read_error_string) 396 397general_error: 398 MSG(general_error_string) 399 400/* go here when you need to stop the machine hard after an error condition */ 401stop: jmp stop 402 403notification_string: .string "GRUB " 404geometry_error_string: .string "Geom" 405hd_probe_error_string: .string "Hard Disk" 406read_error_string: .string "Read" 407general_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 */ 4201: 421 movw $0x0001, %bx 422 movb $0xe, %ah 423 int $0x10 /* display a byte */ 424message: 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 436nt_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 446part_start: 447 . = _start + STAGE1_PARTSTART 448 449probe_values: 450 .byte 36, 18, 15, 9, 0 451 452floppy_probe: 453/* 454 * Perform floppy probe. 455 */ 456 457 movw $ABS(probe_values-1), %si 458 459probe_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 477fd_probe_error_string: .string "Floppy" 478 4791: 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