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:
113
* This is the area for all of the special variables.
116
VARIABLE(grub_boot_drive)
119
/* the real mode code continues... */
121
cli /* we're not safe here! */
123
/* set up %ds, %ss, and %es */
129
/* set up the real mode/BIOS stack */
130
movl $GRUB_MEMORY_MACHINE_REAL_STACK, %ebp
133
sti /* we're safe again */
135
/* save the boot drive */
136
ADDR32 movb %dl, EXT_C(grub_boot_drive)
138
/* reset disk system (%ah = 0) */
141
/* transition to protected mode */
142
DATA32 call real_to_prot
144
/* The ".code32" directive takes GAS out of 16-bit mode. */
150
movl EXT_C(grub_compressed_size), %edx
151
addl $(GRUB_KERNEL_MACHINE_RAW_SIZE - GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_PART), %edx
152
movl reed_solomon_redundancy, %ecx
153
leal _start + GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_PART, %eax
156
call EXT_C (grub_reed_solomon_recover)
157
jmp post_reed_solomon
159
#include <rs_decoder.S>
163
. = _start + GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_PART
165
* Support for booting GRUB from a Multiboot boot loader (e.g. GRUB itself).
166
* This uses the a.out kludge to load raw binary to the area starting at 1MB,
167
* and relocates itself after loaded.
169
.p2align 2 /* force 4-byte alignment */
176
.long -0x1BADB002 - (1 << 16)
178
.long multiboot_header - _start + 0x100000 + 0x200
186
.long multiboot_entry - _start + 0x100000 + 0x200
190
/* obtain the boot device */
193
movl $GRUB_MEMORY_MACHINE_PROT_STACK, %ebp
196
/* relocate the code */
197
movl $(GRUB_KERNEL_MACHINE_RAW_SIZE + 0x200), %ecx
198
addl EXT_C(grub_compressed_size) - _start + 0x100000 + 0x200, %ecx
200
movl $GRUB_BOOT_MACHINE_KERNEL_ADDR, %edi
204
/* jump to the real address */
205
movl $multiboot_trampoline, %eax
208
multiboot_trampoline:
209
/* fill the boot information */
216
movl %ebx, EXT_C(grub_install_dos_part)
221
movl %ebx, EXT_C(grub_install_bsd_part)
225
/* enter the usual booting */
227
jmp LOCAL (codestart)
232
movl $GRUB_MEMORY_MACHINE_DECOMPRESSION_ADDR, %edi
233
movl $(_start + GRUB_KERNEL_MACHINE_RAW_SIZE), %esi
236
movl EXT_C(grub_kernel_image_size), %ecx
237
addl EXT_C(grub_total_module_size), %ecx
238
subl $GRUB_KERNEL_MACHINE_RAW_SIZE, %ecx
240
leal (%edi, %ecx), %ebx
242
/* _LzmaDecodeA clears DF, so no need to run cld */
248
/* copy back the decompressed part (except the modules) */
249
subl EXT_C(grub_total_module_size), %ecx
254
/* copy modules before cleaning out the bss */
255
movl EXT_C(grub_total_module_size), %ecx
256
movl EXT_C(grub_kernel_image_size), %esi
260
movl $END_SYMBOL, %edi
269
/* clean out the bss */
270
bss_start_abs = ABS (bss_start)
271
bss_end_abs = ABS (bss_end)
273
movl bss_start_abs, %edi
275
/* compute the bss length */
276
movl bss_end_abs, %ecx
279
/* clean out the bss */
280
movl $BSS_START_SYMBOL, %edi
282
/* compute the bss length */
283
movl $END_SYMBOL, %ecx
294
* Call the start of main body of C code.
296
call EXT_C(grub_main)
298
#include "../realmode.S"
301
* grub_gate_a20(int on)
303
* Gate address-line 20 for high memory.
305
* This routine is probably overconservative in what it does, but so what?
307
* It also eats any keystrokes in the keyboard buffer. :-(
313
gate_a20_test_current_state:
314
/* first of all, test if already in a good state */
315
call gate_a20_check_state
317
jnz gate_a20_try_bios
321
/* second, try a BIOS call */
332
DATA32 call real_to_prot
336
call gate_a20_check_state
338
jnz gate_a20_try_system_control_port_a
341
gate_a20_try_system_control_port_a:
343
* In macbook, the keyboard test would hang the machine, so we move
346
/* fourth, try the system control port A */
354
/* When turning off Gate A20, do not check the state strictly,
355
because a failure is not fatal usually, and Gate A20 is always
356
on some modern machines. */
359
call gate_a20_check_state
361
jnz gate_a20_try_keyboard_controller
364
gate_a20_flush_keyboard_buffer:
367
jnz gate_a20_flush_keyboard_buffer
377
gate_a20_try_keyboard_controller:
378
/* third, try the keyboard controller */
379
call gate_a20_flush_keyboard_buffer
393
call gate_a20_flush_keyboard_buffer
395
/* output a dummy command (USB keyboard hack) */
398
call gate_a20_flush_keyboard_buffer
400
call gate_a20_check_state
402
/* everything failed, so restart from the beginning */
403
jnz gate_a20_try_bios
406
gate_a20_check_state:
407
/* iterate the checking for a while */
420
/* compare the byte at 0x8000 with that at 0x108000 */
421
movl $GRUB_BOOT_MACHINE_KERNEL_ADDR, %ebx
423
/* save the original byte in CL */
425
/* store the value at 0x108000 in AL */
428
/* try to set one less value at 0x8000 */
436
/* obtain the value at 0x108000 in CH */
440
/* this result is 1 if A20 is on or 0 if it is off */
443
/* restore the original */
451
#include "lzma_decode.S"
455
* The code beyond this point is compressed. Assert that the uncompressed
456
* code fits GRUB_KERNEL_MACHINE_RAW_SIZE.
458
. = _start + GRUB_KERNEL_MACHINE_RAW_SIZE
460
. = _start + GRUB_KERNEL_MACHINE_PREFIX
461
VARIABLE(grub_prefix)
462
/* to be filled by grub-mkimage */
465
* Leave some breathing room for the prefix.
467
. = _start + GRUB_KERNEL_MACHINE_PREFIX_END
479
/* Tell the BIOS a boot failure. If this does not work, reboot. */
485
* void grub_chainloader_real_boot (int drive, void *part_addr)
487
* This starts another boot loader.
490
FUNCTION(grub_chainloader_real_boot)
494
/* Turn off Gate A20 */
498
/* set up to pass boot drive */
501
/* ESI must point to a partition table entry */
506
ljmp $0, $GRUB_MEMORY_MACHINE_BOOT_LOADER_ADDR
510
* void grub_console_putchar (int c)
512
* Put the character C on the console. Because GRUB wants to write a
513
* character with an attribute, this implementation is a bit tricky.
514
* If C is a control character (CR, LF, BEL, BS), use INT 10, AH = 0Eh
515
* (TELETYPE OUTPUT). Otherwise, save the original position, put a space,
516
* save the current position, restore the original position, write the
517
* character and the attribute, and restore the current position.
519
* The reason why this is so complicated is that there is no easy way to
520
* get the height of the screen, and the TELETYPE OUTPUT BIOS call doesn't
521
* support setting a background attribute.
523
FUNCTION(grub_console_putchar)
524
/* Retrieve the base character. */
527
movb EXT_C(grub_console_cur_color), %bl
534
/* use teletype output if control character */
544
/* save the character and the attribute on the stack */
548
/* get the current position */
552
/* check the column with the width */
556
/* print CR and LF, if next write will exceed the width */
562
/* get the current position */
567
/* restore the character and the attribute */
571
/* write the character with the attribute */
576
/* move the cursor forward */
587
3: DATA32 call real_to_prot
595
.word 0x011b, 0x0f00 | '\t', 0x0e00 | '\b', 0x1c00 | '\r'
597
LOCAL(bypass_table_end):
600
* int grub_console_getkey (void)
601
* if there is a character pending, return it; otherwise return -1
602
* BIOS call "INT 16H Function 01H" to check whether a character is pending
603
* Call with %ah = 0x1
605
* If key waiting to be input:
606
* %ah = keyboard scan code
607
* %al = ASCII character
611
* BIOS call "INT 16H Function 00H" to read character from keyboard
612
* Call with %ah = 0x0
613
* Return: %ah = keyboard scan code
614
* %al = ASCII character
617
FUNCTION(grub_console_getkey)
625
* Due to a bug in apple's bootcamp implementation, INT 16/AH = 0 would
626
* cause the machine to hang at the second keystroke. However, we can
627
* work around this problem by ensuring the presence of keystroke with
628
* INT 16/AH = 1 before calling INT 16/AH = 0.
639
movw %ax, %dx /* real_to_prot uses %eax */
641
DATA32 call real_to_prot
652
leal LOCAL(bypass_table), %edi
653
movl $((LOCAL(bypass_table_end) - LOCAL(bypass_table)) / 2), %ecx
658
addl $(('a' - 1) | GRUB_TERM_CTRL), %eax
666
orl $GRUB_TERM_EXTENDED, %eax
674
DATA32 call real_to_prot
676
#if GRUB_TERM_NO_KEY != 0
677
#error Fix this asm code
683
* grub_uint16_t grub_console_getxy (void)
684
* BIOS call "INT 10H Function 03h" to get cursor position
685
* Call with %ah = 0x03
687
* Returns %ch = starting scan line
688
* %cl = ending scan line
689
* %dh = row (0 is top)
690
* %dl = column (0 is left)
694
FUNCTION(grub_console_getxy)
696
pushl %ebx /* save EBX */
701
xorb %bh, %bh /* set page to 0 */
703
int $0x10 /* get cursor position */
705
DATA32 call real_to_prot
717
* void grub_console_gotoxy(grub_uint8_t x, grub_uint8_t y)
718
* BIOS call "INT 10H Function 02h" to set cursor position
719
* Call with %ah = 0x02
721
* %dh = row (0 is top)
722
* %dl = column (0 is left)
726
FUNCTION(grub_console_gotoxy)
728
pushl %ebx /* save EBX */
730
movb %cl, %dh /* %dh = y */
736
xorb %bh, %bh /* set page to 0 */
738
int $0x10 /* set cursor position */
740
DATA32 call real_to_prot
749
* void grub_console_cls (void)
750
* BIOS call "INT 10H Function 09h" to write character and attribute
751
* Call with %ah = 0x09
753
* %bh = (page number)
755
* %cx = (number of times)
758
FUNCTION(grub_console_cls)
760
pushl %ebx /* save EBX */
765
/* move the cursor to the beginning */
771
/* write spaces to the entire screen */
777
/* move back the cursor */
781
DATA32 call real_to_prot
790
* void grub_console_setcursor (int on)
791
* BIOS call "INT 10H Function 01h" to set cursor type
792
* Call with %ah = 0x01
793
* %ch = cursor starting scanline
794
* %cl = cursor ending scanline
797
console_cursor_state:
799
console_cursor_shape:
802
FUNCTION(grub_console_setcursor)
809
/* check if the standard cursor shape has already been saved */
810
movw console_cursor_shape, %ax
821
DATA32 call real_to_prot
828
movw %cx, console_cursor_shape
830
/* set %cx to the designated cursor shape */
835
movw console_cursor_shape, %cx
843
DATA32 call real_to_prot
852
* return the real time in ticks, of which there are about
855
FUNCTION(grub_get_rtc)
858
call prot_to_real /* enter real mode */
861
/* %ax is already zero */
864
DATA32 call real_to_prot
875
* int grub_pxe_call (int func, void* data, grub_uint32_t pxe_rm_entry);
877
FUNCTION(grub_pxe_call)
904
DATA32 call real_to_prot
915
FUNCTION(grub_bios_interrupt)
926
movl %eax, LOCAL(bios_register_eax)
928
movw %ax, LOCAL(bios_register_es)
930
movw %ax, LOCAL(bios_register_ds)
932
movw %ax, LOCAL(bios_register_flags)
948
LOCAL(bios_register_es):
953
LOCAL(bios_register_ds):
959
LOCAL(bios_register_flags):
964
/* movl imm32, %eax*/
966
LOCAL(bios_register_eax):
974
movl %eax, %cs:LOCAL(bios_register_eax)
976
movw %ax, %cs:LOCAL(bios_register_ds)
981
movw %ax, LOCAL(bios_register_flags)
983
movw %ax, LOCAL(bios_register_es)
985
DATA32 call real_to_prot
998
movl LOCAL(bios_register_eax), %eax
1000
movw LOCAL(bios_register_es), %ax
1002
movw LOCAL(bios_register_ds), %ax
1004
movw LOCAL(bios_register_flags), %ax