--- /dev/null
+Index: grub2/conf/i386-efi.rmk
+===================================================================
+--- grub2.orig/conf/i386-efi.rmk
++++ grub2/conf/i386-efi.rmk
+@@ -85,7 +85,7 @@ grub_install_SOURCES = util/i386/efi/gru
+ pkglib_MODULES = kernel.mod chain.mod appleldr.mod \
+ linux.mod halt.mod reboot.mod pci.mod lspci.mod \
+ datetime.mod date.mod datehook.mod loadbios.mod \
+- fixvideo.mod mmap.mod acpi.mod
++ fixvideo.mod mmap.mod acpi.mod legacy.mod
+
+ # For kernel.mod.
+ kernel_mod_EXPORTS = no
+@@ -183,6 +183,11 @@ date_mod_SOURCES = commands/date.c
+ date_mod_CFLAGS = $(COMMON_CFLAGS)
+ date_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
++# For legacy.mod
++legacy_mod_SOURCES = loader/efi/legacy.c
++legacy_mod_CFLAGS = $(COMMON_CFLAGS)
++legacy_mod_LDFLAGS = $(COMMON_LDFLAGS)
++
+ # For datehook.mod
+ datehook_mod_SOURCES = hook/datehook.c
+ datehook_mod_CFLAGS = $(COMMON_CFLAGS)
+Index: grub2/conf/x86_64-efi.rmk
+===================================================================
+--- grub2.orig/conf/x86_64-efi.rmk
++++ grub2/conf/x86_64-efi.rmk
+@@ -82,7 +82,7 @@ grub_install_SOURCES = util/i386/efi/gru
+ pkglib_MODULES = kernel.mod chain.mod appleldr.mod \
+ halt.mod reboot.mod linux.mod pci.mod lspci.mod \
+ datetime.mod date.mod datehook.mod loadbios.mod \
+- fixvideo.mod mmap.mod acpi.mod
++ fixvideo.mod mmap.mod acpi.mod legacy.mod
+
+ # For kernel.mod.
+ kernel_mod_EXPORTS = no
+@@ -176,6 +176,11 @@ datetime_mod_SOURCES = lib/efi/datetime.
+ datetime_mod_CFLAGS = $(COMMON_CFLAGS)
+ datetime_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
++# For legacy.mod
++legacy_mod_SOURCES = loader/efi/legacy.c
++legacy_mod_CFLAGS = $(COMMON_CFLAGS)
++legacy_mod_LDFLAGS = $(COMMON_LDFLAGS)
++
+ # For date.mod
+ date_mod_SOURCES = commands/date.c
+ date_mod_CFLAGS = $(COMMON_CFLAGS)
+Index: grub2/loader/efi/legacy.c
+===================================================================
+--- /dev/null
++++ grub2/loader/efi/legacy.c
+@@ -0,0 +1,417 @@
++/*
++ * GRUB -- GRand Unified Bootloader
++ * Copyright (C) 2003,2007 Free Software Foundation, Inc.
++ * Copyright (C) 2003 NIIBE Yutaka <gniibe@m17n.org>
++ *
++ * 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/types.h>
++#include <grub/misc.h>
++#include <grub/mm.h>
++#include <grub/err.h>
++#include <grub/dl.h>
++#include <grub/extcmd.h>
++#include <grub/efi/api.h>
++#include <grub/efi/efi.h>
++
++static grub_efi_guid_t loaded_image_guid = GRUB_EFI_LOADED_IMAGE_GUID;
++
++
++#if 0
++#define GRUB_EFI_SET_DEVICE_PATH_END_NODE(a) { \
++ (a)->type = GRUB_EFI_END_DEVICE_PATH_TYPE; \
++ (a)->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; \
++ (a)->length[0] = sizeof(grub_efi_device_path_t); \
++ (a)->length[1] = 0; \
++ }
++static grub_efi_guid_t device_path_guid = GRUB_EFI_DEVICE_PATH_GUID;
++
++
++
++
++grub_efi_uintn_t grub_efi_device_path_size(grub_efi_device_path_t *devpath);
++grub_efi_device_path_t *grub_efi_duplicate_device_path(grub_efi_device_path_t *devpath);
++grub_efi_device_path_t *grub_efi_device_path_instance(grub_efi_device_path_t **device_path, grub_efi_uintn_t *size);
++grub_efi_status_t grub_efi_connect_device_path (grub_efi_device_path_t *device_path_to_connect);
++
++
++grub_efi_uintn_t grub_efi_device_path_size(grub_efi_device_path_t *devpath)
++{
++grub_efi_device_path_t *start;
++
++start=devpath;
++while (!GRUB_EFI_END_ENTIRE_DEVICE_PATH(devpath))
++ devpath=GRUB_EFI_NEXT_DEVICE_PATH(devpath);
++
++return ((grub_efi_uintn_t) devpath -(grub_efi_uintn_t) start)+sizeof(grub_efi_device_path_t);
++}
++
++
++grub_efi_device_path_t *grub_efi_duplicate_device_path(grub_efi_device_path_t *devpath)
++{
++grub_efi_device_path_t *new_device_path;
++grub_efi_uintn_t size;
++
++size=grub_efi_device_path_size(devpath);
++new_device_path=grub_malloc(size);
++if (new_device_path) {
++grub_memcpy(new_device_path,devpath,size);
++}
++
++return new_device_path;
++}
++
++
++grub_efi_device_path_t *grub_efi_device_path_instance(grub_efi_device_path_t **device_path,
++ grub_efi_uintn_t *size)
++{
++ grub_efi_device_path_t *start, *next, *devpath;
++ grub_efi_uintn_t count;
++
++ devpath = *device_path;
++ start = devpath;
++
++ if (!devpath) {
++ return NULL;
++ }
++
++ //
++ // Check for end of device path type
++ //
++
++ for (count = 0; ; count++) {
++ next=GRUB_EFI_NEXT_DEVICE_PATH(devpath);
++
++ if (GRUB_EFI_DEVICE_PATH_TYPE(devpath)==GRUB_EFI_END_DEVICE_PATH_TYPE)
++ break;
++
++ if (count > 01000) {
++ //
++ // BugBug: Debug code to catch bogus device paths
++ //
++ grub_printf("device_pathInstance: device_path %p Size %d", *device_path, (int) (((grub_uint8_t *) devpath) - ((grub_uint8_t *) start) ));
++// DumpHex (0, 0, ((grub_uint8_t *) devpath) - ((grub_uint8_t *) start), start);
++ break;
++ }
++
++ devpath = next;
++ }
++
++ //
++ // Set next position
++ //
++
++ if (GRUB_EFI_DEVICE_PATH_SUBTYPE(devpath) == GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE)
++ next = NULL;
++
++ *device_path = next;
++
++ //
++ // Return size and start of device path instance
++ //
++
++ *size = ((grub_uint8_t *) devpath) - ((grub_uint8_t *) start);
++ return start;
++}
++
++
++
++
++grub_efi_status_t grub_efi_connect_device_path (grub_efi_device_path_t *device_path_to_connect)
++/*++
++
++Routine Description:
++ This function will create all handles associate with every device
++ path node. If the handle associate with one device path node can not
++ be created success, then still give one chance to do the dispatch,
++ which load the missing drivers if possible.
++
++Arguments:
++
++ device_path_to_connect - The device path which will be connected, it can
++ be a multi-instance device path
++
++Returns:
++
++ EFI_SUCCESS - All handles associate with every device path
++ node have been created
++
++ EFI_OUT_OF_RESOURCES - There is no resource to create new handles
++
++ EFI_NOT_FOUND - Create the handle associate with one device
++ path node failed
++
++--*/
++{
++ grub_efi_status_t status;
++ grub_efi_device_path_t *device_path;
++ grub_efi_device_path_t *copy_of_device_path;
++ grub_efi_device_path_t *instance;
++ grub_efi_device_path_t *remaining_device_path;
++ grub_efi_device_path_t *next;
++ grub_efi_handle_t handle;
++ grub_efi_handle_t previous_handle;
++ grub_efi_uintn_t size;
++ grub_efi_boot_services_t *b;
++
++ b = grub_efi_system_table->boot_services;
++
++ if (device_path_to_connect == NULL) {
++ return GRUB_EFI_SUCCESS;
++ }
++
++ device_path = grub_efi_duplicate_device_path (device_path_to_connect);
++ copy_of_device_path = device_path;
++
++ if (device_path == NULL) {
++ return GRUB_EFI_OUT_OF_RESOURCES;
++ }
++
++ do {
++ //
++ // The outer loop handles multi instance device paths.
++ // Only console variables contain multiple instance device paths.
++ //
++ // After this call device_path points to the next instance
++ //
++ instance = grub_efi_device_path_instance (&device_path, &size);
++ next = instance;
++ while (GRUB_EFI_DEVICE_PATH_TYPE(next)!=GRUB_EFI_END_DEVICE_PATH_TYPE) {
++ next=GRUB_EFI_NEXT_DEVICE_PATH(next);
++ }
++
++ GRUB_EFI_SET_DEVICE_PATH_END_NODE(next);
++
++ //
++ // start the real work of connect with remaining_device_path
++ //
++ previous_handle = NULL;
++ do {
++ //
++ // Find the handle that best matches the Device Path. If it is only a
++ // partial match the remaining part of the device path is returned in
++ // remaining_device_path.
++ //
++ remaining_device_path = instance;
++ status = efi_call_3(b->locate_device_path,&device_path_guid, &remaining_device_path, &handle);
++
++ if (status==GRUB_EFI_SUCCESS) {
++ if (handle == previous_handle) {
++ //
++ // If no forward progress is made try invoking the Dispatcher.
++ // A new FV may have been added to the system an new drivers
++ // may now be found.
++ // status == EFI_SUCCESS means a driver was dispatched
++ // status == EFI_NOT_FOUND means no new drivers were dispatched
++ //
++ grub_printf("would have invoked the dispatcher\n");
++ status = GRUB_EFI_NOT_FOUND;
++ }
++
++ if (status==GRUB_EFI_SUCCESS) {
++ previous_handle = handle;
++ //
++ // Connect all drivers that apply to handle and remaining_device_path,
++ // the Recursive flag is FALSE so only one level will be expanded.
++ //
++ // Do not check the connect status here, if the connect controller fail,
++ // then still give the chance to do dispatch, because partial
++ // RemainingDevicepath may be in the new FV
++ //
++ // 1. If the connect fail, RemainingDevicepath and handle will not
++ // change, so next time will do the dispatch, then dispatch's status
++ // will take effect
++ // 2. If the connect success, the RemainingDevicepath and handle will
++ // change, then avoid the dispatch, we have chance to continue the
++ // next connection
++ //
++ efi_call_4(b->connect_controller,handle,NULL, remaining_device_path, 0);
++ }
++ }
++ //
++ // Loop until remaining_device_path is an empty device path
++ //
++ } while ((status==GRUB_EFI_SUCCESS) && !GRUB_EFI_END_ENTIRE_DEVICE_PATH(remaining_device_path));
++
++ } while (device_path != NULL);
++
++ if (copy_of_device_path != NULL) {
++ grub_free(copy_of_device_path);
++ }
++ //
++ // All handle with device_path exists in the handle database
++ //
++ return status;
++}
++#endif
++
++#define NPATHS 6
++
++static grub_uint8_t legacy_devpath[NPATHS][256] = {
++ {0x01, 0x03, 0x18, 0x00, 0x0b, 0x00, 0x00, 0x00,
++ 0x00, 0x00, 0xe0, 0xff, 0x00, 0x00, 0x00, 0x00,
++ 0xff, 0xff, 0xf9, 0xff, 0x00, 0x00, 0x00, 0x00,
++ 0x04, 0x06, 0x14, 0x00, 0xeb, 0x85, 0x05, 0x2b,
++ 0xb8, 0xd8, 0xa9, 0x49, 0x8b, 0x8c, 0xe2, 0x1b,
++ 0x01, 0xae, 0xf2, 0xb7, 0x7f, 0xff, 0x04, 0x00,},
++
++ {0x01, 0x03, 0x18, 0x00, 0x0b, 0x00, 0x00, 0x00,
++ 0x00, 0x00, 0xe0, 0xff, 0x00, 0x00, 0x00, 0x00,
++ 0xff, 0xff, 0xf7, 0xff, 0x00, 0x00, 0x00, 0x00,
++ 0x04, 0x06, 0x14, 0x00, 0xeb, 0x85, 0x05, 0x2b,
++ 0xb8, 0xd8, 0xa9, 0x49, 0x8b, 0x8c, 0xe2, 0x1b,
++ 0x01, 0xae, 0xf2, 0xb7, 0x7f, 0xff, 0x04, 0x00,},
++
++ {0x01, 0x03, 0x18, 0x00, 0x0b, 0x00, 0x00, 0x00,
++ 0x00, 0x00, 0xe0, 0xff, 0x00, 0x00, 0x00, 0x00,
++ 0xff, 0xff, 0xf8, 0xff, 0x00, 0x00, 0x00, 0x00,
++ 0x04, 0x06, 0x14, 0x00, 0xeb, 0x85, 0x05, 0x2b,
++ 0xb8, 0xd8, 0xa9, 0x49, 0x8b, 0x8c, 0xe2, 0x1b,
++ 0x01, 0xae, 0xf2, 0xb7, 0x7f, 0xff, 0x04, 0x00,},
++
++ {0x01, 0x03, 0x18, 0x00, 0x0b, 0x00, 0x00, 0x00,
++ 0x00, 0x00, 0xe0, 0xff, 0x00, 0x00, 0x00, 0x00,
++ 0xff, 0xff, 0xf9, 0xff, 0x00, 0x00, 0x00, 0x00,
++ 0x04, 0x06, 0x14, 0x00, 0xeb, 0x85, 0x05, 0x2b,
++ 0xb8, 0xd8, 0xa9, 0x49, 0x8b, 0x8c, 0xe2, 0x1b,
++ 0x01, 0xae, 0xf2, 0xb7, 0x7f, 0xff, 0x04, 0x00,},
++
++ {0x01, 0x03, 0x18, 0x00, 0x0b, 0x00, 0x00, 0x00,
++ 0x00, 0x00, 0xe0, 0xff, 0x00, 0x00, 0x00, 0x00,
++ 0xff, 0xff, 0xf9, 0xff, 0x00, 0x00, 0x00, 0x00,
++ 0x04, 0x06, 0x14, 0x00, 0xeb, 0x85, 0x05, 0x2b,
++ 0xb8, 0xd8, 0xa9, 0x49, 0x8b, 0x8c, 0xe2, 0x1b,
++ 0x01, 0xae, 0xf2, 0xb7, 0x7f, 0xff, 0x04, 0x00,
++ 0x48, 0x00, 0x44, 0x00, 0x00, 0x00,},
++
++ {
++ 0x01, 0x03, 0x18, 0x00, 0x0b, 0x00, 0x00, 0x00,
++ 0x00, 0x40, 0xcb, 0xff, 0x00, 0x00, 0x00, 0x00,
++ 0xff, 0xbf, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
++ 0x04, 0x06, 0x14, 0x00, 0xeb, 0x85, 0x05, 0x2b,
++ 0xb8, 0xd8, 0xa9, 0x49, 0x8b, 0x8c, 0xe2, 0x1b,
++ 0x01, 0xae, 0xf2, 0xb7, 0x7f, 0xff, 0x04, 0x00,}
++};
++
++
++
++static grub_err_t
++grub_cmd_legacy (struct grub_extcmd *cmd __attribute__ ((unused)),
++ int argc __attribute__ ((unused)),
++ char **args __attribute__ ((unused)))
++{
++ int load_options_length;
++ char *load_options;
++ grub_efi_char16_t load_options16[256];
++ grub_efi_loaded_image_t *loaded_image;
++ grub_efi_boot_services_t *b;
++ grub_efi_status_t status;
++ grub_efi_handle_t image_handle;
++
++ int i;
++
++ load_options = (!argc) ? "HD" : args[0];
++
++ b = grub_efi_system_table->boot_services;
++
++#if 0
++ grub_efi_loaded_image_t *grub_loaded_image;
++
++ status=efi_call_3 (b->handle_protocol, grub_efi_image_handle,&loaded_image_guid,
++ (void **) &grub_loaded_image);
++
++ grub_printf ("get grub_loaded_image %x\n",(unsigned int) status);
++
++ if (status != GRUB_EFI_SUCCESS)
++ return grub_error(GRUB_ERR_BAD_OS,"couldn't find our own loaded image info");
++#endif
++
++
++ {
++ grub_efi_char16_t *ptr16 = load_options16;
++ char *ptr = load_options;
++ load_options_length = 0;
++ while (*ptr)
++ {
++ *(ptr16++) = *(ptr++);
++ load_options_length++;
++ }
++ *ptr16 = 0;
++ }
++
++ for (i = 0; i < NPATHS; ++i)
++ {
++
++#if 0
++ grub_printf ("Looking for legacy boot");
++ grub_efi_print_device_path( (grub_efi_device_path_t *) legacy_devpath[i]);
++#endif
++
++
++ //grub_efi_connect_device_path((grub_efi_device_path_t *) legacy_devpath[i]);
++
++ status =
++ efi_call_6 (b->load_image, 0,grub_efi_image_handle,
++ (grub_efi_device_path_t *) legacy_devpath[i], NULL, 0,
++ &image_handle);
++
++ if (status != GRUB_EFI_SUCCESS)
++ continue;
++
++ grub_printf ("Found legacy boot %d\n", i);
++
++#if 0
++ loaded_image = grub_efi_get_loaded_image (image_handle);
++#else
++ status=efi_call_3 (b->handle_protocol, image_handle,&loaded_image_guid,
++ (void **) &loaded_image);
++
++ grub_printf ("get loaded_image %x\n",(unsigned int) status);
++
++ if (status != GRUB_EFI_SUCCESS)
++ continue;
++#endif
++
++
++ loaded_image->load_options = load_options16;
++ loaded_image->load_options_size = load_options_length;
++
++ loaded_image->load_options = L"CD";
++ loaded_image->load_options_size = 6;
++
++ status = efi_call_3 (b->start_image, image_handle, NULL, NULL);
++
++ grub_printf ("Failed to start legacy boot %d(%x)\n", i,(unsigned int) status);
++
++ }
++
++ grub_printf ("Failed to start a legacy boot\n");
++ return grub_error (GRUB_ERR_BAD_OS, "unknown error");
++}
++
++static grub_extcmd_t cmd;
++
++GRUB_MOD_INIT (legacy)
++{
++ (void) mod; /* To stop warning. */
++ cmd =
++ grub_register_extcmd ("legacy", grub_cmd_legacy, GRUB_COMMAND_FLAG_BOTH,
++ "legacy [source]", "boot in legacy (CSM) mode", 0);
++}
++
++GRUB_MOD_FINI (legacy)
++{
++ grub_unregister_extcmd (cmd);
++}
--- /dev/null
+Index: grub2/conf/i386-efi.rmk
+===================================================================
+diff --git a/conf/i386-efi.rmk b/conf/i386-efi.rmk
+index 5abd720..b5b29e3 100644
+--- a/conf/i386-efi.rmk
++++ b/conf/i386-efi.rmk
+@@ -85,7 +85,7 @@ grub_install_SOURCES = util/i386/efi/grub-install.in
+ pkglib_MODULES = kernel.mod chain.mod appleldr.mod \
+ linux.mod halt.mod reboot.mod pci.mod lspci.mod \
+ datetime.mod date.mod datehook.mod loadbios.mod \
+- fixvideo.mod mmap.mod acpi.mod legacy.mod
++ fixvideo.mod mmap.mod acpi.mod legacy.mod xen.mod
+
+ # For kernel.mod.
+ kernel_mod_EXPORTS = no
+@@ -188,6 +188,11 @@ legacy_mod_SOURCES = loader/efi/legacy.c
+ legacy_mod_CFLAGS = $(COMMON_CFLAGS)
+ legacy_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
++# For xen.mod
++xen_mod_SOURCES = loader/i386/efi/xen.c
++xen_mod_CFLAGS = $(COMMON_CFLAGS)
++xen_mod_LDFLAGS = $(COMMON_LDFLAGS)
++
+ # For datehook.mod
+ datehook_mod_SOURCES = hook/datehook.c
+ datehook_mod_CFLAGS = $(COMMON_CFLAGS)
+diff --git a/conf/x86_64-efi.rmk b/conf/x86_64-efi.rmk
+index 6ffa2e0..8ccd3bf 100644
+--- a/conf/x86_64-efi.rmk
++++ b/conf/x86_64-efi.rmk
+@@ -82,7 +82,7 @@ grub_install_SOURCES = util/i386/efi/grub-install.in
+ pkglib_MODULES = kernel.mod chain.mod appleldr.mod \
+ halt.mod reboot.mod linux.mod pci.mod lspci.mod \
+ datetime.mod date.mod datehook.mod loadbios.mod \
+- fixvideo.mod mmap.mod acpi.mod legacy.mod
++ fixvideo.mod mmap.mod acpi.mod legacy.mod xen.mod
+
+ # For kernel.mod.
+ kernel_mod_EXPORTS = no
+@@ -181,6 +181,11 @@ legacy_mod_SOURCES = loader/efi/legacy.c
+ legacy_mod_CFLAGS = $(COMMON_CFLAGS)
+ legacy_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
++# For xen.mod
++xen_mod_SOURCES = loader/i386/efi/xen.c
++xen_mod_CFLAGS = $(COMMON_CFLAGS)
++xen_mod_LDFLAGS = $(COMMON_LDFLAGS)
++
+ # For date.mod
+ date_mod_SOURCES = commands/date.c
+ date_mod_CFLAGS = $(COMMON_CFLAGS)
+diff --git a/loader/i386/efi/xen.c b/loader/i386/efi/xen.c
+new file mode 100644
+index 0000000..baed2e1
+--- /dev/null
++++ b/loader/i386/efi/xen.c
+@@ -0,0 +1,1143 @@
++/*
++ * GRUB -- GRand Unified Bootloader
++ * Copyright (C) 2006,2007,2008,2009 Free Software Foundation, Inc.
++ *
++ * GRUB is free software: you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation, either version 3 of the License, or
++ * (at your option) any later version.
++ *
++ * GRUB is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <grub/loader.h>
++#include <grub/multiboot2.h>
++#include <multiboot2.h>
++#include <grub/machine/loader.h>
++#include <grub/file.h>
++#include <grub/gzio.h>
++#include <grub/disk.h>
++#include <grub/err.h>
++#include <grub/misc.h>
++#include <grub/types.h>
++#include <grub/normal.h>
++#include <grub/time.h>
++#include <grub/dl.h>
++#include <grub/elfload.h>
++#include <grub/mm.h>
++#include <grub/term.h>
++#include <grub/cpu/linux.h>
++#include <grub/efi/api.h>
++#include <grub/efi/efi.h>
++#include <grub/efi/uga_draw.h>
++#include <grub/net.h>
++#include <grub/pci.h>
++#include <grub/command.h>
++#include <grub/memory.h>
++
++
++static grub_dl_t my_mod;
++static int loaded;
++static grub_addr_t entry;
++
++#define XEN_EFI_MAGIC 0xdeadbeefef104eadULL
++#define XEN_LOADER_GRUB_64 0x0034365f36387847ULL
++#define XEN_LOADER_GRUB_32 0x0000003233616947ULL
++
++struct xen_efi_hdr
++{
++ grub_uint64_t magic;
++ grub_uint64_t efi_loader_signature;
++ grub_uint64_t efi_system_table_addr;
++ grub_uint64_t realmode_available;
++ grub_uint64_t boot_vid_mode;
++ grub_uint64_t boot_vid_info;
++} __attribute__((packed));
++
++struct xen_boot_video_info {
++ grub_uint8_t orig_x; /* 0x00 */
++ grub_uint8_t orig_y; /* 0x01 */
++ grub_uint8_t orig_video_mode; /* 0x02 */
++ grub_uint8_t orig_video_cols; /* 0x03 */
++ grub_uint8_t orig_video_lines; /* 0x04 */
++ grub_uint8_t orig_video_isVGA; /* 0x05 */
++ grub_uint16_t orig_video_points; /* 0x06 */
++
++ /* VESA graphic mode -- linear frame buffer */
++ grub_uint32_t capabilities; /* 0x08 */
++ grub_uint16_t lfb_linelength; /* 0x0c */
++ grub_uint16_t lfb_width; /* 0x0e */
++ grub_uint16_t lfb_height; /* 0x10 */
++ grub_uint16_t lfb_depth; /* 0x12 */
++ grub_uint32_t lfb_base; /* 0x14 */
++ grub_uint32_t lfb_size; /* 0x18 */
++ grub_uint8_t red_size; /* 0x1c */
++ grub_uint8_t red_pos; /* 0x1d */
++ grub_uint8_t green_size; /* 0x1e */
++ grub_uint8_t green_pos; /* 0x1f */
++ grub_uint8_t blue_size; /* 0x20 */
++ grub_uint8_t blue_pos; /* 0x21 */
++ grub_uint8_t rsvd_size; /* 0x22 */
++ grub_uint8_t rsvd_pos; /* 0x23 */
++ grub_uint16_t vesapm_seg; /* 0x24 */
++ grub_uint16_t vesapm_off; /* 0x26 */
++ grub_uint16_t vesa_attrib; /* 0x28 */
++} __attribute__((packed));
++
++
++struct xen_mbi
++{
++ grub_uint32_t flags;
++ grub_uint32_t mem_lower;
++ grub_uint32_t mem_upper;
++ grub_uint32_t boot_device;
++ grub_uint32_t cmdline;
++ grub_uint32_t mods_count;
++ grub_uint32_t mods_addr;
++ grub_uint32_t syms[4];
++ grub_uint32_t mmap_length;
++ grub_uint32_t mmap_addr;
++ grub_uint8_t pad[100];
++};
++
++
++
++struct xen_module_rec
++{
++ grub_uint32_t start;
++ grub_uint32_t end;
++ grub_uint32_t string;
++ grub_uint32_t reserved;
++};
++
++struct xen_mm_rec
++{
++ grub_uint32_t size;
++ grub_uint32_t base_addr_low;
++ grub_uint32_t base_addr_high;
++ grub_uint32_t length_low;
++ grub_uint32_t length_high;
++ grub_uint32_t type;
++} __attribute__ ((packed));
++
++
++#define MAX_MODULES 32
++#define DUMMY_MAP_SIZE 128
++
++struct xen_play_pen
++{
++ struct xen_mbi mbi;
++ char cmdline[1024];
++ struct xen_module_rec modules[MAX_MODULES];
++ char module_strings[MAX_MODULES][1024];
++} *play_pen = NULL;
++
++int module_no = 0;
++
++
++
++static grub_uint8_t gdt[] __attribute__ ((aligned (16))) =
++{
++ /* NULL. */
++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++ /* Reserved. */
++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++ /* Code segment. */
++ 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x9A, 0xCF, 0x00,
++ /* Data segment. */
++0xFF, 0xFF, 0x00, 0x00, 0x00, 0x92, 0xCF, 0x00};
++
++struct gdt_descriptor
++{
++ grub_uint16_t limit;
++ void *base;
++} __attribute__ ((packed));
++
++static struct gdt_descriptor gdt_desc = {
++ sizeof (gdt) - 1,
++ gdt
++};
++
++struct idt_descriptor
++{
++ grub_uint16_t limit;
++ void *base;
++} __attribute__ ((packed));
++
++static struct idt_descriptor idt_desc = {
++ 0,
++ 0
++};
++
++
++
++static struct xen_mem_tab
++{
++ struct xen_mem_tab *next;
++ grub_efi_physical_address_t addr;
++ int pages;
++} *mem_tab = NULL;
++
++
++#define PAGE_SHIFT 12 /*4kb Pages */
++#define PAGE_SIZE (1<< PAGE_SHIFT)
++
++#define ONE_MB 0x100000
++
++static grub_efi_physical_address_t
++calculate_hwm (void)
++{
++ struct xen_mem_tab *ptr;
++
++ grub_efi_physical_address_t hwm = ONE_MB, end;
++
++ for (ptr = mem_tab; ptr; ptr = ptr->next)
++ {
++ end = ptr->addr + (ptr->pages << PAGE_SHIFT);
++ if (end > hwm)
++ hwm = end;
++ }
++
++ return hwm;
++}
++
++static int
++size_to_pages (int size)
++{
++ return (size + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
++}
++
++static void *
++give_me_some_low_pages (grub_efi_physical_address_t phys, int pages)
++{
++ (void) phys;
++ (void) pages;
++ return NULL;
++}
++
++static void *
++give_me_some_pages (grub_efi_physical_address_t phys, int pages)
++{
++ struct xen_mem_tab *te;
++
++ te = grub_malloc (sizeof (struct xen_mem_tab));
++
++ if (phys && (phys < ONE_MB))
++ return give_me_some_low_pages (phys, pages);
++
++ if (!phys)
++ phys = calculate_hwm ();
++
++
++ te->addr =
++ (grub_efi_physical_address_t) grub_efi_allocate_pages (phys, pages);
++ te->pages = pages;
++
++ if (!te->addr)
++ {
++ grub_free (te);
++ return NULL;
++ }
++
++ te->next = mem_tab;
++ mem_tab = te;
++
++ return (void *) te->addr;
++}
++
++static void
++mop_up_my_allocations (void)
++{
++ struct xen_mem_tab *te;
++
++ while ((te = mem_tab))
++ {
++ mem_tab = te->next;
++ grub_efi_free_pages (te->addr, te->pages);
++ grub_free (te);
++ }
++
++}
++
++static grub_efi_guid_t uga_draw_guid = GRUB_EFI_UGA_DRAW_GUID;
++
++
++#define RGB_MASK 0xffffff
++#define RGB_MAGIC 0x121314
++#define LINE_MIN 800
++#define LINE_MAX 4096
++#define FBTEST_STEP (0x10000 >> 2)
++#define FBTEST_COUNT 8
++
++static int
++find_line_len (grub_uint32_t *fb_base, grub_uint32_t *line_len)
++{
++ grub_uint32_t *base = (grub_uint32_t *) (grub_target_addr_t) *fb_base;
++ int i;
++
++ for (i = 0; i < FBTEST_COUNT; i++, base += FBTEST_STEP)
++ {
++ grub_printf("Checking %p %x %x\n",base,*base,RGB_MAGIC);
++ grub_printf("fish %p %x %x\n",base,(*base & RGB_MASK),RGB_MAGIC);
++
++ if ((*base & RGB_MASK) == RGB_MAGIC)
++ {
++ int j;
++
++ for (j = LINE_MIN; j <= LINE_MAX; j++)
++ {
++ if ((base[j] & RGB_MASK) == RGB_MAGIC)
++ {
++ grub_printf("%p[%d]=%x\n",base,j,base[j]);
++
++ *fb_base = (grub_uint32_t) (grub_target_addr_t) base;
++ *line_len = j << 2;
++
++ return 1;
++ }
++ }
++
++ break;
++ }
++ }
++
++ return 0;
++}
++
++static int
++find_framebuf (grub_uint32_t *fb_base, grub_uint32_t *line_len)
++{
++ int found = 0;
++
++ auto int NESTED_FUNC_ATTR find_card (int bus, int dev, int func,
++ grub_pci_id_t pciid);
++
++ int NESTED_FUNC_ATTR find_card (int bus, int dev, int func,
++ grub_pci_id_t pciid)
++ {
++ grub_pci_address_t addr;
++
++ addr = grub_pci_make_address (bus, dev, func, 2);
++ if (grub_pci_read (addr) >> 24 == 0x3)
++ {
++ int i;
++
++ grub_printf ("Display controller: %d:%d.%d\nDevice id: %x\n",
++ bus, dev, func, pciid);
++ addr += 8;
++ for (i = 0; i < 6; i++, addr += 4)
++ {
++ grub_uint32_t old_bar1, old_bar2, type;
++ grub_uint64_t base64;
++
++ old_bar1 = grub_pci_read (addr);
++ if ((! old_bar1) || (old_bar1 & GRUB_PCI_ADDR_SPACE_IO))
++ continue;
++
++ type = old_bar1 & GRUB_PCI_ADDR_MEM_TYPE_MASK;
++ if (type == GRUB_PCI_ADDR_MEM_TYPE_64)
++ {
++ if (i == 5)
++ break;
++
++ old_bar2 = grub_pci_read (addr + 4);
++ }
++ else
++ old_bar2 = 0;
++
++ base64 = old_bar2;
++ base64 <<= 32;
++ base64 |= (old_bar1 & GRUB_PCI_ADDR_MEM_MASK);
++
++ grub_printf ("%s(%d): 0x%llx\n",
++ ((old_bar1 & GRUB_PCI_ADDR_MEM_PREFETCH) ?
++ "VMEM" : "MMIO"), i,
++ (unsigned long long) base64);
++
++ if ((old_bar1 & GRUB_PCI_ADDR_MEM_PREFETCH) && (! found))
++ {
++ *fb_base = base64;
++ if (find_line_len (fb_base, line_len)) {
++ grub_printf("Found %x %d\n",*fb_base,*line_len);
++ found++;
++ }
++ }
++
++ if (type == GRUB_PCI_ADDR_MEM_TYPE_64)
++ {
++ i++;
++ addr += 4;
++ }
++ }
++ }
++
++ return found;
++ }
++
++ grub_pci_iterate (find_card);
++ return found;
++}
++static int
++xen_setup_video (struct xen_boot_video_info *bvi)
++{
++ grub_efi_uga_draw_protocol_t *c;
++ grub_uint32_t width, height, depth, rate, pixel, fb_base, line_len;
++ int ret;
++
++ c = grub_efi_locate_protocol (&uga_draw_guid, 0);
++ if (!c)
++ return 1;
++
++#if 0
++ if (efi_call_5 (c->get_mode, c, &width, &height, &depth, &rate))
++ return 1;
++#else
++ if (efi_call_5 (c->get_mode, c, &width, &height, &depth, &rate)) {
++ width=1280;
++ height=800;
++ depth=32;
++ rate=60;
++ }
++#endif
++
++
++ grub_printf ("Video mode: %ux%u-%u@%u\n", width, height, depth, rate);
++
++ grub_efi_set_text_mode (0);
++ pixel = RGB_MAGIC;
++ efi_call_10 (c->blt, c, (struct grub_efi_uga_pixel *) &pixel,
++ GRUB_EFI_UGA_VIDEO_FILL, 0, 0, 0, 0, 1, height, 0);
++ ret = find_framebuf (&fb_base, &line_len);
++ grub_efi_set_text_mode (1);
++
++
++ if (!ret)
++ {
++ grub_printf ("Can\'t find frame buffer address\n");
++ return 1;
++ }
++
++ grub_printf ("Video frame buffer: 0x%x\n", fb_base);
++ grub_printf ("Video line length: %d\n", line_len);
++
++ bvi->orig_video_isVGA=0x23; /*XXX: what is 0x23? */
++
++ bvi->lfb_linelength=line_len;
++ bvi->lfb_width=width;
++ bvi->lfb_height=height;
++ bvi->lfb_depth=32;
++ bvi->lfb_base=(grub_uint32_t) fb_base;
++
++ bvi->red_size=8;
++ bvi->red_pos=16;
++
++ bvi->green_size=8;
++ bvi->green_pos=8;
++
++ bvi->blue_size=8;
++ bvi->blue_pos=0;
++
++ bvi->rsvd_size=8;
++ bvi->rsvd_pos=24;
++
++ bvi->vesa_attrib=0x3; /*Possible(0x1) and has extended data(0x2)*/
++
++ /*Size of video ram in 64k blocks*/
++ {
++ int i=line_len*height;
++ i+=65535;
++
++ bvi->lfb_size= i >> 16;
++ }
++
++ /* No protected mode*/
++ bvi->vesapm_seg=0x0;
++ bvi->vesapm_off=0x0;
++
++ bvi->vesa_attrib=0x1; /*Dac is 8 bit capable*/
++
++
++ return 0;
++}
++
++
++static grub_err_t
++xen_setup (grub_uint8_t * base)
++{
++ struct xen_efi_hdr *hdr;
++ grub_uint8_t *realmode_available;
++ grub_uint16_t *boot_vid_mode;
++ grub_uint64_t *efi_system_table_addr;
++ grub_uint64_t *efi_loader_signature;
++ struct xen_boot_video_info *bvi;
++
++ int i;
++
++ for (i = 0; i <0x200; i++)
++ {
++ hdr = (struct xen_efi_hdr *) (base + i);
++ if (hdr->magic == XEN_EFI_MAGIC)
++ break;
++ }
++
++ if (hdr->magic != XEN_EFI_MAGIC)
++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "No EFI support in hypervisor");
++
++ grub_printf("base addr is %p\n",base);
++
++ realmode_available=(grub_uint8_t *)hdr->realmode_available;
++ grub_printf("realmode_available was %x@%p\n",(int) *realmode_available,realmode_available);
++ *realmode_available=0;
++
++ efi_loader_signature=(grub_uint64_t*)hdr->efi_loader_signature;
++
++#if defined(__x86_64__)
++ *efi_loader_signature=XEN_LOADER_GRUB_64;
++#elif defined (__i386__)
++ *efi_loader_signature=XEN_LOADER_GRUB_32;
++#else
++ *efi_loader_signature=0;
++#endif
++
++ efi_system_table_addr=(grub_uint64_t*)hdr->efi_system_table_addr;
++
++ grub_printf("efi_system_table_addr was %llx@%p\n",(long long unsigned) *efi_system_table_addr, efi_system_table_addr);
++
++ {
++ char buf[1024];
++ grub_sprintf(buf,"Wrote %llx into efi_system_table (was %llx@%p)\n",
++ (long long unsigned) grub_efi_system_table,
++ (long long unsigned) *efi_system_table_addr, efi_system_table_addr);
++ grub_net_syslog (buf);
++ }
++
++ *efi_system_table_addr= (grub_uint64_t) grub_efi_system_table;
++
++ boot_vid_mode=(grub_uint16_t *)hdr->boot_vid_mode;
++ grub_printf("boot_vid_mode was 0x%x@%p\n",(int) *boot_vid_mode,boot_vid_mode);
++ *boot_vid_mode=0xf00;
++
++ bvi=(struct xen_boot_video_info *)hdr->boot_vid_info;
++ grub_printf("boot_vid_info @%p\n",bvi);
++
++ xen_setup_video (bvi);
++
++ return GRUB_ERR_NONE;
++}
++
++
++
++static grub_err_t
++elf32_hook (Elf32_Phdr * phdr, UNUSED grub_addr_t * addr)
++{
++ int pages = size_to_pages (phdr->p_memsz);
++
++ if (!give_me_some_pages (phdr->p_paddr, pages))
++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, "Couldn't claim 0x%lx - 0x%lx",
++ (long unsigned int) phdr->p_paddr,
++ (long unsigned int) (phdr->p_paddr + phdr->p_memsz));
++
++
++ grub_printf ("Claimed 0x%lx - 0x%lx\n", (long unsigned int) phdr->p_paddr,
++ (long unsigned int) (phdr->p_paddr + phdr->p_memsz));
++
++
++ return GRUB_ERR_NONE;
++}
++
++
++static void
++add_region (struct xen_mm_rec *map, int *nrecs, grub_uint64_t start,
++ grub_uint64_t len, grub_uint32_t type)
++{
++ int n = *nrecs;
++
++ if (!len)
++ return;
++
++ if (!map)
++ {
++ (*nrecs)++;
++ return;
++ }
++
++ if (n > 1)
++ {
++ grub_uint64_t last_end, last_len;
++
++ last_end = map[n - 1].base_addr_high;
++ last_end <<= 32;
++ last_end |= map[n - 1].base_addr_low;
++
++ last_len = map[n - 1].length_high;
++ last_len <<= 32;
++ last_len |= map[n - 1].length_low;
++
++ last_end += last_len;
++
++ if ((last_end == start) && (map[n - 1].type == type))
++ {
++ last_len += len;
++
++ map[n - 1].length_low = last_len & 0xffffffff;
++ map[n - 1].length_high = last_len >> 32;
++
++ return;
++ }
++ }
++
++ map[n].size = sizeof (struct xen_mm_rec) - sizeof (uint32_t);
++
++ map[n].base_addr_low = start & 0xffffffff;
++ map[n].base_addr_high = start >> 32;
++
++ map[n].length_low = len & 0xffffffff;
++ map[n].length_high = len >> 32;
++
++ map[n].type = type;
++
++ (*nrecs)++;
++
++}
++
++#define NEXT_MEMORY_DESCRIPTOR(desc, size) \
++ ((grub_efi_memory_descriptor_t *) ((char *) (desc) + (size)))
++
++
++
++static int
++make_mm (struct xen_mm_rec *map, grub_efi_memory_descriptor_t * tab,
++ int desc_size, int tab_size)
++{
++ grub_efi_memory_descriptor_t *desc;
++ int n = 0;
++
++ for (desc = tab;
++ desc < NEXT_MEMORY_DESCRIPTOR (tab, tab_size);
++ desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size))
++ {
++ switch (desc->type)
++ {
++ case GRUB_EFI_ACPI_RECLAIM_MEMORY:
++ add_region (map, &n, desc->physical_start, desc->num_pages << 12,
++ GRUB_E820_ACPI);
++ break;
++
++ case GRUB_EFI_ACPI_MEMORY_NVS:
++ add_region (map, &n,
++ desc->physical_start,
++ desc->num_pages << 12, GRUB_E820_NVS);
++ break;
++
++ case GRUB_EFI_RUNTIME_SERVICES_CODE:
++ add_region (map, &n,
++ desc->physical_start,
++ desc->num_pages << 12, GRUB_E820_EXEC_CODE);
++ break;
++
++ case GRUB_EFI_LOADER_CODE:
++ case GRUB_EFI_LOADER_DATA:
++ case GRUB_EFI_BOOT_SERVICES_CODE:
++ case GRUB_EFI_BOOT_SERVICES_DATA:
++ case GRUB_EFI_CONVENTIONAL_MEMORY:
++ {
++ grub_uint64_t start, size, end;
++
++ start = desc->physical_start;
++ size = desc->num_pages << 12;
++ end = start + size;
++
++ /* Skip A0000 - 100000 region. */
++ if ((start < 0x100000ULL) && (end > 0xA0000ULL))
++ {
++ if (start < 0xA0000ULL)
++ {
++ add_region (map, &n,
++ start, 0xA0000ULL - start, GRUB_E820_RAM);
++ }
++
++ if (end <= 0x100000ULL)
++ continue;
++
++ start = 0x100000ULL;
++ size = end - start;
++ }
++
++ {
++ grub_uint64_t efifb_start = 0xC0010000ULL;
++ grub_uint64_t efifb_end = 0xC0700000ULL;
++
++ /* Skip fb region */
++ if ((start < efifb_end) && (end > efifb_start))
++ {
++ if (start < efifb_start)
++ {
++ add_region (map, &n,
++ start, efifb_start - start, GRUB_E820_RAM);
++ }
++
++ if (end <= efifb_end)
++ continue;
++
++ start = efifb_end;
++ size = end - start;
++ }
++ }
++
++
++ add_region (map, &n, start, size, GRUB_E820_RAM);
++ break;
++ }
++
++ default:
++ add_region (map, &n,
++ desc->physical_start,
++ desc->num_pages << 12, GRUB_E820_RESERVED);
++ }
++ }
++
++ return n;
++}
++
++static grub_efi_guid_t acpi_guid = GRUB_EFI_ACPI_TABLE_GUID;
++static grub_efi_guid_t acpi2_guid = GRUB_EFI_ACPI_20_TABLE_GUID;
++static grub_efi_guid_t smbios_guid = GRUB_EFI_SMBIOS_TABLE_GUID;
++
++#define EBDA_SEG_ADDR 0x40e
++#define LOW_MEM_ADDR 0x413
++#if 0
++#define FAKE_EBDA_SEG 0x9fc0
++#else
++#define FAKE_EBDA_SEG 0x9400
++#define FAKE_SMBIOS_SEG 0x9800
++#endif
++
++static void
++fake_more_bios_data(void)
++{
++ unsigned i;
++ void *smbios;
++
++ smbios = 0;
++ for (i = 0; i < grub_efi_system_table->num_table_entries; i++)
++ {
++ grub_efi_guid_t *guid =
++ &grub_efi_system_table->configuration_table[i].vendor_guid;
++
++ if (!grub_memcmp (guid, &smbios_guid, sizeof (grub_efi_guid_t)))
++ {
++ smbios = grub_efi_system_table->configuration_table[i].vendor_table;
++ grub_printf ("SMBIOS: %p\n", smbios);
++ }
++ }
++
++ if (smbios == 0)
++ return;
++
++ grub_memcpy ((char *) (FAKE_SMBIOS_SEG << 4), smbios, 0x20);
++}
++
++
++
++
++
++
++
++
++static void
++fake_bios_data (void)
++{
++ unsigned i;
++ void *acpi;
++ grub_uint16_t *ebda_seg_ptr, *low_mem_ptr;
++
++ acpi = 0;
++ for (i = 0; i < grub_efi_system_table->num_table_entries; i++)
++ {
++ grub_efi_guid_t *guid =
++ &grub_efi_system_table->configuration_table[i].vendor_guid;
++
++ if (!grub_memcmp (guid, &acpi2_guid, sizeof (grub_efi_guid_t)))
++ {
++ acpi = grub_efi_system_table->configuration_table[i].vendor_table;
++ grub_printf ("ACPI2: %p\n", acpi);
++ }
++ else if (!grub_memcmp (guid, &acpi_guid, sizeof (grub_efi_guid_t)))
++ {
++ void *t;
++
++ t = grub_efi_system_table->configuration_table[i].vendor_table;
++ if (!acpi)
++ acpi = t;
++ grub_printf ("ACPI: %p\n", t);
++ }
++ }
++
++ if (acpi == 0)
++ return;
++
++ ebda_seg_ptr = (grub_uint16_t *) EBDA_SEG_ADDR;
++ low_mem_ptr = (grub_uint16_t *) LOW_MEM_ADDR;
++
++ if ((*ebda_seg_ptr) || (*low_mem_ptr))
++ return;
++
++ *ebda_seg_ptr = FAKE_EBDA_SEG;
++ *low_mem_ptr = FAKE_EBDA_SEG >> 6;
++
++ grub_memcpy ((char *) (FAKE_EBDA_SEG << 4), acpi, 1024);
++}
++
++
++#ifdef __x86_64__
++struct
++{
++ grub_uint32_t xen_entry;
++ grub_uint32_t xen_cs;
++} jumpvector;
++#endif
++
++
++
++static grub_err_t
++grub_xen_boot (void)
++{
++ grub_efi_uintn_t map_key;
++ grub_efi_uintn_t mmap_size;
++ grub_efi_uintn_t desc_size;
++ grub_efi_uint32_t desc_version;
++ struct xen_mm_rec *xen_mm;
++ //grub_efi_memory_descriptor_t *desc;
++ void *mmap_buf;
++
++ int pages = 32;
++ int xen_pages = 32;
++ int xen_mm_size;
++ int len;
++
++
++ grub_printf ("entry = %x, idt_desc = %lx, gdt_desc = %lx\n",
++ (unsigned) entry,
++ (unsigned long) &(idt_desc.limit),
++ (unsigned long) &(gdt_desc.limit));
++ grub_printf ("idt = %x:%lx, gdt = %x:%lx\n",
++ (unsigned) idt_desc.limit, (unsigned long) idt_desc.base,
++ (unsigned) gdt_desc.limit, (unsigned long) gdt_desc.base);
++
++ fake_bios_data ();
++ fake_more_bios_data();
++
++ mmap_buf = give_me_some_pages (0, pages);
++ mmap_size = pages << PAGE_SHIFT;
++
++ xen_mm = give_me_some_pages (0, xen_pages);
++ xen_mm_size = xen_pages << PAGE_SHIFT;
++
++ if (grub_efi_get_memory_map (&mmap_size, mmap_buf, &map_key,
++ &desc_size, &desc_version) <= 0)
++ grub_fatal ("cannot get memory map");
++
++
++ len = make_mm (NULL, mmap_buf, desc_size, mmap_size);
++ len *= sizeof (struct xen_mm_rec);
++
++ if (len > xen_mm_size)
++ grub_fatal ("out of memory for e820ish map");
++
++ len = make_mm (xen_mm, mmap_buf, desc_size, mmap_size);
++ len *= sizeof (struct xen_mm_rec);
++
++ play_pen->mbi.flags |= 1 << 6;
++ play_pen->mbi.mmap_length = len;
++ play_pen->mbi.mmap_addr = (uint32_t) (grub_efi_physical_address_t) xen_mm;
++
++ if (!grub_efi_exit_boot_services (map_key))
++ grub_fatal ("cannot exit boot services");
++
++ /* Hardware interrupts are not safe any longer. */
++ asm volatile ("cli"::);
++
++ /* Load the IDT and the GDT for the bootstrap. */
++ asm volatile ("lidt %0"::"m" (idt_desc));
++ asm volatile ("lgdt %0"::"m" (gdt_desc));
++
++#ifdef __x86_64__
++
++ grub_uint64_t grub_magic = 0x2badb002;
++ grub_uint64_t mbi_ptr = (grub_uint64_t) & play_pen->mbi.flags;
++
++
++ jumpvector.xen_entry = (grub_uint64_t) entry;
++ jumpvector.xen_cs = 0x10;
++
++
++ asm volatile ("mov %0, %%rax\n"
++ "mov %1, %%rbx\n"
++ "ljmp *%2"::"m" (grub_magic), "m" (mbi_ptr),
++ "m" (jumpvector));
++
++#else
++ grub_uint32_t grub_magic = 0x2badb002;
++
++
++ /* Hardware interrupts are not safe any longer. */
++ asm volatile ("cli" : : );
++
++ /* Pass parameters. */
++ asm volatile ("movl %0, %%ecx"::"m" (entry));
++ asm volatile ("movl %0, %%eax"::"m" (grub_magic));
++ asm volatile ("movl %0, %%ebx"::"m" (play_pen->mbi.flags));
++
++ /* Enter Linux. */
++ asm volatile ("jmp *%%ecx"::);
++#endif
++
++ /* Never reach here. */
++ return GRUB_ERR_NONE;
++}
++
++
++static grub_err_t
++grub_xen_unload (void)
++{
++ mop_up_my_allocations ();
++ grub_dl_unref (my_mod);
++ loaded = 0;
++ return GRUB_ERR_NONE;
++}
++
++static grub_err_t
++grub_xenmod_command (grub_command_t cmd __attribute__ ((unused)),
++ int argc, char *argv[])
++{
++ char *module;
++ grub_ssize_t size;
++ grub_errno = GRUB_ERR_NONE;
++ grub_file_t file = 0;
++ int i;
++
++ if (argc == 0)
++ {
++ grub_error (GRUB_ERR_BAD_ARGUMENT, "no file specified");
++ goto fail;
++ }
++
++ if (!loaded)
++ {
++ grub_error (GRUB_ERR_BAD_ARGUMENT, "no hypervisor loaded");
++ goto fail;
++ }
++
++ file = grub_gzfile_open (argv[0], 1);
++ if (!file)
++ {
++ grub_error (GRUB_ERR_BAD_ARGUMENT, "couldn't open file");
++ goto fail;
++ }
++
++ size = grub_file_size (file);
++
++
++ module = give_me_some_pages (0, size_to_pages (size));
++
++ if (!module)
++ goto fail;
++
++
++ if (grub_file_read (file, module, size) != size)
++ {
++ grub_error (GRUB_ERR_FILE_READ_ERROR, "Couldn't read file");
++ goto fail;
++ }
++ grub_printf ("module loaded at 0x%lx.\n", (unsigned long) module);
++
++ play_pen->modules[module_no].start =
++ (grub_uint32_t) (grub_efi_physical_address_t) module;
++ play_pen->modules[module_no].end =
++ (grub_uint32_t) (grub_efi_physical_address_t) (module + size);
++
++#if 0
++ if (argc > 1)
++ {
++#endif
++ play_pen->modules[module_no].string =
++ (grub_uint32_t) (grub_efi_physical_address_t) & play_pen->
++ module_strings[module_no];
++
++ for (i = 0; i < argc; ++i)
++ {
++ if (i)
++ grub_strcat (play_pen->module_strings[module_no], " ");
++ grub_strcat (play_pen->module_strings[module_no], argv[i]);
++ }
++#if 0
++ }
++#endif
++
++
++ module_no++;
++ play_pen->mbi.flags |= 1 << 3;
++ play_pen->mbi.mods_count = module_no;
++ play_pen->mbi.mods_addr =
++ (grub_uint32_t) (grub_efi_physical_address_t) & play_pen->modules[0];
++
++fail:
++ if (file)
++ grub_file_close (file);
++
++ return grub_errno;
++}
++
++static grub_err_t
++grub_xen_command (grub_command_t cmd __attribute__ ((unused)),
++ int argc, char *argv[])
++{
++ grub_file_t file = 0;
++ grub_elf_t elf = 0;
++ grub_err_t err = 0;
++ int i;
++
++
++ grub_addr_t kern_base;
++ grub_size_t kern_size;
++
++ grub_errno = GRUB_ERR_NONE;
++
++ mop_up_my_allocations ();
++
++ module_no = 0;
++
++ grub_dl_ref (my_mod);
++
++ if (argc == 0)
++ {
++ grub_error (GRUB_ERR_BAD_ARGUMENT, "no file specified");
++ goto fail;
++ }
++
++ file = grub_gzfile_open (argv[0], 1);
++ if (!file)
++ {
++ grub_error (GRUB_ERR_BAD_ARGUMENT, "couldn't open file");
++ goto fail;
++ }
++
++ elf = grub_elf_file (file);
++ if (!elf)
++ {
++ grub_error (GRUB_ERR_BAD_ARGUMENT, "couldn't parse elf headers");
++ goto fail;
++
++ }
++
++ if (!grub_elf_is_elf32 (elf))
++ {
++ grub_error (GRUB_ERR_BAD_ARGUMENT, "expecting 32 bit elf");
++ goto fail;
++ }
++
++
++ entry = elf->ehdr.ehdr32.e_entry;
++ err = grub_elf32_load (elf, elf32_hook, &kern_base, &kern_size);
++
++
++
++ if (err)
++ {
++ grub_error (GRUB_ERR_BAD_ARGUMENT, "didn't parse the elf");
++ goto fail;
++ }
++
++ grub_printf ("Entry point is 0x%lx. (%lx %lx)\n", (unsigned long) entry,
++ (unsigned long) kern_base, (unsigned long) kern_size);
++
++ play_pen =
++ give_me_some_pages (0, size_to_pages (sizeof (struct xen_play_pen)));
++
++ if (!play_pen)
++ {
++ grub_error (GRUB_ERR_BAD_ARGUMENT, "failed to allocate play_pen");
++ goto fail;
++
++ }
++ grub_memset (play_pen, 0, sizeof (play_pen));
++
++ grub_printf ("Play pen is at 0x%lx.\n", (unsigned long) play_pen);
++ {
++ char buf[1024];
++ grub_sprintf (buf, "Play pen is at 0x%lx.\n", (unsigned long) play_pen);
++ grub_net_syslog (buf);
++ grub_sprintf (buf, "mbi is at 0x%lx.\n",
++ (unsigned long) (&play_pen->mbi.flags));
++ grub_net_syslog (buf);
++ }
++
++
++
++ if (argc > 1)
++ {
++ play_pen->mbi.flags |= 1 << 2;
++
++ play_pen->mbi.cmdline =
++ (grub_uint32_t) (grub_efi_physical_address_t) & play_pen->cmdline[0];
++
++ for (i = 0; i < argc; ++i)
++ {
++ if (i)
++ grub_strcat (play_pen->cmdline, " ");
++ grub_strcat (play_pen->cmdline, argv[i]);
++ }
++ }
++
++
++ if (xen_setup ((void *) (grub_efi_physical_address_t) kern_base))
++ {
++ grub_printf ("xen_setup fialed\n");
++ goto fail;
++ }
++
++
++
++ grub_loader_set (grub_xen_boot, grub_xen_unload, 1);
++ loaded = 1;
++
++fail:
++
++ if (file)
++ grub_file_close (file);
++
++ if (grub_errno != GRUB_ERR_NONE)
++ {
++ mop_up_my_allocations ();
++ grub_dl_unref (my_mod);
++ loaded = 0;
++ }
++ return grub_errno;
++}
++
++static grub_command_t xen_cmd, xenmod_cmd;
++
++GRUB_MOD_INIT (xen)
++{
++ (void) mod; /* To stop warning. */
++ xen_cmd =
++ grub_register_command ("xen", grub_xen_command, 0,
++ "Load a xen hypervisor.");
++ xenmod_cmd =
++ grub_register_command ("xenmod", grub_xenmod_command, 0,
++ "Load a xen module.");
++
++ my_mod = mod;
++}
++
++GRUB_MOD_FINI (xen)
++{
++ grub_unregister_command (xenmod_cmd);
++ grub_unregister_command (xen_cmd);
++}