2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 1999,2000,2001,2002,2003,2005,2006 Free Software Foundation, Inc.
5 * This program 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 2 of the License, or
8 * (at your option) any later version.
10 * This program 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 this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 * Note: These functions defined in this file may be called from C.
23 * Be careful of that you must not modify some registers. Quote
24 * from gcc-2.95.2/gcc/config/i386/i386.h:
26 1 for registers not available across function calls.
27 These must include the FIXED_REGISTERS and also any
28 registers that can be used without being saved.
29 The latter must include the registers where values are returned
30 and the register where structure-value addresses are passed.
31 Aside from that, you can include as many other registers as you like.
33 ax,dx,cx,bx,si,di,bp,sp,st,st1,st2,st3,st4,st5,st6,st7,arg
34 { 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }
38 * Note: GRUB is compiled with the options -mrtd and -mregparm=3.
39 * So the first three arguments are passed in %eax, %edx, and %ecx,
40 * respectively, and if a function has a fixed number of arguments
41 * and the number if greater than three, the function must return
42 * with "ret $N" where N is ((the number of arguments) - 3) * 4.
46 #include <grub/symbol.h>
47 #include <grub/boot.h>
48 #include <grub/machine/boot.h>
49 #include <grub/machine/memory.h>
50 #include <grub/machine/console.h>
51 #include <grub/machine/linux.h>
52 #include <grub/machine/kernel.h>
53 #include <grub/machine/multiboot.h>
55 #define ABS(x) ((x) - EXT_C(start) + GRUB_BOOT_MACHINE_KERNEL_ADDR + 0x200)
61 /* Tell GAS to generate 16-bit instructions so that this code works
69 * Guarantee that "main" is loaded at 0x0:0x8200.
71 ljmp $0, $ABS(codestart)
74 * Compatibility version number
76 * These MUST be at byte offset 6 and 7 of the executable
79 . = EXT_C(start) + 0x6
80 .byte GRUB_BOOT_VERSION_MAJOR, GRUB_BOOT_VERSION_MINOR
83 * This is a special data area 8 bytes from the beginning.
86 . = EXT_C(start) + 0x8
88 VARIABLE(grub_total_module_size)
90 VARIABLE(grub_kernel_image_size)
92 VARIABLE(grub_compressed_size)
94 VARIABLE(grub_install_dos_part)
96 VARIABLE(grub_install_bsd_part)
102 * Leave some breathing room for the prefix.
105 . = EXT_C(start) + 0x50
108 * Support for booting GRUB from a Multiboot boot loader (e.g. GRUB itself).
109 * This uses the a.out kludge to load raw binary to the area starting at 1MB,
110 * and relocates itself after loaded.
118 .long -0x1BADB002 - (1 << 16)
120 .long multiboot_header - _start + 0x100000 + 0x200
128 .long multiboot_entry - _start + 0x100000 + 0x200
132 /* obtain the boot device */
135 /* relocate the code */
136 movl $(GRUB_KERNEL_MACHINE_RAW_SIZE + 0x200), %ecx
137 addl EXT_C(grub_compressed_size) - _start + 0x100000 + 0x200, %ecx
139 movl $GRUB_BOOT_MACHINE_KERNEL_ADDR, %edi
143 /* jump to the real address */
144 movl $multiboot_trampoline, %eax
147 multiboot_trampoline:
148 /* fill the boot information */
155 movl %ebx, EXT_C(grub_install_dos_part)
160 movl %ebx, EXT_C(grub_install_bsd_part)
163 /* enter the usual booting */
167 /* the real mode code continues... */
169 cli /* we're not safe here! */
171 /* set up %ds, %ss, and %es */
177 /* set up the real mode/BIOS stack */
178 movl $GRUB_MEMORY_MACHINE_REAL_STACK, %ebp
181 sti /* we're safe again */
183 /* save boot drive reference */
184 ADDR32 movb %dl, EXT_C(grub_boot_drive)
186 /* reset disk system (%ah = 0) */
189 /* transition to protected mode */
190 DATA32 call real_to_prot
192 /* The ".code32" directive takes GAS out of 16-bit mode. */
196 call EXT_C(grub_gate_a20)
198 /* decompress the compressed part and put the result at 1MB */
200 movl $(START_SYMBOL + GRUB_KERNEL_MACHINE_RAW_SIZE), %edi
203 pushl EXT_C(grub_compressed_size)
205 call lzo1x_decompress
208 /* copy back the decompressed part */
214 /* copy modules before cleaning out the bss */
215 movl EXT_C(grub_total_module_size), %ecx
216 movl EXT_C(grub_kernel_image_size), %esi
218 addl $START_SYMBOL, %esi
220 movl $END_SYMBOL, %edi
227 /* clean out the bss */
228 movl $BSS_START_SYMBOL, %edi
230 /* compute the bss length */
231 movl $END_SYMBOL, %ecx
241 * Call the start of main body of C code.
243 call EXT_C(grub_main)
247 * This is the area for all of the special variables.
250 .p2align 2 /* force 4-byte alignment */
253 .long GRUB_MEMORY_MACHINE_PROT_STACK
255 VARIABLE(grub_boot_drive)
258 VARIABLE(grub_start_addr)
261 VARIABLE(grub_end_addr)
264 VARIABLE(grub_apm_bios_info)
265 .word 0 /* version */
268 .word 0 /* cseg_16 */
269 .word 0 /* dseg_16 */
270 .word 0 /* cseg_len */
271 .word 0 /* cseg_16_len */
272 .word 0 /* dseg_16_len */
275 * This is the Global Descriptor Table
277 * An entry, a "Segment Descriptor", looks like this:
280 * ------------------------------------------------------------
281 * | | |B| |A| | | |1|0|E|W|A| |
282 * | BASE 31..24 |G|/|L|V| LIMIT |P|DPL| TYPE | BASE 23:16 | 4
283 * | | |D| |L| 19..16| | |1|1|C|R|A| |
284 * ------------------------------------------------------------
286 * | BASE 15..0 | LIMIT 15..0 | 0
288 * ------------------------------------------------------------
290 * Note the ordering of the data items is reversed from the above
294 .p2align 2 /* force 4-byte alignment */
299 /* -- code segment --
300 * base = 0x00000000, limit = 0xFFFFF (4 KiB Granularity), present
301 * type = 32bit code execute/read, DPL = 0
304 .byte 0, 0x9A, 0xCF, 0
306 /* -- data segment --
307 * base = 0x00000000, limit 0xFFFFF (4 KiB Granularity), present
308 * type = 32 bit data read/write, DPL = 0
311 .byte 0, 0x92, 0xCF, 0
313 /* -- 16 bit real mode CS --
314 * base = 0x00000000, limit 0x0FFFF (1 B Granularity), present
315 * type = 16 bit code execute/read only/conforming, DPL = 0
320 /* -- 16 bit real mode DS --
321 * base = 0x00000000, limit 0x0FFFF (1 B Granularity), present
322 * type = 16 bit data read/write, DPL = 0
328 /* this is the GDT descriptor */
330 .word 0x27 /* limit */
335 * These next two routines, "real_to_prot" and "prot_to_real" are structured
336 * in a very specific way. Be very careful when changing them.
338 * NOTE: Use of either one messes up %eax and %ebp.
345 /* load the GDT register */
346 DATA32 ADDR32 lgdt gdtdesc
348 /* turn on protected mode */
350 orl $GRUB_MEMORY_MACHINE_CR0_PE_ON, %eax
353 /* jump to relocation, flush prefetch queue, and reload %cs */
354 DATA32 ljmp $GRUB_MEMORY_MACHINE_PROT_MODE_CSEG, $protcseg
358 /* reload other segment registers */
359 movw $GRUB_MEMORY_MACHINE_PROT_MODE_DSEG, %ax
366 /* put the return address in a known safe location */
368 movl %eax, GRUB_MEMORY_MACHINE_REAL_STACK
370 /* get protected mode stack */
375 /* get return address onto the right stack */
376 movl GRUB_MEMORY_MACHINE_REAL_STACK, %eax
382 /* return on the old (or initialized) stack! */
387 /* just in case, set GDT */
390 /* save the protected mode stack */
394 /* get the return address */
396 movl %eax, GRUB_MEMORY_MACHINE_REAL_STACK
398 /* set up new stack */
399 movl $GRUB_MEMORY_MACHINE_REAL_STACK, %eax
403 /* set up segment limits */
404 movw $GRUB_MEMORY_MACHINE_PSEUDO_REAL_DSEG, %ax
411 /* this might be an extra step */
412 /* jump to a 16 bit segment */
413 ljmp $GRUB_MEMORY_MACHINE_PSEUDO_REAL_CSEG, $tmpcseg
418 /* clear the PE bit of CR0 */
420 andl $(~GRUB_MEMORY_MACHINE_CR0_PE_ON), %eax
423 /* flush prefetch queue, reload %cs */
424 DATA32 ljmp $0, $realcseg
427 /* we are in real mode now
428 * set up the real mode segment registers : DS, SS, ES
439 /* restore interrupts */
442 /* return on new stack! */
449 * grub_gate_a20(int on)
451 * Gate address-line 20 for high memory.
453 * This routine is probably overconservative in what it does, but so what?
455 * It also eats any keystrokes in the keyboard buffer. :-(
458 FUNCTION(grub_gate_a20)
461 gate_a20_test_current_state:
462 /* first of all, test if already in a good state */
463 call gate_a20_check_state
465 jnz gate_a20_try_bios
469 /* second, try a BIOS call */
480 DATA32 call real_to_prot
484 call gate_a20_check_state
486 jnz gate_a20_try_keyboard_controller
489 gate_a20_flush_keyboard_buffer:
492 jnz gate_a20_flush_keyboard_buffer
502 gate_a20_try_keyboard_controller:
503 /* third, try the keyboard controller */
504 call gate_a20_flush_keyboard_buffer
518 call gate_a20_flush_keyboard_buffer
520 /* output a dummy command (USB keyboard hack) */
523 call gate_a20_flush_keyboard_buffer
525 call gate_a20_check_state
527 jnz gate_a20_try_system_control_port_a
530 gate_a20_try_system_control_port_a:
531 /* fourth, try the system control port A */
539 /* When turning off Gate A20, do not check the state strictly,
540 because a failure is not fatal usually, and Gate A20 is always
541 on some modern machines. */
544 call gate_a20_check_state
546 /* everything failed, so restart from the beginning */
547 jnz gate_a20_try_bios
550 gate_a20_check_state:
551 /* iterate the checking for a while */
564 /* compare the byte at 0x8000 with that at 0x108000 */
565 movl $GRUB_BOOT_MACHINE_KERNEL_ADDR, %ebx
567 /* save the original byte in CL */
569 /* store the value at 0x108000 in AL */
572 /* try to set one less value at 0x8000 */
580 /* obtain the value at 0x108000 in CH */
584 /* this result is 1 if A20 is on or 0 if it is off */
587 /* restore the original */
598 * This call is special... it never returns... in fact it should simply
599 * hang at this point!
606 * This next part is sort of evil. It takes advantage of the
607 * byte ordering on the x86 to work in either 16-bit or 32-bit
608 * mode, so think about it before changing it.
611 FUNCTION(grub_hard_stop)
613 jmp EXT_C(grub_hard_stop)
619 * Stop the floppy drive from spinning, so that other software is
620 * jumped to with a known state.
622 FUNCTION(grub_stop_floppy)
636 /* Tell the BIOS a boot failure. If this does not work, reboot. */
643 * Reboot the system. At the moment, rely on BIOS.
645 FUNCTION(grub_reboot)
652 ljmp $0xFFFF, $0x0000
656 * grub_halt(int no_apm)
658 * Halt the system, using APM if possible. If NO_APM is true, don't use
659 * APM even if it is available.
673 jc EXT_C(grub_hard_stop)
674 /* don't check %bx for buggy BIOSes... */
676 /* disconnect APM first */
685 jc EXT_C(grub_hard_stop)
687 /* set APM protocol level - 1.1 or bust. (this covers APM 1.2 also) */
692 jc EXT_C(grub_hard_stop)
694 /* set the power state to off */
700 /* shouldn't reach here */
701 jmp EXT_C(grub_hard_stop)
706 * void grub_chainloader_real_boot (int drive, void *part_addr)
708 * This starts another boot loader.
711 FUNCTION(grub_chainloader_real_boot)
715 call EXT_C(grub_dl_unload_all)
717 /* set up to pass boot drive */
720 /* ESI must point to a partition table entry */
723 /* Turn off Gate A20 */
725 call EXT_C(grub_gate_a20)
729 ljmp $0, $GRUB_MEMORY_MACHINE_BOOT_LOADER_ADDR
734 * void grub_linux_boot_zimage (void)
736 VARIABLE(grub_linux_prot_size)
738 VARIABLE(grub_linux_tmp_addr)
740 VARIABLE(grub_linux_real_addr)
743 FUNCTION(grub_linux_boot_zimage)
744 /* copy the kernel */
745 movl EXT_C(grub_linux_prot_size), %ecx
748 movl $GRUB_LINUX_BZIMAGE_ADDR, %esi
749 movl $GRUB_LINUX_ZIMAGE_ADDR, %edi
754 FUNCTION(grub_linux_boot_bzimage)
755 call EXT_C(grub_dl_unload_all)
757 movl EXT_C(grub_linux_real_addr), %ebx
759 /* copy the real mode code */
760 movl EXT_C(grub_linux_tmp_addr), %esi
762 movl $GRUB_LINUX_SETUP_MOVE_SIZE, %ecx
767 /* change %ebx to the segment address */
771 movw %ax, linux_setup_seg
773 /* XXX new stack pointer in safe area for calling functions */
775 call EXT_C(grub_stop_floppy)
777 /* final setup for linux boot */
783 movw $GRUB_LINUX_SETUP_STACK, %sp
799 * This starts the multiboot kernel.
802 FUNCTION(grub_multiboot_real_boot)
803 /* Push the entry address on the stack. */
805 /* Move the address of the multiboot information structure to ebx. */
808 /* Unload all modules and stop the floppy driver. */
809 call EXT_C(grub_dl_unload_all)
810 call EXT_C(grub_stop_floppy)
812 /* Interrupts should be disabled. */
815 /* Move the magic value into eax and jump to the kernel. */
816 movl $GRUB_MB_MAGIC2,%eax
822 * int grub_biosdisk_rw_int13_extensions (int ah, int drive, void *dap)
824 * Call IBM/MS INT13 Extensions (int 13 %ah=AH) for DRIVE. DAP
825 * is passed for disk address packet. If an error occurs, return
826 * non-zero, otherwise zero.
829 FUNCTION(grub_biosdisk_rw_int13_extensions)
833 /* compute the address of disk_address_packet */
836 shrl $4, %ecx /* save the segment to cx */
840 /* enter real mode */
846 int $0x13 /* do the operation */
847 movb %ah, %dl /* save return value */
848 /* clear the data segment */
851 /* back to protected mode */
852 DATA32 call real_to_prot
855 movb %dl, %al /* return value in %eax */
863 * int grub_biosdisk_rw_standard (int ah, int drive, int coff, int hoff,
864 * int soff, int nsec, int segment)
866 * Call standard and old INT13 (int 13 %ah=AH) for DRIVE. Read/write
867 * NSEC sectors from COFF/HOFF/SOFF into SEGMENT. If an error occurs,
868 * return non-zero, otherwise zero.
871 FUNCTION(grub_biosdisk_rw_standard)
879 /* set up CHS information */
881 /* set %ch to low eight bits of cylinder */
883 /* set bits 6-7 of %cl to high two bits of cylinder */
885 /* set bits 0-5 of %cl to sector */
887 /* set %dh to head */
891 /* set %al to NSEC */
893 /* save %ax in %di */
895 /* save SEGMENT in %bx */
898 /* enter real mode */
904 movw $3, %si /* attempt at least three times */
908 int $0x13 /* do the operation */
909 jnc 2f /* check if successful */
911 movb %ah, %bl /* save return value */
912 /* if fail, reset the disk system */
922 /* back to protected mode */
923 DATA32 call real_to_prot
926 movb %bl, %al /* return value in %eax */
937 * int grub_biosdisk_check_int13_extensions (int drive)
939 * Check if LBA is supported for DRIVE. If it is supported, then return
940 * the major version of extensions, otherwise zero.
943 FUNCTION(grub_biosdisk_check_int13_extensions)
949 /* enter real mode */
955 int $0x13 /* do the operation */
957 /* check the result */
962 movb %ah, %bl /* save the major version into %bl */
964 /* check if AH=0x42 is supported */
971 /* back to protected mode */
972 DATA32 call real_to_prot
975 movb %bl, %al /* return value in %eax */
984 * int grub_biosdisk_get_diskinfo_int13_extensions (int drive, void *drp)
986 * Return the geometry of DRIVE in a drive parameters, DRP. If an error
987 * occurs, then return non-zero, otherwise zero.
990 FUNCTION(grub_biosdisk_get_diskinfo_int13_extensions)
995 /* compute the address of drive parameters */
999 movw %dx, %bx /* save the segment into %bx */
1002 /* enter real mode */
1008 int $0x13 /* do the operation */
1009 movb %ah, %bl /* save return value in %bl */
1010 /* clear the data segment */
1013 /* back to protected mode */
1014 DATA32 call real_to_prot
1017 movb %bl, %al /* return value in %eax */
1027 * int grub_biosdisk_get_diskinfo_standard (int drive,
1028 * unsigned long *cylinders,
1029 * unsigned long *heads,
1030 * unsigned long *sectors)
1032 * Return the geometry of DRIVE in CYLINDERS, HEADS and SECTORS. If an
1033 * error occurs, then return non-zero, otherwise zero.
1036 FUNCTION(grub_biosdisk_get_diskinfo_standard)
1041 /* push CYLINDERS */
1045 /* SECTORS is on the stack */
1049 /* enter real mode */
1054 int $0x13 /* do the operation */
1055 /* check if successful */
1058 /* bogus BIOSes may not return an error number */
1059 testb $0x3f, %cl /* 0 sectors means no disk */
1060 jnz 1f /* if non-zero, then succeed */
1061 /* XXX 0x60 is one of the unused error numbers */
1064 movb %ah, %bl /* save return value in %bl */
1065 /* back to protected mode */
1066 DATA32 call real_to_prot
1072 incl %eax /* the number of heads is counted from zero */
1079 shrb $6, %ah /* the number of cylinders is counted from zero */
1084 movl 0x10(%esp), %edi
1090 movb %bl, %al /* return value in %eax */
1100 * int grub_biosdisk_get_num_floppies (void)
1102 FUNCTION(grub_biosdisk_get_num_floppies)
1109 /* reset the disk system first */
1114 /* call GET DISK TYPE */
1120 /* check if this drive exists */
1128 DATA32 call real_to_prot
1138 * grub_get_memsize(i) : return the memory size in KB. i == 0 for conventional
1139 * memory, i == 1 for extended memory
1140 * BIOS call "INT 12H" to get conventional memory size
1141 * BIOS call "INT 15H, AH=88H" to get extended memory size
1142 * Both have the return value in AX.
1146 FUNCTION(grub_get_memsize)
1151 call prot_to_real /* enter real mode */
1167 DATA32 call real_to_prot
1178 * grub_get_eisa_mmap() : return packed EISA memory map, lower 16 bits is
1179 * memory between 1M and 16M in 1K parts, upper 16 bits is
1180 * memory above 16M in 64K parts. If error, return zero.
1181 * BIOS call "INT 15H, AH=E801H" to get EISA memory map,
1182 * AX = memory between 1M and 16M in 1K parts.
1183 * BX = memory above 16M in 64K parts.
1187 FUNCTION(grub_get_eisa_mmap)
1191 call prot_to_real /* enter real mode */
1200 DATA32 call real_to_prot
1215 * grub_get_mmap_entry(addr, cont) : address and old continuation value (zero to
1216 * start), for the Query System Address Map BIOS call.
1218 * Sets the first 4-byte int value of "addr" to the size returned by
1219 * the call. If the call fails, sets it to zero.
1221 * Returns: new (non-zero) continuation value, 0 if done.
1224 FUNCTION(grub_get_mmap_entry)
1233 /* place address (+4) in ES:DI */
1240 /* set continuation value */
1243 /* set default maximum buffer size */
1246 /* set EDX to 'SMAP' */
1247 movl $0x534d4150, %edx
1249 call prot_to_real /* enter real mode */
1258 cmpl $0x534d4150, %eax
1273 DATA32 call real_to_prot
1276 /* write length of buffer (zero if error) into ADDR */
1280 /* set return value to continuation */
1291 * void grub_console_real_putchar (int c)
1293 * Put the character C on the console. Because GRUB wants to write a
1294 * character with an attribute, this implementation is a bit tricky.
1295 * If C is a control character (CR, LF, BEL, BS), use INT 10, AH = 0Eh
1296 * (TELETYPE OUTPUT). Otherwise, save the original position, put a space,
1297 * save the current position, restore the original position, write the
1298 * character and the attribute, and restore the current position.
1300 * The reason why this is so complicated is that there is no easy way to
1301 * get the height of the screen, and the TELETYPE OUPUT BIOS call doesn't
1302 * support setting a background attribute.
1304 FUNCTION(grub_console_real_putchar)
1307 movb EXT_C(grub_console_cur_color), %bl
1314 /* use teletype output if control character */
1324 /* save the character and the attribute on the stack */
1328 /* get the current position */
1332 /* check the column with the width */
1336 /* print CR and LF, if next write will exceed the width */
1342 /* get the current position */
1347 /* restore the character and the attribute */
1351 /* write the character with the attribute */
1356 /* move the cursor forward */
1367 3: DATA32 call real_to_prot
1375 * int grub_console_getkey (void)
1376 * BIOS call "INT 16H Function 00H" to read character from keyboard
1377 * Call with %ah = 0x0
1378 * Return: %ah = keyboard scan code
1379 * %al = ASCII character
1382 /* this table is used in translate_keycode below */
1384 .word GRUB_CONSOLE_KEY_LEFT, 2
1385 .word GRUB_CONSOLE_KEY_RIGHT, 6
1386 .word GRUB_CONSOLE_KEY_UP, 16
1387 .word GRUB_CONSOLE_KEY_DOWN, 14
1388 .word GRUB_CONSOLE_KEY_HOME, 1
1389 .word GRUB_CONSOLE_KEY_END, 5
1390 .word GRUB_CONSOLE_KEY_DC, 4
1391 .word GRUB_CONSOLE_KEY_BACKSPACE, 8
1392 .word GRUB_CONSOLE_KEY_PPAGE, 7
1393 .word GRUB_CONSOLE_KEY_NPAGE, 3
1397 * translate_keycode translates the key code %dx to an ascii code.
1405 movw $ABS(translation_table), %si
1408 /* check if this is the end */
1411 /* load the ascii code into %ax */
1414 /* check if this matches the key code */
1417 /* translate %dx, if successful */
1426 FUNCTION(grub_console_getkey)
1434 movw %ax, %dx /* real_to_prot uses %eax */
1435 call translate_keycode
1437 DATA32 call real_to_prot
1447 * int grub_console_checkkey (void)
1448 * if there is a character pending, return it; otherwise return -1
1449 * BIOS call "INT 16H Function 01H" to check whether a character is pending
1450 * Call with %ah = 0x1
1452 * If key waiting to be input:
1453 * %ah = keyboard scan code
1454 * %al = ASCII character
1459 FUNCTION(grub_console_checkkey)
1463 call prot_to_real /* enter real mode */
1478 DATA32 call real_to_prot
1488 * grub_uint16_t grub_console_getxy (void)
1489 * BIOS call "INT 10H Function 03h" to get cursor position
1490 * Call with %ah = 0x03
1492 * Returns %ch = starting scan line
1493 * %cl = ending scan line
1494 * %dh = row (0 is top)
1495 * %dl = column (0 is left)
1499 FUNCTION(grub_console_getxy)
1501 pushl %ebx /* save EBX */
1506 xorb %bh, %bh /* set page to 0 */
1508 int $0x10 /* get cursor position */
1510 DATA32 call real_to_prot
1522 * void grub_console_gotoxy(grub_uint8_t x, grub_uint8_t y)
1523 * BIOS call "INT 10H Function 02h" to set cursor position
1524 * Call with %ah = 0x02
1526 * %dh = row (0 is top)
1527 * %dl = column (0 is left)
1531 FUNCTION(grub_console_gotoxy)
1533 pushl %ebx /* save EBX */
1535 movb %dl, %dh /* %dh = y */
1536 movb %al, %dl /* %dl = x */
1541 xorb %bh, %bh /* set page to 0 */
1543 int $0x10 /* set cursor position */
1545 DATA32 call real_to_prot
1554 * void grub_console_cls (void)
1555 * BIOS call "INT 10H Function 09h" to write character and attribute
1556 * Call with %ah = 0x09
1558 * %bh = (page number)
1560 * %cx = (number of times)
1563 FUNCTION(grub_console_cls)
1565 pushl %ebx /* save EBX */
1570 /* move the cursor to the beginning */
1576 /* write spaces to the entire screen */
1579 movw $(80 * 25), %cx
1582 /* move back the cursor */
1586 DATA32 call real_to_prot
1595 * void grub_console_setcursor (int on)
1596 * BIOS call "INT 10H Function 01h" to set cursor type
1597 * Call with %ah = 0x01
1598 * %ch = cursor starting scanline
1599 * %cl = cursor ending scanline
1602 console_cursor_state:
1604 console_cursor_shape:
1607 FUNCTION(grub_console_setcursor)
1614 /* check if the standard cursor shape has already been saved */
1615 movw console_cursor_shape, %ax
1626 DATA32 call real_to_prot
1629 movw %cx, console_cursor_shape
1631 /* set %cx to the designated cursor shape */
1636 movw console_cursor_shape, %cx
1644 DATA32 call real_to_prot
1653 * if a seconds value can be read, read it and return it (BCD),
1654 * otherwise return 0xFF
1655 * BIOS call "INT 1AH Function 02H" to check whether a character is pending
1656 * Call with %ah = 0x2
1658 * If RT Clock can give correct values
1660 * %cl = minutes (BCD)
1661 * %dh = seconds (BCD)
1662 * %dl = daylight savings time (00h std, 01h daylight)
1663 * Carry flag = clear
1666 * (this indicates that the clock is updating, or
1667 * that it isn't running)
1669 FUNCTION(grub_getrtsecs)
1672 call prot_to_real /* enter real mode */
1683 DATA32 call real_to_prot
1694 * return the real time in ticks, of which there are about
1697 FUNCTION(grub_get_rtc)
1700 call prot_to_real /* enter real mode */
1703 /* %ax is already zero */
1706 DATA32 call real_to_prot
1718 * unsigned char grub_vga_set_mode (unsigned char mode)
1720 FUNCTION(grub_vga_set_mode)
1727 /* get current mode */
1733 /* set the new mode */
1738 DATA32 call real_to_prot
1748 * unsigned char *grub_vga_get_font (void)
1750 FUNCTION(grub_vga_get_font)
1761 DATA32 call real_to_prot
1774 * grub_vbe_bios_status_t grub_vbe_get_controller_info (struct grub_vbe_info_block *controller_info)
1776 * Register allocations for parameters:
1777 * %eax *controller_info
1779 FUNCTION(grub_vbe_bios_get_controller_info)
1784 movw %ax, %di /* Store *controller_info to %edx:%di. */
1787 mov %eax, %edx /* prot_to_real destroys %eax. */
1794 movw %dx, %es /* *controller_info is now on %es:%di. */
1798 movw %ax, %dx /* real_to_prot destroys %eax. */
1802 DATA32 call real_to_prot
1806 andl $0x0FFFF, %eax /* Return value in %eax. */
1814 * grub_vbe_status_t grub_vbe_bios_get_mode_info (grub_uint32_t mode,
1815 * struct grub_vbe_mode_info_block *mode_info)
1817 * Register allocations for parameters:
1821 FUNCTION(grub_vbe_bios_get_mode_info)
1825 movl %eax, %ecx /* Store mode number to %ecx. */
1827 movw %dx, %di /* Store *mode_info to %edx:%di. */
1836 movw %dx, %es /* *mode_info is now on %es:%di. */
1840 movw %ax, %dx /* real_to_prot destroys %eax. */
1844 DATA32 call real_to_prot
1848 andl $0x0FFFF, %eax /* Return value in %eax. */
1855 * grub_vbe_status_t grub_vbe_bios_set_mode (grub_uint32_t mode,
1856 * struct grub_vbe_crtc_info_block *crtc_info)
1858 * Register allocations for parameters:
1862 FUNCTION(grub_vbe_bios_set_mode)
1867 movl %eax, %ebx /* Store mode in %ebx. */
1869 movw %dx, %di /* Store *crtc_info to %edx:%di. */
1878 movw %dx, %es /* *crtc_info is now on %es:%di. */
1883 movw %ax, %dx /* real_to_prot destroys %eax. */
1887 DATA32 call real_to_prot
1891 andl $0xFFFF, %eax /* Return value in %eax. */
1899 * grub_vbe_status_t grub_vbe_bios_get_mode (grub_uint32_t *mode)
1901 * Register allocations for parameters:
1904 FUNCTION(grub_vbe_bios_get_mode)
1909 pushl %eax /* Push *mode to stack. */
1917 movw %ax, %dx /* real_to_prot destroys %eax. */
1919 DATA32 call real_to_prot
1922 popl %edi /* Pops *mode from stack to %edi. */
1927 andl $0xFFFF, %eax /* Return value in %eax. */
1936 * grub_vbe_status_t grub_vbe_bios_set_memory_window (grub_uint32_t window,
1937 * grub_uint32_t position);
1939 * Register allocations for parameters:
1943 FUNCTION(grub_vbe_bios_set_memory_window)
1953 andw $0x00ff, %bx /* BL = window, BH = 0, Set memory window. */
1956 movw %ax, %dx /* real_to_prot destroys %eax. */
1958 DATA32 call real_to_prot
1962 andl $0xFFFF, %eax /* Return value in %eax. */
1969 * grub_vbe_status_t grub_vbe_bios_get_memory_window (grub_uint32_t window,
1970 * grub_uint32_t *position);
1972 * Register allocations for parameters:
1976 FUNCTION(grub_vbe_bios_get_memory_window)
1980 pushl %edx /* Push *position to stack. */
1982 movl %eax, %ebx /* Store window in %ebx. */
1988 andw $0x00ff, %bx /* BL = window. */
1989 orw $0x0100, %bx /* BH = 1, Get memory window. */
1992 movw %ax, %bx /* real_to_prot destroys %eax. */
1994 DATA32 call real_to_prot
1997 popl %edi /* pops *position from stack to %edi. */
1999 movl %edx, (%edi) /* Return position to caller. */
2002 andl $0xFFFF, %eax /* Return value in %eax. */
2010 * grub_vbe_status_t grub_vbe_bios_set_scanline_length (grub_uint32_t length)
2012 * Register allocations for parameters:
2015 FUNCTION(grub_vbe_bios_set_scanline_length)
2020 movl %eax, %ecx /* Store length in %ecx. */
2026 movw $0x0002, %bx /* BL = 2, Set Scan Line in Bytes. */
2029 movw %ax, %dx /* real_to_prot destroys %eax. */
2031 DATA32 call real_to_prot
2035 andl $0xFFFF, %eax /* Return value in %eax. */
2043 * grub_vbe_status_t grub_vbe_bios_get_scanline_length (grub_uint32_t *length)
2045 * Register allocations for parameters:
2048 FUNCTION(grub_vbe_bios_get_scanline_length)
2052 pushl %edx /* Push *length to stack. */
2058 movw $0x0001, %bx /* BL = 1, Get Scan Line Length (in bytes). */
2061 movw %ax, %dx /* real_to_prot destroys %eax. */
2063 DATA32 call real_to_prot
2066 popl %edi /* Pops *length from stack to %edi. */
2068 movl %ebx, (%edi) /* Return length to caller. */
2071 andl $0xFFFF, %eax /* Return value in %eax. */
2079 * grub_vbe_status_t grub_vbe_bios_set_display_start (grub_uint32_t x,
2082 * Register allocations for parameters:
2086 FUNCTION(grub_vbe_bios_set_display_start)
2090 movl %eax, %ecx /* Store x in %ecx. */
2096 movw $0x0080, %bx /* BL = 80h, Set Display Start
2097 during Vertical Retrace. */
2100 movw %ax, %dx /* real_to_prot destroys %eax. */
2102 DATA32 call real_to_prot
2106 andl $0xFFFF, %eax /* Return value in %eax. */
2113 * grub_vbe_status_t grub_vbe_bios_get_display_start (grub_uint32_t *x,
2116 * Register allocations for parameters:
2120 FUNCTION(grub_vbe_bios_get_display_start)
2124 pushl %eax /* Push *x to stack. */
2125 pushl %edx /* Push *y to stack. */
2131 movw $0x0001, %bx /* BL = 1, Get Display Start. */
2134 movw %ax, %bx /* real_to_prot destroys %eax. */
2136 DATA32 call real_to_prot
2139 popl %edi /* Pops *y from stack to %edi. */
2141 movl %edx, (%edi) /* Return y-position to caller. */
2143 popl %edi /* Pops *x from stack to %edi. */
2145 movl %ecx, (%edi) /* Return x-position to caller. */
2148 andl $0xFFFF, %eax /* Return value in %eax. */
2156 * grub_vbe_status_t grub_vbe_bios_set_palette_data (grub_uint32_t color_count,
2157 * grub_uint32_t start_index,
2158 * struct grub_vbe_palette_data *palette_data)
2160 * Register allocations for parameters:
2163 * %ecx *palette_data
2165 FUNCTION(grub_vbe_bios_set_palette_data)
2170 movl %eax, %ebx /* Store color_count in %ebx. */
2172 movw %cx, %di /* Store *palette_data to %ecx:%di. */
2181 movw %cx, %es /* *palette_data is now on %es:%di. */
2182 movw %bx, %cx /* color_count is now on %cx. */
2185 xorw %bx, %bx /* BL = 0, Set Palette Data. */
2188 movw %ax, %dx /* real_to_prot destroys %eax. */
2192 DATA32 call real_to_prot
2196 andl $0xFFFF, %eax /* Return value in %eax. */