* grub-core/kern/i386/pc/startup.S: Remove 0-data check. * grub-core/lib/reed_solomon.c (decode_block): Do not proceed on 0 data or 0 redundancy. (grub_reed_solomon_add_redundancy): Do not proceed with 0 redundancy. (grub_reed_solomon_recover): Likewise.
		
			
				
	
	
		
			1011 lines
		
	
	
	
		
			19 KiB
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
			
		
		
	
	
			1011 lines
		
	
	
	
		
			19 KiB
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
| /*
 | |
|  *  GRUB  --  GRand Unified Bootloader
 | |
|  *  Copyright (C) 1999,2000,2001,2002,2003,2005,2006,2007,2008,2009 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) - LOCAL (base) + 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:
 | |
| LOCAL (base):
 | |
| 	/*
 | |
| 	 *  Guarantee that "main" is loaded at 0x0:0x8200.
 | |
| 	 */
 | |
| #ifdef __APPLE__
 | |
| 	ljmp $0, $(ABS(LOCAL (codestart)) - 0x10000)
 | |
| #else
 | |
| 	ljmp $0, $ABS(LOCAL (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
 | |
| reed_solomon_redundancy:
 | |
| 	.long	0
 | |
| 
 | |
| #ifdef APPLE_CC
 | |
| bss_start:
 | |
| 	.long 0
 | |
| bss_end:
 | |
| 	.long 0
 | |
| #endif
 | |
| /*
 | |
|  *  This is the area for all of the special variables.
 | |
|  */
 | |
| 
 | |
| VARIABLE(grub_boot_drive)
 | |
| 	.byte	0
 | |
| 
 | |
| /* the real mode code continues... */
 | |
| LOCAL (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	grub_gate_a20
 | |
| 
 | |
| 	movl	EXT_C(grub_compressed_size), %edx
 | |
| 	addl    $(GRUB_KERNEL_MACHINE_RAW_SIZE - GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_PART), %edx
 | |
| 	movl    reed_solomon_redundancy, %ecx
 | |
| 	leal    _start + GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_PART, %eax
 | |
| 	call    EXT_C (grub_reed_solomon_recover)
 | |
| 	jmp post_reed_solomon
 | |
| 
 | |
| #include <rs_decoder.S>
 | |
| 
 | |
| 	.text
 | |
| 
 | |
| 	. = _start + GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_PART
 | |
| /*
 | |
|  * 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
 | |
| 
 | |
| 	movl	$GRUB_MEMORY_MACHINE_PROT_STACK, %ebp
 | |
| 	movl	%ebp, %esp
 | |
| 
 | |
| 	/* 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
 | |
| 	jmp     LOCAL (codestart)
 | |
| 
 | |
| post_reed_solomon:
 | |
| 
 | |
| #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)
 | |
| 
 | |
| #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.  :-(
 | |
|  */
 | |
| 
 | |
| 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
 | |
| 
 | |
| 	. = _start + GRUB_KERNEL_MACHINE_PREFIX
 | |
| VARIABLE(grub_prefix)
 | |
| 	/* to be filled by grub-mkimage */
 | |
| 
 | |
| 	/*
 | |
| 	 *  Leave some breathing room for the prefix.
 | |
| 	 */
 | |
| 	. = _start + GRUB_KERNEL_MACHINE_PREFIX_END
 | |
| 
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * 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
 | |
| 
 | |
| /*
 | |
|  *  void grub_chainloader_real_boot (int drive, void *part_addr)
 | |
|  *
 | |
|  *  This starts another boot loader.
 | |
|  */
 | |
| 
 | |
| FUNCTION(grub_chainloader_real_boot)
 | |
| 	pushl	%edx
 | |
| 	pushl	%eax
 | |
| 
 | |
| 	/* Turn off Gate A20 */
 | |
| 	xorl	%eax, %eax
 | |
| 	call	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
 | |
| 
 | |
| /*
 | |
|  * void grub_console_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_putchar)
 | |
| 	/* Retrieve the base character.  */
 | |
| 	movl	0(%edx), %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
 | |
| 
 | |
| 
 | |
| LOCAL(bypass_table):
 | |
| 	.word 0x011b, 0x0f00 | '\t', 0x0e00 | '\b', 0x1c00 | '\r'
 | |
| 	.word 0x1c00 | '\n'
 | |
| LOCAL(bypass_table_end):
 | |
| 
 | |
| /*
 | |
|  * int grub_console_getkey (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
 | |
|  * BIOS call "INT 16H Function 00H" to read character from keyboard
 | |
|  *	Call with	%ah = 0x0
 | |
|  *	Return:		%ah = keyboard scan code
 | |
|  *			%al = ASCII character
 | |
|  */
 | |
| 
 | |
| FUNCTION(grub_console_getkey)
 | |
| 	pushl	%ebp
 | |
| 	pushl   %edi
 | |
| 
 | |
| 	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.
 | |
| 	 */
 | |
| 
 | |
| 	movb	$1, %ah
 | |
| 	int	$0x16
 | |
| 	jz	notpending
 | |
| 
 | |
| 	movb	$0, %ah
 | |
| 	int	$0x16
 | |
| 
 | |
| 	xorl    %edx, %edx
 | |
| 	movw	%ax, %dx		/* real_to_prot uses %eax */
 | |
| 
 | |
| 	DATA32	call	real_to_prot
 | |
| 	.code32
 | |
| 
 | |
| 	movl    $0xff, %eax
 | |
| 	testl   %eax, %edx
 | |
| 	jz      1f
 | |
| 
 | |
| 	andl	%edx, %eax
 | |
| 	cmpl    $0x20, %eax
 | |
| 	jae     2f
 | |
| 	movl	%edx, %eax
 | |
| 	leal    LOCAL(bypass_table), %edi
 | |
| 	movl    $((LOCAL(bypass_table_end) - LOCAL(bypass_table)) >> 1), %ecx
 | |
| 	repne scasw 
 | |
| 	jz      3f
 | |
| 
 | |
| 	andl	$0xff, %eax
 | |
| 	addl    $(('a' - 1) | GRUB_TERM_CTRL), %eax
 | |
| 	jmp     2f
 | |
| 3:
 | |
| 	andl    $0xff, %eax
 | |
| 	jmp 2f
 | |
| 
 | |
| 1:	movl    %edx, %eax
 | |
| 	shrl    $8, %eax
 | |
| 	orl     $GRUB_TERM_EXTENDED, %eax
 | |
| 2:
 | |
| 	popl    %edi
 | |
| 	popl	%ebp
 | |
| 	ret
 | |
| 
 | |
| notpending:	
 | |
| 	.code16
 | |
| 	DATA32	call	real_to_prot
 | |
| 	.code32
 | |
| #if GRUB_TERM_NO_KEY != 0
 | |
| #error Fix this asm code
 | |
| #endif
 | |
| 	jmp 2b
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * 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	%cl, %dh	/* %dh = y */
 | |
| 	/* %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	%edx
 | |
| 
 | |
| 	/* 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
 | |
| 
 | |
| 	cmp     %cl, %ch
 | |
| 	jb      3f
 | |
| 	movw    $0x0d0e, %cx
 | |
| 3:	
 | |
| 	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_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
 | |
| 
 | |
| /*
 | |
|  * int grub_pxe_call (int func, void* data, grub_uint32_t pxe_rm_entry);
 | |
|  */
 | |
| FUNCTION(grub_pxe_call)
 | |
| 	pushl	%ebp
 | |
| 	movl	%esp, %ebp
 | |
| 	pushl	%esi
 | |
| 	pushl	%edi
 | |
| 	pushl	%ebx
 | |
| 
 | |
| 	movl	%ecx, %ebx
 | |
| 	movl	%eax, %ecx
 | |
| 	movl	%edx, %eax
 | |
| 	andl	$0xF, %eax
 | |
| 	shrl	$4, %edx
 | |
| 	shll	$16, %edx
 | |
| 	addl	%eax, %edx
 | |
| 
 | |
| 	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
 | |
| 
 | |
| FUNCTION(grub_bios_interrupt)
 | |
| 	pushl    %ebp
 | |
| 	pushl    %ecx
 | |
| 	pushl    %eax
 | |
| 	pushl    %ebx
 | |
| 	pushl    %esi
 | |
| 	pushl    %edi	
 | |
| 	pushl    %edx
 | |
| 	
 | |
| 	movb     %al, intno
 | |
| 	movl	 (%edx), %eax
 | |
| 	movl	 %eax, LOCAL(bios_register_eax)
 | |
| 	movw	 4(%edx), %ax
 | |
| 	movw	 %ax, LOCAL(bios_register_es)
 | |
| 	movw	 6(%edx), %ax
 | |
| 	movw	 %ax, LOCAL(bios_register_ds)
 | |
| 	movw	 8(%edx), %ax
 | |
| 	movw	 %ax, LOCAL(bios_register_flags)
 | |
| 
 | |
| 	movl 	12(%edx), %ebx
 | |
| 	movl 	16(%edx), %ecx
 | |
| 	movl 	20(%edx), %edi
 | |
| 	movl 	24(%edx), %esi
 | |
| 	movl 	28(%edx), %edx
 | |
| 
 | |
| 	call    prot_to_real
 | |
| 	.code16
 | |
| 
 | |
| 	mov	%ds, %ax
 | |
| 	push	%ax
 | |
| 
 | |
| 	/* movw imm16, %ax*/
 | |
| 	.byte	0xb8
 | |
| LOCAL(bios_register_es):
 | |
| 	.short 	0
 | |
| 	movw	%ax, %es
 | |
| 	/* movw imm16, %ax*/
 | |
| 	.byte	0xb8
 | |
| LOCAL(bios_register_ds):
 | |
| 	.short 	0
 | |
| 	movw	%ax, %ds
 | |
| 
 | |
| 	/* movw imm16, %ax*/
 | |
| 	.byte	0xb8
 | |
| LOCAL(bios_register_flags):
 | |
| 	.short 	0
 | |
| 	push	%ax
 | |
| 	popf
 | |
| 
 | |
| 	/* movl imm32, %eax*/
 | |
| 	.byte	0x66, 0xb8
 | |
| LOCAL(bios_register_eax):
 | |
| 	.long 	0
 | |
| 	
 | |
| 	/* int imm8.  */
 | |
| 	.byte   0xcd
 | |
| intno:	
 | |
| 	.byte   0
 | |
| 
 | |
| 	movl 	%eax, %cs:LOCAL(bios_register_eax)
 | |
| 	movw	%ds, %ax
 | |
| 	movw 	%ax, %cs:LOCAL(bios_register_ds)
 | |
| 	pop 	%ax
 | |
| 	mov	%ax, %ds
 | |
| 	pushf
 | |
| 	pop	%ax
 | |
| 	movw	%ax, LOCAL(bios_register_flags)
 | |
| 	mov 	%es, %ax
 | |
| 	movw	%ax, LOCAL(bios_register_es)
 | |
| 
 | |
| 	DATA32  call	real_to_prot
 | |
| 	.code32
 | |
| 
 | |
| 	popl    %eax
 | |
| 
 | |
| 	movl 	%ebx, 12(%eax)
 | |
| 	movl 	%ecx, 16(%eax)
 | |
| 	movl 	%edi, 20(%eax)
 | |
| 	movl 	%esi, 24(%eax)
 | |
| 	movl 	%edx, 28(%eax)
 | |
| 
 | |
| 	movl     %eax, %edx
 | |
| 
 | |
| 	movl	 LOCAL(bios_register_eax), %eax
 | |
| 	movl	 %eax, (%edx)
 | |
| 	movw	 LOCAL(bios_register_es), %ax
 | |
| 	movw	 %ax, 4(%edx)
 | |
| 	movw	 LOCAL(bios_register_ds), %ax
 | |
| 	movw	 %ax, 6(%edx)
 | |
| 	movw	 LOCAL(bios_register_flags), %ax
 | |
| 	movw	 %ax, 8(%edx)
 | |
| 
 | |
| 	popl 	%edi
 | |
| 	popl 	%esi
 | |
| 	popl    %ebx
 | |
| 	popl    %eax
 | |
| 	popl    %ecx
 | |
| 	popl    %ebp
 | |
| 	ret
 |