aboutsummaryrefslogtreecommitdiffstats
path: root/grub-core/kern/i386/pc
diff options
context:
space:
mode:
authorJames <james.mckenzie@citrix.com>2012-11-16 10:41:01 +0000
committerJames <james.mckenzie@citrix.com>2012-11-16 10:41:01 +0000
commit041d1ea37802bf7178a31a53f96c26efa6b8fb7b (patch)
treec193e84ad1237f25a79d0f6a267722e44c73f56a /grub-core/kern/i386/pc
downloadgrub-1.99-041d1ea37802bf7178a31a53f96c26efa6b8fb7b.tar.gz
grub-1.99-041d1ea37802bf7178a31a53f96c26efa6b8fb7b.tar.bz2
grub-1.99-041d1ea37802bf7178a31a53f96c26efa6b8fb7b.zip
fish
Diffstat (limited to 'grub-core/kern/i386/pc')
-rw-r--r--grub-core/kern/i386/pc/init.c234
-rw-r--r--grub-core/kern/i386/pc/lzma_decode.S614
-rw-r--r--grub-core/kern/i386/pc/mmap.c190
-rw-r--r--grub-core/kern/i386/pc/startup.S1011
4 files changed, 2049 insertions, 0 deletions
diff --git a/grub-core/kern/i386/pc/init.c b/grub-core/kern/i386/pc/init.c
new file mode 100644
index 0000000..d8c337b
--- /dev/null
+++ b/grub-core/kern/i386/pc/init.c
@@ -0,0 +1,234 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2002,2003,2004,2005,2006,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/kernel.h>
+#include <grub/mm.h>
+#include <grub/machine/boot.h>
+#include <grub/i386/floppy.h>
+#include <grub/machine/memory.h>
+#include <grub/machine/console.h>
+#include <grub/machine/kernel.h>
+#include <grub/machine/int.h>
+#include <grub/types.h>
+#include <grub/err.h>
+#include <grub/dl.h>
+#include <grub/misc.h>
+#include <grub/loader.h>
+#include <grub/env.h>
+#include <grub/cache.h>
+#include <grub/time.h>
+#include <grub/cpu/tsc.h>
+
+struct mem_region
+{
+ grub_addr_t addr;
+ grub_size_t size;
+};
+
+#define MAX_REGIONS 32
+
+static struct mem_region mem_regions[MAX_REGIONS];
+static int num_regions;
+
+static char *
+make_install_device (void)
+{
+ /* XXX: This should be enough. */
+ char dev[100], *ptr = dev;
+
+ if (grub_prefix[0] != '(')
+ {
+ /* No hardcoded root partition - make it from the boot drive and the
+ partition number encoded at the install time. */
+ if (grub_boot_drive == GRUB_BOOT_MACHINE_PXE_DL)
+ {
+ grub_strcpy (dev, "(pxe");
+ ptr += sizeof ("(pxe") - 1;
+ }
+ else
+ {
+ grub_snprintf (dev, sizeof (dev),
+ "(%cd%u", (grub_boot_drive & 0x80) ? 'h' : 'f',
+ grub_boot_drive & 0x7f);
+ ptr += grub_strlen (ptr);
+
+ if (grub_install_dos_part >= 0)
+ grub_snprintf (ptr, sizeof (dev) - (ptr - dev),
+ ",%u", grub_install_dos_part + 1);
+ ptr += grub_strlen (ptr);
+
+ if (grub_install_bsd_part >= 0)
+ grub_snprintf (ptr, sizeof (dev) - (ptr - dev), ",%u",
+ grub_install_bsd_part + 1);
+ ptr += grub_strlen (ptr);
+ }
+
+ grub_snprintf (ptr, sizeof (dev) - (ptr - dev), ")%s", grub_prefix);
+ grub_strcpy (grub_prefix, dev);
+ }
+ else if (grub_prefix[1] == ',' || grub_prefix[1] == ')')
+ {
+ /* We have a prefix, but still need to fill in the boot drive. */
+ grub_snprintf (dev, sizeof (dev),
+ "(%cd%u%s", (grub_boot_drive & 0x80) ? 'h' : 'f',
+ grub_boot_drive & 0x7f, grub_prefix + 1);
+ grub_strcpy (grub_prefix, dev);
+ }
+
+ return grub_prefix;
+}
+
+/* Add a memory region. */
+static void
+add_mem_region (grub_addr_t addr, grub_size_t size)
+{
+ if (num_regions == MAX_REGIONS)
+ /* Ignore. */
+ return;
+
+ mem_regions[num_regions].addr = addr;
+ mem_regions[num_regions].size = size;
+ num_regions++;
+}
+
+/* Compact memory regions. */
+static void
+compact_mem_regions (void)
+{
+ int i, j;
+
+ /* Sort them. */
+ for (i = 0; i < num_regions - 1; i++)
+ for (j = i + 1; j < num_regions; j++)
+ if (mem_regions[i].addr > mem_regions[j].addr)
+ {
+ struct mem_region tmp = mem_regions[i];
+ mem_regions[i] = mem_regions[j];
+ mem_regions[j] = tmp;
+ }
+
+ /* Merge overlaps. */
+ for (i = 0; i < num_regions - 1; i++)
+ if (mem_regions[i].addr + mem_regions[i].size >= mem_regions[i + 1].addr)
+ {
+ j = i + 1;
+
+ if (mem_regions[i].addr + mem_regions[i].size
+ < mem_regions[j].addr + mem_regions[j].size)
+ mem_regions[i].size = (mem_regions[j].addr + mem_regions[j].size
+ - mem_regions[i].addr);
+
+ grub_memmove (mem_regions + j, mem_regions + j + 1,
+ (num_regions - j - 1) * sizeof (struct mem_region));
+ i--;
+ num_regions--;
+ }
+}
+
+void
+grub_machine_init (void)
+{
+ int i;
+#if 0
+ int grub_lower_mem;
+#endif
+
+ /* Initialize the console as early as possible. */
+ grub_console_init ();
+
+ /* This sanity check is useless since top of GRUB_MEMORY_MACHINE_RESERVED_END
+ is used for stack and if it's unavailable we wouldn't have gotten so far.
+ */
+#if 0
+ grub_lower_mem = grub_get_conv_memsize () << 10;
+
+ /* Sanity check. */
+ if (grub_lower_mem < GRUB_MEMORY_MACHINE_RESERVED_END)
+ grub_fatal ("too small memory");
+#endif
+
+/* FIXME: This prevents loader/i386/linux.c from using low memory. When our
+ heap implements support for requesting a chunk in low memory, this should
+ no longer be a problem. */
+#if 0
+ /* Add the lower memory into free memory. */
+ if (grub_lower_mem >= GRUB_MEMORY_MACHINE_RESERVED_END)
+ add_mem_region (GRUB_MEMORY_MACHINE_RESERVED_END,
+ grub_lower_mem - GRUB_MEMORY_MACHINE_RESERVED_END);
+#endif
+
+ auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t,
+ grub_memory_type_t);
+ int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size,
+ grub_memory_type_t type)
+ {
+ /* Avoid the lower memory. */
+ if (addr < 0x100000)
+ {
+ if (size <= 0x100000 - addr)
+ return 0;
+
+ size -= 0x100000 - addr;
+ addr = 0x100000;
+ }
+
+ /* Ignore >4GB. */
+ if (addr <= 0xFFFFFFFF && type == GRUB_MEMORY_AVAILABLE)
+ {
+ grub_size_t len;
+
+ len = (grub_size_t) ((addr + size > 0xFFFFFFFF)
+ ? 0xFFFFFFFF - addr
+ : size);
+ add_mem_region (addr, len);
+ }
+
+ return 0;
+ }
+
+ grub_machine_mmap_iterate (hook);
+
+ compact_mem_regions ();
+
+ for (i = 0; i < num_regions; i++)
+ grub_mm_init_region ((void *) mem_regions[i].addr, mem_regions[i].size);
+
+ grub_tsc_init ();
+}
+
+void
+grub_machine_set_prefix (void)
+{
+ /* Initialize the prefix. */
+ grub_env_set ("prefix", make_install_device ());
+}
+
+void
+grub_machine_fini (void)
+{
+ grub_console_fini ();
+ grub_stop_floppy ();
+}
+
+/* Return the end of the core image. */
+grub_addr_t
+grub_arch_modules_addr (void)
+{
+ return GRUB_MEMORY_MACHINE_DECOMPRESSION_ADDR
+ + (grub_kernel_image_size - GRUB_KERNEL_MACHINE_RAW_SIZE);
+}
diff --git a/grub-core/kern/i386/pc/lzma_decode.S b/grub-core/kern/i386/pc/lzma_decode.S
new file mode 100644
index 0000000..88c668d
--- /dev/null
+++ b/grub-core/kern/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/kern/i386/pc/mmap.c b/grub-core/kern/i386/pc/mmap.c
new file mode 100644
index 0000000..480ffa9
--- /dev/null
+++ b/grub-core/kern/i386/pc/mmap.c
@@ -0,0 +1,190 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2002,2003,2004,2005,2006,2007,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/>.
+ */
+
+#include <grub/machine/memory.h>
+#include <grub/machine/int.h>
+#include <grub/err.h>
+#include <grub/types.h>
+#include <grub/misc.h>
+
+struct grub_machine_mmap_entry
+{
+ grub_uint32_t size;
+ grub_uint64_t addr;
+ grub_uint64_t len;
+#define GRUB_MACHINE_MEMORY_AVAILABLE 1
+#define GRUB_MACHINE_MEMORY_RESERVED 2
+#define GRUB_MACHINE_MEMORY_ACPI 3
+#define GRUB_MACHINE_MEMORY_NVS 4
+#define GRUB_MACHINE_MEMORY_BADRAM 5
+ grub_uint32_t type;
+} __attribute__((packed));
+
+
+/*
+ *
+ * grub_get_conv_memsize(i) : return the conventional memory size in KB.
+ * BIOS call "INT 12H" to get conventional memory size
+ * The return value in AX.
+ */
+static inline grub_uint16_t
+grub_get_conv_memsize (void)
+{
+ struct grub_bios_int_registers regs;
+
+ regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
+ grub_bios_interrupt (0x12, &regs);
+ return regs.eax & 0xffff;
+}
+
+/*
+ * grub_get_ext_memsize() : return the extended memory size in KB.
+ * BIOS call "INT 15H, AH=88H" to get extended memory size
+ * The return value in AX.
+ *
+ */
+static inline grub_uint16_t
+grub_get_ext_memsize (void)
+{
+ struct grub_bios_int_registers regs;
+
+ regs.eax = 0x8800;
+ regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
+ grub_bios_interrupt (0x15, &regs);
+ return regs.eax & 0xffff;
+}
+
+/* Get a packed EISA memory map. Lower 16 bits are between 1MB and 16MB
+ in 1KB parts, and upper 16 bits are above 16MB in 64KB parts. If error, return zero.
+ BIOS call "INT 15H, AH=E801H" to get EISA memory map,
+ AX = memory between 1M and 16M in 1K parts.
+ BX = memory above 16M in 64K parts.
+*/
+
+static inline grub_uint32_t
+grub_get_eisa_mmap (void)
+{
+ struct grub_bios_int_registers regs;
+
+ regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
+ regs.eax = 0xe801;
+ grub_bios_interrupt (0x15, &regs);
+
+ if ((regs.eax & 0xff00) == 0x8600)
+ return 0;
+
+ return (regs.eax & 0xffff) | (regs.ebx << 16);
+}
+
+/*
+ *
+ * grub_get_mmap_entry(addr, cont) : address and old continuation value (zero to
+ * start), for the Query System Address Map BIOS call.
+ *
+ * Sets the first 4-byte int value of "addr" to the size returned by
+ * the call. If the call fails, sets it to zero.
+ *
+ * Returns: new (non-zero) continuation value, 0 if done.
+ */
+/* Get a memory map entry. Return next continuation value. Zero means
+ the end. */
+static grub_uint32_t
+grub_get_mmap_entry (struct grub_machine_mmap_entry *entry,
+ grub_uint32_t cont)
+{
+ struct grub_bios_int_registers regs;
+
+ regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
+
+ /* place address (+4) in ES:DI */
+ regs.es = ((grub_addr_t) &entry->addr) >> 4;
+ regs.edi = ((grub_addr_t) &entry->addr) & 0xf;
+
+ /* set continuation value */
+ regs.ebx = cont;
+
+ /* set default maximum buffer size */
+ regs.ecx = sizeof (*entry) - sizeof (entry->size);
+
+ /* set EDX to 'SMAP' */
+ regs.edx = 0x534d4150;
+
+ regs.eax = 0xe820;
+ grub_bios_interrupt (0x15, &regs);
+
+ /* write length of buffer (zero if error) into ADDR */
+ if ((regs.flags & GRUB_CPU_INT_FLAGS_CARRY) || regs.eax != 0x534d4150
+ || regs.ecx < 0x14 || regs.ecx > 0x400)
+ entry->size = 0;
+ else
+ entry->size = regs.ecx;
+
+ /* return the continuation value */
+ return regs.ebx;
+}
+
+grub_err_t
+grub_machine_mmap_iterate (grub_memory_hook_t hook)
+{
+ grub_uint32_t cont;
+ struct grub_machine_mmap_entry *entry
+ = (struct grub_machine_mmap_entry *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR;
+
+ grub_memset (entry, 0, sizeof (entry));
+
+ /* Check if grub_get_mmap_entry works. */
+ cont = grub_get_mmap_entry (entry, 0);
+
+ if (entry->size)
+ do
+ {
+ if (hook (entry->addr, entry->len,
+ /* GRUB mmaps have been defined to match with the E820 definition.
+ Therefore, we can just pass type through. */
+ ((entry->type <= GRUB_MACHINE_MEMORY_BADRAM) && (entry->type >= GRUB_MACHINE_MEMORY_AVAILABLE)) ? entry->type : GRUB_MEMORY_RESERVED))
+ break;
+
+ if (! cont)
+ break;
+
+ grub_memset (entry, 0, sizeof (entry));
+
+ cont = grub_get_mmap_entry (entry, cont);
+ }
+ while (entry->size);
+ else
+ {
+ grub_uint32_t eisa_mmap = grub_get_eisa_mmap ();
+
+ if (hook (0x0, ((grub_uint32_t) grub_get_conv_memsize ()) << 10,
+ GRUB_MEMORY_AVAILABLE))
+ return 0;
+
+ if (eisa_mmap)
+ {
+ if (hook (0x100000, (eisa_mmap & 0xFFFF) << 10,
+ GRUB_MEMORY_AVAILABLE) == 0)
+ hook (0x1000000, eisa_mmap & ~0xFFFF, GRUB_MEMORY_AVAILABLE);
+ }
+ else
+ hook (0x100000, ((grub_uint32_t) grub_get_ext_memsize ()) << 10,
+ GRUB_MEMORY_AVAILABLE);
+ }
+
+ return 0;
+}
diff --git a/grub-core/kern/i386/pc/startup.S b/grub-core/kern/i386/pc/startup.S
new file mode 100644
index 0000000..e78a0aa
--- /dev/null
+++ b/grub-core/kern/i386/pc/startup.S
@@ -0,0 +1,1011 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 1999,2000,2001,2002,2003,2005,2006,2007,2008,2009 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+/*
+ * Note: These functions defined in this file may be called from C.
+ * Be careful of that you must not modify some registers. Quote
+ * from gcc-2.95.2/gcc/config/i386/i386.h:
+
+ 1 for registers not available across function calls.
+ These must include the FIXED_REGISTERS and also any
+ registers that can be used without being saved.
+ The latter must include the registers where values are returned
+ and the register where structure-value addresses are passed.
+ Aside from that, you can include as many other registers as you like.
+
+ ax,dx,cx,bx,si,di,bp,sp,st,st1,st2,st3,st4,st5,st6,st7,arg
+{ 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }
+ */
+
+/*
+ * Note: GRUB is compiled with the options -mrtd and -mregparm=3.
+ * So the first three arguments are passed in %eax, %edx, and %ecx,
+ * respectively, and if a function has a fixed number of arguments
+ * and the number is greater than three, the function must return
+ * with "ret $N" where N is ((the number of arguments) - 3) * 4.
+ */
+
+#include <config.h>
+#include <grub/symbol.h>
+#include <grub/boot.h>
+#include <grub/machine/boot.h>
+#include <grub/machine/memory.h>
+#include <grub/machine/console.h>
+#include <grub/cpu/linux.h>
+#include <grub/machine/kernel.h>
+#include <grub/term.h>
+#include <multiboot.h>
+#include <multiboot2.h>
+
+#define ABS(x) ((x) - LOCAL (base) + GRUB_BOOT_MACHINE_KERNEL_ADDR + 0x200)
+
+ .file "startup.S"
+
+ .text
+
+ /* Tell GAS to generate 16-bit instructions so that this code works
+ in real mode. */
+ .code16
+
+ .globl start, _start
+start:
+_start:
+LOCAL (base):
+ /*
+ * Guarantee that "main" is loaded at 0x0:0x8200.
+ */
+#ifdef __APPLE__
+ ljmp $0, $(ABS(LOCAL (codestart)) - 0x10000)
+#else
+ ljmp $0, $ABS(LOCAL (codestart))
+#endif
+ /*
+ * Compatibility version number
+ *
+ * These MUST be at byte offset 6 and 7 of the executable
+ * DO NOT MOVE !!!
+ */
+ . = _start + 0x6
+ .byte GRUB_BOOT_VERSION_MAJOR, GRUB_BOOT_VERSION_MINOR
+
+ /*
+ * This is a special data area 8 bytes from the beginning.
+ */
+
+ . = _start + 0x8
+
+VARIABLE(grub_total_module_size)
+ .long 0
+VARIABLE(grub_kernel_image_size)
+ .long 0
+VARIABLE(grub_compressed_size)
+ .long 0
+VARIABLE(grub_install_dos_part)
+ .long 0xFFFFFFFF
+VARIABLE(grub_install_bsd_part)
+ .long 0xFFFFFFFF
+reed_solomon_redundancy:
+ .long 0
+
+#ifdef APPLE_CC
+bss_start:
+ .long 0
+bss_end:
+ .long 0
+#endif
+/*
+ * This is the area for all of the special variables.
+ */
+
+VARIABLE(grub_boot_drive)
+ .byte 0
+
+/* the real mode code continues... */
+LOCAL (codestart):
+ cli /* we're not safe here! */
+
+ /* set up %ds, %ss, and %es */
+ xorw %ax, %ax
+ movw %ax, %ds
+ movw %ax, %ss
+ movw %ax, %es
+
+ /* set up the real mode/BIOS stack */
+ movl $GRUB_MEMORY_MACHINE_REAL_STACK, %ebp
+ movl %ebp, %esp
+
+ sti /* we're safe again */
+
+ /* save the boot drive */
+ ADDR32 movb %dl, EXT_C(grub_boot_drive)
+
+ /* reset disk system (%ah = 0) */
+ int $0x13
+
+ /* transition to protected mode */
+ DATA32 call real_to_prot
+
+ /* The ".code32" directive takes GAS out of 16-bit mode. */
+ .code32
+
+ incl %eax
+ call grub_gate_a20
+
+ movl EXT_C(grub_compressed_size), %edx
+ addl $(GRUB_KERNEL_MACHINE_RAW_SIZE - GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_PART), %edx
+ movl reed_solomon_redundancy, %ecx
+ leal _start + GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_PART, %eax
+ call EXT_C (grub_reed_solomon_recover)
+ jmp post_reed_solomon
+
+#include <rs_decoder.S>
+
+ .text
+
+ . = _start + GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_PART
+/*
+ * Support for booting GRUB from a Multiboot boot loader (e.g. GRUB itself).
+ * This uses the a.out kludge to load raw binary to the area starting at 1MB,
+ * and relocates itself after loaded.
+ */
+ .p2align 2 /* force 4-byte alignment */
+multiboot_header:
+ /* magic */
+ .long 0x1BADB002
+ /* flags */
+ .long (1 << 16)
+ /* checksum */
+ .long -0x1BADB002 - (1 << 16)
+ /* header addr */
+ .long multiboot_header - _start + 0x100000 + 0x200
+ /* load addr */
+ .long 0x100000
+ /* load end addr */
+ .long 0
+ /* bss end addr */
+ .long 0
+ /* entry addr */
+ .long multiboot_entry - _start + 0x100000 + 0x200
+
+multiboot_entry:
+ .code32
+ /* obtain the boot device */
+ movl 12(%ebx), %edx
+
+ movl $GRUB_MEMORY_MACHINE_PROT_STACK, %ebp
+ movl %ebp, %esp
+
+ /* relocate the code */
+ movl $(GRUB_KERNEL_MACHINE_RAW_SIZE + 0x200), %ecx
+ addl EXT_C(grub_compressed_size) - _start + 0x100000 + 0x200, %ecx
+ movl $0x100000, %esi
+ movl $GRUB_BOOT_MACHINE_KERNEL_ADDR, %edi
+ cld
+ rep
+ movsb
+ /* jump to the real address */
+ movl $multiboot_trampoline, %eax
+ jmp *%eax
+
+multiboot_trampoline:
+ /* fill the boot information */
+ movl %edx, %eax
+ shrl $8, %eax
+ xorl %ebx, %ebx
+ cmpb $0xFF, %ah
+ je 1f
+ movb %ah, %bl
+ movl %ebx, EXT_C(grub_install_dos_part)
+1:
+ cmpb $0xFF, %al
+ je 2f
+ movb %al, %bl
+ movl %ebx, EXT_C(grub_install_bsd_part)
+2:
+ shrl $24, %edx
+ movb $0xFF, %dh
+ /* enter the usual booting */
+ call prot_to_real
+ jmp LOCAL (codestart)
+
+post_reed_solomon:
+
+#ifdef ENABLE_LZMA
+ movl $GRUB_MEMORY_MACHINE_DECOMPRESSION_ADDR, %edi
+ movl $(_start + GRUB_KERNEL_MACHINE_RAW_SIZE), %esi
+ pushl %edi
+ pushl %esi
+ movl EXT_C(grub_kernel_image_size), %ecx
+ addl EXT_C(grub_total_module_size), %ecx
+ subl $GRUB_KERNEL_MACHINE_RAW_SIZE, %ecx
+ pushl %ecx
+ leal (%edi, %ecx), %ebx
+ call _LzmaDecodeA
+ /* _LzmaDecodeA clears DF, so no need to run cld */
+ popl %ecx
+ popl %edi
+ popl %esi
+#endif
+
+ /* copy back the decompressed part (except the modules) */
+ subl EXT_C(grub_total_module_size), %ecx
+ rep
+ movsb
+
+#if 0
+ /* copy modules before cleaning out the bss */
+ movl EXT_C(grub_total_module_size), %ecx
+ movl EXT_C(grub_kernel_image_size), %esi
+ addl %ecx, %esi
+ addl $_start, %esi
+ decl %esi
+ movl $END_SYMBOL, %edi
+ addl %ecx, %edi
+ decl %edi
+ std
+ rep
+ movsb
+#endif
+
+#ifdef APPLE_CC
+ /* clean out the bss */
+ bss_start_abs = ABS (bss_start)
+ bss_end_abs = ABS (bss_end)
+
+ movl bss_start_abs, %edi
+
+ /* compute the bss length */
+ movl bss_end_abs, %ecx
+ subl %edi, %ecx
+#else
+ /* clean out the bss */
+ movl $BSS_START_SYMBOL, %edi
+
+ /* compute the bss length */
+ movl $END_SYMBOL, %ecx
+ subl %edi, %ecx
+#endif
+
+ /* clean out */
+ xorl %eax, %eax
+ cld
+ rep
+ stosb
+
+ /*
+ * Call the start of main body of C code.
+ */
+ call EXT_C(grub_main)
+
+#include "../realmode.S"
+
+/*
+ * grub_gate_a20(int on)
+ *
+ * Gate address-line 20 for high memory.
+ *
+ * This routine is probably overconservative in what it does, but so what?
+ *
+ * It also eats any keystrokes in the keyboard buffer. :-(
+ */
+
+grub_gate_a20:
+ movl %eax, %edx
+
+gate_a20_test_current_state:
+ /* first of all, test if already in a good state */
+ call gate_a20_check_state
+ cmpb %al, %dl
+ jnz gate_a20_try_bios
+ ret
+
+gate_a20_try_bios:
+ /* second, try a BIOS call */
+ pushl %ebp
+ call prot_to_real
+
+ .code16
+ movw $0x2400, %ax
+ testb %dl, %dl
+ jz 1f
+ incw %ax
+1: int $0x15
+
+ DATA32 call real_to_prot
+ .code32
+
+ popl %ebp
+ call gate_a20_check_state
+ cmpb %al, %dl
+ jnz gate_a20_try_system_control_port_a
+ ret
+
+gate_a20_try_system_control_port_a:
+ /*
+ * In macbook, the keyboard test would hang the machine, so we move
+ * this forward.
+ */
+ /* fourth, try the system control port A */
+ inb $0x92
+ andb $(~0x03), %al
+ testb %dl, %dl
+ jz 6f
+ orb $0x02, %al
+6: outb $0x92
+
+ /* When turning off Gate A20, do not check the state strictly,
+ because a failure is not fatal usually, and Gate A20 is always
+ on some modern machines. */
+ testb %dl, %dl
+ jz 7f
+ call gate_a20_check_state
+ cmpb %al, %dl
+ jnz gate_a20_try_keyboard_controller
+7: ret
+
+gate_a20_flush_keyboard_buffer:
+ inb $0x64
+ andb $0x02, %al
+ jnz gate_a20_flush_keyboard_buffer
+2:
+ inb $0x64
+ andb $0x01, %al
+ jz 3f
+ inb $0x60
+ jmp 2b
+3:
+ ret
+
+gate_a20_try_keyboard_controller:
+ /* third, try the keyboard controller */
+ call gate_a20_flush_keyboard_buffer
+
+ movb $0xd1, %al
+ outb $0x64
+4:
+ inb $0x64
+ andb $0x02, %al
+ jnz 4b
+
+ movb $0xdd, %al
+ testb %dl, %dl
+ jz 5f
+ orb $0x02, %al
+5: outb $0x60
+ call gate_a20_flush_keyboard_buffer
+
+ /* output a dummy command (USB keyboard hack) */
+ movb $0xff, %al
+ outb $0x64
+ call gate_a20_flush_keyboard_buffer
+
+ call gate_a20_check_state
+ cmpb %al, %dl
+ /* everything failed, so restart from the beginning */
+ jnz gate_a20_try_bios
+ ret
+
+gate_a20_check_state:
+ /* iterate the checking for a while */
+ movl $100, %ecx
+1:
+ call 3f
+ cmpb %al, %dl
+ jz 2f
+ loop 1b
+2:
+ ret
+3:
+ pushl %ebx
+ pushl %ecx
+ xorl %eax, %eax
+ /* compare the byte at 0x8000 with that at 0x108000 */
+ movl $GRUB_BOOT_MACHINE_KERNEL_ADDR, %ebx
+ pushl %ebx
+ /* save the original byte in CL */
+ movb (%ebx), %cl
+ /* store the value at 0x108000 in AL */
+ addl $0x100000, %ebx
+ movb (%ebx), %al
+ /* try to set one less value at 0x8000 */
+ popl %ebx
+ movb %al, %ch
+ decb %ch
+ movb %ch, (%ebx)
+ /* serialize */
+ outb %al, $0x80
+ outb %al, $0x80
+ /* obtain the value at 0x108000 in CH */
+ pushl %ebx
+ addl $0x100000, %ebx
+ movb (%ebx), %ch
+ /* this result is 1 if A20 is on or 0 if it is off */
+ subb %ch, %al
+ xorb $1, %al
+ /* restore the original */
+ popl %ebx
+ movb %cl, (%ebx)
+ popl %ecx
+ popl %ebx
+ ret
+
+#ifdef ENABLE_LZMA
+#include "lzma_decode.S"
+#endif
+
+/*
+ * The code beyond this point is compressed. Assert that the uncompressed
+ * code fits GRUB_KERNEL_MACHINE_RAW_SIZE.
+ */
+ . = _start + GRUB_KERNEL_MACHINE_RAW_SIZE
+
+ . = _start + GRUB_KERNEL_MACHINE_PREFIX
+VARIABLE(grub_prefix)
+ /* to be filled by grub-mkimage */
+
+ /*
+ * Leave some breathing room for the prefix.
+ */
+ . = _start + GRUB_KERNEL_MACHINE_PREFIX_END
+
+
+
+/*
+ * grub_exit()
+ *
+ * Exit the system.
+ */
+FUNCTION(grub_exit)
+ call prot_to_real
+ .code16
+ /* Tell the BIOS a boot failure. If this does not work, reboot. */
+ int $0x18
+ jmp cold_reboot
+ .code32
+
+/*
+ * void grub_chainloader_real_boot (int drive, void *part_addr)
+ *
+ * This starts another boot loader.
+ */
+
+FUNCTION(grub_chainloader_real_boot)
+ pushl %edx
+ pushl %eax
+
+ /* Turn off Gate A20 */
+ xorl %eax, %eax
+ call grub_gate_a20
+
+ /* set up to pass boot drive */
+ popl %edx
+
+ /* ESI must point to a partition table entry */
+ popl %esi
+
+ call prot_to_real
+ .code16
+ ljmp $0, $GRUB_MEMORY_MACHINE_BOOT_LOADER_ADDR
+ .code32
+
+/*
+ * void grub_console_putchar (int c)
+ *
+ * Put the character C on the console. Because GRUB wants to write a
+ * character with an attribute, this implementation is a bit tricky.
+ * If C is a control character (CR, LF, BEL, BS), use INT 10, AH = 0Eh
+ * (TELETYPE OUTPUT). Otherwise, save the original position, put a space,
+ * save the current position, restore the original position, write the
+ * character and the attribute, and restore the current position.
+ *
+ * The reason why this is so complicated is that there is no easy way to
+ * get the height of the screen, and the TELETYPE OUTPUT BIOS call doesn't
+ * support setting a background attribute.
+ */
+FUNCTION(grub_console_putchar)
+ /* Retrieve the base character. */
+ movl 0(%edx), %edx
+ pusha
+ movb EXT_C(grub_console_cur_color), %bl
+
+ call prot_to_real
+ .code16
+ movb %dl, %al
+ xorb %bh, %bh
+
+ /* use teletype output if control character */
+ cmpb $0x7, %al
+ je 1f
+ cmpb $0x8, %al
+ je 1f
+ cmpb $0xa, %al
+ je 1f
+ cmpb $0xd, %al
+ je 1f
+
+ /* save the character and the attribute on the stack */
+ pushw %ax
+ pushw %bx
+
+ /* get the current position */
+ movb $0x3, %ah
+ int $0x10
+
+ /* check the column with the width */
+ cmpb $79, %dl
+ jl 2f
+
+ /* print CR and LF, if next write will exceed the width */
+ movw $0x0e0d, %ax
+ int $0x10
+ movb $0x0a, %al
+ int $0x10
+
+ /* get the current position */
+ movb $0x3, %ah
+ int $0x10
+
+2:
+ /* restore the character and the attribute */
+ popw %bx
+ popw %ax
+
+ /* write the character with the attribute */
+ movb $0x9, %ah
+ movw $1, %cx
+ int $0x10
+
+ /* move the cursor forward */
+ incb %dl
+ movb $0x2, %ah
+ int $0x10
+
+ jmp 3f
+
+1: movw $1, %bx
+ movb $0xe, %ah
+ int $0x10
+
+3: DATA32 call real_to_prot
+ .code32
+
+ popa
+ ret
+
+
+LOCAL(bypass_table):
+ .word 0x011b, 0x0f00 | '\t', 0x0e00 | '\b', 0x1c00 | '\r'
+ .word 0x1c00 | '\n'
+LOCAL(bypass_table_end):
+
+/*
+ * int grub_console_getkey (void)
+ * if there is a character pending, return it; otherwise return -1
+ * BIOS call "INT 16H Function 01H" to check whether a character is pending
+ * Call with %ah = 0x1
+ * Return:
+ * If key waiting to be input:
+ * %ah = keyboard scan code
+ * %al = ASCII character
+ * Zero flag = clear
+ * else
+ * Zero flag = set
+ * BIOS call "INT 16H Function 00H" to read character from keyboard
+ * Call with %ah = 0x0
+ * Return: %ah = keyboard scan code
+ * %al = ASCII character
+ */
+
+FUNCTION(grub_console_getkey)
+ pushl %ebp
+ pushl %edi
+
+ call prot_to_real
+ .code16
+
+ /*
+ * Due to a bug in apple's bootcamp implementation, INT 16/AH = 0 would
+ * cause the machine to hang at the second keystroke. However, we can
+ * work around this problem by ensuring the presence of keystroke with
+ * INT 16/AH = 1 before calling INT 16/AH = 0.
+ */
+
+ movb $1, %ah
+ int $0x16
+ jz notpending
+
+ movb $0, %ah
+ int $0x16
+
+ xorl %edx, %edx
+ movw %ax, %dx /* real_to_prot uses %eax */
+
+ DATA32 call real_to_prot
+ .code32
+
+ movl $0xff, %eax
+ testl %eax, %edx
+ jz 1f
+
+ andl %edx, %eax
+ cmpl $0x20, %eax
+ jae 2f
+ movl %edx, %eax
+ leal LOCAL(bypass_table), %edi
+ movl $((LOCAL(bypass_table_end) - LOCAL(bypass_table)) >> 1), %ecx
+ repne scasw
+ jz 3f
+
+ andl $0xff, %eax
+ addl $(('a' - 1) | GRUB_TERM_CTRL), %eax
+ jmp 2f
+3:
+ andl $0xff, %eax
+ jmp 2f
+
+1: movl %edx, %eax
+ shrl $8, %eax
+ orl $GRUB_TERM_EXTENDED, %eax
+2:
+ popl %edi
+ popl %ebp
+ ret
+
+notpending:
+ .code16
+ DATA32 call real_to_prot
+ .code32
+#if GRUB_TERM_NO_KEY != 0
+#error Fix this asm code
+#endif
+ jmp 2b
+
+
+/*
+ * grub_uint16_t grub_console_getxy (void)
+ * BIOS call "INT 10H Function 03h" to get cursor position
+ * Call with %ah = 0x03
+ * %bh = page
+ * Returns %ch = starting scan line
+ * %cl = ending scan line
+ * %dh = row (0 is top)
+ * %dl = column (0 is left)
+ */
+
+
+FUNCTION(grub_console_getxy)
+ pushl %ebp
+ pushl %ebx /* save EBX */
+
+ call prot_to_real
+ .code16
+
+ xorb %bh, %bh /* set page to 0 */
+ movb $0x3, %ah
+ int $0x10 /* get cursor position */
+
+ DATA32 call real_to_prot
+ .code32
+
+ movb %dl, %ah
+ movb %dh, %al
+
+ popl %ebx
+ popl %ebp
+ ret
+
+
+/*
+ * void grub_console_gotoxy(grub_uint8_t x, grub_uint8_t y)
+ * BIOS call "INT 10H Function 02h" to set cursor position
+ * Call with %ah = 0x02
+ * %bh = page
+ * %dh = row (0 is top)
+ * %dl = column (0 is left)
+ */
+
+
+FUNCTION(grub_console_gotoxy)
+ pushl %ebp
+ pushl %ebx /* save EBX */
+
+ movb %cl, %dh /* %dh = y */
+ /* %dl = x */
+
+ call prot_to_real
+ .code16
+
+ xorb %bh, %bh /* set page to 0 */
+ movb $0x2, %ah
+ int $0x10 /* set cursor position */
+
+ DATA32 call real_to_prot
+ .code32
+
+ popl %ebx
+ popl %ebp
+ ret
+
+
+/*
+ * void grub_console_cls (void)
+ * BIOS call "INT 10H Function 09h" to write character and attribute
+ * Call with %ah = 0x09
+ * %al = (character)
+ * %bh = (page number)
+ * %bl = (attribute)
+ * %cx = (number of times)
+ */
+
+FUNCTION(grub_console_cls)
+ pushl %ebp
+ pushl %ebx /* save EBX */
+
+ call prot_to_real
+ .code16
+
+ /* move the cursor to the beginning */
+ movb $0x02, %ah
+ xorb %bh, %bh
+ xorw %dx, %dx
+ int $0x10
+
+ /* write spaces to the entire screen */
+ movw $0x0920, %ax
+ movw $0x07, %bx
+ movw $(80 * 25), %cx
+ int $0x10
+
+ /* move back the cursor */
+ movb $0x02, %ah
+ int $0x10
+
+ DATA32 call real_to_prot
+ .code32
+
+ popl %ebx
+ popl %ebp
+ ret
+
+
+/*
+ * void grub_console_setcursor (int on)
+ * BIOS call "INT 10H Function 01h" to set cursor type
+ * Call with %ah = 0x01
+ * %ch = cursor starting scanline
+ * %cl = cursor ending scanline
+ */
+
+console_cursor_state:
+ .byte 1
+console_cursor_shape:
+ .word 0
+
+FUNCTION(grub_console_setcursor)
+ pushl %ebp
+ pushl %ebx
+
+ /* push ON */
+ pushl %edx
+
+ /* check if the standard cursor shape has already been saved */
+ movw console_cursor_shape, %ax
+ testw %ax, %ax
+ jne 1f
+
+ call prot_to_real
+ .code16
+
+ movb $0x03, %ah
+ xorb %bh, %bh
+ int $0x10
+
+ DATA32 call real_to_prot
+ .code32
+
+ cmp %cl, %ch
+ jb 3f
+ movw $0x0d0e, %cx
+3:
+ movw %cx, console_cursor_shape
+1:
+ /* set %cx to the designated cursor shape */
+ movw $0x2000, %cx
+ popl %eax
+ testl %eax, %eax
+ jz 2f
+ movw console_cursor_shape, %cx
+2:
+ call prot_to_real
+ .code16
+
+ movb $0x1, %ah
+ int $0x10
+
+ DATA32 call real_to_prot
+ .code32
+
+ popl %ebx
+ popl %ebp
+ ret
+
+/*
+ * grub_get_rtc()
+ * return the real time in ticks, of which there are about
+ * 18-20 per second
+ */
+FUNCTION(grub_get_rtc)
+ pushl %ebp
+
+ call prot_to_real /* enter real mode */
+ .code16
+
+ /* %ax is already zero */
+ int $0x1a
+
+ DATA32 call real_to_prot
+ .code32
+
+ movl %ecx, %eax
+ shll $16, %eax
+ movw %dx, %ax
+
+ popl %ebp
+ ret
+
+/*
+ * int grub_pxe_call (int func, void* data, grub_uint32_t pxe_rm_entry);
+ */
+FUNCTION(grub_pxe_call)
+ pushl %ebp
+ movl %esp, %ebp
+ pushl %esi
+ pushl %edi
+ pushl %ebx
+
+ movl %ecx, %ebx
+ movl %eax, %ecx
+ movl %edx, %eax
+ andl $0xF, %eax
+ shrl $4, %edx
+ shll $16, %edx
+ addl %eax, %edx
+
+ call prot_to_real
+ .code16
+
+ pushl %ebx
+ pushl %edx
+ pushw %cx
+ movw %sp, %bx
+ lcall *%ss:6(%bx)
+ cld
+ addw $10, %sp
+ movw %ax, %cx
+
+ DATA32 call real_to_prot
+ .code32
+
+ movzwl %cx, %eax
+
+ popl %ebx
+ popl %edi
+ popl %esi
+ popl %ebp
+ ret
+
+FUNCTION(grub_bios_interrupt)
+ pushl %ebp
+ pushl %ecx
+ pushl %eax
+ pushl %ebx
+ pushl %esi
+ pushl %edi
+ pushl %edx
+
+ movb %al, intno
+ movl (%edx), %eax
+ movl %eax, LOCAL(bios_register_eax)
+ movw 4(%edx), %ax
+ movw %ax, LOCAL(bios_register_es)
+ movw 6(%edx), %ax
+ movw %ax, LOCAL(bios_register_ds)
+ movw 8(%edx), %ax
+ movw %ax, LOCAL(bios_register_flags)
+
+ movl 12(%edx), %ebx
+ movl 16(%edx), %ecx
+ movl 20(%edx), %edi
+ movl 24(%edx), %esi
+ movl 28(%edx), %edx
+
+ call prot_to_real
+ .code16
+
+ mov %ds, %ax
+ push %ax
+
+ /* movw imm16, %ax*/
+ .byte 0xb8
+LOCAL(bios_register_es):
+ .short 0
+ movw %ax, %es
+ /* movw imm16, %ax*/
+ .byte 0xb8
+LOCAL(bios_register_ds):
+ .short 0
+ movw %ax, %ds
+
+ /* movw imm16, %ax*/
+ .byte 0xb8
+LOCAL(bios_register_flags):
+ .short 0
+ push %ax
+ popf
+
+ /* movl imm32, %eax*/
+ .byte 0x66, 0xb8
+LOCAL(bios_register_eax):
+ .long 0
+
+ /* int imm8. */
+ .byte 0xcd
+intno:
+ .byte 0
+
+ movl %eax, %cs:LOCAL(bios_register_eax)
+ movw %ds, %ax
+ movw %ax, %cs:LOCAL(bios_register_ds)
+ pop %ax
+ mov %ax, %ds
+ pushf
+ pop %ax
+ movw %ax, LOCAL(bios_register_flags)
+ mov %es, %ax
+ movw %ax, LOCAL(bios_register_es)
+
+ DATA32 call real_to_prot
+ .code32
+
+ popl %eax
+
+ movl %ebx, 12(%eax)
+ movl %ecx, 16(%eax)
+ movl %edi, 20(%eax)
+ movl %esi, 24(%eax)
+ movl %edx, 28(%eax)
+
+ movl %eax, %edx
+
+ movl LOCAL(bios_register_eax), %eax
+ movl %eax, (%edx)
+ movw LOCAL(bios_register_es), %ax
+ movw %ax, 4(%edx)
+ movw LOCAL(bios_register_ds), %ax
+ movw %ax, 6(%edx)
+ movw LOCAL(bios_register_flags), %ax
+ movw %ax, 8(%edx)
+
+ popl %edi
+ popl %esi
+ popl %ebx
+ popl %eax
+ popl %ecx
+ popl %ebp
+ ret