grub-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: multiboot on EFI


From: phcoder
Subject: Re: multiboot on EFI
Date: Sat, 04 Apr 2009 18:51:04 +0200
User-agent: Thunderbird 2.0.0.21 (X11/20090318)

File was empty. Sorry
phcoder wrote:
For those interested in testing: here is a rediff and some updates. Soon I'll split it into components
phcoder wrote:
Robert Millan wrote:
Would it be hard to split the patch and make it more granular?  I see it
implements base mmap / lsmmap support on efi, then ports the *BSD loaders
and the Multiboot loader too, and the uppermem facility.
The only reason why it's not splitted is that it's totally "preview". When it'll be more ready I'll split it
If everybody's fine with it, I'd like to suggest adding stuff to pkglib_MODULES in the same place as its corresponding variables. I've done this already a few times, and I think it makes the build system a bit more maintainable. What do
you all think about this?

I also agree with this but I temporarily kept this in architecture-specific file because of some minor problems with multiboot2. I'll fix this too


diff --git a/include/grub/i386/pc/memory.h b/include/grub/i386/pc/memory.h
index 08e92a9..e69ff77 100644
--- a/include/grub/i386/pc/memory.h
+++ b/include/grub/i386/pc/memory.h
@@ -92,6 +92,8 @@ 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
   grub_uint32_t type;
 } __attribute__((packed));

Do we need specific knowledge of these two on i386-pc ?

This one is because some loaders just copy e820 map types and I don't want to modify what OS gets on i386-pc
 /* The minimum and maximum heap size for GRUB itself.  */
 #define MIN_HEAP_SIZE    0x100000
-#define MAX_HEAP_SIZE    (16 * 0x100000)
+#define MAX_HEAP_SIZE    (1600 * 0x100000)

Is 1600 MB what we want, or to remove the limit?

I would suggest to remove the limit altogether
+  /* Bubble-sort the memory map */
+  while (done)
+    {
+      done = 0;
+      for (i = 0; i < count - 1; i++)
+    if (regions[i].start > regions[i + 1].start)
+      {
+        done = 1;
+        t = regions[i];
+        regions[i] = regions[i + 1];
+        regions[i + 1] = t;
+      }
+    }

Do we need the memory map to be sorted? AFAIK loadees can cope with unsorted
maps fine;  is there an exception?

I prefer to sort. Even as just a precaution. Actually even sorted EFI map may break a lot of OS because it usually has more entries (the runtime code isn't guaranteed to be contiguous and if it isn't it results in mmap having a lot of entries) and sometimes the first N kilobytes are defined as unusable (it's the case with qemu-tianocore) which under current definition means that low_memory=0
+#ifdef GRUB_MACHINE_PCBIOS
+  grub_stop_floppy ();
+#endif

grub_stop_floppy() doesn't do any BIOS-specific stuff. Wouldn't __i386__
be more appropiate?

I've already moved it to machine_fini just because my computer died I couldn't send the new patch





--

Regards
Vladimir 'phcoder' Serbinenko
diff --git a/conf/common.rmk b/conf/common.rmk
index 43bc683..b812d8b 100644
--- a/conf/common.rmk
+++ b/conf/common.rmk
@@ -503,3 +503,10 @@ gzio_mod_LDFLAGS = $(COMMON_LDFLAGS)
 bufio_mod_SOURCES = io/bufio.c
 bufio_mod_CFLAGS = $(COMMON_CFLAGS)
 bufio_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
+pkglib_MODULES += lsmmap.mod
+
+# For lsmmap.mod
+lsmmap_mod_SOURCES = commands/lsmmap.c
+lsmmap_mod_CFLAGS = $(COMMON_CFLAGS)
+lsmmap_mod_LDFLAGS = $(COMMON_LDFLAGS)
diff --git a/conf/i386-coreboot.rmk b/conf/i386-coreboot.rmk
index 53595de..ab4dc4f 100644
--- a/conf/i386-coreboot.rmk
+++ b/conf/i386-coreboot.rmk
@@ -99,8 +99,7 @@ grub_install_SOURCES = util/i386/pc/grub-install.in
 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
+       halt.mod datetime.mod date.mod datehook.mod     
 
 # For linux.mod.
 linux_mod_SOURCES = loader/i386/linux.c
@@ -198,10 +197,5 @@ datehook_mod_SOURCES = hook/datehook.c
 datehook_mod_CFLAGS = $(COMMON_CFLAGS)
 datehook_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
-# For lsmmap.mod
-lsmmap_mod_SOURCES = commands/lsmmap.c
-lsmmap_mod_CFLAGS = $(COMMON_CFLAGS)
-lsmmap_mod_LDFLAGS = $(COMMON_LDFLAGS)
-
 include $(srcdir)/conf/i386.mk
 include $(srcdir)/conf/common.mk
diff --git a/conf/i386-efi.rmk b/conf/i386-efi.rmk
index 18a99df..6de450e 100644
--- a/conf/i386-efi.rmk
+++ b/conf/i386-efi.rmk
@@ -79,7 +79,18 @@ 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
+       datetime.mod date.mod datehook.mod multiboot.mod
+
+# For multiboot.mod.
+multiboot_mod_SOURCES = loader/i386/multiboot.c \
+                        loader/i386/multiboot_helper.S \
+                         loader/multiboot2.c \
+                         loader/efi/multiboot2.c \
+                         loader/multiboot_loader.c
+multiboot_mod_CFLAGS = $(COMMON_CFLAGS)
+multiboot_mod_LDFLAGS = $(COMMON_LDFLAGS)
+multiboot_mod_ASFLAGS = $(COMMON_ASFLAGS)
+
 
 # For kernel.mod.
 kernel_mod_EXPORTS = no
@@ -89,14 +100,14 @@ kernel_mod_SOURCES = kern/i386/efi/startup.S kern/main.c 
kern/device.c \
        kern/i386/dl.c kern/i386/efi/init.c kern/parser.c kern/partition.c \
        kern/env.c symlist.c kern/efi/efi.c kern/efi/init.c kern/efi/mm.c \
        term/efi/console.c disk/efi/efidisk.c \
-       kern/time.c kern/list.c kern/handler.c kern/command.c kern/corecmd.c \
+       kern/efi/mmap.c kern/time.c kern/list.c kern/handler.c kern/command.c 
kern/corecmd.c \
        kern/i386/tsc.c kern/i386/pit.c \
        kern/generic/rtc_get_time_ms.c \
        kern/generic/millisleep.c
 kernel_mod_HEADERS = boot.h cache.h device.h disk.h dl.h elf.h elfload.h \
        env.h err.h file.h fs.h kernel.h loader.h misc.h mm.h net.h parser.h \
        partition.h pc_partition.h rescue.h symbol.h term.h time.h types.h \
-       efi/efi.h efi/time.h efi/disk.h list.h handler.h command.h
+       efi/efi.h efi/time.h efi/disk.h efi/memory.h list.h handler.h command.h
 kernel_mod_CFLAGS = $(COMMON_CFLAGS)
 kernel_mod_ASFLAGS = $(COMMON_ASFLAGS)
 kernel_mod_LDFLAGS = $(COMMON_LDFLAGS)
diff --git a/conf/i386-ieee1275.rmk b/conf/i386-ieee1275.rmk
index a84b5aa..a06f97d 100644
--- a/conf/i386-ieee1275.rmk
+++ b/conf/i386-ieee1275.rmk
@@ -102,7 +102,7 @@ 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
 
 #
 # Only arch dependant part of normal.mod will be here. Common part for
@@ -127,6 +127,7 @@ normal_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
 # For multiboot.mod.
 multiboot_mod_SOURCES = loader/ieee1275/multiboot2.c \
+                       loader/i386/multiboot.c \
                        loader/i386/multiboot_helper.S \
                         loader/multiboot2.c \
                         loader/multiboot_loader.c
@@ -199,10 +200,5 @@ datehook_mod_SOURCES = hook/datehook.c
 datehook_mod_CFLAGS = $(COMMON_CFLAGS)
 datehook_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
-# For lsmmap.mod
-lsmmap_mod_SOURCES = commands/lsmmap.c
-lsmmap_mod_CFLAGS = $(COMMON_CFLAGS)
-lsmmap_mod_LDFLAGS = $(COMMON_LDFLAGS)
-
 include $(srcdir)/conf/i386.mk
 include $(srcdir)/conf/common.mk
diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk
index 7fa1975..405048f 100644
--- a/conf/i386-pc.rmk
+++ b/conf/i386-pc.rmk
@@ -287,16 +287,6 @@ lspci_mod_SOURCES = commands/lspci.c
 lspci_mod_CFLAGS = $(COMMON_CFLAGS)
 lspci_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
-# For aout.mod
-aout_mod_SOURCES = loader/aout.c
-aout_mod_CFLAGS = $(COMMON_CFLAGS)
-aout_mod_LDFLAGS = $(COMMON_LDFLAGS)
-
-# For bsd.mod
-bsd_mod_SOURCES = loader/i386/bsd.c
-bsd_mod_CFLAGS = $(COMMON_CFLAGS)
-bsd_mod_LDFLAGS = $(COMMON_LDFLAGS)
-
 # For usb.mod
 usb_mod_SOURCES = bus/usb/usb.c bus/usb/usbtrans.c bus/usb/usbhub.c
 usb_mod_CFLAGS = $(COMMON_CFLAGS)
@@ -352,11 +342,6 @@ datehook_mod_SOURCES = hook/datehook.c
 datehook_mod_CFLAGS = $(COMMON_CFLAGS)
 datehook_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
-# For lsmmap.mod
-lsmmap_mod_SOURCES = commands/lsmmap.c
-lsmmap_mod_CFLAGS = $(COMMON_CFLAGS)
-lsmmap_mod_LDFLAGS = $(COMMON_LDFLAGS)
-
 # For ata_pthru.mod.
 ata_pthru_mod_SOURCES = disk/ata_pthru.c
 ata_pthru_mod_CFLAGS = $(COMMON_CFLAGS)
diff --git a/conf/i386.rmk b/conf/i386.rmk
index 93f84ce..ddf7118 100644
--- a/conf/i386.rmk
+++ b/conf/i386.rmk
@@ -14,3 +14,21 @@ pkglib_MODULES += vga_text.mod
 vga_text_mod_SOURCES = term/i386/pc/vga_text.c term/i386/vga_common.c
 vga_text_mod_CFLAGS = $(COMMON_CFLAGS)
 vga_text_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
+pkglib_MODULES += uppermem.mod
+uppermem_mod_SOURCES = lib/i386/uppermem.c
+uppermem_mod_CFLAGS = $(COMMON_CFLAGS)
+uppermem_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
+pkglib_MODULES += aout.mod bsd.mod 
+# For aout.mod
+aout_mod_SOURCES = loader/aout.c
+aout_mod_CFLAGS = $(COMMON_CFLAGS)
+aout_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
+# For bsd.mod
+bsd_mod_SOURCES = loader/i386/bsd.c loader/i386/bsd_helper.S
+bsd_mod_CFLAGS = $(COMMON_CFLAGS) -Werror
+bsd_mod_LDFLAGS = $(COMMON_LDFLAGS)
+bsd_mod_ASFLAGS = $(COMMON_ASFLAGS)
+
diff --git a/conf/powerpc-ieee1275.rmk b/conf/powerpc-ieee1275.rmk
index 9ba2981..bcb2e76 100644
--- a/conf/powerpc-ieee1275.rmk
+++ b/conf/powerpc-ieee1275.rmk
@@ -110,8 +110,7 @@ pkglib_MODULES = halt.mod \
        reboot.mod \
        suspend.mod \
         multiboot.mod \
-       memdisk.mod \
-       lsmmap.mod
+       memdisk.mod 
 
 # For linux.mod.
 linux_mod_SOURCES = loader/powerpc/ieee1275/linux.c
@@ -166,10 +165,5 @@ memdisk_mod_SOURCES = disk/memdisk.c
 memdisk_mod_CFLAGS = $(COMMON_CFLAGS)
 memdisk_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
-# For lsmmap.mod
-lsmmap_mod_SOURCES = commands/lsmmap.c
-lsmmap_mod_CFLAGS = $(COMMON_CFLAGS)
-lsmmap_mod_LDFLAGS = $(COMMON_LDFLAGS)
-
 include $(srcdir)/conf/common.mk
 
diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h
index 8c277c0..137a437 100644
--- a/include/grub/efi/efi.h
+++ b/include/grub/efi/efi.h
@@ -54,6 +54,8 @@ char *EXPORT_FUNC(grub_efi_get_filename) 
(grub_efi_device_path_t *dp);
 grub_efi_device_path_t *
 EXPORT_FUNC(grub_efi_get_device_path) (grub_efi_handle_t handle);
 int EXPORT_FUNC(grub_efi_exit_boot_services) (grub_efi_uintn_t map_key);
+int EXPORT_FUNC(grub_efi_finish_boot_services) (void);
+
 void EXPORT_FUNC (grub_reboot) (void);
 void EXPORT_FUNC (grub_halt) (void);
 
diff --git a/include/grub/efi/memory.h b/include/grub/efi/memory.h
new file mode 100644
index 0000000..9000642
--- /dev/null
+++ b/include/grub/efi/memory.h
@@ -0,0 +1,15 @@
+#ifndef GRUB_MEMORY_MACHINE_HEADER
+#define GRUB_MEMORY_MACHINE_HEADER     1
+
+#include <grub/err.h>
+#include <grub/types.h>
+
+#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
+
+grub_err_t EXPORT_FUNC(grub_machine_mmap_iterate) 
+(int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, grub_uint64_t, grub_uint32_t));
+#endif /* ! GRUB_MEMORY_MACHINE_HEADER */
diff --git a/include/grub/i386/bsd.h b/include/grub/i386/bsd.h
index f50f18e..723dff5 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;
 };
 
@@ -222,4 +224,7 @@ struct grub_netbsd_btinfo_bootdisk
   int partition;
 };
 
+void grub_unix_real_boot (grub_addr_t entry, ...)
+  __attribute__ ((cdecl,noreturn));
+
 #endif /* ! GRUB_BSD_CPU_HEADER */
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/loader.h b/include/grub/i386/loader.h
index afd3eb9..685c2e0 100644
--- a/include/grub/i386/loader.h
+++ b/include/grub/i386/loader.h
@@ -27,12 +27,14 @@ extern grub_uint32_t EXPORT_VAR(grub_linux_prot_size);
 extern char *EXPORT_VAR(grub_linux_tmp_addr);
 extern char *EXPORT_VAR(grub_linux_real_addr);
 extern grub_int32_t EXPORT_VAR(grub_linux_is_bzimage);
-extern grub_addr_t EXPORT_VAR(grub_os_area_addr);
-extern grub_size_t EXPORT_VAR(grub_os_area_size);
 
 grub_err_t EXPORT_FUNC(grub_linux16_boot) (void);
 
-void EXPORT_FUNC(grub_unix_real_boot) (grub_addr_t entry, ...)
-     __attribute__ ((cdecl,noreturn));
+/* It is necessary to export these functions, because normal mode commands
+   reuse rescue mode commands.  */
+void grub_rescue_cmd_linux (int argc, char *argv[]);
+void grub_rescue_cmd_initrd (int argc, char *argv[]);
+
+void EXPORT_FUNC(grub_stop_floppy) (void);
 
 #endif /* ! GRUB_LOADER_CPU_HEADER */
diff --git a/include/grub/i386/multiboot.h b/include/grub/i386/multiboot.h
index 2dd7ec0..a6da360 100644
--- a/include/grub/i386/multiboot.h
+++ b/include/grub/i386/multiboot.h
@@ -22,10 +22,10 @@
 /* The asm part of the multiboot loader.  */
 void grub_multiboot_real_boot (grub_addr_t entry,
                               struct grub_multiboot_info *mbi)
-     __attribute__ ((noreturn));
+  __attribute__ ((noreturn,regparm (3)));
 void grub_multiboot2_real_boot (grub_addr_t entry,
                                struct grub_multiboot_info *mbi)
-     __attribute__ ((noreturn));
+     __attribute__ ((noreturn,regparm (3)));
 
 extern grub_addr_t grub_multiboot_payload_orig;
 extern grub_addr_t grub_multiboot_payload_dest;
diff --git a/include/grub/i386/pc/memory.h b/include/grub/i386/pc/memory.h
index 08e92a9..e69ff77 100644
--- a/include/grub/i386/pc/memory.h
+++ b/include/grub/i386/pc/memory.h
@@ -92,6 +92,8 @@ 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
   grub_uint32_t type;
 } __attribute__((packed));
 
diff --git a/include/grub/i386/uppermem.h b/include/grub/i386/uppermem.h
new file mode 100644
index 0000000..bceed3e
--- /dev/null
+++ b/include/grub/i386/uppermem.h
@@ -0,0 +1,7 @@
+#ifndef GRUB_UPPERMEM_HEADER
+#define GRUB_UPPERMEM_HEADER
+
+grub_err_t
+grub_get_lower_upper_memory (grub_uint64_t *lower, grub_uint64_t *upper);
+
+#endif
diff --git a/include/grub/ieee1275/ieee1275.h b/include/grub/ieee1275/ieee1275.h
index 628d888..448fed5 100644
--- a/include/grub/ieee1275/ieee1275.h
+++ b/include/grub/ieee1275/ieee1275.h
@@ -169,7 +169,6 @@ grub_err_t EXPORT_FUNC(grub_children_iterate) (char 
*devpath,
      int (*hook) (struct grub_ieee1275_devalias *alias));
 grub_err_t EXPORT_FUNC(grub_machine_mmap_iterate)
      (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, grub_uint64_t, 
grub_uint32_t));
-int EXPORT_FUNC(grub_claimmap) (grub_addr_t addr, grub_size_t size);
 
 char *EXPORT_FUNC(grub_ieee1275_encode_devname) (const char *path);
 char *EXPORT_FUNC(grub_ieee1275_get_filename) (const char *path);
diff --git a/include/grub/loader.h b/include/grub/loader.h
index 1ae5fdd..544b2f5 100644
--- a/include/grub/loader.h
+++ b/include/grub/loader.h
@@ -41,4 +41,8 @@ void EXPORT_FUNC(grub_loader_unset) (void);
    depending on the setting by grub_loader_set.  */
 grub_err_t EXPORT_FUNC(grub_loader_boot) (void);
 
+int EXPORT_FUNC(grub_claimmap) (grub_addr_t addr, grub_size_t size);
+
+void EXPORT_FUNC(grub_declaimmap) (grub_addr_t addr, grub_size_t size);
+
 #endif /* ! GRUB_LOADER_HEADER */
diff --git a/include/grub/multiboot2.h b/include/grub/multiboot2.h
index bfbffcc..1e6701e 100644
--- a/include/grub/multiboot2.h
+++ b/include/grub/multiboot2.h
@@ -39,12 +39,6 @@ void
 grub_mb2_arch_unload (struct multiboot_tag_header *tags);
 
 grub_err_t
-grub_mb2_arch_elf32_hook (Elf32_Phdr *phdr, grub_addr_t *addr);
-
-grub_err_t 
-grub_mb2_arch_elf64_hook (Elf64_Phdr *phdr, grub_addr_t *addr);
-
-grub_err_t
 grub_mb2_arch_module_alloc (grub_size_t size, grub_addr_t *addr);
 
 grub_err_t
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/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/efi/efi.c b/kern/efi/efi.c
index 9c9a400..754f82c 100644
--- a/kern/efi/efi.c
+++ b/kern/efi/efi.c
@@ -187,6 +187,28 @@ grub_efi_exit_boot_services (grub_efi_uintn_t map_key)
   return status == GRUB_EFI_SUCCESS;
 }
 
+int
+grub_efi_finish_boot_services (void)
+{
+  grub_efi_uintn_t mmap_size = 0;
+  grub_efi_uintn_t map_key;
+  grub_efi_uintn_t desc_size;
+  grub_efi_uint32_t desc_version;
+  void *mmap_buf;
+
+  if (grub_efi_get_memory_map (&mmap_size, mmap_buf, &map_key,
+                              &desc_size, &desc_version) < 0)
+    return 0;
+
+  mmap_buf = grub_malloc (mmap_size);
+  
+  if (grub_efi_get_memory_map (&mmap_size, mmap_buf, &map_key,
+                              &desc_size, &desc_version) <= 0)
+    return 0;
+
+  return  grub_efi_exit_boot_services (map_key);
+}
+
 grub_uint32_t
 grub_get_rtc (void)
 {
diff --git a/kern/efi/mm.c b/kern/efi/mm.c
index 35b12ab..4635776 100644
--- a/kern/efi/mm.c
+++ b/kern/efi/mm.c
@@ -47,7 +47,7 @@ static struct allocated_page *allocated_pages = 0;
 
 /* The minimum and maximum heap size for GRUB itself.  */
 #define MIN_HEAP_SIZE  0x100000
-#define MAX_HEAP_SIZE  (16 * 0x100000)
+#define MAX_HEAP_SIZE  (1600 * 0x100000)
 
 
 /* Allocate pages. Return the pointer to the first of allocated pages.  */
diff --git a/kern/efi/mmap.c b/kern/efi/mmap.c
new file mode 100644
index 0000000..3f795cb
--- /dev/null
+++ b/kern/efi/mmap.c
@@ -0,0 +1,177 @@
+/*
+ *  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/err.h>
+#include <grub/efi/api.h>
+#include <grub/efi/efi.h>
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/loader.h>
+
+#define NEXT_MEMORY_DESCRIPTOR(desc, size)      \
+  ((grub_efi_memory_descriptor_t *) ((char *) (desc) + (size)))
+
+struct region
+{
+  grub_uint64_t start;
+  grub_uint64_t len;
+  grub_uint32_t type;
+};
+
+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_uint64_t curstart, curend;
+  grub_uint32_t curtype;
+  grub_efi_memory_descriptor_t *desc;
+  struct region *regions;
+  struct region t;
+  int i, count, done = 1;
+
+  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;
+    }
+
+  count = mmap_size / desc_size;
+  if (! count)
+    {
+      grub_free (map_buf);
+      return grub_error (GRUB_ERR_IO, "couldn't get EFI memory map");
+    }
+  regions = (struct region *) grub_malloc (count * sizeof (struct region));
+
+  for (desc = map_buf, i = 0;
+       desc < NEXT_MEMORY_DESCRIPTOR (map_buf, mmap_size);
+       desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size), i++)
+    {
+      grub_dprintf ("efi_mmap", "EFI memory region 0x%llx-0x%llx: %d\n",
+                   desc->physical_start, desc->physical_start
+                   + desc->num_pages * 4096, desc->type);
+      switch (desc->type)
+       {
+       case GRUB_EFI_RUNTIME_SERVICES_CODE:
+         regions[i].start = desc->physical_start;
+         regions[i].len = desc->num_pages * 4096;
+         regions[i].type = GRUB_MACHINE_MEMORY_CODE;
+         break;
+
+       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:
+       case GRUB_EFI_MAX_MEMORY_TYPE:
+         regions[i].start = desc->physical_start;
+         regions[i].len = desc->num_pages * 4096;
+         regions[i].type = 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:
+         regions[i].start = desc->physical_start;
+         regions[i].len = desc->num_pages * 4096;
+         regions[i].type = GRUB_MACHINE_MEMORY_AVAILABLE;
+         break;
+
+       case GRUB_EFI_ACPI_RECLAIM_MEMORY:
+         regions[i].start = desc->physical_start;
+         regions[i].len = desc->num_pages * 4096;
+         regions[i].type = GRUB_MACHINE_MEMORY_ACPI;
+         break;
+
+       case GRUB_EFI_ACPI_MEMORY_NVS:
+         regions[i].start = desc->physical_start;
+         regions[i].len = desc->num_pages * 4096;
+         regions[i].type = GRUB_MACHINE_MEMORY_NVS;
+         break;
+       }
+    }
+
+  /* Bubble-sort the memory map */
+  while (done)
+    {
+      done = 0;
+      for (i = 0; i < count - 1; i++)
+       if (regions[i].start > regions[i + 1].start)
+         {
+           done = 1;
+           t = regions[i];
+           regions[i] = regions[i + 1];
+           regions[i + 1] = t;
+         }
+    }
+  
+  curstart = regions[0].start;
+  curend = regions[0].start + regions[0].len;
+  curtype = regions[0].type;
+  for (i = 1; i < count; i++)
+    {
+      if (curend != regions[i].start || curtype != regions[i].type)
+       {
+         hook (curstart, curend - curstart, curtype);
+         curstart = regions[i].start;
+         curtype = regions[i].type;      
+       }
+      curend = regions[i].start + regions[i].len;      
+    }
+
+  hook (curstart, curend - curstart, curtype);  
+
+  return GRUB_ERR_NONE;
+}
+
+/* XXX: Manage subpage allocations */
+int
+grub_claimmap (grub_addr_t addr, grub_size_t size)
+{
+  void *ret;
+  ret = grub_efi_allocate_pages (addr  & (~0xfff), 
+                                (size + (addr & 0xfff) + 0xfff) >> 12);
+  return (! ret) ? -1 : 0;
+}
+
+/* XXX: Manage subpage allocations */
+void
+grub_declaimmap (grub_addr_t addr, grub_size_t size)
+{
+  grub_efi_free_pages (addr  & (~0xfff), 
+                      (size + (addr & 0xfff) + 0xfff) >> 12);
+}
diff --git a/kern/i386/coreboot/init.c b/kern/i386/coreboot/init.c
index 1348488..9c1aee0 100644
--- a/kern/i386/coreboot/init.c
+++ b/kern/i386/coreboot/init.c
@@ -155,3 +155,18 @@ grub_arch_modules_addr (void)
 {
   return ALIGN_UP((grub_addr_t) _end, GRUB_MOD_ALIGN);
 }
+
+int
+grub_claimmap (grub_addr_t addr, grub_size_t size)
+{
+  if ((addr < grub_os_area_addr)
+      || (addr + size > grub_os_area_addr + grub_os_area_size))
+    return -1;
+  return 0;
+}
+
+void
+grub_declaimmap (grub_addr_t addr __attribute__ ((unused)), 
+                grub_size_t size  __attribute__ ((unused)))
+{
+}
diff --git a/kern/i386/loader.S b/kern/i386/loader.S
index bbd2187..d9b37bf 100644
--- a/kern/i386/loader.S
+++ b/kern/i386/loader.S
@@ -117,26 +117,3 @@ bzimage:
 linux_setup_seg:
        .word   0
        .code32
-
-/*
- * Use cdecl calling convention for *BSD kernels.
- */
-
-FUNCTION(grub_unix_real_boot)
-
-        call    EXT_C(grub_dl_unload_all)
-
-       /* Interrupts should be disabled.  */
-        cli
-
-       /* Discard `grub_unix_real_boot' return address.  */
-        popl    %eax
-
-        /* Fetch `entry' address ...  */
-        popl   %eax
-
-        /*
-         * ... and put our return address in its place. The kernel will
-         * ignore it, but it expects %esp to point to it.
-         */
-        call   *%eax
diff --git a/kern/i386/pc/init.c b/kern/i386/pc/init.c
index 6191412..17d5343 100644
--- a/kern/i386/pc/init.c
+++ b/kern/i386/pc/init.c
@@ -43,8 +43,8 @@ struct mem_region
 static struct mem_region mem_regions[MAX_REGIONS];
 static int num_regions;
 
-grub_addr_t grub_os_area_addr;
-grub_size_t grub_os_area_size;
+static grub_addr_t grub_os_area_addr;
+static grub_size_t grub_os_area_size;
 grub_size_t grub_lower_mem, grub_upper_mem;
 
 void 
@@ -233,3 +233,18 @@ grub_arch_modules_addr (void)
   return GRUB_MEMORY_MACHINE_DECOMPRESSION_ADDR
     + (grub_kernel_image_size - GRUB_KERNEL_MACHINE_RAW_SIZE);
 }
+
+int
+grub_claimmap (grub_addr_t addr, grub_size_t size)
+{
+  if ((addr < grub_os_area_addr)
+      || (addr + size > grub_os_area_addr + grub_os_area_size))
+    return -1;
+  return 0;
+}
+
+void
+grub_declaimmap (grub_addr_t addr __attribute__ ((unused)), 
+                grub_size_t size  __attribute__ ((unused)))
+{
+}
diff --git a/kern/ieee1275/openfw.c b/kern/ieee1275/openfw.c
index e88f3b3..27f8293 100644
--- a/kern/ieee1275/openfw.c
+++ b/kern/ieee1275/openfw.c
@@ -194,6 +194,13 @@ grub_claimmap (grub_addr_t addr, grub_size_t size)
   return 0;
 }
 
+/* XXX Could someone with better OFW knowledge that me fill this? */
+void
+grub_declaimmap (grub_addr_t addr __attribute__ ((unused)), 
+                grub_size_t size  __attribute__ ((unused)))
+{
+}
+
 /* Get the device arguments of the Open Firmware node name `path'.  */
 static char *
 grub_ieee1275_get_devargs (const char *path)
diff --git a/lib/i386/uppermem.c b/lib/i386/uppermem.c
new file mode 100644
index 0000000..623535f
--- /dev/null
+++ b/lib/i386/uppermem.c
@@ -0,0 +1,127 @@
+/* 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/>.
+ */
+
+#ifndef EFIEMU
+#include <grub/machine/memory.h>
+#include <grub/i386/uppermem.h>
+#endif
+
+#include <grub/mm.h>
+#include <grub/misc.h>
+
+struct region
+{
+  grub_uint64_t start;
+  grub_uint64_t end;
+};
+
+#ifdef EFIEMU
+grub_err_t
+grub_efiemu_get_lower_upper_memory (grub_uint64_t *lower, grub_uint64_t *upper)
+#else
+grub_err_t
+grub_get_lower_upper_memory (grub_uint64_t *lower, grub_uint64_t *upper)
+#endif
+{
+  grub_size_t count = 0;
+  struct region *regions = 0;
+  int done = 1;
+  unsigned i;
+  struct region t;
+  grub_uint64_t last_addr;
+
+  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)
+    {
+#ifdef EFIEMU  
+      if (type != GRUB_EFIEMU_MEMORY_AVAILABLE)
+#else
+      if (type != GRUB_MACHINE_MEMORY_AVAILABLE)
+#endif
+       return 0;
+      regions = (struct region *) 
+       grub_realloc (regions, (count + 1) * sizeof (struct region));
+      regions[count].start = addr;
+      regions[count].end = addr + size;
+      count++;
+      return 0;
+    }
+
+#ifdef EFIEMU  
+  grub_efiemu_mmap_iterate (hook);
+#else
+  grub_machine_mmap_iterate (hook);
+#endif
+
+  /* Bubble-sort the memory map */
+  while (done)
+    {
+      done = 0;
+      for (i = 0; i < count - 1; i++)
+       if (regions[i].start > regions[i + 1].start)
+         {
+           done = 1;
+           t = regions[i];
+           regions[i] = regions[i + 1];
+           regions[i + 1] = t;
+         }
+    }
+
+  /* Set mem_upper and mem_lower */
+  last_addr = 0;
+  for (i = 0; i < count; i++)
+    {
+      grub_uint64_t end = regions[i].end;
+      /* Don't use memory after 0xa0000*/
+      if (end > 0xa0000)
+       end = 0xa0000;
+
+      /* low memory is finished */
+      if (regions[i].start > end)
+       break;
+
+      /* A hole */
+      if (regions[i].start > last_addr)
+       break;
+
+      last_addr = end;
+    }
+
+  *lower = last_addr;
+
+  /* Skip low memory */
+  for (i = 0; i < count && regions[i].end <= 0x100000; 
+       i++);
+
+  last_addr = 0x100000;
+  for (; i < count; i++)
+    {
+      /* A hole */
+      if (regions[i].start > last_addr)
+       break;
+
+      last_addr = regions[i].end;
+    }
+
+  *upper = (last_addr - 0x100000);
+  grub_free (regions);
+
+  return GRUB_ERR_NONE;
+}
diff --git a/loader/efi/multiboot2.c b/loader/efi/multiboot2.c
new file mode 100644
index 0000000..44bb542
--- /dev/null
+++ b/loader/efi/multiboot2.c
@@ -0,0 +1,75 @@
+/* multiboot2.c - boot a multiboot 2 OS image. */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 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/>.
+ */
+
+#include <multiboot2.h>
+#include <grub/multiboot2.h>
+#include <grub/elf.h>
+#include <grub/err.h>
+#include <grub/machine/loader.h>
+#include <grub/mm.h>
+
+grub_err_t
+grub_mb2_arch_module_alloc (grub_size_t size, grub_addr_t *addr)
+{
+  grub_addr_t modaddr;
+
+  modaddr = (grub_addr_t) grub_memalign (MULTIBOOT2_MOD_ALIGN, size);
+  if (! modaddr)
+    return grub_errno;
+
+  *addr = modaddr;
+  return GRUB_ERR_NONE;
+}
+
+grub_err_t
+grub_mb2_arch_module_free (grub_addr_t addr, UNUSED grub_size_t size)
+{
+  grub_free((void *) addr);
+  return GRUB_ERR_NONE;
+}
+
+void
+grub_mb2_arch_boot (grub_addr_t entry, void *tags)
+{
+  grub_multiboot2_real_boot (entry, tags);
+}
+
+void
+grub_mb2_arch_unload (struct multiboot_tag_header *tags)
+{
+   struct multiboot_tag_header *tag;
+   
+   /* Free all module memory in the tag list.  */
+   for_each_tag (tag, tags)
+     {
+       if (tag->key == MULTIBOOT2_TAG_MODULE)
+         {
+           struct multiboot_tag_module *module =
+              (struct multiboot_tag_module *) tag;
+           grub_free((void *) module->addr);
+         }
+     }
+}
+
+grub_err_t
+grub_mb2_tags_arch_create (void)
+{
+  /* XXX Create system table et al. */
+  return GRUB_ERR_NONE;
+}
diff --git a/loader/i386/bsd.c b/loader/i386/bsd.c
index 355cb3f..4023566 100644
--- a/loader/i386/bsd.c
+++ b/loader/i386/bsd.c
@@ -19,8 +19,8 @@
 #include <grub/loader.h>
 #include <grub/cpu/loader.h>
 #include <grub/cpu/bsd.h>
-#include <grub/machine/init.h>
 #include <grub/machine/memory.h>
+#include <grub/machine/machine.h>
 #include <grub/file.h>
 #include <grub/err.h>
 #include <grub/dl.h>
@@ -30,8 +30,13 @@
 #include <grub/misc.h>
 #include <grub/gzio.h>
 #include <grub/aout.h>
+#include <grub/i386/uppermem.h>
 #include <grub/command.h>
 
+#ifdef GRUB_MACHINE_EFI
+#include <grub/efi/efi.h>
+#endif
+
 #define ALIGN_DWORD(a) ALIGN_UP (a, 4)
 #define ALIGN_PAGE(a)  ALIGN_UP (a, 4096)
 
@@ -302,6 +307,15 @@ grub_freebsd_boot (void)
 
   bi.bi_kernend = kern_end;
 
+#ifdef GRUB_MACHINE_PCBIOS
+  grub_stop_floppy ();
+#endif
+
+#ifdef GRUB_MACHINE_EFI
+  if (! grub_efi_finish_boot_services ())
+     grub_fatal ("cannot exit boot services");
+#endif
+
   grub_unix_real_boot (entry, bootflags | FREEBSD_RB_BOOTINFO, bootdev,
                       0, 0, 0, &bi, bi.bi_modulep, kern_end);
 
@@ -313,30 +327,39 @@ 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;
+  grub_uint64_t lower, upper;
+  grub_err_t err;
+
+  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_machine_mmap_iterate (hook);
 
   pa->ba_size = (char *) pm - (char *) pa;
   pa->ba_next = (struct grub_openbsd_bootargs *) pm;
@@ -348,8 +371,20 @@ grub_openbsd_boot (void)
   bootdev = (OPENBSD_B_DEVMAGIC + (unit << OPENBSD_B_UNITSHIFT) +
             (part << OPENBSD_B_PARTSHIFT));
 
+  if ((err = grub_get_lower_upper_memory (&lower, &upper)))
+    return err;
+
+#ifdef GRUB_MACHINE_PCBIOS
+  grub_stop_floppy ();
+#endif
+
+#ifdef GRUB_MACHINE_EFI
+  if (! grub_efi_finish_boot_services ())
+     grub_fatal ("cannot exit boot services");
+#endif
+
   grub_unix_real_boot (entry, bootflags, bootdev, OPENBSD_BOOTARG_APIVER,
-                      0, grub_upper_mem >> 10, grub_lower_mem >> 10,
+                      0, upper >> 10, lower >> 10,
                       (char *) pa - buf, buf);
 
   /* Not reached.  */
@@ -362,6 +397,8 @@ grub_netbsd_boot (void)
   struct grub_netbsd_btinfo_rootdevice *rootdev;
   struct grub_netbsd_bootinfo *bootinfo;
   grub_uint32_t biosdev, unit, slice, part;
+  grub_uint64_t lower, upper;
+  grub_err_t err;
 
   grub_bsd_get_device (&biosdev, &unit, &slice, &part);
 
@@ -376,8 +413,20 @@ grub_netbsd_boot (void)
   bootinfo->bi_count = 1;
   bootinfo->bi_data[0] = rootdev;
 
+  if ((err = grub_get_lower_upper_memory (&lower, &upper)))
+    return err;
+
+#ifdef GRUB_MACHINE_PCBIOS
+  grub_stop_floppy ();
+#endif
+
+#ifdef GRUB_MACHINE_EFI
+  if (! grub_efi_finish_boot_services ())
+     grub_fatal ("cannot exit boot services");
+#endif
+
   grub_unix_real_boot (entry, bootflags, 0, bootinfo,
-                      0, grub_upper_mem >> 10, grub_lower_mem >> 10);
+                      0, upper >> 10, lower >> 10);
 
   /* Not reached.  */
   return GRUB_ERR_NONE;
@@ -461,8 +510,7 @@ grub_bsd_elf32_hook (Elf32_Phdr * phdr, grub_addr_t * addr)
   phdr->p_paddr &= 0xFFFFFF;
   paddr = phdr->p_paddr;
 
-  if ((paddr < grub_os_area_addr)
-      || (paddr + phdr->p_memsz > grub_os_area_addr + grub_os_area_size))
+  if (grub_claimmap (paddr, phdr->p_memsz) < 0)
     return grub_error (GRUB_ERR_OUT_OF_RANGE, "Address 0x%x is out of range",
                       paddr);
 
@@ -578,7 +626,7 @@ grub_cmd_freebsd (grub_command_t cmd __attribute__ 
((unused)),
          (grub_freebsd_add_meta_module (1, argc, argv, kern_start,
                                         kern_end - kern_start)))
        return grub_errno;
-      grub_loader_set (grub_freebsd_boot, grub_bsd_unload, 1);
+      grub_loader_set (grub_freebsd_boot, grub_bsd_unload, 0);
     }
 
   return grub_errno;
@@ -593,7 +641,7 @@ grub_cmd_openbsd (grub_command_t cmd __attribute__ 
((unused)),
               grub_bsd_parse_flags (argv[1], openbsd_opts, openbsd_flags));
 
   if (grub_bsd_load (argc, argv) == GRUB_ERR_NONE)
-    grub_loader_set (grub_openbsd_boot, grub_bsd_unload, 1);
+    grub_loader_set (grub_openbsd_boot, grub_bsd_unload, 0);
 
   return grub_errno;
 }
@@ -607,7 +655,7 @@ grub_cmd_netbsd (grub_command_t cmd __attribute__ 
((unused)),
               grub_bsd_parse_flags (argv[1], netbsd_opts, netbsd_flags));
 
   if (grub_bsd_load (argc, argv) == GRUB_ERR_NONE)
-    grub_loader_set (grub_netbsd_boot, grub_bsd_unload, 1);
+    grub_loader_set (grub_netbsd_boot, grub_bsd_unload, 0);
 
   return grub_errno;
 }
@@ -725,7 +773,7 @@ grub_cmd_freebsd_module (grub_command_t cmd __attribute__ 
((unused)),
   if ((!file) || (!file->size))
     goto fail;
 
-  if (kern_end + file->size > grub_os_area_addr + grub_os_area_size)
+  if (grub_claimmap (kern_end, file->size) < 0)
     {
       grub_error (GRUB_ERR_OUT_OF_RANGE, "Not enough memory for the module");
       goto fail;
diff --git a/loader/i386/bsd_helper.S b/loader/i386/bsd_helper.S
new file mode 100644
index 0000000..9cdea0c
--- /dev/null
+++ b/loader/i386/bsd_helper.S
@@ -0,0 +1,65 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 1999,2000,2001,2002,2003,2005,2006,2007,2008,2009 Free 
Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+/*
+ * Note: These functions defined in this file may be called from C.
+ *       Be careful of that you must not modify some registers. Quote
+ *       from gcc-2.95.2/gcc/config/i386/i386.h:
+
+   1 for registers not available across function calls.
+   These must include the FIXED_REGISTERS and also any
+   registers that can be used without being saved.
+   The latter must include the registers where values are returned
+   and the register where structure-value addresses are passed.
+   Aside from that, you can include as many other registers as you like.
+
+  ax,dx,cx,bx,si,di,bp,sp,st,st1,st2,st3,st4,st5,st6,st7,arg
+{  1, 1, 1, 0, 0, 0, 0, 1, 1,  1,  1,  1,  1,  1,  1,  1,  1 }
+ */
+
+/*
+ * Note: GRUB is compiled with the options -mrtd and -mregparm=3.
+ *       So the first three arguments are passed in %eax, %edx, and %ecx,
+ *       respectively, and if a function has a fixed number of arguments
+ *       and the number if greater than three, the function must return
+ *       with "ret $N" where N is ((the number of arguments) - 3) * 4.
+ */
+
+#include <grub/symbol.h>
+  
+/*
+ * Use cdecl calling convention for *BSD kernels.
+ */
+
+FUNCTION(grub_unix_real_boot)
+
+       /* Interrupts should be disabled.  */
+        cli
+
+       /* Discard `grub_unix_real_boot' return address.  */
+        popl    %eax
+
+        /* Fetch `entry' address ...  */
+        popl   %eax
+
+        /*
+         * ... and put our return address in its place. The kernel will
+         * ignore it, but it expects %esp to point to it.
+         */
+        call   *%eax
diff --git a/loader/i386/efi/linux.c b/loader/i386/efi/linux.c
index d8c6a67..7cc13d3 100644
--- a/loader/i386/efi/linux.c
+++ b/loader/i386/efi/linux.c
@@ -18,6 +18,7 @@
 
 #include <grub/loader.h>
 #include <grub/machine/loader.h>
+#include <grub/machine/memory.h>
 #include <grub/file.h>
 #include <grub/disk.h>
 #include <grub/err.h>
@@ -45,9 +46,10 @@ static int loaded;
 static void *real_mode_mem;
 static void *prot_mode_mem;
 static void *initrd_mem;
-static grub_efi_uintn_t real_mode_pages;
-static grub_efi_uintn_t prot_mode_pages;
-static grub_efi_uintn_t initrd_pages;
+static grub_size_t real_size;
+static grub_size_t mmap_size;
+static grub_size_t prot_size;
+static grub_size_t initrd_size;
 static void *mmap_buf;
 
 static grub_uint8_t gdt[] __attribute__ ((aligned(16))) =
@@ -94,26 +96,26 @@ page_align (grub_size_t size)
 
 /* Find the optimal number of pages for the memory map. Is it better to
    move this code to efi/mm.c?  */
-static grub_efi_uintn_t
+static grub_size_t
 find_mmap_size (void)
 {
-  static grub_efi_uintn_t mmap_size = 0;
+  static grub_efi_uintn_t cache_mmap_size = 0;
 
-  if (mmap_size != 0)
-    return mmap_size;
+  if (cache_mmap_size != 0)
+    return cache_mmap_size;
   
-  mmap_size = (1 << 12);
+  cache_mmap_size = (1 << 12);
   while (1)
     {
       int ret;
       grub_efi_memory_descriptor_t *mmap;
       grub_efi_uintn_t desc_size;
       
-      mmap = grub_malloc (mmap_size);
+      mmap = grub_malloc (cache_mmap_size);
       if (! mmap)
        return 0;
 
-      ret = grub_efi_get_memory_map (&mmap_size, mmap, 0, &desc_size, 0);
+      ret = grub_efi_get_memory_map (&cache_mmap_size, mmap, 0, &desc_size, 0);
       grub_free (mmap);
       
       if (ret < 0)
@@ -121,14 +123,14 @@ find_mmap_size (void)
       else if (ret > 0)
        break;
 
-      mmap_size += (1 << 12);
+      cache_mmap_size += (1 << 12);
     }
 
   /* Increase the size a bit for safety, because GRUB allocates more on
      later, and EFI itself may allocate more.  */
-  mmap_size += (1 << 12);
+  cache_mmap_size += (1 << 12);
 
-  return page_align (mmap_size);
+  return page_align (cache_mmap_size);
 }
 
 static void
@@ -136,19 +138,19 @@ free_pages (void)
 {
   if (real_mode_mem)
     {
-      grub_efi_free_pages ((grub_addr_t) real_mode_mem, real_mode_pages);
+      grub_declaimmap ((grub_addr_t) real_mode_mem, real_size + mmap_size);
       real_mode_mem = 0;
     }
 
   if (prot_mode_mem)
     {
-      grub_efi_free_pages ((grub_addr_t) prot_mode_mem, prot_mode_pages);
+      grub_declaimmap ((grub_addr_t) prot_mode_mem, prot_size);
       prot_mode_mem = 0;
     }
   
   if (initrd_mem)
     {
-      grub_efi_free_pages ((grub_addr_t) initrd_mem, initrd_pages);
+      grub_declaimmap ((grub_addr_t) initrd_mem, initrd_size);
       initrd_mem = 0;
     }
 }
@@ -160,9 +162,8 @@ allocate_pages (grub_size_t prot_size)
 {
   grub_efi_uintn_t desc_size;
   grub_efi_memory_descriptor_t *mmap, *mmap_end;
-  grub_efi_uintn_t mmap_size, tmp_mmap_size;
+  grub_efi_uintn_t tmp_mmap_size;
   grub_efi_memory_descriptor_t *desc;
-  grub_size_t real_size;
   
   /* Make sure that each size is aligned to a page boundary.  */
   real_size = GRUB_LINUX_CL_END_OFFSET;
@@ -172,11 +173,6 @@ allocate_pages (grub_size_t prot_size)
   grub_dprintf ("linux", "real_size = %x, prot_size = %x, mmap_size = %x\n",
                (unsigned) real_size, (unsigned) prot_size, (unsigned) 
mmap_size);
   
-  /* Calculate the number of pages; Combine the real mode code with
-     the memory map buffer for simplicity.  */
-  real_mode_pages = ((real_size + mmap_size) >> 12);
-  prot_mode_pages = (prot_size >> 12);
-  
   /* Initialize the memory pointers with NULL for convenience.  */
   real_mode_mem = 0;
   prot_mode_mem = 0;
@@ -191,44 +187,40 @@ allocate_pages (grub_size_t prot_size)
     grub_fatal ("cannot get memory map");
 
   mmap_end = NEXT_MEMORY_DESCRIPTOR (mmap, tmp_mmap_size);
-  
-  /* First, find free pages for the real mode code
-     and the memory map buffer.  */
-  for (desc = mmap;
-       desc < mmap_end;
-       desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size))
+
+  /* FIXME: Should request low memory from the heap when this feature is
+     implemented.  */
+
+  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)
     {
-      /* Probably it is better to put the real mode code in the traditional
-        space for safety.  */
-      if (desc->type == GRUB_EFI_CONVENTIONAL_MEMORY
-         && desc->physical_start <= 0x90000
-         && desc->num_pages >= real_mode_pages)
+      /* We must put real mode code in the traditional space.  */
+
+      if (type == GRUB_MACHINE_MEMORY_AVAILABLE
+         && addr <= 0x90000)
        {
-         grub_efi_physical_address_t physical_end;
-         grub_efi_physical_address_t addr;
-         
-         physical_end = desc->physical_start + (desc->num_pages << 12);
-         if (physical_end > 0x90000)
-           physical_end = 0x90000;
-
-         grub_dprintf ("linux", "physical_start = %x, physical_end = %x\n",
-                       (unsigned) desc->physical_start,
-                       (unsigned) physical_end);
-         addr = physical_end - real_size - mmap_size;
          if (addr < 0x10000)
-           continue;
+           {
+             size += addr - 0x10000;
+             addr = 0x10000;
+           }
 
-         grub_dprintf ("linux", "trying to allocate %u pages at %lx\n",
-                       (unsigned) real_mode_pages, (unsigned long) addr);
-         real_mode_mem = grub_efi_allocate_pages (addr, real_mode_pages);
-         if (! real_mode_mem)
-           grub_fatal ("cannot allocate pages");
-         
-         desc->num_pages -= real_mode_pages;
-         break;
+         if (addr + size > 0x90000)
+           size = 0x90000 - addr;
+
+         if (real_size + mmap_size > size)
+           return 0;
+
+         real_mode_mem = (void *) ((addr + size) - (real_size + mmap_size));
+         if (grub_claimmap ((grub_addr_t) real_mode_mem, 
+                            real_size + mmap_size) < 0)
+           return 0;
+         return 1;
        }
-    }
 
+      return 0;
+    }
+  grub_machine_mmap_iterate (hook);
   if (! real_mode_mem)
     {
       grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate real mode pages");
@@ -237,20 +229,20 @@ allocate_pages (grub_size_t prot_size)
 
   mmap_buf = (void *) ((char *) real_mode_mem + real_size);
              
+  prot_mode_mem = (void *) 0x100000;
   /* Next, find free pages for the protected mode code.  */
   /* XXX what happens if anything is using this address?  */
-  prot_mode_mem = grub_efi_allocate_pages (0x100000, prot_mode_pages);
-  if (! prot_mode_mem)
+  if (grub_claimmap (0x100000, prot_size) < 0)
     {
       grub_error (GRUB_ERR_OUT_OF_MEMORY,
                  "cannot allocate protected mode pages");
       goto fail;
     }
 
-  grub_dprintf ("linux", "real_mode_mem = %lx, real_mode_pages = %x, "
-                "prot_mode_mem = %lx, prot_mode_pages = %x\n",
-                (unsigned long) real_mode_mem, (unsigned) real_mode_pages,
-                (unsigned long) prot_mode_mem, (unsigned) prot_mode_pages);
+  grub_dprintf ("linux", "real_mode_mem = %lx, real_size = %x, "
+                "prot_mode_mem = %lx, prot_size = %x\n",
+                (unsigned long) real_mode_mem, (unsigned) real_size,
+                (unsigned long) prot_mode_mem, (unsigned) prot_size);
 
   grub_free (mmap);
   return 1;
@@ -350,7 +342,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;
   
   fake_bios_data ();
@@ -370,77 +361,46 @@ grub_linux_boot (void)
                               &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)
+      switch (type)
         {
-        case GRUB_EFI_ACPI_RECLAIM_MEMORY:
-          grub_e820_add_region (params->e820_map, &e820_num,
-                                desc->physical_start,
-                                desc->num_pages << 12,
-                                GRUB_E820_ACPI);
-          break;
+        case GRUB_MACHINE_MEMORY_AVAILABLE:
+         grub_e820_add_region (params->e820_map, &e820_num,
+                               addr, size, GRUB_E820_RAM);
+         break;
 
-        case GRUB_EFI_ACPI_MEMORY_NVS:
-          grub_e820_add_region (params->e820_map, &e820_num,
-                                desc->physical_start,
-                                desc->num_pages << 12,
-                                GRUB_E820_NVS);
-          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
 
-        case GRUB_EFI_RUNTIME_SERVICES_CODE:
-          grub_e820_add_region (params->e820_map, &e820_num,
-                                desc->physical_start,
-                                desc->num_pages << 12,
-                                GRUB_E820_EXEC_CODE);
-          break;
-
-        case GRUB_EFI_LOADER_CODE:
-        case GRUB_EFI_LOADER_DATA:
-        case GRUB_EFI_BOOT_SERVICES_CODE:
-        case GRUB_EFI_BOOT_SERVICES_DATA:
-        case GRUB_EFI_CONVENTIONAL_MEMORY:
-          {
-            grub_uint64_t start, size, end;
-
-            start = desc->physical_start;
-            size = desc->num_pages << 12;
-            end = start + size;
-
-            /* Skip A0000 - 100000 region.  */
-            if ((start < 0x100000ULL) && (end > 0xA0000ULL))
-              {
-                if (start < 0xA0000ULL)
-                  {
-                    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;
-          }
+#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,
-                                desc->physical_start,
-                                desc->num_pages << 12,
-                                GRUB_E820_RESERVED);
+                                addr, size, GRUB_E820_RESERVED);
         }
+      return 0;
     }
 
+  e820_num = 0;
+  grub_machine_mmap_iterate (hook);
   params->mmap_size = e820_num;
 
   if (! grub_efi_exit_boot_services (map_key))
@@ -617,7 +577,6 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
   struct linux_kernel_header lh;
   struct linux_kernel_params *params;
   grub_uint8_t setup_sects;
-  grub_size_t real_size, prot_size;
   grub_ssize_t len;
   int i;
   char *dest;
@@ -908,9 +867,6 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ 
((unused)),
   grub_ssize_t size;
   grub_addr_t addr_min, addr_max;
   grub_addr_t addr;
-  grub_efi_uintn_t mmap_size;
-  grub_efi_memory_descriptor_t *desc;
-  grub_efi_uintn_t desc_size;
   struct linux_kernel_header *lh;
   
   if (argc == 0)
@@ -930,11 +886,24 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ 
((unused)),
     goto fail;
 
   size = grub_file_size (file);
-  initrd_pages = (page_align (size) >> 12);
+  initrd_size = page_align (size);
 
   lh = (struct linux_kernel_header *) real_mode_mem;
+
+  /* Get the highest address available for the initrd.  */
+  if (grub_le_to_cpu16 (lh->version) >= 0x0203)
+    {
+      addr_max = grub_cpu_to_le32 (lh->initrd_addr_max);
+
+      /* XXX in reality, Linux specifies a bogus value, so
+        it is necessary to make sure that ADDR_MAX does not exceed
+        0x3fffffff.  */
+      if (addr_max > GRUB_LINUX_INITRD_MAX_ADDRESS)
+       addr_max = GRUB_LINUX_INITRD_MAX_ADDRESS;
+    }
+  else
+    addr_max = GRUB_LINUX_INITRD_MAX_ADDRESS;
   
-  addr_max = (grub_cpu_to_le32 (lh->initrd_addr_max) << 10);
   if (linux_mem_size != 0 && linux_mem_size < addr_max)
     addr_max = linux_mem_size;
   
@@ -945,49 +914,21 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ 
((unused)),
   addr_max -= 0x10000;
 
   /* Usually, the compression ratio is about 50%.  */
-  addr_min = (grub_addr_t) prot_mode_mem + ((prot_mode_pages * 3) << 12)
+  addr_min = (grub_addr_t) prot_mode_mem + prot_size * 3
              + page_align (size);
   
-  /* Find the highest address to put the initrd.  */
-  mmap_size = find_mmap_size ();
-  if (grub_efi_get_memory_map (&mmap_size, mmap_buf, 0, &desc_size, 0) <= 0)
-    grub_fatal ("cannot get memory map");
-
-  addr = 0;
-  for (desc = mmap_buf;
-       desc < NEXT_MEMORY_DESCRIPTOR (mmap_buf, mmap_size);
-       desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size))
-    {
-      if (desc->type == GRUB_EFI_CONVENTIONAL_MEMORY
-         && desc->num_pages >= initrd_pages)
-       {
-         grub_efi_physical_address_t physical_end;
-         
-         physical_end = desc->physical_start + (desc->num_pages << 12);
-         if (physical_end > addr_max)
-           physical_end = addr_max;
-
-         if (physical_end < page_align (size))
-            continue;
-
-         physical_end -= page_align (size);
-
-         if ((physical_end >= addr_min) &&
-             (physical_end >= desc->physical_start) &&
-             (physical_end > addr))
-           addr = physical_end;
-       }
-    }
+  /* Put the initrd as high as possible, 4KiB aligned.  */
+  addr = (addr_max - size) & ~0xFFF;
+  while (addr >= addr_min && grub_claimmap (addr, initrd_size) < 0)
+    addr -= 0x1000;
 
-  if (addr == 0)
+  if (addr < addr_min)
     {
-      grub_error (GRUB_ERR_OUT_OF_MEMORY, "no free pages available");
+      grub_error (GRUB_ERR_OUT_OF_RANGE, "The initrd is too big");
       goto fail;
     }
   
-  initrd_mem = grub_efi_allocate_pages (addr, initrd_pages);
-  if (! initrd_mem)
-    grub_fatal ("cannot allocate pages");
+  initrd_mem = (void *) addr;
   
   if (grub_file_read (file, initrd_mem, size) != size)
     {
diff --git a/loader/i386/linux.c b/loader/i386/linux.c
index a2fff83..daff376 100644
--- a/loader/i386/linux.c
+++ b/loader/i386/linux.c
@@ -45,9 +45,10 @@ static int loaded;
 static void *real_mode_mem;
 static void *prot_mode_mem;
 static void *initrd_mem;
-static grub_uint32_t real_mode_pages;
-static grub_uint32_t prot_mode_pages;
-static grub_uint32_t initrd_pages;
+static grub_size_t real_size;
+static grub_size_t mmap_size;
+static grub_size_t prot_size;
+static grub_size_t initrd_size;
 
 static grub_uint8_t gdt[] __attribute__ ((aligned(16))) =
   {
@@ -182,7 +183,24 @@ find_mmap_size (void)
 static void
 free_pages (void)
 {
-  real_mode_mem = prot_mode_mem = initrd_mem = 0;
+  if (real_mode_mem)
+    {
+      grub_declaimmap ((grub_addr_t) real_mode_mem, real_size 
+                              + mmap_size);
+      real_mode_mem = 0;
+    }
+
+  if (prot_mode_mem)
+    {
+      grub_declaimmap ((grub_addr_t) prot_mode_mem, prot_size);
+      prot_mode_mem = 0;
+    }
+  
+  if (initrd_mem)
+    {
+      grub_declaimmap ((grub_addr_t) initrd_mem, initrd_size);
+      initrd_mem = 0;
+    }
 }
 
 /* Allocate pages for the real mode code and the protected mode code
@@ -190,8 +208,6 @@ free_pages (void)
 static int
 allocate_pages (grub_size_t prot_size)
 {
-  grub_size_t real_size, mmap_size;
-
   /* Make sure that each size is aligned to a page boundary.  */
   real_size = GRUB_LINUX_CL_END_OFFSET;
   prot_size = page_align (prot_size);
@@ -200,11 +216,6 @@ allocate_pages (grub_size_t prot_size)
   grub_dprintf ("linux", "real_size = %x, prot_size = %x, mmap_size = %x\n",
                (unsigned) real_size, (unsigned) prot_size, (unsigned) 
mmap_size);
   
-  /* Calculate the number of pages; Combine the real mode code with
-     the memory map buffer for simplicity.  */
-  real_mode_pages = ((real_size + mmap_size) >> 12);
-  prot_mode_pages = (prot_size >> 12);
-  
   /* Initialize the memory pointers with NULL for convenience.  */
   real_mode_mem = 0;
   prot_mode_mem = 0;
@@ -233,6 +244,8 @@ allocate_pages (grub_size_t prot_size)
            return 0;
 
          real_mode_mem = (void *) ((addr + size) - (real_size + mmap_size));
+         if (grub_claimmap (real_mode_mem, real_size + mmap_size) < 0)
+           return 0;
          return 1;
        }
 
@@ -246,6 +259,14 @@ allocate_pages (grub_size_t prot_size)
     }
 
   prot_mode_mem = (void *) 0x100000;
+  /* Next, find free pages for the protected mode code.  */
+  /* XXX what happens if anything is using this address?  */
+  if (grub_claimmap (0x100000, prot_size) < 0)
+    {
+      grub_error (GRUB_ERR_OUT_OF_MEMORY,
+                 "cannot allocate protected mode pages");
+      goto fail;
+    }
 
   grub_dprintf ("linux", "real_mode_mem = %lx, real_mode_pages = %x, "
                 "prot_mode_mem = %lx, prot_mode_pages = %x\n",
@@ -395,6 +416,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);
@@ -457,7 +499,6 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
   struct linux_kernel_header lh;
   struct linux_kernel_params *params;
   grub_uint8_t setup_sects;
-  grub_size_t real_size, prot_size;
   grub_ssize_t len;
   int i;
   char *dest;
@@ -690,7 +731,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ 
((unused)),
     goto fail;
 
   size = grub_file_size (file);
-  initrd_pages = (page_align (size) >> 12);
+  initrd_size = page_align (size);
 
   lh = (struct linux_kernel_header *) real_mode_mem;
 
@@ -721,11 +762,10 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ 
((unused)),
   addr_min = (grub_addr_t) prot_mode_mem + ((prot_mode_pages * 3) << 12)
              + page_align (size);
   
-  if (addr_max > grub_os_area_addr + grub_os_area_size)
-    addr_max = grub_os_area_addr + grub_os_area_size;
-
   /* Put the initrd as high as possible, 4KiB aligned.  */
   addr = (addr_max - size) & ~0xFFF;
+  while (addr >= addr_min && grub_claimmap (addr, initrd_size) < 0)
+    addr -= 0x1000;
 
   if (addr < addr_min)
     {
diff --git a/loader/i386/multiboot.c b/loader/i386/multiboot.c
index 27042a5..055b1cf 100644
--- a/loader/i386/multiboot.c
+++ b/loader/i386/multiboot.c
@@ -30,7 +30,7 @@
 #include <grub/loader.h>
 #include <grub/machine/loader.h>
 #include <grub/multiboot.h>
-#include <grub/machine/init.h>
+#include <grub/machine/machine.h>
 #include <grub/machine/memory.h>
 #include <grub/cpu/multiboot.h>
 #include <grub/elf.h>
@@ -43,6 +43,13 @@
 #include <grub/misc.h>
 #include <grub/gzio.h>
 #include <grub/env.h>
+#include <grub/cpu/loader.h>
+#include <grub/cpu/multiboot.h>
+#include <grub/i386/uppermem.h>
+
+#ifdef GRUB_MACHINE_EFI
+#include <grub/efi/efi.h>
+#endif
 
 extern grub_dl_t my_mod;
 static struct grub_multiboot_info *mbi, *mbi_dest;
@@ -54,6 +61,13 @@ static grub_size_t code_size;
 static grub_err_t
 grub_multiboot_boot (void)
 {
+  grub_printf ("Boot\n");
+
+#ifdef GRUB_MACHINE_EFI
+  if (! grub_efi_finish_boot_services ())
+     grub_fatal ("cannot exit boot services");
+#endif
+
   grub_multiboot_real_boot (entry, mbi_dest);
 
   /* Not reached.  */
@@ -109,14 +123,24 @@ grub_get_multiboot_mmap_len (void)
 static void
 grub_fill_multiboot_mmap (struct grub_multiboot_mmap_entry *first_entry)
 {
-  struct grub_multiboot_mmap_entry *mmap_entry = (struct 
grub_multiboot_mmap_entry *) first_entry;
+  struct grub_multiboot_mmap_entry *mmap_entry 
+    = (struct grub_multiboot_mmap_entry *) first_entry;
 
   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)
     {
       mmap_entry->addr = addr;
       mmap_entry->len = size;
-      mmap_entry->type = type;
+      switch (type)
+        {
+        case GRUB_MACHINE_MEMORY_AVAILABLE:
+         mmap_entry->type = GRUB_MULTIBOOT_MEMORY_AVAILABLE;
+         break;
+         
+       default:
+         mmap_entry->type = GRUB_MULTIBOOT_MEMORY_RESERVED;
+         break;
+       }
       mmap_entry->size = sizeof (struct grub_multiboot_mmap_entry) - sizeof 
(mmap_entry->size);
       mmap_entry++;
 
@@ -199,6 +223,7 @@ grub_multiboot (int argc, char *argv[])
   struct grub_multiboot_header *header;
   grub_ssize_t len, cmdline_length, boot_loader_name_length;
   grub_uint32_t mmap_length;
+  grub_uint64_t lower, upper;
   int i;
 
   grub_loader_unset ();
@@ -286,7 +311,9 @@ grub_multiboot (int argc, char *argv[])
       grub_multiboot_payload_dest = header->load_addr;
 
       grub_multiboot_payload_size += code_size;
-      playground = grub_malloc (RELOCATOR_SIZEOF(forward) + 
grub_multiboot_payload_size + RELOCATOR_SIZEOF(backward));
+      playground = grub_malloc (RELOCATOR_SIZEOF(forward) 
+                               + grub_multiboot_payload_size 
+                               + RELOCATOR_SIZEOF(backward));
       if (! playground)
        goto fail;
 
@@ -341,9 +368,12 @@ grub_multiboot (int argc, char *argv[])
                grub_multiboot_payload_size,
                grub_multiboot_payload_entry_offset);
 
+  if (grub_get_lower_upper_memory (&lower, &upper))
+    goto fail;
+
   /* Convert from bytes to kilobytes.  */
-  mbi->mem_lower = grub_lower_mem / 1024;
-  mbi->mem_upper = grub_upper_mem / 1024;
+  mbi->mem_lower = lower / 1024;
+  mbi->mem_upper = upper / 1024;
   mbi->flags |= MULTIBOOT_INFO_MEMORY;
 
   cmdline = p = cmdline_addr (grub_multiboot_payload_orig);
@@ -370,7 +400,7 @@ grub_multiboot (int argc, char *argv[])
   if (grub_multiboot_get_bootdev (&mbi->boot_device))
     mbi->flags |= MULTIBOOT_INFO_BOOTDEV;
 
-  grub_loader_set (grub_multiboot_boot, grub_multiboot_unload, 1);
+  grub_loader_set (grub_multiboot_boot, grub_multiboot_unload, 0);
 
  fail:
   if (file)
diff --git a/loader/i386/pc/linux.c b/loader/i386/pc/linux.c
index 8ff97f4..4823ddc 100644
--- a/loader/i386/pc/linux.c
+++ b/loader/i386/pc/linux.c
@@ -71,11 +71,10 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
   if (! file)
     goto fail;
 
-  if ((grub_size_t) grub_file_size (file) > grub_os_area_size)
+  if (grub_claimmap (GRUB_LINUX_BZIMAGE_ADDR, grub_file_size (file)) < 0)
     {
-      grub_error (GRUB_ERR_OUT_OF_RANGE, "too big kernel (0x%x > 0x%x)",
-                 (grub_size_t) grub_file_size (file),
-                 grub_os_area_size);
+      grub_error (GRUB_ERR_OUT_OF_RANGE, "too big kernel (0x%x)",
+                 (grub_size_t) grub_file_size (file));
       goto fail;
     }
 
@@ -340,9 +339,6 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ 
((unused)),
      worse than that of Linux 2.3.xx, so avoid the last 64kb.  */
   addr_max -= 0x10000;
 
-  if (addr_max > grub_os_area_addr + grub_os_area_size)
-    addr_max = grub_os_area_addr + grub_os_area_size;
-
   addr_min = (grub_addr_t) grub_linux_tmp_addr + GRUB_LINUX_CL_END_OFFSET;
 
   file = grub_file_open (argv[0]);
@@ -353,6 +349,8 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ 
((unused)),
 
   /* Put the initrd as high as possible, 4KiB aligned.  */
   addr = (addr_max - size) & ~0xFFF;
+  while (addr >= addr_min && grub_claimmap (addr, size) < 0)
+    addr -= 0x1000;
 
   if (addr < addr_min)
     {
diff --git a/loader/i386/pc/multiboot2.c b/loader/i386/pc/multiboot2.c
index d5fe8e3..b065fa7 100644
--- a/loader/i386/pc/multiboot2.c
+++ b/loader/i386/pc/multiboot2.c
@@ -25,32 +25,6 @@
 #include <grub/mm.h>
 
 grub_err_t
-grub_mb2_arch_elf32_hook (Elf32_Phdr *phdr, UNUSED grub_addr_t *addr)
-{
-  Elf32_Addr paddr = phdr->p_paddr;
-
-  if ((paddr < grub_os_area_addr)
-      || (paddr + phdr->p_memsz > grub_os_area_addr + grub_os_area_size))
-    return grub_error(GRUB_ERR_OUT_OF_RANGE,"Address 0x%x is out of range", 
-                      paddr);
-
-  return GRUB_ERR_NONE;
-}
-
-grub_err_t
-grub_mb2_arch_elf64_hook (Elf64_Phdr *phdr, UNUSED grub_addr_t *addr)
-{
-  Elf64_Addr paddr = phdr->p_paddr;
-
-  if ((paddr < grub_os_area_addr)
-      || (paddr + phdr->p_memsz > grub_os_area_addr + grub_os_area_size))
-    return grub_error (GRUB_ERR_OUT_OF_RANGE, "Address 0x%x is out of range",
-                      paddr);
-
-  return GRUB_ERR_NONE;
-}
-
-grub_err_t
 grub_mb2_arch_module_alloc (grub_size_t size, grub_addr_t *addr)
 {
   grub_addr_t modaddr;
@@ -73,6 +47,7 @@ grub_mb2_arch_module_free (grub_addr_t addr, UNUSED 
grub_size_t size)
 void
 grub_mb2_arch_boot (grub_addr_t entry, void *tags)
 {
+  grub_stop_floppy ();
   grub_multiboot2_real_boot (entry, tags);
 }
 
diff --git a/loader/ieee1275/multiboot2.c b/loader/ieee1275/multiboot2.c
index c253fc9..462135b 100644
--- a/loader/ieee1275/multiboot2.c
+++ b/loader/ieee1275/multiboot2.c
@@ -31,41 +31,6 @@
 typedef void (*kernel_entry_t) (unsigned long, void *, int (void *),
                                 unsigned long, unsigned long);
 
-/* Claim the memory occupied by the multiboot kernel.  */
-grub_err_t
-grub_mb2_arch_elf32_hook (Elf32_Phdr *phdr, UNUSED grub_addr_t *addr)
-{
-  int rc;
-
-  rc = grub_claimmap (phdr->p_paddr, phdr->p_memsz);
-  if (rc)
-    return grub_error(GRUB_ERR_OUT_OF_MEMORY, "Couldn't claim %x - %x",
-                     phdr->p_paddr, phdr->p_paddr + phdr->p_memsz);
-
-  grub_dprintf ("loader", "Loading segment at 0x%x - 0x%x\n", phdr->p_paddr,
-               phdr->p_paddr + phdr->p_memsz);
-
-  return GRUB_ERR_NONE;
-}
-
-/* Claim the memory occupied by the multiboot kernel.  */
-grub_err_t
-grub_mb2_arch_elf64_hook (Elf64_Phdr *phdr, UNUSED grub_addr_t *addr)
-{
-  int rc;
-
-  rc = grub_claimmap (phdr->p_paddr, phdr->p_memsz);
-  if (rc)
-    return grub_error(GRUB_ERR_OUT_OF_MEMORY, "Couldn't claim 0x%lx - 0x%lx",
-                     phdr->p_paddr, phdr->p_paddr + phdr->p_memsz);
-
-  grub_dprintf ("loader", "Loading segment at 0x%lx - 0x%lx\n",
-               (unsigned long) phdr->p_paddr,
-               (unsigned long) (phdr->p_paddr + phdr->p_memsz));
-
-  return GRUB_ERR_NONE;
-}
-
 grub_err_t
 grub_mb2_arch_module_alloc (grub_size_t size, grub_addr_t *addr)
 {
diff --git a/loader/multiboot2.c b/loader/multiboot2.c
index 2fb56bf..a6cee06 100644
--- a/loader/multiboot2.c
+++ b/loader/multiboot2.c
@@ -38,6 +38,42 @@ static char *grub_mb2_tags_pos;
 static grub_size_t grub_mb2_tags_len;
 static int grub_mb2_tags_count;
 
+/* Claim the memory occupied by the multiboot kernel.  */
+static grub_err_t
+grub_mb2_elf32_hook (Elf32_Phdr *phdr, UNUSED grub_addr_t *addr)
+{
+  int rc;
+
+  rc = grub_claimmap (phdr->p_paddr, phdr->p_memsz);
+  if (rc)
+    return grub_error(GRUB_ERR_OUT_OF_MEMORY, "Couldn't claim %x - %x",
+                     phdr->p_paddr, phdr->p_paddr + phdr->p_memsz);
+
+  grub_dprintf ("loader", "Loading segment at 0x%x - 0x%x\n", phdr->p_paddr,
+               phdr->p_paddr + phdr->p_memsz);
+
+  return GRUB_ERR_NONE;
+}
+
+/* Claim the memory occupied by the multiboot kernel.  */
+static grub_err_t
+grub_mb2_elf64_hook (Elf64_Phdr *phdr, UNUSED grub_addr_t *addr)
+{
+  int rc;
+
+  rc = grub_claimmap (phdr->p_paddr, phdr->p_memsz);
+  if (rc)
+    return grub_error(GRUB_ERR_OUT_OF_MEMORY, "Couldn't claim 0x%lx - 0x%lx",
+                     phdr->p_paddr, phdr->p_paddr + phdr->p_memsz);
+
+  grub_dprintf ("loader", "Loading segment at 0x%lx - 0x%lx\n",
+               (unsigned long) phdr->p_paddr,
+               (unsigned long) (phdr->p_paddr + phdr->p_memsz));
+
+  return GRUB_ERR_NONE;
+}
+
+
 static void
 grub_mb2_tags_free (void)
 {
@@ -279,13 +315,13 @@ grub_mb2_load_elf (grub_elf_t elf, int argc, char *argv[])
   if (grub_elf_is_elf32 (elf))
     {
       entry = elf->ehdr.ehdr32.e_entry;
-      err = grub_elf32_load (elf, grub_mb2_arch_elf32_hook, &kern_base,
+      err = grub_elf32_load (elf, grub_mb2_elf32_hook, &kern_base,
                             &kern_size);
     }
   else if (grub_elf_is_elf64 (elf))
     {
       entry = elf->ehdr.ehdr64.e_entry;
-      err = grub_elf64_load (elf, grub_mb2_arch_elf64_hook, &kern_base,
+      err = grub_elf64_load (elf, grub_mb2_elf64_hook, &kern_base,
                             &kern_size);
     }
   else
diff --git a/loader/multiboot_loader.c b/loader/multiboot_loader.c
index f4a3933..6c30d5a 100644
--- a/loader/multiboot_loader.c
+++ b/loader/multiboot_loader.c
@@ -137,9 +137,7 @@ grub_cmd_multiboot_loader (grub_command_t cmd __attribute__ 
((unused)),
 
    /* Launch multi boot with header */
 
-   /* XXX Find a better way to identify this. 
-      This is for i386-pc */
-#if defined(GRUB_MACHINE_PCBIOS) || defined(GRUB_MACHINE_LINUXBIOS)
+#if defined(__i386__)
   if (header_multi_ver_found == 1)
     {
       grub_dprintf ("multiboot_loader",
@@ -152,7 +150,9 @@ grub_cmd_multiboot_loader (grub_command_t cmd __attribute__ 
((unused)),
     {
       grub_dprintf ("multiboot_loader",
            "Launching multiboot 2 grub_multiboot2() function\n");
+#ifndef GRUB_MACHINE_EFI
       grub_multiboot2 (argc, argv);
+#endif
       module_version_status = 2;
     }
 
@@ -172,7 +172,7 @@ grub_cmd_module_loader (grub_command_t cmd __attribute__ 
((unused)),
                        int argc, char *argv[])
 {
 
-#if defined(GRUB_MACHINE_PCBIOS) || defined(GRUB_MACHINE_LINUXBIOS)
+#if defined(__i386__)
   if (module_version_status == 1)
     {
       grub_dprintf("multiboot_loader",
@@ -184,7 +184,9 @@ grub_cmd_module_loader (grub_command_t cmd __attribute__ 
((unused)),
     {
       grub_dprintf("multiboot_loader",
           "Launching multiboot 2 grub_module2() function\n");
+#ifndef GRUB_MACHINE_EFI
       grub_module2 (argc, argv);
+#endif
     }
 
   return grub_errno;

reply via email to

[Prev in Thread] Current Thread [Next in Thread]