aboutsummaryrefslogtreecommitdiffstats
path: root/grub-core/boot/i386/pc
diff options
context:
space:
mode:
Diffstat (limited to 'grub-core/boot/i386/pc')
-rw-r--r--grub-core/boot/i386/pc/boot.S481
-rw-r--r--grub-core/boot/i386/pc/cdboot.S173
-rw-r--r--grub-core/boot/i386/pc/diskboot.S380
-rw-r--r--grub-core/boot/i386/pc/lnxboot.S299
-rw-r--r--grub-core/boot/i386/pc/pxeboot.S42
5 files changed, 1375 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..635599a
--- /dev/null
+++ b/grub-core/boot/i386/pc/boot.S
@@ -0,0 +1,481 @@
+/* -*-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/boot.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)
+
+ .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 ??? */
+
+ /*
+ * This space is for the BIOS parameter block!!!! Don't change
+ * the first jump, nor start the code anywhere but right after
+ * this area.
+ */
+
+ . = _start + GRUB_BOOT_MACHINE_BPB_START
+ . = _start + 4
+
+ /* 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... */
+
+ . = _start + GRUB_BOOT_MACHINE_BPB_END
+
+ /*
+ * End of BIOS parameter block.
+ */
+
+kernel_address:
+ .word GRUB_BOOT_MACHINE_KERNEL_ADDR
+
+ . = _start + GRUB_BOOT_MACHINE_KERNEL_SECTOR
+kernel_sector:
+ .long 1, 0
+
+ . = _start + 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).
+ */
+ . = _start + 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)
+
+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 kernel_sector, %ebx
+ movl %ebx, 8(%si)
+ movl kernel_sector + 4, %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)
+
+ /*
+ * The call failed, so maybe use the floppy probe instead.
+ */
+ testb $GRUB_BOOT_MACHINE_BIOS_HD_FLAG, %dl
+ jz 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 kernel_sector + 4, %eax
+
+ orl %eax, %eax
+ jnz LOCAL(geometry_error)
+
+ /* load logical sector start (bottom half) */
+ movl 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 *(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.
+ */
+
+ . = _start + 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?
+ */
+
+ . = _start + GRUB_BOOT_MACHINE_PART_START
+part_start:
+
+probe_values:
+ .byte 36, 18, 15, 9, 0
+
+LOCAL(floppy_probe):
+/*
+ * Perform floppy probe.
+ */
+
+ movw $probe_values - 1, %si
+
+LOCAL(probe_loop):
+ /* reset floppy controller INT 13h AH=0 */
+ xorw %ax, %ax
+ int $0x13
+
+ incw %si
+ movb (%si), %cl
+
+ /* if number of sectors is 0, display error and die */
+ cmpb $0, %cl
+ jne 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 $GRUB_BOOT_MACHINE_BUFFER_SEG, %bx
+ movw %bx, %es
+ xorw %bx, %bx
+ movw $0x201, %ax
+ movb $0, %ch
+ movb $0, %dh
+ int $0x13
+
+ /* if error, jump to "LOCAL(probe_loop)" */
+ jc LOCAL(probe_loop)
+
+ /* %cl is already the correct value! */
+ movb $1, %dh
+ movb $79, %ch
+
+ jmp LOCAL(final_init)
+
+ . = _start + 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..33569ce
--- /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/boot.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
+
+ . = start + 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. */
+ pushl %eax
+ pushl %esi
+
+ /* Buffer address. */
+ pushw $((DATA_ADDR - 0x400)>> 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"
+
+ . = start + 0x1FF
+
+ .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..92f223f
--- /dev/null
+++ b/grub-core/boot/i386/pc/diskboot.S
@@ -0,0 +1,380 @@
+/*
+ * 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 0x2000 and is jumped to with
+ * CS:IP 0:0x2000 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 $(firstlist - GRUB_BOOT_MACHINE_LIST_SIZE), %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
+
+ . = _start + 0x200 - GRUB_BOOT_MACHINE_LIST_SIZE
+
+ /* 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)
+
+firstlist: /* this label has to be after the list data!!! */
diff --git a/grub-core/boot/i386/pc/lnxboot.S b/grub-core/boot/i386/pc/lnxboot.S
new file mode 100644
index 0000000..2c75960
--- /dev/null
+++ b/grub-core/boot/i386/pc/lnxboot.S
@@ -0,0 +1,299 @@
+/* -*-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/boot.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)
+
+ . = data_start + 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
+
+#if GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_PART + 4 < 0x200
+ movl $0x200, %ecx
+ addl %ecx, %esi
+#else
+ movl $(GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_PART + 4), %ecx
+ addl $0x200, %esi
+#endif
+ movl $DATA_ADDR, %edi
+
+ call LOCAL(move_memory)
+
+ /* Check for multiboot signature. */
+ cmpl $MULTIBOOT_HEADER_MAGIC, %ss:(DATA_ADDR + GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_PART)
+ jz 1f
+
+ movl (ramdisk_image - start), %esi
+ movl (ramdisk_size - start), %ecx
+ movl $(DATA_ADDR - 0x200), %edi
+ jmp 2f
+
+1:
+
+ movl %ss:(DATA_ADDR + GRUB_KERNEL_MACHINE_COMPRESSED_SIZE), %ecx
+#if GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_PART + 4 < 0x200
+ addl $(GRUB_KERNEL_MACHINE_RAW_SIZE - 0x200), %ecx
+#else
+ addl $(GRUB_KERNEL_MACHINE_RAW_SIZE - (GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_PART + 4)), %ecx
+#endif
+
+2:
+ call LOCAL(move_memory)
+
+ movsbl %dh, %eax
+ movl %eax, %ss:(DATA_ADDR + GRUB_KERNEL_MACHINE_INSTALL_DOS_PART)
+ movsbl (reg_edx + 2 - start), %eax
+ movl %eax, %ss:(DATA_ADDR + GRUB_KERNEL_MACHINE_INSTALL_BSD_PART)
+
+ 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"
+
+ . = _start + CODE_SECTORS * 512
diff --git a/grub-core/boot/i386/pc/pxeboot.S b/grub-core/boot/i386/pc/pxeboot.S
new file mode 100644
index 0000000..446bfc7
--- /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. */
+ . = _start + 0x8200 - 0x7C00 - 0x200 - 1
+ .byte 0