All of lore.kernel.org
 help / color / mirror / Atom feed
From: phcoder <phcoder@gmail.com>
To: The development of GRUB 2 <grub-devel@gnu.org>
Subject: Efiemu
Date: Sat, 28 Feb 2009 17:17:28 +0100	[thread overview]
Message-ID: <49A96398.1070609@gmail.com> (raw)

[-- Attachment #1: Type: text/plain, Size: 1194 bytes --]

Hello here is a new version of efiemu. Now with 64-bit, virtual and 
clock support. Additionally I added a lot of comments and changelog. 
Remaining drawbacks:
- No wakeup support
- Can't hide bios
- No way to provide non-volatility for variables
- No reset function
These problems can't be addressed in bios environment (and are trivially 
fixed with coreboot) I consider this work conceptually complete on bios.
Usage cases:
-look how OS works in EFI environments. Debugging. Debugging ACPI
-launch darwin on non-EFI machine without usage of unmaintained buggy 
kernel patches (I already have xnu loading, it works but I have to fix 
few things)
-future port of coreboot to mac without losing ability to launch Mac OS X
Usage:
First compile grub2 with this patch and efiemu runtime (in archive)
Then on grub prompt
efiemu_loadcore <efiemu runtime>
efiemu_pnvram <variables file>
efiemu_acpi [-x <tables to delete>] <tables to add if any>
efiemu_prepare
linux_efiemu <normal linux>
initrd_efiemu <initrd>
Soon I'll also submit xnu patch which uses efiemu on non-EFI platforms
Programming note:
To keep compact I use defered allocation of all objects
-- 

Regards
Vladimir 'phcoder' Serbinenko

[-- Attachment #2: efiemu.diff --]
[-- Type: text/x-patch, Size: 156003 bytes --]

Index: conf/i386-pc.rmk
===================================================================
--- conf/i386-pc.rmk	(revision 2008)
+++ conf/i386-pc.rmk	(working copy)
@@ -146,7 +147,11 @@
 	\
 	disk/raid.c disk/raid5_recover.c disk/raid6_recover.c		\
 	disk/mdraid_linux.c disk/dmraid_nvidia.c disk/lvm.c		\
-	grub_emu_init.c
+	grub_emu_init.c efiemu/main.c efiemu/loadcore64.c 		\
+	efiemu/loadcore32.c efiemu/loadcore_common.c efiemu/mm.c	\
+	efiemu/modules/pnvram.c efiemu/i386/loadcore32.c 		\
+	efiemu/i386/loadcore64.c efiemu/symbols.c efiemu/prepare32.c	\
+	efiemu/prepare64.c lib/crc.c 	\
 
 grub_emu_LDFLAGS = $(LIBCURSES) 
 
@@ -172,3 +180,3 @@
 	vbe.mod vbetest.mod vbeinfo.mod play.mod serial.mod	\
 	ata.mod vga.mod memdisk.mod pci.mod lspci.mod \
 	aout.mod _bsd.mod bsd.mod pxe.mod pxecmd.mod datetime.mod date.mod \
	datehook.mod lsmmap.mod ata_pthru.mod hdparm.mod \
-	usb.mod uhci.mod ohci.mod usbtest.mod usbms.mod usb_keyboard.mod
+	usb.mod uhci.mod ohci.mod usbtest.mod usbms.mod usb_keyboard.mod \
+	efiemu.mod efiemu_acpi.mod efiemu_pnvram.mod _linux_efi.mod linux_efi.mod
 
+# For efiemu.mod.
+efiemu_mod_SOURCES = efiemu/main.c efiemu/i386/loadcore32.c efiemu/i386/loadcore64.c efiemu/i386/pc/cfgtables.c efiemu/mm.c efiemu/loadcore_common.c efiemu/symbols.c efiemu/loadcore32.c efiemu/loadcore64.c efiemu/prepare32.c efiemu/prepare64.c lib/i386/pc/acpi.c
+efiemu_mod_CFLAGS = $(COMMON_CFLAGS) -Werror -Wall
+efiemu_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
+efiemu_acpi_mod_SOURCES = efiemu/modules/acpi.c
+efiemu_acpi_mod_CFLAGS = $(COMMON_CFLAGS) -Werror -Wall
+efiemu_acpi_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
+efiemu_pnvram_mod_SOURCES = efiemu/modules/pnvram.c 
+efiemu_pnvram_mod_CFLAGS = $(COMMON_CFLAGS) -Werror -Wall
+efiemu_pnvram_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
 # For biosdisk.mod.
 biosdisk_mod_SOURCES = disk/i386/pc/biosdisk.c
 biosdisk_mod_CFLAGS = $(COMMON_CFLAGS)
@@ -200,6 +228,16 @@
 linux_mod_CFLAGS = $(COMMON_CFLAGS)
 linux_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
+# For _linux.mod.
+_linux_efi_mod_SOURCES = loader/i386/efi/linux.c
+_linux_efi_mod_CFLAGS = $(COMMON_CFLAGS)
+_linux_efi_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
+# For linux.mod.
+linux_efi_mod_SOURCES = loader/linux_normal_efiemu.c
+linux_efi_mod_CFLAGS = $(COMMON_CFLAGS)
+linux_efi_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
 #
 # Only arch dependant part of normal.mod will be here. Common part for
 # all architecures of normal.mod is at start and should be kept at sync
@@ -380,5 +423,19 @@
 hdparm_mod_CFLAGS = $(COMMON_CFLAGS)
 hdparm_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
+efiemu32.o: efiemu/runtime/efiemu.c
+	$(CC) -c -m32 -DELF32 -o $@ -Wall -Werror efiemu/runtime/efiemu.c -nostdlib -O2 -Iefiemu/runtime -Iinclude 
+efiemu64_c.o: efiemu/runtime/efiemu.c
+	$(CC) -c -m64 -DELF64 -o $@ -Wall -Werror efiemu/runtime/efiemu.c -nostdlib  -mcmodel=large -O2 -Iefiemu/runtime -Iinclude 
+
+efiemu64_s.o: efiemu/runtime/efiemu.S
+	$(CC) -c -m64 -DELF64 -o $@ -Wall -Werror efiemu/runtime/efiemu.S -nostdlib  -mcmodel=large -O2 -Iefiemu/runtime -Iinclude 
+
+efiemu64.o: efiemu64_c.o efiemu64_s.o
+	ld -o $@ -r efiemu64_c.o efiemu64_s.o -nostdlib 
+
+CLEANFILES += efiemu32.o efiemu64.o efiemu64_c.o efiemu64_S.o
+lib_DATA += efiemu32.o efiemu64.o
+
 include $(srcdir)/conf/i386.mk
 include $(srcdir)/conf/common.mk
Index: lib/i386/pc/acpi.c
===================================================================
--- lib/i386/pc/acpi.c	(revision 0)
+++ lib/i386/pc/acpi.c	(revision 0)
@@ -0,0 +1,59 @@
+/* Find ACPI tables */
+/*
+ *  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/normal.h>
+#include <grub/misc.h>
+#include <grub/acpi.h>
+
+/* Simple checksum by summing all bytes. Used by ACPI and SMBIOS */
+grub_uint8_t 
+grub_byte_checksum (void *base, grub_size_t size)
+{
+  grub_uint8_t *ptr;
+  grub_uint8_t ret = 0;
+  for (ptr = (grub_uint8_t *) base; ptr < ((grub_uint8_t *) base) + size;
+       ptr++)
+    ret += *ptr;
+  return ret;
+}
+
+struct grub_acpi_rsdp_v10 *
+grub_machine_acpi_get_rsdp (void)
+{
+  int ebda_len;
+  grub_uint8_t *ptr;
+
+  grub_dprintf ("acpi", "Looking for RSDP. Scanning EBDA\n");  
+  ebda_len = 1024 * (*((grub_uint8_t *)0x40e));
+  for (ptr = (grub_uint8_t *) 0x410; ptr < (grub_uint8_t *) (0x410 + ebda_len);
+       ptr += 16)
+    if (!grub_memcmp (ptr, "RSD PTR ", 8) 
+	&& grub_efiemu_byte_checksum (ptr, 
+				      sizeof (struct grub_acpi_rsdp_v10)) == 0)
+      return (struct grub_acpi_rsdp_v10 *) ptr;
+
+  grub_dprintf ("acpi", "Looking for RSDP. Scanning BIOS\n");  
+  for (ptr = (grub_uint8_t *) 0xe0000; ptr < (grub_uint8_t *) 0x100000;
+       ptr += 16)
+    if (!grub_memcmp (ptr, "RSD PTR ", 8)
+	&& grub_efiemu_byte_checksum (ptr, 
+				      sizeof (struct grub_acpi_rsdp_v10)) == 0)
+      return (struct grub_acpi_rsdp_v10 *) ptr;
+  return 0;
+}

Property changes on: lib/i386/pc/acpi.c
___________________________________________________________________
Added: svn:mergeinfo

Index: loader/linux_normal_efiemu.c
===================================================================
--- loader/linux_normal_efiemu.c	(revision 0)
+++ loader/linux_normal_efiemu.c	(revision 0)
@@ -0,0 +1,64 @@
+/* linux_normal.c - boot linux */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2004,2005,2006,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/machine/loader.h>
+#include <grub/err.h>
+#include <grub/normal.h>
+#include <grub/dl.h>
+
+void grub_rescue_cmd_linuxefi (int argc, char *argv[]);
+void grub_rescue_cmd_initrdefi (int argc, char *argv[]);
+
+
+static grub_err_t
+grub_normal_linuxefi_command (struct grub_arg_list *state __attribute__ ((unused)),
+			   int argc, char **args)
+{
+  grub_rescue_cmd_linuxefi (argc, args);
+  return grub_errno;
+}
+
+
+static grub_err_t
+grub_normal_initrd_command (struct grub_arg_list *state __attribute__ ((unused)),
+			    int argc, char **args)
+{
+  grub_rescue_cmd_initrdefi (argc, args);
+  return grub_errno;
+}
+
+GRUB_MOD_INIT(linux_normal)
+{
+  (void) mod; /* To stop warning.  */
+  grub_register_command ("linux_efiemu", grub_normal_linuxefi_command,
+			 GRUB_COMMAND_FLAG_BOTH,
+			 "linux_efiemu FILE [ARGS...]",
+			 "Load a linux kernel.", 0);
+  
+  grub_register_command ("initrd_efiemu", grub_normal_initrd_command,
+			 GRUB_COMMAND_FLAG_BOTH,
+			 "initrd_efiemu FILE",
+			 "Load an initrd.", 0);
+}
+
+GRUB_MOD_FINI(linux_normal)
+{
+  grub_unregister_command ("linux");
+  grub_unregister_command ("initrd");
+}
Index: loader/i386/efi/linux.c
===================================================================
--- loader/i386/efi/linux.c	(revision 2008)
+++ loader/i386/efi/linux.c	(working copy)
@@ -31,6 +31,7 @@
 #include <grub/efi/api.h>
 #include <grub/efi/efi.h>
 #include <grub/efi/uga_draw.h>
+#include <grub/autoefi.h>
 
 #define GRUB_LINUX_CL_OFFSET		0x1000
 #define GRUB_LINUX_CL_END_OFFSET	0x2000
@@ -113,7 +114,7 @@
       if (! mmap)
 	return 0;
 
-      ret = grub_efi_get_memory_map (&mmap_size, mmap, 0, &desc_size, 0);
+      ret = GRUB_EFI (get_memory_map) (&mmap_size, mmap, 0, &desc_size, 0);
       grub_free (mmap);
       
       if (ret < 0)
@@ -187,7 +188,7 @@
     return 0;
 
   tmp_mmap_size = mmap_size;
-  if (grub_efi_get_memory_map (&tmp_mmap_size, mmap, 0, &desc_size, 0) <= 0)
+  if (GRUB_EFI (get_memory_map) (&tmp_mmap_size, mmap, 0, &desc_size, 0) <= 0)
     grub_fatal ("cannot get memory map");
 
   mmap_end = NEXT_MEMORY_DESCRIPTOR (mmap, tmp_mmap_size);
@@ -292,7 +293,7 @@
 #endif
 
 static grub_err_t
-grub_linux_boot (void)
+grub_linux_efi_boot (void)
 {
   struct linux_kernel_params *params;
   grub_efi_uintn_t mmap_size;
@@ -313,8 +314,8 @@
 		(unsigned) gdt_desc.limit, (unsigned long) gdt_desc.base);
 
   mmap_size = find_mmap_size ();
-  if (grub_efi_get_memory_map (&mmap_size, mmap_buf, &map_key,
-			       &desc_size, &desc_version) <= 0)
+  if (GRUB_EFI (get_memory_map) (&mmap_size, mmap_buf, &map_key,
+				 &desc_size, &desc_version) <= 0)
     grub_fatal ("cannot get memory map");
 
   e820_num = 0;
@@ -390,7 +391,7 @@
 
   params->mmap_size = e820_num;
 
-  if (! grub_efi_exit_boot_services (map_key))
+  if (! GRUB_EFI (exit_boot_services) (map_key))
      grub_fatal ("cannot exit boot services");
 
   /* Note that no boot services are available from here.  */
@@ -504,6 +505,7 @@
   return 1;
 }
 
+#ifdef GRUB_MACHINE_EFI
 static int
 grub_linux_setup_video (struct linux_kernel_params *params)
 {
@@ -555,9 +557,15 @@
 
   return 0;
 }
+#endif
 
+#ifndef GRUB_MACHINE_EFI
 void
+grub_rescue_cmd_linuxefi (int argc, char *argv[])
+#else
+void
 grub_rescue_cmd_linux (int argc, char *argv[])
+#endif
 {
   grub_file_t file = 0;
   struct linux_kernel_header lh;
@@ -660,7 +668,11 @@
   params->video_cursor_x = grub_getxy () >> 8;
   params->video_cursor_y = grub_getxy () & 0xff;
   params->video_page = 0; /* ??? */
+#ifdef GRUB_MACHINE_EFI
   params->video_mode = grub_efi_system_table->con_out->mode->mode;
+#else
+  params->video_mode = 0;
+#endif
   params->video_width = (grub_getwh () >> 8);
   params->video_ega_bx = 0;
   params->video_height = (grub_getwh () & 0xff);
@@ -670,15 +682,15 @@
   if (grub_le_to_cpu16 (params->version) >= 0x0206)
     {
       params->v0206.efi_signature = GRUB_LINUX_EFI_SIGNATURE;
-      params->v0206.efi_system_table = (grub_uint32_t) (unsigned long) grub_efi_system_table;
+      params->v0206.efi_system_table = PTR_TO_UINT32 (GRUB_EFI (system_table));
 #ifdef __x86_64__
-      params->v0206.efi_system_table_hi = (grub_uint32_t) ((grub_uint64_t) grub_efi_system_table >> 32);
+      params->v0206.efi_system_table_hi = (grub_uint32_t) (PTR_TO_UINT64 (GRUB_EFI (system_table)) >> 32);
 #endif
     }
   else if (grub_le_to_cpu16 (params->version) >= 0x0204)
     {
       params->v0204.efi_signature = GRUB_LINUX_EFI_SIGNATURE_0204;
-      params->v0204.efi_system_table = (grub_uint32_t) (unsigned long) grub_efi_system_table;
+      params->v0204.efi_system_table = PTR_TO_UINT32 (GRUB_EFI (system_table));
     }
 
 #if 0
@@ -800,11 +812,13 @@
           video_type = GRUB_VIDEO_TYPE_EFI;
       }
 
+#ifdef GRUB_EFI_MACHINE_EFI
   if (video_type)
     {
       if (!  grub_linux_setup_video (params))
-        params->have_vga = video_type;
+	params->have_vga = video_type;
     }
+#endif
 
   /* Specify the boot file.  */
   dest = grub_stpcpy ((char *) real_mode_mem + GRUB_LINUX_CL_OFFSET,
@@ -828,7 +842,7 @@
 
   if (grub_errno == GRUB_ERR_NONE)
     {
-      grub_loader_set (grub_linux_boot, grub_linux_unload, 1);
+      grub_loader_set (grub_linux_efi_boot, grub_linux_unload, 1);
       loaded = 1;
     }
 
@@ -844,8 +858,13 @@
     }
 }
 
+#ifndef GRUB_MACHINE_EFI
 void
+grub_rescue_cmd_initrdefi (int argc, char *argv[])
+#else
+void
 grub_rescue_cmd_initrd (int argc, char *argv[])
+#endif
 {
   grub_file_t file = 0;
   grub_ssize_t size;
@@ -893,7 +912,7 @@
   
   /* Find the highest address to put the initrd.  */
   mmap_size = find_mmap_size ();
-  if (grub_efi_get_memory_map (&mmap_size, mmap_buf, 0, &desc_size, 0) <= 0)
+  if (GRUB_EFI (get_memory_map) (&mmap_size, mmap_buf, 0, &desc_size, 0) <= 0)
     grub_fatal ("cannot get memory map");
 
   addr = 0;
@@ -949,17 +968,31 @@
 
 GRUB_MOD_INIT(linux)
 {
+#ifndef GRUB_MACHINE_EFI
+  grub_rescue_register_command ("linuxefi",
+				grub_rescue_cmd_linuxefi,
+				"load linux");
+  grub_rescue_register_command ("initrdefi",
+				grub_rescue_cmd_initrdefi,
+				"load initrd");
+#else
   grub_rescue_register_command ("linux",
-				grub_rescue_cmd_linux,
+				grub_rescue_cmd_linuxefi,
 				"load linux");
   grub_rescue_register_command ("initrd",
-				grub_rescue_cmd_initrd,
+				grub_rescue_cmd_initrdefi,
 				"load initrd");
+#endif
   my_mod = mod;
 }
 
 GRUB_MOD_FINI(linux)
 {
+#ifndef GRUB_MACHINE_EFI
+  grub_rescue_unregister_command ("linuxefi");
+  grub_rescue_unregister_command ("initrdefi");
+#else
   grub_rescue_unregister_command ("linux");
   grub_rescue_unregister_command ("initrd");
+#endif
 }
Index: util/i386/pc/grub-install.in
===================================================================
--- util/i386/pc/grub-install.in	(revision 2008)
+++ util/i386/pc/grub-install.in	(working copy)
@@ -211,7 +211,7 @@
 fi
 
 # Copy the GRUB images to the GRUB directory.
-for file in ${grubdir}/*.mod ${grubdir}/*.lst ${grubdir}/*.img; do
+for file in ${grubdir}/*.mod ${grubdir}/*.lst ${grubdir}/*.img ${grubdir}/efiemu??.o; do
     if test -f $file && [ "`basename $file`" != menu.lst ]; then
 	rm -f $file || exit 1
     fi
@@ -295,7 +295,7 @@
     $grub_mkimage --output=${grubdir}/core.img --prefix=${prefix_drive}${relative_grubdir} $modules || exit 1
 
     # Now perform the installation.
-    $grub_setup ${setup_verbose} --directory=${grubdir} --device-map=${device_map} \
+    $grub_setup ${setup_verbose} --directory=${grubdir} --prefix=${relative_grubdir} --device-map=${device_map} \
         ${install_device} || exit 1
 else
     $grub_mkimage -d ${pkglibdir} --output=/boot/multiboot.img --prefix=${prefix_drive}${relative_grubdir} $modules || exit 1
Index: include/grub/autoefi.h
===================================================================
--- include/grub/autoefi.h	(revision 0)
+++ include/grub/autoefi.h	(revision 0)
@@ -0,0 +1,46 @@
+/*
+ *  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/>.
+ */
+/* This file provides some abstractions so that the same code compiles with
+   both efi and efiemu
+ */
+#ifndef GRUB_AUTOEFI_HEADER
+#define GRUB_AUTOEFI_HEADER	1
+
+#include <grub/machine/machine.h>
+
+#ifdef GRUB_MACHINE_EFI
+# include <grub/efi/efi.h>
+# define GRUB_EFI(x) grub_efi_ ## x 
+# define SYSTEM_TABLE_SIZEOF(x) (sizeof(grub_efi_system_table->x))
+# define SYSTEM_TABLE_VAR(x) ((void *)&(grub_efi_system_table->x))
+# define SYSTEM_TABLE_PTR(x) ((void *)(grub_efi_system_table->x))
+# define SIZEOF_OF_UINTN sizeof (grub_efi_uintn_t)
+# define SYSTEM_TABLE(x) (grub_efi_system_table->x)
+#else
+# include <grub/efiemu/efiemu.h>
+# define GRUB_EFI(x) grub_efiemu_ ## x 
+# define SYSTEM_TABLE_SIZEOF GRUB_EFIEMU_SYSTEM_TABLE_SIZEOF
+# define SYSTEM_TABLE_VAR GRUB_EFIEMU_SYSTEM_TABLE_VAR
+# define SYSTEM_TABLE_PTR GRUB_EFIEMU_SYSTEM_TABLE_PTR
+# define SIZEOF_OF_UINTN GRUB_EFIEMU_SIZEOF_OF_UINTN 
+# define SYSTEM_TABLE GRUB_EFIEMU_SYSTEM_TABLE 
+# define grub_efi_allocate_pages(x,y) (x)
+# define grub_efi_free_pages(x,y) GRUB_EFI_SUCCESS
+#endif
+
+#endif
Index: include/grub/i386/efiemu.h
===================================================================
--- include/grub/i386/efiemu.h	(revision 0)
+++ include/grub/i386/efiemu.h	(revision 0)
@@ -0,0 +1,33 @@
+/*
+ *  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/>.
+ */
+
+#ifndef GRUB_ARCH_EFI_EMU_HEADER
+#define GRUB_ARCH_EFI_EMU_HEADER	1
+
+grub_err_t
+grub_arch_efiemu_relocate_symbols32 (grub_efiemu_segment_t segs, 
+				     struct grub_efiemu_elf_sym *elfsyms,
+				     void *ehdr);
+grub_err_t
+grub_arch_efiemu_relocate_symbols64 (grub_efiemu_segment_t segs, 
+				     struct grub_efiemu_elf_sym *elfsyms,
+				     void *ehdr);
+
+int grub_arch_efiemu_check_header32 (void *ehdr);
+int grub_arch_efiemu_check_header64 (void *ehdr);
+#endif
Index: include/grub/i386/pc/efiemu.h
===================================================================
--- include/grub/i386/pc/efiemu.h	(revision 0)
+++ include/grub/i386/pc/efiemu.h	(revision 0)
@@ -0,0 +1,24 @@
+/*
+ *  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/>.
+ */
+
+#ifndef GRUB_MACHINE_EFI_EMU_HEADER
+#define GRUB_MACHINE_EFI_EMU_HEADER	1
+
+grub_err_t grub_machine_efiemu_init_tables (void);
+
+#endif
Index: include/grub/i386/pc/memory.h
===================================================================
--- include/grub/i386/pc/memory.h	(revision 2008)
+++ include/grub/i386/pc/memory.h	(working copy)
@@ -92,6 +92,8 @@
   grub_uint64_t len;
 #define GRUB_MACHINE_MEMORY_AVAILABLE	1
 #define GRUB_MACHINE_MEMORY_RESERVED	2
+#define GRUB_MACHINE_MEMORY_ACPI	3
+#define GRUB_MACHINE_MEMORY_NVS         4
   grub_uint32_t type;
 } __attribute__((packed));
 
Index: include/grub/efi/api.h
===================================================================
--- include/grub/efi/api.h	(revision 2008)
+++ include/grub/efi/api.h	(working copy)
@@ -40,15 +40,15 @@
 #define GRUB_EFI_TPL_NOTIFY		16
 #define GRUB_EFI_TPL_HIGH_LEVEL		31
 
-#define GRUB_EFI_MEMORY_UC	0x0000000000000001
-#define GRUB_EFI_MEMORY_WC	0x0000000000000002
-#define GRUB_EFI_MEMORY_WT	0x0000000000000004
-#define GRUB_EFI_MEMORY_WB	0x0000000000000008
-#define GRUB_EFI_MEMORY_UCE	0x0000000000000010
-#define GRUB_EFI_MEMORY_WP	0x0000000000001000
-#define GRUB_EFI_MEMORY_RP	0x0000000000002000
-#define GRUB_EFI_MEMORY_XP	0x0000000000004000
-#define GRUB_EFI_MEMORY_RUNTIME	0x8000000000000000
+#define GRUB_EFI_MEMORY_UC	0x0000000000000001LL
+#define GRUB_EFI_MEMORY_WC	0x0000000000000002LL
+#define GRUB_EFI_MEMORY_WT	0x0000000000000004LL
+#define GRUB_EFI_MEMORY_WB	0x0000000000000008LL
+#define GRUB_EFI_MEMORY_UCE	0x0000000000000010LL
+#define GRUB_EFI_MEMORY_WP	0x0000000000001000LL
+#define GRUB_EFI_MEMORY_RP	0x0000000000002000LL
+#define GRUB_EFI_MEMORY_XP	0x0000000000004000LL
+#define GRUB_EFI_MEMORY_RUNTIME	0x8000000000000000LL
 
 #define GRUB_EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL	0x00000001
 #define GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL		0x00000002
@@ -599,7 +599,7 @@
   grub_efi_int16_t time_zone;
   grub_efi_uint8_t daylight;
   grub_efi_uint8_t pad2;
-};
+} __attribute__ ((packed));
 typedef struct grub_efi_time grub_efi_time_t;
 
 struct grub_efi_time_capabilities
@@ -916,6 +916,20 @@
 };
 typedef struct grub_efi_configuration_table grub_efi_configuration_table_t;
 
+#define GRUB_EFIEMU_SYSTEM_TABLE_SIGNATURE 0x5453595320494249LL
+#define GRUB_EFIEMU_RUNTIME_SERVICES_SIGNATURE 0x56524553544e5552LL
+
+#define GRUB_EFI_ACPI_20_TABLE_GUID \
+  {0x8868e871,0xe4f1,0x11d3,{0xbc,0x22,0x0,0x80,0xc7,0x3c,0x88,0x81}}
+#define GRUB_EFI_ACPI_TABLE_GUID \
+  {0xeb9d2d30,0x2d88,0x11d3,{0x9a,0x16,0x0,0x90,0x27,0x3f,0xc1,0x4d}}
+#define GRUB_EFI_SAL_SYSTEM_TABLE_GUID \
+  {0xeb9d2d32,0x2d88,0x11d3,{0x9a,0x16,0x0,0x90,0x27,0x3f,0xc1,0x4d}}
+#define GRUB_EFI_SMBIOS_TABLE_GUID \
+  {0xeb9d2d31,0x2d88,0x11d3,{0x9a,0x16,0x0,0x90,0x27,0x3f,0xc1,0x4d}}
+#define GRUB_EFI_MPS_TABLE_GUID \
+  {0xeb9d2d2f,0x2d88,0x11d3,{0x9a,0x16,0x0,0x90,0x27,0x3f,0xc1,0x4d}}
+
 struct grub_efi_simple_input_interface
 {
   grub_efi_status_t
Index: include/grub/types.h
===================================================================
--- include/grub/types.h	(revision 2008)
+++ include/grub/types.h	(working copy)
@@ -100,6 +100,16 @@
 # define LONG_MAX 2147483647UL
 #endif
 
+#if GRUB_CPU_SIZEOF_VOID_P == 4
+#define UINT_TO_PTR(x) ((void*)(grub_uint32_t)(x))
+#define PTR_TO_UINT64(x) ((grub_uint64_t)(grub_uint32_t)(x))
+#define PTR_TO_UINT32(x) ((grub_uint32_t)(x))
+#else
+#define UINT_TO_PTR(x) ((void*)(grub_uint64_t)(x))
+#define PTR_TO_UINT64(x) ((grub_uint64_t)(x))
+#define PTR_TO_UINT32(x) ((grub_uint32_t)(grub_uint64_t)(x))
+#endif
+
 /* The type for representing a file offset.  */
 typedef grub_uint64_t	grub_off_t;
 
Index: include/grub/acpi.h
===================================================================
--- include/grub/acpi.h	(revision 0)
+++ include/grub/acpi.h	(revision 0)
@@ -0,0 +1,64 @@
+/*
+ *  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/>.
+ */
+
+#ifndef GRUB_ACPI_HEADER
+#define GRUB_ACPI_HEADER	1
+
+struct grub_acpi_rsdp_v10
+{
+  grub_uint8_t signature[8];
+  grub_uint8_t checksum;
+  grub_uint8_t oemid[6];
+  grub_uint8_t revision;
+  grub_uint32_t rsdt_addr;
+} __attribute__ ((packed));
+struct grub_acpi_rsdp_v20
+{
+  struct grub_acpi_rsdp_v10 rsdpv1;
+  grub_uint32_t length;
+  grub_uint64_t xsdt_addr;
+  grub_uint8_t checksum;
+  grub_uint8_t reserved[3];
+} __attribute__ ((packed));
+struct grub_acpi_table_header
+{
+  grub_uint8_t signature[4];
+  grub_uint32_t length;
+  grub_uint8_t revision;
+  grub_uint8_t checksum;
+  grub_uint8_t oemid[6];
+  grub_uint8_t oemtable[8];
+  grub_uint32_t oemrev;
+  grub_uint8_t creator_id[4];
+  grub_uint32_t creator_rev;  
+} __attribute__ ((packed));
+struct grub_acpi_fadt
+{
+  struct grub_acpi_table_header hdr;
+  grub_uint32_t facs_addr;
+  grub_uint32_t dsdt_addr;
+  grub_uint8_t somefields1[88];
+  grub_uint64_t facs_xaddr;
+  grub_uint64_t dsdt_xaddr;
+  grub_uint8_t somefields2[96];
+} __attribute__ ((packed));
+
+struct grub_acpi_rsdp_v10 *grub_machine_acpi_get_rsdp (void);
+grub_uint8_t grub_byte_checksum (void *base, grub_size_t size);
+
+#endif /* ! GRUB_ACPI_HEADER */

Property changes on: include/grub/acpi.h
___________________________________________________________________
Added: svn:mergeinfo

Index: include/grub/efiemu/efiemu.h
===================================================================
--- include/grub/efiemu/efiemu.h	(revision 0)
+++ include/grub/efiemu/efiemu.h	(revision 0)
@@ -0,0 +1,259 @@
+/*
+ *  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/>.
+ */
+
+#ifndef GRUB_EFI_EMU_HEADER
+#define GRUB_EFI_EMU_HEADER	1
+
+#include <grub/efi/api.h>
+#include <grub/file.h>
+
+#define GRUB_EFIEMU_PAGESIZE 4096
+
+/* EFI api defined in 32-bit and 64-bit version*/
+struct grub_efi_system_table32
+{
+  grub_efi_table_header_t hdr;
+  grub_efi_uint32_t firmware_vendor;
+  grub_efi_uint32_t firmware_revision;
+  grub_efi_uint32_t console_in_handler;
+  grub_efi_uint32_t con_in;
+  grub_efi_uint32_t console_out_handler;
+  grub_efi_uint32_t con_out;
+  grub_efi_uint32_t standard_error_handle;
+  grub_efi_uint32_t std_err;
+  grub_efi_uint32_t runtime_services;
+  grub_efi_uint32_t boot_services;
+  grub_efi_uint32_t num_table_entries;
+  grub_efi_uint32_t configuration_table;
+} __attribute__ ((packed));
+typedef struct grub_efi_system_table32  grub_efi_system_table32_t;
+
+struct grub_efi_system_table64
+{
+  grub_efi_table_header_t hdr;
+  grub_efi_uint64_t firmware_vendor;
+  grub_efi_uint32_t firmware_revision;
+  grub_efi_uint32_t pad;
+  grub_efi_uint64_t console_in_handler;
+  grub_efi_uint64_t con_in;
+  grub_efi_uint64_t console_out_handler;
+  grub_efi_uint64_t con_out;
+  grub_efi_uint64_t standard_error_handle;
+  grub_efi_uint64_t std_err;
+  grub_efi_uint64_t runtime_services;
+  grub_efi_uint64_t boot_services;
+  grub_efi_uint64_t num_table_entries;
+  grub_efi_uint64_t configuration_table;
+} __attribute__ ((packed));
+typedef struct grub_efi_system_table64  grub_efi_system_table64_t;
+
+struct grub_efiemu_runtime_services32
+{
+  grub_efi_table_header_t hdr;
+  grub_efi_uint32_t get_time;
+  grub_efi_uint32_t set_time;
+  grub_efi_uint32_t get_wakeup_time;
+  grub_efi_uint32_t set_wakeup_time;
+  grub_efi_uint32_t set_virtual_address_map;
+  grub_efi_uint32_t convert_pointer;
+  grub_efi_uint32_t get_variable;
+  grub_efi_uint32_t get_next_variable_name;
+  grub_efi_uint32_t set_variable;
+  grub_efi_uint32_t get_next_high_monotonic_count;
+  grub_efi_uint32_t reset_system;
+} __attribute__ ((packed));
+typedef struct grub_efiemu_runtime_services32 grub_efiemu_runtime_services32_t;
+
+struct grub_efiemu_runtime_services64
+{
+  grub_efi_table_header_t hdr;
+  grub_efi_uint64_t get_time;
+  grub_efi_uint64_t set_time;
+  grub_efi_uint64_t get_wakeup_time;
+  grub_efi_uint64_t set_wakeup_time;
+  grub_efi_uint64_t set_virtual_address_map;
+  grub_efi_uint64_t convert_pointer;
+  grub_efi_uint64_t get_variable;
+  grub_efi_uint64_t get_next_variable_name;
+  grub_efi_uint64_t set_variable;
+  grub_efi_uint64_t get_next_high_monotonic_count;
+  grub_efi_uint64_t reset_system;
+} __attribute__ ((packed));
+typedef struct grub_efiemu_runtime_services64 grub_efiemu_runtime_services64_t;
+
+extern grub_efi_system_table32_t *grub_efiemu_system_table32;
+extern grub_efi_system_table64_t *grub_efiemu_system_table64;
+
+/* Convenience macroses to access currently loaded efiemu */
+#define grub_efiemu_system_table ((grub_efiemu_sizeof_uintn_t () == 8) \
+				  ? (void *) grub_efiemu_system_table64 \
+				  : (void *) grub_efiemu_system_table32)
+#define GRUB_EFIEMU_SIZEOF_OF_UINTN (grub_efiemu_sizeof_uintn_t ())
+#define GRUB_EFIEMU_SYSTEM_TABLE(x) ((grub_efiemu_sizeof_uintn_t () == 8) \
+				     ? grub_efiemu_system_table64->x \
+				     : grub_efiemu_system_table32->x)
+#define GRUB_EFIEMU_SYSTEM_TABLE_SET(x,y) ((grub_efiemu_sizeof_uintn_t () == 8)\
+					   ? (grub_efiemu_system_table64->x \
+					      = (y)) \
+					   : (grub_efiemu_system_table32->x \
+					      = (y)))
+#define GRUB_EFIEMU_SYSTEM_TABLE_PTR(x) ((grub_efiemu_sizeof_uintn_t () == 8)\
+					 ? UINT_TO_PTR \
+					 (grub_efiemu_system_table64->x) \
+					 : UINT_TO_PTR \
+					 (grub_efiemu_system_table32->x))
+#define GRUB_EFIEMU_SYSTEM_TABLE_VAR(x) ((grub_efiemu_sizeof_uintn_t () == 8) \
+					 ? (void *) \
+					 &(grub_efiemu_system_table64->x) \
+					 : (void *) \
+					 &(grub_efiemu_system_table32->x))
+#define GRUB_EFIEMU_SYSTEM_TABLE_SIZEOF(x) \
+  ((grub_efiemu_sizeof_uintn_t () == 8) \
+   ? sizeof(grub_efiemu_system_table64->x)\
+   : sizeof(grub_efiemu_system_table32->x))
+#define GRUB_EFIEMU_SYSTEM_TABLE_SIZEOF_TOTAL ((grub_efiemu_sizeof_uintn_t () == 8) ? sizeof(*grub_efiemu_system_table64):sizeof(*grub_efiemu_system_table32))
+
+/* ELF management definitions and functions */
+
+struct grub_efiemu_segment
+{
+  struct grub_efiemu_segment *next;
+  grub_size_t size;
+  unsigned section;
+  int handle;
+  int ptv_rel_needed;
+  grub_off_t off;
+  void *srcptr;
+};
+typedef struct grub_efiemu_segment *grub_efiemu_segment_t;
+
+struct grub_efiemu_elf_sym
+{
+  int handle;
+  grub_off_t off;
+  unsigned section;
+};
+
+int grub_efiemu_check_header32 (void *ehdr, grub_size_t size);
+int grub_efiemu_check_header64 (void *ehdr, grub_size_t size);
+grub_err_t grub_efiemu_loadcore_init32 (void *core, grub_size_t core_size,
+					grub_efiemu_segment_t *segments);
+grub_err_t grub_efiemu_loadcore_init64 (void *core, grub_size_t core_size,
+					grub_efiemu_segment_t *segments);
+grub_err_t grub_efiemu_loadcore_load32 (void *core, 
+					grub_size_t core_size,
+					grub_efiemu_segment_t segments);
+grub_err_t grub_efiemu_loadcore_load64 (void *core, 
+					grub_size_t core_size,
+					grub_efiemu_segment_t segments);
+grub_err_t grub_efiemu_loadcore_unload32 (void);
+grub_err_t grub_efiemu_loadcore_unload64 (void);
+grub_err_t grub_efiemu_loadcore_unload(void);
+grub_err_t grub_efiemu_loadcore_init (grub_file_t file);
+grub_err_t grub_efiemu_loadcore_load (void);
+
+/* Configuration tables manipulation. Definitions and functions */
+struct grub_efiemu_configuration_table
+{
+  struct grub_efiemu_configuration_table *next;
+  grub_efi_guid_t guid;
+  void * (*get_table) (void *data);
+  void (*unload) (void *data);
+  void *data;
+};
+struct grub_efiemu_configuration_table32
+{
+  grub_efi_guid_t vendor_guid;
+  grub_efi_uint32_t vendor_table;
+} __attribute__ ((packed));
+typedef struct grub_efiemu_configuration_table32 grub_efiemu_configuration_table32_t;
+struct grub_efiemu_configuration_table64
+{
+  grub_efi_guid_t vendor_guid;
+  grub_efi_uint64_t vendor_table;
+} __attribute__ ((packed));
+typedef struct grub_efiemu_configuration_table32 grub_efiemu_configuration_table64_t;
+grub_err_t grub_efiemu_unregister_configuration_table (grub_efi_guid_t guid);
+grub_err_t 
+grub_efiemu_register_configuration_table (grub_efi_guid_t guid, 
+					  void * (*get_table) (void *data),
+					  void (*unload) (void *data), 
+					  void *data);
+
+/* Memory management functions */
+int grub_efiemu_request_memalign (grub_size_t align, grub_size_t size, 
+				  grub_efi_memory_type_t type);
+void *grub_efiemu_mm_obtain_request (int handle);
+int grub_efiemu_get_memory_map (grub_efi_uintn_t *memory_map_size,
+				grub_efi_memory_descriptor_t *memory_map,
+				grub_efi_uintn_t *map_key,
+				grub_efi_uintn_t *descriptor_size,
+				grub_efi_uint32_t *descriptor_version);
+grub_err_t grub_efiemu_mm_unload (void);
+grub_err_t grub_efiemu_mm_do_alloc (void);
+grub_err_t grub_efiemu_mm_init (void);
+void *grub_efiemu_mm_obtain_request (int handle);
+void grub_efiemu_mm_return_request (int handle);
+grub_efi_memory_type_t grub_efiemu_mm_get_type (int handle);
+
+/* Drop-in replacements for grub_efi_* */
+int grub_efiemu_get_memory_map (grub_efi_uintn_t *memory_map_size,
+				grub_efi_memory_descriptor_t *memory_map,
+				grub_efi_uintn_t *map_key,
+				grub_efi_uintn_t *descriptor_size,
+				grub_efi_uint32_t *descriptor_version);
+int grub_efiemu_sizeof_uintn_t (void);
+int grub_efiemu_exit_boot_services (grub_efi_uintn_t map_key);
+
+/* efiemu main control definitions and functions*/
+typedef enum {GRUB_EFIEMU_NOTLOADED,
+	      GRUB_EFIEMU32, GRUB_EFIEMU64} grub_efiemu_mode_t;
+struct grub_efiemu_prepare_hook
+{
+  struct grub_efiemu_prepare_hook *next;
+  grub_err_t (*hook) (void *data);
+  void (*unload) (void *data);
+  void *data;
+};
+grub_err_t grub_efiemu_prepare32 (struct grub_efiemu_prepare_hook 
+				  *prepare_hooks,
+				  struct grub_efiemu_configuration_table 
+				  *config_tables);
+grub_err_t grub_efiemu_prepare64 (struct grub_efiemu_prepare_hook 
+				  *prepare_hooks,
+				  struct grub_efiemu_configuration_table 
+				  *config_tables);
+grub_err_t grub_efiemu_unload (void);
+grub_err_t grub_efiemu_prepare (void);
+grub_err_t
+grub_efiemu_register_prepare_hook (grub_err_t (*hook) (void *data),
+				   void (*unload) (void *data), 
+				   void *data);
+
+/* symbols and pointers */
+grub_err_t grub_efiemu_alloc_syms (void);
+grub_err_t grub_efiemu_request_symbols (int num);
+grub_err_t grub_efiemu_resolve_symbol (const char *name, 
+				       int *handle, grub_off_t *off);
+grub_err_t grub_efiemu_register_symbol (const char *name, 
+					int handle, grub_off_t off);
+void grub_efiemu_free_syms (void);
+grub_err_t grub_efiemu_write_value (void * addr, grub_uint32_t value, 
+				    int plus_handle,
+				    int minus_handle, int ptv_needed, int size);
+#endif /* ! GRUB_EFI_EMU_HEADER */

Property changes on: include/grub/efiemu/efiemu.h
___________________________________________________________________
Added: svn:mergeinfo

Index: include/grub/efiemu/runtime.h
===================================================================
--- include/grub/efiemu/runtime.h	(revision 0)
+++ include/grub/efiemu/runtime.h	(revision 0)
@@ -0,0 +1,37 @@
+/*
+ *  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/>.
+ */
+
+#ifndef GRUB_EFI_EMU_RUNTIME_HEADER
+#define GRUB_EFI_EMU_RUNTIME_HEADER	1
+
+struct grub_efiemu_ptv_rel
+{
+  grub_uint64_t addr;
+  grub_efi_memory_type_t plustype;
+  grub_efi_memory_type_t minustype;
+  grub_uint32_t size;
+} __attribute__ ((packed));
+
+struct efi_variable
+{
+  grub_efi_guid_t guid;
+  grub_uint32_t namelen;
+  grub_uint32_t size;
+  grub_efi_uint32_t attributes;
+} __attribute__ ((packed));
+#endif /* ! GRUB_EFI_EMU_RUNTIME_HEADER */
Index: efiemu/prepare.c
===================================================================
--- efiemu/prepare.c	(revision 0)
+++ efiemu/prepare.c	(revision 0)
@@ -0,0 +1,127 @@
+/* Prepare efiemu. E.g. allocate memory, load the runtime 
+   to appropriate place, etc */
+/*
+ *  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/err.h>
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/efiemu/efiemu.h>
+#include <grub/lib/crc.h>
+
+grub_err_t
+SUFFIX (grub_efiemu_prepare) (struct grub_efiemu_prepare_hook *prepare_hooks,
+			      struct grub_efiemu_configuration_table 
+			      *config_tables)
+{
+  grub_err_t err;
+  int conftable_handle;
+  struct grub_efiemu_configuration_table *cur;
+  struct grub_efiemu_prepare_hook *curhook;
+
+  int cntconftables = 0;
+  TYPE (grub_efiemu_configuration_table) *conftables = 0;
+  TYPE (grub_efiemu_runtime_services) *runtime_services;
+  int i;
+  int handle;
+  grub_off_t off;
+
+  grub_dprintf ("efiemu", "Preparing EfiEmu\n");
+
+  /* Request space for the list of configuration tables */
+  for (cur = config_tables; cur; cur = cur->next)
+    cntconftables++;
+  conftable_handle 
+    = grub_efiemu_request_memalign (GRUB_EFIEMU_PAGESIZE, 
+				    cntconftables * sizeof (*conftables),
+				    GRUB_EFI_RUNTIME_SERVICES_DATA);
+
+  /* Switch from phase 1 (counting) to phase 2 (real job) */
+  grub_efiemu_alloc_syms ();
+  grub_efiemu_mm_do_alloc ();
+
+  grub_efiemu_system_table32 = 0;
+  grub_efiemu_system_table64 = 0;
+
+  /* Execute hooks */
+  for (curhook = prepare_hooks; curhook; curhook = curhook->next)
+    curhook->hook (curhook->data);
+
+  /* Move runtime to its due place */
+  if ((err = grub_efiemu_loadcore_load ()))
+    {
+      grub_efiemu_unload ();
+      return err;
+    }
+
+  if ((err = grub_efiemu_resolve_symbol ("efiemu_system_table", 
+					 &handle, &off)))
+    {
+      grub_efiemu_unload ();
+      return err;
+    }
+
+  SUFFIX (grub_efiemu_system_table)  
+    = (TYPE (grub_efi_system_table) *) 
+    ((grub_uint8_t *)grub_efiemu_mm_obtain_request (handle) + off);
+
+  /* compute CRC32 of runtime_services */
+  if ((err = grub_efiemu_resolve_symbol ("efiemu_runtime_services", 
+					 &handle, &off)))
+    return err;
+  runtime_services = (TYPE (grub_efiemu_runtime_services) *)
+	((grub_uint8_t *)grub_efiemu_mm_obtain_request (handle) + off);
+  runtime_services->hdr.crc32 = 0;
+  runtime_services->hdr.crc32 = grub_getcrc32 
+    (0, runtime_services, runtime_services->hdr.header_size);
+
+  /* Put pointer to the list of configuration tables in system table */
+  grub_efiemu_write_value
+    (&(SUFFIX (grub_efiemu_system_table)->configuration_table), 0, 
+     conftable_handle, 0, 1, 
+     sizeof (SUFFIX (grub_efiemu_system_table)->configuration_table));
+  SUFFIX(grub_efiemu_system_table)->num_table_entries = cntconftables;
+
+  /* Fill the list of configuration tables */
+  conftables = (TYPE (grub_efiemu_configuration_table) *)
+    grub_efiemu_mm_obtain_request (conftable_handle);
+  i = 0;
+  for (cur = config_tables; cur; cur = cur->next, i++)
+    {
+      grub_memcpy (&(conftables[i].vendor_guid), &(cur->guid), 
+		       sizeof (cur->guid));
+      if (cur->get_table)
+	conftables[i].vendor_table
+	  = PTR_TO_UINT64 (cur->get_table (cur->data));
+      else
+	conftables[i].vendor_table = PTR_TO_UINT64 (cur->data);
+    }
+
+  /* compute CRC32 of system table */
+  SUFFIX (grub_efiemu_system_table)->hdr.crc32 = 0;
+  SUFFIX (grub_efiemu_system_table)->hdr.crc32 
+    = grub_getcrc32 (0, SUFFIX (grub_efiemu_system_table), 
+		     SUFFIX (grub_efiemu_system_table)->hdr.header_size);
+
+  grub_dprintf ("efiemu","system_table = %p, runtime_services = %p,"
+		" conftables = %p (%d entries)\n",
+		SUFFIX (grub_efiemu_system_table), runtime_services, 
+		conftables, cntconftables);
+
+  return GRUB_ERR_NONE;
+}
Index: efiemu/loadcore_common.c
===================================================================
--- efiemu/loadcore_common.c	(revision 0)
+++ efiemu/loadcore_common.c	(revision 0)
@@ -0,0 +1,189 @@
+/* Load runtime image of EFIemu. Functions common to 32/64-bit mode */
+/*
+ *  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/file.h>
+#include <grub/err.h>
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/efiemu/efiemu.h>
+#include <grub/cpu/efiemu.h>
+
+/* Are we in 32 or 64-bit mode?*/
+static grub_efiemu_mode_t grub_efiemu_mode = GRUB_EFIEMU_NOTLOADED;
+/* Runtime ELF file */
+static grub_ssize_t efiemu_core_size;
+static void *efiemu_core = 0;
+/* Linked list of segments */
+static grub_efiemu_segment_t efiemu_segments = 0;
+
+/* equivalent to sizeof (grub_efi_uintn_t) but taking the mode into account*/
+int
+grub_efiemu_sizeof_uintn_t (void)
+{
+  if (grub_efiemu_mode == GRUB_EFIEMU32)
+    return 4;
+  if (grub_efiemu_mode == GRUB_EFIEMU64)
+    return 8;
+  return 0;
+}
+
+/* Check the header and set mode */
+static grub_err_t
+grub_efiemu_check_header (void *ehdr, grub_size_t size, 
+			  grub_efiemu_mode_t *mode)
+{
+  /* Check the magic numbers.  */
+  if ((*mode == GRUB_EFIEMU_NOTLOADED || *mode == GRUB_EFIEMU32)
+      && grub_efiemu_check_header32 (ehdr,size))
+    {
+      *mode = GRUB_EFIEMU32;
+      return GRUB_ERR_NONE;
+    }
+  if ((*mode == GRUB_EFIEMU_NOTLOADED || *mode == GRUB_EFIEMU64)
+      && grub_efiemu_check_header64 (ehdr,size))
+    {
+      *mode = GRUB_EFIEMU64;
+      return GRUB_ERR_NONE;
+    }
+  return grub_error (GRUB_ERR_BAD_OS, "invalid ELF magic");
+}
+
+/* Unload segments */
+static int
+grub_efiemu_unload_segs (grub_efiemu_segment_t seg)
+{
+  grub_efiemu_segment_t segn;
+  for (; seg; seg = segn)
+    {
+      segn = seg->next;
+      grub_efiemu_mm_return_request (seg->handle);
+      grub_free (seg);
+    }
+  return 1;
+}
+
+
+grub_err_t
+grub_efiemu_loadcore_unload(void)
+{
+  switch (grub_efiemu_mode)
+    {
+    case GRUB_EFIEMU32:
+      grub_efiemu_loadcore_unload32 ();
+      break;
+
+    case GRUB_EFIEMU64:
+      grub_efiemu_loadcore_unload64 ();
+      break;
+      
+    default:
+      break;
+    }
+
+  grub_efiemu_mode = GRUB_EFIEMU_NOTLOADED;
+
+  grub_free (efiemu_core);
+  efiemu_core = 0;
+
+  grub_efiemu_unload_segs (efiemu_segments);
+  efiemu_segments = 0;
+
+  grub_efiemu_free_syms ();
+
+  return GRUB_ERR_NONE;
+}
+
+/* Load runtime file and do some initial preparations */ 
+grub_err_t
+grub_efiemu_loadcore_init (grub_file_t file)
+{
+  grub_err_t err;
+
+  efiemu_core_size = grub_file_size (file);
+  efiemu_core = 0;
+  efiemu_core = grub_malloc (efiemu_core_size);
+  if (! efiemu_core)
+    return grub_errno;
+
+  if (grub_file_read (file, efiemu_core, efiemu_core_size) 
+      != (int) efiemu_core_size)
+    {
+      grub_free (efiemu_core);
+      efiemu_core = 0;
+      return grub_errno;
+    }
+
+  if (grub_efiemu_check_header (efiemu_core, efiemu_core_size, 
+				&grub_efiemu_mode))
+    {
+      grub_free (efiemu_core);
+      efiemu_core = 0;
+      return GRUB_ERR_BAD_MODULE;
+    }
+
+  switch (grub_efiemu_mode)
+    {
+    case GRUB_EFIEMU32:
+      if ((err = grub_efiemu_loadcore_init32 (efiemu_core, efiemu_core_size,
+					      &efiemu_segments)))
+	{
+	  grub_free (efiemu_core);
+	  efiemu_core = 0;
+	  grub_efiemu_mode = GRUB_EFIEMU_NOTLOADED;
+	  return err;
+	}
+      break;
+
+    case GRUB_EFIEMU64:
+      if ((err = grub_efiemu_loadcore_init64 (efiemu_core, efiemu_core_size,
+					      &efiemu_segments)))
+	{
+	  grub_free (efiemu_core);
+	  efiemu_core = 0;
+	  grub_efiemu_mode = GRUB_EFIEMU_NOTLOADED;
+	  return err;
+	}
+      break;
+      
+    default:
+      return grub_error (GRUB_ERR_BAD_OS, "unknown EFI runtime");
+    }
+  return GRUB_ERR_NONE;
+}
+
+grub_err_t
+grub_efiemu_loadcore_load (void)
+{
+  grub_err_t err;
+  switch (grub_efiemu_mode)
+    {
+    case GRUB_EFIEMU32:
+      if ((err = grub_efiemu_loadcore_load32 (efiemu_core, efiemu_core_size,
+					      efiemu_segments)))
+	  grub_efiemu_loadcore_unload ();
+      return err;
+    case GRUB_EFIEMU64:
+      if ((err = grub_efiemu_loadcore_load64 (efiemu_core, efiemu_core_size,
+					      efiemu_segments)))
+	  grub_efiemu_loadcore_unload ();
+      return err;
+    default:
+      return grub_error (GRUB_ERR_BAD_OS, "unknown EFI runtime");
+    }
+}
Index: efiemu/loadcore64.c
===================================================================
--- efiemu/loadcore64.c	(revision 0)
+++ efiemu/loadcore64.c	(revision 0)
@@ -0,0 +1,27 @@
+/* This file contains definitions so that loadcore.c compiles for 64-bit */
+/*
+ *  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/>.
+ */
+
+#define SUFFIX(x) x ## 64
+#define Elf_Ehdr Elf64_Ehdr
+#define Elf_Shdr Elf64_Shdr
+#define Elf_Sym Elf64_Sym
+#define Elf_Word Elf64_Word
+#define ELF_ST_TYPE ELF64_ST_TYPE
+#define ELF_ST_BIND ELF64_ST_BIND
+#include "loadcore.c"
Index: efiemu/runtime/efiemu.sh
===================================================================
--- efiemu/runtime/efiemu.sh	(revision 0)
+++ efiemu/runtime/efiemu.sh	(revision 0)
@@ -0,0 +1,6 @@
+gcc -c -m32 -DELF32 -o efiemu32.o ./efiemu.c -Wall -Werror -nostdlib -O2 -I. -I../../include
+gcc -c -m64 -DELF64 -o efiemu64_c.o ./efiemu.c -Wall -Werror -mcmodel=large -O2 -I. -I../../include
+gcc -c -m64 -DELF64 -o efiemu64_s.o ./efiemu.S -Wall -Werror -mcmodel=large -O2 -I. -I../../include
+ld -o efiemu64.o -r efiemu64_s.o efiemu64_c.o -nostdlib 
+
+
Index: efiemu/runtime/efiemu.S
===================================================================
--- efiemu/runtime/efiemu.S	(revision 0)
+++ efiemu/runtime/efiemu.S	(revision 0)
@@ -0,0 +1,160 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2006,2007,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>
+
+/*
+ * x86_64 uses registry to pass parameters. Unfortunately, gcc and efi use
+ * different call conversion, so we need to do some conversion.
+ *
+ * gcc:
+ *   %rdi,  %rsi,  %rdx,  %rcx, %r8, %r9, 8(%rsp), 16(%rsp), ...
+ *
+ * efi:
+ *   %rcx,  %rdx,  %r8,  %r9,  32(%rsp), 40(%rsp), 48(%rsp), ...
+ *
+ */
+	
+        .file   "efiemu.S"
+	.text
+	
+FUNCTION (efiemu_get_time)
+	push %rdi
+	push %rsi
+	mov %rcx, %rdi
+	mov %rdx, %rsi
+	call efiemu_get_time_real
+	pop %rsi
+	pop %rdi
+	ret
+
+FUNCTION (efiemu_set_time)
+	push %rdi
+	push %rsi
+	mov %rcx, %rdi
+	call efiemu_set_time_real
+	pop %rsi
+	pop %rdi
+	ret
+
+
+FUNCTION (efiemu_get_wakeup_time)
+	push %rdi
+	push %rsi
+	mov %rcx, %rdi
+	mov %rdx, %rsi
+	mov %r8, %rdx
+	call efiemu_get_wakeup_time_real
+	pop %rsi
+	pop %rdi
+	ret
+
+FUNCTION (efiemu_set_wakeup_time)
+	push %rdi
+	push %rsi
+	mov %rcx, %rdi
+	mov %rdx, %rsi
+	call efiemu_set_wakeup_time_real
+	pop %rsi
+	pop %rdi
+	ret
+
+FUNCTION (efiemu_get_variable)
+	push %rdi
+	push %rsi
+	mov %rcx, %rdi
+	mov %rdx, %rsi
+	mov %r8, %rdx
+	mov %r9, %rcx
+	mov 56(%rsp), %r8
+	call efiemu_get_variable_real
+	pop %rsi
+	pop %rdi
+	ret
+
+FUNCTION (efiemu_get_next_variable_name)
+	push %rdi
+	push %rsi
+	mov %rcx, %rdi
+	mov %rdx, %rsi
+	mov %r8, %rdx
+	call efiemu_get_next_variable_name_real
+	pop %rsi
+	pop %rdi
+	ret
+
+FUNCTION (efiemu_set_variable)
+	push %rdi
+	push %rsi
+	mov %rcx, %rdi
+	mov %rdx, %rsi
+	mov %r8, %rdx
+	mov %r9, %rcx	
+	mov 56(%rsp), %r8
+	call efiemu_set_variable_real
+	pop %rsi
+	pop %rdi
+	ret
+
+FUNCTION (efiemu_get_next_high_monotonic_count)
+	push %rdi
+	push %rsi
+	mov %rcx, %rdi
+	call efiemu_get_next_high_monotonic_count_real
+	pop %rsi
+	pop %rdi
+	ret
+
+FUNCTION (efiemu_reset_system)
+	push %rdi
+	push %rsi
+	mov %rcx, %rdi
+	mov %rdx, %rsi
+	mov %r8, %rdx
+	mov %r9, %rcx
+	call efiemu_reset_system_real
+	pop %rsi
+	pop %rdi
+	ret
+
+	/* The following functions are always called in physical mode */
+	.section ".text-physical", "ax"		
+	
+FUNCTION (efiemu_set_virtual_address_map)
+	push %rdi
+	push %rsi
+	mov %rcx, %rdi
+	mov %rdx, %rsi
+	mov %r8, %rdx
+	mov %r9, %rcx
+	call efiemu_set_virtual_address_map_real
+	pop %rsi
+	pop %rdi
+	ret
+
+FUNCTION (efiemu_convert_pointer)
+	push %rdi
+	push %rsi
+	mov %rcx, %rdi
+	mov %rdx, %rsi
+	call efiemu_convert_pointer_real
+	pop %rsi
+	pop %rdi
+	ret
+
+
Index: efiemu/runtime/efiemu.c
===================================================================
--- efiemu/runtime/efiemu.c	(revision 0)
+++ efiemu/runtime/efiemu.c	(revision 0)
@@ -0,0 +1,623 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2006,2007,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/>.
+ */
+
+/* This is an emulation of EFI runtime services.
+   This allows a more uniform boot on i386 machines. 
+   As it emulates only runtime serviceit isn't able 
+   to chainload EFI bootloader on non-EFI system (TODO) */
+
+#include <grub/symbol.h>
+#include <grub/types.h>
+#include <grub/efi/api.h>
+#include <grub/efiemu/runtime.h>
+
+grub_efi_status_t 
+efiemu_get_time (grub_efi_time_t *time,
+		 grub_efi_time_capabilities_t *capabilities);
+grub_efi_status_t
+efiemu_set_time (grub_efi_time_t *time);
+
+grub_efi_status_t
+efiemu_get_wakeup_time (grub_efi_boolean_t *enabled,
+			grub_efi_boolean_t *pending,
+			grub_efi_time_t *time);
+grub_efi_status_t
+efiemu_set_wakeup_time (grub_efi_boolean_t enabled,
+			grub_efi_time_t *time);
+
+
+grub_efi_status_t
+efiemu_set_virtual_address_map (grub_efi_uintn_t memory_map_size,
+				grub_efi_uintn_t descriptor_size,
+				grub_efi_uint32_t descriptor_version,
+				grub_efi_memory_descriptor_t *virtual_map)
+  __attribute__ ((section(".text-physical")));
+
+grub_efi_status_t
+efiemu_convert_pointer (grub_efi_uintn_t debug_disposition, 
+			void **address)
+  __attribute__ ((section(".text-physical")));
+
+grub_efi_status_t
+efiemu_get_variable (grub_efi_char16_t *variable_name,
+		     grub_efi_guid_t *vendor_guid,
+		     grub_efi_uint32_t *attributes,
+		     grub_efi_uintn_t *data_size,
+		     void *data);
+
+grub_efi_status_t
+efiemu_get_next_variable_name (grub_efi_uintn_t *variable_name_size,
+			       grub_efi_char16_t *variable_name,
+			       grub_efi_guid_t *vendor_guid);
+
+grub_efi_status_t
+efiemu_set_variable (grub_efi_char16_t *variable_name,
+		     grub_efi_guid_t *vendor_guid,
+		     grub_efi_uint32_t attributes,
+		     grub_efi_uintn_t data_size,
+		     void *data);
+grub_efi_status_t
+efiemu_get_next_high_monotonic_count (grub_efi_uint32_t *high_count);
+void
+efiemu_reset_system (grub_efi_reset_type_t reset_type,
+		     grub_efi_status_t reset_status,
+		     grub_efi_uintn_t data_size,
+		     grub_efi_char16_t *reset_data);
+
+grub_efi_status_t 
+EFI_FUNC (efiemu_set_virtual_address_map) (grub_efi_uintn_t,
+					      grub_efi_uintn_t,
+					      grub_efi_uint32_t,
+					      grub_efi_memory_descriptor_t *)
+  __attribute__ ((section(".text-physical")));
+grub_efi_status_t
+EFI_FUNC (efiemu_convert_pointer) (grub_efi_uintn_t debug_disposition, 
+				      void **address)
+  __attribute__ ((section(".text-physical")));
+static grub_uint32_t
+efiemu_getcrc32 (grub_uint32_t crc, void *buf, int size)
+     __attribute__ ((section(".text-physical")));
+static void
+init_crc32_table (void)
+  __attribute__ ((section(".text-physical")));
+			     
+/*
+  The log. It's used when examining memory dump
+*/				     
+static grub_uint8_t loge[1000] = "EFIEMULOG";
+static int logn = 9; 
+#define LOG(x)   { if (logn<900) loge[logn++]=x; }
+
+static int ptv_relocated = 0;
+
+/* Interface with grub */
+struct grub_efi_runtime_services efiemu_runtime_services;
+struct grub_efi_system_table efiemu_system_table;
+extern struct grub_efiemu_ptv_rel efiemu_ptv_relloc[];
+extern grub_uint8_t efiemu_variables[];
+extern grub_uint32_t efiemu_varsize;
+extern grub_uint32_t efiemu_high_monotonic_count;
+extern grub_int16_t efiemu_time_zone;
+extern grub_uint8_t efiemu_time_daylight;
+extern grub_uint32_t efiemu_time_accuracy;
+
+/* Some standard functions because we need to be stadalone */
+static void
+efiemu_memcpy (void *to, void *from, int count)
+{
+  int i;
+  for (i = 0; i < count; i++)
+    ((grub_uint8_t *) to)[i] = ((grub_uint8_t *) from)[i];
+}
+
+static int
+efiemu_str16equal (grub_uint16_t *a, grub_uint16_t *b)
+{
+  grub_uint16_t *ptr1, *ptr2;
+  for (ptr1=a,ptr2=b; *ptr1 && *ptr2 == *ptr1; ptr1++, ptr2++);
+  return *ptr2 == *ptr1;
+}
+
+static grub_size_t
+efiemu_str16len (grub_uint16_t *a)
+{
+  grub_uint16_t *ptr1;
+  for (ptr1 = a; *ptr1; ptr1++);
+  return ptr1 - a;
+}
+
+static int
+efiemu_memequal (void *a, void *b, grub_size_t n)
+{
+  grub_uint8_t *ptr1, *ptr2;
+  for (ptr1 = (grub_uint8_t *) a, ptr2 = (grub_uint8_t *)b;
+       ptr1 < (grub_uint8_t *)a + n && *ptr2 == *ptr1; ptr1++, ptr2++);
+  return ptr1 == a + n;
+}
+
+static void
+efiemu_memset (grub_uint8_t *a, grub_uint8_t b, grub_size_t n)
+{
+  grub_uint8_t *ptr1;
+  for (ptr1=a; ptr1 < a + n; ptr1++)
+    *ptr1 = b;
+}
+
+static inline void
+write_cmos (grub_uint8_t addr, grub_uint8_t val)
+{
+  __asm__ __volatile__ ("outb %%al,$0x70\n"
+			"mov %%bl, %%al\n"
+			"outb %%al,$0x71": :"a" (addr), "b" (val));
+}
+
+static inline grub_uint8_t
+read_cmos (grub_uint8_t addr)
+{
+  grub_uint8_t ret;
+  __asm__ __volatile__ ("outb %%al, $0x70\n"
+			"inb $0x71, %%al": "=a"(ret) :"a" (addr));
+  return ret;
+}
+
+/* Needed by some gcc versions */
+int __stack_chk_fail ()
+{
+  return 0;
+}
+
+/* The function that implement runtime services as specified in 
+   EFI specification */
+static inline grub_uint8_t
+bcd_to_hex (grub_uint8_t in)
+{
+  return 10 * ((in & 0xf0) >> 4) + (in & 0x0f);
+}
+
+grub_efi_status_t 
+EFI_FUNC (efiemu_get_time) (grub_efi_time_t *time,
+			       grub_efi_time_capabilities_t *capabilities)
+{
+  LOG ('a');
+  grub_uint8_t state;
+  state = read_cmos (0xb);
+  if (!(state & (1 << 2)))
+    {
+      time->year = 2000 + bcd_to_hex (read_cmos (0x9));
+      time->month = bcd_to_hex (read_cmos (0x8));
+      time->day = bcd_to_hex (read_cmos (0x7));
+      time->hour = bcd_to_hex (read_cmos (0x4));
+      if (time->hour >= 81)
+	time->hour -= 80 - 12;
+      if (time->hour == 24)
+	time->hour = 0;
+      time->minute = bcd_to_hex (read_cmos (0x2));
+      time->second = bcd_to_hex (read_cmos (0x0));
+    }
+  else
+    {
+      time->year = 2000 + read_cmos (0x9);
+      time->month = read_cmos (0x8);
+      time->day = read_cmos (0x7);
+      time->hour = read_cmos (0x4);
+      if (time->hour >= 0x81)
+	time->hour -= 0x80 - 12;
+      if (time->hour == 24)
+	time->hour = 0;
+      time->minute = read_cmos (0x2);
+      time->second = read_cmos (0x0);
+    }
+  time->nanosecond = 0;
+  time->pad1 = 0;
+  time->pad2 = 0;
+  time->time_zone = efiemu_time_zone;
+  time->daylight = efiemu_time_daylight;
+  capabilities->resolution = 1;
+  capabilities->accuracy = efiemu_time_accuracy;
+  capabilities->sets_to_zero = 0;
+  return GRUB_EFI_SUCCESS;
+}
+
+grub_efi_status_t
+EFI_FUNC (efiemu_set_time) (grub_efi_time_t *time)
+{
+  LOG ('b');
+  grub_uint8_t state;
+  state = read_cmos (0xb);
+  write_cmos (0xb, state | 0x6);
+  write_cmos (0x9, time->year - 2000);
+  write_cmos (0x8, time->month);
+  write_cmos (0x7, time->day);
+  write_cmos (0x4, time->hour);
+  write_cmos (0x2, time->minute);
+  write_cmos (0x0, time->second);
+  efiemu_time_zone = time->time_zone;
+  efiemu_time_daylight = time->daylight;
+  return GRUB_EFI_SUCCESS;
+}
+
+/* Folowing 2 functions are vendor specific. So announce it as unsupported */
+grub_efi_status_t
+EFI_FUNC (efiemu_get_wakeup_time) (grub_efi_boolean_t *enabled,
+				      grub_efi_boolean_t *pending,
+				      grub_efi_time_t *time)
+{
+  LOG ('c');
+  return GRUB_EFI_UNSUPPORTED;
+}
+
+grub_efi_status_t
+EFI_FUNC (efiemu_set_wakeup_time) (grub_efi_boolean_t enabled,
+				      grub_efi_time_t *time)
+{
+  LOG ('d');
+  return GRUB_EFI_UNSUPPORTED;
+}
+
+static grub_uint32_t crc32_table [256];
+
+static void
+init_crc32_table (void)
+{
+  auto grub_uint32_t reflect (grub_uint32_t ref, int len);
+  grub_uint32_t reflect (grub_uint32_t ref, int len)
+    {
+      grub_uint32_t result = 0;
+      int i;
+
+      for (i = 1; i <= len; i++)
+        {
+          if (ref & 1)
+            result |= 1 << (len - i);
+          ref >>= 1;
+        }
+
+      return result;
+    }
+
+  grub_uint32_t polynomial = 0x04c11db7;
+  int i, j;
+
+  for(i = 0; i < 256; i++)
+    {
+      crc32_table[i] = reflect(i, 8) << 24;
+      for (j = 0; j < 8; j++)
+        crc32_table[i] = (crc32_table[i] << 1) ^
+            (crc32_table[i] & (1 << 31) ? polynomial : 0);
+      crc32_table[i] = reflect(crc32_table[i], 32);
+    }
+}
+
+static grub_uint32_t
+efiemu_getcrc32 (grub_uint32_t crc, void *buf, int size)
+{
+  int i;
+  grub_uint8_t *data = buf;
+
+  if (! crc32_table[1])
+    init_crc32_table ();
+
+  crc^= 0xffffffff;
+
+  for (i = 0; i < size; i++)
+    {
+      crc = (crc >> 8) ^ crc32_table[(crc & 0xFF) ^ *data];
+      data++;
+    }
+
+  return crc ^ 0xffffffff;
+}
+
+
+grub_efi_status_t EFI_FUNC 
+(efiemu_set_virtual_address_map) (grub_efi_uintn_t memory_map_size,
+				  grub_efi_uintn_t descriptor_size,
+				  grub_efi_uint32_t descriptor_version,
+				  grub_efi_memory_descriptor_t *virtual_map)
+{
+  struct grub_efiemu_ptv_rel *cur_relloc;
+
+  LOG ('e');
+  
+  /* Ensure that we are called only once */
+  if (ptv_relocated)
+    return GRUB_EFI_UNSUPPORTED;
+  ptv_relocated = 1;
+  
+  /* Correct addresses using information supplied by grub */
+  for (cur_relloc = efiemu_ptv_relloc; cur_relloc->size;cur_relloc++)
+    {
+      grub_int64_t corr = 0;
+      grub_efi_memory_descriptor_t *descptr;
+
+      /* Compute correction */
+      for (descptr = virtual_map;  
+	   ((grub_uint8_t *) descptr - (grub_uint8_t *) virtual_map) 
+	     < memory_map_size;
+	   descptr = (grub_efi_memory_descriptor_t *)
+	     ((grub_uint8_t *) descptr + descriptor_size))
+	{
+	  if (descptr->type == cur_relloc->plustype)
+	    corr += descptr->virtual_start - descptr->physical_start;
+	  if (descptr->type == cur_relloc->minustype)
+	    corr -= descptr->virtual_start - descptr->physical_start;
+	}
+
+      /* Apply correction */
+      switch (cur_relloc->size)
+	{
+	case 8:
+	  *((grub_uint64_t *) UINT_TO_PTR (cur_relloc->addr)) += corr;
+	  break;
+	case 4:
+	  *((grub_uint32_t *) UINT_TO_PTR (cur_relloc->addr)) += corr;
+	  break;
+	case 2:
+	  *((grub_uint16_t *) UINT_TO_PTR (cur_relloc->addr)) += corr;
+	  break;
+	case 1:
+	  *((grub_uint8_t *) UINT_TO_PTR (cur_relloc->addr)) += corr;
+	  break;
+	}
+    }
+
+  /* Recompute crc32 of system table and runtime services */
+  efiemu_system_table.hdr.crc32 = 0;
+  efiemu_system_table.hdr.crc32 = efiemu_getcrc32 
+    (0, &efiemu_system_table, sizeof (efiemu_system_table));
+
+  efiemu_runtime_services.hdr.crc32 = 0;
+  efiemu_runtime_services.hdr.crc32 = efiemu_getcrc32 
+    (0, &efiemu_runtime_services, sizeof (efiemu_runtime_services));
+
+  return GRUB_EFI_SUCCESS;
+}
+
+/* since efiemu_set_virtual_address_map corrects all the pointers 
+   we don't need efiemu_convert_pointer */
+grub_efi_status_t
+EFI_FUNC (efiemu_convert_pointer) (grub_efi_uintn_t debug_disposition, 
+				      void **address)
+{
+  LOG ('f');
+  return GRUB_EFI_UNSUPPORTED;
+}
+
+/* Next comes variable services. Because we have no vendor-independent 
+   way to store these variables we have no non-volatility */
+
+/* Find variable by name and GUID. */
+static struct efi_variable *
+find_variable (grub_efi_guid_t *vendor_guid,
+	       grub_efi_char16_t *variable_name)
+{
+  grub_uint8_t *ptr;
+  struct efi_variable *efivar;
+
+  for (ptr = efiemu_variables; ptr < efiemu_variables + efiemu_varsize; )
+    {
+      efivar = (struct efi_variable *) ptr;
+      if (!efivar->namelen)
+	return 0;
+      if (efiemu_str16equal((grub_efi_char16_t *)(efivar + 1), variable_name)
+	  && efiemu_memequal (&(efivar->guid), vendor_guid, 
+			      sizeof (efivar->guid)))
+	return efivar;
+      ptr += efivar->namelen + efivar->size + sizeof (*efivar);
+    }
+  return 0;
+}
+
+grub_efi_status_t
+EFI_FUNC (efiemu_get_variable) (grub_efi_char16_t *variable_name,
+				   grub_efi_guid_t *vendor_guid,
+				   grub_efi_uint32_t *attributes,
+				   grub_efi_uintn_t *data_size,
+				   void *data)
+{
+  struct efi_variable *efivar;
+  LOG ('g');
+  efivar = find_variable (vendor_guid, variable_name);
+  if (!efivar)
+    return GRUB_EFI_NOT_FOUND;
+  if (*data_size < efivar->size)
+    {
+      *data_size = efivar->size;
+      return GRUB_EFI_BUFFER_TOO_SMALL;
+    }
+  *data_size = efivar->size;
+  efiemu_memcpy (data, (grub_uint8_t *)(efivar + 1) + efivar->namelen,
+		 efivar->size);
+  *attributes = efivar->attributes;
+  
+  return GRUB_EFI_SUCCESS;
+}
+
+grub_efi_status_t EFI_FUNC 
+(efiemu_get_next_variable_name) (grub_efi_uintn_t *variable_name_size,
+				 grub_efi_char16_t *variable_name,
+				 grub_efi_guid_t *vendor_guid)
+{
+  struct efi_variable *efivar;
+  LOG ('l');
+
+  if (!variable_name_size || !variable_name || !vendor_guid)
+    return GRUB_EFI_INVALID_PARAMETER;
+  if (variable_name[0])
+    {
+      efivar = find_variable (vendor_guid, variable_name);
+      if (!efivar)
+	return GRUB_EFI_NOT_FOUND;
+      efivar = (struct efi_variable *)((grub_uint8_t *)efivar 
+				       + efivar->namelen 
+				       + efivar->size + sizeof (*efivar));
+    }
+  else
+    efivar = (struct efi_variable *) (efiemu_variables);
+
+  LOG ('m');
+  if ((grub_uint8_t *)efivar >= efiemu_variables + efiemu_varsize 
+      || !efivar->namelen)
+    return GRUB_EFI_NOT_FOUND;
+  if (*variable_name_size < efivar->namelen)
+    {
+      *variable_name_size = efivar->namelen;
+      return GRUB_EFI_BUFFER_TOO_SMALL;
+    }
+
+  efiemu_memcpy (variable_name, efivar + 1, efivar->namelen);
+  efiemu_memcpy (vendor_guid, &(efivar->guid), 
+		 sizeof (efivar->guid));
+
+  LOG('h');
+  return GRUB_EFI_SUCCESS;
+}
+
+grub_efi_status_t
+EFI_FUNC (efiemu_set_variable) (grub_efi_char16_t *variable_name,
+				   grub_efi_guid_t *vendor_guid,
+				   grub_efi_uint32_t attributes,
+				   grub_efi_uintn_t data_size,
+				   void *data)
+{
+  struct efi_variable *efivar;
+  grub_uint8_t *ptr;
+  LOG('i');
+  if (!variable_name[0])
+    return GRUB_EFI_INVALID_PARAMETER;
+  efivar = find_variable (vendor_guid, variable_name);
+
+  /* Delete variable if any */
+  if (efivar)
+    {
+      efiemu_memcpy (efivar, (grub_uint8_t *)(efivar + 1) 
+		     + efivar->namelen + efivar->size, 
+		     (efiemu_variables + efiemu_varsize)
+		     - ((grub_uint8_t *)(efivar + 1) 
+			+ efivar->namelen + efivar->size));
+      efiemu_memset (efiemu_variables + efiemu_varsize 
+		     - (sizeof (*efivar) + efivar->namelen + efivar->size),
+		     0, (sizeof (*efivar) + efivar->namelen + efivar->size));
+    }
+
+  if (!data_size)
+    return GRUB_EFI_SUCCESS;
+
+  for (ptr = efiemu_variables; ptr < efiemu_variables + efiemu_varsize; )
+    {
+      efivar = (struct efi_variable *) ptr;
+      ptr += efivar->namelen + efivar->size + sizeof (*efivar);
+      if (!efivar->namelen)
+	break;
+    }
+  if ((grub_uint8_t *)(efivar + 1) + data_size 
+      + 2 * (efiemu_str16len (variable_name) + 1) 
+      >= efiemu_variables + efiemu_varsize)
+    return GRUB_EFI_OUT_OF_RESOURCES;
+
+  efiemu_memcpy (&(efivar->guid), vendor_guid, sizeof (efivar->guid));
+  efivar->namelen = 2 * (efiemu_str16len (variable_name) + 1);
+  efivar->size = data_size;
+  efivar->attributes = attributes;
+  efiemu_memcpy (efivar + 1, variable_name, 
+		 2 * (efiemu_str16len (variable_name) + 1));
+  efiemu_memcpy ((grub_uint8_t *)(efivar + 1) 
+		 + 2 * (efiemu_str16len (variable_name) + 1), 
+		 data, data_size);
+
+  return GRUB_EFI_SUCCESS;
+}
+
+grub_efi_status_t EFI_FUNC 
+(efiemu_get_next_high_monotonic_count) (grub_efi_uint32_t *high_count)
+{
+  LOG ('j');
+  if (!high_count)
+    return GRUB_EFI_INVALID_PARAMETER;
+  *high_count = ++efiemu_high_monotonic_count;
+  return GRUB_EFI_SUCCESS;
+}
+
+/* To implement it with APM we need to go to real mode. It's too much hassle
+   Besides EFI specification says that this function shouldn't be used
+   on systems supporting ACPI
+ */
+void
+EFI_FUNC (efiemu_reset_system) (grub_efi_reset_type_t reset_type,
+				   grub_efi_status_t reset_status,
+				   grub_efi_uintn_t data_size,
+				   grub_efi_char16_t *reset_data)
+{
+  LOG ('k');
+}
+
+struct grub_efi_runtime_services efiemu_runtime_services = 
+{
+  .hdr = 
+  {
+    .signature = GRUB_EFIEMU_RUNTIME_SERVICES_SIGNATURE,
+    .revision = 0x0001000a,
+    .header_size = sizeof (struct grub_efi_runtime_services),
+    .crc32 = 0, /* filled later*/
+    .reserved = 0
+  },
+  .get_time = efiemu_get_time,
+  .set_time = efiemu_set_time,
+  .get_wakeup_time = efiemu_get_wakeup_time,
+  .set_wakeup_time = efiemu_set_wakeup_time,
+
+  .set_virtual_address_map = efiemu_set_virtual_address_map,
+  .convert_pointer = efiemu_convert_pointer,
+
+  .get_variable = efiemu_get_variable,
+  .get_next_variable_name = efiemu_get_next_variable_name,
+  .set_variable = efiemu_set_variable,
+  .get_next_high_monotonic_count = efiemu_get_next_high_monotonic_count,
+  
+  .reset_system = efiemu_reset_system
+};
+
+
+static grub_uint16_t efiemu_vendor[] = 
+  {'G', 'R', 'U', 'B', ' ', 'E', 'F', 'I', ' ',
+   'R', 'U', 'N', 'T', 'I', 'M', 'E', 0};
+
+struct grub_efi_system_table efiemu_system_table =
+{
+  .hdr = 
+  {
+    .signature = GRUB_EFIEMU_SYSTEM_TABLE_SIGNATURE,
+    .revision = 0x0001000a,
+    .header_size = sizeof (struct grub_efi_system_table),
+    .crc32 = 0, /* filled later*/
+    .reserved = 0
+  },
+  .firmware_vendor = efiemu_vendor,
+  .firmware_revision = 0x0001000a,
+  .console_in_handler = 0,
+  .con_in = 0,
+  .console_out_handler = 0,
+  .con_out = 0,
+  .standard_error_handle = 0,
+  .std_err = 0,
+  .runtime_services = &efiemu_runtime_services,
+  .boot_services = 0,
+  .num_table_entries = 0,
+  .configuration_table = 0
+};
+
Index: efiemu/runtime/config.h
===================================================================
--- efiemu/runtime/config.h	(revision 0)
+++ efiemu/runtime/config.h	(revision 0)
@@ -0,0 +1,35 @@
+/* This is a pseudo config.h so that types.h compiles nicely */
+/*
+ *  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/>.
+ */
+
+#define GRUB_TYPES_CPU_HEADER	1
+
+#ifdef ELF32
+# define SIZEOF_VOID_P	4
+# define SIZEOF_LONG	4
+# define GRUB_TARGET_SIZEOF_VOID_P	4
+# define GRUB_TARGET_SIZEOF_LONG	4
+# define EFI_FUNC(x) x
+#else
+# define SIZEOF_VOID_P	8
+# define SIZEOF_LONG	8
+# define GRUB_TARGET_SIZEOF_VOID_P	8
+# define GRUB_TARGET_SIZEOF_LONG	8
+# define EFI_FUNC(x) x ## _real
+#endif
+
Index: efiemu/prepare32.c
===================================================================
--- efiemu/prepare32.c	(revision 0)
+++ efiemu/prepare32.c	(revision 0)
@@ -0,0 +1,23 @@
+/* This file contains definitions so that prepare.c compiles for 32-bit */
+/*
+ *  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/>.
+ */
+
+#define SUFFIX(x) x ## 32
+#define TYPE(x) x ## 32_t
+
+#include "prepare.c"
Index: efiemu/main.c
===================================================================
--- efiemu/main.c	(revision 0)
+++ efiemu/main.c	(revision 0)
@@ -0,0 +1,276 @@
+/* This is an emulation of EFI runtime services.
+   This allows a more uniform boot on i386 machines. 
+   As it emulates only runtime service it isn't able 
+   to chainload EFI bootloader on non-EFI system. */
+/*
+ *  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/file.h>
+#include <grub/err.h>
+#include <grub/normal.h>
+#include <grub/mm.h>
+#include <grub/dl.h>
+#include <grub/misc.h>
+#include <grub/efiemu/efiemu.h>
+#include <grub/machine/efiemu.h>
+
+/* System table. Two version depending on mode */
+grub_efi_system_table32_t *grub_efiemu_system_table32 = 0;
+grub_efi_system_table64_t *grub_efiemu_system_table64 = 0;
+/* Modules may need to execute some actions after memory allocation happens */
+static struct grub_efiemu_prepare_hook *efiemu_prepare_hooks = 0;
+/* Linked list of configuration tables */
+static struct grub_efiemu_configuration_table *efiemu_config_tables = 0;
+
+/* Free all allocated space */
+grub_err_t
+grub_efiemu_unload (void)
+{
+  struct grub_efiemu_configuration_table *cur, *d;
+  struct grub_efiemu_prepare_hook *curhook, *d2;
+  grub_efiemu_loadcore_unload ();
+
+  grub_efiemu_mm_unload ();
+
+  for (cur = efiemu_config_tables; cur;)
+    {
+      d = cur->next;
+      if (cur->unload)
+	cur->unload (cur->data);
+      grub_free (cur);
+      cur = d;
+    }
+  efiemu_config_tables = 0;
+
+  for (curhook = efiemu_prepare_hooks; curhook;)
+    {
+      d2 = curhook->next;
+      if (curhook->unload)
+	curhook->unload (curhook->data);
+      grub_free (curhook);
+      curhook = d2;
+    }
+  efiemu_prepare_hooks = 0;
+
+  return GRUB_ERR_NONE;
+}
+
+/* Remove previously registered table from the list */
+grub_err_t
+grub_efiemu_unregister_configuration_table (grub_efi_guid_t guid)
+{
+  struct grub_efiemu_configuration_table *cur, *prev;
+
+  /* Special treating if head is to remove */
+  while (efiemu_config_tables
+	 && !grub_memcmp (&(efiemu_config_tables->guid), &guid, sizeof (guid)))
+    {
+      if (efiemu_config_tables->unload)
+	  efiemu_config_tables->unload (efiemu_config_tables->data);
+	cur = efiemu_config_tables->next;
+	grub_free (efiemu_config_tables);
+	efiemu_config_tables = cur;
+    }
+  if (!efiemu_config_tables)
+    return GRUB_ERR_NONE;
+
+  /* Remove from chain */
+  for (prev = efiemu_config_tables, cur=prev->next;cur;)
+    if (!grub_memcmp (&(cur->guid),&guid, sizeof (guid)))
+      {
+	if (cur->unload)
+	  cur->unload (cur->data);
+	prev->next = cur->next;
+	grub_free (cur);
+	cur = prev->next;
+      }
+    else
+      {
+	prev = cur;
+	cur = cur->next;
+      }
+  return GRUB_ERR_NONE;
+}
+
+grub_err_t
+grub_efiemu_register_prepare_hook (grub_err_t (*hook) (void *data),
+				   void (*unload) (void *data), 
+				   void *data)
+{
+  struct grub_efiemu_prepare_hook *nhook;
+  if (!hook)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT, 
+		       "you must set at least get_table or data");
+  nhook = (struct grub_efiemu_prepare_hook *) grub_malloc (sizeof (*nhook));
+  if (!nhook)
+    return grub_error (GRUB_ERR_OUT_OF_MEMORY, "couldn't prepare hook");
+  nhook->hook = hook;
+  nhook->unload = unload;
+  nhook->data = data;
+  nhook->next = efiemu_prepare_hooks;
+  efiemu_prepare_hooks = nhook;
+  return GRUB_ERR_NONE;
+}
+
+/* Register a configuration table either supplying the address directly 
+   or with a hook
+*/
+grub_err_t
+grub_efiemu_register_configuration_table (grub_efi_guid_t guid, 
+					  void * (*get_table) (void *data),
+					  void (*unload) (void *data), 
+					  void *data)
+{
+  struct grub_efiemu_configuration_table *tbl;
+  grub_err_t err;
+ 
+ if (!get_table && !data)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT, 
+		       "you must set at least get_table or data");
+  if ((err = grub_efiemu_unregister_configuration_table (guid)))
+    return err;
+
+  tbl = (struct grub_efiemu_configuration_table *) grub_malloc (sizeof (*tbl));
+  if (!tbl)
+    return grub_error (GRUB_ERR_OUT_OF_MEMORY, "couldn't register table");
+
+  tbl->guid = guid;
+  tbl->get_table = get_table;
+  tbl->unload = unload;
+  tbl->data = data;
+  tbl->next = efiemu_config_tables;
+  efiemu_config_tables = tbl;
+
+  return GRUB_ERR_NONE;
+}
+
+
+static grub_err_t
+grub_cmd_efiemu_unload (struct grub_arg_list *state __attribute__ ((unused)),
+			int argc __attribute__ ((unused)), 
+			char **args __attribute__ ((unused)))
+{
+  return grub_efiemu_unload ();
+}
+
+static grub_err_t
+grub_cmd_efiemu_prepare (struct grub_arg_list *state __attribute__ ((unused)),
+			int argc __attribute__ ((unused)), 
+			char **args __attribute__ ((unused)))
+{
+  grub_dprintf ("efiemu", "Preparing %d-bit efiemu\n", 
+		8*grub_efiemu_sizeof_uintn_t ());
+  if (grub_efiemu_sizeof_uintn_t () == 4)
+    return grub_efiemu_prepare32 (efiemu_prepare_hooks, efiemu_config_tables);
+  else
+    return grub_efiemu_prepare64 (efiemu_prepare_hooks, efiemu_config_tables);
+}
+
+\f
+
+
+int 
+grub_efiemu_exit_boot_services (grub_efi_uintn_t map_key 
+				__attribute__ ((unused)))
+{
+  /* Nothing to do here yet */
+  return 1;
+}
+
+
+/* Load the runtime from the file FILENAME.  */
+static grub_err_t
+grub_efiemu_load_file (const char *filename)
+{
+  grub_file_t file;
+  grub_err_t err;
+  
+  file = grub_file_open (filename);
+  if (! file)
+    return 0;
+  
+  err = grub_efiemu_mm_init ();
+  if (err)
+    {
+      grub_file_close (file);
+      grub_efiemu_unload ();
+      return grub_error (grub_errno, "Couldn't init memory management");
+    }
+
+  grub_dprintf ("efiemu", "mm inited\n");
+
+  if ((err = grub_efiemu_loadcore_init (file)))
+    {
+      grub_file_close (file);
+      grub_efiemu_unload ();
+      return err;
+    }
+
+  grub_file_close (file);
+
+  /* for configuration tables entry in system table*/
+  grub_efiemu_request_symbols (1);
+
+  return GRUB_ERR_NONE;
+}
+
+
+static grub_err_t
+grub_cmd_efiemu_load (struct grub_arg_list *state __attribute__ ((unused)),
+		      int argc, char **args)
+{
+  grub_err_t err;
+
+  grub_efiemu_unload ();
+
+  if (argc != 1)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT, "filename required");
+
+  if ((err = grub_efiemu_load_file (args[0])))
+    return err;
+#ifndef GRUB_UTIL
+  if ((err = grub_machine_efiemu_init_tables ()))
+    return err;
+#endif
+  return GRUB_ERR_NONE;
+}
+
+
+GRUB_MOD_INIT(efiemu)
+{
+  (void) mod;			/* To stop warning. */
+  grub_register_command ("efiemu_loadcore", grub_cmd_efiemu_load, 
+			 GRUB_COMMAND_FLAG_BOTH,
+			 "efiemu_loadcore FILE", 
+			 "Load and initialize EFI emulator", 0);
+  grub_register_command ("efiemu_prepare", grub_cmd_efiemu_prepare, 
+			 GRUB_COMMAND_FLAG_BOTH,
+			 "efiemu_prepare", 
+			 "Finalize loading of EFI emulator", 0);
+  grub_register_command ("efiemu_unload", grub_cmd_efiemu_unload, 
+			 GRUB_COMMAND_FLAG_BOTH,
+			 "efiemu_unload", 
+			 "Unload  EFI emulator", 0);
+}
+
+GRUB_MOD_FINI(efiemu)
+{
+  grub_unregister_command ("efiemu_loadcore");
+  grub_unregister_command ("efiemu_prepare");
+  grub_unregister_command ("efiemu_unload");
+}

Property changes on: efiemu/main.c
___________________________________________________________________
Added: svn:mergeinfo

Index: efiemu/modules/pnvram.c
===================================================================
--- efiemu/modules/pnvram.c	(revision 0)
+++ efiemu/modules/pnvram.c	(revision 0)
@@ -0,0 +1,355 @@
+/* Export pnvram and some variables for runtime */
+/*
+ *  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/file.h>
+#include <grub/err.h>
+#include <grub/normal.h>
+#include <grub/dl.h>
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/efiemu/efiemu.h>
+#include <grub/efiemu/runtime.h>
+
+/* Place for final location of variables */
+static int nvram_handle = 0;
+static int nvramsize_handle = 0;
+static int high_monotonic_count_handle = 0;
+static int timezone_handle = 0;
+static int accuracy_handle = 0;
+static int daylight_handle = 0;
+
+/* Temporary place */
+static grub_uint8_t *nvram;
+static grub_size_t nvramsize;
+static grub_dl_t my_mod;
+static grub_uint32_t high_monotonic_count;
+static grub_int8_t timezone;
+static grub_uint16_t daylight;
+static grub_uint32_t accuracy;
+
+static const struct grub_arg_option options[] = {
+  {"size", 's', 0, "number of bytes to reserve for pseudo NVRAM", 0,
+   ARG_TYPE_INT},
+  {"high-monotonic-count", 'm', 0, 
+   "Initial value of high monotonic count", 0, ARG_TYPE_INT},
+  {"timezone", 't', 0, 
+   "Timezone, offset in minutes from GMT", 0, ARG_TYPE_INT},
+  {"accuracy", 'a', 0, 
+   "Accuracy of clock, in 1e-12 units", 0, ARG_TYPE_INT},
+  {"daylight", 'd', 0, 
+   "Daylight value, as per EFI specifications", 0, ARG_TYPE_INT},
+  {0, 0, 0, 0, 0, 0}
+};
+
+/* Parse signed value */
+static int
+grub_strtosl (char *arg, char **end, int base)
+{
+  if (arg[0] == '-')
+    return -grub_strtoul (arg + 1, end, base);
+  return grub_strtoul (arg, end, base);
+}
+
+/* Export stuff for efiemu */
+static grub_err_t
+nvram_set (void * data __attribute__ ((unused)))
+{      
+  /* Take definitive pointers */
+  grub_uint8_t *nvram_def = grub_efiemu_mm_obtain_request (nvram_handle);
+  grub_uint32_t *nvramsize_def 
+    = grub_efiemu_mm_obtain_request (nvramsize_handle);
+  grub_uint32_t *high_monotonic_count_def
+    = grub_efiemu_mm_obtain_request (high_monotonic_count_handle);
+  grub_int8_t *timezone_def 
+    = grub_efiemu_mm_obtain_request (timezone_handle);
+  grub_uint16_t *daylight_def
+    = grub_efiemu_mm_obtain_request (daylight_handle);
+  grub_uint32_t *accuracy_def
+    = grub_efiemu_mm_obtain_request (accuracy_handle);
+
+  /* Copy to definitive loaction */
+  grub_dprintf ("efiemu", "preparing pnvram\n");
+  grub_memcpy (nvram_def, nvram, nvramsize);
+  *nvramsize_def = nvramsize;
+  *high_monotonic_count_def = high_monotonic_count;
+  *timezone_def = timezone;
+  *daylight_def = daylight;
+  *accuracy_def = accuracy;
+
+  /* Register symbols */
+  grub_efiemu_register_symbol ("efiemu_variables", nvram_handle, 0);
+  grub_efiemu_register_symbol ("efiemu_varsize", nvramsize_handle, 0);
+  grub_efiemu_register_symbol ("efiemu_high_monotonic_count", 
+			       high_monotonic_count_handle, 0);
+  grub_efiemu_register_symbol ("efiemu_time_zone", timezone_handle, 0);
+  grub_efiemu_register_symbol ("efiemu_time_daylight", daylight_handle, 0);
+  grub_efiemu_register_symbol ("efiemu_time_accuracy", 
+			       accuracy_handle, 0);
+
+  return GRUB_ERR_NONE;
+}
+
+static void
+nvram_unload (void * data __attribute__ ((unused)))
+{
+  grub_efiemu_mm_return_request (nvram_handle);
+  grub_efiemu_mm_return_request (nvramsize_handle);
+  grub_efiemu_mm_return_request (high_monotonic_count_handle);
+  grub_efiemu_mm_return_request (timezone_handle);
+  grub_efiemu_mm_return_request (accuracy_handle);
+  grub_efiemu_mm_return_request (daylight_handle);
+
+  grub_free (nvram);
+  nvram = 0;
+}
+
+/* Load the variables file It's in format
+   guid1:attr1:name1:data1;
+   guid2:attr2:name2:data2;
+   ...
+   Where all fields are in hex
+*/
+static grub_err_t
+read_pnvram (char *filename)
+{
+  char *buf, *ptr, *ptr2;
+  grub_file_t file;
+  grub_size_t size;
+  grub_uint8_t *nvramptr = nvram;
+  struct efi_variable *efivar;
+  grub_size_t guidlen, datalen;
+  unsigned i, j;
+  
+  file = grub_file_open (filename);
+  if (!file)
+    return grub_error (GRUB_ERR_BAD_OS, "couldn't read pnvram");
+  size = grub_file_size (file);
+  buf = grub_malloc (size + 1);
+  if (!buf)
+    return grub_error (GRUB_ERR_OUT_OF_MEMORY, "couldn't read pnvram");
+  if (grub_file_read (file, buf, size) != (grub_ssize_t) size)
+    return grub_error (GRUB_ERR_BAD_OS, "couldn't read pnvram");
+  buf[size] = 0;
+  grub_file_close (file);
+
+  for (ptr = buf; *ptr; )
+    {
+      if (grub_isspace (*ptr))
+	{
+	  ptr++;
+	  continue;
+	}
+
+      efivar = (struct efi_variable *) nvramptr;
+      if (nvramptr - nvram + sizeof (struct efi_variable) > nvramsize)
+	return grub_error (GRUB_ERR_OUT_OF_MEMORY, 
+			   "file is too large for reserved variable space");
+
+      nvramptr += sizeof (struct efi_variable);
+
+      /* look ahow long guid field is*/
+      guidlen = 0;      
+      for (ptr2 = ptr; (grub_isspace (*ptr2) 
+			|| (*ptr2 >= '0' && *ptr2 <= '9')
+			|| (*ptr2 >= 'a' && *ptr2 <= 'f')
+			|| (*ptr2 >= 'A' && *ptr2 <= 'F')); 
+	   ptr2++)
+	if (!grub_isspace (*ptr2))
+	  guidlen++;
+      guidlen /= 2;
+
+      /* Read guid */
+      if (guidlen != sizeof (efivar->guid))
+	{   
+	  grub_free (buf);
+	  return grub_error (GRUB_ERR_BAD_OS, "can't parse %s", filename);
+	}
+      for (i = 0; i < 2 * sizeof (efivar->guid); i++)
+	{
+	  int hex = 0;
+	  while (grub_isspace (*ptr))
+	    ptr++;
+	  if (*ptr >= '0' && *ptr <= '9')
+	    hex = *ptr - '0';
+	  if (*ptr >= 'a' && *ptr <= 'f')
+	    hex = *ptr - 'a' + 10;
+	  if (*ptr >= 'A' && *ptr <= 'F')
+	    hex = *ptr - 'A' + 10;
+	  
+	  if (i%2 == 0)
+	    ((grub_uint8_t *)&(efivar->guid))[i/2] = hex << 4;
+	  else
+	    ((grub_uint8_t *)&(efivar->guid))[i/2] |= hex;
+	  ptr++;
+	}
+      
+      while (grub_isspace (*ptr))
+	ptr++;
+      if (*ptr != ':')
+	{
+	  grub_dprintf ("efiemu", "Not colon\n");
+	  grub_free (buf);
+	  return grub_error (GRUB_ERR_BAD_OS, "can't parse %s", filename);
+	}
+      ptr++;
+      while (grub_isspace (*ptr))
+	ptr++;
+
+      /* Attributes can be just parsed by existing functions */
+      efivar->attributes = grub_strtoul (ptr, &ptr, 16);
+
+      while (grub_isspace (*ptr))
+	ptr++;
+      if (*ptr != ':')
+	{
+	  grub_dprintf ("efiemu", "Not colon\n");
+	  grub_free (buf);
+	  return grub_error (GRUB_ERR_BAD_OS, "can't parse %s", filename);
+	}
+      ptr++;
+      while (grub_isspace (*ptr))
+	ptr++;
+
+      /* Read name and value */
+      for (j = 0; j < 2; j++)
+	{
+	  /* Look the length */
+	  datalen = 0;
+	  for (ptr2 = ptr; *ptr2 && (grub_isspace (*ptr2) 
+				     || (*ptr2 >= '0' && *ptr2 <= '9')
+				     || (*ptr2 >= 'a' && *ptr2 <= 'f')
+				     || (*ptr2 >= 'A' && *ptr2 <= 'F')); 
+	       ptr2++)
+	    if (!grub_isspace (*ptr2))
+	      datalen++;
+	  datalen /= 2;
+	 
+	  if (nvramptr - nvram + datalen > nvramsize)
+	    {
+	      grub_free (buf);
+	      return grub_error (GRUB_ERR_OUT_OF_MEMORY, 
+				 "file is too large for reserved "
+				 " variable space");
+	    }
+	  
+	  for (i = 0; i < 2 * datalen; i++)
+	    {
+	      int hex = 0;
+	      while (grub_isspace (*ptr))
+		ptr++;
+	      if (*ptr >= '0' && *ptr <= '9')
+		hex = *ptr - '0';
+	      if (*ptr >= 'a' && *ptr <= 'f')
+		hex = *ptr - 'a' + 10;
+	      if (*ptr >= 'A' && *ptr <= 'F')
+		hex = *ptr - 'A' + 10;
+	      
+	      if (i%2 == 0)
+		nvramptr[i/2] = hex << 4;
+	      else
+		nvramptr[i/2] |= hex;
+	      ptr++;
+	    }
+	  nvramptr += datalen;
+	  while (grub_isspace (*ptr))
+	    ptr++;
+	  if (*ptr != (j ? ';' : ':'))
+	    {
+	      grub_free (buf);
+	      grub_dprintf ("efiemu", j?"Not semicolon\n":"Not colon\n");
+	      return grub_error (GRUB_ERR_BAD_OS, "can't parse %s", filename);
+	    }
+	  if (j)
+	    efivar->size = datalen;
+	  else
+	    efivar->namelen = datalen;
+	  
+	  ptr++;
+	}
+    }
+  grub_free (buf);
+  return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_cmd_efiemu_pnvram (struct grub_arg_list *state,
+		       int argc, char **args)
+{
+  grub_err_t err;
+
+  if (argc > 1)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT, "only one argument expected");
+
+  nvramsize = state[0].set ? grub_strtoul (state[0].arg, 0, 0) : 2048;
+  high_monotonic_count = state[1].set ? grub_strtoul (state[1].arg, 0, 0) : 1;
+  timezone = state[2].set ? grub_strtosl (state[2].arg, 0, 0) 
+    : GRUB_EFI_UNSPECIFIED_TIMEZONE;
+  accuracy = state[3].set ? grub_strtoul (state[3].arg, 0, 0) : 50000000;
+  daylight = state[4].set ? grub_strtoul (state[4].arg, 0, 0) : 0;
+  
+  nvram = grub_malloc (nvramsize);
+  if (!nvram)
+    return grub_error (GRUB_ERR_OUT_OF_MEMORY, 
+		       "Couldn't allocate space for temporary pnvram storage");
+  grub_memset (nvram, 0, nvramsize);  
+
+  if (argc == 1 && (err = read_pnvram (args[0])))
+    {
+      grub_free (nvram);
+      return err;
+    }
+
+  if ((err = grub_efiemu_register_prepare_hook (nvram_set, nvram_unload, 0)))
+    {
+      grub_free (nvram);
+      return err;
+    }
+  nvram_handle 
+    = grub_efiemu_request_memalign (1, nvramsize, 
+				    GRUB_EFI_RUNTIME_SERVICES_DATA);
+  nvramsize_handle 
+    = grub_efiemu_request_memalign (1, sizeof (grub_uint32_t), 
+				    GRUB_EFI_RUNTIME_SERVICES_DATA);
+  high_monotonic_count_handle
+    = grub_efiemu_request_memalign (1, sizeof (grub_uint32_t), 
+				    GRUB_EFI_RUNTIME_SERVICES_DATA);
+  grub_efiemu_request_symbols (6);
+#ifndef GRUB_UTIL
+  grub_dl_ref (my_mod);
+#endif
+  return GRUB_ERR_NONE;
+}
+
+
+
+GRUB_MOD_INIT(efiemu_pnvram)
+{
+  (void) mod;			/* To stop warning. */
+  grub_register_command ("efiemu_pnvram", grub_cmd_efiemu_pnvram, 
+			 GRUB_COMMAND_FLAG_BOTH,
+			 "efiemu_pnvram [FILENAME]",
+			 "Initialise pseudo-NVRAM and load variables from FILE", 
+			 options);
+  my_mod=mod;
+}
+
+GRUB_MOD_FINI(efiemu_pnvram)
+{
+  grub_unregister_command ("efiemu_pnvram");
+}

Property changes on: efiemu/modules/pnvram.c
___________________________________________________________________
Added: svn:mergeinfo

Index: efiemu/modules/acpi.c
===================================================================
--- efiemu/modules/acpi.c	(revision 0)
+++ efiemu/modules/acpi.c	(revision 0)
@@ -0,0 +1,592 @@
+/* Register and manipulate ACPI tables */
+/*
+ *  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/normal.h>
+#include <grub/dl.h>
+#include <grub/arg.h>
+#include <grub/file.h>
+#include <grub/disk.h>
+#include <grub/term.h>
+#include <grub/misc.h>
+#include <grub/gzio.h>
+#include <grub/efiemu/efiemu.h>
+#include <grub/acpi.h>
+#include <grub/mm.h>
+
+static const struct grub_arg_option options[] = {
+  {"exclude", 'x', 0, 
+   "Don't load host tables specified by comma-separated list", 
+   0, ARG_TYPE_STRING},
+  {"load-only", 'n', 0, 
+   "Load only tables specified by comma-separated list", 0, ARG_TYPE_STRING},
+  {"v1", '1', 0, "Expose v1 tables", 0, ARG_TYPE_NONE},
+  {"v2", '2', 0, "Expose v2 and v3 tables", 0, ARG_TYPE_NONE},
+  {"oemid", 'o', 0, "Set OEMID of RSDP, XSDT and RSDT", 0, ARG_TYPE_STRING},
+  {"oemtable", 't', 0, 
+   "Set OEMTABLE ID of RSDP, XSDT and RSDT", 0, ARG_TYPE_STRING},  
+  {"oemtablerev", 'r', 0, 
+   "Set OEMTABLE revision of RSDP, XSDT and RSDT", 0, ARG_TYPE_INT},  
+  {"oemtablecreator", 'c', 0, 
+   "Set creator field of RSDP, XSDT and RSDT", 0, ARG_TYPE_STRING},  
+  {"oemtablecreatorrev", 'd', 0, 
+   "Set creator revision of RSDP, XSDT and RSDT", 0, ARG_TYPE_INT},  
+  {0, 0, 0, 0, 0, 0}
+};
+
+/* rev1 is 1 if ACPIv1 is to be generated, 0 otherwise. 
+   rev2 contains the revision of ACPIv2+ to generate or 0 if */
+static int rev1, rev2;
+static grub_dl_t my_mod;
+/* OEMID of RSDP, RSDT and XSDT */
+static char root_oemid[6];
+/* OEMTABLE of the same tables */
+static char root_oemtable[8];
+/* OEMREVISION of the same tables */
+static grub_uint32_t root_oemrev;
+/* CreatorID of the same tables */
+static char root_creator_id[4];
+/* CreatorRevision of the same tables */
+static grub_uint32_t root_creator_rev;
+
+/* Linked list of ACPI tables */
+struct efiemu_acpi_table
+{
+  void *data;
+  void *addr;
+  grub_size_t size;
+  int alloc_handle;
+  struct efiemu_acpi_table *next;
+};
+static struct efiemu_acpi_table *acpi_tables = 0;
+
+/* DSDT isn't in RSDT. So treat it specially */
+static void *table_dsdt = 0;
+/* Pointer to recreated RSDT*/
+static void *rsdt_addr = 0;
+
+/* Allocation handles for different tables */
+static int dsdt_alloc_handle = 0;
+static grub_size_t dsdt_size = 0;
+static int rsdpv1_alloc_handle = 0;
+static int rsdpv2_alloc_handle = 0;
+static int rsdt_alloc_handle = 0;
+static int xsdt_alloc_handle = 0;
+
+/* Address of original FACS */
+static grub_uint32_t facs_addr = 0;
+
+/* Are RDSP and FACP already generated */
+static int tables_set = 0;
+static int locked = 0;
+
+/* Free common v1 & v2 structures */
+static void
+grub_efiemu_acpi_clear (void)
+{
+  static struct efiemu_acpi_table *cur, *d;
+  for (cur = acpi_tables; cur; )
+    {
+      grub_free (cur->data);
+      d = cur->next;
+      grub_free (cur);
+      cur = d;
+    }
+
+  acpi_tables = 0;
+  grub_free (table_dsdt);
+  table_dsdt = 0;
+  dsdt_size = 0;
+  dsdt_alloc_handle = 0;
+  rev1 = rev2 = 0;
+
+  grub_efiemu_mm_return_request (dsdt_alloc_handle);
+  grub_efiemu_mm_return_request (rsdpv1_alloc_handle);
+  grub_efiemu_mm_return_request (rsdpv2_alloc_handle);
+  grub_efiemu_mm_return_request (rsdt_alloc_handle);
+  grub_efiemu_mm_return_request (xsdt_alloc_handle);
+
+  dsdt_alloc_handle = 0;
+  rsdpv1_alloc_handle = 0;
+  rsdpv2_alloc_handle = 0;
+  rsdt_alloc_handle = 0;
+  xsdt_alloc_handle = 0;
+
+  tables_set = 0;
+  rsdt_addr = 0;
+
+  if (locked)
+    grub_dl_unref (my_mod);
+}
+
+static void
+unloadv1table (void *data __attribute__ ((unused)))
+{
+  rev1 = 0;
+  grub_efiemu_mm_return_request (rsdpv1_alloc_handle);
+  rsdpv1_alloc_handle = 0;
+
+  /* If we have no ACPIv2+ free common structures */
+  if (!rev2)
+    grub_efiemu_acpi_clear ();
+}
+
+static void
+unloadv2table (void *data __attribute__ ((unused)))
+{
+  rev2 = 0;
+  grub_efiemu_mm_return_request (rsdpv2_alloc_handle);
+  grub_efiemu_mm_return_request (xsdt_alloc_handle);
+  rsdpv2_alloc_handle = 0;
+  xsdt_alloc_handle = 0;
+
+  /* If we have no ACPIv1 free common structures */
+  if (!rev1)
+    grub_efiemu_acpi_clear ();
+}
+
+/* Create tables common to ACPIv1 and ACPIv2+ */
+static void
+setup_common_tables (void)
+{
+  struct efiemu_acpi_table *cur;
+  void *dest;
+  void *dsdt_addr = 0;
+  struct grub_acpi_table_header *rsdt;
+  grub_uint32_t *rsdt_entry;
+  int numoftables;
+
+  /* Don't redo the same job twice */
+  if (tables_set)
+    return;
+
+  /* Copy override dsdt if any */
+  if (table_dsdt)
+    {
+      dsdt_addr = grub_efiemu_mm_obtain_request (dsdt_alloc_handle);
+      grub_memcpy (dsdt_addr, table_dsdt, dsdt_size);
+    }
+  
+  /* Copy other tables */
+  for (cur = acpi_tables; cur; cur = cur->next)
+    {
+      struct grub_acpi_fadt *fadt;
+
+      cur->addr = dest = grub_efiemu_mm_obtain_request (cur->alloc_handle);
+      grub_memcpy (dest, cur->data, cur->size);
+
+      /* If it's FADT correct DSDT and FACS addresses */
+      fadt = (struct grub_acpi_fadt *) dest;
+      if (!grub_memcmp (fadt->hdr.signature, "FACP", 4))
+	{
+	  fadt->dsdt_addr = PTR_TO_UINT32 (dsdt_addr);
+	  fadt->facs_addr = facs_addr;
+
+	  /* Does a revision 2 exist at all? */
+	  if (fadt->hdr.revision >= 3)
+	    {
+	      fadt->dsdt_xaddr = PTR_TO_UINT64 (dsdt_addr);
+	      fadt->facs_xaddr = facs_addr;
+	    }
+
+	  /* Recompute checksum */
+	  fadt->hdr.checksum = 0;
+	  fadt->hdr.checksum = 1 + ~grub_byte_checksum (fadt, fadt->hdr.length);
+	}
+    }
+ 
+  /* Fill RSDT entries */
+  rsdt_addr = rsdt = (struct grub_acpi_table_header *) 
+    grub_efiemu_mm_obtain_request (rsdt_alloc_handle);
+  rsdt_entry = (grub_uint32_t *)(rsdt + 1);
+  numoftables = 0;
+  for (cur = acpi_tables; cur; cur = cur->next)
+    {
+      *(rsdt_entry++) = PTR_TO_UINT32 (cur->addr);
+      numoftables++;
+    }
+
+  /* Fill RSDT header */
+  grub_memcpy (&(rsdt->signature), "RSDT", 4);
+  rsdt->length = sizeof (struct grub_acpi_table_header) + 4 * numoftables;
+  rsdt->revision = 1;
+  grub_memcpy (&(rsdt->oemid), root_oemid, 6);
+  grub_memcpy (&(rsdt->oemtable), root_oemtable, 4);
+  rsdt->oemrev = root_oemrev;
+  grub_memcpy (&(rsdt->creator_id), root_creator_id, 6);
+  rsdt->creator_rev = root_creator_rev;
+  
+  /* Recompute checksum */
+  rsdt->checksum = 0;
+  rsdt->checksum = 1 + ~grub_byte_checksum (rsdt, rsdt->length);
+}
+
+/* Get address of regenerated ACPIv1 RSDP */
+static void *
+getv1table (void *data __attribute__ ((unused)))
+{
+  struct grub_acpi_rsdp_v10 *rsdp;
+
+  setup_common_tables ();
+
+  /* Create RSDP */
+  rsdp = (struct grub_acpi_rsdp_v10 *) 
+    grub_efiemu_mm_obtain_request (rsdpv1_alloc_handle);
+  grub_memcpy (&(rsdp->signature), "RSD PTR ", 8);
+  grub_memcpy (&(rsdp->oemid), root_oemid, sizeof  (rsdp->oemid));
+  rsdp->revision = 0;
+  rsdp->rsdt_addr = PTR_TO_UINT32 (rsdt_addr);
+  rsdp->checksum = 0;
+  rsdp->checksum = 1 + ~grub_byte_checksum (rsdp, sizeof (*rsdp));  
+  grub_dprintf ("efiemu", "Generated ACPIv1 tables\n");
+
+  return rsdp;
+}
+
+static void *
+getv2table (void *data __attribute__ ((unused)))
+{
+  struct grub_acpi_rsdp_v20 *rsdp;
+  struct grub_acpi_table_header *xsdt;
+  struct efiemu_acpi_table *cur;
+  grub_uint64_t *xsdt_entry;
+  int numoftables;
+
+  setup_common_tables ();
+
+  /* Create XSDT */
+  xsdt = (struct grub_acpi_table_header *) 
+    grub_efiemu_mm_obtain_request (xsdt_alloc_handle);
+  xsdt_entry = (grub_uint64_t *)(xsdt + 1);
+  numoftables = 0;
+  for (cur = acpi_tables; cur; cur = cur->next)
+    {
+      *(xsdt_entry++) = PTR_TO_UINT64 (cur->addr);
+      numoftables++;
+    }
+  grub_memcpy (&(xsdt->signature), "XSDT", 4);
+  xsdt->length = sizeof (struct grub_acpi_table_header) + 8 * numoftables;
+  xsdt->revision = 1;
+  grub_memcpy (&(xsdt->oemid), root_oemid, sizeof (xsdt->oemid));
+  grub_memcpy (&(xsdt->oemtable), root_oemtable, sizeof (xsdt->oemtable));
+  xsdt->oemrev = root_oemrev;
+  grub_memcpy (&(xsdt->creator_id), root_creator_id, sizeof (xsdt->creator_id));
+  xsdt->creator_rev = root_creator_rev;
+  xsdt->checksum = 0;
+  xsdt->checksum = 1 + ~grub_byte_checksum (xsdt, xsdt->length);
+
+  /* Create RSDP */
+  rsdp = (struct grub_acpi_rsdp_v20 *) 
+    grub_efiemu_mm_obtain_request (rsdpv2_alloc_handle);
+  grub_memcpy (&(rsdp->rsdpv1.signature), "RSD PTR ", 
+	       sizeof (rsdp->rsdpv1.signature));
+  grub_memcpy (&(rsdp->rsdpv1.oemid), root_oemid, sizeof (rsdp->rsdpv1.oemid));
+  rsdp->rsdpv1.revision = rev2;
+  rsdp->rsdpv1.rsdt_addr = PTR_TO_UINT32 (rsdt_addr);
+  rsdp->rsdpv1.checksum = 0;
+  rsdp->rsdpv1.checksum = 1 + ~grub_byte_checksum 
+    (&(rsdp->rsdpv1), sizeof (rsdp->rsdpv1));
+  rsdp->length = sizeof (*rsdp);
+  rsdp->xsdt_addr = PTR_TO_UINT64 (xsdt);
+  rsdp->checksum = 0;
+  rsdp->checksum = 1 + ~grub_byte_checksum (rsdp, rsdp->length);
+  grub_dprintf ("efiemu", "Generated ACPIv2 tables\n");
+  
+  return rsdp;
+}
+
+static grub_err_t
+grub_cmd_efiemu_acpi (struct grub_arg_list *state,
+		      int argc, char **args)
+{
+  grub_efi_guid_t acpi20 = GRUB_EFI_ACPI_20_TABLE_GUID;
+  grub_efi_guid_t acpi =  GRUB_EFI_ACPI_TABLE_GUID;
+  struct grub_acpi_rsdp_v10 *rsdp;
+  int i;
+  int numtables;
+  
+  grub_efiemu_unregister_configuration_table (acpi);  
+  grub_efiemu_unregister_configuration_table (acpi20);  
+
+  /* Default values if no RSDP is found */
+  rev1 = 1;
+  rev2 = 3;
+
+  facs_addr = 0;
+  
+  rsdp = grub_machine_acpi_get_rsdp ();
+
+  if (rsdp)
+    {
+      grub_uint32_t *entry_ptr;
+      char *exclude = 0;
+      char *load_only = 0;
+      char *ptr;
+      /* RSDT consists of header and an array of 32-bit pointers */
+      struct grub_acpi_table_header *rsdt;
+
+      exclude = state[0].set ? grub_strdup (state[0].arg) : 0;
+      if (exclude)
+	{
+	  for (ptr = exclude; ptr; ptr++)
+	    *ptr = grub_tolower (*ptr);
+	}
+
+      load_only = state[1].set ? grub_strdup (state[1].arg) : 0;
+      if (load_only)
+	{
+	  for (ptr = load_only; ptr; ptr++)
+	    *ptr = grub_tolower (*ptr);
+	}
+
+      /* Set revision variables to replicant the same version as host */
+      rev1 = !rsdp->revision;
+      rev2 = rsdp->revision;
+      rsdt = (struct grub_acpi_table_header *)(rsdp->rsdt_addr);
+      /* Load host tables */
+      for (entry_ptr = (grub_uint32_t *)(rsdt + 1);
+	   entry_ptr < (grub_uint32_t *)(((grub_uint8_t *) rsdt)+rsdt->length);
+	   entry_ptr++)
+	{
+	  char signature[5];
+	  struct efiemu_acpi_table *table;
+	  struct grub_acpi_table_header *curtable 
+	    = (struct grub_acpi_table_header *)*entry_ptr;
+	  signature[4] = 0;
+	  for (i = 0; i < 4;i++)
+	    signature[i] = grub_tolower (curtable->signature[i]);
+	  
+	  /* If it's FADT it contains addresses of DSDT and FACS */
+	  if (!grub_strcmp (signature, "facp"))
+	    {
+	      struct grub_acpi_table_header *dsdt;
+	      struct grub_acpi_fadt *fadt = (struct grub_acpi_fadt *) curtable;
+
+	      /* Set root header variables to the same values 
+		 as FACP by default */
+	      grub_memcpy (&root_oemid, &(fadt->hdr.oemid), 
+			   sizeof (root_oemid));
+	      grub_memcpy (&root_oemtable, &(fadt->hdr.oemtable), 
+			   sizeof (root_oemtable));
+	      root_oemrev = fadt->hdr.oemrev;
+	      grub_memcpy (&root_creator_id, &(fadt->hdr.creator_id), 
+			   sizeof (root_creator_id));
+	      root_creator_rev = fadt->hdr.creator_rev;
+
+	      /* Load DSDT if not excluded */
+	      dsdt = (struct grub_acpi_table_header *) fadt->dsdt_addr;
+	      if (dsdt && (!exclude || !grub_strword (exclude, "dsdt"))
+		  && (!load_only || grub_strword (load_only, "dsdt"))
+		  && dsdt->length >= sizeof (*dsdt))
+		{
+		  dsdt_size = dsdt->length;
+		  table_dsdt = grub_malloc (dsdt->length);
+		  if (!table_dsdt)
+		    {
+		      grub_efiemu_acpi_clear ();
+		      return grub_error (GRUB_ERR_OUT_OF_MEMORY, 
+					 "Could allocate table");
+		    }
+		  grub_memcpy (table_dsdt, dsdt, dsdt->length);
+		}
+
+	      /* Save FACS address. FACS shouldn't be overriden */
+	      facs_addr = fadt->facs_addr;
+	    }
+  
+	  /* skip excluded tables */
+	  if (exclude && grub_strword (exclude, signature))
+	    continue;
+	  if (load_only && !grub_strword (load_only, signature))
+	    continue;
+
+	  /* Sanity check */
+	  if (curtable->length < sizeof (*curtable))
+	    continue;
+	  
+	  table = (struct efiemu_acpi_table *) grub_malloc 
+	    (sizeof (struct efiemu_acpi_table));
+	  if (!table)
+	    {
+	      grub_efiemu_acpi_clear ();
+	      return grub_error (GRUB_ERR_OUT_OF_MEMORY, 
+				 "Could allocate table structure");
+	    }
+	  table->size = curtable->length;
+	  table->data = grub_malloc (table->size);
+	  if (!table->data)
+	    {
+	      grub_efiemu_acpi_clear ();
+	      return grub_error (GRUB_ERR_OUT_OF_MEMORY, 
+				 "Could allocate table");
+	    }
+	  table->alloc_handle = 0;
+	  table->next = acpi_tables;
+	  acpi_tables = table;
+	  grub_memcpy (table->data, curtable, table->size);
+	}
+      grub_free (exclude);
+      grub_free (load_only);      
+    }
+
+  /* Does user specify versions to generate ? */
+  if (state[2].set || state[3].set)
+    {
+      rev1 = state[2].set;
+      if (state[3].set)
+	rev2 = rev2 ? : 2;
+      else
+	rev2 = 0;
+    }
+
+  /* Does user override root header information? */
+  if (state[4].set)
+    grub_strncpy (root_oemid, state[4].arg, sizeof (root_oemid));
+  if (state[5].set)
+    grub_strncpy (root_oemtable, state[5].arg, sizeof (root_oemtable));
+  if (state[6].set)
+    root_oemrev = grub_strtoul (state[6].arg, 0, 0);
+  if (state[7].set)
+    grub_strncpy (root_creator_id, state[7].arg, sizeof (root_creator_id));
+  if (state[8].set)
+    root_creator_rev = grub_strtoul (state[8].arg, 0, 0);
+
+  /* Load user tables */
+  for (i = 0; i < argc; i++)
+    {
+      grub_file_t file;
+      grub_size_t size;
+      char *buf;
+
+      file = grub_gzfile_open (args[i], 1);
+      if (!file)
+	{
+	  grub_efiemu_acpi_clear ();
+	  return grub_error (GRUB_ERR_BAD_OS, "couldn't open file %s", args[i]);
+	}
+
+      size = grub_file_size (file);
+      if (size < sizeof (struct grub_acpi_table_header))
+	{
+	  grub_file_close (file);
+	  grub_efiemu_acpi_clear ();
+	  return grub_error (GRUB_ERR_BAD_OS, "file %s is too small", args[i]);
+	}
+
+      buf = (char *) grub_malloc (size);
+      if (grub_file_read (file, buf, size) != (int) size)
+	{
+	  grub_file_close (file);
+	  grub_efiemu_acpi_clear ();
+	  return grub_error (GRUB_ERR_BAD_OS, "couldn't read file %s", args[i]);
+	}
+      grub_file_close (file);      
+
+      if (!grub_memcmp (((struct grub_acpi_table_header *) buf)->signature, 
+			"DSDT", 4))
+	{
+	  grub_free (table_dsdt);
+	  table_dsdt = buf;
+	  dsdt_size = size;
+	}
+      else
+	{
+	  struct efiemu_acpi_table *table;
+	  table = (struct efiemu_acpi_table *) grub_malloc 
+	    (sizeof (struct efiemu_acpi_table));
+	  if (!table)
+	    {
+	      grub_efiemu_acpi_clear ();
+	      return grub_error (GRUB_ERR_OUT_OF_MEMORY, 
+				 "Could allocate table structure");
+	    }
+	  table->alloc_handle = 0;
+	  table->size = size;
+	  table->data = buf;
+	}
+    }
+
+  /* Request space for normal tables */
+  numtables = 0;
+  {
+    struct efiemu_acpi_table *cur;
+    for (cur = acpi_tables; cur; cur = cur->next)
+      {
+	cur->alloc_handle = grub_efiemu_request_memalign 
+	  (1, cur->size, GRUB_EFI_ACPI_RECLAIM_MEMORY);
+	numtables++;
+      }
+  }
+
+  /* Request space for RSDT */
+  rsdt_alloc_handle = grub_efiemu_request_memalign 
+    (1, sizeof (struct grub_acpi_table_header)+4*numtables, 
+     GRUB_EFI_ACPI_RECLAIM_MEMORY);
+
+  /* Request space for RSDPv1 */
+  if (rev1)
+    {
+      rsdpv1_alloc_handle = grub_efiemu_request_memalign 
+	(1, sizeof (struct grub_acpi_rsdp_v10), 
+	 GRUB_EFI_ACPI_RECLAIM_MEMORY);
+      grub_efiemu_register_configuration_table (acpi, getv1table,
+						unloadv1table, 0);
+    }
+
+  /* Request space for RSDPv2+ and XSDT */
+  if (rev2)
+    {
+      rsdpv2_alloc_handle = grub_efiemu_request_memalign 
+	(1, sizeof (struct grub_acpi_rsdp_v20), 
+	 GRUB_EFI_ACPI_RECLAIM_MEMORY);
+      xsdt_alloc_handle = grub_efiemu_request_memalign 
+	(1, sizeof (struct grub_acpi_table_header)+8*numtables, 
+	 GRUB_EFI_ACPI_RECLAIM_MEMORY);
+      grub_efiemu_register_configuration_table (acpi20, getv2table,
+						unloadv2table, 0);
+    }
+
+  /* Request space for DSDT */
+  if (dsdt_size)
+    dsdt_alloc_handle = grub_efiemu_request_memalign 
+      (1, dsdt_size, GRUB_EFI_ACPI_RECLAIM_MEMORY);
+
+  /* Lock the module */
+  grub_dl_ref (my_mod);
+  locked = 1;
+  return GRUB_ERR_NONE;
+}
+
+GRUB_MOD_INIT(efiemu_acpi)
+{
+  (void) mod;			/* To stop warning. */
+  grub_register_command ("efiemu_acpi", grub_cmd_efiemu_acpi, 
+			 GRUB_COMMAND_FLAG_BOTH,
+			 "efiemu_acpi [-1|-2] [--exclude=table1,table2|"
+			 "--load-only=table1,table2] filename1 [filename2] "
+			 "[...]",
+			 "Load host acpi tables and tables "
+			 "specified by arguments", 
+			 options);
+  my_mod=mod;
+}
+
+GRUB_MOD_FINI(efiemu_acpi)
+{
+  grub_unregister_command ("efiemu_acpi");
+}
Index: efiemu/i386/pc/cfgtables.c
===================================================================
--- efiemu/i386/pc/cfgtables.c	(revision 0)
+++ efiemu/i386/pc/cfgtables.c	(revision 0)
@@ -0,0 +1,46 @@
+/* Find SMBIOS table */
+/*
+ *  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/err.h>
+#include <grub/efiemu/efiemu.h>
+#include <grub/machine/efiemu.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+
+grub_err_t
+grub_machine_efiemu_init_tables ()
+{
+  grub_uint8_t *ptr;
+  grub_efi_guid_t smbios = GRUB_EFI_SMBIOS_TABLE_GUID;
+
+
+  for (ptr = (grub_uint8_t *) 0xf0000; ptr < (grub_uint8_t *) 0x100000; 
+       ptr += 16)
+    if (!grub_memcmp (ptr, "_SM_", 4) 
+	&& grub_efiemu_byte_checksum (ptr, *(ptr+5)) == 0)
+      break;
+
+  if (ptr < (grub_uint8_t *)0x100000)
+    {
+      grub_dprintf ("efiemu", "Registering SMBIOS\n");
+      grub_efiemu_register_configuration_table (smbios, 0, 0, ptr);
+    }
+
+  return GRUB_ERR_NONE;
+}

Property changes on: efiemu/i386/pc/cfgtables.c
___________________________________________________________________
Added: svn:mergeinfo

Index: efiemu/i386/loadcore64.c
===================================================================
--- efiemu/i386/loadcore64.c	(revision 0)
+++ efiemu/i386/loadcore64.c	(revision 0)
@@ -0,0 +1,121 @@
+/* i386 CPU-specific part of loadcore.c for 32-bit mode */
+/*
+ *  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/err.h>
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/efiemu/efiemu.h>
+#include <grub/cpu/efiemu.h>
+#include <grub/elf.h>
+
+/* Check if EHDR is a valid ELF header.  */
+int
+grub_arch_efiemu_check_header64 (void *ehdr)
+{
+  Elf64_Ehdr *e = ehdr;
+
+  return (e->e_ident[EI_CLASS] == ELFCLASS64
+	  && e->e_ident[EI_DATA] == ELFDATA2LSB
+	  && e->e_machine == EM_X86_64);
+}
+
+/* Relocate symbols.  */
+grub_err_t
+grub_arch_efiemu_relocate_symbols64 (grub_efiemu_segment_t segs, 
+				     struct grub_efiemu_elf_sym *elfsyms,
+				     void *ehdr)
+{
+  unsigned i;
+  Elf64_Ehdr *e = ehdr;
+  Elf64_Shdr *s;
+  grub_err_t err;
+
+  for (i = 0, s = (Elf64_Shdr *) ((char *) e + e->e_shoff);
+       i < e->e_shnum;
+       i++, s = (Elf64_Shdr *) ((char *) s + e->e_shentsize))
+    if (s->sh_type == SHT_RELA)
+      {
+	grub_efiemu_segment_t seg;
+	grub_dprintf ("efiemu", "shtrel\n");
+
+	/* Find the target segment.  */
+	for (seg = segs; seg; seg = seg->next)
+	  if (seg->section == s->sh_info)
+	    break;
+
+	if (seg)
+	  {
+	    Elf64_Rela *rel, *max;
+	    
+	    for (rel = (Elf64_Rela *) ((char *) e + s->sh_offset),
+		   max = rel + (unsigned long) s->sh_size 
+		   / (unsigned long)s->sh_entsize;
+		 rel < max;
+		 rel++)
+	      {
+		void *addr;
+		grub_uint32_t *addr32;
+		grub_uint64_t *addr64;
+		struct grub_efiemu_elf_sym sym;
+		if (seg->size < rel->r_offset)
+		  return grub_error (GRUB_ERR_BAD_MODULE,
+				     "reloc offset is out of the segment");
+		
+		addr =
+		  ((char *) grub_efiemu_mm_obtain_request (seg->handle) 
+		   + seg->off + rel->r_offset);
+		addr32 = (grub_uint32_t *) addr;
+		addr64 = (grub_uint64_t *) addr;
+		sym = elfsyms[ELF64_R_SYM (rel->r_info)];
+		
+		switch (ELF64_R_TYPE (rel->r_info))
+		  {
+		  case R_X86_64_64:
+		    if ((err = grub_efiemu_write_value 
+			 (addr, *addr64 + rel->r_addend + sym.off, sym.handle, 
+			  0, seg->ptv_rel_needed, sizeof (grub_uint64_t))))
+		      return err;
+		    break;
+
+		  case R_X86_64_PC32:
+		    if ((err = grub_efiemu_write_value
+			 (addr, *addr32 + rel->r_addend + sym.off 
+			  - rel->r_offset - seg->off, sym.handle, seg->handle, 
+			  seg->ptv_rel_needed, sizeof (grub_uint32_t))))
+		      return err;
+		    break;
+
+                  case R_X86_64_32:
+                  case R_X86_64_32S:
+		    if ((err = grub_efiemu_write_value 
+			 (addr, *addr32 + rel->r_addend + sym.off, sym.handle, 
+			  0, seg->ptv_rel_needed, sizeof (grub_uint32_t))))
+		      return err;
+                    break;
+		  default:
+		    return grub_error (GRUB_ERR_BAD_OS, 
+				       "unrecognised relocation");
+		  }
+	      }
+	  }
+      }
+
+  return GRUB_ERR_NONE;
+}
+
Index: efiemu/i386/loadcore32.c
===================================================================
--- efiemu/i386/loadcore32.c	(revision 0)
+++ efiemu/i386/loadcore32.c	(revision 0)
@@ -0,0 +1,113 @@
+/* i386 CPU-specific part of loadcore.c for 32-bit mode */
+/*
+ *  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/err.h>
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/efiemu/efiemu.h>
+#include <grub/cpu/efiemu.h>
+#include <grub/elf.h>
+
+/* Check if EHDR is a valid ELF header.  */
+int
+grub_arch_efiemu_check_header32 (void *ehdr)
+{
+  Elf32_Ehdr *e = ehdr;
+
+  /* Check the magic numbers.  */
+  return (e->e_ident[EI_CLASS] == ELFCLASS32
+	  && e->e_ident[EI_DATA] == ELFDATA2LSB
+	  && e->e_machine == EM_386);
+}
+
+/* Relocate symbols.  */
+grub_err_t
+grub_arch_efiemu_relocate_symbols32 (grub_efiemu_segment_t segs, 
+				     struct grub_efiemu_elf_sym *elfsyms,
+				     void *ehdr)
+{
+  unsigned i;
+  Elf32_Ehdr *e = ehdr;
+  Elf32_Shdr *s;
+  grub_err_t err;
+
+  grub_dprintf ("efiemu", "relocating symbols %d %d\n",
+		e->e_shoff, e->e_shnum);
+
+  for (i = 0, s = (Elf32_Shdr *) ((char *) e + e->e_shoff);
+       i < e->e_shnum;
+       i++, s = (Elf32_Shdr *) ((char *) s + e->e_shentsize))
+    if (s->sh_type == SHT_REL)
+      {
+	grub_efiemu_segment_t seg;
+	grub_dprintf ("efiemu", "shtrel\n");
+
+	/* Find the target segment.  */
+	for (seg = segs; seg; seg = seg->next)
+	  if (seg->section == s->sh_info)
+	    break;
+
+	if (seg)
+	  {
+	    Elf32_Rel *rel, *max;
+	    
+	    for (rel = (Elf32_Rel *) ((char *) e + s->sh_offset),
+		   max = rel + s->sh_size / s->sh_entsize;
+		 rel < max;
+		 rel++)
+	      {
+		Elf32_Word *addr;
+		struct grub_efiemu_elf_sym sym;
+		if (seg->size < rel->r_offset)
+		  return grub_error (GRUB_ERR_BAD_MODULE,
+				     "reloc offset is out of the segment");
+		
+		addr = (Elf32_Word *) 
+		  ((char *) grub_efiemu_mm_obtain_request (seg->handle) 
+		   + seg->off + rel->r_offset);
+		sym = elfsyms[ELF32_R_SYM (rel->r_info)];
+		
+		switch (ELF32_R_TYPE (rel->r_info))
+		  {
+		  case R_386_32:
+		    if ((err = grub_efiemu_write_value 
+			 (addr, sym.off + *addr, sym.handle, 0, 
+			  seg->ptv_rel_needed, sizeof (grub_uint32_t))))
+		      return err;
+		    
+		    break;
+
+		  case R_386_PC32:
+		    if ((err = grub_efiemu_write_value
+			 (addr, sym.off + *addr - rel->r_offset 
+			  - seg->off, sym.handle, seg->handle, 
+			  seg->ptv_rel_needed, sizeof (grub_uint32_t))))
+		      return err;
+		    break;
+		  default:
+		    return grub_error (GRUB_ERR_BAD_OS, 
+				       "unrecognised relocation");
+		  }
+	      }
+	  }
+      }
+
+  return GRUB_ERR_NONE;
+}
+
Index: efiemu/prepare64.c
===================================================================
--- efiemu/prepare64.c	(revision 0)
+++ efiemu/prepare64.c	(revision 0)
@@ -0,0 +1,23 @@
+/* This file contains definitions so that prepare.c compiles for 64-bit */
+/*
+ *  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/>.
+ */
+
+#define SUFFIX(x) x ## 64
+#define TYPE(x) x ## 64_t
+
+#include "prepare.c"
Index: efiemu/loadcore.c
===================================================================
--- efiemu/loadcore.c	(revision 0)
+++ efiemu/loadcore.c	(revision 0)
@@ -0,0 +1,370 @@
+/* Load runtime image of EFIemu. Functions specific to 32/64-bit mode */
+/*
+ *  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/err.h>
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/efiemu/efiemu.h>
+#include <grub/cpu/efiemu.h>
+#include <grub/machine/efiemu.h>
+#include <grub/elf.h>
+
+/* ELF symbols and their values */
+static struct grub_efiemu_elf_sym *grub_efiemu_elfsyms = 0;
+static int grub_efiemu_nelfsyms = 0;
+
+/* Return the address of a section whose index is N.  */
+static grub_err_t
+grub_efiemu_get_section_addr (grub_efiemu_segment_t segs, unsigned n,
+			      int *handle, grub_off_t *off)
+{
+  grub_efiemu_segment_t seg;
+
+  for (seg = segs; seg; seg = seg->next)
+    if (seg->section == n)
+      {
+	*handle = seg->handle;
+	*off = seg->off;	
+	return GRUB_ERR_NONE;
+      }
+
+  return grub_error (GRUB_ERR_BAD_OS, "section %d not found", n);
+}
+
+grub_err_t
+SUFFIX (grub_efiemu_loadcore_unload) (void)
+{
+  grub_free (grub_efiemu_elfsyms);
+  grub_efiemu_elfsyms = 0;
+  return GRUB_ERR_NONE;
+}
+
+/* Check if EHDR is a valid ELF header.  */
+int
+SUFFIX (grub_efiemu_check_header) (void *ehdr, grub_size_t size)
+{
+  Elf_Ehdr *e = ehdr;
+
+  /* Check the header size.  */
+  if (size < sizeof (Elf_Ehdr))
+    return 0;
+
+  /* Check the magic numbers.  */
+  if (!SUFFIX (grub_arch_efiemu_check_header) (ehdr)
+      || e->e_ident[EI_MAG0] != ELFMAG0
+      || e->e_ident[EI_MAG1] != ELFMAG1
+      || e->e_ident[EI_MAG2] != ELFMAG2
+      || e->e_ident[EI_MAG3] != ELFMAG3
+      || e->e_ident[EI_VERSION] != EV_CURRENT
+      || e->e_version != EV_CURRENT)
+    return 0;
+
+  return 1;
+}
+
+/* Load all segments from memory specified by E.  */
+static grub_err_t
+grub_efiemu_load_segments (grub_efiemu_segment_t segs, const Elf_Ehdr *e)
+{
+  Elf_Shdr *s;
+  grub_efiemu_segment_t cur;
+
+  grub_dprintf ("efiemu", "loading segments\n");
+  
+  for (cur=segs; cur; cur = cur->next)
+    {
+      s = (Elf_Shdr *)cur->srcptr;
+
+      if ((s->sh_flags & SHF_ALLOC) && s->sh_size)
+	{
+	  void *addr;
+	  
+	  addr = (grub_uint8_t *) grub_efiemu_mm_obtain_request (cur->handle) 
+	    + cur->off;
+	  
+	  switch (s->sh_type)
+	    {
+	    case SHT_PROGBITS:
+	      grub_memcpy (addr, (char *) e + s->sh_offset, s->sh_size);
+	      break;
+	    case SHT_NOBITS:
+	      grub_memset (addr, 0, s->sh_size);
+	      break;
+	    }
+	}
+    }
+
+  return GRUB_ERR_NONE;
+}
+
+/* Get a string at offset OFFSET from strtab */
+static char *
+grub_efiemu_get_string (unsigned offset, const Elf_Ehdr *e)
+{
+  unsigned i;
+  Elf_Shdr *s;
+
+  for (i = 0, s = (Elf_Shdr *)((char *) e + e->e_shoff);
+       i < e->e_shnum;
+       i++, s = (Elf_Shdr *)((char *) s + e->e_shentsize))
+    if (s->sh_type == SHT_STRTAB && offset < s->sh_size)
+      return (char *) e + s->sh_offset + offset;
+  return 0;
+}
+
+/* Request memory for segments and fill segments info */
+static grub_err_t
+grub_efiemu_init_segments (grub_efiemu_segment_t *segs, const Elf_Ehdr *e)
+{
+  unsigned i;
+  Elf_Shdr *s;
+
+  for (i = 0, s = (Elf_Shdr *)((char *) e + e->e_shoff);
+       i < e->e_shnum;
+       i++, s = (Elf_Shdr *)((char *) s + e->e_shentsize))
+    {
+      if (s->sh_flags & SHF_ALLOC)
+	{
+	  grub_efiemu_segment_t seg;
+	  seg = (grub_efiemu_segment_t) grub_malloc (sizeof (*seg));
+	  if (! seg)
+	    return grub_errno;
+	  
+	  if (s->sh_size)
+	    {
+	      seg->handle 
+		= grub_efiemu_request_memalign 
+		(s->sh_addralign, s->sh_size,
+		 s->sh_flags & SHF_EXECINSTR ? GRUB_EFI_RUNTIME_SERVICES_CODE
+		 : GRUB_EFI_RUNTIME_SERVICES_DATA);
+	      if (seg->handle < 0)
+		return grub_errno;
+	      seg->off = 0;
+	    }
+	  
+	  /* 
+	     .text-physical doesn't need to be relocated when switching to
+	     virtual mode
+	   */
+	  if (!grub_strcmp (grub_efiemu_get_string (s->sh_name, e), 
+			    ".text-physical"))
+	    seg->ptv_rel_needed = 0;
+	  else
+	    seg->ptv_rel_needed = 1;
+	  seg->size = s->sh_size;
+	  seg->section = i;
+	  seg->next = *segs;
+	  seg->srcptr = s;
+	  *segs = seg;
+	}
+    }
+  
+  return GRUB_ERR_NONE;
+}
+
+/* Count symbols and relocators and allocate/request memory for them */
+static grub_err_t
+grub_efiemu_count_symbols (const Elf_Ehdr *e)
+{
+  unsigned i;
+  Elf_Shdr *s;
+  int num = 0;
+  
+  /* Symbols */
+  for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
+       i < e->e_shnum;
+       i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize))
+    if (s->sh_type == SHT_SYMTAB)
+      break;
+
+  if (i == e->e_shnum)
+    return grub_error (GRUB_ERR_BAD_OS, "no symbol table");
+
+  grub_efiemu_nelfsyms = (unsigned) s->sh_size / (unsigned) s->sh_entsize;
+  grub_efiemu_elfsyms = (struct grub_efiemu_elf_sym *) 
+    grub_malloc (sizeof (struct grub_efiemu_elf_sym) * grub_efiemu_nelfsyms);
+
+  /* Relocators */
+  for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
+       i < e->e_shnum;
+       i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize))
+    if (s->sh_type == SHT_REL || s->sh_type == SHT_RELA)
+      num += ((unsigned) s->sh_size) / ((unsigned) s->sh_entsize);
+
+  grub_efiemu_request_symbols (num);
+
+  return GRUB_ERR_NONE;
+}
+
+/* Fill grub_efiemu_elfsyms with symbol values */
+static grub_err_t
+grub_efiemu_resolve_symbols (grub_efiemu_segment_t segs, Elf_Ehdr *e)
+{
+  unsigned i;
+  Elf_Shdr *s;
+  Elf_Sym *sym;
+  const char *str;
+  Elf_Word size, entsize;
+  
+  grub_dprintf ("efiemu", "resolving symbols\n");
+
+  for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
+       i < e->e_shnum;
+       i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize))
+    if (s->sh_type == SHT_SYMTAB)
+      break;
+
+  if (i == e->e_shnum)
+    return grub_error (GRUB_ERR_BAD_OS, "no symbol table");
+
+  sym = (Elf_Sym *) ((char *) e + s->sh_offset);
+  size = s->sh_size;
+  entsize = s->sh_entsize;
+
+  grub_efiemu_nelfsyms = size / entsize;
+  grub_efiemu_elfsyms = (struct grub_efiemu_elf_sym *) 
+    grub_malloc (sizeof (struct grub_efiemu_elf_sym) * grub_efiemu_nelfsyms);
+
+
+  s = (Elf_Shdr *) ((char *) e + e->e_shoff + e->e_shentsize * s->sh_link);
+  str = (char *) e + s->sh_offset;
+
+  for (i = 0;
+       i < size / entsize;
+       i++, sym = (Elf_Sym *) ((char *) sym + entsize))
+    {
+      unsigned char type = ELF_ST_TYPE (sym->st_info);
+      unsigned char bind = ELF_ST_BIND (sym->st_info);
+      int handle;
+      grub_off_t off;
+      grub_err_t err;
+      const char *name = str + sym->st_name;
+      grub_efiemu_elfsyms[i].section = sym->st_shndx;
+      switch (type)
+	{
+	case STT_NOTYPE:
+	  /* Resolve a global symbol.  */
+	  if (sym->st_name != 0 && sym->st_shndx == 0)
+	    {
+	      if ((err = grub_efiemu_resolve_symbol (name, &handle, &off)))
+		return err;
+	      grub_efiemu_elfsyms[i].handle = handle;
+	      grub_efiemu_elfsyms[i].off = off;
+	    }
+	  else
+	    sym->st_value = 0;
+	  break;
+
+	case STT_OBJECT:
+	  if ((err = grub_efiemu_get_section_addr 
+	       (segs, sym->st_shndx, &handle, &off)))
+	    return err;
+
+	  off += sym->st_value;
+	  if (bind != STB_LOCAL)
+	    if ((err = grub_efiemu_register_symbol (name, handle, off)))
+	      return err;
+	  grub_efiemu_elfsyms[i].handle = handle;
+	  grub_efiemu_elfsyms[i].off = off;
+	  break;
+
+	case STT_FUNC:
+	  if ((err = grub_efiemu_get_section_addr 
+	       (segs, sym->st_shndx, &handle, &off)))
+	    return err;
+
+	  off += sym->st_value;
+	  if (bind != STB_LOCAL)
+	    if ((err = grub_efiemu_register_symbol (name, handle, off)))
+	      return err;
+	  grub_efiemu_elfsyms[i].handle = handle;
+	  grub_efiemu_elfsyms[i].off = off;
+	  break;
+
+	case STT_SECTION:
+	  if ((err = grub_efiemu_get_section_addr 
+	       (segs, sym->st_shndx, &handle, &off)))
+	    {
+	      grub_efiemu_elfsyms[i].handle = 0;
+	      grub_efiemu_elfsyms[i].off = 0;
+	      grub_errno = GRUB_ERR_NONE; 
+	      break;
+	    }
+
+	  grub_efiemu_elfsyms[i].handle = handle;
+	  grub_efiemu_elfsyms[i].off = off;
+	  break;
+
+	case STT_FILE:
+	  grub_efiemu_elfsyms[i].handle = 0;
+	  grub_efiemu_elfsyms[i].off = 0;
+	  break;
+
+	default:
+	  return grub_error (GRUB_ERR_BAD_MODULE,
+			     "unknown symbol type `%d'", (int) type);
+	}
+    }
+
+  return GRUB_ERR_NONE;
+}
+
+/* Load runtime to the memory and request memory for definitive location*/
+grub_err_t
+SUFFIX (grub_efiemu_loadcore_init) (void *core, grub_size_t core_size,
+				    grub_efiemu_segment_t *segments)
+{
+  Elf_Ehdr *e = (Elf_Ehdr *) core;
+  grub_err_t err;
+
+  if (e->e_type != ET_REL)
+    return grub_error (GRUB_ERR_BAD_MODULE, "invalid ELF file type");
+
+  /* Make sure that every section is within the core.  */
+  if ((grub_size_t) core_size < e->e_shoff + e->e_shentsize * e->e_shnum)
+    return grub_error (GRUB_ERR_BAD_OS, "ELF sections outside core");
+
+  if ((err = grub_efiemu_init_segments (segments, core)))
+    return err;
+  if ((err = grub_efiemu_count_symbols (core)))
+    return err;
+
+  grub_efiemu_request_symbols (1);
+  return GRUB_ERR_NONE;
+}
+
+/* Load runtime definitively */
+grub_err_t
+SUFFIX (grub_efiemu_loadcore_load) (void *core, 
+				    grub_size_t core_size 
+				    __attribute__ ((unused)),
+				    grub_efiemu_segment_t segments)
+{
+  grub_err_t err;
+  if ((err = grub_efiemu_load_segments (segments, core)))
+    return err;
+  if ((err = grub_efiemu_resolve_symbols (segments, core)))
+    return err;
+  if ((err = SUFFIX (grub_arch_efiemu_relocate_symbols) (segments, 
+							 grub_efiemu_elfsyms,
+							 core)))
+    return err;
+    
+  return GRUB_ERR_NONE;
+}
Index: efiemu/symbols.c
===================================================================
--- efiemu/symbols.c	(revision 0)
+++ efiemu/symbols.c	(revision 0)
@@ -0,0 +1,187 @@
+/* Code for managing symbols and pointers in efiemu */
+/*
+ *  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/err.h>
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/efiemu/efiemu.h>
+#include <grub/efiemu/runtime.h>
+
+static int ptv_written = 0;
+static int ptv_alloc = 0;
+static int ptv_handle = 0;
+static int ptv_requested = 0;
+static struct grub_efiemu_sym *efiemu_syms = 0;
+
+struct grub_efiemu_sym
+{
+  struct grub_efiemu_sym *next;
+  char *name;
+  int handle;
+  grub_off_t off;
+};
+
+void
+grub_efiemu_free_syms (void)
+{
+  struct grub_efiemu_sym *cur, *d;
+  for (cur = efiemu_syms; cur;)
+    {
+      d = cur->next;
+      grub_free (cur->name);
+      grub_free (cur);
+      cur = d;
+    }
+  efiemu_syms = 0;
+  ptv_written = 0;
+  ptv_alloc = 0;
+  ptv_requested = 0;
+  grub_efiemu_mm_return_request (ptv_handle);
+  ptv_handle = 0;
+}
+
+/* Announce that the module will need NUM allocators */
+/* Because of deferred memory allocation all the relocators have to be 
+   announced during phase 1*/
+grub_err_t
+grub_efiemu_request_symbols (int num)
+{
+  if (ptv_alloc)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT, 
+		       "symbols have already been allocated");
+  if (num < 0)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT, 
+		       "can't request negative symbols");
+  ptv_requested += num;
+  return GRUB_ERR_NONE;
+}
+
+/* Resolve the symbol name NAME and set HANDLE and OFF accordingly  */
+grub_err_t
+grub_efiemu_resolve_symbol (const char *name, int *handle, grub_off_t *off)
+{
+  struct grub_efiemu_sym *cur;
+  for (cur = efiemu_syms; cur; cur = cur->next)
+    if (!grub_strcmp (name, cur->name))
+      {
+	*handle = cur->handle;
+	*off = cur->off;
+	return GRUB_ERR_NONE;
+      }
+  grub_dprintf ("efiemu", "%s not found\n", name);
+  return grub_error (GRUB_ERR_BAD_OS, "symbol %s isn't found", name);
+}
+
+/* Register symbol named NAME in memory handle HANDLE at offset OFF */
+grub_err_t
+grub_efiemu_register_symbol (const char *name, int handle, grub_off_t off)
+{
+  struct grub_efiemu_sym *cur;
+  cur = (struct grub_efiemu_sym *) grub_malloc (sizeof (*cur));
+  if (!cur)
+    return grub_error (GRUB_ERR_OUT_OF_MEMORY, "couldn't register symbol");
+  cur->name = grub_strdup (name);
+  cur->next = efiemu_syms;
+  cur->handle = handle;
+  cur->off = off;
+  efiemu_syms = cur;
+
+  return 0;
+}
+
+/* Go from phase 1 to phase 2. Must be called before similar function in mm.c */
+grub_err_t
+grub_efiemu_alloc_syms (void)
+{
+  ptv_alloc = ptv_requested;
+  ptv_handle = grub_efiemu_request_memalign 
+    (1, (ptv_requested + 1) * sizeof (struct grub_efiemu_ptv_rel), 
+     GRUB_EFI_RUNTIME_SERVICES_DATA);
+  grub_efiemu_register_symbol ("efiemu_ptv_relloc", ptv_handle, 0);
+  return grub_errno;
+}
+
+/* Write value (pointer to memory PLUS_HANDLE) 
+   - (pointer to memory MINUS_HANDLE) + VALUE to ADDR assuming that the 
+   size SIZE bytes. If PTV_NEEDED is 1 then announce it to runtime that this
+   value needs to be recomputed before going to virtual mode
+*/
+grub_err_t
+grub_efiemu_write_value (void *addr, grub_uint32_t value, int plus_handle,
+			 int minus_handle, int ptv_needed, int size)
+{
+  /* Announce relocator to runtime */
+  if (ptv_needed)
+    {
+      struct grub_efiemu_ptv_rel *ptv_rels 
+	= grub_efiemu_mm_obtain_request (ptv_handle);
+
+      if (ptv_needed && ptv_written >= ptv_alloc)
+	return grub_error (GRUB_ERR_OUT_OF_MEMORY, 
+			   "your module didn't declare efiemu "
+			   " relocators correctly");
+
+      if (minus_handle)
+	ptv_rels[ptv_written].minustype 
+	  = grub_efiemu_mm_get_type (minus_handle);
+      else
+	ptv_rels[ptv_written].minustype = 0;
+
+      if (plus_handle)
+	ptv_rels[ptv_written].plustype 
+	  = grub_efiemu_mm_get_type (plus_handle);
+      else
+	ptv_rels[ptv_written].plustype = 0;
+
+      ptv_rels[ptv_written].addr = PTR_TO_UINT64 (addr);
+      ptv_rels[ptv_written].size = size;
+      ptv_written++;
+      
+      /* memset next value to zero to mark the end */
+      grub_memset (&ptv_rels[ptv_written], 0, sizeof (ptv_rels[ptv_written]));
+    }
+
+  /* Compute the value */
+  if (minus_handle)
+    value -= PTR_TO_UINT32 (grub_efiemu_mm_obtain_request (minus_handle));
+
+  if (plus_handle)
+    value += PTR_TO_UINT32 (grub_efiemu_mm_obtain_request (plus_handle));
+
+  /* Write the value */
+  switch (size)
+    {
+    case 8:
+      *((grub_uint64_t *) addr) = value;
+      break;
+    case 4:
+      *((grub_uint32_t *) addr) = value;
+      break;
+    case 2:
+      *((grub_uint16_t *) addr) = value;
+      break;
+    case 1:
+      *((grub_uint8_t *) addr) = value;
+      break;
+    default:
+      return grub_error (GRUB_ERR_BAD_ARGUMENT, "wrong symbol size");
+    }
+
+  return GRUB_ERR_NONE;
+}
Index: efiemu/mm.c
===================================================================
--- efiemu/mm.c	(revision 0)
+++ efiemu/mm.c	(revision 0)
@@ -0,0 +1,585 @@
+/* Memory management for efiemu */
+/*
+ *  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/>.
+ */
+/*
+  To keep efiemu runtime contiguous this mm is special. 
+  It uses deffered allocation.
+  In the first stage you may request memory with grub_efiemu_request_memalign
+  It will give you a handle with which in the second phase you can access your 
+  memory with grub_efiemu_mm_obtain_request (handle). It's guaranteed that
+  subsequent calls with the same handle return the same result. You can't request any additional memory once you're in the second phase
+*/
+
+#include <grub/err.h>
+#include <grub/normal.h>
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/machine/memory.h>
+#include <grub/efiemu/efiemu.h>
+
+struct grub_efiemu_memrequest 
+{
+  struct grub_efiemu_memrequest *next;
+  grub_efi_memory_type_t type;
+  grub_size_t size;
+  grub_size_t align_overhead;
+  int handle;
+  void *val;
+};
+/* Linked list of requested memory */
+static struct grub_efiemu_memrequest *memrequests = 0;
+/* Memory map */
+static grub_efi_memory_descriptor_t *efiemu_mmap = 0;
+/* Pointer to allocated memory */
+static void *resident_memory = 0;
+/* Size of requested memory per type */
+static grub_size_t requested_memory[GRUB_EFI_MAX_MEMORY_TYPE];
+/* How many slots is allocated for memory_map and how many are already used */
+static int mmap_reserved_size = 0, mmap_num = 0;
+
+/* Add a memory region to map*/
+static grub_err_t
+grub_efiemu_add_to_mmap (grub_uint64_t start, grub_uint64_t size, 
+			 grub_efi_memory_type_t type)
+{
+  grub_uint64_t page_start, npages;
+
+  /* Extend map if necessary*/
+  if (mmap_num >= mmap_reserved_size)
+    {
+      efiemu_mmap =  (grub_efi_memory_descriptor_t *)
+	grub_realloc (efiemu_mmap, (++mmap_reserved_size) 
+		      * sizeof (grub_efi_memory_descriptor_t));
+      if (!efiemu_mmap)
+	return grub_error (GRUB_ERR_OUT_OF_MEMORY, 
+			   "Not enough space for memory map");
+    }
+
+  /* Fill slot*/
+  page_start = start - (start % GRUB_EFIEMU_PAGESIZE);
+  npages = (size + (start % GRUB_EFIEMU_PAGESIZE) + GRUB_EFIEMU_PAGESIZE - 1)
+    / GRUB_EFIEMU_PAGESIZE;
+  efiemu_mmap[mmap_num].physical_start = page_start; 
+  efiemu_mmap[mmap_num].virtual_start = page_start; 
+  efiemu_mmap[mmap_num].num_pages = npages; 
+  efiemu_mmap[mmap_num].type = type;
+  mmap_num++;
+
+  return GRUB_ERR_NONE;
+}
+
+/* Request a resident memory of type TYPE of size SIZE aligned at ALIGN
+   ALIGN must be a divisor of page size (if it's a divisor of 4096 
+   it should be ok on all platforms)
+ */
+int
+grub_efiemu_request_memalign (grub_size_t align, grub_size_t size, 
+			      grub_efi_memory_type_t type)
+{
+  grub_size_t align_overhead;
+  struct grub_efiemu_memrequest *ret, *cur, *prev;
+  /* Check that the request is correct */
+  if (type >= GRUB_EFI_MAX_MEMORY_TYPE || type <= GRUB_EFI_LOADER_CODE)
+    return -2;
+
+  /* Add new size to requested size */
+  align_overhead = align - (requested_memory[type]%align);
+  if (align_overhead == align)
+    align_overhead = 0;
+  requested_memory[type] += align_overhead + size;
+
+  /* Remember the request */
+  ret = grub_malloc (sizeof (*ret));
+  if (!ret)
+    return -1;
+  ret->type = type;
+  ret->size = size;
+  ret->align_overhead = align_overhead;
+  ret->val = 0;
+  ret->next = 0;
+  prev = 0;
+  
+  /* Add request to the end of the chain. 
+     It should be at the end because otherwise alignment isn't guaranteed */
+  for (cur = memrequests; cur; prev = cur, cur = cur->next);
+  if (prev)
+    {
+      ret->handle = prev->handle + 1;
+      prev->next = ret;
+    }
+  else
+    {
+      ret->handle = 1; /* Avoid 0 handle*/
+      memrequests = ret;
+    }
+  return ret->handle;
+}
+
+/* Really allocate the memory */
+static grub_err_t
+efiemu_alloc_requests (void)
+{
+  grub_size_t align_overhead = 0;
+  grub_uint8_t *curptr, *typestart;
+  struct grub_efiemu_memrequest *cur;
+  grub_size_t total_alloc = 0;
+  unsigned i;
+  /* Order of memory regions */
+  grub_efi_memory_type_t reqorder[] =
+    {
+      /* First come regions usable by OS*/
+      GRUB_EFI_LOADER_CODE,
+      GRUB_EFI_LOADER_DATA,
+      GRUB_EFI_BOOT_SERVICES_CODE,
+      GRUB_EFI_BOOT_SERVICES_DATA,
+      GRUB_EFI_CONVENTIONAL_MEMORY,
+      GRUB_EFI_ACPI_RECLAIM_MEMORY,
+
+      /* Then memory used by runtime */
+      /* This way all our regions are in a single block */
+      GRUB_EFI_RUNTIME_SERVICES_CODE,
+      GRUB_EFI_RUNTIME_SERVICES_DATA,
+      GRUB_EFI_ACPI_MEMORY_NVS,
+      
+      /* And then unavailable memory types. This is more for a completeness. 
+	 You should double think before allocating memory of any of these types
+       */
+      GRUB_EFI_UNUSABLE_MEMORY,
+      GRUB_EFI_MEMORY_MAPPED_IO,
+      GRUB_EFI_MEMORY_MAPPED_IO_PORT_SPACE,
+      GRUB_EFI_PAL_CODE 
+    };
+
+  /* Compute total memory needed */
+  for (i = 0; i < sizeof (reqorder) / sizeof (reqorder[0]); i++)
+    {
+      align_overhead = GRUB_EFIEMU_PAGESIZE 
+	- (requested_memory[reqorder[i]] % GRUB_EFIEMU_PAGESIZE);
+      if (align_overhead == GRUB_EFIEMU_PAGESIZE)
+	align_overhead = 0;
+      total_alloc += requested_memory[reqorder[i]] + align_overhead;
+    }
+
+  /* Allocate the whole memory in one block */
+  resident_memory = grub_memalign (GRUB_EFIEMU_PAGESIZE, total_alloc);
+  if (!resident_memory)
+    return grub_error (GRUB_ERR_OUT_OF_MEMORY, 
+		       "couldn't allocate resident memory");
+
+  /* Split the memory into blocks by type */
+  curptr = resident_memory;
+  for (i = 0; i < sizeof (reqorder) / sizeof (reqorder[0]); i++)
+    {
+      if (!requested_memory[reqorder[i]])
+	continue;
+      typestart = curptr;
+
+      /* Write pointers to requests */
+      for (cur = memrequests; cur; cur = cur->next)
+	if (cur->type == reqorder[i])
+	  {
+	    curptr = ((grub_uint8_t *)curptr) + cur->align_overhead;
+	    cur->val = curptr;
+	    curptr = ((grub_uint8_t *)curptr) + cur->size;
+	  }
+
+      /* Ensure that the regions are page-aligned */
+      align_overhead = GRUB_EFIEMU_PAGESIZE 
+	- (requested_memory[reqorder[i]] % GRUB_EFIEMU_PAGESIZE);
+      if (align_overhead == GRUB_EFIEMU_PAGESIZE)
+	align_overhead = 0;
+      curptr = ((grub_uint8_t *)curptr) + align_overhead;
+      
+      /* Add the region to memory map */
+      grub_efiemu_add_to_mmap (PTR_TO_UINT64 (typestart), 
+			       curptr - typestart, reqorder[i]);
+    }
+
+  return GRUB_ERR_NONE;
+}
+
+/* Get a pointer to requested memory from handle */
+void *
+grub_efiemu_mm_obtain_request (int handle)
+{
+  struct grub_efiemu_memrequest *cur;
+  for (cur = memrequests; cur; cur = cur->next)
+    if (cur->handle == handle)
+      return cur->val;
+  return 0;
+}
+
+/* Get type of requested memory by handle */
+grub_efi_memory_type_t
+grub_efiemu_mm_get_type (int handle)
+{
+  struct grub_efiemu_memrequest *cur;
+  for (cur = memrequests; cur; cur = cur->next)
+    if (cur->handle == handle)
+      return cur->type;
+  return 0;
+}
+
+/* Free a request */
+void
+grub_efiemu_mm_return_request (int handle)
+{
+  struct grub_efiemu_memrequest *cur, *prev;
+
+  /* Remove head if necessary */
+  while (memrequests && memrequests->handle == handle)
+    {
+      cur = memrequests->next;
+      grub_free (memrequests);
+      memrequests = cur;
+    }
+  if (!memrequests)
+    return;
+
+  /* Remove request from a middle of chain*/
+  for (prev = memrequests, cur = prev->next; cur;)
+    if (cur->handle == handle)
+      {
+	prev->next = cur->next;
+	grub_free (cur);
+	cur = prev->next;
+      }
+    else
+      {
+	prev = cur;
+	cur = prev->next;
+      }
+}
+
+/* Reserve space for memory map */
+static grub_err_t
+grub_efiemu_mmap_init (void)
+{
+  auto int NESTED_FUNC_ATTR bounds_hook (grub_uint64_t, grub_uint64_t, 
+					 grub_uint32_t);
+  int NESTED_FUNC_ATTR bounds_hook (grub_uint64_t addr __attribute__ ((unused)),
+				    grub_uint64_t size __attribute__ ((unused)),
+				    grub_uint32_t type __attribute__ ((unused)))
+    {
+      mmap_reserved_size++;
+      return 0;
+    }
+
+  // the place for memory used by efiemu itself
+  mmap_reserved_size = GRUB_EFI_MAX_MEMORY_TYPE + 1;
+
+#ifndef GRUB_UTIL
+  grub_machine_mmap_iterate (bounds_hook);
+#endif
+
+  return GRUB_ERR_NONE;
+}
+
+/* This is a drop-in replacement of grub_efi_get_memory_map */
+/* Get the memory map as defined in the EFI spec. Return 1 if successful,
+   return 0 if partial, or return -1 if an error occurs.  */
+int
+grub_efiemu_get_memory_map (grub_efi_uintn_t *memory_map_size,
+			    grub_efi_memory_descriptor_t *memory_map,
+			    grub_efi_uintn_t *map_key,
+			    grub_efi_uintn_t *descriptor_size,
+			    grub_efi_uint32_t *descriptor_version)
+{
+  if (!efiemu_mmap)
+    {
+      grub_error (GRUB_ERR_INVALID_COMMAND, 
+		  "you need to first launch efiemu_prepare");
+      return -1;
+    }
+
+  if (*memory_map_size < mmap_num * sizeof (grub_efi_memory_descriptor_t))
+    {
+      *memory_map_size = mmap_num * sizeof (grub_efi_memory_descriptor_t);
+      return 0;
+    }
+
+  *memory_map_size = mmap_num * sizeof (grub_efi_memory_descriptor_t);
+  grub_memcpy (memory_map, efiemu_mmap, *memory_map_size);
+  if (descriptor_size)
+    *descriptor_size = sizeof (grub_efi_memory_descriptor_t);
+  if (descriptor_version)
+    *descriptor_version = 1;
+  if (map_key)
+    *map_key = 0;
+
+  return 1;
+}
+
+/* Free everything */
+grub_err_t
+grub_efiemu_mm_unload (void)
+{
+  struct grub_efiemu_memrequest *cur, *d;
+  for (cur = memrequests; cur;)
+    {
+      d = cur->next;
+      grub_free (cur);
+      cur = d;
+    }
+  memrequests = 0;
+  grub_memset (&requested_memory, 0, sizeof (requested_memory));
+  grub_free (resident_memory);
+  resident_memory = 0;
+  grub_free (efiemu_mmap);
+  efiemu_mmap = 0;
+  mmap_reserved_size = mmap_num = 0;
+  return GRUB_ERR_NONE;
+}
+
+/* This function should be called before doing any requests */
+grub_err_t
+grub_efiemu_mm_init (void)
+{
+  grub_err_t err;
+
+  err = grub_efiemu_mm_unload ();
+  if (err)
+    return err;
+
+  grub_efiemu_mmap_init ();
+
+  return GRUB_ERR_NONE;
+}
+
+/* Copy host memory map */
+static grub_err_t
+grub_efiemu_mmap_fill (void)
+{
+  auto int NESTED_FUNC_ATTR fill_hook (grub_uint64_t, grub_uint64_t, grub_uint32_t);
+  int NESTED_FUNC_ATTR fill_hook (grub_uint64_t addr,
+				  grub_uint64_t size,
+				  grub_uint32_t type)
+    {
+      switch (type)
+	{
+	case GRUB_MACHINE_MEMORY_AVAILABLE:
+	  return grub_efiemu_add_to_mmap (addr, size, 
+					  GRUB_EFI_CONVENTIONAL_MEMORY);
+
+#ifdef GRUB_MACHINE_MEMORY_ACPI
+	case GRUB_MACHINE_MEMORY_ACPI:
+	  return grub_efiemu_add_to_mmap (addr, size, 
+					  GRUB_EFI_ACPI_RECLAIM_MEMORY);
+#endif
+
+#ifdef GRUB_MACHINE_MEMORY_NVS
+	case GRUB_MACHINE_MEMORY_NVS:
+	  return grub_efiemu_add_to_mmap (addr, size, 
+					  GRUB_EFI_ACPI_MEMORY_NVS);
+#endif
+
+	default:
+	  grub_printf ("Unknown memory type %d. Marking as unusable\n", type);
+	case GRUB_MACHINE_MEMORY_RESERVED:
+	  return grub_efiemu_add_to_mmap (addr, size, 
+					  GRUB_EFI_UNUSABLE_MEMORY);	  
+	}
+    }
+
+#ifndef GRUB_UTIL
+  grub_machine_mmap_iterate (fill_hook);
+#endif
+
+  return GRUB_ERR_NONE;
+}
+
+/* This function resolves overlapping regions and sorts the memory map
+   It uses scanline (sweeping) algorithm
+ */
+static grub_err_t
+grub_efiemu_mmap_sort_and_uniq (void)
+{
+  /* If same page is used by multiple types it's resolved 
+     according to priority 
+     0 - free memory
+     1 - memory immediately usable after ExitBootServices
+     2 - memory usable after loading ACPI tables
+     3 - efiemu memory
+     4 - unusable memory
+  */
+  int priority[GRUB_EFI_MAX_MEMORY_TYPE] =
+    {
+      [GRUB_EFI_RESERVED_MEMORY_TYPE] = 4,
+      [GRUB_EFI_LOADER_CODE] = 1,
+      [GRUB_EFI_LOADER_DATA] = 1,
+      [GRUB_EFI_BOOT_SERVICES_CODE] = 1,
+      [GRUB_EFI_BOOT_SERVICES_DATA] = 1,
+      [GRUB_EFI_RUNTIME_SERVICES_CODE] = 3,
+      [GRUB_EFI_RUNTIME_SERVICES_DATA] = 3,
+      [GRUB_EFI_CONVENTIONAL_MEMORY] = 0,
+      [GRUB_EFI_UNUSABLE_MEMORY] = 4,
+      [GRUB_EFI_ACPI_RECLAIM_MEMORY] = 2,
+      [GRUB_EFI_ACPI_MEMORY_NVS] = 3,
+      [GRUB_EFI_MEMORY_MAPPED_IO] = 4,
+      [GRUB_EFI_MEMORY_MAPPED_IO_PORT_SPACE] = 4,
+      [GRUB_EFI_PAL_CODE] = 4
+    };
+
+  int i, j, k, done;
+
+  /* Scanline events */
+  struct grub_efiemu_mmap_scan
+  {
+    /* At which memory address*/
+    grub_uint64_t pos;
+    /* 0 = region starts, 1 = region ends */
+    int type;
+    /* Which type of memory region */
+    grub_efi_memory_type_t memtype;
+  };
+  struct grub_efiemu_mmap_scan *scanline_events;
+  struct grub_efiemu_mmap_scan t;
+
+  /* Previous scanline event */
+  grub_uint64_t lastaddr;
+  int lasttype;
+  /* Current scanline event */
+  int curtype;
+  /* how many regions of given type overlap at current location */
+  int present[GRUB_EFI_MAX_MEMORY_TYPE];
+  /* Here is stored the resulting memory map*/
+  grub_efi_memory_descriptor_t *result;
+
+  /* Initialize variables*/
+  grub_memset (present, 0, sizeof (int) * GRUB_EFI_MAX_MEMORY_TYPE);
+  scanline_events = (struct grub_efiemu_mmap_scan *) 
+    grub_malloc (sizeof (struct grub_efiemu_mmap_scan) * 2 * mmap_num);
+
+  /* Number of chunks can't increase more than by factor of 2 */
+  result = (grub_efi_memory_descriptor_t *) 
+    grub_malloc (sizeof (grub_efi_memory_descriptor_t) * 2 * mmap_num);
+  if (!result || !scanline_events)
+    {
+      grub_free (result);
+      grub_free (scanline_events);
+      return grub_error (GRUB_ERR_OUT_OF_MEMORY, 
+			 "couldn't allocate space for new memory map");
+    }
+   
+  /* Register scanline events */
+  for (i = 0; i < mmap_num; i++)
+    {
+      scanline_events[2 * i].pos = efiemu_mmap[i].physical_start;
+      scanline_events[2 * i].type = 0;
+      scanline_events[2 * i].memtype = efiemu_mmap[i].type;
+      scanline_events[2 * i + 1].pos = efiemu_mmap[i].physical_start
+	+ efiemu_mmap[i].num_pages * GRUB_EFIEMU_PAGESIZE;
+      scanline_events[2 * i + 1].type = 1;
+      scanline_events[2 * i + 1].memtype = efiemu_mmap[i].type;
+    }
+
+  /* Primitive bubble sort. It has complexity O(n^2) but since we're 
+     unlikely to have more than 100 chunks it's probably one of the 
+     fastest for one purpose */
+  done = 1;
+  while (done)
+    {
+      done = 0;
+      for (i = 0; i < 2 * mmap_num - 1; i++)
+	if (scanline_events[i + 1].pos < scanline_events[i].pos)
+	  {
+	    t = scanline_events[i + 1];
+	    scanline_events[i + 1] = scanline_events[i];
+	    scanline_events[i] = t;
+	    done = 1;
+	  }
+    }
+
+  /* Pointer in resulting memory map */
+  j = 0;
+  lastaddr = scanline_events[0].pos;
+  lasttype = scanline_events[0].memtype;
+  for (i = 0; i < 2 * mmap_num; i++)
+    {
+      /* Process event */
+      if (scanline_events[i].type)
+	present[scanline_events[i].memtype]--;
+      else
+	present[scanline_events[i].memtype]++;
+
+      /* Determine current region type */
+      curtype = -1;
+      for (k = 0; k < GRUB_EFI_MAX_MEMORY_TYPE; k++)
+	if (present[k] && (curtype == -1 || priority[k] > priority[curtype]))
+	  curtype = k;
+
+      /* Add memory region to resulting map if necessary */
+      if ((curtype == -1 || curtype != lasttype) 
+	  && lastaddr != scanline_events[i].pos
+	  && lasttype != -1)
+	{
+	  result[j].virtual_start = result[j].physical_start = lastaddr;
+	  result[j].num_pages = (scanline_events[i].pos - lastaddr) 
+	    / GRUB_EFIEMU_PAGESIZE;
+	  result[j].type = lasttype;
+
+	  /* We set runtime attribute on pages we need to be mapped */
+	  result[j].attribute 
+	    = (lasttype == GRUB_EFI_RUNTIME_SERVICES_CODE
+		   || lasttype == GRUB_EFI_RUNTIME_SERVICES_DATA)
+	    ? GRUB_EFI_MEMORY_RUNTIME : 0;
+	  grub_dprintf ("efiemu", 
+			"mmap entry: type %d start 0x%llx 0x%llx pages\n", 
+			result[j].type,
+			result[j].physical_start, result[j].num_pages);
+	  j++;
+	}
+
+      /* Update last values if necessary */
+      if (curtype == -1 || curtype != lasttype) 
+	{
+	  lasttype = curtype;
+	  lastaddr = scanline_events[i].pos;
+	}
+    }
+
+  grub_free (scanline_events);
+
+  /* Shrink resulting memory map to really used size and replace efiemu_mmap 
+     by new value */
+  grub_free (efiemu_mmap);
+  efiemu_mmap = grub_realloc (result, j * sizeof (*result));
+  return GRUB_ERR_NONE;
+}
+
+/* This function is called to switch from first to second phase */
+grub_err_t
+grub_efiemu_mm_do_alloc (void)
+{
+  grub_err_t err;
+
+  /* Preallocate mmap */
+  efiemu_mmap = (grub_efi_memory_descriptor_t *) 
+    grub_malloc (mmap_reserved_size * sizeof (grub_efi_memory_descriptor_t));
+  if (!efiemu_mmap)
+    {
+      grub_efiemu_unload ();
+      return grub_error (GRUB_ERR_OUT_OF_MEMORY, "Couldn't initilaize mmap");
+    }
+
+  if ((err = efiemu_alloc_requests ()))
+    return err;
+  if ((err = grub_efiemu_mmap_fill ()))
+    return err;
+  return grub_efiemu_mmap_sort_and_uniq ();
+} 
Index: efiemu/loadcore32.c
===================================================================
--- efiemu/loadcore32.c	(revision 0)
+++ efiemu/loadcore32.c	(revision 0)
@@ -0,0 +1,27 @@
+/* This file contains definitions so that loadcore.c compiles for 32-bit */
+/*
+ *  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/>.
+ */
+
+#define SUFFIX(x) x ## 32
+#define Elf_Ehdr Elf32_Ehdr
+#define Elf_Shdr Elf32_Shdr
+#define Elf_Sym Elf32_Sym
+#define Elf_Word Elf32_Word
+#define ELF_ST_TYPE ELF32_ST_TYPE
+#define ELF_ST_BIND ELF32_ST_BIND
+#include "loadcore.c"
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 2008)
+++ ChangeLog	(working copy)
@@ -1,3 +1,50 @@
+2009-02-28  Vladimir Serbinenko  <phcoder@gmail.com>
+
+	Efiemu
+
+	* conf/i386-pc.rmk: new modules efiemu, efiemu_acpi, efiemu_pnvram,
+	_linux_efi, linux_efi. 
+	new files in grub-emu 
+	new targets efiemu32.o and efiemu64.o
+	* lib/i386/pc/acpi.c: new file
+	* loader/linux_normal_efiemu.c: likewise
+	* loader/i386/efi/linux.c: added preliminary efiemu support
+	* util/i386/pc/grub-install.in: add efiemu??.o to the list of 
+	files to copy
+	* include/grub/autoefi.h: new file
+	* nclude/grub/i386/efiemu.h: likewise
+	* include/grub/i386/pc/efiemu.h: likewise
+	* include/grub/acpi.h: likewise
+	* include/grub/i386/pc/memory.h: 
+	(GRUB_MACHINE_MEMORY_ACPI): new definition
+	(GRUB_MACHINE_MEMORY_NVS): likewise
+	* include/grub/efi/api.h: add LL suffix when necessary
+	new definitions relating to tables
+	* include/grub/types.h: new definitions for pointer conversion
+	* include/grub/efiemu/efiemu.h: new file
+	* include/grub/efiemu/runtime.h: likewise
+	* efiemu/prepare.c: likewise
+	* efiemu/loadcore_common.c: likewise
+	* efiemu/loadcore64.c: likewise
+	* efiemu/runtime/efiemu.sh: likewise
+	* efiemu/runtime/efiemu.S: likewise
+	* efiemu/runtime/efiemu.c: likewise
+	* efiemu/runtime/config.h: likewise
+	* efiemu/prepare32.c: likewise
+	* efiemu/main.c: likewise
+	* efiemu/modules/pnvram.c: likewise
+	* efiemu/modules/i386: likewise
+	* efiemu/modules/i386/pc: likewise
+	* efiemu/modules/acpi.c: likewise
+	* efiemu/i386/pc/cfgtables.c: likewise
+	* efiemu/i386/loadcore64.c: likewise
+	* efiemu/i386/loadcore32.c: likewise
+	* efiemu/prepare64.c: likewise
+	* efiemu/loadcore.c: likewise
+	* efiemu/symbols.c: likewise
+	* efiemu/mm.c: likewise
+	* efiemu/loadcore32.c: likewise
+	
 2009-02-27  Robert Millan  <rmh@aybabtu.com>
 
 	Factorize elf32 / elf64 code in Multiboot loader.  This will

             reply	other threads:[~2009-02-28 16:17 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-02-28 16:17 phcoder [this message]
2009-03-01 10:49 ` Efiemu phcoder
2009-03-01 20:00   ` Efiemu Bean
2009-03-01 21:13     ` Efiemu phcoder
2009-03-20 19:32       ` Efiemu phcoder

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=49A96398.1070609@gmail.com \
    --to=phcoder@gmail.com \
    --cc=grub-devel@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.