diff options
Diffstat (limited to 'grub-core/boot/i386/pc/startup_raw.S')
-rw-r--r-- | grub-core/boot/i386/pc/startup_raw.S | 369 |
1 files changed, 369 insertions, 0 deletions
diff --git a/grub-core/boot/i386/pc/startup_raw.S b/grub-core/boot/i386/pc/startup_raw.S new file mode 100644 index 0000000..2897482 --- /dev/null +++ b/grub-core/boot/i386/pc/startup_raw.S @@ -0,0 +1,369 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999,2000,2001,2002,2003,2005,2006,2007,2008,2009,2011 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/>. + */ + +#include <config.h> +#include <grub/symbol.h> +#include <grub/offsets.h> +#include <grub/machine/boot.h> +#include <grub/machine/memory.h> +#include <grub/machine/kernel.h> + +#define ABS(x) ((x) - LOCAL (base) + GRUB_BOOT_MACHINE_KERNEL_ADDR + 0x200) + + .file "startup_raw.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 + + /* + * This is a special data area. + */ + + .org GRUB_DECOMPRESSOR_MACHINE_COMPRESSED_SIZE +LOCAL(compressed_size): + .long 0 + .org GRUB_DECOMPRESSOR_MACHINE_UNCOMPRESSED_SIZE +LOCAL(uncompressed_size): + .long 0 + + .org GRUB_KERNEL_I386_PC_REED_SOLOMON_REDUNDANCY +reed_solomon_redundancy: + .long 0 + .org GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_LENGTH + .short (LOCAL(reed_solomon_part) - _start) + +/* + * This is the area for all of the special variables. + */ + .org GRUB_DECOMPRESSOR_I386_PC_BOOT_DEVICE +LOCAL(boot_dev): + .byte 0xFF, 0xFF, 0xFF +LOCAL(boot_drive): + .byte 0x00 + +/* 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 */ + movb %dl, LOCAL(boot_drive) + + /* reset disk system (%ah = 0) */ + int $0x13 + + /* transition to protected mode */ + calll real_to_prot + + /* The ".code32" directive takes GAS out of 16-bit mode. */ + .code32 + + cld + call grub_gate_a20 + + movl LOCAL(compressed_size), %edx +#ifdef __APPLE__ + addl $decompressor_end, %edx + subl $(LOCAL(reed_solomon_part)), %edx +#else + addl $(LOCAL(decompressor_end) - LOCAL(reed_solomon_part)), %edx +#endif + movl reed_solomon_redundancy, %ecx + leal LOCAL(reed_solomon_part), %eax + cld + call EXT_C (grub_reed_solomon_recover) + jmp post_reed_solomon + +#include "../../../kern/i386/realmode.S" + +/* + * + * This is a workaround for clang adding a section containing only .addrsig + * Since clang itself is unable to assemble this pseudo-opcode, just replace + * it with .text + * + */ +#define addrsig text +#include <rs_decoder.h> +#undef addrsig + + .text + +/* + * grub_gate_a20(void) + * + * 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: +gate_a20_test_current_state: + /* first of all, test if already in a good state */ + call gate_a20_check_state + testb %al, %al + jnz gate_a20_try_bios + ret + +gate_a20_try_bios: + /* second, try a BIOS call */ + pushl %ebp + call prot_to_real + + .code16 + movw $0x2401, %ax + int $0x15 + + calll real_to_prot + .code32 + + popl %ebp + call gate_a20_check_state + testb %al, %al + 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 + orb $0x02, %al + outb $0x92 + + call gate_a20_check_state + testb %al, %al + jnz gate_a20_try_keyboard_controller + 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 $0xdf, %al + 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 + testb %al, %al + /* 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 + testb %al, %al + 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 0 if A20 is on or 1 if it is off */ + subb %ch, %al + /* restore the original */ + popl %ebx + movb %cl, (%ebx) + popl %ecx + popl %ebx + ret + +LOCAL(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 */ +#ifdef __APPLE__ + LOCAL(compressed_size_offset) = LOCAL(compressed_size) - LOCAL(base) + movl $0x200, %ecx + addl $decompressor_end, %ecx + subl $LOCAL(base), %ecx + addl LOCAL(compressed_size_offset) + 0x100000 + 0x200, %ecx +#else + movl $(LOCAL(decompressor_end) - _start + 0x200), %ecx + addl LOCAL(compressed_size) - _start + 0x100000 + 0x200, %ecx +#endif + 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, LOCAL(boot_dev) + shrl $24, %edx + /* enter the usual booting */ + call prot_to_real + .code16 + jmp LOCAL (codestart) + .code32 + +post_reed_solomon: + +#ifdef ENABLE_LZMA + movl $GRUB_MEMORY_MACHINE_DECOMPRESSION_ADDR, %edi +#ifdef __APPLE__ + movl $decompressor_end, %esi +#else + movl $LOCAL(decompressor_end), %esi +#endif + pushl %edi + movl LOCAL (uncompressed_size), %ecx + leal (%edi, %ecx), %ebx + /* Don't remove this push: it's an argument. */ + push %ecx + call _LzmaDecodeA + pop %ecx + /* _LzmaDecodeA clears DF, so no need to run cld */ + popl %esi +#endif + + movl LOCAL(boot_dev), %edx + movl $prot_to_real, %edi + movl $real_to_prot, %ecx + movl $LOCAL(realidt), %eax + jmp *%esi + +#ifdef ENABLE_LZMA +#include "lzma_decode.S" +#endif + + .p2align 4 + +#ifdef __APPLE__ + .zerofill __DATA, __aa_before_bss, decompressor_end, 10, 0 +#else + .bss +LOCAL(decompressor_end): +#endif |