2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 1999,2000,2001,2002,2003,2005,2006,2007,2008,2009 Free Software Foundation, Inc.
5 * GRUB is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * GRUB is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
21 * Note: These functions defined in this file may be called from C.
22 * Be careful of that you must not modify some registers. Quote
23 * from gcc-2.95.2/gcc/config/i386/i386.h:
25 1 for registers not available across function calls.
26 These must include the FIXED_REGISTERS and also any
27 registers that can be used without being saved.
28 The latter must include the registers where values are returned
29 and the register where structure-value addresses are passed.
30 Aside from that, you can include as many other registers as you like.
32 ax,dx,cx,bx,si,di,bp,sp,st,st1,st2,st3,st4,st5,st6,st7,arg
33 { 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }
37 * Note: GRUB is compiled with the options -mrtd and -mregparm=3.
38 * So the first three arguments are passed in %eax, %edx, and %ecx,
39 * respectively, and if a function has a fixed number of arguments
40 * and the number is greater than three, the function must return
41 * with "ret $N" where N is ((the number of arguments) - 3) * 4.
45 #include <grub/symbol.h>
46 #include <grub/boot.h>
47 #include <grub/machine/boot.h>
48 #include <grub/machine/memory.h>
49 #include <grub/machine/console.h>
50 #include <grub/cpu/linux.h>
51 #include <grub/machine/kernel.h>
52 #include <grub/term.h>
53 #include <multiboot.h>
54 #include <multiboot2.h>
56 #define ABS(x) ((x) - LOCAL (base) + GRUB_BOOT_MACHINE_KERNEL_ADDR + 0x200)
62 /* Tell GAS to generate 16-bit instructions so that this code works
71 * Guarantee that "main" is loaded at 0x0:0x8200.
74 ljmp $0, $(ABS(LOCAL (codestart)) - 0x10000)
76 ljmp $0, $ABS(LOCAL (codestart))
79 * Compatibility version number
81 * These MUST be at byte offset 6 and 7 of the executable
85 .byte GRUB_BOOT_VERSION_MAJOR, GRUB_BOOT_VERSION_MINOR
88 * This is a special data area 8 bytes from the beginning.
93 VARIABLE(grub_total_module_size)
95 VARIABLE(grub_kernel_image_size)
97 VARIABLE(grub_compressed_size)
99 VARIABLE(grub_install_dos_part)
101 VARIABLE(grub_install_bsd_part)
103 reed_solomon_redundancy:
114 * Support for booting GRUB from a Multiboot boot loader (e.g. GRUB itself).
115 * This uses the a.out kludge to load raw binary to the area starting at 1MB,
116 * and relocates itself after loaded.
118 .p2align 2 /* force 4-byte alignment */
125 .long -0x1BADB002 - (1 << 16)
127 .long multiboot_header - _start + 0x100000 + 0x200
135 .long multiboot_entry - _start + 0x100000 + 0x200
139 /* obtain the boot device */
142 movl $GRUB_MEMORY_MACHINE_PROT_STACK, %ebp
145 /* relocate the code */
146 movl $(GRUB_KERNEL_MACHINE_RAW_SIZE + 0x200), %ecx
147 addl EXT_C(grub_compressed_size) - _start + 0x100000 + 0x200, %ecx
149 movl $GRUB_BOOT_MACHINE_KERNEL_ADDR, %edi
153 /* jump to the real address */
154 movl $multiboot_trampoline, %eax
157 multiboot_trampoline:
158 /* fill the boot information */
165 movl %ebx, EXT_C(grub_install_dos_part)
170 movl %ebx, EXT_C(grub_install_bsd_part)
174 /* enter the usual booting */
178 /* the real mode code continues... */
180 cli /* we're not safe here! */
182 /* set up %ds, %ss, and %es */
188 /* set up the real mode/BIOS stack */
189 movl $GRUB_MEMORY_MACHINE_REAL_STACK, %ebp
192 sti /* we're safe again */
194 /* save the boot drive */
195 ADDR32 movb %dl, EXT_C(grub_boot_drive)
197 /* reset disk system (%ah = 0) */
200 /* transition to protected mode */
201 DATA32 call real_to_prot
203 /* The ".code32" directive takes GAS out of 16-bit mode. */
210 movl $GRUB_MEMORY_MACHINE_DECOMPRESSION_ADDR, %edi
211 movl $(_start + GRUB_KERNEL_MACHINE_RAW_SIZE), %esi
214 movl EXT_C(grub_kernel_image_size), %ecx
215 addl EXT_C(grub_total_module_size), %ecx
216 subl $GRUB_KERNEL_MACHINE_RAW_SIZE, %ecx
218 leal (%edi, %ecx), %ebx
220 /* _LzmaDecodeA clears DF, so no need to run cld */
226 /* copy back the decompressed part (except the modules) */
227 subl EXT_C(grub_total_module_size), %ecx
232 /* copy modules before cleaning out the bss */
233 movl EXT_C(grub_total_module_size), %ecx
234 movl EXT_C(grub_kernel_image_size), %esi
238 movl $END_SYMBOL, %edi
247 /* clean out the bss */
248 bss_start_abs = ABS (bss_start)
249 bss_end_abs = ABS (bss_end)
251 movl bss_start_abs, %edi
253 /* compute the bss length */
254 movl bss_end_abs, %ecx
257 /* clean out the bss */
258 movl $BSS_START_SYMBOL, %edi
260 /* compute the bss length */
261 movl $END_SYMBOL, %ecx
272 * Call the start of main body of C code.
274 call EXT_C(grub_main)
277 * This is the area for all of the special variables.
280 VARIABLE(grub_boot_drive)
283 .p2align 2 /* force 4-byte alignment */
285 #include "../realmode.S"
288 * grub_gate_a20(int on)
290 * Gate address-line 20 for high memory.
292 * This routine is probably overconservative in what it does, but so what?
294 * It also eats any keystrokes in the keyboard buffer. :-(
300 gate_a20_test_current_state:
301 /* first of all, test if already in a good state */
302 call gate_a20_check_state
304 jnz gate_a20_try_bios
308 /* second, try a BIOS call */
319 DATA32 call real_to_prot
323 call gate_a20_check_state
325 jnz gate_a20_try_system_control_port_a
328 gate_a20_try_system_control_port_a:
330 * In macbook, the keyboard test would hang the machine, so we move
333 /* fourth, try the system control port A */
341 /* When turning off Gate A20, do not check the state strictly,
342 because a failure is not fatal usually, and Gate A20 is always
343 on some modern machines. */
346 call gate_a20_check_state
348 jnz gate_a20_try_keyboard_controller
351 gate_a20_flush_keyboard_buffer:
354 jnz gate_a20_flush_keyboard_buffer
364 gate_a20_try_keyboard_controller:
365 /* third, try the keyboard controller */
366 call gate_a20_flush_keyboard_buffer
380 call gate_a20_flush_keyboard_buffer
382 /* output a dummy command (USB keyboard hack) */
385 call gate_a20_flush_keyboard_buffer
387 call gate_a20_check_state
389 /* everything failed, so restart from the beginning */
390 jnz gate_a20_try_bios
393 gate_a20_check_state:
394 /* iterate the checking for a while */
407 /* compare the byte at 0x8000 with that at 0x108000 */
408 movl $GRUB_BOOT_MACHINE_KERNEL_ADDR, %ebx
410 /* save the original byte in CL */
412 /* store the value at 0x108000 in AL */
415 /* try to set one less value at 0x8000 */
423 /* obtain the value at 0x108000 in CH */
427 /* this result is 1 if A20 is on or 0 if it is off */
430 /* restore the original */
438 #include "lzma_decode.S"
442 * The code beyond this point is compressed. Assert that the uncompressed
443 * code fits GRUB_KERNEL_MACHINE_RAW_SIZE.
445 . = _start + GRUB_KERNEL_MACHINE_RAW_SIZE
447 . = _start + GRUB_KERNEL_MACHINE_PREFIX
448 VARIABLE(grub_prefix)
449 /* to be filled by grub-mkimage */
452 * Leave some breathing room for the prefix.
454 . = _start + GRUB_KERNEL_MACHINE_PREFIX_END
466 /* Tell the BIOS a boot failure. If this does not work, reboot. */
472 * void grub_chainloader_real_boot (int drive, void *part_addr)
474 * This starts another boot loader.
477 FUNCTION(grub_chainloader_real_boot)
481 /* Turn off Gate A20 */
485 /* set up to pass boot drive */
488 /* ESI must point to a partition table entry */
493 ljmp $0, $GRUB_MEMORY_MACHINE_BOOT_LOADER_ADDR
497 * void grub_console_putchar (int c)
499 * Put the character C on the console. Because GRUB wants to write a
500 * character with an attribute, this implementation is a bit tricky.
501 * If C is a control character (CR, LF, BEL, BS), use INT 10, AH = 0Eh
502 * (TELETYPE OUTPUT). Otherwise, save the original position, put a space,
503 * save the current position, restore the original position, write the
504 * character and the attribute, and restore the current position.
506 * The reason why this is so complicated is that there is no easy way to
507 * get the height of the screen, and the TELETYPE OUTPUT BIOS call doesn't
508 * support setting a background attribute.
510 FUNCTION(grub_console_putchar)
511 /* Retrieve the base character. */
514 movb EXT_C(grub_console_cur_color), %bl
521 /* use teletype output if control character */
531 /* save the character and the attribute on the stack */
535 /* get the current position */
539 /* check the column with the width */
543 /* print CR and LF, if next write will exceed the width */
549 /* get the current position */
554 /* restore the character and the attribute */
558 /* write the character with the attribute */
563 /* move the cursor forward */
574 3: DATA32 call real_to_prot
582 .word 0x0100 | '\e',0x0f00 | '\t', 0x0e00 | '\b', 0x1c00 | '\r'
584 LOCAL(bypass_table_end):
587 * int grub_console_getkey (void)
588 * if there is a character pending, return it; otherwise return -1
589 * BIOS call "INT 16H Function 01H" to check whether a character is pending
590 * Call with %ah = 0x1
592 * If key waiting to be input:
593 * %ah = keyboard scan code
594 * %al = ASCII character
598 * BIOS call "INT 16H Function 00H" to read character from keyboard
599 * Call with %ah = 0x0
600 * Return: %ah = keyboard scan code
601 * %al = ASCII character
604 FUNCTION(grub_console_getkey)
611 * Due to a bug in apple's bootcamp implementation, INT 16/AH = 0 would
612 * cause the machine to hang at the second keystroke. However, we can
613 * work around this problem by ensuring the presence of keystroke with
614 * INT 16/AH = 1 before calling INT 16/AH = 0.
625 movw %ax, %dx /* real_to_prot uses %eax */
627 DATA32 call real_to_prot
638 leal LOCAL(bypass_table), %esi
639 movl $((LOCAL(bypass_table_end) - LOCAL(bypass_table)) / 2), %ecx
643 addl $('a' - 1 | GRUB_TERM_CTRL), %eax
651 orl $GRUB_TERM_EXTENDED, %eax
658 DATA32 call real_to_prot
660 #if GRUB_TERM_NO_KEY != 0
661 #error Fix this asm code
667 * grub_uint16_t grub_console_getxy (void)
668 * BIOS call "INT 10H Function 03h" to get cursor position
669 * Call with %ah = 0x03
671 * Returns %ch = starting scan line
672 * %cl = ending scan line
673 * %dh = row (0 is top)
674 * %dl = column (0 is left)
678 FUNCTION(grub_console_getxy)
680 pushl %ebx /* save EBX */
685 xorb %bh, %bh /* set page to 0 */
687 int $0x10 /* get cursor position */
689 DATA32 call real_to_prot
701 * void grub_console_gotoxy(grub_uint8_t x, grub_uint8_t y)
702 * BIOS call "INT 10H Function 02h" to set cursor position
703 * Call with %ah = 0x02
705 * %dh = row (0 is top)
706 * %dl = column (0 is left)
710 FUNCTION(grub_console_gotoxy)
712 pushl %ebx /* save EBX */
714 movb %cl, %dh /* %dh = y */
720 xorb %bh, %bh /* set page to 0 */
722 int $0x10 /* set cursor position */
724 DATA32 call real_to_prot
733 * void grub_console_cls (void)
734 * BIOS call "INT 10H Function 09h" to write character and attribute
735 * Call with %ah = 0x09
737 * %bh = (page number)
739 * %cx = (number of times)
742 FUNCTION(grub_console_cls)
744 pushl %ebx /* save EBX */
749 /* move the cursor to the beginning */
755 /* write spaces to the entire screen */
761 /* move back the cursor */
765 DATA32 call real_to_prot
774 * void grub_console_setcursor (int on)
775 * BIOS call "INT 10H Function 01h" to set cursor type
776 * Call with %ah = 0x01
777 * %ch = cursor starting scanline
778 * %cl = cursor ending scanline
781 console_cursor_state:
783 console_cursor_shape:
786 FUNCTION(grub_console_setcursor)
793 /* check if the standard cursor shape has already been saved */
794 movw console_cursor_shape, %ax
805 DATA32 call real_to_prot
808 movw %cx, console_cursor_shape
810 /* set %cx to the designated cursor shape */
815 movw console_cursor_shape, %cx
823 DATA32 call real_to_prot
832 * return the real time in ticks, of which there are about
835 FUNCTION(grub_get_rtc)
838 call prot_to_real /* enter real mode */
841 /* %ax is already zero */
844 DATA32 call real_to_prot
855 * int grub_pxe_call (int func, void* data, grub_uint32_t pxe_rm_entry);
857 FUNCTION(grub_pxe_call)
884 DATA32 call real_to_prot
895 FUNCTION(grub_bios_interrupt)
906 movl %eax, LOCAL(bios_register_eax)
908 movw %ax, LOCAL(bios_register_es)
910 movw %ax, LOCAL(bios_register_ds)
912 movw %ax, LOCAL(bios_register_flags)
928 LOCAL(bios_register_es):
933 LOCAL(bios_register_ds):
939 LOCAL(bios_register_flags):
944 /* movl imm32, %eax*/
946 LOCAL(bios_register_eax):
954 movl %eax, %cs:LOCAL(bios_register_eax)
956 movw %ax, %cs:LOCAL(bios_register_ds)
961 movw %ax, LOCAL(bios_register_flags)
963 movw %ax, LOCAL(bios_register_es)
965 DATA32 call real_to_prot
978 movl LOCAL(bios_register_eax), %eax
980 movw LOCAL(bios_register_es), %ax
982 movw LOCAL(bios_register_ds), %ax
984 movw LOCAL(bios_register_flags), %ax