]> xenbits.xensource.com Git - people/jamesmck/efi-grub2-r2364-pq.git/commitdiff
From XC trunk Apr 13 2011 master
authorJames McKenzie james.mckenzie@citrix.com <jamesmck@taoand.cam.xci-test.com>
Wed, 13 Apr 2011 09:58:27 +0000 (10:58 +0100)
committerJames McKenzie james.mckenzie@citrix.com <jamesmck@taoand.cam.xci-test.com>
Wed, 13 Apr 2011 09:58:27 +0000 (10:58 +0100)
master/legacy [new file with mode: 0644]
master/series [new file with mode: 0644]
master/xen [new file with mode: 0644]

diff --git a/master/legacy b/master/legacy
new file mode 100644 (file)
index 0000000..db0d2bd
--- /dev/null
@@ -0,0 +1,472 @@
+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);
++}
diff --git a/master/series b/master/series
new file mode 100644 (file)
index 0000000..5c3d3da
--- /dev/null
@@ -0,0 +1,2 @@
+legacy
+xen
diff --git a/master/xen b/master/xen
new file mode 100644 (file)
index 0000000..c8356bb
--- /dev/null
@@ -0,0 +1,1201 @@
+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);
++}