All of lore.kernel.org
 help / color / mirror / Atom feed
* mmap services
@ 2009-04-11 21:01 phcoder
  2009-04-26 14:42 ` Vladimir 'phcoder' Serbinenko
  0 siblings, 1 reply; 4+ messages in thread
From: phcoder @ 2009-04-11 21:01 UTC (permalink / raw)
  To: The development of GRUB 2

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

Hello. Here is the patch to allow different mmap filtering. It naturally 
incorporates badram and also intercepts int12/15 so it works also with 
OS recieving mmap from BIOS. It's useful for intercepting any bios 
interrupts
-- 

Regards
Vladimir 'phcoder' Serbinenko

[-- Attachment #2: mmap.diff --]
[-- Type: text/x-diff, Size: 39093 bytes --]

diff --git a/ChangeLog b/ChangeLog
index a6dd8f7..ce0eb8d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,52 @@
+2009-04-11  Vladimir Serbinenko <phcoder@gmail.com>
+
+	Mmap services
+
+	* commands/lsmmap.c (grub_cmd_lsmmap): use grub_mmap_iterate
+	* loader/i386/linux.c (find_mmap_size): likewise
+	(allocate_pages): likewise
+	* loader/i386/multiboot.c (grub_get_multiboot_mmap_len): likewise
+	(grub_fill_multiboot_mmap): likewise
+	(grub_multiboot): use grub_mmap_get_lower and grub_mmap_get_upper
+	* loader/i386/pc/linux.c (grub_cmd_linux): use grub_mmap_get_lower
+	* include/grub/i386/bsd.h (OPENBSD_MMAP_AVAILABLE): new definition
+	(OPENBSD_MMAP_RESERVED): likewise
+	* include/grub/i386/pc/memory.h: include grub/memory.h
+	(grub_lower_mem): removed
+	(grub_upper_mem): likewise
+	(GRUB_MACHINE_MEMORY_ACPI): new definition
+	(GRUB_MACHINE_MEMORY_NVS): likewise
+	(GRUB_MACHINE_MEMORY_MAX_TYPE): likewise
+	(GRUB_MACHINE_MEMORY_HOLE): likewise
+	(grub_machine_mmap_register): likewise
+	(grub_machine_mmap_unregister): likewise
+	(grub_machine_get_upper): likewise
+	(grub_machine_get_lower): likewise
+	(grub_machine_get_post64): likewise
+	* conf/i386-pc.rmk (pkglib_MODULES): added mmap.mod
+	(mmap_mod_SOURCES): new variable
+	(mmap_mod_LDFLAGS): likewise
+	(mmap_mod_ASFLAGS): likewise
+	* conf/i386-coreboot.rmk: likewise
+	* conf/i386-ieee1275.rmk: likewise
+	* include/grub/types.h (UINT_TO_PTR): new macro
+	(PTR_TO_UINT32): likewise
+	(PTR_TO_UINT64): likewise
+	* include/grub/memory.h: new file
+	* mmap/i386/pc/mmap.c: likewise
+	* mmap/i386/pc/mmap_helper.S: likewise
+	* mmap/i386/uppermem.c: likewise
+	* mmap/mmap.c: likewise
+	* kern/i386/coreboot/init.c (grub_machine_init): don't use 
+	grub_upper_mem
+	* kern/i386/pc/init.c (grub_lower_mem): removed variable
+	(grub_upper_mem): likewise
+	(grub_machine_init): don't use grub_upper_mem,
+	make grub_lower_mem local
+	* loader/i386/bsd.c (grub_openbsd_boot): use grub_mmap_get_lower,
+	grub_mmap_iterate and grub_mmap_get_upper
+	(grub_netbsd_boot): use grub_mmap_get_lower and grub_mmap_get_upper
+
 2009-04-06  Vladimir Serbinenko <phcoder@gmail.com>
 
 	Preboot hooks support
diff --git a/conf/i386-coreboot.rmk b/conf/i386-coreboot.rmk
index bc500d9..554463f 100644
--- a/conf/i386-coreboot.rmk
+++ b/conf/i386-coreboot.rmk
@@ -102,7 +102,13 @@ pkglib_MODULES = linux.mod normal.mod multiboot.mod 	\
 	aout.mod play.mod serial.mod ata.mod		\
 	memdisk.mod pci.mod lspci.mod reboot.mod	\
 	halt.mod datetime.mod date.mod datehook.mod	\
-	lsmmap.mod
+	lsmmap.mod mmap.mod
+
+# For mmap.mod.
+mmap_mod_SOURCES = mmap/mmap.c mmap/i386/uppermem.c
+mmap_mod_CFLAGS = $(COMMON_CFLAGS)
+mmap_mod_LDFLAGS = $(COMMON_LDFLAGS)
+mmap_mod_ASFLAGS = $(COMMON_ASFLAGS)
 
 # For linux.mod.
 linux_mod_SOURCES = loader/i386/linux.c
diff --git a/conf/i386-ieee1275.rmk b/conf/i386-ieee1275.rmk
index bbd6c09..9c0e4bc 100644
--- a/conf/i386-ieee1275.rmk
+++ b/conf/i386-ieee1275.rmk
@@ -103,7 +103,13 @@ grub_install_SOURCES = util/ieee1275/grub-install.in
 pkglib_MODULES = normal.mod halt.mod reboot.mod suspend.mod		\
 	multiboot.mod aout.mod serial.mod linux.mod	\
 	nand.mod memdisk.mod pci.mod lspci.mod datetime.mod	\
-	date.mod datehook.mod lsmmap.mod
+	date.mod datehook.mod lsmmap.mod mmap.mod
+
+# For mmap.mod.
+mmap_mod_SOURCES = mmap/mmap.c mmap/i386/uppermem.c
+mmap_mod_CFLAGS = $(COMMON_CFLAGS)
+mmap_mod_LDFLAGS = $(COMMON_LDFLAGS)
+mmap_mod_ASFLAGS = $(COMMON_ASFLAGS)
 
 #
 # Only arch dependant part of normal.mod will be here. Common part for
diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk
index fdb43df..178974c 100644
--- a/conf/i386-pc.rmk
+++ b/conf/i386-pc.rmk
@@ -175,7 +175,15 @@ pkglib_MODULES = biosdisk.mod chain.mod normal.mod \
 	ata.mod vga.mod memdisk.mod pci.mod lspci.mod	\
 	aout.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 \
+	mmap.mod
+
+# For mmap.mod.
+mmap_mod_SOURCES = mmap/mmap.c mmap/i386/uppermem.c mmap/i386/pc/mmap.c \
+		   mmap/i386/pc/mmap_helper.S
+mmap_mod_CFLAGS = $(COMMON_CFLAGS)
+mmap_mod_LDFLAGS = $(COMMON_LDFLAGS)
+mmap_mod_ASFLAGS = $(COMMON_ASFLAGS)
 
 # For biosdisk.mod.
 biosdisk_mod_SOURCES = disk/i386/pc/biosdisk.c
diff --git a/include/grub/i386/bsd.h b/include/grub/i386/bsd.h
index f50f18e..78fae79 100644
--- a/include/grub/i386/bsd.h
+++ b/include/grub/i386/bsd.h
@@ -148,6 +148,8 @@ struct grub_openbsd_bios_mmap
 {
   grub_uint64_t addr;
   grub_uint64_t len;
+#define	OPENBSD_MMAP_AVAILABLE	1
+#define	OPENBSD_MMAP_RESERVED 2
   grub_uint32_t type;
 };
 
diff --git a/include/grub/i386/pc/memory.h b/include/grub/i386/pc/memory.h
index 08e92a9..610c65a 100644
--- a/include/grub/i386/pc/memory.h
+++ b/include/grub/i386/pc/memory.h
@@ -25,6 +25,7 @@
 #ifndef ASM_FILE
 #include <grub/types.h>
 #include <grub/err.h>
+#include <grub/memory.h>
 #endif
 
 /* The scratch buffer used in real mode code.  */
@@ -79,12 +80,6 @@
 
 #ifndef ASM_FILE
 
-#ifndef GRUB_MACHINE_IEEE1275
-extern grub_size_t EXPORT_VAR(grub_lower_mem);
-#endif
-
-extern grub_size_t EXPORT_VAR(grub_upper_mem);
-
 struct grub_machine_mmap_entry
 {
   grub_uint32_t size;
@@ -92,12 +87,40 @@ struct grub_machine_mmap_entry
   grub_uint64_t len;
 #define GRUB_MACHINE_MEMORY_AVAILABLE	1
 #define GRUB_MACHINE_MEMORY_RESERVED	2
+#define GRUB_MACHINE_MEMORY_ACPI	3
+#define GRUB_MACHINE_MEMORY_NVS 	4
+#define GRUB_MACHINE_MEMORY_MAX_TYPE 	4
+  /* This one is special: it's used internally but is never reported 
+     by firmware. */
+#define GRUB_MACHINE_MEMORY_HOLE 	5
+
   grub_uint32_t type;
 } __attribute__((packed));
 
 grub_err_t EXPORT_FUNC(grub_machine_mmap_iterate)
      (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, grub_uint64_t, grub_uint32_t));
 
+grub_uint64_t grub_mmap_get_post64 (void);
+grub_uint64_t grub_mmap_get_upper (void);
+grub_uint64_t grub_mmap_get_lower (void);
+
+#ifdef GRUB_MACHINE_PCBIOS
+grub_err_t grub_machine_mmap_register (grub_uint64_t start, grub_uint64_t size, 
+				       int type, int handle);
+grub_err_t grub_machine_mmap_unregister (int handle);
+#else
+static inline grub_err_t grub_machine_mmap_register (grub_uint64_t start, 
+					      grub_uint64_t size, 
+					      int type, int handle)
+{
+  return GRUB_ERR_NONE;
+}
+static inline grub_err_t grub_machine_mmap_unregister (int handle)
+{
+  return GRUB_ERR_NONE;
+}
+#endif
+
 #endif
 
 #endif /* ! GRUB_MEMORY_MACHINE_HEADER */
diff --git a/include/grub/memory.h b/include/grub/memory.h
new file mode 100644
index 0000000..03a8516
--- /dev/null
+++ b/include/grub/memory.h
@@ -0,0 +1,34 @@
+/* memory.h - describe the memory map */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2002,2007,2008  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_MEMORY_HEADER
+#define GRUB_MEMORY_HEADER	1
+
+#include <grub/types.h>
+#include <grub/err.h>
+
+grub_err_t
+grub_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, 
+						 grub_uint64_t, grub_uint32_t));
+int
+grub_mmap_register (grub_uint64_t start, grub_uint64_t size, int type);
+grub_err_t
+grub_mmap_unregister (int handle);
+
+#endif /* ! GRUB_MEMORY_HEADER */
diff --git a/include/grub/types.h b/include/grub/types.h
index 8d51b66..faf2257 100644
--- a/include/grub/types.h
+++ b/include/grub/types.h
@@ -100,6 +100,16 @@ typedef grub_int32_t	grub_ssize_t;
 # 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;
 
diff --git a/kern/i386/coreboot/init.c b/kern/i386/coreboot/init.c
index 1348488..2f7e875 100644
--- a/kern/i386/coreboot/init.c
+++ b/kern/i386/coreboot/init.c
@@ -82,16 +82,11 @@ grub_machine_init (void)
 #if GRUB_CPU_SIZEOF_VOID_P == 4
     /* Restrict ourselves to 32-bit memory space.  */
     if (addr > ULONG_MAX)
-      {
-	grub_upper_mem = ULONG_MAX;
-	return 0;
-      }
+      return 0;
     if (addr + size > ULONG_MAX)
       size = ULONG_MAX - addr;
 #endif
 
-    grub_upper_mem = grub_max (grub_upper_mem, addr + size);
-
     if (type != GRUB_MACHINE_MEMORY_AVAILABLE)
       return 0;
 
@@ -128,9 +123,6 @@ grub_machine_init (void)
   grub_machine_mmap_init ();
   grub_machine_mmap_iterate (heap_init);
 
-  /* This variable indicates size, not offset.  */
-  grub_upper_mem -= GRUB_MEMORY_MACHINE_UPPER_START;
-
   grub_tsc_init ();
 }
 
diff --git a/kern/i386/pc/init.c b/kern/i386/pc/init.c
index 6191412..c64497e 100644
--- a/kern/i386/pc/init.c
+++ b/kern/i386/pc/init.c
@@ -45,7 +45,6 @@ static int num_regions;
 
 grub_addr_t grub_os_area_addr;
 grub_size_t grub_os_area_size;
-grub_size_t grub_lower_mem, grub_upper_mem;
 
 void 
 grub_arch_sync_caches (void *address __attribute__ ((unused)),
@@ -133,6 +132,7 @@ void
 grub_machine_init (void)
 {
   int i;
+  int grub_lower_mem;
   
   /* Initialize the console as early as possible.  */
   grub_console_init ();
@@ -197,7 +197,6 @@ grub_machine_init (void)
       {
 	grub_size_t quarter = mem_regions[i].size >> 2;
 
-	grub_upper_mem = mem_regions[i].size;
 	grub_os_area_addr = mem_regions[i].addr;
 	grub_os_area_size = mem_regions[i].size - quarter;
 	grub_mm_init_region ((void *) (grub_os_area_addr + grub_os_area_size),
diff --git a/loader/i386/bsd.c b/loader/i386/bsd.c
index 355cb3f..ea51aa2 100644
--- a/loader/i386/bsd.c
+++ b/loader/i386/bsd.c
@@ -313,30 +313,36 @@ static grub_err_t
 grub_openbsd_boot (void)
 {
   char *buf = (char *) GRUB_BSD_TEMP_BUFFER;
-  struct grub_machine_mmap_entry mmap;
   struct grub_openbsd_bios_mmap *pm;
   struct grub_openbsd_bootargs *pa;
-  grub_uint32_t bootdev, biosdev, unit, slice, part, cont;
+  grub_uint32_t bootdev, biosdev, unit, slice, part;
+
+  auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t);
+  int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size, grub_uint32_t type)
+    {
+      pm->addr = addr;
+      pm->len = size;
+
+      switch (type)
+        {
+        case GRUB_MACHINE_MEMORY_AVAILABLE:
+	  pm->type = OPENBSD_MMAP_AVAILABLE;
+	  break;
+	  
+	default:
+	  pm->type = OPENBSD_MMAP_RESERVED;
+	  break;
+	}
+      pm++;
+
+      return 0;
+    }
 
   pa = (struct grub_openbsd_bootargs *) buf;
 
   pa->ba_type = OPENBSD_BOOTARG_MMAP;
   pm = (struct grub_openbsd_bios_mmap *) (pa + 1);
-  cont = grub_get_mmap_entry (&mmap, 0);
-  if (mmap.size)
-    do
-      {
-	pm->addr = mmap.addr;
-	pm->len = mmap.len;
-	pm->type = mmap.type;
-	pm++;
-
-	if (!cont)
-	  break;
-
-	cont = grub_get_mmap_entry (&mmap, cont);
-      }
-    while (mmap.size);
+  grub_mmap_iterate (hook);
 
   pa->ba_size = (char *) pm - (char *) pa;
   pa->ba_next = (struct grub_openbsd_bootargs *) pm;
@@ -349,7 +355,8 @@ grub_openbsd_boot (void)
 	     (part << OPENBSD_B_PARTSHIFT));
 
   grub_unix_real_boot (entry, bootflags, bootdev, OPENBSD_BOOTARG_APIVER,
-		       0, grub_upper_mem >> 10, grub_lower_mem >> 10,
+		       0, grub_mmap_get_upper () >> 10, 
+		       grub_mmap_get_lower () >> 10,
 		       (char *) pa - buf, buf);
 
   /* Not reached.  */
@@ -377,7 +384,8 @@ grub_netbsd_boot (void)
   bootinfo->bi_data[0] = rootdev;
 
   grub_unix_real_boot (entry, bootflags, 0, bootinfo,
-		       0, grub_upper_mem >> 10, grub_lower_mem >> 10);
+		       0, grub_mmap_get_upper () >> 10, 
+		       grub_mmap_get_lower () >> 10);
 
   /* Not reached.  */
   return GRUB_ERR_NONE;
diff --git a/loader/i386/ieee1275/linux.c b/loader/i386/ieee1275/linux.c
index 2f52880..a563577 100644
--- a/loader/i386/ieee1275/linux.c
+++ b/loader/i386/ieee1275/linux.c
@@ -100,7 +100,7 @@ grub_linux_boot (void)
 
   grub_memset ((char *) params, 0, GRUB_OFW_LINUX_CL_OFFSET);
 
-  params->alt_mem = grub_upper_mem >> 10;
+  params->alt_mem = grub_mmap_get_upper () >> 10;
   params->ext_mem = params->alt_mem;
 
   lh->cmd_line_ptr = (char *)
diff --git a/loader/i386/linux.c b/loader/i386/linux.c
index 01d10d5..aac9bf3 100644
--- a/loader/i386/linux.c
+++ b/loader/i386/linux.c
@@ -168,7 +168,7 @@ find_mmap_size (void)
       return 0;
     }
   
-  grub_machine_mmap_iterate (hook);
+  grub_mmap_iterate (hook);
   
   mmap_size = count * sizeof (struct grub_e820_mmap);
 
@@ -237,7 +237,7 @@ allocate_pages (grub_size_t prot_size)
 
       return 0;
     }
-  grub_machine_mmap_iterate (hook);
+  grub_mmap_iterate (hook);
   if (! real_mode_mem)
     {
       grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate real mode pages");
@@ -404,7 +404,7 @@ grub_linux_boot (void)
     }
 
   e820_num = 0;
-  grub_machine_mmap_iterate (hook);
+  grub_mmap_iterate (hook);
   params->mmap_size = e820_num;
 
   /* Hardware interrupts are not safe any longer.  */
diff --git a/loader/i386/multiboot.c b/loader/i386/multiboot.c
index 27042a5..d38590f 100644
--- a/loader/i386/multiboot.c
+++ b/loader/i386/multiboot.c
@@ -100,7 +100,7 @@ grub_get_multiboot_mmap_len (void)
       return 0;
     }
   
-  grub_machine_mmap_iterate (hook);
+  grub_mmap_iterate (hook);
   
   return count * sizeof (struct grub_multiboot_mmap_entry);
 }
@@ -123,7 +123,7 @@ grub_fill_multiboot_mmap (struct grub_multiboot_mmap_entry *first_entry)
       return 0;
     }
 
-  grub_machine_mmap_iterate (hook);
+  grub_mmap_iterate (hook);
 }
 
 #define MULTIBOOT_LOAD_ELF64
@@ -342,8 +342,8 @@ grub_multiboot (int argc, char *argv[])
 		grub_multiboot_payload_entry_offset);
 
   /* Convert from bytes to kilobytes.  */
-  mbi->mem_lower = grub_lower_mem / 1024;
-  mbi->mem_upper = grub_upper_mem / 1024;
+  mbi->mem_lower = grub_mmap_get_lower () / 1024;
+  mbi->mem_upper = grub_mmap_get_upper () / 1024;
   mbi->flags |= MULTIBOOT_INFO_MEMORY;
 
   cmdline = p = cmdline_addr (grub_multiboot_payload_orig);
diff --git a/loader/i386/pc/linux.c b/loader/i386/pc/linux.c
index 8ff97f4..34a4ebc 100644
--- a/loader/i386/pc/linux.c
+++ b/loader/i386/pc/linux.c
@@ -108,8 +108,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
       lh.type_of_loader = GRUB_LINUX_BOOT_LOADER_TYPE;
       
       /* Put the real mode part at as a high location as possible.  */
-      grub_linux_real_addr = (char *) (grub_lower_mem
-				       - GRUB_LINUX_SETUP_MOVE_SIZE);
+      grub_linux_real_addr 
+	= (char *) UINT_TO_PTR (grub_mmap_get_lower ()
+				- GRUB_LINUX_SETUP_MOVE_SIZE);
       /* But it must not exceed the traditional area.  */
       if (grub_linux_real_addr > (char *) GRUB_LINUX_OLD_REAL_MODE_ADDR)
 	grub_linux_real_addr = (char *) GRUB_LINUX_OLD_REAL_MODE_ADDR;
@@ -159,12 +160,12 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
     }
   
   if (grub_linux_real_addr + GRUB_LINUX_SETUP_MOVE_SIZE
-      > (char *) grub_lower_mem)
+      > (char *) UINT_TO_PTR (grub_mmap_get_lower ()))
     {
       grub_error (GRUB_ERR_OUT_OF_RANGE,
 		 "too small lower memory (0x%x > 0x%x)",
-		 grub_linux_real_addr + GRUB_LINUX_SETUP_MOVE_SIZE,
-		 (char *) grub_lower_mem);
+		  grub_linux_real_addr + GRUB_LINUX_SETUP_MOVE_SIZE,
+		  (int) grub_mmap_get_lower ());
       goto fail;
     }
 
diff --git a/mmap/i386/pc/mmap.c b/mmap/i386/pc/mmap.c
new file mode 100644
index 0000000..3b45de4
--- /dev/null
+++ b/mmap/i386/pc/mmap.c
@@ -0,0 +1,240 @@
+/* Mmap management. */
+/*
+ *  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/machine/memory.h>
+#include <grub/memory.h>
+#include <grub/loader.h>
+#include <grub/misc.h>
+#include <grub/term.h>
+
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+
+static void *hooktarget = 0;
+
+extern grub_uint8_t grub_machine_mmaphook_start;
+extern grub_uint8_t grub_machine_mmaphook_end;
+extern grub_uint8_t grub_machine_mmaphook_int12;
+extern grub_uint8_t grub_machine_mmaphook_int15;
+
+static grub_uint16_t grub_machine_mmaphook_int12offset = 0;
+static grub_uint16_t grub_machine_mmaphook_int12segment = 0;
+extern grub_uint16_t grub_machine_mmaphook_int15offset;
+extern grub_uint16_t grub_machine_mmaphook_int15segment;
+
+extern grub_uint16_t grub_machine_mmaphook_mmap_num;
+extern grub_uint16_t grub_machine_mmaphook_kblow;
+extern grub_uint16_t grub_machine_mmaphook_kbin16mb;
+extern grub_uint16_t grub_machine_mmaphook_64kbin4gb;
+
+struct grub_e820_mmap_entry
+{
+  grub_uint64_t addr;
+  grub_uint64_t len;
+  grub_uint32_t type;
+} __attribute__((packed));
+
+
+static grub_err_t 
+preboot (int noreturn __attribute__ ((unused)))
+{
+  struct grub_e820_mmap_entry *hookmmap, *hookmmapcur;
+  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)
+  {
+    grub_dprintf ("mmap", "mmap chunk %llx-%llx:%x\n", addr, addr + size, type);
+    hookmmapcur->addr = addr;
+    hookmmapcur->len = size;
+    hookmmapcur->type = type;
+    hookmmapcur++;
+    return 0;
+  }
+
+  if (! hooktarget)
+    return grub_error (GRUB_ERR_OUT_OF_MEMORY, 
+		       "no space is allocated for memory hook");
+
+  grub_dprintf ("mmap", "installing preboot handlers\n");
+
+  hookmmapcur = hookmmap = (struct grub_e820_mmap_entry *) 
+    ((grub_uint8_t *) hooktarget + (&grub_machine_mmaphook_end 
+				    - &grub_machine_mmaphook_start));
+
+  grub_mmap_iterate (fill_hook);  
+  grub_machine_mmaphook_mmap_num = hookmmapcur - hookmmap;
+
+  grub_machine_mmaphook_kblow = grub_mmap_get_lower () >> 10;
+  grub_machine_mmaphook_kbin16mb 
+    = min (grub_mmap_get_upper (),0x3f00000ULL) >> 10;
+  grub_machine_mmaphook_64kbin4gb 
+    = min (grub_mmap_get_post64 (), 0xfc000000ULL) >> 16;
+
+  /* Correct BDA. */
+  *((grub_uint16_t *) 0x413) = grub_mmap_get_lower () >> 10;
+
+  /* Save old interrupt handlers. */
+  grub_machine_mmaphook_int12offset = *((grub_uint16_t *) 0x48);
+  grub_machine_mmaphook_int12segment = *((grub_uint16_t *) 0x4a);
+  grub_machine_mmaphook_int15offset = *((grub_uint16_t *) 0x54);
+  grub_machine_mmaphook_int15segment = *((grub_uint16_t *) 0x56);
+
+  grub_dprintf ("mmap", "hooktarget = %p\n", hooktarget);
+
+  /* Install the interrupt handlers. */
+  grub_memcpy (hooktarget, &grub_machine_mmaphook_start,
+	       &grub_machine_mmaphook_end - &grub_machine_mmaphook_start);
+
+  *((grub_uint16_t *) 0x4a) = PTR_TO_UINT32 (hooktarget) >> 4;
+  *((grub_uint16_t *) 0x56) = PTR_TO_UINT32 (hooktarget) >> 4;
+  *((grub_uint16_t *) 0x48) = &grub_machine_mmaphook_int12 
+    - &grub_machine_mmaphook_start;
+  *((grub_uint16_t *) 0x54) = &grub_machine_mmaphook_int15
+    - &grub_machine_mmaphook_start;
+
+  return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+preboot_rest (void)
+{
+  /* Restore old interrupt handlers. */
+  *((grub_uint16_t *) 0x48) = grub_machine_mmaphook_int12offset;
+  *((grub_uint16_t *) 0x4a) = grub_machine_mmaphook_int12segment;
+  *((grub_uint16_t *) 0x54) = grub_machine_mmaphook_int15offset;
+  *((grub_uint16_t *) 0x56) = grub_machine_mmaphook_int15segment;
+
+  return GRUB_ERR_NONE;
+}
+
+static grub_err_t 
+malloc_hook (void)
+{
+  static int reentry = 0;
+  static int mmapregion = 0;
+  static int slots_available = 0;
+  int hooksize;
+  int regcount = 0;
+  grub_uint64_t highestlow = 0;
+  auto int NESTED_FUNC_ATTR count_hook (grub_uint64_t, grub_uint64_t, 
+					grub_uint32_t);
+  int NESTED_FUNC_ATTR count_hook (grub_uint64_t addr __attribute__ ((unused)), 
+				   grub_uint64_t size __attribute__ ((unused)), 
+				   grub_uint32_t type __attribute__ ((unused)))
+  {
+    regcount++;
+    return 0;
+  }
+
+  auto int NESTED_FUNC_ATTR find_hook (grub_uint64_t, grub_uint64_t, 
+				       grub_uint32_t);
+  int NESTED_FUNC_ATTR find_hook (grub_uint64_t start, grub_uint64_t size, 
+				  grub_uint32_t type)
+  {
+    grub_uint64_t end = start + size;
+    if (type != GRUB_MACHINE_MEMORY_AVAILABLE)
+      return 0;
+    if (end > 0x100000)
+      end = 0x100000;
+    if (end > start + hooksize
+	&& highestlow < ((end - hooksize) & (~0xf)) )
+      highestlow = (end - hooksize) & (~0xf);
+    return 0;
+  }
+
+  if (reentry)
+    return GRUB_ERR_NONE;
+
+  grub_dprintf ("mmap", "registering\n");
+
+  grub_mmap_iterate (count_hook);
+
+  /* Mapping hook itself may introduce up to 2 additional regions. */
+  regcount += 2;
+
+  if (regcount <= slots_available)
+    return GRUB_ERR_NONE;
+
+  if (mmapregion)
+    {
+      grub_mmap_unregister (mmapregion);
+      mmapregion = 0;
+      hooktarget = 0;
+    }
+
+  hooksize = &grub_machine_mmaphook_end - &grub_machine_mmaphook_start
+    + regcount * sizeof (struct grub_e820_mmap_entry);
+  /* Allocate an integer number of KiB. */
+  hooksize = ((hooksize - 1) | 0x3ff) + 1;
+  slots_available = (hooksize - (&grub_machine_mmaphook_end 
+				 - &grub_machine_mmaphook_start))
+    / sizeof (struct grub_e820_mmap_entry);
+    
+  /* FIXME: use low-memory mm allocation once it's available. */
+  grub_mmap_iterate (find_hook);
+  if (! highestlow)
+    {
+      slots_available = 0;
+      hooktarget = 0;
+      return grub_error (GRUB_ERR_OUT_OF_MEMORY, "No space for mmap hook");
+    }
+
+  hooktarget = UINT_TO_PTR (highestlow);
+
+  reentry = 1;
+  mmapregion = grub_mmap_register (PTR_TO_UINT64 (hooktarget), hooksize, 
+				   GRUB_MACHINE_MEMORY_RESERVED);
+  reentry = 0;
+  if (! mmapregion)
+    {
+      slots_available = 0;
+      hooktarget = 0;
+      return grub_errno;
+    }
+  return GRUB_ERR_NONE;
+}
+
+grub_err_t
+grub_machine_mmap_register (grub_uint64_t start __attribute__ ((unused)), 
+			    grub_uint64_t size __attribute__ ((unused)), 
+			    int type __attribute__ ((unused)),
+			    int handle  __attribute__ ((unused)))
+{
+  grub_err_t err;
+  static void *preb_handle = 0;
+
+  if ((err = malloc_hook ()))
+    return err;
+
+  if (! preb_handle)
+    {
+      grub_dprintf ("mmap", "adding preboot\n");
+      preb_handle = grub_loader_register_preboot_hook (preboot, preboot_rest, 
+						       -10);
+      if (! preb_handle)
+	return grub_errno;
+    }
+  return GRUB_ERR_NONE;
+}
+
+grub_err_t
+grub_machine_mmap_unregister (int handle __attribute__ ((unused)))
+{
+  return GRUB_ERR_NONE;
+}
diff --git a/mmap/i386/pc/mmap_helper.S b/mmap/i386/pc/mmap_helper.S
new file mode 100644
index 0000000..ab7c0d2
--- /dev/null
+++ b/mmap/i386/pc/mmap_helper.S
@@ -0,0 +1,122 @@
+/* Mmap management. */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2009  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/symbol.h>
+
+#define DS(x) ((x) - segstart)
+
+segstart:	
+VARIABLE(grub_machine_mmaphook_start)
+	.code16
+VARIABLE(grub_machine_mmaphook_int12)
+	push %ds
+	push %cs
+	pop %ds
+	movw DS (EXT_C (grub_machine_mmaphook_kblow)), %ax
+	pop %ds
+	iret
+
+VARIABLE(grub_machine_mmaphook_int15)
+	pushf
+	cmpw $0xe801, %ax
+	jz e801
+	cmpw $0xe820, %ax
+	jz e820
+	cmpb $0x88, %ah
+	jz h88
+	popf
+	/* ljmp */
+	.byte	0xea
+VARIABLE (grub_machine_mmaphook_int15offset)
+	.word	0
+VARIABLE (grub_machine_mmaphook_int15segment)
+	.word	0
+	
+e801:
+	popf
+	push %ds
+	push %cs
+	pop %ds
+	movw DS (EXT_C (grub_machine_mmaphook_kbin16mb)), %ax
+	movw DS (EXT_C (grub_machine_mmaphook_64kbin4gb)), %bx
+	movw %ax, %cx
+	movw %bx, %dx
+	pop %ds
+	clc
+	iret
+
+h88:
+	popf
+	push %ds
+	push %cs
+	pop %ds
+	movw DS (EXT_C (grub_machine_mmaphook_kbin16mb)), %ax
+	pop %ds
+	clc
+	iret
+
+e820:
+	popf
+	push %ds
+	push %cs
+	pop %ds
+	cmpw $20, %cx
+	jb errexit
+	cmpw DS (EXT_C (grub_machine_mmaphook_mmap_num)), %bx
+	jae errexit
+	cmp $0x534d4150, %edx
+	jne errexit
+	push %si
+	push %di
+	movw $20, %cx
+	movw $(DS(mmaphook_mmap)), %si
+	mov %bx, %ax
+	imul $20, %ax
+	add %ax, %si
+	rep movsb
+	pop %di
+	pop %si
+	movl $20, %ecx
+	inc %bx
+	cmpw DS(EXT_C(grub_machine_mmaphook_mmap_num)), %bx
+	jb noclean
+	xor %bx, %bx	
+noclean:	
+	mov $0x534d4150, %eax
+	pop %ds
+	clc
+	iret
+errexit:
+	mov $0x534d4150, %eax
+	pop %ds
+	stc
+	xor %bx, %bx
+	iret	
+	
+VARIABLE(grub_machine_mmaphook_mmap_num)
+	.word 0
+VARIABLE(grub_machine_mmaphook_kblow)
+	.word 0
+VARIABLE (grub_machine_mmaphook_kbin16mb)
+	.word 0
+VARIABLE (grub_machine_mmaphook_64kbin4gb)
+	.word 0
+mmaphook_mmap:
+	/* Memory map is placed just after the interrupt handlers. */
+VARIABLE(grub_machine_mmaphook_end)
diff --git a/mmap/i386/uppermem.c b/mmap/i386/uppermem.c
new file mode 100644
index 0000000..1fb339d
--- /dev/null
+++ b/mmap/i386/uppermem.c
@@ -0,0 +1,85 @@
+/* Compute amount of lower and upper memory till the first hole. */
+/*
+ *  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/machine/memory.h>
+#include <grub/mm.h>
+#include <grub/misc.h>
+
+grub_uint64_t 
+grub_mmap_get_lower (void)
+{
+  grub_uint64_t lower = 0;
+
+  auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t);
+  int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size,
+			     grub_uint32_t type)
+    {
+      if (type != GRUB_MACHINE_MEMORY_AVAILABLE)
+	return 0;
+      if (addr == 0)
+	lower = size;
+      return 0;
+    }
+
+  grub_mmap_iterate (hook);
+  if (lower > 0x100000)
+    lower =  0x100000;
+  return lower;
+}
+
+grub_uint64_t 
+grub_mmap_get_upper (void)
+{
+  grub_uint64_t upper = 0;
+
+  auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t);
+  int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size,
+			     grub_uint32_t type)
+    {
+      if (type != GRUB_MACHINE_MEMORY_AVAILABLE)
+	return 0;
+      if (addr <= 0x100000 && addr + size > 0x100000)
+	upper = addr + size - 0x100000;
+      return 0;
+    }
+
+  grub_mmap_iterate (hook);
+  return upper;
+}
+
+/* Count the continous bytes after 64 MiB. */
+grub_uint64_t 
+grub_mmap_get_post64 (void)
+{
+  grub_uint64_t post64 = 0;
+
+  auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t);
+  int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size,
+			     grub_uint32_t type)
+    {
+      if (type != GRUB_MACHINE_MEMORY_AVAILABLE)
+	return 0;
+      if (addr <= 0x4000000 && addr + size > 0x4000000)
+	post64 = addr + size - 0x4000000;
+      return 0;
+    }
+
+  grub_mmap_iterate (hook);
+  return post64;
+}
diff --git a/mmap/mmap.c b/mmap/mmap.c
new file mode 100644
index 0000000..01480ff
--- /dev/null
+++ b/mmap/mmap.c
@@ -0,0 +1,364 @@
+/* Mmap management. */
+/*
+ *  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/machine/memory.h>
+#include <grub/memory.h>
+#include <grub/err.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/command.h>
+#include <grub/dl.h>
+
+#ifndef GRUB_MMAP_REGISTER_BY_FIRMWARE
+
+struct region
+{
+  struct region *next;
+  grub_uint64_t start;
+  grub_uint64_t end;
+  int type;
+  int handle;
+};
+
+static struct region *overlays = 0;
+static int curhandle = 1;
+
+grub_err_t
+grub_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, 
+						 grub_uint64_t, grub_uint32_t))
+{
+  /* This function resolves overlapping regions and sorts the memory map.
+     It uses scanline (sweeping) algorithm.
+  */
+  /* If same page is used by multiple types it's resolved 
+     according to priority:
+     1 - free memory
+     2 - memory usable by firmware-aware code
+     3 - unusable memory
+     4 - a range deliberately empty
+  */
+  int priority[GRUB_MACHINE_MEMORY_MAX_TYPE + 2] =
+    {
+#ifdef GRUB_MACHINE_MEMORY_AVAILABLE
+      [GRUB_MACHINE_MEMORY_AVAILABLE] = 1,
+#endif
+#ifdef GRUB_MACHINE_MEMORY_RESERVED
+      [GRUB_MACHINE_MEMORY_RESERVED] = 3,
+#endif
+#ifdef GRUB_MACHINE_MEMORY_ACPI
+      [GRUB_MACHINE_MEMORY_ACPI] = 2,
+#endif
+#ifdef GRUB_MACHINE_MEMORY_NVS
+      [GRUB_MACHINE_MEMORY_NVS] = 3,
+#endif
+      [GRUB_MACHINE_MEMORY_HOLE] = 4,
+    };
+
+  int i, k, done;
+
+  /* Scanline events. */
+  struct grub_mmap_scan
+  {
+    /* At which memory address. */
+    grub_uint64_t pos;
+    /* 0 = region starts, 1 = region ends. */
+    int type;
+    /* Which type of memory region? */
+    int memtype;
+  };
+  struct grub_mmap_scan *scanline_events;
+  struct grub_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_MACHINE_MEMORY_MAX_TYPE + 2];
+  /* Number of mmap chunks. */
+  int mmap_num;
+  
+  struct region *cur;
+  
+  auto int NESTED_FUNC_ATTR count_hook (grub_uint64_t, grub_uint64_t, 
+					grub_uint32_t);
+  int NESTED_FUNC_ATTR count_hook (grub_uint64_t addr __attribute__ ((unused)),
+				   grub_uint64_t size __attribute__ ((unused)),
+				   grub_uint32_t type __attribute__ ((unused)))
+  {
+    mmap_num++;
+    return 0;
+  }
+
+  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)
+  {
+    scanline_events[i].pos = addr;
+    scanline_events[i].type = 0;
+    if (type <= GRUB_MACHINE_MEMORY_MAX_TYPE && priority[type])
+      scanline_events[i].memtype = type;
+    else
+      {
+	grub_dprintf ("mmap", "Unknown memory type %d. Assuming unusable\n",
+		      type);
+	scanline_events[i].memtype = GRUB_MACHINE_MEMORY_RESERVED;
+      }
+    i++;
+
+    scanline_events[i].pos = addr + size;
+    scanline_events[i].type = 1;
+    scanline_events[i].memtype = scanline_events[i - 1].memtype;
+    i++;
+
+    return 0;
+  }
+  
+  mmap_num = 0;
+  for (cur = overlays; cur; cur = cur->next)
+    mmap_num++;
+  grub_machine_mmap_iterate (count_hook);
+  
+  /* Initialize variables. */
+  grub_memset (present, 0, sizeof (present));
+  scanline_events = (struct grub_mmap_scan *) 
+    grub_malloc (sizeof (struct grub_mmap_scan) * 2 * mmap_num);
+  
+  if (! scanline_events)
+    {
+      return grub_error (GRUB_ERR_OUT_OF_MEMORY, 
+			 "couldn't allocate space for new memory map");
+    }
+   
+  /* Register scanline events. */
+  for (cur = overlays, i = 0; cur; cur = cur->next)
+    {
+      scanline_events[i].pos = cur->start;
+      scanline_events[i].type = 0;
+      if (cur->type == GRUB_MACHINE_MEMORY_HOLE 
+	  || (cur->type >= 0 && cur->type <= GRUB_MACHINE_MEMORY_MAX_TYPE
+	      && priority[cur->type]))
+	scanline_events[i].memtype = cur->type;
+      else
+	scanline_events[i].memtype = GRUB_MACHINE_MEMORY_RESERVED;
+      i++;
+
+      scanline_events[i].pos = cur->end;
+      scanline_events[i].type = 1;
+      scanline_events[i].memtype = scanline_events[i - 1].memtype;
+      i++;
+    }
+
+  grub_machine_mmap_iterate (fill_hook);
+
+  /* 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
+	    || (scanline_events[i + 1].pos == scanline_events[i].pos
+		&& scanline_events[i + 1].type == 0 
+		&& scanline_events[i].type == 1))
+	  {
+	    t = scanline_events[i + 1];
+	    scanline_events[i + 1] = scanline_events[i];
+	    scanline_events[i] = t;
+	    done = 1;
+	  }
+    }
+
+  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_MACHINE_MEMORY_MAX_TYPE + 1; k++)
+	if (present[k] && (curtype == -1 || priority[k] > priority[curtype]))
+	  curtype = k;
+
+      /* Anounce region to the hook if necessary. */
+      if ((curtype == -1 || curtype != lasttype) 
+	  && lastaddr != scanline_events[i].pos
+	  && lasttype != -1
+	  && lasttype != GRUB_MACHINE_MEMORY_HOLE
+	  && hook (lastaddr, scanline_events[i].pos - lastaddr, lasttype))
+	{
+	  grub_free (scanline_events);
+	  return GRUB_ERR_NONE;
+	}
+
+      /* Update last values if necessary. */
+      if (curtype == -1 || curtype != lasttype) 
+	{
+	  lasttype = curtype;
+	  lastaddr = scanline_events[i].pos;
+	}
+    }
+
+  grub_free (scanline_events);
+  return GRUB_ERR_NONE;
+}
+
+int
+grub_mmap_register (grub_uint64_t start, grub_uint64_t size, int type)
+{
+  struct region *cur;
+
+  grub_dprintf ("mmap", "registering\n");
+
+  cur = (struct region *) grub_malloc (sizeof (struct region));
+  if (! cur)
+    {
+      grub_error (GRUB_ERR_OUT_OF_MEMORY, 
+		  "couldn't allocate memory map overlay");
+      return 0;
+    }
+
+  cur->next = overlays;
+  cur->start = start;
+  cur->end = start + size;
+  cur->type = type;
+  cur->handle = curhandle++;
+  overlays = cur;
+
+  if (grub_machine_mmap_register (start, size, type, curhandle))
+    {
+      overlays = cur->next;
+      grub_free (cur);
+      return 0;
+    }
+
+  return cur->handle;
+}
+
+grub_err_t
+grub_mmap_unregister (int handle)
+{
+  struct region *cur, *prev;
+
+  for (cur = overlays, prev = 0; cur; prev= cur, cur = cur->next)
+    if (handle == cur->handle)
+      {
+	grub_err_t err;
+	if ((err = grub_machine_mmap_unregister (handle)))
+	  return err;
+
+	if (prev)
+	  prev->next = cur->next;
+	else
+	  overlays = cur->next;
+	grub_free (cur);
+	return GRUB_ERR_NONE;
+      }
+  return grub_error (GRUB_ERR_BAD_ARGUMENT, "mmap overlay not found");
+}
+
+#endif /* ! GRUB_MMAP_REGISTER_BY_FIRMWARE */
+
+#define CHUNK_SIZE	0x400
+
+static grub_err_t
+grub_cmd_badram (grub_command_t cmd __attribute__ ((unused)),
+		 int argc, char **args)
+{
+  char * str;
+  grub_uint64_t badaddr, badmask;
+
+  auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t);
+  int NESTED_FUNC_ATTR hook (grub_uint64_t addr, 
+			     grub_uint64_t size, 
+			     grub_uint32_t type __attribute__ ((unused)))
+  {
+    grub_uint64_t start;
+    grub_dprintf ("badram", "hook %llx+%llx\n", addr,size); 
+
+    /* FIXME: use more efficient algorithm. */
+    for (start = (addr & ~(CHUNK_SIZE - 1)); start < addr + size; 
+	 start += CHUNK_SIZE)
+      if (((start ^ badaddr) & badmask) == 0)
+	{
+	  grub_dprintf ("badram", "%llx is a bad boy\n", start); 
+	  grub_mmap_register (start, CHUNK_SIZE, GRUB_MACHINE_MEMORY_HOLE);
+	}
+    return 0;
+  }
+
+  if (argc != 1)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT, "badram string required");
+
+  grub_dprintf ("badram", "executing badram\n");
+
+  str = args[0];
+
+  while (1)
+    {
+      /* Parse address and mask.  */
+      badaddr = grub_strtoull (str, &str, 16);
+      if (*str == ',')
+	str++;
+      badmask = grub_strtoull (str, &str, 16);
+      if (*str == ',')
+	str++;
+
+      if (grub_errno == GRUB_ERR_BAD_NUMBER)
+	{
+	  grub_errno = 0;
+	  return GRUB_ERR_NONE;
+	}
+
+      /* When part of a page is tainted, we discard the whole of it.  There's
+	 no point in providing sub-page chunks.  */
+      badmask &= ~(CHUNK_SIZE - 1);
+
+      grub_dprintf ("badram", "badram %llx:%llx\n", badaddr, badmask);
+
+      grub_mmap_iterate (hook);
+    }
+}
+
+static grub_command_t cmd;
+
+\f
+GRUB_MOD_INIT(mmap)
+{
+  (void) mod;			/* To stop warning. */
+  cmd = grub_register_command ("badram", grub_cmd_badram,
+			       "badram ADDR1,MASK1[,ADDR2,MASK2[,...]]", 
+			       "declare memory regions as badram");
+}
+
+GRUB_MOD_FINI(mmap)
+{
+  grub_unregister_command (cmd);
+}
+

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: mmap services
  2009-04-11 21:01 mmap services phcoder
@ 2009-04-26 14:42 ` Vladimir 'phcoder' Serbinenko
  2009-04-30 13:36   ` Vladimir 'phcoder' Serbinenko
  0 siblings, 1 reply; 4+ messages in thread
From: Vladimir 'phcoder' Serbinenko @ 2009-04-26 14:42 UTC (permalink / raw)
  To: The development of GRUB 2


[-- Attachment #1.1: Type: text/plain, Size: 610 bytes --]

Updated. Now works on EFI. Additional function
grub_mmap_malign_and_register
Which finds a spot in memory map with required characteristics and registers
it.
I successfully booted freedos with this patch and badram

On Sat, Apr 11, 2009 at 11:01 PM, phcoder <phcoder@gmail.com> wrote:

> Hello. Here is the patch to allow different mmap filtering. It naturally
> incorporates badram and also intercepts int12/15 so it works also with OS
> recieving mmap from BIOS. It's useful for intercepting any bios interrupts
> --
>
> Regards
> Vladimir 'phcoder' Serbinenko
>



-- 
Regards
Vladimir 'phcoder' Serbinenko

[-- Attachment #1.2: Type: text/html, Size: 967 bytes --]

[-- Attachment #2: mmap.diff --]
[-- Type: text/x-diff, Size: 60465 bytes --]

diff --git a/ChangeLog b/ChangeLog
index 2f2afc2..2a800d9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,60 @@
 2009-04-26  Vladimir Serbinenko <phcoder@gmail.com>
 
+	Mmap services
+
+	* loader/i386/efi/linux.c (grub_linux_boot): use grub_mmap_iterate
+	* loader/i386/linux.c (find_mmap_size): likewise
+	(allocate_pages): likewise
+	* loader/i386/multiboot.c (grub_get_multiboot_mmap_len): likewise
+	(grub_fill_multiboot_mmap): likewise
+	(grub_multiboot): use grub_mmap_get_lower and grub_mmap_get_upper
+	* loader/i386/pc/linux.c (grub_cmd_linux): use grub_mmap_get_lower
+	* include/grub/i386/bsd.h (OPENBSD_MMAP_AVAILABLE): new definition
+	(OPENBSD_MMAP_RESERVED): likewise
+	* include/grub/i386/pc/memory.h: include grub/memory.h
+	(grub_lower_mem): removed
+	(grub_upper_mem): likewise
+	(GRUB_MACHINE_MEMORY_ACPI): new definition
+	(GRUB_MACHINE_MEMORY_NVS): likewise
+	(GRUB_MACHINE_MEMORY_MAX_TYPE): likewise
+	(GRUB_MACHINE_MEMORY_HOLE): likewise
+	(grub_machine_mmap_register): likewise
+	(grub_machine_mmap_unregister): likewise
+	(grub_machine_get_upper): likewise
+	(grub_machine_get_lower): likewise
+	(grub_machine_get_post64): likewise
+	* include/grub/i386/efi/memory.h: new file
+	* include/grub/x86_64/efi/memory.h: likewise
+	* include/grub/efi/memory.h: likewise
+	* conf/i386-pc.rmk (pkglib_MODULES): added mmap.mod
+	(mmap_mod_SOURCES): new variable
+	(mmap_mod_LDFLAGS): likewise
+	(mmap_mod_ASFLAGS): likewise
+	* conf/i386-coreboot.rmk: likewise
+	* conf/i386-ieee1275.rmk: likewise
+	* conf/i386-efi.rmk: likewise
+	* conf/x86_64-efi.rmk: likewise
+	* include/grub/types.h (UINT_TO_PTR): new macro
+	(PTR_TO_UINT32): likewise
+	(PTR_TO_UINT64): likewise
+	* include/grub/memory.h: new file
+	* mmap/i386/pc/mmap.c: likewise
+	* mmap/i386/pc/mmap_helper.S: likewise
+	* mmap/i386/uppermem.c: likewise
+	* mmap/mmap.c: likewise
+	* mmap/efi/mmap.c: likewise
+	* kern/i386/coreboot/init.c (grub_machine_init): don't use 
+	grub_upper_mem
+	* kern/i386/pc/init.c (grub_lower_mem): removed variable
+	(grub_upper_mem): likewise
+	(grub_machine_init): don't use grub_upper_mem,
+	make grub_lower_mem local
+	* loader/i386/bsd.c (grub_openbsd_boot): use grub_mmap_get_lower,
+	grub_mmap_iterate and grub_mmap_get_upper
+	(grub_netbsd_boot): use grub_mmap_get_lower and grub_mmap_get_upper
+
+2009-04-26  Vladimir Serbinenko <phcoder@gmail.com>
+
 	Preboot hooks support
 
 	* commands/boot.c (struct grub_preboot_t): new declaration
diff --git a/conf/i386-coreboot.rmk b/conf/i386-coreboot.rmk
index 1284fe4..89014a6 100644
--- a/conf/i386-coreboot.rmk
+++ b/conf/i386-coreboot.rmk
@@ -104,7 +104,13 @@ pkglib_MODULES = linux.mod normal.mod multiboot.mod 	\
 	aout.mod play.mod serial.mod ata.mod		\
 	memdisk.mod pci.mod lspci.mod reboot.mod	\
 	halt.mod datetime.mod date.mod datehook.mod	\
-	lsmmap.mod
+	lsmmap.mod mmap.mod
+
+# For mmap.mod.
+mmap_mod_SOURCES = mmap/mmap.c mmap/i386/uppermem.c mmap/i386/mmap.c
+mmap_mod_CFLAGS = $(COMMON_CFLAGS)
+mmap_mod_LDFLAGS = $(COMMON_LDFLAGS)
+mmap_mod_ASFLAGS = $(COMMON_ASFLAGS)
 
 # For linux.mod.
 linux_mod_SOURCES = loader/i386/linux.c
diff --git a/conf/i386-efi.rmk b/conf/i386-efi.rmk
index 717683b..3c8c62d 100644
--- a/conf/i386-efi.rmk
+++ b/conf/i386-efi.rmk
@@ -82,7 +82,7 @@ grub_install_SOURCES = util/i386/efi/grub-install.in
 # Modules.
 pkglib_MODULES = kernel.mod normal.mod chain.mod appleldr.mod \
 	linux.mod halt.mod reboot.mod pci.mod lspci.mod \
-	datetime.mod date.mod datehook.mod loadbios.mod fixvideo.mod
+	datetime.mod date.mod datehook.mod loadbios.mod fixvideo.mod mmap.mod
 
 # For kernel.mod.
 kernel_mod_EXPORTS = no
@@ -135,6 +135,12 @@ normal_mod_CFLAGS = $(COMMON_CFLAGS)
 normal_mod_ASFLAGS = $(COMMON_ASFLAGS)
 normal_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
+# For mmap.mod.
+mmap_mod_SOURCES = mmap/mmap.c mmap/i386/uppermem.c mmap/i386/mmap.c \
+		   mmap/efi/mmap.c
+mmap_mod_CFLAGS = $(COMMON_CFLAGS)
+mmap_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
 # For chain.mod.
 chain_mod_SOURCES = loader/efi/chainloader.c
 chain_mod_CFLAGS = $(COMMON_CFLAGS)
diff --git a/conf/i386-ieee1275.rmk b/conf/i386-ieee1275.rmk
index cb32c73..08fdd98 100644
--- a/conf/i386-ieee1275.rmk
+++ b/conf/i386-ieee1275.rmk
@@ -104,7 +104,13 @@ grub_install_SOURCES = util/ieee1275/grub-install.in
 pkglib_MODULES = normal.mod halt.mod reboot.mod suspend.mod		\
 	multiboot.mod aout.mod serial.mod linux.mod	\
 	nand.mod memdisk.mod pci.mod lspci.mod datetime.mod	\
-	date.mod datehook.mod lsmmap.mod
+	date.mod datehook.mod lsmmap.mod mmap.mod
+
+# For mmap.mod.
+mmap_mod_SOURCES = mmap/mmap.c mmap/i386/uppermem.c mmap/i386/mmap.c
+mmap_mod_CFLAGS = $(COMMON_CFLAGS)
+mmap_mod_LDFLAGS = $(COMMON_LDFLAGS)
+mmap_mod_ASFLAGS = $(COMMON_ASFLAGS)
 
 #
 # Only arch dependant part of normal.mod will be here. Common part for
diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk
index d74a5fa..709741a 100644
--- a/conf/i386-pc.rmk
+++ b/conf/i386-pc.rmk
@@ -182,7 +182,15 @@ pkglib_MODULES = biosdisk.mod chain.mod normal.mod \
 	ata.mod vga.mod memdisk.mod pci.mod lspci.mod	\
 	aout.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 \
+	mmap.mod
+
+# For mmap.mod.
+mmap_mod_SOURCES = mmap/mmap.c mmap/i386/uppermem.c mmap/i386/mmap.c \
+		   mmap/i386/pc/mmap.c mmap/i386/pc/mmap_helper.S
+mmap_mod_CFLAGS = $(COMMON_CFLAGS)
+mmap_mod_LDFLAGS = $(COMMON_LDFLAGS)
+mmap_mod_ASFLAGS = $(COMMON_ASFLAGS)
 
 # For biosdisk.mod.
 biosdisk_mod_SOURCES = disk/i386/pc/biosdisk.c
diff --git a/conf/x86_64-efi.rmk b/conf/x86_64-efi.rmk
index d7ad9a4..d19649b 100644
--- a/conf/x86_64-efi.rmk
+++ b/conf/x86_64-efi.rmk
@@ -83,7 +83,7 @@ grub_install_SOURCES = util/i386/efi/grub-install.in
 # Modules.
 pkglib_MODULES = kernel.mod normal.mod chain.mod appleldr.mod \
 	halt.mod reboot.mod linux.mod pci.mod lspci.mod \
-	datetime.mod date.mod datehook.mod loadbios.mod fixvideo.mod
+	datetime.mod date.mod datehook.mod loadbios.mod fixvideo.mod mmap.mod
 
 # For kernel.mod.
 kernel_mod_EXPORTS = no
@@ -137,6 +137,12 @@ normal_mod_CFLAGS = $(COMMON_CFLAGS)
 normal_mod_ASFLAGS = $(COMMON_ASFLAGS)
 normal_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
+# For mmap.mod.
+mmap_mod_SOURCES = mmap/mmap.c mmap/i386/uppermem.c mmap/i386/mmap.c \
+		   mmap/efi/mmap.c
+mmap_mod_CFLAGS = $(COMMON_CFLAGS)
+mmap_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
 # For chain.mod.
 chain_mod_SOURCES = loader/efi/chainloader.c
 chain_mod_CFLAGS = $(COMMON_CFLAGS)
diff --git a/include/grub/efi/memory.h b/include/grub/efi/memory.h
new file mode 100644
index 0000000..e1ac47c
--- /dev/null
+++ b/include/grub/efi/memory.h
@@ -0,0 +1,48 @@
+/*
+ *  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_MEMORY_MACHINE_HEADER
+#define GRUB_MEMORY_MACHINE_HEADER	1
+
+#include <grub/err.h>
+#include <grub/types.h>
+
+#define GRUB_MMAP_REGISTER_BY_FIRMWARE  1
+
+#define GRUB_MACHINE_MEMORY_AVAILABLE	1
+#define GRUB_MACHINE_MEMORY_RESERVED	2
+#define GRUB_MACHINE_MEMORY_ACPI	3
+#define GRUB_MACHINE_MEMORY_NVS         4
+#define GRUB_MACHINE_MEMORY_CODE        5
+#define GRUB_MACHINE_MEMORY_MAX_TYPE 	5
+  /* This one is special: it's used internally but is never reported 
+     by firmware. */
+#define GRUB_MACHINE_MEMORY_HOLE 	6
+
+
+grub_err_t EXPORT_FUNC(grub_machine_mmap_iterate) 
+(int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, grub_uint64_t, grub_uint32_t));
+grub_err_t grub_machine_mmap_register (grub_uint64_t start, grub_uint64_t size, 
+				       int type, int handle);
+grub_err_t grub_machine_mmap_unregister (int handle);
+
+grub_uint64_t grub_mmap_get_post64 (void);
+grub_uint64_t grub_mmap_get_upper (void);
+grub_uint64_t grub_mmap_get_lower (void);
+
+#endif /* ! GRUB_MEMORY_MACHINE_HEADER */
diff --git a/include/grub/i386/bsd.h b/include/grub/i386/bsd.h
index f50f18e..78fae79 100644
--- a/include/grub/i386/bsd.h
+++ b/include/grub/i386/bsd.h
@@ -148,6 +148,8 @@ struct grub_openbsd_bios_mmap
 {
   grub_uint64_t addr;
   grub_uint64_t len;
+#define	OPENBSD_MMAP_AVAILABLE	1
+#define	OPENBSD_MMAP_RESERVED 2
   grub_uint32_t type;
 };
 
diff --git a/include/grub/i386/efi/memory.h b/include/grub/i386/efi/memory.h
new file mode 100644
index 0000000..c9a61bb
--- /dev/null
+++ b/include/grub/i386/efi/memory.h
@@ -0,0 +1 @@
+#include <grub/efi/memory.h>
diff --git a/include/grub/i386/pc/memory.h b/include/grub/i386/pc/memory.h
index 08e92a9..d8d4342 100644
--- a/include/grub/i386/pc/memory.h
+++ b/include/grub/i386/pc/memory.h
@@ -25,6 +25,7 @@
 #ifndef ASM_FILE
 #include <grub/types.h>
 #include <grub/err.h>
+#include <grub/memory.h>
 #endif
 
 /* The scratch buffer used in real mode code.  */
@@ -79,12 +80,6 @@
 
 #ifndef ASM_FILE
 
-#ifndef GRUB_MACHINE_IEEE1275
-extern grub_size_t EXPORT_VAR(grub_lower_mem);
-#endif
-
-extern grub_size_t EXPORT_VAR(grub_upper_mem);
-
 struct grub_machine_mmap_entry
 {
   grub_uint32_t size;
@@ -92,12 +87,41 @@ struct grub_machine_mmap_entry
   grub_uint64_t len;
 #define GRUB_MACHINE_MEMORY_AVAILABLE	1
 #define GRUB_MACHINE_MEMORY_RESERVED	2
+#define GRUB_MACHINE_MEMORY_ACPI	3
+#define GRUB_MACHINE_MEMORY_NVS 	4
+#define GRUB_MACHINE_MEMORY_MAX_TYPE 	4
+  /* This one is special: it's used internally but is never reported 
+     by firmware. */
+#define GRUB_MACHINE_MEMORY_HOLE 	5
+
   grub_uint32_t type;
 } __attribute__((packed));
 
 grub_err_t EXPORT_FUNC(grub_machine_mmap_iterate)
      (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, grub_uint64_t, grub_uint32_t));
 
+grub_uint64_t grub_mmap_get_post64 (void);
+grub_uint64_t grub_mmap_get_upper (void);
+grub_uint64_t grub_mmap_get_lower (void);
+
+#ifdef GRUB_MACHINE_PCBIOS
+grub_err_t grub_machine_mmap_register (grub_uint64_t start, grub_uint64_t size, 
+				       int type, int handle);
+grub_err_t grub_machine_mmap_unregister (int handle);
+#define GRUB_MMAP_MALLOC_LOW 1
+#else
+static inline grub_err_t grub_machine_mmap_register (grub_uint64_t start, 
+					      grub_uint64_t size, 
+					      int type, int handle)
+{
+  return GRUB_ERR_NONE;
+}
+static inline grub_err_t grub_machine_mmap_unregister (int handle)
+{
+  return GRUB_ERR_NONE;
+}
+#endif
+
 #endif
 
 #endif /* ! GRUB_MEMORY_MACHINE_HEADER */
diff --git a/include/grub/memory.h b/include/grub/memory.h
new file mode 100644
index 0000000..df64207
--- /dev/null
+++ b/include/grub/memory.h
@@ -0,0 +1,52 @@
+/* memory.h - describe the memory map */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2002,2007,2008  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_MEMORY_HEADER
+#define GRUB_MEMORY_HEADER	1
+
+#include <grub/types.h>
+#include <grub/err.h>
+#include <grub/machine/memory.h>
+
+grub_err_t grub_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, 
+							    grub_uint64_t, 
+							    grub_uint32_t));
+int grub_mmap_register (grub_uint64_t start, grub_uint64_t size, int type);
+grub_err_t grub_mmap_unregister (int handle);
+
+char *grub_mmap_malign_and_register (grub_uint64_t align, grub_uint64_t size,
+				     int *handle, int type, int flags);
+
+void grub_mmap_free_and_unregister (int handle);
+
+#ifndef GRUB_MMAP_REGISTER_BY_FIRMWARE
+
+struct grub_mmap_region
+{
+  struct grub_mmap_region *next;
+  grub_uint64_t start;
+  grub_uint64_t end;
+  int type;
+  int handle;
+};
+
+extern struct grub_mmap_region *grub_mmap_overlays;
+#endif
+
+#endif /* ! GRUB_MEMORY_HEADER */
diff --git a/include/grub/types.h b/include/grub/types.h
index 50f8f58..114b456 100644
--- a/include/grub/types.h
+++ b/include/grub/types.h
@@ -102,6 +102,16 @@ typedef grub_int32_t	grub_ssize_t;
 # define GRUB_LONG_MIN -2147483648UL
 #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;
 
diff --git a/include/grub/x86_64/efi/memory.h b/include/grub/x86_64/efi/memory.h
new file mode 100644
index 0000000..c9a61bb
--- /dev/null
+++ b/include/grub/x86_64/efi/memory.h
@@ -0,0 +1 @@
+#include <grub/efi/memory.h>
diff --git a/kern/i386/coreboot/init.c b/kern/i386/coreboot/init.c
index fdaf6fd..7bc4291 100644
--- a/kern/i386/coreboot/init.c
+++ b/kern/i386/coreboot/init.c
@@ -82,16 +82,11 @@ grub_machine_init (void)
 #if GRUB_CPU_SIZEOF_VOID_P == 4
     /* Restrict ourselves to 32-bit memory space.  */
     if (addr > GRUB_ULONG_MAX)
-      {
-	grub_upper_mem = GRUB_ULONG_MAX;
-	return 0;
-      }
-    if (addr + size > GRUB_ULONG_MAX)
+      return 0;
+    if (addr + size > ULONG_MAX)
       size = GRUB_ULONG_MAX - addr;
 #endif
 
-    grub_upper_mem = grub_max (grub_upper_mem, addr + size);
-
     if (type != GRUB_MACHINE_MEMORY_AVAILABLE)
       return 0;
 
@@ -128,9 +123,6 @@ grub_machine_init (void)
   grub_machine_mmap_init ();
   grub_machine_mmap_iterate (heap_init);
 
-  /* This variable indicates size, not offset.  */
-  grub_upper_mem -= GRUB_MEMORY_MACHINE_UPPER_START;
-
   grub_tsc_init ();
 }
 
diff --git a/kern/i386/pc/init.c b/kern/i386/pc/init.c
index 6191412..c64497e 100644
--- a/kern/i386/pc/init.c
+++ b/kern/i386/pc/init.c
@@ -45,7 +45,6 @@ static int num_regions;
 
 grub_addr_t grub_os_area_addr;
 grub_size_t grub_os_area_size;
-grub_size_t grub_lower_mem, grub_upper_mem;
 
 void 
 grub_arch_sync_caches (void *address __attribute__ ((unused)),
@@ -133,6 +132,7 @@ void
 grub_machine_init (void)
 {
   int i;
+  int grub_lower_mem;
   
   /* Initialize the console as early as possible.  */
   grub_console_init ();
@@ -197,7 +197,6 @@ grub_machine_init (void)
       {
 	grub_size_t quarter = mem_regions[i].size >> 2;
 
-	grub_upper_mem = mem_regions[i].size;
 	grub_os_area_addr = mem_regions[i].addr;
 	grub_os_area_size = mem_regions[i].size - quarter;
 	grub_mm_init_region ((void *) (grub_os_area_addr + grub_os_area_size),
diff --git a/loader/i386/bsd.c b/loader/i386/bsd.c
index 355cb3f..ea51aa2 100644
--- a/loader/i386/bsd.c
+++ b/loader/i386/bsd.c
@@ -313,30 +313,36 @@ static grub_err_t
 grub_openbsd_boot (void)
 {
   char *buf = (char *) GRUB_BSD_TEMP_BUFFER;
-  struct grub_machine_mmap_entry mmap;
   struct grub_openbsd_bios_mmap *pm;
   struct grub_openbsd_bootargs *pa;
-  grub_uint32_t bootdev, biosdev, unit, slice, part, cont;
+  grub_uint32_t bootdev, biosdev, unit, slice, part;
+
+  auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t);
+  int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size, grub_uint32_t type)
+    {
+      pm->addr = addr;
+      pm->len = size;
+
+      switch (type)
+        {
+        case GRUB_MACHINE_MEMORY_AVAILABLE:
+	  pm->type = OPENBSD_MMAP_AVAILABLE;
+	  break;
+	  
+	default:
+	  pm->type = OPENBSD_MMAP_RESERVED;
+	  break;
+	}
+      pm++;
+
+      return 0;
+    }
 
   pa = (struct grub_openbsd_bootargs *) buf;
 
   pa->ba_type = OPENBSD_BOOTARG_MMAP;
   pm = (struct grub_openbsd_bios_mmap *) (pa + 1);
-  cont = grub_get_mmap_entry (&mmap, 0);
-  if (mmap.size)
-    do
-      {
-	pm->addr = mmap.addr;
-	pm->len = mmap.len;
-	pm->type = mmap.type;
-	pm++;
-
-	if (!cont)
-	  break;
-
-	cont = grub_get_mmap_entry (&mmap, cont);
-      }
-    while (mmap.size);
+  grub_mmap_iterate (hook);
 
   pa->ba_size = (char *) pm - (char *) pa;
   pa->ba_next = (struct grub_openbsd_bootargs *) pm;
@@ -349,7 +355,8 @@ grub_openbsd_boot (void)
 	     (part << OPENBSD_B_PARTSHIFT));
 
   grub_unix_real_boot (entry, bootflags, bootdev, OPENBSD_BOOTARG_APIVER,
-		       0, grub_upper_mem >> 10, grub_lower_mem >> 10,
+		       0, grub_mmap_get_upper () >> 10, 
+		       grub_mmap_get_lower () >> 10,
 		       (char *) pa - buf, buf);
 
   /* Not reached.  */
@@ -377,7 +384,8 @@ grub_netbsd_boot (void)
   bootinfo->bi_data[0] = rootdev;
 
   grub_unix_real_boot (entry, bootflags, 0, bootinfo,
-		       0, grub_upper_mem >> 10, grub_lower_mem >> 10);
+		       0, grub_mmap_get_upper () >> 10, 
+		       grub_mmap_get_lower () >> 10);
 
   /* Not reached.  */
   return GRUB_ERR_NONE;
diff --git a/loader/i386/efi/linux.c b/loader/i386/efi/linux.c
index 100b268..9be88aa 100644
--- a/loader/i386/efi/linux.c
+++ b/loader/i386/efi/linux.c
@@ -32,6 +32,7 @@
 #include <grub/efi/uga_draw.h>
 #include <grub/pci.h>
 #include <grub/command.h>
+#include <grub/memory.h>
 
 #define GRUB_LINUX_CL_OFFSET		0x1000
 #define GRUB_LINUX_CL_END_OFFSET	0x2000
@@ -300,7 +301,6 @@ grub_linux_boot (void)
   grub_efi_uintn_t map_key;
   grub_efi_uintn_t desc_size;
   grub_efi_uint32_t desc_version;
-  grub_efi_memory_descriptor_t *desc;
   int e820_num;
   
   params = real_mode_mem;
@@ -313,84 +313,53 @@ grub_linux_boot (void)
 		(unsigned) idt_desc.limit, (unsigned long) idt_desc.base,
 		(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)
-    grub_fatal ("cannot get memory map");
-
-  e820_num = 0;
-  for (desc = mmap_buf;
-       desc < NEXT_MEMORY_DESCRIPTOR (mmap_buf, mmap_size);
-       desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size))
+  auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t);
+  int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size, grub_uint32_t type)
     {
-      switch (desc->type)
-	{
-	case GRUB_EFI_ACPI_RECLAIM_MEMORY:
+      switch (type)
+        {
+        case GRUB_MACHINE_MEMORY_AVAILABLE:
 	  grub_e820_add_region (params->e820_map, &e820_num,
-				desc->physical_start,
-				desc->num_pages << 12,
-				GRUB_E820_ACPI);
+				addr, size, GRUB_E820_RAM);
 	  break;
 
-	case GRUB_EFI_ACPI_MEMORY_NVS:
+#ifdef GRUB_MACHINE_MEMORY_ACPI
+        case GRUB_MACHINE_MEMORY_ACPI:
 	  grub_e820_add_region (params->e820_map, &e820_num,
-				desc->physical_start,
-				desc->num_pages << 12,
-				GRUB_E820_NVS);
+				addr, size, GRUB_E820_ACPI);
 	  break;
+#endif
 
-	case GRUB_EFI_RUNTIME_SERVICES_CODE:
+#ifdef GRUB_MACHINE_MEMORY_NVS
+        case GRUB_MACHINE_MEMORY_NVS:
 	  grub_e820_add_region (params->e820_map, &e820_num,
-				desc->physical_start,
-				desc->num_pages << 12,
-				GRUB_E820_EXEC_CODE);
+				addr, size, GRUB_E820_NVS);
 	  break;
+#endif
 
-	case GRUB_EFI_LOADER_CODE:
-	case GRUB_EFI_LOADER_DATA:
-	case GRUB_EFI_BOOT_SERVICES_CODE:
-	case GRUB_EFI_BOOT_SERVICES_DATA:
-	case GRUB_EFI_CONVENTIONAL_MEMORY:
-	  {
-	    grub_uint64_t start, size, end;
-
-	    start = desc->physical_start;
-	    size = desc->num_pages << 12;
-	    end = start + size;
-
-	    /* Skip A0000 - 100000 region.  */
-	    if ((start < 0x100000ULL) && (end > 0xA0000ULL))
-	      {
-		if (start < 0xA0000ULL)
-		  {
-		    grub_e820_add_region (params->e820_map, &e820_num,
-					  start,
-					  0xA0000ULL - start,
-					  GRUB_E820_RAM);
-		  }
-
-		if (end <= 0x100000ULL)
-		  continue;
-
-		start = 0x100000ULL;
-		size = end - start;
-	      }
-
-	    grub_e820_add_region (params->e820_map, &e820_num,
-				  start, size, GRUB_E820_RAM);
-	    break;
-	  }
-
-	default:
+#ifdef GRUB_MACHINE_MEMORY_CODE
+        case GRUB_MACHINE_MEMORY_CODE:
 	  grub_e820_add_region (params->e820_map, &e820_num,
-				desc->physical_start,
-				desc->num_pages << 12,
-				GRUB_E820_RESERVED);
-	}
+				addr, size, GRUB_E820_EXEC_CODE);
+	  break;
+#endif
+
+        default:
+          grub_e820_add_region (params->e820_map, &e820_num,
+                                addr, size, GRUB_E820_RESERVED);
+        }
+      return 0;
     }
 
+  e820_num = 0;
+  grub_mmap_iterate (hook);
   params->mmap_size = e820_num;
 
+  mmap_size = find_mmap_size ();
+  if (grub_efi_get_memory_map (&mmap_size, mmap_buf, &map_key,
+			       &desc_size, &desc_version) <= 0)
+    grub_fatal ("cannot get memory map");
+
   if (! grub_efi_exit_boot_services (map_key))
      grub_fatal ("cannot exit boot services");
 
diff --git a/loader/i386/ieee1275/linux.c b/loader/i386/ieee1275/linux.c
index 2f52880..a563577 100644
--- a/loader/i386/ieee1275/linux.c
+++ b/loader/i386/ieee1275/linux.c
@@ -100,7 +100,7 @@ grub_linux_boot (void)
 
   grub_memset ((char *) params, 0, GRUB_OFW_LINUX_CL_OFFSET);
 
-  params->alt_mem = grub_upper_mem >> 10;
+  params->alt_mem = grub_mmap_get_upper () >> 10;
   params->ext_mem = params->alt_mem;
 
   lh->cmd_line_ptr = (char *)
diff --git a/loader/i386/linux.c b/loader/i386/linux.c
index 19444f4..a72871b 100644
--- a/loader/i386/linux.c
+++ b/loader/i386/linux.c
@@ -168,7 +168,7 @@ find_mmap_size (void)
       return 0;
     }
   
-  grub_machine_mmap_iterate (hook);
+  grub_mmap_iterate (hook);
   
   mmap_size = count * sizeof (struct grub_e820_mmap);
 
@@ -237,7 +237,7 @@ allocate_pages (grub_size_t prot_size)
 
       return 0;
     }
-  grub_machine_mmap_iterate (hook);
+  grub_mmap_iterate (hook);
   if (! real_mode_mem)
     {
       grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate real mode pages");
@@ -396,6 +396,27 @@ grub_linux_boot (void)
 				addr, size, GRUB_E820_RAM);
 	  break;
 
+#ifdef GRUB_MACHINE_MEMORY_ACPI
+        case GRUB_MACHINE_MEMORY_ACPI:
+	  grub_e820_add_region (params->e820_map, &e820_num,
+				addr, size, GRUB_E820_ACPI);
+	  break;
+#endif
+
+#ifdef GRUB_MACHINE_MEMORY_NVS
+        case GRUB_MACHINE_MEMORY_NVS:
+	  grub_e820_add_region (params->e820_map, &e820_num,
+				addr, size, GRUB_E820_NVS);
+	  break;
+#endif
+
+#ifdef GRUB_MACHINE_MEMORY_CODE
+        case GRUB_MACHINE_MEMORY_CODE:
+	  grub_e820_add_region (params->e820_map, &e820_num,
+				addr, size, GRUB_E820_EXEC_CODE);
+	  break;
+#endif
+
         default:
           grub_e820_add_region (params->e820_map, &e820_num,
                                 addr, size, GRUB_E820_RESERVED);
@@ -404,9 +425,10 @@ grub_linux_boot (void)
     }
 
   e820_num = 0;
-  grub_machine_mmap_iterate (hook);
+  grub_mmap_iterate (hook);
   params->mmap_size = e820_num;
 
+
   /* Hardware interrupts are not safe any longer.  */
   asm volatile ("cli" : : );
   
diff --git a/loader/i386/multiboot.c b/loader/i386/multiboot.c
index 27042a5..d38590f 100644
--- a/loader/i386/multiboot.c
+++ b/loader/i386/multiboot.c
@@ -100,7 +100,7 @@ grub_get_multiboot_mmap_len (void)
       return 0;
     }
   
-  grub_machine_mmap_iterate (hook);
+  grub_mmap_iterate (hook);
   
   return count * sizeof (struct grub_multiboot_mmap_entry);
 }
@@ -123,7 +123,7 @@ grub_fill_multiboot_mmap (struct grub_multiboot_mmap_entry *first_entry)
       return 0;
     }
 
-  grub_machine_mmap_iterate (hook);
+  grub_mmap_iterate (hook);
 }
 
 #define MULTIBOOT_LOAD_ELF64
@@ -342,8 +342,8 @@ grub_multiboot (int argc, char *argv[])
 		grub_multiboot_payload_entry_offset);
 
   /* Convert from bytes to kilobytes.  */
-  mbi->mem_lower = grub_lower_mem / 1024;
-  mbi->mem_upper = grub_upper_mem / 1024;
+  mbi->mem_lower = grub_mmap_get_lower () / 1024;
+  mbi->mem_upper = grub_mmap_get_upper () / 1024;
   mbi->flags |= MULTIBOOT_INFO_MEMORY;
 
   cmdline = p = cmdline_addr (grub_multiboot_payload_orig);
diff --git a/loader/i386/pc/linux.c b/loader/i386/pc/linux.c
index 8ff97f4..34a4ebc 100644
--- a/loader/i386/pc/linux.c
+++ b/loader/i386/pc/linux.c
@@ -108,8 +108,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
       lh.type_of_loader = GRUB_LINUX_BOOT_LOADER_TYPE;
       
       /* Put the real mode part at as a high location as possible.  */
-      grub_linux_real_addr = (char *) (grub_lower_mem
-				       - GRUB_LINUX_SETUP_MOVE_SIZE);
+      grub_linux_real_addr 
+	= (char *) UINT_TO_PTR (grub_mmap_get_lower ()
+				- GRUB_LINUX_SETUP_MOVE_SIZE);
       /* But it must not exceed the traditional area.  */
       if (grub_linux_real_addr > (char *) GRUB_LINUX_OLD_REAL_MODE_ADDR)
 	grub_linux_real_addr = (char *) GRUB_LINUX_OLD_REAL_MODE_ADDR;
@@ -159,12 +160,12 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
     }
   
   if (grub_linux_real_addr + GRUB_LINUX_SETUP_MOVE_SIZE
-      > (char *) grub_lower_mem)
+      > (char *) UINT_TO_PTR (grub_mmap_get_lower ()))
     {
       grub_error (GRUB_ERR_OUT_OF_RANGE,
 		 "too small lower memory (0x%x > 0x%x)",
-		 grub_linux_real_addr + GRUB_LINUX_SETUP_MOVE_SIZE,
-		 (char *) grub_lower_mem);
+		  grub_linux_real_addr + GRUB_LINUX_SETUP_MOVE_SIZE,
+		  (int) grub_mmap_get_lower ());
       goto fail;
     }
 
diff --git a/mmap/efi/mmap.c b/mmap/efi/mmap.c
new file mode 100644
index 0000000..25d0d15
--- /dev/null
+++ b/mmap/efi/mmap.c
@@ -0,0 +1,284 @@
+/* Mmap management. */
+/*
+ *  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/machine/memory.h>
+#include <grub/memory.h>
+#include <grub/err.h>
+#include <grub/efi/api.h>
+#include <grub/efi/efi.h>
+#include <grub/mm.h>
+#include <grub/misc.h>
+
+#define NEXT_MEMORY_DESCRIPTOR(desc, size)      \
+  ((grub_efi_memory_descriptor_t *) ((char *) (desc) + (size)))
+
+grub_err_t
+grub_machine_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, 
+							 grub_uint64_t, 
+							 grub_uint32_t))
+{
+  grub_efi_uintn_t mmap_size = 0;
+  grub_efi_memory_descriptor_t *map_buf;
+  grub_efi_uintn_t map_key = 0;
+  grub_efi_uintn_t desc_size = 0;
+  grub_efi_uint32_t desc_version = 0;
+  grub_efi_memory_descriptor_t *desc;
+
+  if (grub_efi_get_memory_map (&mmap_size, map_buf,
+			       &map_key, &desc_size,
+			       &desc_version) < 0)
+    return grub_errno;
+
+  map_buf = grub_malloc (mmap_size);
+  if (!map_buf)
+    return grub_errno;
+
+  if (grub_efi_get_memory_map (&mmap_size, map_buf,
+			       &map_key, &desc_size,
+			       &desc_version) <= 0)
+    {
+      grub_free (map_buf);
+      return grub_errno;
+    }
+
+  for (desc = map_buf;
+       desc < NEXT_MEMORY_DESCRIPTOR (map_buf, mmap_size);
+       desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size))
+    {
+      grub_dprintf ("mmap", "EFI memory region 0x%llx-0x%llx: %d\n",
+		    (unsigned long long) desc->physical_start, 
+		    (unsigned long long) desc->physical_start
+		    + desc->num_pages * 4096, desc->type);
+      switch (desc->type)
+	{
+	case GRUB_EFI_RUNTIME_SERVICES_CODE:
+	  hook (desc->physical_start, desc->num_pages * 4096, 
+		GRUB_MACHINE_MEMORY_CODE);
+	  break;
+
+	default:
+	  grub_printf ("Unknown memory type %d, considering reserved\n",
+		       desc->type);
+
+	case GRUB_EFI_RESERVED_MEMORY_TYPE:
+	case GRUB_EFI_RUNTIME_SERVICES_DATA:
+	case GRUB_EFI_UNUSABLE_MEMORY:
+	case GRUB_EFI_MEMORY_MAPPED_IO:
+	case GRUB_EFI_MEMORY_MAPPED_IO_PORT_SPACE:
+	case GRUB_EFI_PAL_CODE:
+	  hook (desc->physical_start, desc->num_pages * 4096, 
+		GRUB_MACHINE_MEMORY_RESERVED);
+	  break;
+
+	case GRUB_EFI_LOADER_CODE:
+	case GRUB_EFI_LOADER_DATA:
+	case GRUB_EFI_BOOT_SERVICES_CODE:
+	case GRUB_EFI_BOOT_SERVICES_DATA:
+	case GRUB_EFI_CONVENTIONAL_MEMORY:
+	  hook (desc->physical_start, desc->num_pages * 4096, 
+		GRUB_MACHINE_MEMORY_AVAILABLE);
+	  break;
+
+	case GRUB_EFI_ACPI_RECLAIM_MEMORY:
+	  hook (desc->physical_start, desc->num_pages * 4096, 
+		GRUB_MACHINE_MEMORY_ACPI);
+	  break;
+
+	case GRUB_EFI_ACPI_MEMORY_NVS:
+	  hook (desc->physical_start, desc->num_pages * 4096, 
+		GRUB_MACHINE_MEMORY_NVS);
+	  break;
+	}
+    }
+
+  return GRUB_ERR_NONE;
+}
+
+static inline grub_efi_memory_type_t 
+make_efi_memtype (int type)
+{
+  switch (type)
+    {
+    case GRUB_MACHINE_MEMORY_CODE:
+      return GRUB_EFI_RUNTIME_SERVICES_CODE;
+
+      /* No way to remove a chunk of memory from EFI mmap. 
+	 So mark it as unusable. */
+    case GRUB_MACHINE_MEMORY_HOLE:
+      
+    default:
+
+    case GRUB_MACHINE_MEMORY_RESERVED:
+      return GRUB_EFI_UNUSABLE_MEMORY;
+
+    case GRUB_MACHINE_MEMORY_AVAILABLE:
+      return GRUB_EFI_CONVENTIONAL_MEMORY;
+
+    case GRUB_MACHINE_MEMORY_ACPI:
+      return GRUB_EFI_ACPI_RECLAIM_MEMORY;
+
+    case GRUB_MACHINE_MEMORY_NVS:
+      return GRUB_EFI_ACPI_RECLAIM_MEMORY;
+      
+    }
+
+}
+
+struct overlay
+{
+  struct overlay *next;
+  grub_efi_physical_address_t address;
+  grub_efi_uintn_t pages;
+  int handle;
+};
+
+static struct overlay *overlays = 0;
+static int curhandle = 1;
+
+int
+grub_mmap_register (grub_uint64_t start, grub_uint64_t size, int type)
+{
+  grub_uint64_t end = start + size;
+  grub_efi_physical_address_t address;
+  grub_efi_boot_services_t *b;
+  grub_efi_uintn_t pages;
+  grub_efi_status_t status;
+  struct overlay *curover;
+
+  curover = (struct overlay *) grub_malloc (sizeof (struct overlay));
+  if (! curover)
+    return 0;
+      
+  b = grub_efi_system_table->boot_services;
+  address = start & (~0x3ffULL);
+  pages = (end - address  + 0x3ff) >> 12;
+  status = efi_call_2 (b->free_pages, address, pages);
+  if (status != GRUB_EFI_SUCCESS && status != GRUB_EFI_NOT_FOUND)
+    {
+      grub_free (curover);
+      return 0;
+    }
+  status = efi_call_4 (b->allocate_pages, GRUB_EFI_ALLOCATE_ADDRESS, 
+		       make_efi_memtype (type), pages, &address);
+  if (status != GRUB_EFI_SUCCESS)
+    {
+      grub_free (curover);
+      return 0;
+    }
+  curover->next = overlays;
+  curover->handle = curhandle++;
+  curover->address = address;
+  curover->pages = pages;
+  overlays = curover;
+
+  return curover->handle;
+}
+
+grub_err_t 
+grub_machine_mmap_unregister (int handle)
+{
+  struct overlay *curover, *prevover;
+  grub_efi_boot_services_t *b;
+  grub_efi_status_t status;
+
+  b = grub_efi_system_table->boot_services;
+
+  
+  for (curover = overlays, prevover = 0; curover; 
+       prevover = curover, curover = curover->next)
+    {
+      if (curover->handle == handle)
+	{
+	  status = efi_call_2 (b->free_pages, curover->address, curover->pages);
+	  if (prevover != 0)
+	    prevover->next = curover->next;
+	  else
+	    overlays = curover->next;
+	  grub_free (curover);
+	  return GRUB_ERR_NONE;
+	}
+    }
+  return grub_error (GRUB_ERR_BAD_ARGUMENT, "handle %d not found", handle);
+}
+
+/* Result is always page-aligned. */
+char *
+grub_mmap_malign_and_register (grub_uint64_t align __attribute__ ((unused)), 
+			       grub_uint64_t size,
+			       int *handle, int type, 
+			       int flags __attribute__ ((unused)))
+{
+  grub_efi_physical_address_t address;
+  grub_efi_boot_services_t *b;
+  grub_efi_uintn_t pages;
+  grub_efi_status_t status;
+  struct overlay *curover;
+  grub_efi_allocate_type_t atype;
+
+  curover = (struct overlay *) grub_malloc (sizeof (struct overlay));
+  if (! curover)
+    return 0;
+      
+  b = grub_efi_system_table->boot_services;
+
+  address = 0xffffffff;
+
+#if GRUB_TARGET_SIZEOF_VOID_P < 8
+  /* Limit the memory access to less than 4GB for 32-bit platforms.  */
+  atype = GRUB_EFI_ALLOCATE_MAX_ADDRESS;
+#else
+  atype = GRUB_EFI_ALLOCATE_ANY_PAGES;
+#endif
+
+  pages = (size + 0x3ff) >> 12;
+  status = efi_call_4 (b->allocate_pages, atype, 
+		       make_efi_memtype (type), pages, &address);
+  if (status != GRUB_EFI_SUCCESS)
+    {
+      grub_free (curover);
+      return 0;
+    }
+
+  if (address == 0)
+    {
+      /* Uggh, the address 0 was allocated... This is too annoying,
+	 so reallocate another one.  */
+      address = 0xffffffff;
+      status = efi_call_4 (b->allocate_pages, atype, 
+			   make_efi_memtype (type), pages, &address);
+      grub_efi_free_pages (0, pages);
+      if (status != GRUB_EFI_SUCCESS)
+	return 0;
+    }
+  
+  curover->next = overlays;
+  curover->handle = curhandle++;
+  curover->address = address;
+  curover->pages = pages;
+  overlays = curover;
+  *handle = curover->handle;
+
+  return UINT_TO_PTR (curover->address);
+}
+
+void 
+grub_mmap_free_and_unregister (int handle)
+{
+  grub_machine_mmap_unregister (handle);
+}
diff --git a/mmap/i386/mmap.c b/mmap/i386/mmap.c
new file mode 100644
index 0000000..e997cc7
--- /dev/null
+++ b/mmap/i386/mmap.c
@@ -0,0 +1,98 @@
+/* Mmap management. */
+/*
+ *  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/machine/memory.h>
+#include <grub/memory.h>
+#include <grub/err.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+
+
+#ifndef GRUB_MMAP_REGISTER_BY_FIRMWARE
+
+char *
+grub_mmap_malign_and_register (grub_uint64_t align, grub_uint64_t size,
+			       int *handle, int type, int flags)
+{
+  grub_uint64_t highestlow = 0;
+
+  auto int NESTED_FUNC_ATTR find_hook (grub_uint64_t, grub_uint64_t, 
+				       grub_uint32_t);
+  int NESTED_FUNC_ATTR find_hook (grub_uint64_t start, grub_uint64_t rangesize, 
+				  grub_uint32_t type)
+  {
+    grub_uint64_t end = start + rangesize;
+    if (type != GRUB_MACHINE_MEMORY_AVAILABLE)
+      return 0;
+    if (end > 0x100000)
+      end = 0x100000;
+    if (end > start + size
+	&& highestlow < ((end - size) - ((end - size) & (align - 1))))
+      highestlow = (end - size)  - ((end - size) & (align - 1));
+    return 0;
+  }
+
+  char * ret;
+  if (flags & GRUB_MMAP_MALLOC_LOW)
+    {
+      /* FIXME: use low-memory mm allocation once it's available. */
+      grub_mmap_iterate (find_hook);
+      ret = UINT_TO_PTR (highestlow);
+    }
+  else
+    ret = grub_memalign (align, size);
+
+  if (! ret)
+    {
+      *handle = 0;
+      return 0;
+    }
+
+  *handle = grub_mmap_register (PTR_TO_UINT64 (ret), size, type);
+  if (! *handle)
+    {
+      grub_free (ret);
+      return 0;
+    }    
+
+  return ret;
+}
+
+void
+grub_mmap_free_and_unregister (int handle)
+{
+  struct grub_mmap_region *cur;
+  grub_uint64_t addr;
+
+  for (cur = grub_mmap_overlays; cur; cur = cur->next)
+    if (cur->handle == handle)
+      break;
+
+  if (! cur)
+    return;
+
+  addr = cur->start;
+    
+  grub_mmap_unregister (handle);
+
+  if (addr >= 0x100000)
+    grub_free (UINT_TO_PTR (addr));
+}
+
+#endif
diff --git a/mmap/i386/pc/mmap.c b/mmap/i386/pc/mmap.c
new file mode 100644
index 0000000..ec51727
--- /dev/null
+++ b/mmap/i386/pc/mmap.c
@@ -0,0 +1,216 @@
+/* Mmap management. */
+/*
+ *  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/machine/memory.h>
+#include <grub/memory.h>
+#include <grub/misc.h>
+#include <grub/term.h>
+#include <grub/loader.h>
+
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+
+static void *hooktarget = 0;
+
+extern grub_uint8_t grub_machine_mmaphook_start;
+extern grub_uint8_t grub_machine_mmaphook_end;
+extern grub_uint8_t grub_machine_mmaphook_int12;
+extern grub_uint8_t grub_machine_mmaphook_int15;
+
+static grub_uint16_t grub_machine_mmaphook_int12offset = 0;
+static grub_uint16_t grub_machine_mmaphook_int12segment = 0;
+extern grub_uint16_t grub_machine_mmaphook_int15offset;
+extern grub_uint16_t grub_machine_mmaphook_int15segment;
+
+extern grub_uint16_t grub_machine_mmaphook_mmap_num;
+extern grub_uint16_t grub_machine_mmaphook_kblow;
+extern grub_uint16_t grub_machine_mmaphook_kbin16mb;
+extern grub_uint16_t grub_machine_mmaphook_64kbin4gb;
+
+struct grub_e820_mmap_entry
+{
+  grub_uint64_t addr;
+  grub_uint64_t len;
+  grub_uint32_t type;
+} __attribute__((packed));
+
+
+static grub_err_t 
+preboot (int noreturn __attribute__ ((unused)))
+{
+  struct grub_e820_mmap_entry *hookmmap, *hookmmapcur;
+  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)
+  {
+    grub_dprintf ("mmap", "mmap chunk %llx-%llx:%x\n", addr, addr + size, type);
+    hookmmapcur->addr = addr;
+    hookmmapcur->len = size;
+    hookmmapcur->type = type;
+    hookmmapcur++;
+    return 0;
+  }
+
+  if (! hooktarget)
+    return grub_error (GRUB_ERR_OUT_OF_MEMORY, 
+		       "no space is allocated for memory hook");
+
+  grub_dprintf ("mmap", "installing preboot handlers\n");
+
+  hookmmapcur = hookmmap = (struct grub_e820_mmap_entry *) 
+    ((grub_uint8_t *) hooktarget + (&grub_machine_mmaphook_end 
+				    - &grub_machine_mmaphook_start));
+
+  grub_mmap_iterate (fill_hook);  
+  grub_machine_mmaphook_mmap_num = hookmmapcur - hookmmap;
+
+  grub_machine_mmaphook_kblow = grub_mmap_get_lower () >> 10;
+  grub_machine_mmaphook_kbin16mb 
+    = min (grub_mmap_get_upper (),0x3f00000ULL) >> 10;
+  grub_machine_mmaphook_64kbin4gb 
+    = min (grub_mmap_get_post64 (), 0xfc000000ULL) >> 16;
+
+  /* Correct BDA. */
+  *((grub_uint16_t *) 0x413) = grub_mmap_get_lower () >> 10;
+
+  /* Save old interrupt handlers. */
+  grub_machine_mmaphook_int12offset = *((grub_uint16_t *) 0x48);
+  grub_machine_mmaphook_int12segment = *((grub_uint16_t *) 0x4a);
+  grub_machine_mmaphook_int15offset = *((grub_uint16_t *) 0x54);
+  grub_machine_mmaphook_int15segment = *((grub_uint16_t *) 0x56);
+
+  grub_dprintf ("mmap", "hooktarget = %p\n", hooktarget);
+
+  /* Install the interrupt handlers. */
+  grub_memcpy (hooktarget, &grub_machine_mmaphook_start,
+	       &grub_machine_mmaphook_end - &grub_machine_mmaphook_start);
+
+  *((grub_uint16_t *) 0x4a) = PTR_TO_UINT32 (hooktarget) >> 4;
+  *((grub_uint16_t *) 0x56) = PTR_TO_UINT32 (hooktarget) >> 4;
+  *((grub_uint16_t *) 0x48) = &grub_machine_mmaphook_int12 
+    - &grub_machine_mmaphook_start;
+  *((grub_uint16_t *) 0x54) = &grub_machine_mmaphook_int15
+    - &grub_machine_mmaphook_start;
+
+  return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+preboot_rest (void)
+{
+  /* Restore old interrupt handlers. */
+  *((grub_uint16_t *) 0x48) = grub_machine_mmaphook_int12offset;
+  *((grub_uint16_t *) 0x4a) = grub_machine_mmaphook_int12segment;
+  *((grub_uint16_t *) 0x54) = grub_machine_mmaphook_int15offset;
+  *((grub_uint16_t *) 0x56) = grub_machine_mmaphook_int15segment;
+
+  return GRUB_ERR_NONE;
+}
+
+static grub_err_t 
+malloc_hook (void)
+{
+  static int reentry = 0;
+  static int mmapregion = 0;
+  static int slots_available = 0;
+  int hooksize;
+  int regcount = 0;
+  auto int NESTED_FUNC_ATTR count_hook (grub_uint64_t, grub_uint64_t, 
+					grub_uint32_t);
+  int NESTED_FUNC_ATTR count_hook (grub_uint64_t addr __attribute__ ((unused)), 
+				   grub_uint64_t size __attribute__ ((unused)), 
+				   grub_uint32_t type __attribute__ ((unused)))
+  {
+    regcount++;
+    return 0;
+  }
+
+  if (reentry)
+    return GRUB_ERR_NONE;
+
+  grub_dprintf ("mmap", "registering\n");
+
+  grub_mmap_iterate (count_hook);
+
+  /* Mapping hook itself may introduce up to 2 additional regions. */
+  regcount += 2;
+
+  if (regcount <= slots_available)
+    return GRUB_ERR_NONE;
+
+  if (mmapregion)
+    {
+      grub_mmap_free_and_unregister (mmapregion);
+      mmapregion = 0;
+      hooktarget = 0;
+    }
+
+  hooksize = &grub_machine_mmaphook_end - &grub_machine_mmaphook_start
+    + regcount * sizeof (struct grub_e820_mmap_entry);
+  /* Allocate an integer number of KiB. */
+  hooksize = ((hooksize - 1) | 0x3ff) + 1;
+  slots_available = (hooksize - (&grub_machine_mmaphook_end 
+				 - &grub_machine_mmaphook_start))
+    / sizeof (struct grub_e820_mmap_entry);
+
+  reentry = 1;
+  hooktarget 
+    = grub_mmap_malign_and_register (16, hooksize, &mmapregion, 
+				     GRUB_MACHINE_MEMORY_RESERVED,
+				     GRUB_MMAP_MALLOC_LOW);
+  reentry = 0;
+
+  if (! hooktarget)
+    {
+      slots_available = 0;
+      return grub_error (GRUB_ERR_OUT_OF_MEMORY, "No space for mmap hook");
+    }
+  return GRUB_ERR_NONE;
+}
+
+grub_err_t
+grub_machine_mmap_register (grub_uint64_t start __attribute__ ((unused)), 
+			    grub_uint64_t size __attribute__ ((unused)), 
+			    int type __attribute__ ((unused)),
+			    int handle  __attribute__ ((unused)))
+{
+  grub_err_t err;
+  static void *preb_handle = 0;
+
+  err = malloc_hook ();
+  if (err)
+    return err;
+
+  if (! preb_handle)
+    {
+      grub_dprintf ("mmap", "adding preboot\n");
+      preb_handle 
+	= grub_loader_register_preboot_hook (preboot, preboot_rest, 
+					     GRUB_LOADER_PREBOOT_HOOK_PRIO_MEMORY);
+      if (! preb_handle)
+	return grub_errno;
+    }
+  return GRUB_ERR_NONE;
+}
+
+grub_err_t
+grub_machine_mmap_unregister (int handle __attribute__ ((unused)))
+{
+  return GRUB_ERR_NONE;
+}
diff --git a/mmap/i386/pc/mmap_helper.S b/mmap/i386/pc/mmap_helper.S
new file mode 100644
index 0000000..ab7c0d2
--- /dev/null
+++ b/mmap/i386/pc/mmap_helper.S
@@ -0,0 +1,122 @@
+/* Mmap management. */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2009  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/symbol.h>
+
+#define DS(x) ((x) - segstart)
+
+segstart:	
+VARIABLE(grub_machine_mmaphook_start)
+	.code16
+VARIABLE(grub_machine_mmaphook_int12)
+	push %ds
+	push %cs
+	pop %ds
+	movw DS (EXT_C (grub_machine_mmaphook_kblow)), %ax
+	pop %ds
+	iret
+
+VARIABLE(grub_machine_mmaphook_int15)
+	pushf
+	cmpw $0xe801, %ax
+	jz e801
+	cmpw $0xe820, %ax
+	jz e820
+	cmpb $0x88, %ah
+	jz h88
+	popf
+	/* ljmp */
+	.byte	0xea
+VARIABLE (grub_machine_mmaphook_int15offset)
+	.word	0
+VARIABLE (grub_machine_mmaphook_int15segment)
+	.word	0
+	
+e801:
+	popf
+	push %ds
+	push %cs
+	pop %ds
+	movw DS (EXT_C (grub_machine_mmaphook_kbin16mb)), %ax
+	movw DS (EXT_C (grub_machine_mmaphook_64kbin4gb)), %bx
+	movw %ax, %cx
+	movw %bx, %dx
+	pop %ds
+	clc
+	iret
+
+h88:
+	popf
+	push %ds
+	push %cs
+	pop %ds
+	movw DS (EXT_C (grub_machine_mmaphook_kbin16mb)), %ax
+	pop %ds
+	clc
+	iret
+
+e820:
+	popf
+	push %ds
+	push %cs
+	pop %ds
+	cmpw $20, %cx
+	jb errexit
+	cmpw DS (EXT_C (grub_machine_mmaphook_mmap_num)), %bx
+	jae errexit
+	cmp $0x534d4150, %edx
+	jne errexit
+	push %si
+	push %di
+	movw $20, %cx
+	movw $(DS(mmaphook_mmap)), %si
+	mov %bx, %ax
+	imul $20, %ax
+	add %ax, %si
+	rep movsb
+	pop %di
+	pop %si
+	movl $20, %ecx
+	inc %bx
+	cmpw DS(EXT_C(grub_machine_mmaphook_mmap_num)), %bx
+	jb noclean
+	xor %bx, %bx	
+noclean:	
+	mov $0x534d4150, %eax
+	pop %ds
+	clc
+	iret
+errexit:
+	mov $0x534d4150, %eax
+	pop %ds
+	stc
+	xor %bx, %bx
+	iret	
+	
+VARIABLE(grub_machine_mmaphook_mmap_num)
+	.word 0
+VARIABLE(grub_machine_mmaphook_kblow)
+	.word 0
+VARIABLE (grub_machine_mmaphook_kbin16mb)
+	.word 0
+VARIABLE (grub_machine_mmaphook_64kbin4gb)
+	.word 0
+mmaphook_mmap:
+	/* Memory map is placed just after the interrupt handlers. */
+VARIABLE(grub_machine_mmaphook_end)
diff --git a/mmap/i386/uppermem.c b/mmap/i386/uppermem.c
new file mode 100644
index 0000000..80576ca
--- /dev/null
+++ b/mmap/i386/uppermem.c
@@ -0,0 +1,85 @@
+/* Compute amount of lower and upper memory till the first hole. */
+/*
+ *  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/memory.h>
+#include <grub/mm.h>
+#include <grub/misc.h>
+
+grub_uint64_t 
+grub_mmap_get_lower (void)
+{
+  grub_uint64_t lower = 0;
+
+  auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t);
+  int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size,
+			     grub_uint32_t type)
+    {
+      if (type != GRUB_MACHINE_MEMORY_AVAILABLE)
+	return 0;
+      if (addr == 0)
+	lower = size;
+      return 0;
+    }
+
+  grub_mmap_iterate (hook);
+  if (lower > 0x100000)
+    lower =  0x100000;
+  return lower;
+}
+
+grub_uint64_t 
+grub_mmap_get_upper (void)
+{
+  grub_uint64_t upper = 0;
+
+  auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t);
+  int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size,
+			     grub_uint32_t type)
+    {
+      if (type != GRUB_MACHINE_MEMORY_AVAILABLE)
+	return 0;
+      if (addr <= 0x100000 && addr + size > 0x100000)
+	upper = addr + size - 0x100000;
+      return 0;
+    }
+
+  grub_mmap_iterate (hook);
+  return upper;
+}
+
+/* Count the continous bytes after 64 MiB. */
+grub_uint64_t 
+grub_mmap_get_post64 (void)
+{
+  grub_uint64_t post64 = 0;
+
+  auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t);
+  int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size,
+			     grub_uint32_t type)
+    {
+      if (type != GRUB_MACHINE_MEMORY_AVAILABLE)
+	return 0;
+      if (addr <= 0x4000000 && addr + size > 0x4000000)
+	post64 = addr + size - 0x4000000;
+      return 0;
+    }
+
+  grub_mmap_iterate (hook);
+  return post64;
+}
diff --git a/mmap/mmap.c b/mmap/mmap.c
new file mode 100644
index 0000000..1d82db7
--- /dev/null
+++ b/mmap/mmap.c
@@ -0,0 +1,426 @@
+/* Mmap management. */
+/*
+ *  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/machine/memory.h>
+#include <grub/memory.h>
+#include <grub/err.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/command.h>
+#include <grub/dl.h>
+
+#ifndef GRUB_MMAP_REGISTER_BY_FIRMWARE
+
+struct grub_mmap_region *grub_mmap_overlays = 0;
+static int curhandle = 1;
+
+#endif
+
+grub_err_t
+grub_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, 
+						 grub_uint64_t, grub_uint32_t))
+{
+
+  /* This function resolves overlapping regions and sorts the memory map.
+     It uses scanline (sweeping) algorithm.
+  */
+  /* If same page is used by multiple types it's resolved 
+     according to priority:
+     1 - free memory
+     2 - memory usable by firmware-aware code
+     3 - unusable memory
+     4 - a range deliberately empty
+  */
+  int priority[GRUB_MACHINE_MEMORY_MAX_TYPE + 2] =
+    {
+#ifdef GRUB_MACHINE_MEMORY_AVAILABLE
+      [GRUB_MACHINE_MEMORY_AVAILABLE] = 1,
+#endif
+#ifdef GRUB_MACHINE_MEMORY_RESERVED
+      [GRUB_MACHINE_MEMORY_RESERVED] = 3,
+#endif
+#ifdef GRUB_MACHINE_MEMORY_ACPI
+      [GRUB_MACHINE_MEMORY_ACPI] = 2,
+#endif
+#ifdef GRUB_MACHINE_MEMORY_CODE
+      [GRUB_MACHINE_MEMORY_CODE] = 3,
+#endif
+#ifdef GRUB_MACHINE_MEMORY_NVS
+      [GRUB_MACHINE_MEMORY_NVS] = 3,
+#endif
+      [GRUB_MACHINE_MEMORY_HOLE] = 4,
+    };
+
+  int i, k, done;
+
+  /* Scanline events. */
+  struct grub_mmap_scan
+  {
+    /* At which memory address. */
+    grub_uint64_t pos;
+    /* 0 = region starts, 1 = region ends. */
+    int type;
+    /* Which type of memory region? */
+    int memtype;
+  };
+  struct grub_mmap_scan *scanline_events;
+  struct grub_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_MACHINE_MEMORY_MAX_TYPE + 2];
+  /* Number of mmap chunks. */
+  int mmap_num;
+
+#ifndef GRUB_MMAP_REGISTER_BY_FIRMWARE     
+  struct grub_mmap_region *cur;
+#endif
+  
+  auto int NESTED_FUNC_ATTR count_hook (grub_uint64_t, grub_uint64_t, 
+					grub_uint32_t);
+  int NESTED_FUNC_ATTR count_hook (grub_uint64_t addr __attribute__ ((unused)),
+				   grub_uint64_t size __attribute__ ((unused)),
+				   grub_uint32_t type __attribute__ ((unused)))
+  {
+    mmap_num++;
+    return 0;
+  }
+
+  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)
+  {
+    scanline_events[i].pos = addr;
+    scanline_events[i].type = 0;
+    if (type <= GRUB_MACHINE_MEMORY_MAX_TYPE && priority[type])
+      scanline_events[i].memtype = type;
+    else
+      {
+	grub_dprintf ("mmap", "Unknown memory type %d. Assuming unusable\n",
+		      type);
+	scanline_events[i].memtype = GRUB_MACHINE_MEMORY_RESERVED;
+      }
+    i++;
+
+    scanline_events[i].pos = addr + size;
+    scanline_events[i].type = 1;
+    scanline_events[i].memtype = scanline_events[i - 1].memtype;
+    i++;
+
+    return 0;
+  }
+  
+  mmap_num = 0;
+
+#ifndef GRUB_MMAP_REGISTER_BY_FIRMWARE   
+  for (cur = grub_mmap_overlays; cur; cur = cur->next)
+    mmap_num++;
+#endif
+
+  grub_machine_mmap_iterate (count_hook);
+  
+  /* Initialize variables. */
+  grub_memset (present, 0, sizeof (present));
+  scanline_events = (struct grub_mmap_scan *) 
+    grub_malloc (sizeof (struct grub_mmap_scan) * 2 * mmap_num);
+  
+  if (! scanline_events)
+    {
+      return grub_error (GRUB_ERR_OUT_OF_MEMORY, 
+			 "couldn't allocate space for new memory map");
+    }
+
+  i = 0;
+#ifndef GRUB_MMAP_REGISTER_BY_FIRMWARE   
+  /* Register scanline events. */
+  for (cur = grub_mmap_overlays; cur; cur = cur->next)
+    {
+      scanline_events[i].pos = cur->start;
+      scanline_events[i].type = 0;
+      if (cur->type == GRUB_MACHINE_MEMORY_HOLE 
+	  || (cur->type >= 0 && cur->type <= GRUB_MACHINE_MEMORY_MAX_TYPE
+	      && priority[cur->type]))
+	scanline_events[i].memtype = cur->type;
+      else
+	scanline_events[i].memtype = GRUB_MACHINE_MEMORY_RESERVED;
+      i++;
+
+      scanline_events[i].pos = cur->end;
+      scanline_events[i].type = 1;
+      scanline_events[i].memtype = scanline_events[i - 1].memtype;
+      i++;
+    }
+#endif /* ! GRUB_MMAP_REGISTER_BY_FIRMWARE */
+
+  grub_machine_mmap_iterate (fill_hook);
+
+  /* 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
+	    || (scanline_events[i + 1].pos == scanline_events[i].pos
+		&& scanline_events[i + 1].type == 0 
+		&& scanline_events[i].type == 1))
+	  {
+	    t = scanline_events[i + 1];
+	    scanline_events[i + 1] = scanline_events[i];
+	    scanline_events[i] = t;
+	    done = 1;
+	  }
+    }
+
+  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_MACHINE_MEMORY_MAX_TYPE + 1; k++)
+	if (present[k] && (curtype == -1 || priority[k] > priority[curtype]))
+	  curtype = k;
+
+      /* Anounce region to the hook if necessary. */
+      if ((curtype == -1 || curtype != lasttype) 
+	  && lastaddr != scanline_events[i].pos
+	  && lasttype != -1
+	  && lasttype != GRUB_MACHINE_MEMORY_HOLE
+	  && hook (lastaddr, scanline_events[i].pos - lastaddr, lasttype))
+	{
+	  grub_free (scanline_events);
+	  return GRUB_ERR_NONE;
+	}
+
+      /* Update last values if necessary. */
+      if (curtype == -1 || curtype != lasttype) 
+	{
+	  lasttype = curtype;
+	  lastaddr = scanline_events[i].pos;
+	}
+    }
+
+  grub_free (scanline_events);
+  return GRUB_ERR_NONE;
+}
+
+#ifndef GRUB_MMAP_REGISTER_BY_FIRMWARE   
+int
+grub_mmap_register (grub_uint64_t start, grub_uint64_t size, int type)
+{
+  struct grub_mmap_region *cur;
+
+  grub_dprintf ("mmap", "registering\n");
+
+  cur = (struct grub_mmap_region *) 
+    grub_malloc (sizeof (struct grub_mmap_region));
+  if (! cur)
+    {
+      grub_error (GRUB_ERR_OUT_OF_MEMORY, 
+		  "couldn't allocate memory map overlay");
+      return 0;
+    }
+
+  cur->next = grub_mmap_overlays;
+  cur->start = start;
+  cur->end = start + size;
+  cur->type = type;
+  cur->handle = curhandle++;
+  grub_mmap_overlays = cur;
+
+  if (grub_machine_mmap_register (start, size, type, curhandle))
+    {
+      grub_mmap_overlays = cur->next;
+      grub_free (cur);
+      return 0;
+    }
+
+  return cur->handle;
+}
+
+grub_err_t
+grub_mmap_unregister (int handle)
+{
+  struct grub_mmap_region *cur, *prev;
+
+  for (cur = grub_mmap_overlays, prev = 0; cur; prev= cur, cur = cur->next)
+    if (handle == cur->handle)
+      {
+	grub_err_t err;
+	if ((err = grub_machine_mmap_unregister (handle)))
+	  return err;
+
+	if (prev)
+	  prev->next = cur->next;
+	else
+	  grub_mmap_overlays = cur->next;
+	grub_free (cur);
+	return GRUB_ERR_NONE;
+      }
+  return grub_error (GRUB_ERR_BAD_ARGUMENT, "mmap overlay not found");
+}
+
+#endif /* ! GRUB_MMAP_REGISTER_BY_FIRMWARE */
+
+#define CHUNK_SIZE	0x400
+
+static inline grub_uint64_t 
+fill_mask (grub_uint64_t addr, grub_uint64_t mask, grub_uint64_t iterator)
+{
+  int i, j;
+  grub_uint64_t ret = (addr & mask);
+
+  /* Find first fixed bit. */
+  for (i = 0; i < 64; i++)
+    if ((mask & (1ULL << i)) != 0)
+      break;
+  j = 0;
+  for (; i < 64; i++)
+    if ((mask & (1ULL << i)) == 0)
+      {
+	if ((iterator & (1ULL << j)) != 0)
+	  ret |= 1ULL << i;
+	j++;
+      }
+  return ret;
+}
+
+static grub_err_t
+grub_cmd_badram (grub_command_t cmd __attribute__ ((unused)),
+		 int argc, char **args)
+{
+  char * str;
+  grub_uint64_t badaddr, badmask;
+
+  auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t);
+  int NESTED_FUNC_ATTR hook (grub_uint64_t addr, 
+			     grub_uint64_t size, 
+			     grub_uint32_t type __attribute__ ((unused)))
+  {
+    grub_uint64_t iterator, low, high, cur;
+    int tail, var;
+    int i;
+    grub_dprintf ("badram", "hook %llx+%llx\n", (unsigned long long) addr, 
+		  (unsigned long long) size); 
+
+    /* How many trailing zeros? */
+    for (tail = 0; ! (badmask & (1ULL << tail)); tail++);
+
+    /* How many zeros in mask? */
+    var = 0;
+    for (i = 0; i < 64; i++)
+      if (! (badmask & (1ULL << i)))
+	var++;
+
+    if (fill_mask (badaddr, badmask, 0) >= addr)
+      iterator = 0;
+    else
+      {
+	low = 0;
+	high = ~0ULL;
+	/* Find starting value. Keep low and high such that 
+	   fill_mask (low) < addr and fill_mask (high) >= addr;
+	*/
+	while (high - low > 1)
+	  {
+	    cur = (low + high) / 2;
+	    if (fill_mask (badaddr, badmask, cur) >= addr)
+	      high = cur;
+	    else
+	      low = cur;
+	  }
+	iterator = high;
+      }
+
+    for (; iterator < (1ULL << (var - tail))
+	   && (cur = fill_mask (badaddr, badmask, iterator)) < addr + size; 
+	 iterator++)
+      {
+	grub_dprintf ("badram", "%llx (size %llx) is a badram range\n", 
+		      (long long) cur, (long long) (1ULL << tail) - 1); 
+	grub_mmap_register (cur, (1ULL << tail) - 1, GRUB_MACHINE_MEMORY_HOLE);
+      }
+    return 0;
+  }
+
+  if (argc != 1)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT, "badram string required");
+
+  grub_dprintf ("badram", "executing badram\n");
+
+  str = args[0];
+
+  while (1)
+    {
+      /* Parse address and mask.  */
+      badaddr = grub_strtoull (str, &str, 16);
+      if (*str == ',')
+	str++;
+      badmask = grub_strtoull (str, &str, 16);
+      if (*str == ',')
+	str++;
+
+      if (grub_errno == GRUB_ERR_BAD_NUMBER)
+	{
+	  grub_errno = 0;
+	  return GRUB_ERR_NONE;
+	}
+
+      /* When part of a page is tainted, we discard the whole of it.  There's
+	 no point in providing sub-page chunks.  */
+      badmask &= ~(CHUNK_SIZE - 1);
+
+      grub_dprintf ("badram", "badram %llx:%llx\n", 
+		    (unsigned long long) badaddr, (unsigned long long) badmask);
+
+      grub_mmap_iterate (hook);
+    }
+}
+
+static grub_command_t cmd;
+
+\f
+GRUB_MOD_INIT(mmap)
+{
+  (void) mod;			/* To stop warning. */
+  cmd = grub_register_command ("badram", grub_cmd_badram,
+			       "badram ADDR1,MASK1[,ADDR2,MASK2[,...]]", 
+			       "declare memory regions as badram");
+}
+
+GRUB_MOD_FINI(mmap)
+{
+  grub_unregister_command (cmd);
+}
+

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: mmap services
  2009-04-26 14:42 ` Vladimir 'phcoder' Serbinenko
@ 2009-04-30 13:36   ` Vladimir 'phcoder' Serbinenko
  2009-04-30 13:46     ` David Miller
  0 siblings, 1 reply; 4+ messages in thread
From: Vladimir 'phcoder' Serbinenko @ 2009-04-30 13:36 UTC (permalink / raw)
  To: The development of GRUB 2


[-- Attachment #1.1: Type: text/plain, Size: 836 bytes --]

Rediffed and reposted due to request by David Miller

On Sun, Apr 26, 2009 at 4:42 PM, Vladimir 'phcoder' Serbinenko <
phcoder@gmail.com> wrote:

> Updated. Now works on EFI. Additional function
> grub_mmap_malign_and_register
> Which finds a spot in memory map with required characteristics and
> registers it.
> I successfully booted freedos with this patch and badram
>
>
> On Sat, Apr 11, 2009 at 11:01 PM, phcoder <phcoder@gmail.com> wrote:
>
>> Hello. Here is the patch to allow different mmap filtering. It naturally
>> incorporates badram and also intercepts int12/15 so it works also with OS
>> recieving mmap from BIOS. It's useful for intercepting any bios interrupts
>>  --
>>
>> Regards
>> Vladimir 'phcoder' Serbinenko
>>
>
>
>
> --
> Regards
> Vladimir 'phcoder' Serbinenko
>



-- 
Regards
Vladimir 'phcoder' Serbinenko

[-- Attachment #1.2: Type: text/html, Size: 1564 bytes --]

[-- Attachment #2: mmap.diff --]
[-- Type: text/x-diff, Size: 60445 bytes --]

diff --git a/ChangeLog b/ChangeLog
index 9097f25..3dab81c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,58 @@
+2009-04-26  Vladimir Serbinenko <phcoder@gmail.com>
+
+	Mmap services
+
+	* loader/i386/efi/linux.c (grub_linux_boot): use grub_mmap_iterate
+	* loader/i386/linux.c (find_mmap_size): likewise
+	(allocate_pages): likewise
+	* loader/i386/multiboot.c (grub_get_multiboot_mmap_len): likewise
+	(grub_fill_multiboot_mmap): likewise
+	(grub_multiboot): use grub_mmap_get_lower and grub_mmap_get_upper
+	* loader/i386/pc/linux.c (grub_cmd_linux): use grub_mmap_get_lower
+	* include/grub/i386/bsd.h (OPENBSD_MMAP_AVAILABLE): new definition
+	(OPENBSD_MMAP_RESERVED): likewise
+	* include/grub/i386/pc/memory.h: include grub/memory.h
+	(grub_lower_mem): removed
+	(grub_upper_mem): likewise
+	(GRUB_MACHINE_MEMORY_ACPI): new definition
+	(GRUB_MACHINE_MEMORY_NVS): likewise
+	(GRUB_MACHINE_MEMORY_MAX_TYPE): likewise
+	(GRUB_MACHINE_MEMORY_HOLE): likewise
+	(grub_machine_mmap_register): likewise
+	(grub_machine_mmap_unregister): likewise
+	(grub_machine_get_upper): likewise
+	(grub_machine_get_lower): likewise
+	(grub_machine_get_post64): likewise
+	* include/grub/i386/efi/memory.h: new file
+	* include/grub/x86_64/efi/memory.h: likewise
+	* include/grub/efi/memory.h: likewise
+	* conf/i386-pc.rmk (pkglib_MODULES): added mmap.mod
+	(mmap_mod_SOURCES): new variable
+	(mmap_mod_LDFLAGS): likewise
+	(mmap_mod_ASFLAGS): likewise
+	* conf/i386-coreboot.rmk: likewise
+	* conf/i386-ieee1275.rmk: likewise
+	* conf/i386-efi.rmk: likewise
+	* conf/x86_64-efi.rmk: likewise
+	* include/grub/types.h (UINT_TO_PTR): new macro
+	(PTR_TO_UINT32): likewise
+	(PTR_TO_UINT64): likewise
+	* include/grub/memory.h: new file
+	* mmap/i386/pc/mmap.c: likewise
+	* mmap/i386/pc/mmap_helper.S: likewise
+	* mmap/i386/uppermem.c: likewise
+	* mmap/mmap.c: likewise
+	* mmap/efi/mmap.c: likewise
+	* kern/i386/coreboot/init.c (grub_machine_init): don't use 
+	grub_upper_mem
+	* kern/i386/pc/init.c (grub_lower_mem): removed variable
+	(grub_upper_mem): likewise
+	(grub_machine_init): don't use grub_upper_mem,
+	make grub_lower_mem local
+	* loader/i386/bsd.c (grub_openbsd_boot): use grub_mmap_get_lower,
+	grub_mmap_iterate and grub_mmap_get_upper
+	(grub_netbsd_boot): use grub_mmap_get_lower and grub_mmap_get_upper
+
 2009-04-30  David S. Miller  <davem@davemloft.net>
 
 	* util/hostdisk.c (device_is_wholedisk): New function.
diff --git a/conf/i386-coreboot.rmk b/conf/i386-coreboot.rmk
index 1284fe4..89014a6 100644
--- a/conf/i386-coreboot.rmk
+++ b/conf/i386-coreboot.rmk
@@ -104,7 +104,13 @@ pkglib_MODULES = linux.mod normal.mod multiboot.mod 	\
 	aout.mod play.mod serial.mod ata.mod		\
 	memdisk.mod pci.mod lspci.mod reboot.mod	\
 	halt.mod datetime.mod date.mod datehook.mod	\
-	lsmmap.mod
+	lsmmap.mod mmap.mod
+
+# For mmap.mod.
+mmap_mod_SOURCES = mmap/mmap.c mmap/i386/uppermem.c mmap/i386/mmap.c
+mmap_mod_CFLAGS = $(COMMON_CFLAGS)
+mmap_mod_LDFLAGS = $(COMMON_LDFLAGS)
+mmap_mod_ASFLAGS = $(COMMON_ASFLAGS)
 
 # For linux.mod.
 linux_mod_SOURCES = loader/i386/linux.c
diff --git a/conf/i386-efi.rmk b/conf/i386-efi.rmk
index 717683b..3c8c62d 100644
--- a/conf/i386-efi.rmk
+++ b/conf/i386-efi.rmk
@@ -82,7 +82,7 @@ grub_install_SOURCES = util/i386/efi/grub-install.in
 # Modules.
 pkglib_MODULES = kernel.mod normal.mod chain.mod appleldr.mod \
 	linux.mod halt.mod reboot.mod pci.mod lspci.mod \
-	datetime.mod date.mod datehook.mod loadbios.mod fixvideo.mod
+	datetime.mod date.mod datehook.mod loadbios.mod fixvideo.mod mmap.mod
 
 # For kernel.mod.
 kernel_mod_EXPORTS = no
@@ -135,6 +135,12 @@ normal_mod_CFLAGS = $(COMMON_CFLAGS)
 normal_mod_ASFLAGS = $(COMMON_ASFLAGS)
 normal_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
+# For mmap.mod.
+mmap_mod_SOURCES = mmap/mmap.c mmap/i386/uppermem.c mmap/i386/mmap.c \
+		   mmap/efi/mmap.c
+mmap_mod_CFLAGS = $(COMMON_CFLAGS)
+mmap_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
 # For chain.mod.
 chain_mod_SOURCES = loader/efi/chainloader.c
 chain_mod_CFLAGS = $(COMMON_CFLAGS)
diff --git a/conf/i386-ieee1275.rmk b/conf/i386-ieee1275.rmk
index cb32c73..08fdd98 100644
--- a/conf/i386-ieee1275.rmk
+++ b/conf/i386-ieee1275.rmk
@@ -104,7 +104,13 @@ grub_install_SOURCES = util/ieee1275/grub-install.in
 pkglib_MODULES = normal.mod halt.mod reboot.mod suspend.mod		\
 	multiboot.mod aout.mod serial.mod linux.mod	\
 	nand.mod memdisk.mod pci.mod lspci.mod datetime.mod	\
-	date.mod datehook.mod lsmmap.mod
+	date.mod datehook.mod lsmmap.mod mmap.mod
+
+# For mmap.mod.
+mmap_mod_SOURCES = mmap/mmap.c mmap/i386/uppermem.c mmap/i386/mmap.c
+mmap_mod_CFLAGS = $(COMMON_CFLAGS)
+mmap_mod_LDFLAGS = $(COMMON_LDFLAGS)
+mmap_mod_ASFLAGS = $(COMMON_ASFLAGS)
 
 #
 # Only arch dependant part of normal.mod will be here. Common part for
diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk
index d74a5fa..709741a 100644
--- a/conf/i386-pc.rmk
+++ b/conf/i386-pc.rmk
@@ -182,7 +182,15 @@ pkglib_MODULES = biosdisk.mod chain.mod normal.mod \
 	ata.mod vga.mod memdisk.mod pci.mod lspci.mod	\
 	aout.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 \
+	mmap.mod
+
+# For mmap.mod.
+mmap_mod_SOURCES = mmap/mmap.c mmap/i386/uppermem.c mmap/i386/mmap.c \
+		   mmap/i386/pc/mmap.c mmap/i386/pc/mmap_helper.S
+mmap_mod_CFLAGS = $(COMMON_CFLAGS)
+mmap_mod_LDFLAGS = $(COMMON_LDFLAGS)
+mmap_mod_ASFLAGS = $(COMMON_ASFLAGS)
 
 # For biosdisk.mod.
 biosdisk_mod_SOURCES = disk/i386/pc/biosdisk.c
diff --git a/conf/x86_64-efi.rmk b/conf/x86_64-efi.rmk
index d7ad9a4..d19649b 100644
--- a/conf/x86_64-efi.rmk
+++ b/conf/x86_64-efi.rmk
@@ -83,7 +83,7 @@ grub_install_SOURCES = util/i386/efi/grub-install.in
 # Modules.
 pkglib_MODULES = kernel.mod normal.mod chain.mod appleldr.mod \
 	halt.mod reboot.mod linux.mod pci.mod lspci.mod \
-	datetime.mod date.mod datehook.mod loadbios.mod fixvideo.mod
+	datetime.mod date.mod datehook.mod loadbios.mod fixvideo.mod mmap.mod
 
 # For kernel.mod.
 kernel_mod_EXPORTS = no
@@ -137,6 +137,12 @@ normal_mod_CFLAGS = $(COMMON_CFLAGS)
 normal_mod_ASFLAGS = $(COMMON_ASFLAGS)
 normal_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
+# For mmap.mod.
+mmap_mod_SOURCES = mmap/mmap.c mmap/i386/uppermem.c mmap/i386/mmap.c \
+		   mmap/efi/mmap.c
+mmap_mod_CFLAGS = $(COMMON_CFLAGS)
+mmap_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
 # For chain.mod.
 chain_mod_SOURCES = loader/efi/chainloader.c
 chain_mod_CFLAGS = $(COMMON_CFLAGS)
diff --git a/include/grub/efi/memory.h b/include/grub/efi/memory.h
new file mode 100644
index 0000000..e1ac47c
--- /dev/null
+++ b/include/grub/efi/memory.h
@@ -0,0 +1,48 @@
+/*
+ *  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_MEMORY_MACHINE_HEADER
+#define GRUB_MEMORY_MACHINE_HEADER	1
+
+#include <grub/err.h>
+#include <grub/types.h>
+
+#define GRUB_MMAP_REGISTER_BY_FIRMWARE  1
+
+#define GRUB_MACHINE_MEMORY_AVAILABLE	1
+#define GRUB_MACHINE_MEMORY_RESERVED	2
+#define GRUB_MACHINE_MEMORY_ACPI	3
+#define GRUB_MACHINE_MEMORY_NVS         4
+#define GRUB_MACHINE_MEMORY_CODE        5
+#define GRUB_MACHINE_MEMORY_MAX_TYPE 	5
+  /* This one is special: it's used internally but is never reported 
+     by firmware. */
+#define GRUB_MACHINE_MEMORY_HOLE 	6
+
+
+grub_err_t EXPORT_FUNC(grub_machine_mmap_iterate) 
+(int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, grub_uint64_t, grub_uint32_t));
+grub_err_t grub_machine_mmap_register (grub_uint64_t start, grub_uint64_t size, 
+				       int type, int handle);
+grub_err_t grub_machine_mmap_unregister (int handle);
+
+grub_uint64_t grub_mmap_get_post64 (void);
+grub_uint64_t grub_mmap_get_upper (void);
+grub_uint64_t grub_mmap_get_lower (void);
+
+#endif /* ! GRUB_MEMORY_MACHINE_HEADER */
diff --git a/include/grub/i386/bsd.h b/include/grub/i386/bsd.h
index f50f18e..78fae79 100644
--- a/include/grub/i386/bsd.h
+++ b/include/grub/i386/bsd.h
@@ -148,6 +148,8 @@ struct grub_openbsd_bios_mmap
 {
   grub_uint64_t addr;
   grub_uint64_t len;
+#define	OPENBSD_MMAP_AVAILABLE	1
+#define	OPENBSD_MMAP_RESERVED 2
   grub_uint32_t type;
 };
 
diff --git a/include/grub/i386/efi/memory.h b/include/grub/i386/efi/memory.h
new file mode 100644
index 0000000..c9a61bb
--- /dev/null
+++ b/include/grub/i386/efi/memory.h
@@ -0,0 +1 @@
+#include <grub/efi/memory.h>
diff --git a/include/grub/i386/pc/memory.h b/include/grub/i386/pc/memory.h
index 08e92a9..d8d4342 100644
--- a/include/grub/i386/pc/memory.h
+++ b/include/grub/i386/pc/memory.h
@@ -25,6 +25,7 @@
 #ifndef ASM_FILE
 #include <grub/types.h>
 #include <grub/err.h>
+#include <grub/memory.h>
 #endif
 
 /* The scratch buffer used in real mode code.  */
@@ -79,12 +80,6 @@
 
 #ifndef ASM_FILE
 
-#ifndef GRUB_MACHINE_IEEE1275
-extern grub_size_t EXPORT_VAR(grub_lower_mem);
-#endif
-
-extern grub_size_t EXPORT_VAR(grub_upper_mem);
-
 struct grub_machine_mmap_entry
 {
   grub_uint32_t size;
@@ -92,12 +87,41 @@ struct grub_machine_mmap_entry
   grub_uint64_t len;
 #define GRUB_MACHINE_MEMORY_AVAILABLE	1
 #define GRUB_MACHINE_MEMORY_RESERVED	2
+#define GRUB_MACHINE_MEMORY_ACPI	3
+#define GRUB_MACHINE_MEMORY_NVS 	4
+#define GRUB_MACHINE_MEMORY_MAX_TYPE 	4
+  /* This one is special: it's used internally but is never reported 
+     by firmware. */
+#define GRUB_MACHINE_MEMORY_HOLE 	5
+
   grub_uint32_t type;
 } __attribute__((packed));
 
 grub_err_t EXPORT_FUNC(grub_machine_mmap_iterate)
      (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, grub_uint64_t, grub_uint32_t));
 
+grub_uint64_t grub_mmap_get_post64 (void);
+grub_uint64_t grub_mmap_get_upper (void);
+grub_uint64_t grub_mmap_get_lower (void);
+
+#ifdef GRUB_MACHINE_PCBIOS
+grub_err_t grub_machine_mmap_register (grub_uint64_t start, grub_uint64_t size, 
+				       int type, int handle);
+grub_err_t grub_machine_mmap_unregister (int handle);
+#define GRUB_MMAP_MALLOC_LOW 1
+#else
+static inline grub_err_t grub_machine_mmap_register (grub_uint64_t start, 
+					      grub_uint64_t size, 
+					      int type, int handle)
+{
+  return GRUB_ERR_NONE;
+}
+static inline grub_err_t grub_machine_mmap_unregister (int handle)
+{
+  return GRUB_ERR_NONE;
+}
+#endif
+
 #endif
 
 #endif /* ! GRUB_MEMORY_MACHINE_HEADER */
diff --git a/include/grub/memory.h b/include/grub/memory.h
new file mode 100644
index 0000000..df64207
--- /dev/null
+++ b/include/grub/memory.h
@@ -0,0 +1,52 @@
+/* memory.h - describe the memory map */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2002,2007,2008  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_MEMORY_HEADER
+#define GRUB_MEMORY_HEADER	1
+
+#include <grub/types.h>
+#include <grub/err.h>
+#include <grub/machine/memory.h>
+
+grub_err_t grub_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, 
+							    grub_uint64_t, 
+							    grub_uint32_t));
+int grub_mmap_register (grub_uint64_t start, grub_uint64_t size, int type);
+grub_err_t grub_mmap_unregister (int handle);
+
+char *grub_mmap_malign_and_register (grub_uint64_t align, grub_uint64_t size,
+				     int *handle, int type, int flags);
+
+void grub_mmap_free_and_unregister (int handle);
+
+#ifndef GRUB_MMAP_REGISTER_BY_FIRMWARE
+
+struct grub_mmap_region
+{
+  struct grub_mmap_region *next;
+  grub_uint64_t start;
+  grub_uint64_t end;
+  int type;
+  int handle;
+};
+
+extern struct grub_mmap_region *grub_mmap_overlays;
+#endif
+
+#endif /* ! GRUB_MEMORY_HEADER */
diff --git a/include/grub/types.h b/include/grub/types.h
index 50f8f58..114b456 100644
--- a/include/grub/types.h
+++ b/include/grub/types.h
@@ -102,6 +102,16 @@ typedef grub_int32_t	grub_ssize_t;
 # define GRUB_LONG_MIN -2147483648UL
 #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;
 
diff --git a/include/grub/x86_64/efi/memory.h b/include/grub/x86_64/efi/memory.h
new file mode 100644
index 0000000..c9a61bb
--- /dev/null
+++ b/include/grub/x86_64/efi/memory.h
@@ -0,0 +1 @@
+#include <grub/efi/memory.h>
diff --git a/kern/i386/coreboot/init.c b/kern/i386/coreboot/init.c
index fdaf6fd..7bc4291 100644
--- a/kern/i386/coreboot/init.c
+++ b/kern/i386/coreboot/init.c
@@ -82,16 +82,11 @@ grub_machine_init (void)
 #if GRUB_CPU_SIZEOF_VOID_P == 4
     /* Restrict ourselves to 32-bit memory space.  */
     if (addr > GRUB_ULONG_MAX)
-      {
-	grub_upper_mem = GRUB_ULONG_MAX;
-	return 0;
-      }
-    if (addr + size > GRUB_ULONG_MAX)
+      return 0;
+    if (addr + size > ULONG_MAX)
       size = GRUB_ULONG_MAX - addr;
 #endif
 
-    grub_upper_mem = grub_max (grub_upper_mem, addr + size);
-
     if (type != GRUB_MACHINE_MEMORY_AVAILABLE)
       return 0;
 
@@ -128,9 +123,6 @@ grub_machine_init (void)
   grub_machine_mmap_init ();
   grub_machine_mmap_iterate (heap_init);
 
-  /* This variable indicates size, not offset.  */
-  grub_upper_mem -= GRUB_MEMORY_MACHINE_UPPER_START;
-
   grub_tsc_init ();
 }
 
diff --git a/kern/i386/pc/init.c b/kern/i386/pc/init.c
index 6191412..c64497e 100644
--- a/kern/i386/pc/init.c
+++ b/kern/i386/pc/init.c
@@ -45,7 +45,6 @@ static int num_regions;
 
 grub_addr_t grub_os_area_addr;
 grub_size_t grub_os_area_size;
-grub_size_t grub_lower_mem, grub_upper_mem;
 
 void 
 grub_arch_sync_caches (void *address __attribute__ ((unused)),
@@ -133,6 +132,7 @@ void
 grub_machine_init (void)
 {
   int i;
+  int grub_lower_mem;
   
   /* Initialize the console as early as possible.  */
   grub_console_init ();
@@ -197,7 +197,6 @@ grub_machine_init (void)
       {
 	grub_size_t quarter = mem_regions[i].size >> 2;
 
-	grub_upper_mem = mem_regions[i].size;
 	grub_os_area_addr = mem_regions[i].addr;
 	grub_os_area_size = mem_regions[i].size - quarter;
 	grub_mm_init_region ((void *) (grub_os_area_addr + grub_os_area_size),
diff --git a/loader/i386/bsd.c b/loader/i386/bsd.c
index 355cb3f..ea51aa2 100644
--- a/loader/i386/bsd.c
+++ b/loader/i386/bsd.c
@@ -313,30 +313,36 @@ static grub_err_t
 grub_openbsd_boot (void)
 {
   char *buf = (char *) GRUB_BSD_TEMP_BUFFER;
-  struct grub_machine_mmap_entry mmap;
   struct grub_openbsd_bios_mmap *pm;
   struct grub_openbsd_bootargs *pa;
-  grub_uint32_t bootdev, biosdev, unit, slice, part, cont;
+  grub_uint32_t bootdev, biosdev, unit, slice, part;
+
+  auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t);
+  int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size, grub_uint32_t type)
+    {
+      pm->addr = addr;
+      pm->len = size;
+
+      switch (type)
+        {
+        case GRUB_MACHINE_MEMORY_AVAILABLE:
+	  pm->type = OPENBSD_MMAP_AVAILABLE;
+	  break;
+	  
+	default:
+	  pm->type = OPENBSD_MMAP_RESERVED;
+	  break;
+	}
+      pm++;
+
+      return 0;
+    }
 
   pa = (struct grub_openbsd_bootargs *) buf;
 
   pa->ba_type = OPENBSD_BOOTARG_MMAP;
   pm = (struct grub_openbsd_bios_mmap *) (pa + 1);
-  cont = grub_get_mmap_entry (&mmap, 0);
-  if (mmap.size)
-    do
-      {
-	pm->addr = mmap.addr;
-	pm->len = mmap.len;
-	pm->type = mmap.type;
-	pm++;
-
-	if (!cont)
-	  break;
-
-	cont = grub_get_mmap_entry (&mmap, cont);
-      }
-    while (mmap.size);
+  grub_mmap_iterate (hook);
 
   pa->ba_size = (char *) pm - (char *) pa;
   pa->ba_next = (struct grub_openbsd_bootargs *) pm;
@@ -349,7 +355,8 @@ grub_openbsd_boot (void)
 	     (part << OPENBSD_B_PARTSHIFT));
 
   grub_unix_real_boot (entry, bootflags, bootdev, OPENBSD_BOOTARG_APIVER,
-		       0, grub_upper_mem >> 10, grub_lower_mem >> 10,
+		       0, grub_mmap_get_upper () >> 10, 
+		       grub_mmap_get_lower () >> 10,
 		       (char *) pa - buf, buf);
 
   /* Not reached.  */
@@ -377,7 +384,8 @@ grub_netbsd_boot (void)
   bootinfo->bi_data[0] = rootdev;
 
   grub_unix_real_boot (entry, bootflags, 0, bootinfo,
-		       0, grub_upper_mem >> 10, grub_lower_mem >> 10);
+		       0, grub_mmap_get_upper () >> 10, 
+		       grub_mmap_get_lower () >> 10);
 
   /* Not reached.  */
   return GRUB_ERR_NONE;
diff --git a/loader/i386/efi/linux.c b/loader/i386/efi/linux.c
index 100b268..9be88aa 100644
--- a/loader/i386/efi/linux.c
+++ b/loader/i386/efi/linux.c
@@ -32,6 +32,7 @@
 #include <grub/efi/uga_draw.h>
 #include <grub/pci.h>
 #include <grub/command.h>
+#include <grub/memory.h>
 
 #define GRUB_LINUX_CL_OFFSET		0x1000
 #define GRUB_LINUX_CL_END_OFFSET	0x2000
@@ -300,7 +301,6 @@ grub_linux_boot (void)
   grub_efi_uintn_t map_key;
   grub_efi_uintn_t desc_size;
   grub_efi_uint32_t desc_version;
-  grub_efi_memory_descriptor_t *desc;
   int e820_num;
   
   params = real_mode_mem;
@@ -313,84 +313,53 @@ grub_linux_boot (void)
 		(unsigned) idt_desc.limit, (unsigned long) idt_desc.base,
 		(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)
-    grub_fatal ("cannot get memory map");
-
-  e820_num = 0;
-  for (desc = mmap_buf;
-       desc < NEXT_MEMORY_DESCRIPTOR (mmap_buf, mmap_size);
-       desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size))
+  auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t);
+  int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size, grub_uint32_t type)
     {
-      switch (desc->type)
-	{
-	case GRUB_EFI_ACPI_RECLAIM_MEMORY:
+      switch (type)
+        {
+        case GRUB_MACHINE_MEMORY_AVAILABLE:
 	  grub_e820_add_region (params->e820_map, &e820_num,
-				desc->physical_start,
-				desc->num_pages << 12,
-				GRUB_E820_ACPI);
+				addr, size, GRUB_E820_RAM);
 	  break;
 
-	case GRUB_EFI_ACPI_MEMORY_NVS:
+#ifdef GRUB_MACHINE_MEMORY_ACPI
+        case GRUB_MACHINE_MEMORY_ACPI:
 	  grub_e820_add_region (params->e820_map, &e820_num,
-				desc->physical_start,
-				desc->num_pages << 12,
-				GRUB_E820_NVS);
+				addr, size, GRUB_E820_ACPI);
 	  break;
+#endif
 
-	case GRUB_EFI_RUNTIME_SERVICES_CODE:
+#ifdef GRUB_MACHINE_MEMORY_NVS
+        case GRUB_MACHINE_MEMORY_NVS:
 	  grub_e820_add_region (params->e820_map, &e820_num,
-				desc->physical_start,
-				desc->num_pages << 12,
-				GRUB_E820_EXEC_CODE);
+				addr, size, GRUB_E820_NVS);
 	  break;
+#endif
 
-	case GRUB_EFI_LOADER_CODE:
-	case GRUB_EFI_LOADER_DATA:
-	case GRUB_EFI_BOOT_SERVICES_CODE:
-	case GRUB_EFI_BOOT_SERVICES_DATA:
-	case GRUB_EFI_CONVENTIONAL_MEMORY:
-	  {
-	    grub_uint64_t start, size, end;
-
-	    start = desc->physical_start;
-	    size = desc->num_pages << 12;
-	    end = start + size;
-
-	    /* Skip A0000 - 100000 region.  */
-	    if ((start < 0x100000ULL) && (end > 0xA0000ULL))
-	      {
-		if (start < 0xA0000ULL)
-		  {
-		    grub_e820_add_region (params->e820_map, &e820_num,
-					  start,
-					  0xA0000ULL - start,
-					  GRUB_E820_RAM);
-		  }
-
-		if (end <= 0x100000ULL)
-		  continue;
-
-		start = 0x100000ULL;
-		size = end - start;
-	      }
-
-	    grub_e820_add_region (params->e820_map, &e820_num,
-				  start, size, GRUB_E820_RAM);
-	    break;
-	  }
-
-	default:
+#ifdef GRUB_MACHINE_MEMORY_CODE
+        case GRUB_MACHINE_MEMORY_CODE:
 	  grub_e820_add_region (params->e820_map, &e820_num,
-				desc->physical_start,
-				desc->num_pages << 12,
-				GRUB_E820_RESERVED);
-	}
+				addr, size, GRUB_E820_EXEC_CODE);
+	  break;
+#endif
+
+        default:
+          grub_e820_add_region (params->e820_map, &e820_num,
+                                addr, size, GRUB_E820_RESERVED);
+        }
+      return 0;
     }
 
+  e820_num = 0;
+  grub_mmap_iterate (hook);
   params->mmap_size = e820_num;
 
+  mmap_size = find_mmap_size ();
+  if (grub_efi_get_memory_map (&mmap_size, mmap_buf, &map_key,
+			       &desc_size, &desc_version) <= 0)
+    grub_fatal ("cannot get memory map");
+
   if (! grub_efi_exit_boot_services (map_key))
      grub_fatal ("cannot exit boot services");
 
diff --git a/loader/i386/ieee1275/linux.c b/loader/i386/ieee1275/linux.c
index 2f52880..a563577 100644
--- a/loader/i386/ieee1275/linux.c
+++ b/loader/i386/ieee1275/linux.c
@@ -100,7 +100,7 @@ grub_linux_boot (void)
 
   grub_memset ((char *) params, 0, GRUB_OFW_LINUX_CL_OFFSET);
 
-  params->alt_mem = grub_upper_mem >> 10;
+  params->alt_mem = grub_mmap_get_upper () >> 10;
   params->ext_mem = params->alt_mem;
 
   lh->cmd_line_ptr = (char *)
diff --git a/loader/i386/linux.c b/loader/i386/linux.c
index 19444f4..a72871b 100644
--- a/loader/i386/linux.c
+++ b/loader/i386/linux.c
@@ -168,7 +168,7 @@ find_mmap_size (void)
       return 0;
     }
   
-  grub_machine_mmap_iterate (hook);
+  grub_mmap_iterate (hook);
   
   mmap_size = count * sizeof (struct grub_e820_mmap);
 
@@ -237,7 +237,7 @@ allocate_pages (grub_size_t prot_size)
 
       return 0;
     }
-  grub_machine_mmap_iterate (hook);
+  grub_mmap_iterate (hook);
   if (! real_mode_mem)
     {
       grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate real mode pages");
@@ -396,6 +396,27 @@ grub_linux_boot (void)
 				addr, size, GRUB_E820_RAM);
 	  break;
 
+#ifdef GRUB_MACHINE_MEMORY_ACPI
+        case GRUB_MACHINE_MEMORY_ACPI:
+	  grub_e820_add_region (params->e820_map, &e820_num,
+				addr, size, GRUB_E820_ACPI);
+	  break;
+#endif
+
+#ifdef GRUB_MACHINE_MEMORY_NVS
+        case GRUB_MACHINE_MEMORY_NVS:
+	  grub_e820_add_region (params->e820_map, &e820_num,
+				addr, size, GRUB_E820_NVS);
+	  break;
+#endif
+
+#ifdef GRUB_MACHINE_MEMORY_CODE
+        case GRUB_MACHINE_MEMORY_CODE:
+	  grub_e820_add_region (params->e820_map, &e820_num,
+				addr, size, GRUB_E820_EXEC_CODE);
+	  break;
+#endif
+
         default:
           grub_e820_add_region (params->e820_map, &e820_num,
                                 addr, size, GRUB_E820_RESERVED);
@@ -404,9 +425,10 @@ grub_linux_boot (void)
     }
 
   e820_num = 0;
-  grub_machine_mmap_iterate (hook);
+  grub_mmap_iterate (hook);
   params->mmap_size = e820_num;
 
+
   /* Hardware interrupts are not safe any longer.  */
   asm volatile ("cli" : : );
   
diff --git a/loader/i386/multiboot.c b/loader/i386/multiboot.c
index 27042a5..d38590f 100644
--- a/loader/i386/multiboot.c
+++ b/loader/i386/multiboot.c
@@ -100,7 +100,7 @@ grub_get_multiboot_mmap_len (void)
       return 0;
     }
   
-  grub_machine_mmap_iterate (hook);
+  grub_mmap_iterate (hook);
   
   return count * sizeof (struct grub_multiboot_mmap_entry);
 }
@@ -123,7 +123,7 @@ grub_fill_multiboot_mmap (struct grub_multiboot_mmap_entry *first_entry)
       return 0;
     }
 
-  grub_machine_mmap_iterate (hook);
+  grub_mmap_iterate (hook);
 }
 
 #define MULTIBOOT_LOAD_ELF64
@@ -342,8 +342,8 @@ grub_multiboot (int argc, char *argv[])
 		grub_multiboot_payload_entry_offset);
 
   /* Convert from bytes to kilobytes.  */
-  mbi->mem_lower = grub_lower_mem / 1024;
-  mbi->mem_upper = grub_upper_mem / 1024;
+  mbi->mem_lower = grub_mmap_get_lower () / 1024;
+  mbi->mem_upper = grub_mmap_get_upper () / 1024;
   mbi->flags |= MULTIBOOT_INFO_MEMORY;
 
   cmdline = p = cmdline_addr (grub_multiboot_payload_orig);
diff --git a/loader/i386/pc/linux.c b/loader/i386/pc/linux.c
index 8ff97f4..34a4ebc 100644
--- a/loader/i386/pc/linux.c
+++ b/loader/i386/pc/linux.c
@@ -108,8 +108,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
       lh.type_of_loader = GRUB_LINUX_BOOT_LOADER_TYPE;
       
       /* Put the real mode part at as a high location as possible.  */
-      grub_linux_real_addr = (char *) (grub_lower_mem
-				       - GRUB_LINUX_SETUP_MOVE_SIZE);
+      grub_linux_real_addr 
+	= (char *) UINT_TO_PTR (grub_mmap_get_lower ()
+				- GRUB_LINUX_SETUP_MOVE_SIZE);
       /* But it must not exceed the traditional area.  */
       if (grub_linux_real_addr > (char *) GRUB_LINUX_OLD_REAL_MODE_ADDR)
 	grub_linux_real_addr = (char *) GRUB_LINUX_OLD_REAL_MODE_ADDR;
@@ -159,12 +160,12 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
     }
   
   if (grub_linux_real_addr + GRUB_LINUX_SETUP_MOVE_SIZE
-      > (char *) grub_lower_mem)
+      > (char *) UINT_TO_PTR (grub_mmap_get_lower ()))
     {
       grub_error (GRUB_ERR_OUT_OF_RANGE,
 		 "too small lower memory (0x%x > 0x%x)",
-		 grub_linux_real_addr + GRUB_LINUX_SETUP_MOVE_SIZE,
-		 (char *) grub_lower_mem);
+		  grub_linux_real_addr + GRUB_LINUX_SETUP_MOVE_SIZE,
+		  (int) grub_mmap_get_lower ());
       goto fail;
     }
 
diff --git a/mmap/efi/mmap.c b/mmap/efi/mmap.c
new file mode 100644
index 0000000..3b1a0bd
--- /dev/null
+++ b/mmap/efi/mmap.c
@@ -0,0 +1,284 @@
+/* Mmap management. */
+/*
+ *  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/machine/memory.h>
+#include <grub/memory.h>
+#include <grub/err.h>
+#include <grub/efi/api.h>
+#include <grub/efi/efi.h>
+#include <grub/mm.h>
+#include <grub/misc.h>
+
+#define NEXT_MEMORY_DESCRIPTOR(desc, size)      \
+  ((grub_efi_memory_descriptor_t *) ((char *) (desc) + (size)))
+
+grub_err_t
+grub_machine_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, 
+							 grub_uint64_t, 
+							 grub_uint32_t))
+{
+  grub_efi_uintn_t mmap_size = 0;
+  grub_efi_memory_descriptor_t *map_buf = 0;
+  grub_efi_uintn_t map_key = 0;
+  grub_efi_uintn_t desc_size = 0;
+  grub_efi_uint32_t desc_version = 0;
+  grub_efi_memory_descriptor_t *desc;
+
+  if (grub_efi_get_memory_map (&mmap_size, map_buf,
+			       &map_key, &desc_size,
+			       &desc_version) < 0)
+    return grub_errno;
+
+  map_buf = grub_malloc (mmap_size);
+  if (! map_buf)
+    return grub_errno;
+
+  if (grub_efi_get_memory_map (&mmap_size, map_buf,
+			       &map_key, &desc_size,
+			       &desc_version) <= 0)
+    {
+      grub_free (map_buf);
+      return grub_errno;
+    }
+
+  for (desc = map_buf;
+       desc < NEXT_MEMORY_DESCRIPTOR (map_buf, mmap_size);
+       desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size))
+    {
+      grub_dprintf ("mmap", "EFI memory region 0x%llx-0x%llx: %d\n",
+		    (unsigned long long) desc->physical_start, 
+		    (unsigned long long) desc->physical_start
+		    + desc->num_pages * 4096, desc->type);
+      switch (desc->type)
+	{
+	case GRUB_EFI_RUNTIME_SERVICES_CODE:
+	  hook (desc->physical_start, desc->num_pages * 4096, 
+		GRUB_MACHINE_MEMORY_CODE);
+	  break;
+
+	default:
+	  grub_printf ("Unknown memory type %d, considering reserved\n",
+		       desc->type);
+
+	case GRUB_EFI_RESERVED_MEMORY_TYPE:
+	case GRUB_EFI_RUNTIME_SERVICES_DATA:
+	case GRUB_EFI_UNUSABLE_MEMORY:
+	case GRUB_EFI_MEMORY_MAPPED_IO:
+	case GRUB_EFI_MEMORY_MAPPED_IO_PORT_SPACE:
+	case GRUB_EFI_PAL_CODE:
+	  hook (desc->physical_start, desc->num_pages * 4096, 
+		GRUB_MACHINE_MEMORY_RESERVED);
+	  break;
+
+	case GRUB_EFI_LOADER_CODE:
+	case GRUB_EFI_LOADER_DATA:
+	case GRUB_EFI_BOOT_SERVICES_CODE:
+	case GRUB_EFI_BOOT_SERVICES_DATA:
+	case GRUB_EFI_CONVENTIONAL_MEMORY:
+	  hook (desc->physical_start, desc->num_pages * 4096, 
+		GRUB_MACHINE_MEMORY_AVAILABLE);
+	  break;
+
+	case GRUB_EFI_ACPI_RECLAIM_MEMORY:
+	  hook (desc->physical_start, desc->num_pages * 4096, 
+		GRUB_MACHINE_MEMORY_ACPI);
+	  break;
+
+	case GRUB_EFI_ACPI_MEMORY_NVS:
+	  hook (desc->physical_start, desc->num_pages * 4096, 
+		GRUB_MACHINE_MEMORY_NVS);
+	  break;
+	}
+    }
+
+  return GRUB_ERR_NONE;
+}
+
+static inline grub_efi_memory_type_t 
+make_efi_memtype (int type)
+{
+  switch (type)
+    {
+    case GRUB_MACHINE_MEMORY_CODE:
+      return GRUB_EFI_RUNTIME_SERVICES_CODE;
+
+      /* No way to remove a chunk of memory from EFI mmap. 
+	 So mark it as unusable. */
+    case GRUB_MACHINE_MEMORY_HOLE:
+      
+    default:
+
+    case GRUB_MACHINE_MEMORY_RESERVED:
+      return GRUB_EFI_UNUSABLE_MEMORY;
+
+    case GRUB_MACHINE_MEMORY_AVAILABLE:
+      return GRUB_EFI_CONVENTIONAL_MEMORY;
+
+    case GRUB_MACHINE_MEMORY_ACPI:
+      return GRUB_EFI_ACPI_RECLAIM_MEMORY;
+
+    case GRUB_MACHINE_MEMORY_NVS:
+      return GRUB_EFI_ACPI_RECLAIM_MEMORY;
+      
+    }
+
+}
+
+struct overlay
+{
+  struct overlay *next;
+  grub_efi_physical_address_t address;
+  grub_efi_uintn_t pages;
+  int handle;
+};
+
+static struct overlay *overlays = 0;
+static int curhandle = 1;
+
+int
+grub_mmap_register (grub_uint64_t start, grub_uint64_t size, int type)
+{
+  grub_uint64_t end = start + size;
+  grub_efi_physical_address_t address;
+  grub_efi_boot_services_t *b;
+  grub_efi_uintn_t pages;
+  grub_efi_status_t status;
+  struct overlay *curover;
+
+  curover = (struct overlay *) grub_malloc (sizeof (struct overlay));
+  if (! curover)
+    return 0;
+      
+  b = grub_efi_system_table->boot_services;
+  address = start & (~0x3ffULL);
+  pages = (end - address  + 0x3ff) >> 12;
+  status = efi_call_2 (b->free_pages, address, pages);
+  if (status != GRUB_EFI_SUCCESS && status != GRUB_EFI_NOT_FOUND)
+    {
+      grub_free (curover);
+      return 0;
+    }
+  status = efi_call_4 (b->allocate_pages, GRUB_EFI_ALLOCATE_ADDRESS, 
+		       make_efi_memtype (type), pages, &address);
+  if (status != GRUB_EFI_SUCCESS)
+    {
+      grub_free (curover);
+      return 0;
+    }
+  curover->next = overlays;
+  curover->handle = curhandle++;
+  curover->address = address;
+  curover->pages = pages;
+  overlays = curover;
+
+  return curover->handle;
+}
+
+grub_err_t 
+grub_machine_mmap_unregister (int handle)
+{
+  struct overlay *curover, *prevover;
+  grub_efi_boot_services_t *b;
+  grub_efi_status_t status;
+
+  b = grub_efi_system_table->boot_services;
+
+  
+  for (curover = overlays, prevover = 0; curover; 
+       prevover = curover, curover = curover->next)
+    {
+      if (curover->handle == handle)
+	{
+	  status = efi_call_2 (b->free_pages, curover->address, curover->pages);
+	  if (prevover != 0)
+	    prevover->next = curover->next;
+	  else
+	    overlays = curover->next;
+	  grub_free (curover);
+	  return GRUB_ERR_NONE;
+	}
+    }
+  return grub_error (GRUB_ERR_BAD_ARGUMENT, "handle %d not found", handle);
+}
+
+/* Result is always page-aligned. */
+char *
+grub_mmap_malign_and_register (grub_uint64_t align __attribute__ ((unused)), 
+			       grub_uint64_t size,
+			       int *handle, int type, 
+			       int flags __attribute__ ((unused)))
+{
+  grub_efi_physical_address_t address;
+  grub_efi_boot_services_t *b;
+  grub_efi_uintn_t pages;
+  grub_efi_status_t status;
+  struct overlay *curover;
+  grub_efi_allocate_type_t atype;
+
+  curover = (struct overlay *) grub_malloc (sizeof (struct overlay));
+  if (! curover)
+    return 0;
+      
+  b = grub_efi_system_table->boot_services;
+
+  address = 0xffffffff;
+
+#if GRUB_TARGET_SIZEOF_VOID_P < 8
+  /* Limit the memory access to less than 4GB for 32-bit platforms.  */
+  atype = GRUB_EFI_ALLOCATE_MAX_ADDRESS;
+#else
+  atype = GRUB_EFI_ALLOCATE_ANY_PAGES;
+#endif
+
+  pages = (size + 0x3ff) >> 12;
+  status = efi_call_4 (b->allocate_pages, atype, 
+		       make_efi_memtype (type), pages, &address);
+  if (status != GRUB_EFI_SUCCESS)
+    {
+      grub_free (curover);
+      return 0;
+    }
+
+  if (address == 0)
+    {
+      /* Uggh, the address 0 was allocated... This is too annoying,
+	 so reallocate another one.  */
+      address = 0xffffffff;
+      status = efi_call_4 (b->allocate_pages, atype, 
+			   make_efi_memtype (type), pages, &address);
+      grub_efi_free_pages (0, pages);
+      if (status != GRUB_EFI_SUCCESS)
+	return 0;
+    }
+  
+  curover->next = overlays;
+  curover->handle = curhandle++;
+  curover->address = address;
+  curover->pages = pages;
+  overlays = curover;
+  *handle = curover->handle;
+
+  return UINT_TO_PTR (curover->address);
+}
+
+void 
+grub_mmap_free_and_unregister (int handle)
+{
+  grub_machine_mmap_unregister (handle);
+}
diff --git a/mmap/i386/mmap.c b/mmap/i386/mmap.c
new file mode 100644
index 0000000..ed0c6e4
--- /dev/null
+++ b/mmap/i386/mmap.c
@@ -0,0 +1,98 @@
+/* Mmap management. */
+/*
+ *  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/machine/memory.h>
+#include <grub/memory.h>
+#include <grub/err.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+
+
+#ifndef GRUB_MMAP_REGISTER_BY_FIRMWARE
+
+char *
+grub_mmap_malign_and_register (grub_uint64_t align, grub_uint64_t size,
+			       int *handle, int type, int flags)
+{
+  grub_uint64_t highestlow = 0;
+
+  auto int NESTED_FUNC_ATTR find_hook (grub_uint64_t, grub_uint64_t, 
+				       grub_uint32_t);
+  int NESTED_FUNC_ATTR find_hook (grub_uint64_t start, grub_uint64_t rangesize, 
+				  grub_uint32_t memtype)
+  {
+    grub_uint64_t end = start + rangesize;
+    if (memtype != GRUB_MACHINE_MEMORY_AVAILABLE)
+      return 0;
+    if (end > 0x100000)
+      end = 0x100000;
+    if (end > start + size
+	&& highestlow < ((end - size) - ((end - size) & (align - 1))))
+      highestlow = (end - size)  - ((end - size) & (align - 1));
+    return 0;
+  }
+
+  char * ret;
+  if (flags & GRUB_MMAP_MALLOC_LOW)
+    {
+      /* FIXME: use low-memory mm allocation once it's available. */
+      grub_mmap_iterate (find_hook);
+      ret = UINT_TO_PTR (highestlow);
+    }
+  else
+    ret = grub_memalign (align, size);
+
+  if (! ret)
+    {
+      *handle = 0;
+      return 0;
+    }
+
+  *handle = grub_mmap_register (PTR_TO_UINT64 (ret), size, type);
+  if (! *handle)
+    {
+      grub_free (ret);
+      return 0;
+    }    
+
+  return ret;
+}
+
+void
+grub_mmap_free_and_unregister (int handle)
+{
+  struct grub_mmap_region *cur;
+  grub_uint64_t addr;
+
+  for (cur = grub_mmap_overlays; cur; cur = cur->next)
+    if (cur->handle == handle)
+      break;
+
+  if (! cur)
+    return;
+
+  addr = cur->start;
+    
+  grub_mmap_unregister (handle);
+
+  if (addr >= 0x100000)
+    grub_free (UINT_TO_PTR (addr));
+}
+
+#endif
diff --git a/mmap/i386/pc/mmap.c b/mmap/i386/pc/mmap.c
new file mode 100644
index 0000000..ec51727
--- /dev/null
+++ b/mmap/i386/pc/mmap.c
@@ -0,0 +1,216 @@
+/* Mmap management. */
+/*
+ *  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/machine/memory.h>
+#include <grub/memory.h>
+#include <grub/misc.h>
+#include <grub/term.h>
+#include <grub/loader.h>
+
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+
+static void *hooktarget = 0;
+
+extern grub_uint8_t grub_machine_mmaphook_start;
+extern grub_uint8_t grub_machine_mmaphook_end;
+extern grub_uint8_t grub_machine_mmaphook_int12;
+extern grub_uint8_t grub_machine_mmaphook_int15;
+
+static grub_uint16_t grub_machine_mmaphook_int12offset = 0;
+static grub_uint16_t grub_machine_mmaphook_int12segment = 0;
+extern grub_uint16_t grub_machine_mmaphook_int15offset;
+extern grub_uint16_t grub_machine_mmaphook_int15segment;
+
+extern grub_uint16_t grub_machine_mmaphook_mmap_num;
+extern grub_uint16_t grub_machine_mmaphook_kblow;
+extern grub_uint16_t grub_machine_mmaphook_kbin16mb;
+extern grub_uint16_t grub_machine_mmaphook_64kbin4gb;
+
+struct grub_e820_mmap_entry
+{
+  grub_uint64_t addr;
+  grub_uint64_t len;
+  grub_uint32_t type;
+} __attribute__((packed));
+
+
+static grub_err_t 
+preboot (int noreturn __attribute__ ((unused)))
+{
+  struct grub_e820_mmap_entry *hookmmap, *hookmmapcur;
+  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)
+  {
+    grub_dprintf ("mmap", "mmap chunk %llx-%llx:%x\n", addr, addr + size, type);
+    hookmmapcur->addr = addr;
+    hookmmapcur->len = size;
+    hookmmapcur->type = type;
+    hookmmapcur++;
+    return 0;
+  }
+
+  if (! hooktarget)
+    return grub_error (GRUB_ERR_OUT_OF_MEMORY, 
+		       "no space is allocated for memory hook");
+
+  grub_dprintf ("mmap", "installing preboot handlers\n");
+
+  hookmmapcur = hookmmap = (struct grub_e820_mmap_entry *) 
+    ((grub_uint8_t *) hooktarget + (&grub_machine_mmaphook_end 
+				    - &grub_machine_mmaphook_start));
+
+  grub_mmap_iterate (fill_hook);  
+  grub_machine_mmaphook_mmap_num = hookmmapcur - hookmmap;
+
+  grub_machine_mmaphook_kblow = grub_mmap_get_lower () >> 10;
+  grub_machine_mmaphook_kbin16mb 
+    = min (grub_mmap_get_upper (),0x3f00000ULL) >> 10;
+  grub_machine_mmaphook_64kbin4gb 
+    = min (grub_mmap_get_post64 (), 0xfc000000ULL) >> 16;
+
+  /* Correct BDA. */
+  *((grub_uint16_t *) 0x413) = grub_mmap_get_lower () >> 10;
+
+  /* Save old interrupt handlers. */
+  grub_machine_mmaphook_int12offset = *((grub_uint16_t *) 0x48);
+  grub_machine_mmaphook_int12segment = *((grub_uint16_t *) 0x4a);
+  grub_machine_mmaphook_int15offset = *((grub_uint16_t *) 0x54);
+  grub_machine_mmaphook_int15segment = *((grub_uint16_t *) 0x56);
+
+  grub_dprintf ("mmap", "hooktarget = %p\n", hooktarget);
+
+  /* Install the interrupt handlers. */
+  grub_memcpy (hooktarget, &grub_machine_mmaphook_start,
+	       &grub_machine_mmaphook_end - &grub_machine_mmaphook_start);
+
+  *((grub_uint16_t *) 0x4a) = PTR_TO_UINT32 (hooktarget) >> 4;
+  *((grub_uint16_t *) 0x56) = PTR_TO_UINT32 (hooktarget) >> 4;
+  *((grub_uint16_t *) 0x48) = &grub_machine_mmaphook_int12 
+    - &grub_machine_mmaphook_start;
+  *((grub_uint16_t *) 0x54) = &grub_machine_mmaphook_int15
+    - &grub_machine_mmaphook_start;
+
+  return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+preboot_rest (void)
+{
+  /* Restore old interrupt handlers. */
+  *((grub_uint16_t *) 0x48) = grub_machine_mmaphook_int12offset;
+  *((grub_uint16_t *) 0x4a) = grub_machine_mmaphook_int12segment;
+  *((grub_uint16_t *) 0x54) = grub_machine_mmaphook_int15offset;
+  *((grub_uint16_t *) 0x56) = grub_machine_mmaphook_int15segment;
+
+  return GRUB_ERR_NONE;
+}
+
+static grub_err_t 
+malloc_hook (void)
+{
+  static int reentry = 0;
+  static int mmapregion = 0;
+  static int slots_available = 0;
+  int hooksize;
+  int regcount = 0;
+  auto int NESTED_FUNC_ATTR count_hook (grub_uint64_t, grub_uint64_t, 
+					grub_uint32_t);
+  int NESTED_FUNC_ATTR count_hook (grub_uint64_t addr __attribute__ ((unused)), 
+				   grub_uint64_t size __attribute__ ((unused)), 
+				   grub_uint32_t type __attribute__ ((unused)))
+  {
+    regcount++;
+    return 0;
+  }
+
+  if (reentry)
+    return GRUB_ERR_NONE;
+
+  grub_dprintf ("mmap", "registering\n");
+
+  grub_mmap_iterate (count_hook);
+
+  /* Mapping hook itself may introduce up to 2 additional regions. */
+  regcount += 2;
+
+  if (regcount <= slots_available)
+    return GRUB_ERR_NONE;
+
+  if (mmapregion)
+    {
+      grub_mmap_free_and_unregister (mmapregion);
+      mmapregion = 0;
+      hooktarget = 0;
+    }
+
+  hooksize = &grub_machine_mmaphook_end - &grub_machine_mmaphook_start
+    + regcount * sizeof (struct grub_e820_mmap_entry);
+  /* Allocate an integer number of KiB. */
+  hooksize = ((hooksize - 1) | 0x3ff) + 1;
+  slots_available = (hooksize - (&grub_machine_mmaphook_end 
+				 - &grub_machine_mmaphook_start))
+    / sizeof (struct grub_e820_mmap_entry);
+
+  reentry = 1;
+  hooktarget 
+    = grub_mmap_malign_and_register (16, hooksize, &mmapregion, 
+				     GRUB_MACHINE_MEMORY_RESERVED,
+				     GRUB_MMAP_MALLOC_LOW);
+  reentry = 0;
+
+  if (! hooktarget)
+    {
+      slots_available = 0;
+      return grub_error (GRUB_ERR_OUT_OF_MEMORY, "No space for mmap hook");
+    }
+  return GRUB_ERR_NONE;
+}
+
+grub_err_t
+grub_machine_mmap_register (grub_uint64_t start __attribute__ ((unused)), 
+			    grub_uint64_t size __attribute__ ((unused)), 
+			    int type __attribute__ ((unused)),
+			    int handle  __attribute__ ((unused)))
+{
+  grub_err_t err;
+  static void *preb_handle = 0;
+
+  err = malloc_hook ();
+  if (err)
+    return err;
+
+  if (! preb_handle)
+    {
+      grub_dprintf ("mmap", "adding preboot\n");
+      preb_handle 
+	= grub_loader_register_preboot_hook (preboot, preboot_rest, 
+					     GRUB_LOADER_PREBOOT_HOOK_PRIO_MEMORY);
+      if (! preb_handle)
+	return grub_errno;
+    }
+  return GRUB_ERR_NONE;
+}
+
+grub_err_t
+grub_machine_mmap_unregister (int handle __attribute__ ((unused)))
+{
+  return GRUB_ERR_NONE;
+}
diff --git a/mmap/i386/pc/mmap_helper.S b/mmap/i386/pc/mmap_helper.S
new file mode 100644
index 0000000..ab7c0d2
--- /dev/null
+++ b/mmap/i386/pc/mmap_helper.S
@@ -0,0 +1,122 @@
+/* Mmap management. */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2009  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/symbol.h>
+
+#define DS(x) ((x) - segstart)
+
+segstart:	
+VARIABLE(grub_machine_mmaphook_start)
+	.code16
+VARIABLE(grub_machine_mmaphook_int12)
+	push %ds
+	push %cs
+	pop %ds
+	movw DS (EXT_C (grub_machine_mmaphook_kblow)), %ax
+	pop %ds
+	iret
+
+VARIABLE(grub_machine_mmaphook_int15)
+	pushf
+	cmpw $0xe801, %ax
+	jz e801
+	cmpw $0xe820, %ax
+	jz e820
+	cmpb $0x88, %ah
+	jz h88
+	popf
+	/* ljmp */
+	.byte	0xea
+VARIABLE (grub_machine_mmaphook_int15offset)
+	.word	0
+VARIABLE (grub_machine_mmaphook_int15segment)
+	.word	0
+	
+e801:
+	popf
+	push %ds
+	push %cs
+	pop %ds
+	movw DS (EXT_C (grub_machine_mmaphook_kbin16mb)), %ax
+	movw DS (EXT_C (grub_machine_mmaphook_64kbin4gb)), %bx
+	movw %ax, %cx
+	movw %bx, %dx
+	pop %ds
+	clc
+	iret
+
+h88:
+	popf
+	push %ds
+	push %cs
+	pop %ds
+	movw DS (EXT_C (grub_machine_mmaphook_kbin16mb)), %ax
+	pop %ds
+	clc
+	iret
+
+e820:
+	popf
+	push %ds
+	push %cs
+	pop %ds
+	cmpw $20, %cx
+	jb errexit
+	cmpw DS (EXT_C (grub_machine_mmaphook_mmap_num)), %bx
+	jae errexit
+	cmp $0x534d4150, %edx
+	jne errexit
+	push %si
+	push %di
+	movw $20, %cx
+	movw $(DS(mmaphook_mmap)), %si
+	mov %bx, %ax
+	imul $20, %ax
+	add %ax, %si
+	rep movsb
+	pop %di
+	pop %si
+	movl $20, %ecx
+	inc %bx
+	cmpw DS(EXT_C(grub_machine_mmaphook_mmap_num)), %bx
+	jb noclean
+	xor %bx, %bx	
+noclean:	
+	mov $0x534d4150, %eax
+	pop %ds
+	clc
+	iret
+errexit:
+	mov $0x534d4150, %eax
+	pop %ds
+	stc
+	xor %bx, %bx
+	iret	
+	
+VARIABLE(grub_machine_mmaphook_mmap_num)
+	.word 0
+VARIABLE(grub_machine_mmaphook_kblow)
+	.word 0
+VARIABLE (grub_machine_mmaphook_kbin16mb)
+	.word 0
+VARIABLE (grub_machine_mmaphook_64kbin4gb)
+	.word 0
+mmaphook_mmap:
+	/* Memory map is placed just after the interrupt handlers. */
+VARIABLE(grub_machine_mmaphook_end)
diff --git a/mmap/i386/uppermem.c b/mmap/i386/uppermem.c
new file mode 100644
index 0000000..80576ca
--- /dev/null
+++ b/mmap/i386/uppermem.c
@@ -0,0 +1,85 @@
+/* Compute amount of lower and upper memory till the first hole. */
+/*
+ *  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/memory.h>
+#include <grub/mm.h>
+#include <grub/misc.h>
+
+grub_uint64_t 
+grub_mmap_get_lower (void)
+{
+  grub_uint64_t lower = 0;
+
+  auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t);
+  int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size,
+			     grub_uint32_t type)
+    {
+      if (type != GRUB_MACHINE_MEMORY_AVAILABLE)
+	return 0;
+      if (addr == 0)
+	lower = size;
+      return 0;
+    }
+
+  grub_mmap_iterate (hook);
+  if (lower > 0x100000)
+    lower =  0x100000;
+  return lower;
+}
+
+grub_uint64_t 
+grub_mmap_get_upper (void)
+{
+  grub_uint64_t upper = 0;
+
+  auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t);
+  int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size,
+			     grub_uint32_t type)
+    {
+      if (type != GRUB_MACHINE_MEMORY_AVAILABLE)
+	return 0;
+      if (addr <= 0x100000 && addr + size > 0x100000)
+	upper = addr + size - 0x100000;
+      return 0;
+    }
+
+  grub_mmap_iterate (hook);
+  return upper;
+}
+
+/* Count the continous bytes after 64 MiB. */
+grub_uint64_t 
+grub_mmap_get_post64 (void)
+{
+  grub_uint64_t post64 = 0;
+
+  auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t);
+  int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size,
+			     grub_uint32_t type)
+    {
+      if (type != GRUB_MACHINE_MEMORY_AVAILABLE)
+	return 0;
+      if (addr <= 0x4000000 && addr + size > 0x4000000)
+	post64 = addr + size - 0x4000000;
+      return 0;
+    }
+
+  grub_mmap_iterate (hook);
+  return post64;
+}
diff --git a/mmap/mmap.c b/mmap/mmap.c
new file mode 100644
index 0000000..1d82db7
--- /dev/null
+++ b/mmap/mmap.c
@@ -0,0 +1,426 @@
+/* Mmap management. */
+/*
+ *  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/machine/memory.h>
+#include <grub/memory.h>
+#include <grub/err.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/command.h>
+#include <grub/dl.h>
+
+#ifndef GRUB_MMAP_REGISTER_BY_FIRMWARE
+
+struct grub_mmap_region *grub_mmap_overlays = 0;
+static int curhandle = 1;
+
+#endif
+
+grub_err_t
+grub_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, 
+						 grub_uint64_t, grub_uint32_t))
+{
+
+  /* This function resolves overlapping regions and sorts the memory map.
+     It uses scanline (sweeping) algorithm.
+  */
+  /* If same page is used by multiple types it's resolved 
+     according to priority:
+     1 - free memory
+     2 - memory usable by firmware-aware code
+     3 - unusable memory
+     4 - a range deliberately empty
+  */
+  int priority[GRUB_MACHINE_MEMORY_MAX_TYPE + 2] =
+    {
+#ifdef GRUB_MACHINE_MEMORY_AVAILABLE
+      [GRUB_MACHINE_MEMORY_AVAILABLE] = 1,
+#endif
+#ifdef GRUB_MACHINE_MEMORY_RESERVED
+      [GRUB_MACHINE_MEMORY_RESERVED] = 3,
+#endif
+#ifdef GRUB_MACHINE_MEMORY_ACPI
+      [GRUB_MACHINE_MEMORY_ACPI] = 2,
+#endif
+#ifdef GRUB_MACHINE_MEMORY_CODE
+      [GRUB_MACHINE_MEMORY_CODE] = 3,
+#endif
+#ifdef GRUB_MACHINE_MEMORY_NVS
+      [GRUB_MACHINE_MEMORY_NVS] = 3,
+#endif
+      [GRUB_MACHINE_MEMORY_HOLE] = 4,
+    };
+
+  int i, k, done;
+
+  /* Scanline events. */
+  struct grub_mmap_scan
+  {
+    /* At which memory address. */
+    grub_uint64_t pos;
+    /* 0 = region starts, 1 = region ends. */
+    int type;
+    /* Which type of memory region? */
+    int memtype;
+  };
+  struct grub_mmap_scan *scanline_events;
+  struct grub_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_MACHINE_MEMORY_MAX_TYPE + 2];
+  /* Number of mmap chunks. */
+  int mmap_num;
+
+#ifndef GRUB_MMAP_REGISTER_BY_FIRMWARE     
+  struct grub_mmap_region *cur;
+#endif
+  
+  auto int NESTED_FUNC_ATTR count_hook (grub_uint64_t, grub_uint64_t, 
+					grub_uint32_t);
+  int NESTED_FUNC_ATTR count_hook (grub_uint64_t addr __attribute__ ((unused)),
+				   grub_uint64_t size __attribute__ ((unused)),
+				   grub_uint32_t type __attribute__ ((unused)))
+  {
+    mmap_num++;
+    return 0;
+  }
+
+  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)
+  {
+    scanline_events[i].pos = addr;
+    scanline_events[i].type = 0;
+    if (type <= GRUB_MACHINE_MEMORY_MAX_TYPE && priority[type])
+      scanline_events[i].memtype = type;
+    else
+      {
+	grub_dprintf ("mmap", "Unknown memory type %d. Assuming unusable\n",
+		      type);
+	scanline_events[i].memtype = GRUB_MACHINE_MEMORY_RESERVED;
+      }
+    i++;
+
+    scanline_events[i].pos = addr + size;
+    scanline_events[i].type = 1;
+    scanline_events[i].memtype = scanline_events[i - 1].memtype;
+    i++;
+
+    return 0;
+  }
+  
+  mmap_num = 0;
+
+#ifndef GRUB_MMAP_REGISTER_BY_FIRMWARE   
+  for (cur = grub_mmap_overlays; cur; cur = cur->next)
+    mmap_num++;
+#endif
+
+  grub_machine_mmap_iterate (count_hook);
+  
+  /* Initialize variables. */
+  grub_memset (present, 0, sizeof (present));
+  scanline_events = (struct grub_mmap_scan *) 
+    grub_malloc (sizeof (struct grub_mmap_scan) * 2 * mmap_num);
+  
+  if (! scanline_events)
+    {
+      return grub_error (GRUB_ERR_OUT_OF_MEMORY, 
+			 "couldn't allocate space for new memory map");
+    }
+
+  i = 0;
+#ifndef GRUB_MMAP_REGISTER_BY_FIRMWARE   
+  /* Register scanline events. */
+  for (cur = grub_mmap_overlays; cur; cur = cur->next)
+    {
+      scanline_events[i].pos = cur->start;
+      scanline_events[i].type = 0;
+      if (cur->type == GRUB_MACHINE_MEMORY_HOLE 
+	  || (cur->type >= 0 && cur->type <= GRUB_MACHINE_MEMORY_MAX_TYPE
+	      && priority[cur->type]))
+	scanline_events[i].memtype = cur->type;
+      else
+	scanline_events[i].memtype = GRUB_MACHINE_MEMORY_RESERVED;
+      i++;
+
+      scanline_events[i].pos = cur->end;
+      scanline_events[i].type = 1;
+      scanline_events[i].memtype = scanline_events[i - 1].memtype;
+      i++;
+    }
+#endif /* ! GRUB_MMAP_REGISTER_BY_FIRMWARE */
+
+  grub_machine_mmap_iterate (fill_hook);
+
+  /* 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
+	    || (scanline_events[i + 1].pos == scanline_events[i].pos
+		&& scanline_events[i + 1].type == 0 
+		&& scanline_events[i].type == 1))
+	  {
+	    t = scanline_events[i + 1];
+	    scanline_events[i + 1] = scanline_events[i];
+	    scanline_events[i] = t;
+	    done = 1;
+	  }
+    }
+
+  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_MACHINE_MEMORY_MAX_TYPE + 1; k++)
+	if (present[k] && (curtype == -1 || priority[k] > priority[curtype]))
+	  curtype = k;
+
+      /* Anounce region to the hook if necessary. */
+      if ((curtype == -1 || curtype != lasttype) 
+	  && lastaddr != scanline_events[i].pos
+	  && lasttype != -1
+	  && lasttype != GRUB_MACHINE_MEMORY_HOLE
+	  && hook (lastaddr, scanline_events[i].pos - lastaddr, lasttype))
+	{
+	  grub_free (scanline_events);
+	  return GRUB_ERR_NONE;
+	}
+
+      /* Update last values if necessary. */
+      if (curtype == -1 || curtype != lasttype) 
+	{
+	  lasttype = curtype;
+	  lastaddr = scanline_events[i].pos;
+	}
+    }
+
+  grub_free (scanline_events);
+  return GRUB_ERR_NONE;
+}
+
+#ifndef GRUB_MMAP_REGISTER_BY_FIRMWARE   
+int
+grub_mmap_register (grub_uint64_t start, grub_uint64_t size, int type)
+{
+  struct grub_mmap_region *cur;
+
+  grub_dprintf ("mmap", "registering\n");
+
+  cur = (struct grub_mmap_region *) 
+    grub_malloc (sizeof (struct grub_mmap_region));
+  if (! cur)
+    {
+      grub_error (GRUB_ERR_OUT_OF_MEMORY, 
+		  "couldn't allocate memory map overlay");
+      return 0;
+    }
+
+  cur->next = grub_mmap_overlays;
+  cur->start = start;
+  cur->end = start + size;
+  cur->type = type;
+  cur->handle = curhandle++;
+  grub_mmap_overlays = cur;
+
+  if (grub_machine_mmap_register (start, size, type, curhandle))
+    {
+      grub_mmap_overlays = cur->next;
+      grub_free (cur);
+      return 0;
+    }
+
+  return cur->handle;
+}
+
+grub_err_t
+grub_mmap_unregister (int handle)
+{
+  struct grub_mmap_region *cur, *prev;
+
+  for (cur = grub_mmap_overlays, prev = 0; cur; prev= cur, cur = cur->next)
+    if (handle == cur->handle)
+      {
+	grub_err_t err;
+	if ((err = grub_machine_mmap_unregister (handle)))
+	  return err;
+
+	if (prev)
+	  prev->next = cur->next;
+	else
+	  grub_mmap_overlays = cur->next;
+	grub_free (cur);
+	return GRUB_ERR_NONE;
+      }
+  return grub_error (GRUB_ERR_BAD_ARGUMENT, "mmap overlay not found");
+}
+
+#endif /* ! GRUB_MMAP_REGISTER_BY_FIRMWARE */
+
+#define CHUNK_SIZE	0x400
+
+static inline grub_uint64_t 
+fill_mask (grub_uint64_t addr, grub_uint64_t mask, grub_uint64_t iterator)
+{
+  int i, j;
+  grub_uint64_t ret = (addr & mask);
+
+  /* Find first fixed bit. */
+  for (i = 0; i < 64; i++)
+    if ((mask & (1ULL << i)) != 0)
+      break;
+  j = 0;
+  for (; i < 64; i++)
+    if ((mask & (1ULL << i)) == 0)
+      {
+	if ((iterator & (1ULL << j)) != 0)
+	  ret |= 1ULL << i;
+	j++;
+      }
+  return ret;
+}
+
+static grub_err_t
+grub_cmd_badram (grub_command_t cmd __attribute__ ((unused)),
+		 int argc, char **args)
+{
+  char * str;
+  grub_uint64_t badaddr, badmask;
+
+  auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t);
+  int NESTED_FUNC_ATTR hook (grub_uint64_t addr, 
+			     grub_uint64_t size, 
+			     grub_uint32_t type __attribute__ ((unused)))
+  {
+    grub_uint64_t iterator, low, high, cur;
+    int tail, var;
+    int i;
+    grub_dprintf ("badram", "hook %llx+%llx\n", (unsigned long long) addr, 
+		  (unsigned long long) size); 
+
+    /* How many trailing zeros? */
+    for (tail = 0; ! (badmask & (1ULL << tail)); tail++);
+
+    /* How many zeros in mask? */
+    var = 0;
+    for (i = 0; i < 64; i++)
+      if (! (badmask & (1ULL << i)))
+	var++;
+
+    if (fill_mask (badaddr, badmask, 0) >= addr)
+      iterator = 0;
+    else
+      {
+	low = 0;
+	high = ~0ULL;
+	/* Find starting value. Keep low and high such that 
+	   fill_mask (low) < addr and fill_mask (high) >= addr;
+	*/
+	while (high - low > 1)
+	  {
+	    cur = (low + high) / 2;
+	    if (fill_mask (badaddr, badmask, cur) >= addr)
+	      high = cur;
+	    else
+	      low = cur;
+	  }
+	iterator = high;
+      }
+
+    for (; iterator < (1ULL << (var - tail))
+	   && (cur = fill_mask (badaddr, badmask, iterator)) < addr + size; 
+	 iterator++)
+      {
+	grub_dprintf ("badram", "%llx (size %llx) is a badram range\n", 
+		      (long long) cur, (long long) (1ULL << tail) - 1); 
+	grub_mmap_register (cur, (1ULL << tail) - 1, GRUB_MACHINE_MEMORY_HOLE);
+      }
+    return 0;
+  }
+
+  if (argc != 1)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT, "badram string required");
+
+  grub_dprintf ("badram", "executing badram\n");
+
+  str = args[0];
+
+  while (1)
+    {
+      /* Parse address and mask.  */
+      badaddr = grub_strtoull (str, &str, 16);
+      if (*str == ',')
+	str++;
+      badmask = grub_strtoull (str, &str, 16);
+      if (*str == ',')
+	str++;
+
+      if (grub_errno == GRUB_ERR_BAD_NUMBER)
+	{
+	  grub_errno = 0;
+	  return GRUB_ERR_NONE;
+	}
+
+      /* When part of a page is tainted, we discard the whole of it.  There's
+	 no point in providing sub-page chunks.  */
+      badmask &= ~(CHUNK_SIZE - 1);
+
+      grub_dprintf ("badram", "badram %llx:%llx\n", 
+		    (unsigned long long) badaddr, (unsigned long long) badmask);
+
+      grub_mmap_iterate (hook);
+    }
+}
+
+static grub_command_t cmd;
+
+\f
+GRUB_MOD_INIT(mmap)
+{
+  (void) mod;			/* To stop warning. */
+  cmd = grub_register_command ("badram", grub_cmd_badram,
+			       "badram ADDR1,MASK1[,ADDR2,MASK2[,...]]", 
+			       "declare memory regions as badram");
+}
+
+GRUB_MOD_FINI(mmap)
+{
+  grub_unregister_command (cmd);
+}
+

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: mmap services
  2009-04-30 13:36   ` Vladimir 'phcoder' Serbinenko
@ 2009-04-30 13:46     ` David Miller
  0 siblings, 0 replies; 4+ messages in thread
From: David Miller @ 2009-04-30 13:46 UTC (permalink / raw)
  To: grub-devel, phcoder

From: "Vladimir 'phcoder' Serbinenko" <phcoder@gmail.com>
Date: Thu, 30 Apr 2009 15:36:36 +0200

> Rediffed and reposted due to request by David Miller

I've looked these over and I'm completely OK with these
changes as long as at least basic testing occurs for
the BIOS, ACPI, and EFI cases that are effected by this
change.



^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2009-04-30 13:46 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-04-11 21:01 mmap services phcoder
2009-04-26 14:42 ` Vladimir 'phcoder' Serbinenko
2009-04-30 13:36   ` Vladimir 'phcoder' Serbinenko
2009-04-30 13:46     ` David Miller

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.