summaryrefslogtreecommitdiffstats
path: root/grub-core/lib/i386
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 16:29:51 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 16:29:51 +0000
commit6e7a315eb67cb6c113cf37e1d66c4f11a51a2b3e (patch)
tree32451fa3cdd9321fb2591fada9891b2cb70a9cd1 /grub-core/lib/i386
parentInitial commit. (diff)
downloadgrub2-upstream/2.06.tar.xz
grub2-upstream/2.06.zip
Adding upstream version 2.06.upstream/2.06upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--grub-core/lib/i386/backtrace.c66
-rw-r--r--grub-core/lib/i386/halt.c82
-rw-r--r--grub-core/lib/i386/pc/biosnum.c47
-rw-r--r--grub-core/lib/i386/pc/vesa_modes_table.c127
-rw-r--r--grub-core/lib/i386/random.c103
-rw-r--r--grub-core/lib/i386/reboot.c64
-rw-r--r--grub-core/lib/i386/reboot_trampoline.S34
-rw-r--r--grub-core/lib/i386/relocator.c210
-rw-r--r--grub-core/lib/i386/relocator16.S341
-rw-r--r--grub-core/lib/i386/relocator32.S134
-rw-r--r--grub-core/lib/i386/relocator64.S210
-rw-r--r--grub-core/lib/i386/relocator_asm.S80
-rw-r--r--grub-core/lib/i386/relocator_common.S111
-rw-r--r--grub-core/lib/i386/relocator_common_c.c109
-rw-r--r--grub-core/lib/i386/setjmp.S59
-rw-r--r--grub-core/lib/i386/xen/relocator.S165
16 files changed, 1942 insertions, 0 deletions
diff --git a/grub-core/lib/i386/backtrace.c b/grub-core/lib/i386/backtrace.c
new file mode 100644
index 0000000..c3e03c7
--- /dev/null
+++ b/grub-core/lib/i386/backtrace.c
@@ -0,0 +1,66 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 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/misc.h>
+#include <grub/command.h>
+#include <grub/err.h>
+#include <grub/dl.h>
+#include <grub/mm.h>
+#include <grub/term.h>
+#include <grub/backtrace.h>
+
+#define MAX_STACK_FRAME 102400
+
+void
+grub_backtrace_pointer (void *ebp)
+{
+ void *ptr, *nptr;
+ unsigned i;
+
+ ptr = ebp;
+ while (1)
+ {
+ grub_printf ("%p: ", ptr);
+ grub_backtrace_print_address (((void **) ptr)[1]);
+ grub_printf (" (");
+ for (i = 0; i < 2; i++)
+ grub_printf ("%p,", ((void **)ptr) [i + 2]);
+ grub_printf ("%p)\n", ((void **)ptr) [i + 2]);
+ nptr = *(void **)ptr;
+ if (nptr < ptr || (void **) nptr - (void **) ptr > MAX_STACK_FRAME
+ || nptr == ptr)
+ {
+ grub_printf ("Invalid stack frame at %p (%p)\n", ptr, nptr);
+ break;
+ }
+ ptr = nptr;
+ }
+}
+
+void
+grub_backtrace (void)
+{
+#ifdef __x86_64__
+ asm volatile ("movq %%rbp, %%rdi\n"
+ "callq *%%rax": :"a"(grub_backtrace_pointer));
+#else
+ asm volatile ("movl %%ebp, %%eax\n"
+ "calll *%%ecx": :"c"(grub_backtrace_pointer));
+#endif
+}
+
diff --git a/grub-core/lib/i386/halt.c b/grub-core/lib/i386/halt.c
new file mode 100644
index 0000000..2364fe4
--- /dev/null
+++ b/grub-core/lib/i386/halt.c
@@ -0,0 +1,82 @@
+/*
+ * 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/>.
+ */
+
+#include <grub/cpu/io.h>
+#include <grub/misc.h>
+#include <grub/acpi.h>
+#include <grub/i18n.h>
+#include <grub/pci.h>
+#include <grub/mm.h>
+
+const char bochs_shutdown[] = "Shutdown";
+
+/*
+ * This call is special... it never returns... in fact it should simply
+ * hang at this point!
+ */
+static inline void __attribute__ ((noreturn))
+stop (void)
+{
+ asm volatile ("cli");
+ while (1)
+ {
+ asm volatile ("hlt");
+ }
+}
+
+static int
+grub_shutdown_pci_iter (grub_pci_device_t dev, grub_pci_id_t pciid,
+ void *data __attribute__ ((unused)))
+{
+ /* QEMU. */
+ if (pciid == 0x71138086)
+ {
+ grub_pci_address_t addr;
+ addr = grub_pci_make_address (dev, 0x40);
+ grub_pci_write (addr, 0x7001);
+ addr = grub_pci_make_address (dev, 0x80);
+ grub_pci_write (addr, grub_pci_read (addr) | 1);
+ grub_outw (0x2000, 0x7004);
+ }
+ return 0;
+}
+
+void
+grub_halt (void)
+{
+ unsigned int i;
+
+#if defined (GRUB_MACHINE_COREBOOT) || defined (GRUB_MACHINE_MULTIBOOT)
+ grub_acpi_halt ();
+#endif
+
+ /* Disable interrupts. */
+ asm volatile ("cli");
+
+ /* Bochs, QEMU, etc. Removed in newer QEMU releases. */
+ for (i = 0; i < sizeof (bochs_shutdown) - 1; i++)
+ grub_outb (bochs_shutdown[i], 0x8900);
+
+ grub_pci_iterate (grub_shutdown_pci_iter, NULL);
+
+ grub_puts_ (N_("GRUB doesn't know how to halt this machine yet!"));
+
+ /* In order to return we'd have to check what the previous status of IF
+ flag was. But user most likely doesn't want to return anyway ... */
+ stop ();
+}
diff --git a/grub-core/lib/i386/pc/biosnum.c b/grub-core/lib/i386/pc/biosnum.c
new file mode 100644
index 0000000..0f0e743
--- /dev/null
+++ b/grub-core/lib/i386/pc/biosnum.c
@@ -0,0 +1,47 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 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/env.h>
+#include <grub/misc.h>
+#include <grub/disk.h>
+#include <grub/machine/biosnum.h>
+
+static int
+grub_get_root_biosnumber_default (void)
+{
+ const char *biosnum;
+ int ret = -1;
+ grub_device_t dev;
+
+ biosnum = grub_env_get ("biosnum");
+
+ if (biosnum)
+ return grub_strtoul (biosnum, 0, 0);
+
+ dev = grub_device_open (0);
+ if (dev && dev->disk && dev->disk->dev
+ && dev->disk->dev->id == GRUB_DISK_DEVICE_BIOSDISK_ID)
+ ret = (int) dev->disk->id;
+
+ if (dev)
+ grub_device_close (dev);
+
+ return ret;
+}
+
+int (*grub_get_root_biosnumber) (void) = grub_get_root_biosnumber_default;
diff --git a/grub-core/lib/i386/pc/vesa_modes_table.c b/grub-core/lib/i386/pc/vesa_modes_table.c
new file mode 100644
index 0000000..6dc4b7d
--- /dev/null
+++ b/grub-core/lib/i386/pc/vesa_modes_table.c
@@ -0,0 +1,127 @@
+
+#include <grub/i386/pc/vesa_modes_table.h>
+
+/* This is the reverse of the table in [linux]/Documentation/fb/vesafb.txt
+ plus a few more modes based on the table in
+ http://en.wikipedia.org/wiki/VESA_BIOS_Extensions */
+struct grub_vesa_mode_table_entry
+grub_vesa_mode_table[GRUB_VESA_MODE_TABLE_END
+ - GRUB_VESA_MODE_TABLE_START + 1] =
+ {
+ { 640, 400, 8 }, /* 0x300 */
+ { 640, 480, 8 }, /* 0x301 */
+ { 800, 600, 4 }, /* 0x302 */
+ { 800, 600, 8 }, /* 0x303 */
+ { 1024, 768, 4 }, /* 0x304 */
+ { 1024, 768, 8 }, /* 0x305 */
+ { 1280, 1024, 4 }, /* 0x306 */
+ { 1280, 1024, 8 }, /* 0x307 */
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 320, 200, 15 }, /* 0x30d */
+ { 320, 200, 16 }, /* 0x30e */
+ { 320, 200, 24 }, /* 0x30f */
+ { 640, 480, 15 }, /* 0x310 */
+ { 640, 480, 16 }, /* 0x311 */
+ { 640, 480, 24 }, /* 0x312 */
+ { 800, 600, 15 }, /* 0x313 */
+ { 800, 600, 16 }, /* 0x314 */
+ { 800, 600, 24 }, /* 0x315 */
+ { 1024, 768, 15 }, /* 0x316 */
+ { 1024, 768, 16 }, /* 0x317 */
+ { 1024, 768, 24 }, /* 0x318 */
+ { 1280, 1024, 15 }, /* 0x319 */
+ { 1280, 1024, 16 }, /* 0x31a */
+ { 1280, 1024, 24 }, /* 0x31b */
+ { 1600, 1200, 8 }, /* 0x31c */
+ { 1600, 1200, 15 }, /* 0x31d */
+ { 1600, 1200, 16 }, /* 0x31e */
+ { 1600, 1200, 24 }, /* 0x31f */
+ { 0, 0, 0 },
+ { 640, 400, 15 }, /* 0x321 */
+ { 640, 400, 16 }, /* 0x322 */
+ { 640, 400, 24 }, /* 0x323 */
+ { 640, 400, 32 }, /* 0x324 */
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 640, 480, 32 }, /* 0x329 */
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 896, 672, 8 }, /* 0x32f */
+ { 896, 672, 15 }, /* 0x330 */
+ { 896, 672, 16 }, /* 0x331 */
+ { 896, 672, 24 }, /* 0x332 */
+ { 896, 672, 32 }, /* 0x333 */
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 1600, 1200, 32 }, /* 0x342 */
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 1440, 900, 8 }, /* 0x360 */
+ { 1440, 900, 15 }, /* 0x361 */
+ { 1440, 900, 16 }, /* 0x362 */
+ { 1440, 900, 24 }, /* 0x363 */
+ { 1440, 900, 32 }, /* 0x364 */
+ { 1152, 720, 8 }, /* 0x365 */
+ { 1152, 720, 15 }, /* 0x366 */
+ { 1152, 720, 16 }, /* 0x367 */
+ { 1152, 720, 24 }, /* 0x368 */
+ { 1152, 720, 32 }, /* 0x369 */
+ { 1024, 640, 8 }, /* 0x36a */
+ { 1024, 640, 15 }, /* 0x36b */
+ { 1024, 640, 16 }, /* 0x36c */
+ { 1024, 640, 24 }, /* 0x36d */
+ { 1024, 640, 32 }, /* 0x36e */
+ { 800, 500, 8 }, /* 0x36f */
+ { 800, 500, 15 }, /* 0x370 */
+ { 800, 500, 16 }, /* 0x371 */
+ { 800, 500, 24 }, /* 0x372 */
+ { 800, 500, 32 }, /* 0x373 */
+ };
diff --git a/grub-core/lib/i386/random.c b/grub-core/lib/i386/random.c
new file mode 100644
index 0000000..cd83d2f
--- /dev/null
+++ b/grub-core/lib/i386/random.c
@@ -0,0 +1,103 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2016 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/random.h>
+#include <grub/i386/io.h>
+#include <grub/i386/tsc.h>
+#include <grub/i386/pmtimer.h>
+#include <grub/acpi.h>
+
+static int have_tsc = -1, have_pmtimer = -1;
+static grub_port_t pmtimer_port;
+
+static int
+detect_pmtimer (void)
+{
+ struct grub_acpi_fadt *fadt;
+ fadt = grub_acpi_find_fadt ();
+ if (!fadt)
+ return 0;
+ pmtimer_port = fadt->pmtimer;
+ if (!pmtimer_port)
+ return 0;
+ return 1;
+}
+
+static int
+pmtimer_tsc_get_random_bit (void)
+{
+ /* It's hard to come up with figures about pmtimer and tsc jitter but
+ 50 ppm seems to be typical. So we need 10^6/50 tsc cycles to get drift
+ of one tsc cycle. With TSC at least of 800 MHz it means 1/(50*800)
+ = 1/40000 s or about 3579545 / 40000 = 90 pmtimer ticks.
+ This gives us rate of 40000 bit/s or 5 kB/s.
+ */
+ grub_uint64_t tsc_diff;
+ tsc_diff = grub_pmtimer_wait_count_tsc (pmtimer_port, 90);
+ if (tsc_diff == 0)
+ {
+ have_pmtimer = 0;
+ return -1;
+ }
+ return tsc_diff & 1;
+}
+
+static int
+pmtimer_tsc_get_random_byte (void)
+{
+ grub_uint8_t ret = 0;
+ int i, c;
+ for (i = 0; i < 8; i++)
+ {
+ c = pmtimer_tsc_get_random_bit ();
+ if (c < 0)
+ return -1;
+ ret |= c << i;
+ }
+ return ret;
+}
+
+static int
+pmtimer_fill_buffer (void *buffer, grub_size_t sz)
+{
+ grub_uint8_t *p = buffer;
+ int c;
+ while (sz)
+ {
+ c = pmtimer_tsc_get_random_byte ();
+ if (c < 0)
+ return 0;
+ *p++ = c;
+ sz--;
+ }
+ return 1;
+}
+
+int
+grub_crypto_arch_get_random (void *buffer, grub_size_t sz)
+{
+ if (have_tsc == -1)
+ have_tsc = grub_cpu_is_tsc_supported ();
+ if (!have_tsc)
+ return 0;
+ if (have_pmtimer == -1)
+ have_pmtimer = detect_pmtimer ();
+ if (!have_pmtimer)
+ return 0;
+ return pmtimer_fill_buffer (buffer, sz);
+}
diff --git a/grub-core/lib/i386/reboot.c b/grub-core/lib/i386/reboot.c
new file mode 100644
index 0000000..dce0b56
--- /dev/null
+++ b/grub-core/lib/i386/reboot.c
@@ -0,0 +1,64 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 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/>.
+ */
+
+#ifndef GRUB_MACHINE_EFI
+
+#include <grub/relocator.h>
+#include <grub/cpu/relocator.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/cpu/reboot.h>
+#include <grub/i386/floppy.h>
+
+void
+grub_reboot (void)
+{
+ struct grub_relocator *relocator = NULL;
+ grub_relocator_chunk_t ch;
+ grub_err_t err;
+ void *buf;
+ struct grub_relocator16_state state;
+ grub_uint16_t segment;
+
+ relocator = grub_relocator_new ();
+ if (!relocator)
+ while (1);
+ err = grub_relocator_alloc_chunk_align (relocator, &ch, 0x1000, 0x1000,
+ grub_reboot_end - grub_reboot_start,
+ 16, GRUB_RELOCATOR_PREFERENCE_NONE,
+ 0);
+ if (err)
+ while (1);
+ buf = get_virtual_current_address (ch);
+ grub_memcpy (buf, grub_reboot_start, grub_reboot_end - grub_reboot_start);
+
+ segment = ((grub_addr_t) get_physical_target_address (ch)) >> 4;
+ state.gs = state.fs = state.es = state.ds = state.ss = segment;
+ state.sp = 0;
+ state.cs = segment;
+ state.ip = 0;
+ state.a20 = 0;
+
+ grub_stop_floppy ();
+
+ err = grub_relocator16_boot (relocator, state);
+
+ while (1);
+}
+
+#endif /* GRUB_MACHINE_EFI */
diff --git a/grub-core/lib/i386/reboot_trampoline.S b/grub-core/lib/i386/reboot_trampoline.S
new file mode 100644
index 0000000..c088cd0
--- /dev/null
+++ b/grub-core/lib/i386/reboot_trampoline.S
@@ -0,0 +1,34 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 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 <grub/symbol.h>
+#include <grub/i386/reboot.h>
+
+ .p2align 4
+
+VARIABLE(grub_reboot_start)
+ .code16
+
+ /* set 0x472 to 0x0000 for cold boot (0x1234 for warm boot) */
+ movw $0x0472, %di
+ xorw %ax, %ax
+ movw %ax, (%di)
+ ljmp $0xf000, $0xfff0
+
+ .code32
+VARIABLE(grub_reboot_end)
diff --git a/grub-core/lib/i386/relocator.c b/grub-core/lib/i386/relocator.c
new file mode 100644
index 0000000..34cbe83
--- /dev/null
+++ b/grub-core/lib/i386/relocator.c
@@ -0,0 +1,210 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 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/mm.h>
+#include <grub/misc.h>
+
+#include <grub/types.h>
+#include <grub/err.h>
+#include <grub/term.h>
+
+#include <grub/i386/relocator.h>
+#include <grub/relocator_private.h>
+#include <grub/i386/relocator_private.h>
+#include <grub/i386/pc/int.h>
+
+extern grub_uint8_t grub_relocator16_start;
+extern grub_uint8_t grub_relocator16_end;
+extern grub_uint16_t grub_relocator16_cs;
+extern grub_uint16_t grub_relocator16_ip;
+extern grub_uint16_t grub_relocator16_ds;
+extern grub_uint16_t grub_relocator16_es;
+extern grub_uint16_t grub_relocator16_fs;
+extern grub_uint16_t grub_relocator16_gs;
+extern grub_uint16_t grub_relocator16_ss;
+extern grub_uint16_t grub_relocator16_sp;
+extern grub_uint32_t grub_relocator16_edx;
+extern grub_uint32_t grub_relocator16_ebx;
+extern grub_uint32_t grub_relocator16_esi;
+extern grub_uint32_t grub_relocator16_ebp;
+
+extern grub_uint16_t grub_relocator16_keep_a20_enabled;
+
+extern grub_uint8_t grub_relocator32_start;
+extern grub_uint8_t grub_relocator32_end;
+extern grub_uint32_t grub_relocator32_eax;
+extern grub_uint32_t grub_relocator32_ebx;
+extern grub_uint32_t grub_relocator32_ecx;
+extern grub_uint32_t grub_relocator32_edx;
+extern grub_uint32_t grub_relocator32_eip;
+extern grub_uint32_t grub_relocator32_esp;
+extern grub_uint32_t grub_relocator32_ebp;
+extern grub_uint32_t grub_relocator32_esi;
+extern grub_uint32_t grub_relocator32_edi;
+
+extern grub_uint8_t grub_relocator64_start;
+extern grub_uint8_t grub_relocator64_end;
+extern grub_uint64_t grub_relocator64_rax;
+extern grub_uint64_t grub_relocator64_rbx;
+extern grub_uint64_t grub_relocator64_rcx;
+extern grub_uint64_t grub_relocator64_rdx;
+extern grub_uint64_t grub_relocator64_rip;
+extern grub_uint64_t grub_relocator64_rsp;
+extern grub_uint64_t grub_relocator64_rsi;
+extern grub_addr_t grub_relocator64_cr3;
+extern struct grub_i386_idt grub_relocator16_idt;
+
+#define RELOCATOR_SIZEOF(x) (&grub_relocator##x##_end - &grub_relocator##x##_start)
+
+grub_err_t
+grub_relocator32_boot (struct grub_relocator *rel,
+ struct grub_relocator32_state state,
+ int avoid_efi_bootservices)
+{
+ grub_err_t err;
+ void *relst;
+ grub_relocator_chunk_t ch;
+
+ /* Specific memory range due to Global Descriptor Table for use by payload
+ that we will store in returned chunk. The address range and preference
+ are based on "THE LINUX/x86 BOOT PROTOCOL" specification. */
+ err = grub_relocator_alloc_chunk_align_safe (rel, &ch, 0x1000, 0x9a000,
+ RELOCATOR_SIZEOF (32), 16,
+ GRUB_RELOCATOR_PREFERENCE_LOW,
+ avoid_efi_bootservices);
+ if (err)
+ return err;
+
+ grub_relocator32_eax = state.eax;
+ grub_relocator32_ebx = state.ebx;
+ grub_relocator32_ecx = state.ecx;
+ grub_relocator32_edx = state.edx;
+ grub_relocator32_eip = state.eip;
+ grub_relocator32_esp = state.esp;
+ grub_relocator32_ebp = state.ebp;
+ grub_relocator32_esi = state.esi;
+ grub_relocator32_edi = state.edi;
+
+ grub_memmove (get_virtual_current_address (ch), &grub_relocator32_start,
+ RELOCATOR_SIZEOF (32));
+
+ err = grub_relocator_prepare_relocs (rel, get_physical_target_address (ch),
+ &relst, NULL);
+ if (err)
+ return err;
+
+ asm volatile ("cli");
+ ((void (*) (void)) relst) ();
+
+ /* Not reached. */
+ return GRUB_ERR_NONE;
+}
+
+grub_err_t
+grub_relocator16_boot (struct grub_relocator *rel,
+ struct grub_relocator16_state state)
+{
+ grub_err_t err;
+ void *relst;
+ grub_relocator_chunk_t ch;
+
+ /* Put it higher than the byte it checks for A20 check. */
+ err = grub_relocator_alloc_chunk_align_safe (rel, &ch, 0x8010, 0xa0000,
+ RELOCATOR_SIZEOF (16) +
+ GRUB_RELOCATOR16_STACK_SIZE, 16,
+ GRUB_RELOCATOR_PREFERENCE_NONE, 0);
+ if (err)
+ return err;
+
+ grub_relocator16_cs = state.cs;
+ grub_relocator16_ip = state.ip;
+
+ grub_relocator16_ds = state.ds;
+ grub_relocator16_es = state.es;
+ grub_relocator16_fs = state.fs;
+ grub_relocator16_gs = state.gs;
+
+ grub_relocator16_ss = state.ss;
+ grub_relocator16_sp = state.sp;
+
+ grub_relocator16_ebp = state.ebp;
+ grub_relocator16_ebx = state.ebx;
+ grub_relocator16_edx = state.edx;
+ grub_relocator16_esi = state.esi;
+#ifdef GRUB_MACHINE_PCBIOS
+ grub_relocator16_idt = *grub_realidt;
+#else
+ grub_relocator16_idt.base = 0;
+ grub_relocator16_idt.limit = 0;
+#endif
+
+ grub_relocator16_keep_a20_enabled = state.a20;
+
+ grub_memmove (get_virtual_current_address (ch), &grub_relocator16_start,
+ RELOCATOR_SIZEOF (16));
+
+ err = grub_relocator_prepare_relocs (rel, get_physical_target_address (ch),
+ &relst, NULL);
+ if (err)
+ return err;
+
+ asm volatile ("cli");
+ ((void (*) (void)) relst) ();
+
+ /* Not reached. */
+ return GRUB_ERR_NONE;
+}
+
+grub_err_t
+grub_relocator64_boot (struct grub_relocator *rel,
+ struct grub_relocator64_state state,
+ grub_addr_t min_addr, grub_addr_t max_addr)
+{
+ grub_err_t err;
+ void *relst;
+ grub_relocator_chunk_t ch;
+
+ err = grub_relocator_alloc_chunk_align_safe (rel, &ch, min_addr, max_addr,
+ RELOCATOR_SIZEOF (64), 16,
+ GRUB_RELOCATOR_PREFERENCE_NONE, 0);
+ if (err)
+ return err;
+
+ grub_relocator64_rax = state.rax;
+ grub_relocator64_rbx = state.rbx;
+ grub_relocator64_rcx = state.rcx;
+ grub_relocator64_rdx = state.rdx;
+ grub_relocator64_rip = state.rip;
+ grub_relocator64_rsp = state.rsp;
+ grub_relocator64_rsi = state.rsi;
+ grub_relocator64_cr3 = state.cr3;
+
+ grub_memmove (get_virtual_current_address (ch), &grub_relocator64_start,
+ RELOCATOR_SIZEOF (64));
+
+ err = grub_relocator_prepare_relocs (rel, get_physical_target_address (ch),
+ &relst, NULL);
+ if (err)
+ return err;
+
+ asm volatile ("cli");
+ ((void (*) (void)) relst) ();
+
+ /* Not reached. */
+ return GRUB_ERR_NONE;
+}
diff --git a/grub-core/lib/i386/relocator16.S b/grub-core/lib/i386/relocator16.S
new file mode 100644
index 0000000..e923811
--- /dev/null
+++ b/grub-core/lib/i386/relocator16.S
@@ -0,0 +1,341 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 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/>.
+ */
+
+/* The code segment of the protected mode. */
+#define CODE_SEGMENT 0x08
+
+/* The data segment of the protected mode. */
+#define DATA_SEGMENT 0x10
+
+#define PSEUDO_REAL_CSEG 0x18
+
+#define PSEUDO_REAL_DSEG 0x20
+
+#include <grub/i386/relocator_private.h>
+
+#include "relocator_common.S"
+
+ .p2align 4 /* force 16-byte alignment */
+
+VARIABLE(grub_relocator16_start)
+ PREAMBLE
+
+#ifdef __APPLE__
+ LOCAL(cs_base_bytes12_offset) = LOCAL (cs_base_bytes12) - LOCAL (base)
+ LOCAL(cs_base_byte3_offset) = LOCAL (cs_base_byte3) - LOCAL (base)
+ LOCAL(ds_base_bytes12_offset) = LOCAL (ds_base_bytes12) - LOCAL (base)
+ LOCAL(ds_base_byte3_offset) = LOCAL (ds_base_byte3) - LOCAL (base)
+ movl %esi, %eax
+ movw %ax, (LOCAL(cs_base_bytes12_offset)) (RSI, 1)
+ movw %ax, (LOCAL(ds_base_bytes12_offset)) (RSI, 1)
+ shrl $16, %eax
+ movb %al, (LOCAL (cs_base_byte3_offset)) (RSI, 1)
+ movb %al, (LOCAL (ds_base_byte3_offset)) (RSI, 1)
+#else
+ movl %esi, %eax
+ movw %ax, (LOCAL (cs_base_bytes12) - LOCAL (base)) (RSI, 1)
+ movw %ax, (LOCAL (ds_base_bytes12) - LOCAL (base)) (RSI, 1)
+ shrl $16, %eax
+ movb %al, (LOCAL (cs_base_byte3) - LOCAL (base)) (RSI, 1)
+ movb %al, (LOCAL (ds_base_byte3) - LOCAL (base)) (RSI, 1)
+#endif
+
+ RELOAD_GDT
+ .code32
+ /* Update other registers. */
+ movl $DATA_SEGMENT, %eax
+ movl %eax, %ds
+ movl %eax, %es
+ movl %eax, %fs
+ movl %eax, %gs
+ movl %eax, %ss
+
+ DISABLE_PAGING
+
+#ifdef __x86_64__
+ /* Disable amd64. */
+ movl $GRUB_MEMORY_CPU_AMD64_MSR, %ecx
+ rdmsr
+ andl $(~GRUB_MEMORY_CPU_AMD64_MSR_ON), %eax
+ wrmsr
+#endif
+
+ /* Turn off PAE. */
+ movl %cr4, %eax
+ andl $(~GRUB_MEMORY_CPU_CR4_PAE_ON), %eax
+ movl %eax, %cr4
+
+ /* Update other registers. */
+ movl $PSEUDO_REAL_DSEG, %eax
+ movl %eax, %ds
+ movl %eax, %es
+ movl %eax, %fs
+ movl %eax, %gs
+ movl %eax, %ss
+
+ movl %esi, %eax
+ shrl $4, %eax
+#ifdef __APPLE__
+ LOCAL(segment_offset) = LOCAL (segment) - LOCAL (base)
+ LOCAL(idt_offset) = LOCAL(relocator16_idt) - LOCAL (base)
+ LOCAL(cont2_offset) = LOCAL (cont2) - LOCAL(base)
+ movw %ax, (LOCAL(segment_offset))
+ lidt (LOCAL(idt_offset))
+
+ /* jump to a 16 bit segment */
+ ljmp $PSEUDO_REAL_CSEG, $(LOCAL(cont2_offset))
+#else
+ movw %ax, (LOCAL (segment) - LOCAL (base))
+
+ lidt (EXT_C(grub_relocator16_idt) - LOCAL (base))
+
+ /* jump to a 16 bit segment */
+ ljmp $PSEUDO_REAL_CSEG, $(LOCAL (cont2) - LOCAL(base))
+#endif
+LOCAL(cont2):
+ .code16
+
+ /* clear the PE bit of CR0 */
+ movl %cr0, %eax
+ andl $(~GRUB_MEMORY_CPU_CR0_PE_ON), %eax
+ movl %eax, %cr0
+
+ /* flush prefetch queue, reload %cs */
+ /* ljmp */
+ .byte 0xea
+#ifdef __APPLE__
+ LOCAL(cont3_offset) = LOCAL(cont3) - LOCAL(base)
+ .word LOCAL(cont3_offset)
+#else
+ .word LOCAL(cont3)-LOCAL(base)
+#endif
+LOCAL(segment):
+ .word 0
+
+LOCAL(cont3):
+
+ /* movw imm16, %ax. */
+ .byte 0xb8
+VARIABLE(grub_relocator16_keep_a20_enabled)
+ .word 0
+
+ test %ax, %ax
+ jnz LOCAL(gate_a20_done)
+
+ movw %cs, %ax
+ movw %ax, %ss
+#ifdef __APPLE__
+ LOCAL(relocator16_end_offset) = LOCAL(relocator16_end) - LOCAL(base)
+ leaw LOCAL(relocator16_end_offset), %sp
+#else
+ leaw LOCAL(relocator16_end) - LOCAL(base), %sp
+#endif
+ addw $GRUB_RELOCATOR16_STACK_SIZE, %sp
+
+ /* second, try a BIOS call */
+ movw $0x2400, %ax
+ int $0x15
+
+ call LOCAL(gate_a20_check_state)
+ testb %al, %al
+ jz LOCAL(gate_a20_done)
+
+ /*
+ * 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
+ 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. */
+ jmp LOCAL(gate_a20_done)
+
+LOCAL(gate_a20_check_state):
+ /* iterate the checking for a while */
+ movw $100, %cx
+1:
+ xorw %ax, %ax
+ movw %ax, %ds
+ decw %ax
+ movw %ax, %es
+ xorw %ax, %ax
+
+ movw $0x8000, %ax
+ /* compare the byte at ADDR with that at 0x100000 + ADDR */
+ movw %ax, %si
+ addw $0x10, %ax
+ movw %ax, %di
+
+ /* save the original byte in DL */
+ movb %ds:(%si), %dl
+ movb %es:(%di), %al
+ /* try to set one less value at ADDR */
+ movb %al, %dh
+ decb %dh
+ movb %dh, %ds:(%si)
+ /* serialize */
+ outb %al, $0x80
+ outb %al, $0x80
+ /* obtain the value at 0x100000 + ADDR in CH */
+ movb %es:(%di), %dh
+ /* this result is 1 if A20 is on or 0 if it is off */
+ subb %dh, %al
+ xorb $1, %al
+ /* restore the original */
+ movb %dl, %ds:(%si)
+
+ testb %al, %al
+ jz LOCAL(gate_a20_done)
+ loop 1b
+2:
+ ret
+
+LOCAL(gate_a20_done):
+ /*
+ * We are in real mode now. Set up the real mode segment registers and
+ * all the other general purpose registers. cs is updated with ljmp.
+ */
+ /* movw imm16, %ax. */
+ .byte 0xb8
+VARIABLE(grub_relocator16_ds)
+ .word 0
+ movw %ax, %ds
+
+ /* movw imm16, %ax. */
+ .byte 0xb8
+VARIABLE(grub_relocator16_es)
+ .word 0
+ movw %ax, %es
+
+ /* movw imm16, %ax. */
+ .byte 0xb8
+VARIABLE(grub_relocator16_fs)
+ .word 0
+ movw %ax, %fs
+
+ /* movw imm16, %ax. */
+ .byte 0xb8
+VARIABLE(grub_relocator16_gs)
+ .word 0
+ movw %ax, %gs
+
+ /* movw imm16, %ax. */
+ .byte 0xb8
+VARIABLE(grub_relocator16_ss)
+ .word 0
+ movw %ax, %ss
+
+ /* movw imm16, %ax. */
+ .byte 0xb8
+VARIABLE(grub_relocator16_sp)
+ .word 0
+ movzwl %ax, %esp
+
+ /* movw imm32, %eax. */
+ .byte 0x66, 0xb8
+VARIABLE(grub_relocator16_esi)
+ .long 0
+ movl %eax, %esi
+
+ /* movw imm32, %edx. */
+ .byte 0x66, 0xba
+VARIABLE(grub_relocator16_edx)
+ .long 0
+
+ /* movw imm32, %ebx. */
+ .byte 0x66, 0xbb
+VARIABLE(grub_relocator16_ebx)
+ .long 0
+
+ /* movl imm32, %ebp. */
+ .byte 0x66, 0xbd
+VARIABLE(grub_relocator16_ebp)
+ .long 0
+
+ /* Cleared direction flag is of no problem with any current
+ payload and makes this implementation easier. */
+ cld
+
+ /* ljmp */
+ .byte 0xea
+VARIABLE(grub_relocator16_ip)
+ .word 0
+VARIABLE(grub_relocator16_cs)
+ .word 0
+
+ .code32
+
+ /* GDT. Copied from loader/i386/linux.c. */
+ .p2align 4
+LOCAL(gdt):
+ .word 0, 0
+ .byte 0, 0, 0, 0
+
+ /* -- code segment --
+ * base = 0x00000000, limit = 0xFFFFF (4 KiB Granularity), present
+ * type = 32bit code execute/read, DPL = 0
+ */
+ .word 0xFFFF, 0
+ .byte 0, 0x9A, 0xCF, 0
+
+ /* -- data segment --
+ * base = 0x00000000, limit 0xFFFFF (4 KiB Granularity), present
+ * type = 32 bit data read/write, DPL = 0
+ */
+ .word 0xFFFF, 0
+ .byte 0, 0x92, 0xCF, 0
+
+ /* -- 16 bit real mode CS --
+ * base = filled by code, limit 0x0FFFF (1 B Granularity), present
+ * type = 16 bit code execute/read only/conforming, DPL = 0
+ */
+ .word 0xFFFF
+LOCAL(cs_base_bytes12):
+ .word 0
+LOCAL(cs_base_byte3):
+ .byte 0
+
+ .byte 0x9E, 0, 0
+
+ /* -- 16 bit real mode DS --
+ * base = filled by code, limit 0x0FFFF (1 B Granularity), present
+ * type = 16 bit data read/write, DPL = 0
+ */
+ .word 0xFFFF
+LOCAL(ds_base_bytes12):
+ .word 0
+LOCAL(ds_base_byte3):
+ .byte 0
+
+ .byte 0x92, 0, 0
+
+LOCAL(gdt_end):
+
+#ifdef __APPLE__
+LOCAL(relocator16_idt):
+#endif
+VARIABLE(grub_relocator16_idt)
+ .word 0
+ .long 0
+LOCAL(relocator16_end):
+VARIABLE(grub_relocator16_end)
+ .byte 0
diff --git a/grub-core/lib/i386/relocator32.S b/grub-core/lib/i386/relocator32.S
new file mode 100644
index 0000000..09ce56a
--- /dev/null
+++ b/grub-core/lib/i386/relocator32.S
@@ -0,0 +1,134 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 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/>.
+ */
+
+/* The code segment of the protected mode. */
+#define CODE_SEGMENT 0x10
+
+/* The data segment of the protected mode. */
+#define DATA_SEGMENT 0x18
+
+#include "relocator_common.S"
+
+ .p2align 4 /* force 16-byte alignment */
+
+VARIABLE(grub_relocator32_start)
+ PREAMBLE
+
+ RELOAD_GDT
+ .code32
+ /* Update other registers. */
+ movl $DATA_SEGMENT, %eax
+ movl %eax, %ds
+ movl %eax, %es
+ movl %eax, %fs
+ movl %eax, %gs
+ movl %eax, %ss
+
+ DISABLE_PAGING
+
+#ifdef __x86_64__
+ /* Disable amd64. */
+ movl $GRUB_MEMORY_CPU_AMD64_MSR, %ecx
+ rdmsr
+ andl $(~GRUB_MEMORY_CPU_AMD64_MSR_ON), %eax
+ wrmsr
+#endif
+
+ /* Turn off PAE. */
+ movl %cr4, %eax
+ andl $(~GRUB_MEMORY_CPU_CR4_PAE_ON), %eax
+ movl %eax, %cr4
+
+ jmp LOCAL(cont2)
+LOCAL(cont2):
+ .code32
+
+ /* mov imm32, %eax */
+ .byte 0xb8
+VARIABLE(grub_relocator32_esp)
+ .long 0
+
+ movl %eax, %esp
+
+ /* mov imm32, %eax */
+ .byte 0xb8
+VARIABLE(grub_relocator32_ebp)
+ .long 0
+
+ movl %eax, %ebp
+
+ /* mov imm32, %eax */
+ .byte 0xb8
+VARIABLE(grub_relocator32_esi)
+ .long 0
+
+ movl %eax, %esi
+
+ /* mov imm32, %eax */
+ .byte 0xb8
+VARIABLE(grub_relocator32_edi)
+ .long 0
+
+ movl %eax, %edi
+
+ /* mov imm32, %eax */
+ .byte 0xb8
+VARIABLE(grub_relocator32_eax)
+ .long 0
+
+ /* mov imm32, %ebx */
+ .byte 0xbb
+VARIABLE(grub_relocator32_ebx)
+ .long 0
+
+ /* mov imm32, %ecx */
+ .byte 0xb9
+VARIABLE(grub_relocator32_ecx)
+ .long 0
+
+ /* mov imm32, %edx */
+ .byte 0xba
+VARIABLE(grub_relocator32_edx)
+ .long 0
+
+ /* Cleared direction flag is of no problem with any current
+ payload and makes this implementation easier. */
+ cld
+
+ .byte 0xea
+VARIABLE(grub_relocator32_eip)
+ .long 0
+ .word CODE_SEGMENT
+
+ /* GDT. Copied from loader/i386/linux.c. */
+ .p2align 4
+LOCAL(gdt):
+ /* NULL. */
+ .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+
+ /* Reserved. */
+ .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+
+ /* Code segment. */
+ .byte 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x9A, 0xCF, 0x00
+
+ /* Data segment. */
+ .byte 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x92, 0xCF, 0x00
+LOCAL(gdt_end):
+
+VARIABLE(grub_relocator32_end)
diff --git a/grub-core/lib/i386/relocator64.S b/grub-core/lib/i386/relocator64.S
new file mode 100644
index 0000000..00bf315
--- /dev/null
+++ b/grub-core/lib/i386/relocator64.S
@@ -0,0 +1,210 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 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/>.
+ */
+
+#define CODE32_SEGMENT 0x18
+#define CODE_SEGMENT 0x08
+
+/* The data segment of the protected mode. */
+#define DATA_SEGMENT 0x10
+
+#include "relocator_common.S"
+
+ .p2align 4 /* force 16-byte alignment */
+
+VARIABLE(grub_relocator64_start)
+ PREAMBLE
+#ifndef __x86_64__
+ DISABLE_PAGING
+
+ /* Turn on PAE. */
+ movl %cr4, %eax
+ orl $(GRUB_MEMORY_CPU_CR4_PAE_ON | GRUB_MEMORY_CPU_CR4_PSE_ON), %eax
+ movl %eax, %cr4
+
+ /* mov imm32, %eax */
+ .byte 0xb8
+VARIABLE(grub_relocator64_cr3)
+ .long 0
+ movl %eax, %cr3
+
+ /* Turn on amd64. */
+ movl $GRUB_MEMORY_CPU_AMD64_MSR, %ecx
+ rdmsr
+ orl $GRUB_MEMORY_CPU_AMD64_MSR_ON, %eax
+ wrmsr
+
+ /* Enable paging. */
+ movl %cr0, %eax
+ orl $GRUB_MEMORY_CPU_CR0_PAGING_ON, %eax
+ movl %eax, %cr0
+
+ RELOAD_GDT
+#else
+ /* mov imm64, %rax */
+ .byte 0x48
+ .byte 0xb8
+VARIABLE(grub_relocator64_cr3)
+ .quad 0
+ movq %rax, %cr3
+#endif
+
+#ifdef __x86_64__
+ .code64
+#endif
+
+ /* mov imm64, %rax */
+ .byte 0x48
+ .byte 0xb8
+VARIABLE(grub_relocator64_rsp)
+ .quad 0
+
+#ifdef __x86_64__
+ movq %rax, %rsp
+#else
+ /* movq %rax, %rsp */
+ .byte 0x48
+ .byte 0x89
+ .byte 0xc4
+#endif
+
+#ifdef GRUB_MACHINE_EFI
+ jmp LOCAL(skip_efi_stack_align)
+
+ /*
+ * Here is grub_relocator64_efi_start() entry point. Most of the
+ * code below is shared between grub_relocator64_efi_start()
+ * and grub_relocator64_start().
+ *
+ * Think twice before changing anything there!!!
+ */
+VARIABLE(grub_relocator64_efi_start)
+ /* Align the stack as UEFI spec requires. */
+#ifdef __x86_64__
+ andq $~15, %rsp
+#else
+ /* andq $~15, %rsp */
+ .byte 0x48
+ .byte 0x83
+ .byte 0xe4
+ .byte 0xf0
+#endif
+
+LOCAL(skip_efi_stack_align):
+#endif
+ /* mov imm64, %rax */
+ .byte 0x48
+ .byte 0xb8
+VARIABLE(grub_relocator64_rsi)
+ .quad 0
+
+#ifdef __x86_64__
+ movq %rax, %rsi
+#else
+ /* movq %rax, %rsi */
+ .byte 0x48
+ .byte 0x89
+ .byte 0xc6
+#endif
+
+ /* mov imm64, %rax */
+ .byte 0x48
+ .byte 0xb8
+VARIABLE(grub_relocator64_rax)
+ .quad 0
+
+ /* mov imm64, %rbx */
+ .byte 0x48
+ .byte 0xbb
+VARIABLE(grub_relocator64_rbx)
+ .quad 0
+
+ /* mov imm64, %rcx */
+ .byte 0x48
+ .byte 0xb9
+VARIABLE(grub_relocator64_rcx)
+ .quad 0
+
+ /* mov imm64, %rdx */
+ .byte 0x48
+ .byte 0xba
+VARIABLE(grub_relocator64_rdx)
+ .quad 0
+
+ /* Cleared direction flag is of no problem with any current
+ payload and makes this implementation easier. */
+ cld
+
+#if defined (__APPLE__) || !defined (__x86_64__)
+ .byte 0xff, 0x25
+ .quad 0
+#else
+ jmp *LOCAL(jump_addr) (%rip)
+#endif
+
+LOCAL(jump_addr):
+VARIABLE(grub_relocator64_rip)
+ .quad 0
+
+#ifdef GRUB_MACHINE_EFI
+ /* Here grub_relocator64_efi_start() ends. Ufff... */
+VARIABLE(grub_relocator64_efi_end)
+#endif
+
+#ifndef __x86_64__
+ .p2align 4
+LOCAL(gdt):
+ /* NULL. */
+ .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+
+ /* 64-bit segment. */
+ .word 0xffff /* Limit xffff. */
+ .word 0x0000 /* Base xxxx0000. */
+ .byte 0x00 /* Base xx00xxxx. */
+ .byte (0x8 /* Type 8. */ | (1 << 4) /* Code. */ \
+ | (0 << 5) /* Ring 0. */ | (1 << 7) /* Present. */)
+ .byte (0xf /* Limit fxxxx. */ | (0 << 4) /* AVL flag. */ \
+ | (1 << 5) /* 64-bit. */ | (0 << 6) \
+ | (1 << 7) /* 4K granular. */)
+ .byte 0x00 /* Base 00xxxxxx. */
+
+ /* Data segment*/
+ .word 0xffff /* Limit xffff. */
+ .word 0x0000 /* Base xxxx0000. */
+ .byte 0x00 /* Base xx00xxxx. */
+ .byte (0x0 /* Type 0. */ | (0 << 4) /* Data. */ \
+ | (0 << 5) /* Ring 0. */ | (1 << 7) /* Present. */)
+ .byte (0xf /* Limit fxxxx. */ | (0 << 4) /* AVL flag. */ \
+ | (0 << 5) /* Data. */ | (0 << 6) \
+ | (1 << 7) /* 4K granular. */)
+ .byte 0x00 /* Base 00xxxxxx. */
+
+ /* Compatibility segment. */
+ .word 0xffff /* Limit xffff. */
+ .word 0x0000 /* Base xxxx0000. */
+ .byte 0x00 /* Base xx00xxxx. */
+ .byte (0x8 /* Type 8. */ | (1 << 4) /* Code. */ \
+ | (0 << 5) /* Ring 0. */ | (1 << 7) /* Present. */)
+ .byte (0xf /* Limit fxxxx. */ | (0 << 4) /* AVL flag. */ \
+ | (0 << 5) /* 32-bit. */ | (1 << 6) /* 32-bit. */ \
+ | (1 << 7) /* 4K granular. */)
+ .byte 0x00 /* Base 00xxxxxx. */
+
+LOCAL(gdt_end):
+#endif
+
+VARIABLE(grub_relocator64_end)
diff --git a/grub-core/lib/i386/relocator_asm.S b/grub-core/lib/i386/relocator_asm.S
new file mode 100644
index 0000000..f273586
--- /dev/null
+++ b/grub-core/lib/i386/relocator_asm.S
@@ -0,0 +1,80 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 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/i386/memory.h>
+
+ .p2align 2
+
+VARIABLE(grub_relocator_backward_start)
+ /* mov imm32, %eax */
+ .byte 0xb8
+VARIABLE(grub_relocator_backward_dest)
+ .long 0
+ movl %eax, %edi
+
+ /* mov imm32, %eax */
+ .byte 0xb8
+VARIABLE(grub_relocator_backward_src)
+ .long 0
+ movl %eax, %esi
+
+ /* mov imm32, %ecx */
+ .byte 0xb9
+VARIABLE(grub_relocator_backward_chunk_size)
+ .long 0
+
+ add %ecx, %esi
+ add %ecx, %edi
+
+
+ /* Backward movsb is implicitly off-by-one. compensate that. */
+ sub $1, %esi
+ sub $1, %edi
+
+ /* Backward copy. */
+ std
+
+ rep
+ movsb
+VARIABLE(grub_relocator_backward_end)
+
+
+VARIABLE(grub_relocator_forward_start)
+ /* mov imm32, %eax */
+ .byte 0xb8
+VARIABLE(grub_relocator_forward_dest)
+ .long 0
+ movl %eax, %edi
+
+ /* mov imm32, %rax */
+ .byte 0xb8
+VARIABLE(grub_relocator_forward_src)
+ .long 0
+ movl %eax, %esi
+
+ /* mov imm32, %ecx */
+ .byte 0xb9
+VARIABLE(grub_relocator_forward_chunk_size)
+ .long 0
+
+ /* Forward copy. */
+ cld
+ rep
+ movsb
+VARIABLE(grub_relocator_forward_end)
diff --git a/grub-core/lib/i386/relocator_common.S b/grub-core/lib/i386/relocator_common.S
new file mode 100644
index 0000000..1b5210d
--- /dev/null
+++ b/grub-core/lib/i386/relocator_common.S
@@ -0,0 +1,111 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 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/i386/memory.h>
+
+#ifdef __x86_64__
+#define RAX %rax
+#define RSI %rsi
+#else
+#define RAX %eax
+#define RSI %esi
+#endif
+
+ .macro DISABLE_PAGING
+
+ movl %cr0, %eax
+ andl $(~GRUB_MEMORY_CPU_CR0_PAGING_ON), %eax
+ movl %eax, %cr0
+ .endm
+
+ .macro PREAMBLE
+LOCAL(base):
+ /* %rax contains now our new 'base'. */
+ mov RAX, RSI
+
+#if defined (__APPLE__) && defined (__x86_64__)
+ leaq LOCAL(cont0) (%rip), RAX
+#elif defined (__APPLE__)
+ LOCAL(cont0_offset) = LOCAL(cont0) - LOCAL(base)
+ add $LOCAL(cont0_offset), RAX
+#else
+ add $(LOCAL(cont0) - LOCAL(base)), RAX
+#endif
+ jmp *RAX
+LOCAL(cont0):
+ .endm
+
+ .macro RELOAD_GDT
+#ifdef __APPLE__
+ LOCAL(cont1_offset) = LOCAL(cont1) - LOCAL(base)
+ LOCAL(jump_vector_offset) = LOCAL(jump_vector) - LOCAL(base)
+ LOCAL(gdt_offset) = LOCAL(gdt) - LOCAL(base)
+ LOCAL(gdt_addr_offset) = LOCAL(gdt_addr) - LOCAL(base)
+ LOCAL(gdtdesc_offset) = LOCAL(gdtdesc) - LOCAL(base)
+
+ lea LOCAL(cont1_offset) (RSI, 1), RAX
+ movl %eax, LOCAL(jump_vector_offset) (RSI, 1)
+
+ lea LOCAL(gdt_offset) (RSI, 1), RAX
+ mov RAX, (LOCAL(gdt_addr_offset)) (RSI, 1)
+
+ /* Switch to compatibility mode. */
+ lgdt (LOCAL(gdtdesc_offset)) (RSI, 1)
+
+ /* Update %cs. */
+ ljmp *(LOCAL(jump_vector_offset)) (RSI, 1)
+ .p2align 4
+LOCAL(gdtdesc):
+ LOCAL(gdtsize) = LOCAL(gdt_end) - LOCAL(gdt)
+ .word LOCAL(gdtsize)
+#else
+ lea (LOCAL(cont1) - LOCAL(base)) (RSI, 1), RAX
+ movl %eax, (LOCAL(jump_vector) - LOCAL(base)) (RSI, 1)
+
+ lea (LOCAL(gdt) - LOCAL(base)) (RSI, 1), RAX
+ mov RAX, (LOCAL(gdt_addr) - LOCAL(base)) (RSI, 1)
+
+ /* Switch to compatibility mode. */
+ lgdt (LOCAL(gdtdesc) - LOCAL(base)) (RSI, 1)
+
+ /* Update %cs. */
+ ljmp *(LOCAL(jump_vector) - LOCAL(base)) (RSI, 1)
+
+ .p2align 4
+LOCAL(gdtdesc):
+ .word LOCAL(gdt_end) - LOCAL(gdt)
+#endif
+LOCAL(gdt_addr):
+#ifdef __x86_64__
+ /* Filled by the code. */
+ .quad 0
+#else
+ /* Filled by the code. */
+ .long 0
+#endif
+
+ .p2align 4
+LOCAL(jump_vector):
+ /* Jump location. Is filled by the code */
+ .long 0
+ .long CODE_SEGMENT
+
+LOCAL(cont1):
+ .endm
diff --git a/grub-core/lib/i386/relocator_common_c.c b/grub-core/lib/i386/relocator_common_c.c
new file mode 100644
index 0000000..7be609b
--- /dev/null
+++ b/grub-core/lib/i386/relocator_common_c.c
@@ -0,0 +1,109 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2009-2013 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/mm.h>
+#include <grub/misc.h>
+
+#include <grub/types.h>
+#include <grub/err.h>
+#include <grub/term.h>
+
+#include <grub/relocator.h>
+#include <grub/relocator_private.h>
+
+extern grub_uint8_t grub_relocator_forward_start;
+extern grub_uint8_t grub_relocator_forward_end;
+extern grub_uint8_t grub_relocator_backward_start;
+extern grub_uint8_t grub_relocator_backward_end;
+
+extern void *grub_relocator_backward_dest;
+extern void *grub_relocator_backward_src;
+extern grub_size_t grub_relocator_backward_chunk_size;
+
+extern void *grub_relocator_forward_dest;
+extern void *grub_relocator_forward_src;
+extern grub_size_t grub_relocator_forward_chunk_size;
+
+#define RELOCATOR_SIZEOF(x) (&grub_relocator##x##_end - &grub_relocator##x##_start)
+
+grub_size_t grub_relocator_align = 1;
+grub_size_t grub_relocator_forward_size;
+grub_size_t grub_relocator_backward_size;
+#ifdef __x86_64__
+grub_size_t grub_relocator_jumper_size = 12;
+#else
+grub_size_t grub_relocator_jumper_size = 7;
+#endif
+
+void
+grub_cpu_relocator_init (void)
+{
+ grub_relocator_forward_size = RELOCATOR_SIZEOF (_forward);
+ grub_relocator_backward_size = RELOCATOR_SIZEOF (_backward);
+}
+
+void
+grub_cpu_relocator_jumper (void *rels, grub_addr_t addr)
+{
+ grub_uint8_t *ptr;
+ ptr = rels;
+#ifdef __x86_64__
+ /* movq imm64, %rax (for relocator) */
+ *(grub_uint8_t *) ptr = 0x48;
+ ptr++;
+ *(grub_uint8_t *) ptr = 0xb8;
+ ptr++;
+ *(grub_uint64_t *) ptr = addr;
+ ptr += sizeof (grub_uint64_t);
+#else
+ /* movl imm32, %eax (for relocator) */
+ *(grub_uint8_t *) ptr = 0xb8;
+ ptr++;
+ *(grub_uint32_t *) ptr = addr;
+ ptr += sizeof (grub_uint32_t);
+#endif
+ /* jmp $eax/$rax */
+ *(grub_uint8_t *) ptr = 0xff;
+ ptr++;
+ *(grub_uint8_t *) ptr = 0xe0;
+ ptr++;
+}
+
+void
+grub_cpu_relocator_backward (void *ptr, void *src, void *dest,
+ grub_size_t size)
+{
+ grub_relocator_backward_dest = dest;
+ grub_relocator_backward_src = src;
+ grub_relocator_backward_chunk_size = size;
+
+ grub_memmove (ptr,
+ &grub_relocator_backward_start, RELOCATOR_SIZEOF (_backward));
+}
+
+void
+grub_cpu_relocator_forward (void *ptr, void *src, void *dest,
+ grub_size_t size)
+{
+ grub_relocator_forward_dest = dest;
+ grub_relocator_forward_src = src;
+ grub_relocator_forward_chunk_size = size;
+
+ grub_memmove (ptr,
+ &grub_relocator_forward_start, RELOCATOR_SIZEOF (_forward));
+}
diff --git a/grub-core/lib/i386/setjmp.S b/grub-core/lib/i386/setjmp.S
new file mode 100644
index 0000000..0b0740f
--- /dev/null
+++ b/grub-core/lib/i386/setjmp.S
@@ -0,0 +1,59 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2003,2007 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/dl.h>
+
+ .file "setjmp.S"
+
+GRUB_MOD_LICENSE "GPLv3+"
+
+ .text
+
+/*
+ * int grub_setjmp (grub_jmp_buf env)
+ */
+FUNCTION(grub_setjmp)
+ movl %ebx, 0(%eax) /* EBX */
+ movl %esi, 4(%eax) /* ESI */
+ movl %edi, 8(%eax) /* EDI */
+ movl %ebp, 12(%eax) /* EBP */
+ popl %ecx
+ movl %esp, 16(%eax) /* ESP */
+ movl %ecx, 20(%eax) /* EIP */
+ xorl %eax, %eax
+ jmp *%ecx
+
+
+/*
+ * int grub_longjmp (grub_jmp_buf env, int val)
+ */
+FUNCTION(grub_longjmp)
+ movl 0(%eax), %ebx
+ movl 4(%eax), %esi
+ movl 8(%eax), %edi
+ movl 12(%eax), %ebp
+ movl 16(%eax), %esp
+ movl 20(%eax), %ecx
+
+ movl %edx, %eax
+ testl %eax, %eax
+ jnz 1f
+ incl %eax
+1: jmp *%ecx
+
diff --git a/grub-core/lib/i386/xen/relocator.S b/grub-core/lib/i386/xen/relocator.S
new file mode 100644
index 0000000..96e51b5
--- /dev/null
+++ b/grub-core/lib/i386/xen/relocator.S
@@ -0,0 +1,165 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2013 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/i386/memory.h>
+#include <grub/i386/types.h>
+#include <grub/symbol.h>
+#include <grub/xen.h>
+
+ .p2align 4 /* force 16-byte alignment */
+
+VARIABLE(grub_relocator_xen_remap_start)
+LOCAL(base):
+ /* Remap the remapper to it's new address. */
+ /* mov imm32, %ebx - %ebx: new virtual address of remapper */
+ .byte 0xbb
+VARIABLE(grub_relocator_xen_remapper_virt)
+ .long 0
+
+ /* mov imm32, %ecx - %ecx: low part of page table entry */
+ .byte 0xb9
+VARIABLE(grub_relocator_xen_remapper_map)
+ .long 0
+
+ /* mov imm32, %edx - %edx: high part of page table entry */
+ .byte 0xba
+VARIABLE(grub_relocator_xen_remapper_map_high)
+ .long 0
+
+ movl %ebx, %ebp /* %ebx is clobbered by hypercall */
+
+ movl $UVMF_INVLPG, %esi /* esi: flags (inv. single entry) */
+ movl $__HYPERVISOR_update_va_mapping, %eax
+ int $0x82
+
+ movl %ebp, %ebx
+ addl $(LOCAL(cont) - LOCAL(base)), %ebx
+
+ jmp *%ebx /* Continue with new virtual address */
+
+LOCAL(cont):
+ /* Modify mappings of new page tables to be read-only. */
+ /* mov imm32, %eax */
+ .byte 0xb8
+VARIABLE(grub_relocator_xen_paging_areas_addr)
+ .long 0
+ movl %eax, %ebx
+1:
+ movl 0(%ebx), %ebp /* Get start pfn of the current area */
+ movl GRUB_TARGET_SIZEOF_LONG(%ebx), %ecx /* Get # of pg tables */
+ testl %ecx, %ecx /* 0 -> last area reached */
+ jz 3f
+ addl $(2 * GRUB_TARGET_SIZEOF_LONG), %ebx
+ movl %ebx, %esp /* Save current area pointer */
+
+2:
+ movl %ecx, %edi
+ /* mov imm32, %eax */
+ .byte 0xb8
+VARIABLE(grub_relocator_xen_mfn_list)
+ .long 0
+ movl 0(%eax, %ebp, 4), %ecx /* mfn */
+ movl %ebp, %ebx
+ shll $PAGE_SHIFT, %ebx /* virtual address (1:1 mapping) */
+ movl %ecx, %edx
+ shll $PAGE_SHIFT, %ecx /* prepare pte low part */
+ shrl $(32 - PAGE_SHIFT), %edx /* pte high part */
+ orl $(GRUB_PAGE_PRESENT | GRUB_PAGE_USER), %ecx /* pte low */
+ movl $UVMF_INVLPG, %esi
+ movl $__HYPERVISOR_update_va_mapping, %eax
+ int $0x82 /* parameters: eax, ebx, ecx, edx, esi */
+
+ incl %ebp /* next pfn */
+ movl %edi, %ecx
+
+ loop 2b
+
+ mov %esp, %ebx /* restore area poniter */
+ jmp 1b
+
+3:
+ /* Switch page tables: pin new L3 pt, load cr3, unpin old L3. */
+ /* mov imm32, %ebx */
+ .byte 0xbb
+VARIABLE(grub_relocator_xen_mmu_op_addr)
+ .long 0
+ movl $3, %ecx /* 3 mmu ops */
+ movl $0, %edx /* pdone (not used) */
+ movl $DOMID_SELF, %esi
+ movl $__HYPERVISOR_mmuext_op, %eax
+ int $0x82
+
+ /* Continue in virtual kernel mapping. */
+ /* mov imm32, %eax */
+ .byte 0xb8
+VARIABLE(grub_relocator_xen_remap_continue)
+ .long 0
+
+ jmp *%eax
+
+VARIABLE(grub_relocator_xen_paging_areas)
+ .long 0, 0, 0, 0, 0, 0, 0, 0
+
+VARIABLE(grub_relocator_xen_mmu_op)
+ .space 256
+
+VARIABLE(grub_relocator_xen_remap_end)
+
+
+VARIABLE(grub_relocator_xen_start)
+ /* Unmap old remapper area. */
+ /* mov imm32, %eax */
+ .byte 0xb8
+VARIABLE(grub_relocator_xen_remapper_virt2)
+ .long 0
+
+ movl %eax, %ebx
+
+ xorl %ecx, %ecx /* Invalid pte */
+ xorl %edx, %edx
+
+ movl $UVMF_INVLPG, %esi
+ movl $__HYPERVISOR_update_va_mapping, %eax
+ int $0x82
+
+ /* Prepare registers for starting kernel. */
+ /* mov imm32, %eax */
+ .byte 0xb8
+VARIABLE(grub_relocator_xen_stack)
+ .long 0
+
+ movl %eax, %esp
+
+ /* mov imm32, %eax */
+ .byte 0xb8
+VARIABLE(grub_relocator_xen_start_info)
+ .long 0
+
+ movl %eax, %esi
+
+ cld
+
+ /* mov imm32, %eax */
+ .byte 0xb8
+VARIABLE(grub_relocator_xen_entry_point)
+ .long 0
+
+ /* Now start the new kernel. */
+ jmp *%eax
+
+VARIABLE(grub_relocator_xen_end)