summaryrefslogtreecommitdiffstats
path: root/grub-core/boot/i386
diff options
context:
space:
mode:
Diffstat (limited to 'grub-core/boot/i386')
-rw-r--r--grub-core/boot/i386/pc/boot.S542
-rw-r--r--grub-core/boot/i386/pc/cdboot.S173
-rw-r--r--grub-core/boot/i386/pc/diskboot.S378
-rw-r--r--grub-core/boot/i386/pc/lnxboot.S295
-rw-r--r--grub-core/boot/i386/pc/lzma_decode.S614
-rw-r--r--grub-core/boot/i386/pc/pxeboot.S42
-rw-r--r--grub-core/boot/i386/pc/startup_raw.S369
-rw-r--r--grub-core/boot/i386/qemu/boot.S74
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