3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 1999,2000,2001,2002,2005,2006,2007,2008,2009 Free Software Foundation, Inc.
6 * GRUB 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 3 of the License, or
9 * (at your option) any later version.
11 * GRUB 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.
16 * You should have received a copy of the GNU General Public License
17 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
20 #include <grub/symbol.h>
21 #include <grub/machine/boot.h>
24 * defines for the code go here
27 /* Print message string */
28 #define MSG(x) movw $x, %si; call LOCAL(message)
29 #define ERR(x) movw $x, %si; jmp LOCAL(error_message)
35 .byte 36, 18, 15, 9, 0
40 * Perform floppy probe.
43 LOCAL(probe_values_minus_one) = LOCAL(probe_values) - 1
44 movw MACRO_DOLLAR(LOCAL(probe_values_minus_one)), %si
46 movw MACRO_DOLLAR(LOCAL(probe_values)) - 1, %si
50 /* reset floppy controller INT 13h AH=0 */
52 int MACRO_DOLLAR(0x13)
57 /* if number of sectors is 0, display error and die */
62 * Floppy disk probe failure.
64 MSG(fd_probe_error_string)
65 jmp LOCAL(general_error)
68 fd_probe_error_string: .asciz "Floppy"
72 movw MACRO_DOLLAR(GRUB_BOOT_MACHINE_BUFFER_SEG), %bx
75 movw MACRO_DOLLAR(0x201), %ax
76 movb MACRO_DOLLAR(0), %ch
77 movb MACRO_DOLLAR(0), %dh
78 int MACRO_DOLLAR(0x13)
80 /* if error, jump to "LOCAL(probe_loop)" */
83 /* %cl is already the correct value! */
84 movb MACRO_DOLLAR(1), %dh
85 movb MACRO_DOLLAR(79), %ch
115 /* Tell GAS to generate 16-bit instructions so that this code works
119 .globl _start, start;
123 * _start is loaded at 0x7c00 and is jumped to with CS:IP 0:0x7c00
127 * Beginning of the sector is compatible with the FAT/HPFS BIOS
132 nop /* do I care about this ??? */
163 * This space is for the BIOS parameter block!!!! Don't change
164 * the first jump, nor start the code anywhere but right after
168 .org GRUB_BOOT_MACHINE_BPB_START
177 .org GRUB_BOOT_MACHINE_BPB_END
179 * End of BIOS parameter block.
182 LOCAL(kernel_address):
183 .word GRUB_BOOT_MACHINE_KERNEL_ADDR
186 .org GRUB_BOOT_MACHINE_KERNEL_SECTOR
187 LOCAL(kernel_sector):
189 LOCAL(kernel_sector_high):
193 .org GRUB_BOOT_MACHINE_BOOT_DRIVE
195 .byte 0xff /* the disk to load kernel from */
196 /* 0xff means use the boot drive */
201 cli /* we're not safe here! */
204 * This is a workaround for buggy BIOSes which don't pass boot
205 * drive correctly. If GRUB is installed into a HDD, check if
206 * DL is masked correctly. If not, assume that the BIOS passed
207 * a bogus value and set DL to 0x80, since this is the only
208 * possible boot drive. If GRUB is installed into a floppy,
209 * this does nothing (only jump).
211 .org GRUB_BOOT_MACHINE_DRIVE_CHECK
213 jmp 3f /* grub-setup may overwrite this jump */
217 /* Ignore %dl different from 0-0x0f and 0x80-0x8f. */
224 * ljmp to the next instruction because some bogus BIOSes
225 * jump to 07C0:0000 instead of 0000:7C00.
231 /* set up %ds and %ss as offset from 0 */
236 /* set up the REAL stack */
237 movw $GRUB_BOOT_MACHINE_STACK_SEG, %sp
239 sti /* we're safe again */
242 * Check if we have a forced disk reference here
249 /* save drive reference first thing! */
252 /* print a notification message on the screen */
253 MSG(notification_string)
255 /* set %si to the disk address packet */
256 movw $disk_address_packet, %si
258 /* check if LBA is supported */
264 * %dl may have been clobbered by INT 13, AH=41H.
265 * This happens, for example, with AST BIOS 1.04.
270 /* use CHS if fails */
283 /* set the mode to non-zero */
289 /* the size and the reserved byte */
292 /* the absolute address */
293 movl LOCAL(kernel_sector), %ebx
295 movl LOCAL(kernel_sector_high), %ebx
298 /* the segment of buffer address */
299 movw $GRUB_BOOT_MACHINE_BUFFER_SEG, 6(%si)
302 * BIOS call "INT 0x13 Function 0x42" to read sectors from disk into memory
303 * Call with %ah = 0x42
305 * %ds:%si = segment:offset of disk address packet
307 * %al = 0x0 on success; err code on failure
313 /* LBA read is not supported, so fallback to CHS. */
316 movw $GRUB_BOOT_MACHINE_BUFFER_SEG, %bx
317 jmp LOCAL(copy_buffer)
321 * Determine the hard disk geometry from the BIOS!
322 * We do this first, so that LS-120 IDE floppies work correctly.
326 jnc LOCAL(final_init)
330 * The call failed, so maybe use the floppy probe instead.
333 jnb LOCAL(floppy_probe)
335 /* Nope, we definitely have a hard disk, and we're screwed. */
336 ERR(hd_probe_error_string)
339 /* set the mode to zero */
343 /* save number of heads */
352 /* save number of cylinders */
359 /* save number of sectors */
363 /* load logical sector start (top half) */
364 movl LOCAL(kernel_sector_high), %eax
367 jnz LOCAL(geometry_error)
369 /* load logical sector start (bottom half) */
370 movl LOCAL(kernel_sector), %eax
375 /* divide by number of sectors */
378 /* save sector start */
381 xorw %dx, %dx /* zero %edx */
382 divl 4(%si) /* divide by number of heads */
384 /* do we need too many cylinders? */
386 jge LOCAL(geometry_error)
388 /* normalize sector start (1-based) */
391 /* low bits of cylinder start */
394 /* high bits of cylinder start */
399 /* save head start */
409 * BIOS call "INT 0x13 Function 0x2" to read sectors from disk into memory
410 * Call with %ah = 0x2
411 * %al = number of sectors
413 * %cl = sector (bits 6-7 are high bits of "cylinder")
415 * %dl = drive (0x80 for hard disk, 0x0 for floppy disk)
416 * %es:%bx = segment:offset of buffer
418 * %al = 0x0 on success; err code on failure
421 movw $GRUB_BOOT_MACHINE_BUFFER_SEG, %bx
422 movw %bx, %es /* load %es segment with disk buffer */
424 xorw %bx, %bx /* %bx = 0, put it at 0 in the segment */
425 movw $0x0201, %ax /* function 2 */
434 * We need to save %cx and %si because the startup code in
435 * kernel uses them without initializing them.
443 movw $GRUB_BOOT_MACHINE_KERNEL_ADDR, %di
455 jmp *(LOCAL(kernel_address))
457 /* END OF MAIN LOOP */
460 * BIOS Geometry translation error (past the end of the disk geometry!).
462 LOCAL(geometry_error):
463 ERR(geometry_error_string)
466 * Read error on the disk.
469 movw $read_error_string, %si
470 LOCAL(error_message):
472 LOCAL(general_error):
473 MSG(general_error_string)
475 /* go here when you need to stop the machine hard after an error condition */
476 /* tell the BIOS a boot failure, which may result in no effect */
481 ventoy_uuid: .ascii "XXXXXXXXXXXXXXXX"
482 notification_string: .asciz "GR"
483 geometry_error_string: .asciz "Ge"
484 hd_probe_error_string: .asciz "HD"
485 read_error_string: .asciz "Rd"
486 general_error_string: .asciz " Er\r\n"
491 * message: write the string pointed to by %si
493 * WARNING: trashes %si, %ax, and %bx
497 * Use BIOS "int 10H Function 0Eh" to write character in teletype mode
498 * %ah = 0xe %al = character
499 * %bh = page %bl = foreground color (graphics modes)
504 int $0x10 /* display a byte */
508 jne 1b /* if not end of string, jmp to display */
512 * Windows NT breaks compatibility by embedding a magic
518 LOCAL(kernel_sector):
520 LOCAL(kernel_sector_high):
523 .org GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC
529 * This is where an MBR would go if on a hard disk. The code
530 * here isn't even referenced unless we're on a floppy. Kinda
534 .org GRUB_BOOT_MACHINE_PART_START
542 .org GRUB_BOOT_MACHINE_PART_END
544 /* the last 2 bytes in the sector 0 contain the signature */
545 .word GRUB_BOOT_MACHINE_SIGNATURE