diff options
Diffstat (limited to 'grub-core/boot/i386')
-rw-r--r-- | grub-core/boot/i386/pc/boot.S | 542 | ||||
-rw-r--r-- | grub-core/boot/i386/pc/cdboot.S | 173 | ||||
-rw-r--r-- | grub-core/boot/i386/pc/diskboot.S | 378 | ||||
-rw-r--r-- | grub-core/boot/i386/pc/lnxboot.S | 295 | ||||
-rw-r--r-- | grub-core/boot/i386/pc/lzma_decode.S | 614 | ||||
-rw-r--r-- | grub-core/boot/i386/pc/pxeboot.S | 42 | ||||
-rw-r--r-- | grub-core/boot/i386/pc/startup_raw.S | 369 | ||||
-rw-r--r-- | grub-core/boot/i386/qemu/boot.S | 74 |
8 files changed, 2487 insertions, 0 deletions
diff --git a/grub-core/boot/i386/pc/boot.S b/grub-core/boot/i386/pc/boot.S new file mode 100644 index 0000000..2bd0b2d --- /dev/null +++ b/grub-core/boot/i386/pc/boot.S @@ -0,0 +1,542 @@ +/* -*-Asm-*- */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999,2000,2001,2002,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/>. + */ + +#include <grub/symbol.h> +#include <grub/machine/boot.h> + +/* + * defines for the code go here + */ + + /* Print message string */ +#define MSG(x) movw $x, %si; call LOCAL(message) +#define ERR(x) movw $x, %si; jmp LOCAL(error_message) + + .macro floppy +part_start: + +LOCAL(probe_values): + .byte 36, 18, 15, 9, 0 + +LOCAL(floppy_probe): + pushw %dx +/* + * Perform floppy probe. + */ +#ifdef __APPLE__ + LOCAL(probe_values_minus_one) = LOCAL(probe_values) - 1 + movw MACRO_DOLLAR(LOCAL(probe_values_minus_one)), %si +#else + movw MACRO_DOLLAR(LOCAL(probe_values)) - 1, %si +#endif + +LOCAL(probe_loop): + /* reset floppy controller INT 13h AH=0 */ + xorw %ax, %ax + int MACRO_DOLLAR(0x13) + + incw %si + movb (%si), %cl + + /* if number of sectors is 0, display error and die */ + testb %cl, %cl + jnz 1f + +/* + * Floppy disk probe failure. + */ + MSG(fd_probe_error_string) + jmp LOCAL(general_error) + +/* "Floppy" */ +fd_probe_error_string: .asciz "Floppy" + +1: + /* perform read */ + movw MACRO_DOLLAR(GRUB_BOOT_MACHINE_BUFFER_SEG), %bx + movw %bx, %es + xorw %bx, %bx + movw MACRO_DOLLAR(0x201), %ax + movb MACRO_DOLLAR(0), %ch + movb MACRO_DOLLAR(0), %dh + int MACRO_DOLLAR(0x13) + + /* if error, jump to "LOCAL(probe_loop)" */ + jc LOCAL(probe_loop) + + /* %cl is already the correct value! */ + movb MACRO_DOLLAR(1), %dh + movb MACRO_DOLLAR(79), %ch + + jmp LOCAL(final_init) + .endm + + .macro scratch + + /* scratch space */ +mode: + .byte 0 +disk_address_packet: +sectors: + .long 0 +heads: + .long 0 +cylinders: + .word 0 +sector_start: + .byte 0 +head_start: + .byte 0 +cylinder_start: + .word 0 + /* more space... */ + .endm + + .file "boot.S" + + .text + + /* Tell GAS to generate 16-bit instructions so that this code works + in real mode. */ + .code16 + +.globl _start, start; +_start: +start: + /* + * _start is loaded at 0x7c00 and is jumped to with CS:IP 0:0x7c00 + */ + + /* + * Beginning of the sector is compatible with the FAT/HPFS BIOS + * parameter block. + */ + + jmp LOCAL(after_BPB) + nop /* do I care about this ??? */ + +#ifdef HYBRID_BOOT + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + + nop + nop + nop + nop + nop + nop + nop + nop + + nop + nop + jmp LOCAL(after_BPB) +#else + /* + * This space is for the BIOS parameter block!!!! Don't change + * the first jump, nor start the code anywhere but right after + * this area. + */ + + .org GRUB_BOOT_MACHINE_BPB_START + .org 4 +#endif +#ifdef HYBRID_BOOT + floppy +#else + scratch +#endif + + .org GRUB_BOOT_MACHINE_BPB_END + /* + * End of BIOS parameter block. + */ + +LOCAL(kernel_address): + .word GRUB_BOOT_MACHINE_KERNEL_ADDR + +#ifndef HYBRID_BOOT + .org GRUB_BOOT_MACHINE_KERNEL_SECTOR +LOCAL(kernel_sector): + .long 1 +LOCAL(kernel_sector_high): + .long 0 +#endif + + .org GRUB_BOOT_MACHINE_BOOT_DRIVE +boot_drive: + .byte 0xff /* the disk to load kernel from */ + /* 0xff means use the boot drive */ + +LOCAL(after_BPB): + +/* general setup */ + cli /* we're not safe here! */ + + /* + * This is a workaround for buggy BIOSes which don't pass boot + * drive correctly. If GRUB is installed into a HDD, check if + * DL is masked correctly. If not, assume that the BIOS passed + * a bogus value and set DL to 0x80, since this is the only + * possible boot drive. If GRUB is installed into a floppy, + * this does nothing (only jump). + */ + .org GRUB_BOOT_MACHINE_DRIVE_CHECK +boot_drive_check: + jmp 3f /* grub-setup may overwrite this jump */ + testb $0x80, %dl + jz 2f +3: + /* Ignore %dl different from 0-0x0f and 0x80-0x8f. */ + testb $0x70, %dl + jz 1f +2: + movb $0x80, %dl +1: + /* + * ljmp to the next instruction because some bogus BIOSes + * jump to 07C0:0000 instead of 0000:7C00. + */ + ljmp $0, $real_start + +real_start: + + /* set up %ds and %ss as offset from 0 */ + xorw %ax, %ax + movw %ax, %ds + movw %ax, %ss + + /* set up the REAL stack */ + movw $GRUB_BOOT_MACHINE_STACK_SEG, %sp + + sti /* we're safe again */ + + /* + * Check if we have a forced disk reference here + */ + movb boot_drive, %al + cmpb $0xff, %al + je 1f + movb %al, %dl +1: + /* save drive reference first thing! */ + pushw %dx + + /* print a notification message on the screen */ + MSG(notification_string) + + /* set %si to the disk address packet */ + movw $disk_address_packet, %si + + /* check if LBA is supported */ + movb $0x41, %ah + movw $0x55aa, %bx + int $0x13 + + /* + * %dl may have been clobbered by INT 13, AH=41H. + * This happens, for example, with AST BIOS 1.04. + */ + popw %dx + pushw %dx + + /* use CHS if fails */ + jc LOCAL(chs_mode) + cmpw $0xaa55, %bx + jne LOCAL(chs_mode) + + andw $1, %cx + jz LOCAL(chs_mode) + +LOCAL(lba_mode): + xorw %ax, %ax + movw %ax, 4(%si) + + incw %ax + /* set the mode to non-zero */ + movb %al, -1(%si) + + /* the blocks */ + movw %ax, 2(%si) + + /* the size and the reserved byte */ + movw $0x0010, (%si) + + /* the absolute address */ + movl LOCAL(kernel_sector), %ebx + movl %ebx, 8(%si) + movl LOCAL(kernel_sector_high), %ebx + movl %ebx, 12(%si) + + /* the segment of buffer address */ + movw $GRUB_BOOT_MACHINE_BUFFER_SEG, 6(%si) + +/* + * BIOS call "INT 0x13 Function 0x42" to read sectors from disk into memory + * Call with %ah = 0x42 + * %dl = drive number + * %ds:%si = segment:offset of disk address packet + * Return: + * %al = 0x0 on success; err code on failure + */ + + movb $0x42, %ah + int $0x13 + + /* LBA read is not supported, so fallback to CHS. */ + jc LOCAL(chs_mode) + + movw $GRUB_BOOT_MACHINE_BUFFER_SEG, %bx + jmp LOCAL(copy_buffer) + +LOCAL(chs_mode): + /* + * Determine the hard disk geometry from the BIOS! + * We do this first, so that LS-120 IDE floppies work correctly. + */ + movb $8, %ah + int $0x13 + jnc LOCAL(final_init) + + popw %dx + /* + * The call failed, so maybe use the floppy probe instead. + */ + testb %dl, %dl + jnb LOCAL(floppy_probe) + + /* Nope, we definitely have a hard disk, and we're screwed. */ + ERR(hd_probe_error_string) + +LOCAL(final_init): + /* set the mode to zero */ + movzbl %dh, %eax + movb %ah, -1(%si) + + /* save number of heads */ + incw %ax + movl %eax, 4(%si) + + movzbw %cl, %dx + shlw $2, %dx + movb %ch, %al + movb %dh, %ah + + /* save number of cylinders */ + incw %ax + movw %ax, 8(%si) + + movzbw %dl, %ax + shrb $2, %al + + /* save number of sectors */ + movl %eax, (%si) + +setup_sectors: + /* load logical sector start (top half) */ + movl LOCAL(kernel_sector_high), %eax + + orl %eax, %eax + jnz LOCAL(geometry_error) + + /* load logical sector start (bottom half) */ + movl LOCAL(kernel_sector), %eax + + /* zero %edx */ + xorl %edx, %edx + + /* divide by number of sectors */ + divl (%si) + + /* save sector start */ + movb %dl, %cl + + xorw %dx, %dx /* zero %edx */ + divl 4(%si) /* divide by number of heads */ + + /* do we need too many cylinders? */ + cmpw 8(%si), %ax + jge LOCAL(geometry_error) + + /* normalize sector start (1-based) */ + incb %cl + + /* low bits of cylinder start */ + movb %al, %ch + + /* high bits of cylinder start */ + xorb %al, %al + shrw $2, %ax + orb %al, %cl + + /* save head start */ + movb %dl, %al + + /* restore %dl */ + popw %dx + + /* head start */ + movb %al, %dh + +/* + * BIOS call "INT 0x13 Function 0x2" to read sectors from disk into memory + * Call with %ah = 0x2 + * %al = number of sectors + * %ch = cylinder + * %cl = sector (bits 6-7 are high bits of "cylinder") + * %dh = head + * %dl = drive (0x80 for hard disk, 0x0 for floppy disk) + * %es:%bx = segment:offset of buffer + * Return: + * %al = 0x0 on success; err code on failure + */ + + movw $GRUB_BOOT_MACHINE_BUFFER_SEG, %bx + movw %bx, %es /* load %es segment with disk buffer */ + + xorw %bx, %bx /* %bx = 0, put it at 0 in the segment */ + movw $0x0201, %ax /* function 2 */ + int $0x13 + + jc LOCAL(read_error) + + movw %es, %bx + +LOCAL(copy_buffer): + /* + * We need to save %cx and %si because the startup code in + * kernel uses them without initializing them. + */ + pusha + pushw %ds + + movw $0x100, %cx + movw %bx, %ds + xorw %si, %si + movw $GRUB_BOOT_MACHINE_KERNEL_ADDR, %di + movw %si, %es + + cld + + rep + movsw + + popw %ds + popa + + /* boot kernel */ + jmp *(LOCAL(kernel_address)) + +/* END OF MAIN LOOP */ + +/* + * BIOS Geometry translation error (past the end of the disk geometry!). + */ +LOCAL(geometry_error): + ERR(geometry_error_string) + +/* + * Read error on the disk. + */ +LOCAL(read_error): + movw $read_error_string, %si +LOCAL(error_message): + call LOCAL(message) +LOCAL(general_error): + MSG(general_error_string) + +/* go here when you need to stop the machine hard after an error condition */ + /* tell the BIOS a boot failure, which may result in no effect */ + int $0x18 +LOCAL(stop): + jmp LOCAL(stop) + +notification_string: .asciz "GRUB " +geometry_error_string: .asciz "Geom" +hd_probe_error_string: .asciz "Hard Disk" +read_error_string: .asciz "Read" +general_error_string: .asciz " Error\r\n" + +/* + * message: write the string pointed to by %si + * + * WARNING: trashes %si, %ax, and %bx + */ + + /* + * Use BIOS "int 10H Function 0Eh" to write character in teletype mode + * %ah = 0xe %al = character + * %bh = page %bl = foreground color (graphics modes) + */ +1: + movw $0x0001, %bx + movb $0xe, %ah + int $0x10 /* display a byte */ +LOCAL(message): + lodsb + cmpb $0, %al + jne 1b /* if not end of string, jmp to display */ + ret + + /* + * Windows NT breaks compatibility by embedding a magic + * number here. + */ + +#ifdef HYBRID_BOOT + .org 0x1b0 +LOCAL(kernel_sector): + .long 1 +LOCAL(kernel_sector_high): + .long 0 +#endif + .org GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC +nt_magic: + .long 0 + .word 0 + + /* + * This is where an MBR would go if on a hard disk. The code + * here isn't even referenced unless we're on a floppy. Kinda + * sneaky, huh? + */ + + .org GRUB_BOOT_MACHINE_PART_START + +#ifndef HYBRID_BOOT + floppy +#else + scratch +#endif + + .org GRUB_BOOT_MACHINE_PART_END + +/* the last 2 bytes in the sector 0 contain the signature */ + .word GRUB_BOOT_MACHINE_SIGNATURE diff --git a/grub-core/boot/i386/pc/cdboot.S b/grub-core/boot/i386/pc/cdboot.S new file mode 100644 index 0000000..de4f809 --- /dev/null +++ b/grub-core/boot/i386/pc/cdboot.S @@ -0,0 +1,173 @@ +/* -*-Asm-*- */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 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/>. + */ + +#include <grub/symbol.h> +#include <grub/machine/boot.h> +#include <grub/machine/kernel.h> +#include <multiboot.h> + + .file "cdboot.S" + +#define CODE_ADDR 0x6000 +#define DATA_ADDR ((GRUB_BOOT_MACHINE_KERNEL_ADDR) + 0x200) + +#define CDSEC_SHIFT 11 +#define CDBLK_LENG 16 + + .text + + .code16 + + .globl start, _start + +start: +_start: + call LOCAL(next) + +LOCAL(next): + jmp 1f + + .org 8 + +bi_pvd: + .long 0 /* LBA of primary volume descriptor. */ +bi_file: + .long 0 /* LBA of boot file. */ +bi_length: + .long 0 /* Length of boot file. */ +bi_csum: + .long 0 /* Checksum of boot file */ +bi_reserved: + .space (10*4) /* Reserved */ + +1: + popw %bx + + /* Boot from CDROM. */ + + xorw %ax, %ax + movw %ax, %ss + movw $(CODE_ADDR), %sp + movw %ax, %ds + movw %ax, %es + + movw $(0x7C00 + err_noboot_msg - start), %si + movl %cs: bi_length - LOCAL(next)(%bx), %ecx + orl %ecx, %ecx + jz LOCAL(fail) + + addl $((1 << CDSEC_SHIFT) - 1), %ecx + shrl $CDSEC_SHIFT, %ecx + + movl %cs: bi_file - LOCAL(next)(%bx), %esi + + call LOCAL(read_cdrom) + + ljmp $(DATA_ADDR >> 4), $0 + +/* + * Parameters: + * esi: start sector + * ecx: number of sectors + */ +LOCAL(read_cdrom): + xorl %eax, %eax + + /* Number of blocks to read. */ + pushw $CDBLK_LENG + + /* Block number. */ + incl %esi + pushl %eax + pushl %esi + + /* Buffer address. */ + pushw $((DATA_ADDR - 0x200)>> 4) + pushl %eax + pushw $0x10 + + xorl %edi, %edi + movw %sp, %si + +1: + movw 0x10(%si), %di + cmpl %ecx, %edi + jbe 2f + movl %ecx, %edi + +2: + mov %di, 2(%si) + + pushl %ecx + + movb $0x42, %ah + int $0x13 + + jnc 3f + + movb $0x42, %ah /* Try again. */ + int $0x13 + + jnc 3f + +2: + shrw $1, %di /* Reduce transfer size. */ + jz LOCAL(cdrom_fail) + movw %di, 0x10(%si) + movw %di, 2(%si) + movb $0x42, %ah + int $0x13 + jc 2b + +3: + + movw %di, %ax + shlw $(CDSEC_SHIFT - 4), %ax + addw %ax, 6(%si) + addl %edi, 8(%si) + + popl %ecx + subl %edi, %ecx + jnz 1b + + addw $0x12, %sp + ret + +LOCAL(cdrom_fail): + movw $(0x7C00 + err_cdfail_msg - start), %si + +LOCAL(fail): + movb $0x0e, %ah + xorw %bx, %bx +1: + lodsb (%si), %al + int $0x10 + cmpb $0, %al + jne 1b +1: jmp 1b + +err_noboot_msg: + .ascii "no boot info\0" + +err_cdfail_msg: + .ascii "cdrom read fails\0" + + .org 0x7FF + + .byte 0 diff --git a/grub-core/boot/i386/pc/diskboot.S b/grub-core/boot/i386/pc/diskboot.S new file mode 100644 index 0000000..c1addc0 --- /dev/null +++ b/grub-core/boot/i386/pc/diskboot.S @@ -0,0 +1,378 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999,2000,2001,2002,2006,2007,2009,2010 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 <grub/symbol.h> +#include <grub/machine/boot.h> + +/* + * defines for the code go here + */ + +#define MSG(x) movw $x, %si; call LOCAL(message) + + .file "diskboot.S" + + .text + + /* Tell GAS to generate 16-bit instructions so that this code works + in real mode. */ + .code16 + + .globl start, _start +start: +_start: + /* + * _start is loaded at 0x8000 and is jumped to with + * CS:IP 0:0x8000 in kernel. + */ + + /* + * we continue to use the stack for boot.img and assume that + * some registers are set to correct values. See boot.S + * for more information. + */ + + /* save drive reference first thing! */ + pushw %dx + + /* print a notification message on the screen */ + pushw %si + MSG(notification_string) + popw %si + + /* this sets up for the first run through "bootloop" */ + movw $LOCAL(firstlist), %di + + /* save the sector number of the second sector in %ebp */ + movl (%di), %ebp + + /* this is the loop for reading the rest of the kernel in */ +LOCAL(bootloop): + + /* check the number of sectors to read */ + cmpw $0, 8(%di) + + /* if zero, go to the start function */ + je LOCAL(bootit) + +LOCAL(setup_sectors): + /* check if we use LBA or CHS */ + cmpb $0, -1(%si) + + /* use CHS if zero, LBA otherwise */ + je LOCAL(chs_mode) + + /* load logical sector start */ + movl (%di), %ebx + movl 4(%di), %ecx + + /* the maximum is limited to 0x7f because of Phoenix EDD */ + xorl %eax, %eax + movb $0x7f, %al + + /* how many do we really want to read? */ + cmpw %ax, 8(%di) /* compare against total number of sectors */ + + /* which is greater? */ + jg 1f + + /* if less than, set to total */ + movw 8(%di), %ax + +1: + /* subtract from total */ + subw %ax, 8(%di) + + /* add into logical sector start */ + addl %eax, (%di) + adcl $0, 4(%di) + + /* set up disk address packet */ + + /* the size and the reserved byte */ + movw $0x0010, (%si) + + /* the number of sectors */ + movw %ax, 2(%si) + + /* the absolute address */ + movl %ebx, 8(%si) + movl %ecx, 12(%si) + + /* the segment of buffer address */ + movw $GRUB_BOOT_MACHINE_BUFFER_SEG, 6(%si) + + /* save %ax from destruction! */ + pushw %ax + + /* the offset of buffer address */ + movw $0, 4(%si) + +/* + * BIOS call "INT 0x13 Function 0x42" to read sectors from disk into memory + * Call with %ah = 0x42 + * %dl = drive number + * %ds:%si = segment:offset of disk address packet + * Return: + * %al = 0x0 on success; err code on failure + */ + + movb $0x42, %ah + int $0x13 + + jc LOCAL(read_error) + + movw $GRUB_BOOT_MACHINE_BUFFER_SEG, %bx + jmp LOCAL(copy_buffer) + +LOCAL(chs_mode): + /* load logical sector start (top half) */ + movl 4(%di), %eax + orl %eax, %eax + jnz LOCAL(geometry_error) + + /* load logical sector start (bottom half) */ + movl (%di), %eax + + /* zero %edx */ + xorl %edx, %edx + + /* divide by number of sectors */ + divl (%si) + + /* save sector start */ + movb %dl, 10(%si) + + xorl %edx, %edx /* zero %edx */ + divl 4(%si) /* divide by number of heads */ + + /* save head start */ + movb %dl, 11(%si) + + /* save cylinder start */ + movw %ax, 12(%si) + + /* do we need too many cylinders? */ + cmpw 8(%si), %ax + jge LOCAL(geometry_error) + + /* determine the maximum sector length of this read */ + movw (%si), %ax /* get number of sectors per track/head */ + + /* subtract sector start */ + subb 10(%si), %al + + /* how many do we really want to read? */ + cmpw %ax, 8(%di) /* compare against total number of sectors */ + + + /* which is greater? */ + jg 2f + + /* if less than, set to total */ + movw 8(%di), %ax + +2: + /* subtract from total */ + subw %ax, 8(%di) + + /* add into logical sector start */ + addl %eax, (%di) + adcl $0, 4(%di) + +/* + * This is the loop for taking care of BIOS geometry translation (ugh!) + */ + + /* get high bits of cylinder */ + movb 13(%si), %dl + + shlb $6, %dl /* shift left by 6 bits */ + movb 10(%si), %cl /* get sector */ + + incb %cl /* normalize sector (sectors go + from 1-N, not 0-(N-1) ) */ + orb %dl, %cl /* composite together */ + movb 12(%si), %ch /* sector+hcyl in cl, cylinder in ch */ + + /* restore %dx */ + popw %dx + pushw %dx + + /* head number */ + movb 11(%si), %dh + + pushw %ax /* save %ax from destruction! */ + +/* + * BIOS call "INT 0x13 Function 0x2" to read sectors from disk into memory + * Call with %ah = 0x2 + * %al = number of sectors + * %ch = cylinder + * %cl = sector (bits 6-7 are high bits of "cylinder") + * %dh = head + * %dl = drive (0x80 for hard disk, 0x0 for floppy disk) + * %es:%bx = segment:offset of buffer + * Return: + * %al = 0x0 on success; err code on failure + */ + + movw $GRUB_BOOT_MACHINE_BUFFER_SEG, %bx + movw %bx, %es /* load %es segment with disk buffer */ + + xorw %bx, %bx /* %bx = 0, put it at 0 in the segment */ + movb $0x2, %ah /* function 2 */ + int $0x13 + + jc LOCAL(read_error) + + /* save source segment */ + movw %es, %bx + +LOCAL(copy_buffer): + + /* load addresses for copy from disk buffer to destination */ + movw 10(%di), %es /* load destination segment */ + + /* restore %ax */ + popw %ax + + /* determine the next possible destination address (presuming + 512 byte sectors!) */ + shlw $5, %ax /* shift %ax five bits to the left */ + addw %ax, 10(%di) /* add the corrected value to the destination + address for next time */ + + /* save addressing regs */ + pusha + pushw %ds + + /* get the copy length */ + shlw $3, %ax + movw %ax, %cx + + xorw %di, %di /* zero offset of destination addresses */ + xorw %si, %si /* zero offset of source addresses */ + movw %bx, %ds /* restore the source segment */ + + cld /* sets the copy direction to forward */ + + /* perform copy */ + rep /* sets a repeat */ + movsw /* this runs the actual copy */ + + /* restore addressing regs and print a dot with correct DS + (MSG modifies SI, which is saved, and unused AX and BX) */ + popw %ds + MSG(notification_step) + popa + + /* check if finished with this dataset */ + cmpw $0, 8(%di) + jne LOCAL(setup_sectors) + + /* update position to load from */ + subw $GRUB_BOOT_MACHINE_LIST_SIZE, %di + + /* jump to bootloop */ + jmp LOCAL(bootloop) + +/* END OF MAIN LOOP */ + +LOCAL(bootit): + /* print a newline */ + MSG(notification_done) + popw %dx /* this makes sure %dl is our "boot" drive */ + ljmp $0, $(GRUB_BOOT_MACHINE_KERNEL_ADDR + 0x200) + + +/* + * BIOS Geometry translation error (past the end of the disk geometry!). + */ +LOCAL(geometry_error): + MSG(geometry_error_string) + jmp LOCAL(general_error) + +/* + * Read error on the disk. + */ +LOCAL(read_error): + MSG(read_error_string) + +LOCAL(general_error): + MSG(general_error_string) + +/* go here when you need to stop the machine hard after an error condition */ +LOCAL(stop): jmp LOCAL(stop) + +notification_string: .asciz "loading" + +notification_step: .asciz "." +notification_done: .asciz "\r\n" + +geometry_error_string: .asciz "Geom" +read_error_string: .asciz "Read" +general_error_string: .asciz " Error" + +/* + * message: write the string pointed to by %si + * + * WARNING: trashes %si, %ax, and %bx + */ + + /* + * Use BIOS "int 10H Function 0Eh" to write character in teletype mode + * %ah = 0xe %al = character + * %bh = page %bl = foreground color (graphics modes) + */ +1: + movw $0x0001, %bx + movb $0xe, %ah + int $0x10 /* display a byte */ + + incw %si +LOCAL(message): + movb (%si), %al + cmpb $0, %al + jne 1b /* if not end of string, jmp to display */ + ret + +/* + * This area is an empty space between the main body of code below which + * grows up (fixed after compilation, but between releases it may change + * in size easily), and the lists of sectors to read, which grows down + * from a fixed top location. + */ + + .word 0 + .word 0 + + .org 0x200 - GRUB_BOOT_MACHINE_LIST_SIZE +LOCAL(firstlist): /* this label has to be before the first list entry!!! */ + /* fill the first data listing with the default */ +blocklist_default_start: + /* this is the sector start parameter, in logical sectors from + the start of the disk, sector 0 */ + .long 2, 0 +blocklist_default_len: + /* this is the number of sectors to read. grub-mkimage + will fill this up */ + .word 0 +blocklist_default_seg: + /* this is the segment of the starting address to load the data into */ + .word (GRUB_BOOT_MACHINE_KERNEL_SEG + 0x20) diff --git a/grub-core/boot/i386/pc/lnxboot.S b/grub-core/boot/i386/pc/lnxboot.S new file mode 100644 index 0000000..2dda0e0 --- /dev/null +++ b/grub-core/boot/i386/pc/lnxboot.S @@ -0,0 +1,295 @@ +/* -*-Asm-*- */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 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/>. + */ + +#include <config.h> +#include <grub/symbol.h> +#include <grub/machine/boot.h> +#include <grub/machine/kernel.h> +#include <multiboot.h> + + .file "lnxboot.S" + +#define CODE_ADDR 0x6000 +#define CODE_SECTORS 1 +#define DATA_ADDR ((GRUB_BOOT_MACHINE_KERNEL_ADDR) + 0x200) + +#define BLCK_LENG 0x4000 + + .text + + .code16 + + .globl start, _start + +data_start: + xorl %ebp, %ebp + jmp LOCAL(linux_next) + + .org 0x1F1 + +setup_sects: + .byte CODE_SECTORS +root_flags: + .word 0 +syssize: + .word 0 +swap_dev: + .word 0 +ram_size: + .word 0 +vid_mode: + .word 0 +root_dev: + .word 0 +boot_flag: + .word 0xAA55 + +start: +_start: + + jmp LOCAL(linux_init) + + .ascii "HdrS" /* Header signature. */ + .word 0x0203 /* Header version number. */ + +realmode_swtch: + .word 0, 0 /* default_switch, SETUPSEG. */ +start_sys_seg: + .word 0x1000 /* Obsolete. */ +version_ptr: + .word 0 /* Version string ptr. */ +type_of_loader: + .byte 0 /* Filled in by boot loader. */ +loadflags: + .byte 1 /* Please load high. */ +setup_move_size: + .word 0 /* Unused. */ +code32_start: + .long 0x100000 /* 32-bit start address. */ +ramdisk_image: + .long 0 /* Loaded ramdisk image address. */ +ramdisk_size: + .long 0 /* Size of loaded ramdisk. */ +bootsect_kludge: + .word 0, 0 +heap_end_ptr: + .word 0 +pad1: + .word 0 +cmd_line_ptr: + .long 0 /* Command line. */ +ramdisk_max: + .long 0xffffffff /* Highest allowed ramdisk address. */ + +gdt: + .long 0, 0, 0, 0 /* Must be zero. */ + .word 0xffff /* 64 K segment size. */ +gdt_src1: + .byte 0, 0 ,0 /* Low 24 bits of source address. */ + .byte 0x93 /* Access rights. */ + .byte 0 /* Extended access rights. */ +gdt_src2: + .byte 0 /* High 8 bits of source address. */ + .word 0xffff /* 64 K segment size. */ +gdt_dst1: + .byte 0, 0, 0 /* Low 24 bits of target address. */ + .byte 0x93 /* Access rights. */ + .byte 0 /* Extended access rights. */ +gdt_dst2: + .byte 0 /* High 8 bits of source address. */ + .long 0, 0, 0, 0 /* More space for the BIOS. */ + +reg_edx: + .byte 0x80, 0, 0xFF, 0xFF + +data_leng: + .long 0 + +LOCAL(linux_init): + movw %cs:(reg_edx - start), %dx + movl %cs:(code32_start - start), %ebp + +LOCAL(linux_next): + + call LOCAL(normalize) + +LOCAL(normalize): + popw %bx + subw $(LOCAL(normalize) - start), %bx + shrw $4, %bx + movw %cs, %ax + addw %bx, %ax + pushw %ax + pushw $(real_code - start) + lret /* Jump to real_code. */ + +real_code: + subw $0x20, %ax + movw %ax, %ds + movw (setup_sects - data_start), %cx + shlw $7, %cx + + /* Setup stack. */ + + xorw %si, %si + movw %si, %ss + movw $(CODE_ADDR), %sp + + /* Move itself to 0:CODE_ADDR. */ + + cld + movw %cs, %ax + movw %ax, %ds + movw $(CODE_ADDR >> 4), %ax + movw %ax, %es + movw %si, %di + + rep + movsl + ljmp $(CODE_ADDR >> 4), $(real_code_2 - start) + +real_code_2: + + xchgl %ebp, %esi + orl %esi, %esi + jnz 1f + movw %ds, %si + shll $4, %esi + addl %ebp, %esi +1: + + pushw %es + popw %ds + + movl $0x1000, %ecx + addl $0x200, %esi + movl $DATA_ADDR, %edi + + call LOCAL(move_memory) + + /* Check for multiboot signature. */ + movl $DATA_ADDR, %edi +3: + movl %ss:(%edi), %eax + cmpl $MULTIBOOT_HEADER_MAGIC, %eax + jz 1f + addl $4, %edi + cmpl $(DATA_ADDR + 0x1000), %edi + jne 3b + + movl (ramdisk_image - start), %esi + movl (ramdisk_size - start), %ecx + movl $(DATA_ADDR - 0x200), %edi + jmp 2f + +1: + + movl $(DATA_ADDR + 0x1000), %edi + movl %ss:(DATA_ADDR + GRUB_DECOMPRESSOR_MACHINE_COMPRESSED_SIZE), %ecx + addl $GRUB_DECOMPRESSOR_I386_PC_MAX_DECOMPRESSOR_SIZE, %ecx + +2: + call LOCAL(move_memory) + + movb %dh, %ss:(DATA_ADDR + GRUB_DECOMPRESSOR_I386_PC_BOOT_DEVICE + 2) + movb (reg_edx + 2 - start), %dh + movb %dh, %ss:(DATA_ADDR + GRUB_DECOMPRESSOR_I386_PC_BOOT_DEVICE + 1) + + movb $0xFF, %dh + + ljmp $(DATA_ADDR >> 4), $0 + +/* + * Parameters: + * esi: source address + * edi: target address + * ecx: number of bytes + */ + +LOCAL(move_memory): + incl %ecx + andb $0xFE, %cl + pushw %dx +1: + pushl %esi + pushl %edi + pushl %ecx + cmpl $BLCK_LENG, %ecx + jbe 2f + movl $BLCK_LENG, %ecx +2: + pushl %ecx + + movl %esi, %eax + movw %si, (gdt_src1 - start) + shrl $16, %eax + movb %al, (gdt_src1 + 2 - start) + movb %ah, (gdt_src2 - start) + + movl %edi, %eax + movw %di, (gdt_dst1 - start) + shrl $16, %eax + movb %al, (gdt_dst1 + 2 - start) + movb %ah, (gdt_dst2 - start) + + movw $(gdt - start), %si + movb $0x87, %ah + shrw $1, %cx + + int $0x15 + + popl %eax + popl %ecx + popl %edi + popl %esi + + jnc 2f + movw $(err_int15_msg - start), %si + jmp LOCAL(fail) + +2: + + addl %eax, %esi + addl %eax, %edi + subl %eax, %ecx + jnz 1b + + + popw %dx + ret + +/* + * Parameters: + * si: message + */ + +LOCAL(fail): + movb $0x0e, %ah + xorw %bx, %bx +1: + lodsb (%si), %al + int $0x10 + cmpb $0, %al + jne 1b +1: jmp 1b + +err_int15_msg: + .ascii "move memory fails\0" + + .org (CODE_SECTORS * 512 + 512) diff --git a/grub-core/boot/i386/pc/lzma_decode.S b/grub-core/boot/i386/pc/lzma_decode.S new file mode 100644 index 0000000..88c668d --- /dev/null +++ b/grub-core/boot/i386/pc/lzma_decode.S @@ -0,0 +1,614 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 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/>. + */ + +#define FIXED_PROPS + +#define LZMA_BASE_SIZE 1846 +#define LZMA_LIT_SIZE 768 + +#define LZMA_PROPERTIES_SIZE 5 + +#define kNumTopBits 24 +#define kTopValue (1 << kNumTopBits) + +#define kNumBitModelTotalBits 11 +#define kBitModelTotal (1 << kNumBitModelTotalBits) +#define kNumMoveBits 5 + + +#define kNumPosBitsMax 4 +#define kNumPosStatesMax (1 << kNumPosBitsMax) + +#define kLenNumLowBits 3 +#define kLenNumLowSymbols (1 << kLenNumLowBits) +#define kLenNumMidBits 3 +#define kLenNumMidSymbols (1 << kLenNumMidBits) +#define kLenNumHighBits 8 +#define kLenNumHighSymbols (1 << kLenNumHighBits) + +#define LenChoice 0 +#define LenChoice2 (LenChoice + 1) +#define LenLow (LenChoice2 + 1) +#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits)) +#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits)) +#define kNumLenProbs (LenHigh + kLenNumHighSymbols) + + +#define kNumStates 12 +#define kNumLitStates 7 + +#define kStartPosModelIndex 4 +#define kEndPosModelIndex 14 +#define kNumFullDistances (1 << (kEndPosModelIndex >> 1)) + +#define kNumPosSlotBits 6 +#define kNumLenToPosStates 4 + +#define kNumAlignBits 4 +#define kAlignTableSize (1 << kNumAlignBits) + +#define kMatchMinLen 2 + +#define IsMatch 0 +#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax)) +#define IsRepG0 (IsRep + kNumStates) +#define IsRepG1 (IsRepG0 + kNumStates) +#define IsRepG2 (IsRepG1 + kNumStates) +#define IsRep0Long (IsRepG2 + kNumStates) +#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax)) +#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits)) +#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex) +#define LenCoder (Align + kAlignTableSize) +#define RepLenCoder (LenCoder + kNumLenProbs) +#define Literal (RepLenCoder + kNumLenProbs) + +#define out_size 8(%ebp) + +#define now_pos -4(%ebp) +#define prev_byte -8(%ebp) +#define range -12(%ebp) +#define code -16(%ebp) +#define state -20(%ebp) +#define rep0 -24(%ebp) +#define rep1 -28(%ebp) +#define rep2 -32(%ebp) +#define rep3 -36(%ebp) + +#ifdef FIXED_PROPS + +#define FIXED_LC 3 +#define FIXED_LP 0 +#define FIXED_PB 2 + +#define POS_STATE_MASK ((1 << (FIXED_PB)) - 1) +#define LIT_POS_MASK ((1 << (FIXED_LP)) - 1) + +#define LOCAL_SIZE 36 + +#else + +#define lc (%ebx) +#define lp 4(%ebx) +#define pb 8(%ebx) +#define probs 12(%ebx) + +#define pos_state_mask -40(%ebp) +#define lit_pos_mask -44(%ebp) + +#define LOCAL_SIZE 44 + +#endif + +RangeDecoderBitDecode: +#ifdef FIXED_PROPS + leal (%ebx, %eax, 4), %eax +#else + shll $2, %eax + addl probs, %eax +#endif + + movl %eax, %ecx + movl (%ecx), %eax + + movl range, %edx + shrl $kNumBitModelTotalBits, %edx + mull %edx + + cmpl code, %eax + jbe 1f + + movl %eax, range + movl $kBitModelTotal, %edx + subl (%ecx), %edx + shrl $kNumMoveBits, %edx + addl %edx, (%ecx) + clc +3: + pushf + cmpl $kTopValue, range + jnc 2f + shll $8, code + lodsb + movb %al, code + shll $8, range +2: + popf + ret +1: + subl %eax, range + subl %eax, code + movl (%ecx), %edx + shrl $kNumMoveBits, %edx + subl %edx, (%ecx) + stc + jmp 3b + +RangeDecoderBitTreeDecode: +RangeDecoderReverseBitTreeDecode: + movzbl %cl, %ecx + xorl %edx, %edx + pushl %edx + incl %edx + pushl %edx + +1: + pushl %eax + pushl %ecx + pushl %edx + + addl %edx, %eax + call RangeDecoderBitDecode + + popl %edx + popl %ecx + + jnc 2f + movl 4(%esp), %eax + orl %eax, 8(%esp) + stc + +2: + adcl %edx, %edx + popl %eax + + shll $1, (%esp) + loop 1b + + popl %ecx + subl %ecx, %edx /* RangeDecoderBitTreeDecode */ + popl %ecx /* RangeDecoderReverseBitTreeDecode */ + ret + +LzmaLenDecode: + pushl %eax + addl $LenChoice, %eax + call RangeDecoderBitDecode + popl %eax + jc 1f + pushl $0 + movb $kLenNumLowBits, %cl + addl $LenLow, %eax +2: + movl 12(%esp), %edx + shll %cl, %edx + addl %edx, %eax +3: + + call RangeDecoderBitTreeDecode + popl %eax + addl %eax, %edx + ret + +1: + pushl %eax + addl $LenChoice2, %eax + call RangeDecoderBitDecode + popl %eax + jc 1f + pushl $kLenNumLowSymbols + movb $kLenNumMidBits, %cl + addl $LenMid, %eax + jmp 2b + +1: + pushl $(kLenNumLowSymbols + kLenNumMidSymbols) + addl $LenHigh, %eax + movb $kLenNumHighBits, %cl + jmp 3b + +WriteByte: + movb %al, prev_byte + stosb + incl now_pos + ret + +/* + * int LzmaDecode(CLzmaDecoderState *vs, + * const unsigned char *inStream, + * unsigned char *outStream, + * SizeT outSize); + */ + +_LzmaDecodeA: + + pushl %ebp + movl %esp, %ebp + subl $LOCAL_SIZE, %esp + +#ifndef ASM_FILE + pushl %esi + pushl %edi + pushl %ebx + + movl %eax, %ebx + movl %edx, %esi + pushl %ecx +#else + pushl %edi +#endif + + cld + +#ifdef FIXED_PROPS + movl %ebx, %edi + movl $(Literal + (LZMA_LIT_SIZE << (FIXED_LC + FIXED_LP))), %ecx +#else + movl $LZMA_LIT_SIZE, %eax + movb lc, %cl + addb lp, %cl + shll %cl, %eax + addl $Literal, %eax + movl %eax, %ecx + movl probs, %edi +#endif + + movl $(kBitModelTotal >> 1), %eax + + rep + stosl + + popl %edi + + xorl %eax, %eax + movl %eax, now_pos + movl %eax, prev_byte + movl %eax, state + + incl %eax + movl %eax, rep0 + movl %eax, rep1 + movl %eax, rep2 + movl %eax, rep3 + +#ifndef FIXED_PROPS + movl %eax, %edx + movb pb, %cl + shll %cl, %edx + decl %edx + movl %edx, pos_state_mask + + movl %eax, %edx + movb lp, %cl + shll %cl, %edx + decl %edx + movl %edx, lit_pos_mask; +#endif + + /* RangeDecoderInit */ + negl %eax + movl %eax, range + + incl %eax + movb $5, %cl + +1: + shll $8, %eax + lodsb + loop 1b + + movl %eax, code + +lzma_decode_loop: + movl now_pos, %eax + cmpl out_size, %eax + + jb 1f + +#ifndef ASM_FILE + xorl %eax, %eax + + popl %ebx + popl %edi + popl %esi +#endif + + movl %ebp, %esp + popl %ebp + ret + +1: +#ifdef FIXED_PROPS + andl $POS_STATE_MASK, %eax +#else + andl pos_state_mask, %eax +#endif + pushl %eax /* posState */ + movl state, %edx + shll $kNumPosBitsMax, %edx + addl %edx, %eax + pushl %eax /* (state << kNumPosBitsMax) + posState */ + + call RangeDecoderBitDecode + jc 1f + + movl now_pos, %eax + +#ifdef FIXED_PROPS + andl $LIT_POS_MASK, %eax + shll $FIXED_LC, %eax + movl prev_byte, %edx + shrl $(8 - FIXED_LC), %edx +#else + andl lit_pos_mask, %eax + movb lc, %cl + shll %cl, %eax + negb %cl + addb $8, %cl + movl prev_byte, %edx + shrl %cl, %edx +#endif + + addl %edx, %eax + movl $LZMA_LIT_SIZE, %edx + mull %edx + addl $Literal, %eax + pushl %eax + + incl %edx /* edx = 1 */ + + movl rep0, %eax + negl %eax + pushl (%edi, %eax) /* matchByte */ + + cmpb $kNumLitStates, state + jb 5f + + /* LzmaLiteralDecodeMatch */ + +3: + cmpl $0x100, %edx + jae 4f + + xorl %eax, %eax + shlb $1, (%esp) + adcl %eax, %eax + + pushl %eax + pushl %edx + + shll $8, %eax + leal 0x100(%edx, %eax), %eax + addl 12(%esp), %eax + call RangeDecoderBitDecode + + setc %al + popl %edx + adcl %edx, %edx + + popl %ecx + cmpb %cl, %al + jz 3b + +5: + + /* LzmaLiteralDecode */ + + cmpl $0x100, %edx + jae 4f + + pushl %edx + movl %edx, %eax + addl 8(%esp), %eax + call RangeDecoderBitDecode + popl %edx + adcl %edx, %edx + jmp 5b + +4: + addl $16, %esp + + movb %dl, %al + call WriteByte + + movb state, %al + cmpb $4, %al + jae 2f + xorb %al, %al + jmp 3f +2: + subb $3, %al + cmpb $7, %al + jb 3f + subb $3, %al +3: + movb %al, state + jmp lzma_decode_loop + +1: + movl state, %eax + addl $IsRep, %eax + call RangeDecoderBitDecode + jnc 1f + + movl state, %eax + addl $IsRepG0, %eax + call RangeDecoderBitDecode + jc 10f + + movl (%esp), %eax + addl $IsRep0Long, %eax + call RangeDecoderBitDecode + jc 20f + + cmpb $7, state + movb $9, state + jb 100f + addb $2, state +100: + + movl $1, %ecx + +3: + movl rep0, %edx + negl %edx + +4: + movb (%edi, %edx), %al + call WriteByte + loop 4b + + popl %eax + popl %eax + jmp lzma_decode_loop + +10: + movl state, %eax + addl $IsRepG1, %eax + call RangeDecoderBitDecode + movl rep1, %edx + jnc 100f + + movl state, %eax + addl $IsRepG2, %eax + call RangeDecoderBitDecode + movl rep2, %edx + jnc 1000f + movl rep2, %edx + xchgl rep3, %edx +1000: + pushl rep1 + popl rep2 +100: + xchg rep0, %edx + movl %edx, rep1 +20: + + movl $RepLenCoder, %eax + call LzmaLenDecode + + cmpb $7, state + movb $8, state + jb 100f + addb $3, state +100: + jmp 2f + +1: + movl rep0, %eax + xchgl rep1, %eax + xchgl rep2, %eax + movl %eax, rep3 + + cmpb $7, state + movb $7, state + jb 10f + addb $3, state +10: + + movl $LenCoder, %eax + call LzmaLenDecode + pushl %edx + + movl $(kNumLenToPosStates - 1), %eax + cmpl %eax, %edx + jbe 100f + movl %eax, %edx +100: + movb $kNumPosSlotBits, %cl + shll %cl, %edx + leal PosSlot(%edx), %eax + call RangeDecoderBitTreeDecode + + movl %edx, rep0 + cmpl $kStartPosModelIndex, %edx + jb 100f + + movl %edx, %ecx + shrl $1, %ecx + decl %ecx + + movzbl %dl, %eax + andb $1, %al + orb $2, %al + shll %cl, %eax + movl %eax, rep0 + + cmpl $kEndPosModelIndex, %edx + jae 200f + movl rep0, %eax + addl $(SpecPos - 1), %eax + subl %edx, %eax + jmp 300f +200: + + subb $kNumAlignBits, %cl + + /* RangeDecoderDecodeDirectBits */ + xorl %edx, %edx + +1000: + shrl $1, range + shll $1, %edx + + movl range, %eax + cmpl %eax, code + jb 2000f + subl %eax, code + orb $1, %dl +2000: + + cmpl $kTopValue, %eax + jae 3000f + shll $8, range + shll $8, code + lodsb + movb %al, code + +3000: + loop 1000b + + movb $kNumAlignBits, %cl + shll %cl, %edx + addl %edx, rep0 + + movl $Align, %eax + +300: + call RangeDecoderReverseBitTreeDecode + addl %ecx, rep0 + +100: + incl rep0 + popl %edx + +2: + + addl $kMatchMinLen, %edx + movl %edx, %ecx + + jmp 3b diff --git a/grub-core/boot/i386/pc/pxeboot.S b/grub-core/boot/i386/pc/pxeboot.S new file mode 100644 index 0000000..b695b24 --- /dev/null +++ b/grub-core/boot/i386/pc/pxeboot.S @@ -0,0 +1,42 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2000,2005,2007,2008,2009,2010 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 <grub/machine/boot.h> + + .file "pxeboot.S" + .text + + /* Start with the prehistoric environment... */ + .code16 + + /* Let's go */ +.globl start, _start; +_start: +start: + + /* Use drive number 0x7F for PXE */ + movb $GRUB_BOOT_MACHINE_PXE_DL, %dl + + /* Jump to the real world */ + ljmp $0, $0x8200 + + /* This region is a junk. Do you say that this is wasteful? + But I like that the memory layout of the body is consistent + among different kernels rather than scamping just for 1.5KB. */ + .org 0x8200 - 0x7C00 - 0x200 - 1 + .byte 0 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 diff --git a/grub-core/boot/i386/qemu/boot.S b/grub-core/boot/i386/qemu/boot.S new file mode 100644 index 0000000..8c3a1db --- /dev/null +++ b/grub-core/boot/i386/qemu/boot.S @@ -0,0 +1,74 @@ +/* + * 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/>. + */ + +#include <config.h> +#include <grub/symbol.h> +#include <grub/machine/memory.h> +#include <grub/machine/boot.h> +#include <grub/machine/kernel.h> + + .text + .code16 + .globl _start +_start: + /* Disable interrupts. */ + cli + + jmp 1f + + .org GRUB_BOOT_I386_QEMU_CORE_ENTRY_ADDR +VARIABLE(grub_core_entry_addr) + .long 0 +1: + + /* Set up %ds, %ss, and %es. */ + xorw %ax, %ax + movw %ax, %ds + movw %ax, %ss + movw %ax, %es + + /* Set up the real mode stack. */ + movl $GRUB_MEMORY_MACHINE_REAL_STACK, %esp + + /* Transition to protected mode. We use pushl to force generation + of a flat return address. */ + pushl $1f + jmp real_to_prot + .code32 +1: + /* Ensure A20 is enabled. We're in qemu, so control port A works + and there is no need to wait since there is no real logic, it's + all emulated. */ + inb $0x92 + andb $(~0x03), %al + orb $0x02, %al + outb $0x92 + movl EXT_C(grub_core_entry_addr), %edx + jmp *%edx + +#include "../../../kern/i386/realmode.S" + + /* Intel, in its infinite wisdom, decided to put the i8086 entry point + *right here* and this is why we need this kludge. */ + + .org GRUB_BOOT_MACHINE_SIZE - 16 + + .code16 + + jmp _start + .org GRUB_BOOT_MACHINE_SIZE |