5c9f8d8427
Fix memory corruption issue (spotted by Colin Watson). * kern/i386/pc/startup.S (grub_vbe_bios_getset_dac_palette): Fix bug causing returned size to be stored in an incorrect memory location. Fix use of uninitialized value when storing the returned size.
2146 lines
39 KiB
ArmAsm
2146 lines
39 KiB
ArmAsm
/*
|
|
* GRUB -- GRand Unified Bootloader
|
|
* Copyright (C) 1999,2000,2001,2002,2003,2005,2006,2007,2008 Free Software Foundation, Inc.
|
|
*
|
|
* GRUB is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* GRUB is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
|
|
/*
|
|
* Note: These functions defined in this file may be called from C.
|
|
* Be careful of that you must not modify some registers. Quote
|
|
* from gcc-2.95.2/gcc/config/i386/i386.h:
|
|
|
|
1 for registers not available across function calls.
|
|
These must include the FIXED_REGISTERS and also any
|
|
registers that can be used without being saved.
|
|
The latter must include the registers where values are returned
|
|
and the register where structure-value addresses are passed.
|
|
Aside from that, you can include as many other registers as you like.
|
|
|
|
ax,dx,cx,bx,si,di,bp,sp,st,st1,st2,st3,st4,st5,st6,st7,arg
|
|
{ 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }
|
|
*/
|
|
|
|
/*
|
|
* Note: GRUB is compiled with the options -mrtd and -mregparm=3.
|
|
* So the first three arguments are passed in %eax, %edx, and %ecx,
|
|
* respectively, and if a function has a fixed number of arguments
|
|
* and the number is greater than three, the function must return
|
|
* with "ret $N" where N is ((the number of arguments) - 3) * 4.
|
|
*/
|
|
|
|
#include <config.h>
|
|
#include <grub/symbol.h>
|
|
#include <grub/boot.h>
|
|
#include <grub/machine/boot.h>
|
|
#include <grub/machine/memory.h>
|
|
#include <grub/machine/console.h>
|
|
#include <grub/cpu/linux.h>
|
|
#include <grub/machine/kernel.h>
|
|
#include <grub/term.h>
|
|
#include <multiboot.h>
|
|
#include <multiboot2.h>
|
|
|
|
#define ABS(x) ((x) - _start + GRUB_BOOT_MACHINE_KERNEL_ADDR + 0x200)
|
|
|
|
.file "startup.S"
|
|
|
|
.text
|
|
|
|
/* Tell GAS to generate 16-bit instructions so that this code works
|
|
in real mode. */
|
|
.code16
|
|
|
|
.globl start, _start
|
|
start:
|
|
_start:
|
|
/*
|
|
* Guarantee that "main" is loaded at 0x0:0x8200.
|
|
*/
|
|
#ifdef APPLE_CC
|
|
codestart_abs = ABS(codestart) - 0x10000
|
|
ljmp $0, $(codestart_abs)
|
|
#else
|
|
ljmp $0, $ABS(codestart)
|
|
#endif
|
|
|
|
/*
|
|
* Compatibility version number
|
|
*
|
|
* These MUST be at byte offset 6 and 7 of the executable
|
|
* DO NOT MOVE !!!
|
|
*/
|
|
. = _start + 0x6
|
|
.byte GRUB_BOOT_VERSION_MAJOR, GRUB_BOOT_VERSION_MINOR
|
|
|
|
/*
|
|
* This is a special data area 8 bytes from the beginning.
|
|
*/
|
|
|
|
. = _start + 0x8
|
|
|
|
VARIABLE(grub_total_module_size)
|
|
.long 0
|
|
VARIABLE(grub_kernel_image_size)
|
|
.long 0
|
|
VARIABLE(grub_compressed_size)
|
|
.long 0
|
|
VARIABLE(grub_install_dos_part)
|
|
.long 0xFFFFFFFF
|
|
VARIABLE(grub_install_bsd_part)
|
|
.long 0xFFFFFFFF
|
|
VARIABLE(grub_prefix)
|
|
/* to be filled by grub-mkimage */
|
|
|
|
/*
|
|
* Leave some breathing room for the prefix.
|
|
*/
|
|
|
|
. = _start + GRUB_KERNEL_MACHINE_DATA_END
|
|
|
|
#ifdef APPLE_CC
|
|
bss_start:
|
|
.long 0
|
|
bss_end:
|
|
.long 0
|
|
#endif
|
|
|
|
/*
|
|
* Support for booting GRUB from a Multiboot boot loader (e.g. GRUB itself).
|
|
* This uses the a.out kludge to load raw binary to the area starting at 1MB,
|
|
* and relocates itself after loaded.
|
|
*/
|
|
.p2align 2 /* force 4-byte alignment */
|
|
multiboot_header:
|
|
/* magic */
|
|
.long 0x1BADB002
|
|
/* flags */
|
|
.long (1 << 16)
|
|
/* checksum */
|
|
.long -0x1BADB002 - (1 << 16)
|
|
/* header addr */
|
|
.long multiboot_header - _start + 0x100000 + 0x200
|
|
/* load addr */
|
|
.long 0x100000
|
|
/* load end addr */
|
|
.long 0
|
|
/* bss end addr */
|
|
.long 0
|
|
/* entry addr */
|
|
.long multiboot_entry - _start + 0x100000 + 0x200
|
|
|
|
multiboot_entry:
|
|
.code32
|
|
/* obtain the boot device */
|
|
movl 12(%ebx), %edx
|
|
|
|
/* relocate the code */
|
|
movl $(GRUB_KERNEL_MACHINE_RAW_SIZE + 0x200), %ecx
|
|
addl EXT_C(grub_compressed_size) - _start + 0x100000 + 0x200, %ecx
|
|
movl $0x100000, %esi
|
|
movl $GRUB_BOOT_MACHINE_KERNEL_ADDR, %edi
|
|
cld
|
|
rep
|
|
movsb
|
|
/* jump to the real address */
|
|
movl $multiboot_trampoline, %eax
|
|
jmp *%eax
|
|
|
|
multiboot_trampoline:
|
|
/* fill the boot information */
|
|
movl %edx, %eax
|
|
shrl $8, %eax
|
|
xorl %ebx, %ebx
|
|
cmpb $0xFF, %ah
|
|
je 1f
|
|
movb %ah, %bl
|
|
movl %ebx, EXT_C(grub_install_dos_part)
|
|
1:
|
|
cmpb $0xFF, %al
|
|
je 2f
|
|
movb %al, %bl
|
|
movl %ebx, EXT_C(grub_install_bsd_part)
|
|
2:
|
|
shrl $24, %edx
|
|
movb $0xFF, %dh
|
|
/* enter the usual booting */
|
|
call prot_to_real
|
|
.code16
|
|
|
|
/* the real mode code continues... */
|
|
codestart:
|
|
cli /* we're not safe here! */
|
|
|
|
/* set up %ds, %ss, and %es */
|
|
xorw %ax, %ax
|
|
movw %ax, %ds
|
|
movw %ax, %ss
|
|
movw %ax, %es
|
|
|
|
/* set up the real mode/BIOS stack */
|
|
movl $GRUB_MEMORY_MACHINE_REAL_STACK, %ebp
|
|
movl %ebp, %esp
|
|
|
|
sti /* we're safe again */
|
|
|
|
/* save the boot drive */
|
|
ADDR32 movb %dl, EXT_C(grub_boot_drive)
|
|
|
|
/* reset disk system (%ah = 0) */
|
|
int $0x13
|
|
|
|
/* transition to protected mode */
|
|
DATA32 call real_to_prot
|
|
|
|
/* The ".code32" directive takes GAS out of 16-bit mode. */
|
|
.code32
|
|
|
|
incl %eax
|
|
call EXT_C(grub_gate_a20)
|
|
|
|
#ifdef ENABLE_LZMA
|
|
movl $GRUB_MEMORY_MACHINE_DECOMPRESSION_ADDR, %edi
|
|
movl $(_start + GRUB_KERNEL_MACHINE_RAW_SIZE), %esi
|
|
pushl %edi
|
|
pushl %esi
|
|
movl EXT_C(grub_kernel_image_size), %ecx
|
|
addl EXT_C(grub_total_module_size), %ecx
|
|
subl $GRUB_KERNEL_MACHINE_RAW_SIZE, %ecx
|
|
pushl %ecx
|
|
leal (%edi, %ecx), %ebx
|
|
call _LzmaDecodeA
|
|
/* _LzmaDecodeA clears DF, so no need to run cld */
|
|
popl %ecx
|
|
popl %edi
|
|
popl %esi
|
|
#endif
|
|
|
|
/* copy back the decompressed part (except the modules) */
|
|
subl EXT_C(grub_total_module_size), %ecx
|
|
rep
|
|
movsb
|
|
|
|
#if 0
|
|
/* copy modules before cleaning out the bss */
|
|
movl EXT_C(grub_total_module_size), %ecx
|
|
movl EXT_C(grub_kernel_image_size), %esi
|
|
addl %ecx, %esi
|
|
addl $_start, %esi
|
|
decl %esi
|
|
movl $END_SYMBOL, %edi
|
|
addl %ecx, %edi
|
|
decl %edi
|
|
std
|
|
rep
|
|
movsb
|
|
#endif
|
|
|
|
#ifdef APPLE_CC
|
|
/* clean out the bss */
|
|
bss_start_abs = ABS (bss_start)
|
|
bss_end_abs = ABS (bss_end)
|
|
|
|
movl bss_start_abs, %edi
|
|
|
|
/* compute the bss length */
|
|
movl bss_end_abs, %ecx
|
|
subl %edi, %ecx
|
|
#else
|
|
/* clean out the bss */
|
|
movl $BSS_START_SYMBOL, %edi
|
|
|
|
/* compute the bss length */
|
|
movl $END_SYMBOL, %ecx
|
|
subl %edi, %ecx
|
|
#endif
|
|
|
|
/* clean out */
|
|
xorl %eax, %eax
|
|
cld
|
|
rep
|
|
stosb
|
|
|
|
/*
|
|
* Call the start of main body of C code.
|
|
*/
|
|
call EXT_C(grub_main)
|
|
|
|
/*
|
|
* This is the area for all of the special variables.
|
|
*/
|
|
|
|
VARIABLE(grub_boot_drive)
|
|
.byte 0
|
|
|
|
.p2align 2 /* force 4-byte alignment */
|
|
|
|
#include "../realmode.S"
|
|
|
|
/*
|
|
* grub_gate_a20(int on)
|
|
*
|
|
* Gate address-line 20 for high memory.
|
|
*
|
|
* This routine is probably overconservative in what it does, but so what?
|
|
*
|
|
* It also eats any keystrokes in the keyboard buffer. :-(
|
|
*/
|
|
|
|
FUNCTION(grub_gate_a20)
|
|
movl %eax, %edx
|
|
|
|
gate_a20_test_current_state:
|
|
/* first of all, test if already in a good state */
|
|
call gate_a20_check_state
|
|
cmpb %al, %dl
|
|
jnz gate_a20_try_bios
|
|
ret
|
|
|
|
gate_a20_try_bios:
|
|
/* second, try a BIOS call */
|
|
pushl %ebp
|
|
call prot_to_real
|
|
|
|
.code16
|
|
movw $0x2400, %ax
|
|
testb %dl, %dl
|
|
jz 1f
|
|
incw %ax
|
|
1: int $0x15
|
|
|
|
DATA32 call real_to_prot
|
|
.code32
|
|
|
|
popl %ebp
|
|
call gate_a20_check_state
|
|
cmpb %al, %dl
|
|
jnz gate_a20_try_system_control_port_a
|
|
ret
|
|
|
|
gate_a20_try_system_control_port_a:
|
|
/*
|
|
* In macbook, the keyboard test would hang the machine, so we move
|
|
* this forward.
|
|
*/
|
|
/* fourth, try the system control port A */
|
|
inb $0x92
|
|
andb $(~0x03), %al
|
|
testb %dl, %dl
|
|
jz 6f
|
|
orb $0x02, %al
|
|
6: outb $0x92
|
|
|
|
/* When turning off Gate A20, do not check the state strictly,
|
|
because a failure is not fatal usually, and Gate A20 is always
|
|
on some modern machines. */
|
|
testb %dl, %dl
|
|
jz 7f
|
|
call gate_a20_check_state
|
|
cmpb %al, %dl
|
|
jnz gate_a20_try_keyboard_controller
|
|
7: ret
|
|
|
|
gate_a20_flush_keyboard_buffer:
|
|
inb $0x64
|
|
andb $0x02, %al
|
|
jnz gate_a20_flush_keyboard_buffer
|
|
2:
|
|
inb $0x64
|
|
andb $0x01, %al
|
|
jz 3f
|
|
inb $0x60
|
|
jmp 2b
|
|
3:
|
|
ret
|
|
|
|
gate_a20_try_keyboard_controller:
|
|
/* third, try the keyboard controller */
|
|
call gate_a20_flush_keyboard_buffer
|
|
|
|
movb $0xd1, %al
|
|
outb $0x64
|
|
4:
|
|
inb $0x64
|
|
andb $0x02, %al
|
|
jnz 4b
|
|
|
|
movb $0xdd, %al
|
|
testb %dl, %dl
|
|
jz 5f
|
|
orb $0x02, %al
|
|
5: outb $0x60
|
|
call gate_a20_flush_keyboard_buffer
|
|
|
|
/* output a dummy command (USB keyboard hack) */
|
|
movb $0xff, %al
|
|
outb $0x64
|
|
call gate_a20_flush_keyboard_buffer
|
|
|
|
call gate_a20_check_state
|
|
cmpb %al, %dl
|
|
/* everything failed, so restart from the beginning */
|
|
jnz gate_a20_try_bios
|
|
ret
|
|
|
|
gate_a20_check_state:
|
|
/* iterate the checking for a while */
|
|
movl $100, %ecx
|
|
1:
|
|
call 3f
|
|
cmpb %al, %dl
|
|
jz 2f
|
|
loop 1b
|
|
2:
|
|
ret
|
|
3:
|
|
pushl %ebx
|
|
pushl %ecx
|
|
xorl %eax, %eax
|
|
/* compare the byte at 0x8000 with that at 0x108000 */
|
|
movl $GRUB_BOOT_MACHINE_KERNEL_ADDR, %ebx
|
|
pushl %ebx
|
|
/* save the original byte in CL */
|
|
movb (%ebx), %cl
|
|
/* store the value at 0x108000 in AL */
|
|
addl $0x100000, %ebx
|
|
movb (%ebx), %al
|
|
/* try to set one less value at 0x8000 */
|
|
popl %ebx
|
|
movb %al, %ch
|
|
decb %ch
|
|
movb %ch, (%ebx)
|
|
/* serialize */
|
|
outb %al, $0x80
|
|
outb %al, $0x80
|
|
/* obtain the value at 0x108000 in CH */
|
|
pushl %ebx
|
|
addl $0x100000, %ebx
|
|
movb (%ebx), %ch
|
|
/* this result is 1 if A20 is on or 0 if it is off */
|
|
subb %ch, %al
|
|
xorb $1, %al
|
|
/* restore the original */
|
|
popl %ebx
|
|
movb %cl, (%ebx)
|
|
popl %ecx
|
|
popl %ebx
|
|
ret
|
|
|
|
#ifdef ENABLE_LZMA
|
|
#include "lzma_decode.S"
|
|
#endif
|
|
|
|
/*
|
|
* The code beyond this point is compressed. Assert that the uncompressed
|
|
* code fits GRUB_KERNEL_MACHINE_RAW_SIZE.
|
|
*/
|
|
. = _start + GRUB_KERNEL_MACHINE_RAW_SIZE
|
|
|
|
/*
|
|
* This next part is sort of evil. It takes advantage of the
|
|
* byte ordering on the x86 to work in either 16-bit or 32-bit
|
|
* mode, so think about it before changing it.
|
|
*/
|
|
|
|
FUNCTION(grub_hard_stop)
|
|
hlt
|
|
jmp EXT_C(grub_hard_stop)
|
|
|
|
|
|
/*
|
|
* grub_stop_floppy()
|
|
*
|
|
* Stop the floppy drive from spinning, so that other software is
|
|
* jumped to with a known state.
|
|
*/
|
|
FUNCTION(grub_stop_floppy)
|
|
movw $0x3F2, %dx
|
|
xorb %al, %al
|
|
outb %al, %dx
|
|
ret
|
|
|
|
/*
|
|
* grub_exit()
|
|
*
|
|
* Exit the system.
|
|
*/
|
|
FUNCTION(grub_exit)
|
|
call prot_to_real
|
|
.code16
|
|
/* Tell the BIOS a boot failure. If this does not work, reboot. */
|
|
int $0x18
|
|
jmp cold_reboot
|
|
.code32
|
|
|
|
/*
|
|
* grub_reboot()
|
|
*
|
|
* Reboot the system. At the moment, rely on BIOS.
|
|
*/
|
|
FUNCTION(grub_reboot)
|
|
call prot_to_real
|
|
.code16
|
|
cold_reboot:
|
|
/* cold boot */
|
|
movw $0x0472, %di
|
|
movw %ax, (%di)
|
|
ljmp $0xFFFF, $0x0000
|
|
.code32
|
|
|
|
/*
|
|
* grub_halt(int no_apm)
|
|
*
|
|
* Halt the system, using APM if possible. If NO_APM is true, don't use
|
|
* APM even if it is available.
|
|
*/
|
|
FUNCTION(grub_halt)
|
|
/* see if zero */
|
|
testl %eax, %eax
|
|
jnz EXT_C(grub_stop)
|
|
|
|
call prot_to_real
|
|
.code16
|
|
|
|
/* detect APM */
|
|
movw $0x5300, %ax
|
|
xorw %bx, %bx
|
|
int $0x15
|
|
jc EXT_C(grub_hard_stop)
|
|
/* don't check %bx for buggy BIOSes... */
|
|
|
|
/* disconnect APM first */
|
|
movw $0x5304, %ax
|
|
xorw %bx, %bx
|
|
int $0x15
|
|
|
|
/* connect APM */
|
|
movw $0x5301, %ax
|
|
xorw %bx, %bx
|
|
int $0x15
|
|
jc EXT_C(grub_hard_stop)
|
|
|
|
/* set APM protocol level - 1.1 or bust. (this covers APM 1.2 also) */
|
|
movw $0x530E, %ax
|
|
xorw %bx, %bx
|
|
movw $0x0101, %cx
|
|
int $0x15
|
|
jc EXT_C(grub_hard_stop)
|
|
|
|
/* set the power state to off */
|
|
movw $0x5307, %ax
|
|
movw $1, %bx
|
|
movw $3, %cx
|
|
int $0x15
|
|
|
|
/* shouldn't reach here */
|
|
jmp EXT_C(grub_hard_stop)
|
|
.code32
|
|
|
|
|
|
/*
|
|
* void grub_chainloader_real_boot (int drive, void *part_addr)
|
|
*
|
|
* This starts another boot loader.
|
|
*/
|
|
|
|
FUNCTION(grub_chainloader_real_boot)
|
|
pushl %edx
|
|
pushl %eax
|
|
|
|
call EXT_C(grub_dl_unload_all)
|
|
|
|
/* Turn off Gate A20 */
|
|
xorl %eax, %eax
|
|
call EXT_C(grub_gate_a20)
|
|
|
|
/* set up to pass boot drive */
|
|
popl %edx
|
|
|
|
/* ESI must point to a partition table entry */
|
|
popl %esi
|
|
|
|
call prot_to_real
|
|
.code16
|
|
ljmp $0, $GRUB_MEMORY_MACHINE_BOOT_LOADER_ADDR
|
|
.code32
|
|
|
|
#include "../loader.S"
|
|
|
|
/*
|
|
* int grub_biosdisk_rw_int13_extensions (int ah, int drive, void *dap)
|
|
*
|
|
* Call IBM/MS INT13 Extensions (int 13 %ah=AH) for DRIVE. DAP
|
|
* is passed for disk address packet. If an error occurs, return
|
|
* non-zero, otherwise zero.
|
|
*/
|
|
|
|
FUNCTION(grub_biosdisk_rw_int13_extensions)
|
|
pushl %ebp
|
|
pushl %esi
|
|
|
|
/* compute the address of disk_address_packet */
|
|
movw %cx, %si
|
|
xorw %cx, %cx
|
|
shrl $4, %ecx /* save the segment to cx */
|
|
|
|
/* ah */
|
|
movb %al, %dh
|
|
/* enter real mode */
|
|
call prot_to_real
|
|
|
|
.code16
|
|
movb %dh, %ah
|
|
movw %cx, %ds
|
|
int $0x13 /* do the operation */
|
|
movb %ah, %dl /* save return value */
|
|
/* back to protected mode */
|
|
DATA32 call real_to_prot
|
|
.code32
|
|
|
|
movb %dl, %al /* return value in %eax */
|
|
|
|
popl %esi
|
|
popl %ebp
|
|
|
|
ret
|
|
|
|
/*
|
|
* int grub_biosdisk_rw_standard (int ah, int drive, int coff, int hoff,
|
|
* int soff, int nsec, int segment)
|
|
*
|
|
* Call standard and old INT13 (int 13 %ah=AH) for DRIVE. Read/write
|
|
* NSEC sectors from COFF/HOFF/SOFF into SEGMENT. If an error occurs,
|
|
* return non-zero, otherwise zero.
|
|
*/
|
|
|
|
FUNCTION(grub_biosdisk_rw_standard)
|
|
pushl %ebp
|
|
movl %esp, %ebp
|
|
|
|
pushl %ebx
|
|
pushl %edi
|
|
pushl %esi
|
|
|
|
/* set up CHS information */
|
|
|
|
/* set %ch to low eight bits of cylinder */
|
|
xchgb %cl, %ch
|
|
/* set bits 6-7 of %cl to high two bits of cylinder */
|
|
shlb $6, %cl
|
|
/* set bits 0-5 of %cl to sector */
|
|
addb 0xc(%ebp), %cl
|
|
/* set %dh to head */
|
|
movb 0x8(%ebp), %dh
|
|
/* set %ah to AH */
|
|
movb %al, %ah
|
|
/* set %al to NSEC */
|
|
movb 0x10(%ebp), %al
|
|
/* save %ax in %di */
|
|
movw %ax, %di
|
|
/* save SEGMENT in %bx */
|
|
movw 0x14(%ebp), %bx
|
|
|
|
/* enter real mode */
|
|
call prot_to_real
|
|
|
|
.code16
|
|
movw %bx, %es
|
|
xorw %bx, %bx
|
|
movw $3, %si /* attempt at least three times */
|
|
|
|
1:
|
|
movw %di, %ax
|
|
int $0x13 /* do the operation */
|
|
jnc 2f /* check if successful */
|
|
|
|
movb %ah, %bl /* save return value */
|
|
/* if fail, reset the disk system */
|
|
xorw %ax, %ax
|
|
int $0x13
|
|
|
|
decw %si
|
|
cmpw $0, %si
|
|
je 2f
|
|
xorb %bl, %bl
|
|
jmp 1b /* retry */
|
|
2:
|
|
/* back to protected mode */
|
|
DATA32 call real_to_prot
|
|
.code32
|
|
|
|
movb %bl, %al /* return value in %eax */
|
|
|
|
popl %esi
|
|
popl %edi
|
|
popl %ebx
|
|
popl %ebp
|
|
|
|
ret $(4 * 4)
|
|
|
|
|
|
/*
|
|
* int grub_biosdisk_check_int13_extensions (int drive)
|
|
*
|
|
* Check if LBA is supported for DRIVE. If it is supported, then return
|
|
* the major version of extensions, otherwise zero.
|
|
*/
|
|
|
|
FUNCTION(grub_biosdisk_check_int13_extensions)
|
|
pushl %ebp
|
|
pushl %ebx
|
|
|
|
/* drive */
|
|
movb %al, %dl
|
|
/* enter real mode */
|
|
call prot_to_real
|
|
|
|
.code16
|
|
movb $0x41, %ah
|
|
movw $0x55aa, %bx
|
|
int $0x13 /* do the operation */
|
|
|
|
/* check the result */
|
|
jc 1f
|
|
cmpw $0xaa55, %bx
|
|
jne 1f
|
|
|
|
movb %ah, %bl /* save the major version into %bl */
|
|
|
|
/* check if AH=0x42 is supported */
|
|
andw $1, %cx
|
|
jnz 2f
|
|
|
|
1:
|
|
xorb %bl, %bl
|
|
2:
|
|
/* back to protected mode */
|
|
DATA32 call real_to_prot
|
|
.code32
|
|
|
|
movb %bl, %al /* return value in %eax */
|
|
|
|
popl %ebx
|
|
popl %ebp
|
|
|
|
ret
|
|
|
|
|
|
/*
|
|
* int grub_biosdisk_get_cdinfo_int13_extensions (int drive, void *cdrp)
|
|
*
|
|
* Return the cdrom information of DRIVE in CDRP. If an error occurs,
|
|
* then return non-zero, otherwise zero.
|
|
*/
|
|
|
|
FUNCTION(grub_biosdisk_get_cdinfo_int13_extensions)
|
|
movw $0x4B01, %cx
|
|
jmp 1f
|
|
|
|
/*
|
|
* int grub_biosdisk_get_diskinfo_int13_extensions (int drive, void *drp)
|
|
*
|
|
* Return the geometry of DRIVE in a drive parameters, DRP. If an error
|
|
* occurs, then return non-zero, otherwise zero.
|
|
*/
|
|
|
|
FUNCTION(grub_biosdisk_get_diskinfo_int13_extensions)
|
|
movb $0x48, %ch
|
|
1:
|
|
pushl %ebp
|
|
pushl %ebx
|
|
pushl %esi
|
|
|
|
/* compute the address of drive parameters */
|
|
movw %dx, %si
|
|
andl $0xf, %esi
|
|
shrl $4, %edx
|
|
movw %dx, %bx /* save the segment into %bx */
|
|
/* drive */
|
|
movb %al, %dl
|
|
/* enter real mode */
|
|
call prot_to_real
|
|
|
|
.code16
|
|
movw %cx, %ax
|
|
movw %bx, %ds
|
|
int $0x13 /* do the operation */
|
|
movb %ah, %bl /* save return value in %bl */
|
|
/* back to protected mode */
|
|
DATA32 call real_to_prot
|
|
.code32
|
|
|
|
movb %bl, %al /* return value in %eax */
|
|
|
|
popl %esi
|
|
popl %ebx
|
|
popl %ebp
|
|
|
|
ret
|
|
|
|
|
|
/*
|
|
* int grub_biosdisk_get_diskinfo_standard (int drive,
|
|
* unsigned long *cylinders,
|
|
* unsigned long *heads,
|
|
* unsigned long *sectors)
|
|
*
|
|
* Return the geometry of DRIVE in CYLINDERS, HEADS and SECTORS. If an
|
|
* error occurs, then return non-zero, otherwise zero.
|
|
*/
|
|
|
|
FUNCTION(grub_biosdisk_get_diskinfo_standard)
|
|
pushl %ebp
|
|
pushl %ebx
|
|
pushl %edi
|
|
|
|
/* push CYLINDERS */
|
|
pushl %edx
|
|
/* push HEADS */
|
|
pushl %ecx
|
|
/* SECTORS is on the stack */
|
|
|
|
/* drive */
|
|
movb %al, %dl
|
|
/* enter real mode */
|
|
call prot_to_real
|
|
|
|
.code16
|
|
movb $0x8, %ah
|
|
int $0x13 /* do the operation */
|
|
/* check if successful */
|
|
testb %ah, %ah
|
|
jnz 1f
|
|
/* bogus BIOSes may not return an error number */
|
|
testb $0x3f, %cl /* 0 sectors means no disk */
|
|
jnz 1f /* if non-zero, then succeed */
|
|
/* XXX 0x60 is one of the unused error numbers */
|
|
movb $0x60, %ah
|
|
1:
|
|
movb %ah, %bl /* save return value in %bl */
|
|
/* back to protected mode */
|
|
DATA32 call real_to_prot
|
|
.code32
|
|
|
|
/* pop HEADS */
|
|
popl %edi
|
|
movb %dh, %al
|
|
incl %eax /* the number of heads is counted from zero */
|
|
movl %eax, (%edi)
|
|
|
|
/* pop CYLINDERS */
|
|
popl %edi
|
|
movb %ch, %al
|
|
movb %cl, %ah
|
|
shrb $6, %ah /* the number of cylinders is counted from zero */
|
|
incl %eax
|
|
movl %eax, (%edi)
|
|
|
|
/* SECTORS */
|
|
movl 0x10(%esp), %edi
|
|
andb $0x3f, %cl
|
|
movzbl %cl, %eax
|
|
movl %eax, (%edi)
|
|
|
|
xorl %eax, %eax
|
|
movb %bl, %al /* return value in %eax */
|
|
|
|
popl %edi
|
|
popl %ebx
|
|
popl %ebp
|
|
|
|
ret $4
|
|
|
|
|
|
/*
|
|
* int grub_biosdisk_get_num_floppies (void)
|
|
*/
|
|
FUNCTION(grub_biosdisk_get_num_floppies)
|
|
pushl %ebp
|
|
|
|
xorl %edx, %edx
|
|
call prot_to_real
|
|
|
|
.code16
|
|
/* reset the disk system first */
|
|
int $0x13
|
|
1:
|
|
stc
|
|
|
|
/* call GET DISK TYPE */
|
|
movb $0x15, %ah
|
|
int $0x13
|
|
|
|
jc 2f
|
|
|
|
/* check if this drive exists */
|
|
testb $0x3, %ah
|
|
jz 2f
|
|
|
|
incb %dl
|
|
cmpb $2, %dl
|
|
jne 1b
|
|
2:
|
|
DATA32 call real_to_prot
|
|
.code32
|
|
|
|
movl %edx, %eax
|
|
popl %ebp
|
|
ret
|
|
|
|
|
|
/*
|
|
*
|
|
* grub_get_memsize(i) : return the memory size in KB. i == 0 for conventional
|
|
* memory, i == 1 for extended memory
|
|
* BIOS call "INT 12H" to get conventional memory size
|
|
* BIOS call "INT 15H, AH=88H" to get extended memory size
|
|
* Both have the return value in AX.
|
|
*
|
|
*/
|
|
|
|
FUNCTION(grub_get_memsize)
|
|
pushl %ebp
|
|
|
|
movl %eax, %edx
|
|
|
|
call prot_to_real /* enter real mode */
|
|
.code16
|
|
|
|
testl %edx, %edx
|
|
jnz xext
|
|
|
|
int $0x12
|
|
jmp xdone
|
|
|
|
xext:
|
|
movb $0x88, %ah
|
|
int $0x15
|
|
|
|
xdone:
|
|
movw %ax, %dx
|
|
|
|
DATA32 call real_to_prot
|
|
.code32
|
|
|
|
movw %dx, %ax
|
|
|
|
popl %ebp
|
|
ret
|
|
|
|
|
|
/*
|
|
*
|
|
* grub_get_eisa_mmap() : return packed EISA memory map, lower 16 bits is
|
|
* memory between 1M and 16M in 1K parts, upper 16 bits is
|
|
* memory above 16M in 64K parts. If error, return zero.
|
|
* BIOS call "INT 15H, AH=E801H" to get EISA memory map,
|
|
* AX = memory between 1M and 16M in 1K parts.
|
|
* BX = memory above 16M in 64K parts.
|
|
*
|
|
*/
|
|
|
|
FUNCTION(grub_get_eisa_mmap)
|
|
pushl %ebp
|
|
pushl %ebx
|
|
|
|
call prot_to_real /* enter real mode */
|
|
.code16
|
|
|
|
movw $0xe801, %ax
|
|
int $0x15
|
|
|
|
shll $16, %ebx
|
|
movw %ax, %bx
|
|
|
|
DATA32 call real_to_prot
|
|
.code32
|
|
|
|
cmpb $0x86, %bh
|
|
je xnoteisa
|
|
|
|
movl %ebx, %eax
|
|
|
|
xnoteisa:
|
|
popl %ebx
|
|
popl %ebp
|
|
ret
|
|
|
|
/*
|
|
*
|
|
* grub_get_mmap_entry(addr, cont) : address and old continuation value (zero to
|
|
* start), for the Query System Address Map BIOS call.
|
|
*
|
|
* Sets the first 4-byte int value of "addr" to the size returned by
|
|
* the call. If the call fails, sets it to zero.
|
|
*
|
|
* Returns: new (non-zero) continuation value, 0 if done.
|
|
*/
|
|
|
|
FUNCTION(grub_get_mmap_entry)
|
|
pushl %ebp
|
|
pushl %ebx
|
|
pushl %edi
|
|
pushl %esi
|
|
|
|
/* push ADDR */
|
|
pushl %eax
|
|
|
|
/* place address (+4) in ES:DI */
|
|
addl $4, %eax
|
|
movl %eax, %edi
|
|
andl $0xf, %edi
|
|
shrl $4, %eax
|
|
movl %eax, %esi
|
|
|
|
/* set continuation value */
|
|
movl %edx, %ebx
|
|
|
|
/* set default maximum buffer size */
|
|
movl $0x14, %ecx
|
|
|
|
/* set EDX to 'SMAP' */
|
|
movl $0x534d4150, %edx
|
|
|
|
call prot_to_real /* enter real mode */
|
|
.code16
|
|
|
|
movw %si, %es
|
|
movl $0xe820, %eax
|
|
int $0x15
|
|
|
|
DATA32 jc xnosmap
|
|
|
|
cmpl $0x534d4150, %eax
|
|
jne xnosmap
|
|
|
|
cmpl $0x14, %ecx
|
|
jl xnosmap
|
|
|
|
cmpl $0x400, %ecx
|
|
jg xnosmap
|
|
|
|
jmp xsmap
|
|
|
|
xnosmap:
|
|
xorl %ecx, %ecx
|
|
|
|
/* Apple's cc jumps few bytes before the correct
|
|
label in this context. Hence nops. */
|
|
#ifdef APPLE_CC
|
|
nop
|
|
nop
|
|
nop
|
|
nop
|
|
nop
|
|
nop
|
|
#endif
|
|
|
|
xsmap:
|
|
DATA32 call real_to_prot
|
|
.code32
|
|
|
|
/* write length of buffer (zero if error) into ADDR */
|
|
popl %eax
|
|
movl %ecx, (%eax)
|
|
|
|
/* set return value to continuation */
|
|
movl %ebx, %eax
|
|
|
|
popl %esi
|
|
popl %edi
|
|
popl %ebx
|
|
popl %ebp
|
|
ret
|
|
|
|
|
|
/*
|
|
* void grub_console_real_putchar (int c)
|
|
*
|
|
* Put the character C on the console. Because GRUB wants to write a
|
|
* character with an attribute, this implementation is a bit tricky.
|
|
* If C is a control character (CR, LF, BEL, BS), use INT 10, AH = 0Eh
|
|
* (TELETYPE OUTPUT). Otherwise, save the original position, put a space,
|
|
* save the current position, restore the original position, write the
|
|
* character and the attribute, and restore the current position.
|
|
*
|
|
* The reason why this is so complicated is that there is no easy way to
|
|
* get the height of the screen, and the TELETYPE OUTPUT BIOS call doesn't
|
|
* support setting a background attribute.
|
|
*/
|
|
FUNCTION(grub_console_real_putchar)
|
|
movl %eax, %edx
|
|
pusha
|
|
movb EXT_C(grub_console_cur_color), %bl
|
|
|
|
call prot_to_real
|
|
.code16
|
|
movb %dl, %al
|
|
xorb %bh, %bh
|
|
|
|
/* use teletype output if control character */
|
|
cmpb $0x7, %al
|
|
je 1f
|
|
cmpb $0x8, %al
|
|
je 1f
|
|
cmpb $0xa, %al
|
|
je 1f
|
|
cmpb $0xd, %al
|
|
je 1f
|
|
|
|
/* save the character and the attribute on the stack */
|
|
pushw %ax
|
|
pushw %bx
|
|
|
|
/* get the current position */
|
|
movb $0x3, %ah
|
|
int $0x10
|
|
|
|
/* check the column with the width */
|
|
cmpb $79, %dl
|
|
jl 2f
|
|
|
|
/* print CR and LF, if next write will exceed the width */
|
|
movw $0x0e0d, %ax
|
|
int $0x10
|
|
movb $0x0a, %al
|
|
int $0x10
|
|
|
|
/* get the current position */
|
|
movb $0x3, %ah
|
|
int $0x10
|
|
|
|
2:
|
|
/* restore the character and the attribute */
|
|
popw %bx
|
|
popw %ax
|
|
|
|
/* write the character with the attribute */
|
|
movb $0x9, %ah
|
|
movw $1, %cx
|
|
int $0x10
|
|
|
|
/* move the cursor forward */
|
|
incb %dl
|
|
movb $0x2, %ah
|
|
int $0x10
|
|
|
|
jmp 3f
|
|
|
|
1: movw $1, %bx
|
|
movb $0xe, %ah
|
|
int $0x10
|
|
|
|
3: DATA32 call real_to_prot
|
|
.code32
|
|
|
|
popa
|
|
ret
|
|
|
|
|
|
/*
|
|
* int grub_console_getkey (void)
|
|
* BIOS call "INT 16H Function 00H" to read character from keyboard
|
|
* Call with %ah = 0x0
|
|
* Return: %ah = keyboard scan code
|
|
* %al = ASCII character
|
|
*/
|
|
|
|
/* this table is used in translate_keycode below */
|
|
translation_table:
|
|
.word GRUB_CONSOLE_KEY_LEFT, GRUB_TERM_LEFT
|
|
.word GRUB_CONSOLE_KEY_RIGHT, GRUB_TERM_RIGHT
|
|
.word GRUB_CONSOLE_KEY_UP, GRUB_TERM_UP
|
|
.word GRUB_CONSOLE_KEY_DOWN, GRUB_TERM_DOWN
|
|
.word GRUB_CONSOLE_KEY_HOME, GRUB_TERM_HOME
|
|
.word GRUB_CONSOLE_KEY_END, GRUB_TERM_END
|
|
.word GRUB_CONSOLE_KEY_DC, GRUB_TERM_DC
|
|
.word GRUB_CONSOLE_KEY_BACKSPACE, GRUB_TERM_BACKSPACE
|
|
.word GRUB_CONSOLE_KEY_PPAGE, GRUB_TERM_PPAGE
|
|
.word GRUB_CONSOLE_KEY_NPAGE, GRUB_TERM_NPAGE
|
|
.word 0
|
|
|
|
/*
|
|
* translate_keycode translates the key code %dx to an ascii code.
|
|
*/
|
|
.code16
|
|
|
|
translate_keycode:
|
|
pushw %bx
|
|
pushw %si
|
|
|
|
#ifdef APPLE_CC
|
|
translation_table_abs = ABS (translation_table) - 0x10000
|
|
movw $(translation_table_abs), %si
|
|
#else
|
|
movw $ABS(translation_table), %si
|
|
#endif
|
|
|
|
1: lodsw
|
|
/* check if this is the end */
|
|
testw %ax, %ax
|
|
jz 2f
|
|
/* load the ascii code into %ax */
|
|
movw %ax, %bx
|
|
lodsw
|
|
/* check if this matches the key code */
|
|
cmpw %bx, %dx
|
|
jne 1b
|
|
/* translate %dx, if successful */
|
|
movw %ax, %dx
|
|
|
|
2: popw %si
|
|
popw %bx
|
|
ret
|
|
|
|
.code32
|
|
|
|
FUNCTION(grub_console_getkey)
|
|
pushl %ebp
|
|
|
|
call prot_to_real
|
|
.code16
|
|
|
|
/*
|
|
* Due to a bug in apple's bootcamp implementation, INT 16/AH = 0 would
|
|
* cause the machine to hang at the second keystroke. However, we can
|
|
* work around this problem by ensuring the presence of keystroke with
|
|
* INT 16/AH = 1 before calling INT 16/AH = 0.
|
|
*/
|
|
|
|
1:
|
|
movb $1, %ah
|
|
int $0x16
|
|
jnz 2f
|
|
hlt
|
|
jmp 1b
|
|
|
|
2:
|
|
|
|
movb $0, %ah
|
|
int $0x16
|
|
|
|
movw %ax, %dx /* real_to_prot uses %eax */
|
|
call translate_keycode
|
|
|
|
DATA32 call real_to_prot
|
|
.code32
|
|
|
|
movw %dx, %ax
|
|
|
|
popl %ebp
|
|
ret
|
|
|
|
|
|
/*
|
|
* int grub_console_checkkey (void)
|
|
* if there is a character pending, return it; otherwise return -1
|
|
* BIOS call "INT 16H Function 01H" to check whether a character is pending
|
|
* Call with %ah = 0x1
|
|
* Return:
|
|
* If key waiting to be input:
|
|
* %ah = keyboard scan code
|
|
* %al = ASCII character
|
|
* Zero flag = clear
|
|
* else
|
|
* Zero flag = set
|
|
*/
|
|
FUNCTION(grub_console_checkkey)
|
|
pushl %ebp
|
|
xorl %edx, %edx
|
|
|
|
call prot_to_real /* enter real mode */
|
|
.code16
|
|
|
|
movb $0x1, %ah
|
|
int $0x16
|
|
|
|
jz notpending
|
|
|
|
movw %ax, %dx
|
|
DATA32 jmp pending
|
|
|
|
notpending:
|
|
decl %edx
|
|
|
|
pending:
|
|
DATA32 call real_to_prot
|
|
.code32
|
|
|
|
movl %edx, %eax
|
|
|
|
popl %ebp
|
|
ret
|
|
|
|
|
|
/*
|
|
* grub_uint16_t grub_console_getxy (void)
|
|
* BIOS call "INT 10H Function 03h" to get cursor position
|
|
* Call with %ah = 0x03
|
|
* %bh = page
|
|
* Returns %ch = starting scan line
|
|
* %cl = ending scan line
|
|
* %dh = row (0 is top)
|
|
* %dl = column (0 is left)
|
|
*/
|
|
|
|
|
|
FUNCTION(grub_console_getxy)
|
|
pushl %ebp
|
|
pushl %ebx /* save EBX */
|
|
|
|
call prot_to_real
|
|
.code16
|
|
|
|
xorb %bh, %bh /* set page to 0 */
|
|
movb $0x3, %ah
|
|
int $0x10 /* get cursor position */
|
|
|
|
DATA32 call real_to_prot
|
|
.code32
|
|
|
|
movb %dl, %ah
|
|
movb %dh, %al
|
|
|
|
popl %ebx
|
|
popl %ebp
|
|
ret
|
|
|
|
|
|
/*
|
|
* void grub_console_gotoxy(grub_uint8_t x, grub_uint8_t y)
|
|
* BIOS call "INT 10H Function 02h" to set cursor position
|
|
* Call with %ah = 0x02
|
|
* %bh = page
|
|
* %dh = row (0 is top)
|
|
* %dl = column (0 is left)
|
|
*/
|
|
|
|
|
|
FUNCTION(grub_console_gotoxy)
|
|
pushl %ebp
|
|
pushl %ebx /* save EBX */
|
|
|
|
movb %dl, %dh /* %dh = y */
|
|
movb %al, %dl /* %dl = x */
|
|
|
|
call prot_to_real
|
|
.code16
|
|
|
|
xorb %bh, %bh /* set page to 0 */
|
|
movb $0x2, %ah
|
|
int $0x10 /* set cursor position */
|
|
|
|
DATA32 call real_to_prot
|
|
.code32
|
|
|
|
popl %ebx
|
|
popl %ebp
|
|
ret
|
|
|
|
|
|
/*
|
|
* void grub_console_cls (void)
|
|
* BIOS call "INT 10H Function 09h" to write character and attribute
|
|
* Call with %ah = 0x09
|
|
* %al = (character)
|
|
* %bh = (page number)
|
|
* %bl = (attribute)
|
|
* %cx = (number of times)
|
|
*/
|
|
|
|
FUNCTION(grub_console_cls)
|
|
pushl %ebp
|
|
pushl %ebx /* save EBX */
|
|
|
|
call prot_to_real
|
|
.code16
|
|
|
|
/* move the cursor to the beginning */
|
|
movb $0x02, %ah
|
|
xorb %bh, %bh
|
|
xorw %dx, %dx
|
|
int $0x10
|
|
|
|
/* write spaces to the entire screen */
|
|
movw $0x0920, %ax
|
|
movw $0x07, %bx
|
|
movw $(80 * 25), %cx
|
|
int $0x10
|
|
|
|
/* move back the cursor */
|
|
movb $0x02, %ah
|
|
int $0x10
|
|
|
|
DATA32 call real_to_prot
|
|
.code32
|
|
|
|
popl %ebx
|
|
popl %ebp
|
|
ret
|
|
|
|
|
|
/*
|
|
* void grub_console_setcursor (int on)
|
|
* BIOS call "INT 10H Function 01h" to set cursor type
|
|
* Call with %ah = 0x01
|
|
* %ch = cursor starting scanline
|
|
* %cl = cursor ending scanline
|
|
*/
|
|
|
|
console_cursor_state:
|
|
.byte 1
|
|
console_cursor_shape:
|
|
.word 0
|
|
|
|
FUNCTION(grub_console_setcursor)
|
|
pushl %ebp
|
|
pushl %ebx
|
|
|
|
/* push ON */
|
|
pushl %eax
|
|
|
|
/* check if the standard cursor shape has already been saved */
|
|
movw console_cursor_shape, %ax
|
|
testw %ax, %ax
|
|
jne 1f
|
|
|
|
call prot_to_real
|
|
.code16
|
|
|
|
movb $0x03, %ah
|
|
xorb %bh, %bh
|
|
int $0x10
|
|
|
|
DATA32 call real_to_prot
|
|
.code32
|
|
|
|
movw %cx, console_cursor_shape
|
|
1:
|
|
/* set %cx to the designated cursor shape */
|
|
movw $0x2000, %cx
|
|
popl %eax
|
|
testl %eax, %eax
|
|
jz 2f
|
|
movw console_cursor_shape, %cx
|
|
2:
|
|
call prot_to_real
|
|
.code16
|
|
|
|
movb $0x1, %ah
|
|
int $0x10
|
|
|
|
DATA32 call real_to_prot
|
|
.code32
|
|
|
|
popl %ebx
|
|
popl %ebp
|
|
ret
|
|
|
|
/*
|
|
* grub_getrtsecs()
|
|
* if a seconds value can be read, read it and return it (BCD),
|
|
* otherwise return 0xFF
|
|
* BIOS call "INT 1AH Function 02H" to check whether a character is pending
|
|
* Call with %ah = 0x2
|
|
* Return:
|
|
* If RT Clock can give correct values
|
|
* %ch = hour (BCD)
|
|
* %cl = minutes (BCD)
|
|
* %dh = seconds (BCD)
|
|
* %dl = daylight savings time (00h std, 01h daylight)
|
|
* Carry flag = clear
|
|
* else
|
|
* Carry flag = set
|
|
* (this indicates that the clock is updating, or
|
|
* that it isn't running)
|
|
*/
|
|
FUNCTION(grub_getrtsecs)
|
|
pushl %ebp
|
|
|
|
call prot_to_real /* enter real mode */
|
|
.code16
|
|
|
|
clc
|
|
movb $0x2, %ah
|
|
int $0x1a
|
|
|
|
DATA32 jnc gottime
|
|
movb $0xff, %dh
|
|
|
|
gottime:
|
|
DATA32 call real_to_prot
|
|
.code32
|
|
|
|
movb %dh, %al
|
|
|
|
popl %ebp
|
|
ret
|
|
|
|
|
|
/*
|
|
* grub_get_rtc()
|
|
* return the real time in ticks, of which there are about
|
|
* 18-20 per second
|
|
*/
|
|
FUNCTION(grub_get_rtc)
|
|
pushl %ebp
|
|
|
|
call prot_to_real /* enter real mode */
|
|
.code16
|
|
|
|
/* %ax is already zero */
|
|
int $0x1a
|
|
|
|
DATA32 call real_to_prot
|
|
.code32
|
|
|
|
movl %ecx, %eax
|
|
shll $16, %eax
|
|
movw %dx, %ax
|
|
|
|
popl %ebp
|
|
ret
|
|
|
|
|
|
/*
|
|
* unsigned char grub_vga_set_mode (unsigned char mode)
|
|
*/
|
|
FUNCTION(grub_vga_set_mode)
|
|
pushl %ebp
|
|
pushl %ebx
|
|
movl %eax, %ecx
|
|
|
|
call prot_to_real
|
|
.code16
|
|
/* get current mode */
|
|
xorw %bx, %bx
|
|
movb $0x0f, %ah
|
|
int $0x10
|
|
movb %al, %dl
|
|
|
|
/* set the new mode */
|
|
movb %cl, %al
|
|
xorb %ah, %ah
|
|
int $0x10
|
|
|
|
DATA32 call real_to_prot
|
|
.code32
|
|
|
|
movb %dl, %al
|
|
popl %ebx
|
|
popl %ebp
|
|
ret
|
|
|
|
|
|
/*
|
|
* unsigned char *grub_vga_get_font (void)
|
|
*/
|
|
FUNCTION(grub_vga_get_font)
|
|
pushl %ebp
|
|
pushl %ebx
|
|
|
|
call prot_to_real
|
|
.code16
|
|
movw $0x1130, %ax
|
|
movb $0x06, %bh
|
|
int $0x10
|
|
movw %es, %bx
|
|
movw %bp, %dx
|
|
DATA32 call real_to_prot
|
|
.code32
|
|
|
|
movzwl %bx, %ecx
|
|
shll $4, %ecx
|
|
movw %dx, %ax
|
|
addl %ecx, %eax
|
|
|
|
popl %ebx
|
|
popl %ebp
|
|
ret
|
|
|
|
/*
|
|
* grub_vbe_bios_status_t grub_vbe_get_controller_info (struct grub_vbe_info_block *controller_info)
|
|
*
|
|
* Register allocations for parameters:
|
|
* %eax *controller_info
|
|
*/
|
|
FUNCTION(grub_vbe_bios_get_controller_info)
|
|
pushl %ebp
|
|
pushl %edi
|
|
pushl %edx
|
|
|
|
movw %ax, %di /* Store *controller_info to %edx:%di. */
|
|
xorw %ax, %ax
|
|
shrl $4, %eax
|
|
mov %eax, %edx /* prot_to_real destroys %eax. */
|
|
|
|
call prot_to_real
|
|
.code16
|
|
|
|
pushw %es
|
|
|
|
movw %dx, %es /* *controller_info is now on %es:%di. */
|
|
movw $0x4f00, %ax
|
|
int $0x10
|
|
|
|
movw %ax, %dx /* real_to_prot destroys %eax. */
|
|
|
|
popw %es
|
|
|
|
DATA32 call real_to_prot
|
|
.code32
|
|
|
|
movl %edx, %eax
|
|
andl $0x0FFFF, %eax /* Return value in %eax. */
|
|
|
|
pop %edx
|
|
popl %edi
|
|
popl %ebp
|
|
ret
|
|
|
|
/*
|
|
* grub_vbe_status_t grub_vbe_bios_get_mode_info (grub_uint32_t mode,
|
|
* struct grub_vbe_mode_info_block *mode_info)
|
|
*
|
|
* Register allocations for parameters:
|
|
* %eax mode
|
|
* %edx *mode_info
|
|
*/
|
|
FUNCTION(grub_vbe_bios_get_mode_info)
|
|
pushl %ebp
|
|
pushl %edi
|
|
|
|
movl %eax, %ecx /* Store mode number to %ecx. */
|
|
|
|
movw %dx, %di /* Store *mode_info to %edx:%di. */
|
|
xorw %dx, %dx
|
|
shrl $4, %edx
|
|
|
|
call prot_to_real
|
|
.code16
|
|
|
|
pushw %es
|
|
|
|
movw %dx, %es /* *mode_info is now on %es:%di. */
|
|
movw $0x4f01, %ax
|
|
int $0x10
|
|
|
|
movw %ax, %dx /* real_to_prot destroys %eax. */
|
|
|
|
popw %es
|
|
|
|
DATA32 call real_to_prot
|
|
.code32
|
|
|
|
movl %edx, %eax
|
|
andl $0x0FFFF, %eax /* Return value in %eax. */
|
|
|
|
popl %edi
|
|
popl %ebp
|
|
ret
|
|
|
|
/*
|
|
* grub_vbe_status_t grub_vbe_bios_set_mode (grub_uint32_t mode,
|
|
* struct grub_vbe_crtc_info_block *crtc_info)
|
|
*
|
|
* Register allocations for parameters:
|
|
* %eax mode
|
|
* %edx *crtc_info
|
|
*/
|
|
FUNCTION(grub_vbe_bios_set_mode)
|
|
pushl %ebp
|
|
pushl %ebx
|
|
pushl %edi
|
|
|
|
movl %eax, %ebx /* Store mode in %ebx. */
|
|
|
|
movw %dx, %di /* Store *crtc_info to %edx:%di. */
|
|
xorw %dx, %dx
|
|
shrl $4, %edx
|
|
|
|
call prot_to_real
|
|
.code16
|
|
|
|
pushw %es
|
|
|
|
movw %dx, %es /* *crtc_info is now on %es:%di. */
|
|
|
|
movw $0x4f02, %ax
|
|
int $0x10
|
|
|
|
movw %ax, %dx /* real_to_prot destroys %eax. */
|
|
|
|
popw %es
|
|
|
|
DATA32 call real_to_prot
|
|
.code32
|
|
|
|
movw %dx, %ax
|
|
andl $0xFFFF, %eax /* Return value in %eax. */
|
|
|
|
popl %edi
|
|
popl %ebx
|
|
popl %ebp
|
|
ret
|
|
|
|
/*
|
|
* grub_vbe_status_t grub_vbe_bios_get_mode (grub_uint32_t *mode)
|
|
*
|
|
* Register allocations for parameters:
|
|
* %eax *mode
|
|
*/
|
|
FUNCTION(grub_vbe_bios_get_mode)
|
|
pushl %ebp
|
|
pushl %ebx
|
|
pushl %edi
|
|
pushl %edx
|
|
pushl %eax /* Push *mode to stack. */
|
|
|
|
call prot_to_real
|
|
.code16
|
|
|
|
movw $0x4f03, %ax
|
|
int $0x10
|
|
|
|
movw %ax, %dx /* real_to_prot destroys %eax. */
|
|
|
|
DATA32 call real_to_prot
|
|
.code32
|
|
|
|
popl %edi /* Pops *mode from stack to %edi. */
|
|
andl $0xFFFF, %ebx
|
|
movl %ebx, (%edi)
|
|
|
|
movw %dx, %ax
|
|
andl $0xFFFF, %eax /* Return value in %eax. */
|
|
|
|
popl %edx
|
|
popl %edi
|
|
popl %ebx
|
|
popl %ebp
|
|
ret
|
|
|
|
/*
|
|
* grub_vbe_status_t grub_vbe_bios_getset_dac_palette_width (int set, int *dac_mask_size)
|
|
*
|
|
* Register allocations for parameters:
|
|
* %eax set
|
|
* %edx *dac_mask_size
|
|
*/
|
|
FUNCTION(grub_vbe_bios_getset_dac_palette_width)
|
|
pushl %ebp
|
|
pushl %ebx
|
|
|
|
xorl %ebx, %ebx
|
|
|
|
/* If we only want to fetch the value, set %bl to 1. */
|
|
testl %eax, %eax
|
|
jne 1f
|
|
incb %bl
|
|
1:
|
|
|
|
/* Put desired width in %bh. */
|
|
movl (%edx), %eax
|
|
movb %al, %bh
|
|
|
|
call prot_to_real
|
|
.code16
|
|
|
|
movw $0x4f08, %ax
|
|
int $0x10
|
|
|
|
movw %ax, %cx /* real_to_prot destroys %eax. */
|
|
|
|
DATA32 call real_to_prot
|
|
.code32
|
|
|
|
/* Move result back to *dac_mask_size. */
|
|
xorl %eax, %eax
|
|
movb %bh, %al
|
|
movl %eax, (%edx)
|
|
|
|
/* Return value in %eax. */
|
|
movw %cx, %ax
|
|
|
|
popl %ebx
|
|
popl %ebp
|
|
ret
|
|
|
|
/*
|
|
* grub_vbe_status_t grub_vbe_bios_set_memory_window (grub_uint32_t window,
|
|
* grub_uint32_t position);
|
|
*
|
|
* Register allocations for parameters:
|
|
* %eax window
|
|
* %edx position
|
|
*/
|
|
FUNCTION(grub_vbe_bios_set_memory_window)
|
|
pushl %ebp
|
|
pushl %ebx
|
|
|
|
movl %eax, %ebx
|
|
|
|
call prot_to_real
|
|
.code16
|
|
|
|
movw $0x4f05, %ax
|
|
andw $0x00ff, %bx /* BL = window, BH = 0, Set memory window. */
|
|
int $0x10
|
|
|
|
movw %ax, %dx /* real_to_prot destroys %eax. */
|
|
|
|
DATA32 call real_to_prot
|
|
.code32
|
|
|
|
movw %dx, %ax
|
|
andl $0xFFFF, %eax /* Return value in %eax. */
|
|
|
|
popl %ebx
|
|
popl %ebp
|
|
ret
|
|
|
|
/*
|
|
* grub_vbe_status_t grub_vbe_bios_get_memory_window (grub_uint32_t window,
|
|
* grub_uint32_t *position);
|
|
*
|
|
* Register allocations for parameters:
|
|
* %eax window
|
|
* %edx *position
|
|
*/
|
|
FUNCTION(grub_vbe_bios_get_memory_window)
|
|
pushl %ebp
|
|
pushl %ebx
|
|
pushl %edi
|
|
pushl %edx /* Push *position to stack. */
|
|
|
|
movl %eax, %ebx /* Store window in %ebx. */
|
|
|
|
call prot_to_real
|
|
.code16
|
|
|
|
movw $0x4f05, %ax
|
|
andw $0x00ff, %bx /* BL = window. */
|
|
orw $0x0100, %bx /* BH = 1, Get memory window. */
|
|
int $0x10
|
|
|
|
movw %ax, %bx /* real_to_prot destroys %eax. */
|
|
|
|
DATA32 call real_to_prot
|
|
.code32
|
|
|
|
popl %edi /* pops *position from stack to %edi. */
|
|
andl $0xFFFF, %edx
|
|
movl %edx, (%edi) /* Return position to caller. */
|
|
|
|
movw %bx, %ax
|
|
andl $0xFFFF, %eax /* Return value in %eax. */
|
|
|
|
popl %edi
|
|
popl %ebx
|
|
popl %ebp
|
|
ret
|
|
|
|
/*
|
|
* grub_vbe_status_t grub_vbe_bios_set_scanline_length (grub_uint32_t length)
|
|
*
|
|
* Register allocations for parameters:
|
|
* %eax length
|
|
*/
|
|
FUNCTION(grub_vbe_bios_set_scanline_length)
|
|
pushl %ebp
|
|
pushl %ebx
|
|
pushl %edx
|
|
|
|
movl %eax, %ecx /* Store length in %ecx. */
|
|
|
|
call prot_to_real
|
|
.code16
|
|
|
|
movw $0x4f06, %ax
|
|
movw $0x0002, %bx /* BL = 2, Set Scan Line in Bytes. */
|
|
int $0x10
|
|
|
|
movw %ax, %dx /* real_to_prot destroys %eax. */
|
|
|
|
DATA32 call real_to_prot
|
|
.code32
|
|
|
|
movw %dx, %ax
|
|
andl $0xFFFF, %eax /* Return value in %eax. */
|
|
|
|
popl %edx
|
|
popl %ebx
|
|
popl %ebp
|
|
ret
|
|
|
|
/*
|
|
* grub_vbe_status_t grub_vbe_bios_get_scanline_length (grub_uint32_t *length)
|
|
*
|
|
* Register allocations for parameters:
|
|
* %eax *length
|
|
*/
|
|
FUNCTION(grub_vbe_bios_get_scanline_length)
|
|
pushl %ebp
|
|
pushl %ebx
|
|
pushl %edi
|
|
pushl %edx /* Push *length to stack. */
|
|
|
|
call prot_to_real
|
|
.code16
|
|
|
|
movw $0x4f06, %ax
|
|
movw $0x0001, %bx /* BL = 1, Get Scan Line Length (in bytes). */
|
|
int $0x10
|
|
|
|
movw %ax, %dx /* real_to_prot destroys %eax. */
|
|
|
|
DATA32 call real_to_prot
|
|
.code32
|
|
|
|
popl %edi /* Pops *length from stack to %edi. */
|
|
andl $0xFFFF, %ebx
|
|
movl %ebx, (%edi) /* Return length to caller. */
|
|
|
|
movw %dx, %ax
|
|
andl $0xFFFF, %eax /* Return value in %eax. */
|
|
|
|
popl %edi
|
|
popl %ebx
|
|
popl %ebp
|
|
ret
|
|
|
|
/*
|
|
* grub_vbe_status_t grub_vbe_bios_set_display_start (grub_uint32_t x,
|
|
* grub_uint32_t y)
|
|
*
|
|
* Register allocations for parameters:
|
|
* %eax x
|
|
* %edx y
|
|
*/
|
|
FUNCTION(grub_vbe_bios_set_display_start)
|
|
pushl %ebp
|
|
pushl %ebx
|
|
|
|
movl %eax, %ecx /* Store x in %ecx. */
|
|
|
|
call prot_to_real
|
|
.code16
|
|
|
|
movw $0x4f07, %ax
|
|
movw $0x0080, %bx /* BL = 80h, Set Display Start
|
|
during Vertical Retrace. */
|
|
int $0x10
|
|
|
|
movw %ax, %dx /* real_to_prot destroys %eax. */
|
|
|
|
DATA32 call real_to_prot
|
|
.code32
|
|
|
|
movw %dx, %ax
|
|
andl $0xFFFF, %eax /* Return value in %eax. */
|
|
|
|
popl %ebx
|
|
popl %ebp
|
|
ret
|
|
|
|
/*
|
|
* grub_vbe_status_t grub_vbe_bios_get_display_start (grub_uint32_t *x,
|
|
* grub_uint32_t *y)
|
|
*
|
|
* Register allocations for parameters:
|
|
* %eax *x
|
|
* %edx *y
|
|
*/
|
|
FUNCTION(grub_vbe_bios_get_display_start)
|
|
pushl %ebp
|
|
pushl %ebx
|
|
pushl %edi
|
|
pushl %eax /* Push *x to stack. */
|
|
pushl %edx /* Push *y to stack. */
|
|
|
|
call prot_to_real
|
|
.code16
|
|
|
|
movw $0x4f07, %ax
|
|
movw $0x0001, %bx /* BL = 1, Get Display Start. */
|
|
int $0x10
|
|
|
|
movw %ax, %bx /* real_to_prot destroys %eax. */
|
|
|
|
DATA32 call real_to_prot
|
|
.code32
|
|
|
|
popl %edi /* Pops *y from stack to %edi. */
|
|
andl $0xFFFF, %edx
|
|
movl %edx, (%edi) /* Return y-position to caller. */
|
|
|
|
popl %edi /* Pops *x from stack to %edi. */
|
|
andl $0xFFFF, %ecx
|
|
movl %ecx, (%edi) /* Return x-position to caller. */
|
|
|
|
movw %bx, %ax
|
|
andl $0xFFFF, %eax /* Return value in %eax. */
|
|
|
|
popl %edi
|
|
popl %ebx
|
|
popl %ebp
|
|
ret
|
|
|
|
/*
|
|
* grub_vbe_status_t grub_vbe_bios_set_palette_data (grub_uint32_t color_count,
|
|
* grub_uint32_t start_index,
|
|
* struct grub_vbe_palette_data *palette_data)
|
|
*
|
|
* Register allocations for parameters:
|
|
* %eax color_count
|
|
* %edx start_index
|
|
* %ecx *palette_data
|
|
*/
|
|
FUNCTION(grub_vbe_bios_set_palette_data)
|
|
pushl %ebp
|
|
pushl %ebx
|
|
pushl %edi
|
|
|
|
movl %eax, %ebx /* Store color_count in %ebx. */
|
|
|
|
movw %cx, %di /* Store *palette_data to %ecx:%di. */
|
|
xorw %cx, %cx
|
|
shrl $4, %ecx
|
|
|
|
call prot_to_real
|
|
.code16
|
|
|
|
pushw %es
|
|
|
|
movw %cx, %es /* *palette_data is now on %es:%di. */
|
|
movw %bx, %cx /* color_count is now on %cx. */
|
|
|
|
movw $0x4f09, %ax
|
|
xorw %bx, %bx /* BL = 0, Set Palette Data. */
|
|
int $0x10
|
|
|
|
movw %ax, %dx /* real_to_prot destroys %eax. */
|
|
|
|
popw %es
|
|
|
|
DATA32 call real_to_prot
|
|
.code32
|
|
|
|
movw %dx, %ax
|
|
andl $0xFFFF, %eax /* Return value in %eax. */
|
|
|
|
popl %edi
|
|
popl %ebx
|
|
popl %ebp
|
|
ret
|
|
|
|
|
|
pxe_rm_entry:
|
|
.long 0
|
|
|
|
/*
|
|
* struct grub_pxenv *grub_pxe_scan (void);
|
|
*/
|
|
FUNCTION(grub_pxe_scan)
|
|
pushl %ebp
|
|
pushl %ebx
|
|
|
|
xorl %ebx, %ebx
|
|
xorl %ecx, %ecx
|
|
|
|
call prot_to_real
|
|
.code16
|
|
|
|
pushw %es
|
|
|
|
movw $0x5650, %ax
|
|
int $0x1A
|
|
cmpw $0x564E, %ax
|
|
jnz 1f
|
|
cmpl $0x4E455850, %es:(%bx) /* PXEN(V+) */
|
|
jnz 1f
|
|
cmpw $0x201, %es:6(%bx) /* API version */
|
|
jb 1f
|
|
lesw %es:0x28(%bx), %bx /* !PXE structure */
|
|
cmpl $0x45585021, %es:(%bx) /* !PXE */
|
|
jnz 1f
|
|
movw %es, %cx
|
|
jmp 2f
|
|
1:
|
|
xorw %bx, %bx
|
|
xorw %cx, %cx
|
|
2:
|
|
|
|
popw %es
|
|
|
|
DATA32 call real_to_prot
|
|
.code32
|
|
|
|
xorl %eax, %eax
|
|
leal (%eax, %ecx, 4), %ecx
|
|
leal (%ebx, %ecx, 4), %eax /* eax = ecx * 16 + ebx */
|
|
|
|
orl %eax, %eax
|
|
jz 1f
|
|
|
|
movl 0x10(%eax), %ecx
|
|
movl %ecx, pxe_rm_entry
|
|
|
|
1:
|
|
|
|
popl %ebx
|
|
popl %ebp
|
|
ret
|
|
|
|
/*
|
|
* int grub_pxe_call (int func, void* data);
|
|
*/
|
|
FUNCTION(grub_pxe_call)
|
|
pushl %ebp
|
|
movl %esp, %ebp
|
|
pushl %esi
|
|
pushl %edi
|
|
pushl %ebx
|
|
|
|
movl %eax, %ecx
|
|
movl %edx, %eax
|
|
andl $0xF, %eax
|
|
shrl $4, %edx
|
|
shll $16, %edx
|
|
addl %eax, %edx
|
|
movl pxe_rm_entry, %ebx
|
|
|
|
call prot_to_real
|
|
.code16
|
|
|
|
pushl %ebx
|
|
pushl %edx
|
|
pushw %cx
|
|
movw %sp, %bx
|
|
lcall *%ss:6(%bx)
|
|
cld
|
|
addw $10, %sp
|
|
movw %ax, %cx
|
|
|
|
DATA32 call real_to_prot
|
|
.code32
|
|
|
|
movzwl %cx, %eax
|
|
|
|
popl %ebx
|
|
popl %edi
|
|
popl %esi
|
|
popl %ebp
|
|
ret
|