All of lore.kernel.org
 help / color / mirror / Atom feed
* Re: [RFC] grub-install C rewrite
@ 2013-09-26 17:52 Kalamatee
  0 siblings, 0 replies; 20+ messages in thread
From: Kalamatee @ 2013-09-26 17:52 UTC (permalink / raw)
  To: grub-devel

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

Sounds great phcoder,

Anything that removes grubs dependency on a *nix-specific environment has
to be a good thing imho (or is it the grand *nix bootloader?)

[-- Attachment #2: Type: text/html, Size: 204 bytes --]

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

* Re: [RFC] grub-install C rewrite
  2013-10-06 15:56   ` Andrey Borzenkov
@ 2013-10-06 18:05     ` Vladimir 'φ-coder/phcoder' Serbinenko
  0 siblings, 0 replies; 20+ messages in thread
From: Vladimir 'φ-coder/phcoder' Serbinenko @ 2013-10-06 18:05 UTC (permalink / raw)
  To: The development of GNU GRUB

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

On 06.10.2013 17:56, Andrey Borzenkov wrote:
> В Sun, 06 Oct 2013 16:54:08 +0200
> Vladimir 'φ-coder/phcoder' Serbinenko <phcoder@gmail.com> пишет:
> 
>> On 26.09.2013 15:08, Vladimir 'φ-coder/phcoder' Serbinenko wrote:
>>> Hello, all. Recently I made some order in hostdisk.c and getroot.c
>>> involving splitting in OS-specific parts.
>>> In the same time I added WinAPI version of getroot/hostdisk allowing
>>> grub-probe to work on windows natively
>>> Also on-going is AROS-specific parts.
>>> Windows and AROS are not friendly with bash.
>>> The attempt to make both multiple files of same type work and handling
>>> whitespaces/newlines/... in filenames would result in very ugly code
>>> with loads of evals.
>>> Current code may have subtle assumptions on behaviour of common tools
>>> like sed and on locale (E.g. "[a-z]" doesn't cover u if locale is Estonian).
>>> So to check viability I rewrote grub-install in C. This is mostly proof
>>> of concept with loads of FIXMEs but I could boot i386-pc install made
>>> with it. In many aspects (static variables, some tests, general
>>> structure) it's reminiscent of sh version of grub-install it's based on.
>>> Some functionality is likely to stay OS-specific, e.g. executing
>>> compressors or determining firmware.
>> Attached is the second iteration of this patch.
> 
>> @@ -308,6 +310,7 @@
>>    installdir = sbin;
>>    mansection = 8;
>>    common = util/grub-setup.c;
>> +  common = util/setup_bios.c;
> +  extra_dist = util/setup.c;
> 
>> @@ -324,6 +327,7 @@
>>    installdir = sbin;
>>    mansection = 8;
>>    common = util/grub-setup.c;
>> +  common = util/setup_sparc.c;
> +  extra_dist = util/setup.c;
> 
>> +program = {
>>    mansection = 8;
>>    installdir = sbin;
>>    name = grub-install;
>>  
>> -  common = util/grub-install_header;
>> -  common = util/grub-install.in;
>> +  common = util/mkimage.c;
>> +  common = util/grub-install.c;
>> +  common = util/grub-install-common.c;
>> +  common = util/setup_bios.c;
>> +  common = util/setup_sparc.c;
> +  extra_dist = util/setup.c;
> 
> 
>>                                                 Now the biggest problem
>> is in reading /etc/default/grub and getting GRUB_DISTRIBUTOR and
>> GRUB_ENABLE_CRYPTODISK. Trouble is that now this file is simply included
>> in bash script and e.g. Debian uses it to determine GRUB_DISTRIBUTOR
>> based on lsb_release output. Does anyone have an elegant solution for this?
>>
> 
> If declaring this as unsupported is not an option, the only solution is
> wrapper, something like
> 
> sh -c '/etc/default/grub; printf
> GRUB_DISTRIBUTOR=%s\\nGRUB_ENABLE_CRYPTODISK=%s\\n "$GRUB_DISTRIBUTOR" "$GRUB_ENABLE_CRYPTODISK"'
> 
Rather
sh -c '. /etc/default/grub; printf GRUB_DISTRIBUTOR=%s\\nGRUB_ENABLE_CRYPTODISK=%s\\n "$GRUB_DISTRIBUTOR" "$GRUB_ENABLE_CRYPTODISK"'
This is probably the best way to do it on Unix-like systems with fallback for simple parser for other systems.
> 
> 
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> https://lists.gnu.org/mailman/listinfo/grub-devel
> 



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 291 bytes --]

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

* Re: [RFC] grub-install C rewrite
  2013-10-06 14:54 ` Vladimir 'φ-coder/phcoder' Serbinenko
@ 2013-10-06 15:56   ` Andrey Borzenkov
  2013-10-06 18:05     ` Vladimir 'φ-coder/phcoder' Serbinenko
  0 siblings, 1 reply; 20+ messages in thread
From: Andrey Borzenkov @ 2013-10-06 15:56 UTC (permalink / raw)
  To: grub-devel

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

В Sun, 06 Oct 2013 16:54:08 +0200
Vladimir 'φ-coder/phcoder' Serbinenko <phcoder@gmail.com> пишет:

> On 26.09.2013 15:08, Vladimir 'φ-coder/phcoder' Serbinenko wrote:
> > Hello, all. Recently I made some order in hostdisk.c and getroot.c
> > involving splitting in OS-specific parts.
> > In the same time I added WinAPI version of getroot/hostdisk allowing
> > grub-probe to work on windows natively
> > Also on-going is AROS-specific parts.
> > Windows and AROS are not friendly with bash.
> > The attempt to make both multiple files of same type work and handling
> > whitespaces/newlines/... in filenames would result in very ugly code
> > with loads of evals.
> > Current code may have subtle assumptions on behaviour of common tools
> > like sed and on locale (E.g. "[a-z]" doesn't cover u if locale is Estonian).
> > So to check viability I rewrote grub-install in C. This is mostly proof
> > of concept with loads of FIXMEs but I could boot i386-pc install made
> > with it. In many aspects (static variables, some tests, general
> > structure) it's reminiscent of sh version of grub-install it's based on.
> > Some functionality is likely to stay OS-specific, e.g. executing
> > compressors or determining firmware.
> Attached is the second iteration of this patch.

> @@ -308,6 +310,7 @@
>    installdir = sbin;
>    mansection = 8;
>    common = util/grub-setup.c;
> +  common = util/setup_bios.c;
+  extra_dist = util/setup.c;

> @@ -324,6 +327,7 @@
>    installdir = sbin;
>    mansection = 8;
>    common = util/grub-setup.c;
> +  common = util/setup_sparc.c;
+  extra_dist = util/setup.c;

> +program = {
>    mansection = 8;
>    installdir = sbin;
>    name = grub-install;
>  
> -  common = util/grub-install_header;
> -  common = util/grub-install.in;
> +  common = util/mkimage.c;
> +  common = util/grub-install.c;
> +  common = util/grub-install-common.c;
> +  common = util/setup_bios.c;
> +  common = util/setup_sparc.c;
+  extra_dist = util/setup.c;


>                                                 Now the biggest problem
> is in reading /etc/default/grub and getting GRUB_DISTRIBUTOR and
> GRUB_ENABLE_CRYPTODISK. Trouble is that now this file is simply included
> in bash script and e.g. Debian uses it to determine GRUB_DISTRIBUTOR
> based on lsb_release output. Does anyone have an elegant solution for this?
> 

If declaring this as unsupported is not an option, the only solution is
wrapper, something like

sh -c '/etc/default/grub; printf
GRUB_DISTRIBUTOR=%s\\nGRUB_ENABLE_CRYPTODISK=%s\\n "$GRUB_DISTRIBUTOR" "$GRUB_ENABLE_CRYPTODISK"'


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

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

* Re: [RFC] grub-install C rewrite
  2013-09-26 13:08 Vladimir 'φ-coder/phcoder' Serbinenko
  2013-09-26 13:35 ` Lennart Sorensen
  2013-09-26 14:49 ` Andrey Borzenkov
@ 2013-10-06 14:54 ` Vladimir 'φ-coder/phcoder' Serbinenko
  2013-10-06 15:56   ` Andrey Borzenkov
  2 siblings, 1 reply; 20+ messages in thread
From: Vladimir 'φ-coder/phcoder' Serbinenko @ 2013-10-06 14:54 UTC (permalink / raw)
  To: The development of GRUB 2


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

On 26.09.2013 15:08, Vladimir 'φ-coder/phcoder' Serbinenko wrote:
> Hello, all. Recently I made some order in hostdisk.c and getroot.c
> involving splitting in OS-specific parts.
> In the same time I added WinAPI version of getroot/hostdisk allowing
> grub-probe to work on windows natively
> Also on-going is AROS-specific parts.
> Windows and AROS are not friendly with bash.
> The attempt to make both multiple files of same type work and handling
> whitespaces/newlines/... in filenames would result in very ugly code
> with loads of evals.
> Current code may have subtle assumptions on behaviour of common tools
> like sed and on locale (E.g. "[a-z]" doesn't cover u if locale is Estonian).
> So to check viability I rewrote grub-install in C. This is mostly proof
> of concept with loads of FIXMEs but I could boot i386-pc install made
> with it. In many aspects (static variables, some tests, general
> structure) it's reminiscent of sh version of grub-install it's based on.
> Some functionality is likely to stay OS-specific, e.g. executing
> compressors or determining firmware.
Attached is the second iteration of this patch. Now the biggest problem
is in reading /etc/default/grub and getting GRUB_DISTRIBUTOR and
GRUB_ENABLE_CRYPTODISK. Trouble is that now this file is simply included
in bash script and e.g. Debian uses it to determine GRUB_DISTRIBUTOR
based on lsb_release output. Does anyone have an elegant solution for this?


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1.2: install_c.diff --]
[-- Type: text/x-diff; name="install_c.diff", Size: 295156 bytes --]

=== modified file 'Makefile.util.def'
--- Makefile.util.def	2013-10-03 23:29:10 +0000
+++ Makefile.util.def	2013-10-04 13:50:03 +0000
@@ -159,6 +159,7 @@
   mansection = 1;
 
   common = util/grub-mkimage.c;
+  common = util/mkimage.c;
   common = util/resolve.c;
   common = grub-core/kern/emu/argp_common.c;
 
@@ -208,6 +209,7 @@
   mansection = 1;
 
   common = util/grub-editenv.c;
+  common = util/editenv.c;
 
   ldadd = libgrubmods.a;
   ldadd = libgrubgcry.a;
@@ -308,6 +310,7 @@
   installdir = sbin;
   mansection = 8;
   common = util/grub-setup.c;
+  common = util/setup_bios.c;
   common = grub-core/kern/emu/argp_common.c;
   common = grub-core/lib/reed_solomon.c;
 
@@ -316,7 +319,7 @@
   ldadd = libgrubgcry.a;
   ldadd = grub-core/gnulib/libgnu.a;
   ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
-  cppflags = '-DGRUB_SETUP_BIOS=1';
+  cppflags = '-DGRUB_SETUP_FUNC=grub_bios_setup';
 };
 
 program = {
@@ -324,6 +327,7 @@
   installdir = sbin;
   mansection = 8;
   common = util/grub-setup.c;
+  common = util/setup_sparc.c;
   common = grub-core/kern/emu/argp_common.c;
   common = grub-core/lib/reed_solomon.c;
   common = util/ieee1275/ofpath.c;
@@ -333,7 +337,7 @@
   ldadd = libgrubgcry.a;
   ldadd = grub-core/gnulib/libgnu.a;
   ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
-  cppflags = '-DGRUB_SETUP_SPARC64=1';
+  cppflags = '-DGRUB_SETUP_FUNC=grub_sparc_setup';
 };
 
 program = {
@@ -464,14 +468,33 @@
   common = util/grub-mkstandalone.in;
 };
 
-script = {
+program = {
   mansection = 8;
   installdir = sbin;
   name = grub-install;
 
-  common = util/grub-install_header;
-  common = util/grub-install.in;
+  common = util/mkimage.c;
+  common = util/grub-install.c;
+  common = util/grub-install-common.c;
+  common = util/setup_bios.c;
+  common = util/setup_sparc.c;
+  common = grub-core/lib/reed_solomon.c;
+  common = util/random.c;
+  common = util/ieee1275/ofpath.c;
+  common = util/editenv.c;
+
+  common = grub-core/kern/arm/dl_helper.c;
+
+  common = util/resolve.c;
   enable = noemu;
+  common = grub-core/kern/emu/argp_common.c;
+
+  ldadd = '$(LIBLZMA)';
+  ldadd = libgrubmods.a;
+  ldadd = libgrubgcry.a;
+  ldadd = libgrubkern.a;
+  ldadd = grub-core/gnulib/libgnu.a;
+  ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
 };
 
 script = {

=== modified file 'configure.ac'
--- configure.ac	2013-09-23 11:48:10 +0000
+++ configure.ac	2013-10-04 10:59:26 +0000
@@ -73,14 +73,10 @@
   TARGET_CFLAGS="$TARGET_CFLAGS -Os"
 fi
 
-BUILD_CPPFLAGS="$BUILD_CPPFLAGS -DLOCALEDIR=\\\"\$(localedir)\\\""
-
 # Default HOST_CPPFLAGS
 HOST_CPPFLAGS="$HOST_CPPFLAGS -Wall -W"
 HOST_CPPFLAGS="$HOST_CPPFLAGS -I\$(top_builddir)/include"
 HOST_CPPFLAGS="$HOST_CPPFLAGS -DGRUB_UTIL=1"
-HOST_CPPFLAGS="$HOST_CPPFLAGS -DGRUB_LIBDIR=\\\"\$(pkglibdir)\\\""
-HOST_CPPFLAGS="$HOST_CPPFLAGS -DLOCALEDIR=\\\"\$(localedir)\\\""
 
 TARGET_CPPFLAGS="$TARGET_CPPFLAGS -Wall -W"
 TARGET_CPPFLAGS="$TARGET_CPPFLAGS -I\$(top_srcdir)/include"
@@ -1344,6 +1340,19 @@
 AM_CONDITIONAL([COND_CYGWIN], [test x$target_os = xcygwin])
 AM_CONDITIONAL([COND_STARFIELD], [test "x$starfield_excuse" = x])
 
+test "x$prefix" = xNONE && prefix="$ac_default_prefix"
+test "x$exec_prefix" = xNONE && exec_prefix="${prefix}"
+datarootdir="$(eval echo "$datarootdir")"
+grub_libdir="$(eval echo "$libdir")"
+grub_localedir="$(eval echo "$localedir")"
+grub_datadir="$(eval echo "$datadir")"
+grub_sysconfdir="$(eval echo "$sysconfdir")"
+AC_DEFINE_UNQUOTED(LOCALEDIR, "$grub_localedir", [Locale dir])
+AC_DEFINE_UNQUOTED(GRUB_LIBDIR, "$grub_libdir", [Library dir])
+AC_DEFINE_UNQUOTED(GRUB_DATADIR, "$grub_datadir", [Data dir])
+AC_DEFINE_UNQUOTED(GRUB_SYSCONFDIR, "$sysconfdir", [Configuration dir])
+
+
 # Output files.
 cpudir="${target_cpu}"
 if test x${cpudir} = xmipsel; then

=== added file 'include/grub/util/install.h'
--- include/grub/util/install.h	1970-01-01 00:00:00 +0000
+++ include/grub/util/install.h	2013-10-05 16:58:59 +0000
@@ -0,0 +1,189 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2013  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_UTIL_INSTALL_HEADER
+#define GRUB_UTIL_INSTALL_HEADER	1
+
+#define GRUB_INSTALL_OPTIONS					  \
+  { "modules",      GRUB_INSTALL_OPTIONS_MODULES, N_("MODULES"),	  \
+    0, N_("pre-load specified modules MODULES"), 1 },			  \
+  { "install-modules", GRUB_INSTALL_OPTIONS_INSTALL_MODULES,	  \
+    N_("MODULES"), 0,							  \
+    N_("install only MODULES and their dependencies [default=all]"), 1 }, \
+  { "themes", GRUB_INSTALL_OPTIONS_INSTALL_THEMES, N_("THEMES"),   \
+    0, N_("install THEMES [default=%s]"), 1 },	 		          \
+  { "fonts", GRUB_INSTALL_OPTIONS_INSTALL_FONTS, N_("FONTS"),	  \
+    0, N_("install FONTS [default=%s]"), 1  },	  		          \
+  { "locales", GRUB_INSTALL_OPTIONS_INSTALL_LOCALES, N_("LOCALES"),\
+    0, N_("install only LOCALES [default=all]"), 1 },			  \
+  { "compress", GRUB_INSTALL_OPTIONS_INSTALL_COMPRESS,		  \
+    "no,xz,gz,lzo", OPTION_ARG_OPTIONAL,				  \
+    N_("compress GRUB files [optional]"), 1 },			          \
+    /* TRANSLATORS: platform here isn't identifier. It can be translated. */ \
+  { "directory", 'd', N_("DIR"), 0,					\
+    N_("use images and modules under DIR [default=%s/<platform>]"), 1 },  \
+  { "override-directory", GRUB_INSTALL_OPTIONS_DIRECTORY2,		\
+      N_("DIR"), OPTION_HIDDEN,						\
+    N_("use images and modules under DIR [default=%s/<platform>]"), 1 },  \
+  { "grub-mkimage", GRUB_INSTALL_OPTIONS_GRUB_MKIMAGE,		\
+      "FILE", OPTION_HIDDEN, 0, 1 },					\
+    /* TRANSLATORS: "embed" is a verb (command description).  "*/	\
+  { "pubkey",   'k', N_("FILE"), 0,					\
+      N_("embed FILE as public key for signature checking"), 0}
+
+int
+grub_install_parse (int key, char *arg);
+
+void
+grub_install_push_module (const char *val);
+
+char *
+grub_install_help_filter (int key, const char *text,
+			  void *input __attribute__ ((unused)));
+
+enum grub_install_plat
+  {
+    GRUB_INSTALL_PLATFORM_I386_PC,
+    GRUB_INSTALL_PLATFORM_I386_EFI,
+    GRUB_INSTALL_PLATFORM_I386_QEMU,
+    GRUB_INSTALL_PLATFORM_I386_COREBOOT,
+    GRUB_INSTALL_PLATFORM_I386_MULTIBOOT,
+    GRUB_INSTALL_PLATFORM_I386_IEEE1275,
+    GRUB_INSTALL_PLATFORM_X86_64_EFI,
+    GRUB_INSTALL_PLATFORM_MIPSEL_LOONGSON,
+    GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275,
+    GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275,
+    GRUB_INSTALL_PLATFORM_MIPSEL_ARC,
+    GRUB_INSTALL_PLATFORM_MIPS_ARC,
+    GRUB_INSTALL_PLATFORM_IA64_EFI,
+    GRUB_INSTALL_PLATFORM_ARM_UBOOT,
+    GRUB_INSTALL_PLATFORM_ARM_EFI,
+    GRUB_INSTALL_PLATFORM_MIPSEL_QEMU_MIPS,
+    GRUB_INSTALL_PLATFORM_MIPS_QEMU_MIPS,
+  };
+
+enum grub_install_options {
+  GRUB_INSTALL_OPTIONS_DIRECTORY = 'd',
+  GRUB_INSTALL_OPTIONS_MODULES = 0x201,
+  GRUB_INSTALL_OPTIONS_INSTALL_MODULES,
+  GRUB_INSTALL_OPTIONS_INSTALL_THEMES,
+  GRUB_INSTALL_OPTIONS_INSTALL_FONTS,
+  GRUB_INSTALL_OPTIONS_INSTALL_LOCALES,
+  GRUB_INSTALL_OPTIONS_INSTALL_COMPRESS,
+  GRUB_INSTALL_OPTIONS_DIRECTORY2,
+  GRUB_INSTALL_OPTIONS_GRUB_MKIMAGE
+};
+
+void
+grub_install_args_finish (void);
+
+extern char *grub_install_source_directory;
+
+char *
+grub_install_concat_ext (size_t n, ...);
+char *
+grub_install_concat (size_t n, ...);
+
+enum grub_install_plat
+grub_install_get_target (const char *src);
+void
+grub_install_mkdir_p (const char *dst);
+
+void
+grub_install_copy_files (const char *src,
+			 const char *dst,
+			 enum grub_install_plat platid);
+char *
+grub_install_get_platform_name (enum grub_install_plat platid);
+
+const char *
+grub_install_get_platform_cpu (enum grub_install_plat platid);
+
+const char *
+grub_install_get_platform_platform (enum grub_install_plat platid);
+
+
+typedef enum {
+  GRUB_COMPRESSION_AUTO,
+  GRUB_COMPRESSION_NONE,
+  GRUB_COMPRESSION_XZ,
+  GRUB_COMPRESSION_LZMA
+} grub_compression_t;
+
+void
+grub_install_make_image_wrap (const char *dir, const char *prefix,
+			      const char *outname, char *memdisk_path,
+			      char *config_path,
+			      const char *format, int note,
+			      grub_compression_t comp);
+
+void
+grub_install_copy_file (const char *src,
+			const char *dst);
+
+struct grub_install_image_target_desc;
+
+void
+grub_install_generate_image (const char *dir, const char *prefix,
+			     FILE *out, const char *outname, char *mods[],
+			     char *memdisk_path, char **pubkey_paths,
+			     size_t npubkeys,
+			     char *config_path,
+			     struct grub_install_image_target_desc *image_target, int note,
+			     grub_compression_t comp);
+
+struct grub_install_image_target_desc *
+grub_install_get_image_target (const char *arg);
+void
+grub_bios_setup (const char *dir,
+		 const char *boot_file, const char *core_file,
+		 const char *dest, int force,
+		 int fs_probe, int allow_floppy);
+void
+grub_sparc_setup (const char *dir,
+		  const char *boot_file, const char *core_file,
+		  const char *dest, int force,
+		  int fs_probe, int allow_floppy);
+
+char *
+grub_install_get_image_targets_string (void);
+
+const char *
+grub_util_get_target_dirname (struct grub_install_image_target_desc *t);
+
+#if !defined (__MINGW32__) && !defined (__CYGWIN__)
+
+int
+grub_util_exec (char **argv);
+int
+grub_util_check_executable (const char *fn);
+void
+grub_util_exec_redirect (char **argv, const char *stdin_file,
+			 const char *stdout_file);
+int
+grub_util_exec_redirect_null (char **argv);
+
+#endif
+
+int
+grub_install_is_regular_file (const char *dir);
+
+void
+grub_install_create_envblk_file (const char *name);
+
+#endif

=== added file 'util/editenv.c'
--- util/editenv.c	1970-01-01 00:00:00 +0000
+++ util/editenv.c	2013-10-04 13:49:28 +0000
@@ -0,0 +1,66 @@
+/* grub-editenv.c - tool to edit environment block.  */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008,2009,2010 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 <config.h>
+#include <grub/types.h>
+#include <grub/emu/misc.h>
+#include <grub/util/misc.h>
+#include <grub/lib/envblk.h>
+#include <grub/i18n.h>
+#include <grub/util/install.h>
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <argp.h>
+
+#define DEFAULT_ENVBLK_SIZE	1024
+
+void
+grub_install_create_envblk_file (const char *name)
+{
+  FILE *fp;
+  char *buf;
+  char *namenew;
+
+  buf = xmalloc (DEFAULT_ENVBLK_SIZE);
+
+  namenew = xasprintf ("%s.new", name);
+  fp = fopen (namenew, "wb");
+  if (! fp)
+    grub_util_error (_("cannot open `%s': %s"), namenew,
+		     strerror (errno));
+
+  memcpy (buf, GRUB_ENVBLK_SIGNATURE, sizeof (GRUB_ENVBLK_SIGNATURE) - 1);
+  memset (buf + sizeof (GRUB_ENVBLK_SIGNATURE) - 1, '#',
+          DEFAULT_ENVBLK_SIZE - sizeof (GRUB_ENVBLK_SIGNATURE) + 1);
+
+  if (fwrite (buf, 1, DEFAULT_ENVBLK_SIZE, fp) != DEFAULT_ENVBLK_SIZE)
+    grub_util_error (_("cannot write to `%s': %s"), namenew,
+		     strerror (errno));
+
+  fsync (fileno (fp));
+  free (buf);
+  fclose (fp);
+
+  if (rename (namenew, name) < 0)
+    grub_util_error (_("cannot rename the file %s to %s"), namenew, name);
+  free (namenew);
+}

=== modified file 'util/getroot_unix.c'
--- util/getroot_unix.c	2013-09-24 17:19:31 +0000
+++ util/getroot_unix.c	2013-10-04 14:29:13 +0000
@@ -143,6 +143,77 @@
   return path;
 }
 
+int
+grub_util_exec (char **argv)
+{
+  pid_t pid;
+  int status = -1;
+
+  pid = fork ();
+  if (pid < 0)
+    grub_util_error (_("Unable to fork: %s"), strerror (errno));
+  else if (pid == 0)
+    {
+      /* Child.  */
+
+      /* Close fd's.  */
+      grub_util_devmapper_cleanup ();
+      grub_diskfilter_fini ();
+
+      /* Ensure child is not localised.  */
+      setenv ("LC_ALL", "C", 1);
+
+      execvp (argv[0], argv);
+      exit (127);
+    }
+
+  waitpid (pid, &status, 0);
+  if (!WIFEXITED (status))
+    return -1;
+  return WEXITSTATUS (status);
+}
+
+void
+grub_util_exec_redirect (char **argv, const char *stdin_file,
+			 const char *stdout_file)
+{
+  pid_t mdadm_pid;
+
+  mdadm_pid = fork ();
+  if (mdadm_pid < 0)
+    grub_util_error (_("Unable to fork: %s"), strerror (errno));
+  else if (mdadm_pid == 0)
+    {
+      int in, out;
+      /* Child.  */
+      
+      /* Close fd's.  */
+      grub_util_devmapper_cleanup ();
+      grub_diskfilter_fini ();
+
+      in = open (stdin_file, O_RDONLY);
+      dup2 (in, STDIN_FILENO);
+      close (in);
+
+      out = open (stdout_file, O_WRONLY | O_CREAT, 0700);
+      dup2 (out, STDOUT_FILENO);
+      close (out);
+
+      /* Ensure child is not localised.  */
+      setenv ("LC_ALL", "C", 1);
+
+      execvp (argv[0], argv);
+      exit (127);
+    }
+}
+
+void
+grub_util_exec_redirect_null (char **argv, const char *stdin_file,
+			 const char *stdout_file)
+{
+  grub_util_exec_redirect (argv, "/dev/null", "/dev/null");
+}
+
 pid_t
 grub_util_exec_pipe (char **argv, int *fd)
 {
@@ -518,11 +589,15 @@
 }
 
 char **
-grub_guess_root_devices (const char *dir)
+grub_guess_root_devices (const char *dir_in)
 {
   char **os_dev = NULL;
   struct stat st;
   dev_t dev;
+  char *dir = canonicalize_file_name (dir_in);
+
+  if (!dir)
+    grub_util_error (_("failed to get canonical path of `%s'"), dir_in);
 
 #ifdef __linux__
   if (!os_dev)

=== modified file 'util/grub-editenv.c'
--- util/grub-editenv.c	2013-09-27 00:08:32 +0000
+++ util/grub-editenv.c	2013-10-05 16:57:05 +0000
@@ -23,6 +23,7 @@
 #include <grub/util/misc.h>
 #include <grub/lib/envblk.h>
 #include <grub/i18n.h>
+#include <grub/util/install.h>
 
 #include <stdio.h>
 #include <unistd.h>
@@ -32,7 +33,6 @@
 
 #include "progname.h"
 
-#define DEFAULT_ENVBLK_SIZE	1024
 #define DEFAULT_ENVBLK_PATH DEFAULT_DIRECTORY "/" GRUB_ENVBLK_DEFCFG
 
 static struct argp_option options[] = {
@@ -108,38 +108,6 @@
   NULL, help_filter, NULL
 };
 
-static void
-create_envblk_file (const char *name)
-{
-  FILE *fp;
-  char *buf;
-  char *namenew;
-
-  buf = xmalloc (DEFAULT_ENVBLK_SIZE);
-
-  namenew = xasprintf ("%s.new", name);
-  fp = fopen (namenew, "wb");
-  if (! fp)
-    grub_util_error (_("cannot open `%s': %s"), namenew,
-		     strerror (errno));
-
-  memcpy (buf, GRUB_ENVBLK_SIGNATURE, sizeof (GRUB_ENVBLK_SIGNATURE) - 1);
-  memset (buf + sizeof (GRUB_ENVBLK_SIGNATURE) - 1, '#',
-          DEFAULT_ENVBLK_SIZE - sizeof (GRUB_ENVBLK_SIGNATURE) + 1);
-
-  if (fwrite (buf, 1, DEFAULT_ENVBLK_SIZE, fp) != DEFAULT_ENVBLK_SIZE)
-    grub_util_error (_("cannot write to `%s': %s"), namenew,
-		     strerror (errno));
-
-  fsync (fileno (fp));
-  free (buf);
-  fclose (fp);
-
-  if (rename (namenew, name) < 0)
-    grub_util_error (_("cannot rename the file %s to %s"), namenew, name);
-  free (namenew);
-}
-
 static grub_envblk_t
 open_envblk_file (const char *name)
 {
@@ -152,7 +120,7 @@
   if (! fp)
     {
       /* Create the file implicitly.  */
-      create_envblk_file (name);
+      grub_install_create_envblk_file (name);
       fp = fopen (name, "rb");
       if (! fp)
         grub_util_error (_("cannot open `%s': %s"), name,
@@ -300,7 +268,7 @@
     }
 
   if (strcmp (command, "create") == 0)
-    create_envblk_file (filename);
+    grub_install_create_envblk_file (filename);
   else if (strcmp (command, "list") == 0)
     list_variables (filename);
   else if (strcmp (command, "set") == 0)

=== added file 'util/grub-install-common.c'
--- util/grub-install-common.c	1970-01-01 00:00:00 +0000
+++ util/grub-install-common.c	2013-10-05 16:59:27 +0000
@@ -0,0 +1,810 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010,2011,2012,2013 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 <config.h>
+#include <grub/types.h>
+#include <grub/emu/misc.h>
+#include <grub/util/misc.h>
+#include <grub/misc.h>
+#include <grub/device.h>
+#include <grub/disk.h>
+#include <grub/file.h>
+#include <grub/fs.h>
+#include <grub/env.h>
+#include <grub/term.h>
+#include <grub/mm.h>
+#include <grub/lib/hexdump.h>
+#include <grub/crypto.h>
+#include <grub/command.h>
+#include <grub/i18n.h>
+#include <grub/zfs/zfs.h>
+#include <grub/util/install.h>
+#include <grub/util/resolve.h>
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <dirent.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+char *
+grub_install_help_filter (int key, const char *text,
+				 void *input __attribute__ ((unused)))
+{
+  switch (key)
+    {
+    case GRUB_INSTALL_OPTIONS_INSTALL_THEMES:
+      return xasprintf(text, "starfield");
+    case GRUB_INSTALL_OPTIONS_INSTALL_FONTS:
+      return xasprintf(text, "unicode");
+    case GRUB_INSTALL_OPTIONS_DIRECTORY:
+    case GRUB_INSTALL_OPTIONS_DIRECTORY2:
+      return xasprintf(text, GRUB_LIBDIR PACKAGE);      
+    default:
+      return (char *) text;
+    }
+}
+
+static char **compress_argv;
+static char *copy_buf;
+
+#define COPY_BUF_SIZE 1048576
+
+static char *
+grub_install_concat_real (size_t n, int ext, va_list ap)
+{
+  size_t totlen = 0;
+  char **l = xmalloc ((n + ext) * sizeof (l[0]));
+  char *r, *p, *pi;
+  size_t i;
+  int first = 1;
+
+  for (i = 0; i < n + ext; i++)
+    {
+      l[i] = va_arg (ap, char *);
+      if (l[i])
+	totlen += strlen (l[i]) + 1;
+    }
+
+  r = xmalloc (totlen + 10);
+
+  p = r;
+  for (i = 0; i < n; i++)
+    {
+      pi = l[i];
+      if (!pi)
+	continue;
+      while (*pi == '/')
+	pi++;
+      if ((p != r || (pi != l[i] && first)) && (p == r || *(p - 1) != '/'))
+	*p++ = '/';
+      first = 0;
+      p = stpcpy (p, l[i]);
+      while (p != r && p != r + 1 && *(p - 1) == '/')
+	p--;
+    }
+
+  if (ext && l[i])
+    p = stpcpy (p, l[i]);
+
+  *p = '\0';
+
+  free (l);
+
+  return r;
+}
+
+char *
+grub_install_concat (size_t n, ...)
+{
+  va_list ap;
+  char *r;
+
+  va_start (ap, n);
+
+  r = grub_install_concat_real (n, 0, ap);
+
+  va_end (ap);
+
+  return r;
+}
+
+char *
+grub_install_concat_ext (size_t n, ...)
+{
+  va_list ap;
+  char *r;
+
+  va_start (ap, n);
+
+  r = grub_install_concat_real (n, 1, ap);
+
+  va_end (ap);
+
+  return r;
+}
+
+void
+grub_install_copy_file (const char *src,
+			 const char *dst)
+{
+  FILE *in, *out;
+  in = fopen (src, "rb");
+  if (!in)
+    {
+      grub_util_warn (_("cannot open `%s': %s"), src, strerror (errno));
+      return;
+    }
+  out = fopen (dst, "wb");
+  if (!out)
+    {
+      grub_util_warn (_("cannot open `%s': %s"), dst, strerror (errno));
+      fclose (in);
+      return;
+    }
+
+  if (!copy_buf)
+    copy_buf = xmalloc (COPY_BUF_SIZE);
+ 
+  while (1)
+    {
+      size_t r;
+      r = fread (copy_buf, 1, COPY_BUF_SIZE, in);
+      if (r == 0)
+	break;
+      fwrite (copy_buf, 1, r, out);
+    }
+  fclose (in);
+  fclose (out);
+
+  return;
+}
+
+int
+grub_install_compress_file (const char *in_name,
+				   const char *out_name,
+				   int is_needed)
+{
+  FILE *in, *out;
+  in = fopen (in_name, "rb");
+  if (!in && !is_needed && errno == ENOENT)
+    return 0;
+  if (!in)
+    {
+      grub_util_warn (_("cannot open `%s': %s"), in_name, strerror (errno));
+      return 0;
+    }
+  out = fopen (out_name, "wb");
+  if (!out)
+    {
+      grub_util_warn (_("cannot open `%s': %s"), out_name, strerror (errno));
+      fclose (in);
+      return 0;
+    }
+
+  if (!copy_buf)
+    copy_buf = xmalloc (COPY_BUF_SIZE);
+
+  if (compress_argv)
+    {
+      fclose (in);
+      fclose (out);
+      grub_util_exec_redirect (compress_argv, in_name,
+			       out_name);
+      return 1;
+    }
+
+  while (1)
+    {
+      size_t r;
+      r = fread (copy_buf, 1, COPY_BUF_SIZE, in);
+      if (r == 0)
+	break;
+      fwrite (copy_buf, 1, r, out);
+    }
+  fclose (in);
+  fclose (out);
+
+  return 1;
+}
+
+static int
+is_path_separator (char c)
+{
+#if defined (__MINGW32__) || defined (__CYGWIN__)
+  if (c == '\\')
+    return 1;
+#endif
+  if (c == '/')
+    return 1;
+  return 0;
+}
+
+void
+grub_install_mkdir_p (const char *dst)
+{
+  char *t = xstrdup (dst);
+  char *p;
+  for (p = t; *p; p++)
+    {
+      if (is_path_separator (*p))
+	{
+	  char s = *p;
+	  *p = '\0';
+	  mkdir (t, 0700);
+	  *p = s;
+	}
+    }
+  mkdir (t, 0700);
+}
+
+static void
+clean_grub_dir (const char *di)
+{
+  DIR *d;
+  struct dirent *de;
+
+  d = opendir (di);
+  if (!d)
+    grub_util_error (_("cannot open directory `%s': %s"),
+		     di, strerror (errno));
+
+  while ((de = readdir (d)))
+    {
+      const char *ext = strrchr (de->d_name, '.');
+      if ((ext && (strcmp (ext, ".mod") == 0
+		   || strcmp (ext, ".lst") == 0
+		   || strcmp (ext, ".img") == 0
+		   || strcmp (ext, ".mo") == 0)
+	   && strcmp (de->d_name, "menu.lst") != 0)
+	  || strcmp (de->d_name, "efiemu32.o") == 0
+	  || strcmp (de->d_name, "efiemu64.o") == 0)
+	{
+	  char *x = grub_install_concat (2, di, de->d_name);
+	  if (unlink (x) < 0)
+	    grub_util_error ("cannont delete `%s': %s", x, strerror (errno));
+	  free (x);
+	}
+    }
+  closedir (d);
+}
+
+struct install_list
+{
+  int is_default;
+  char **entries;
+  size_t n_entries;
+  size_t n_alloc;
+};
+
+struct install_list install_modules = { 1, 0, 0, 0 };
+struct install_list modules = { 1, 0, 0, 0 };
+struct install_list install_locales = { 1, 0, 0, 0 };
+struct install_list install_fonts = { 1, 0, 0, 0 };
+struct install_list install_themes = { 1, 0, 0, 0 };
+char *grub_install_source_directory = NULL;
+
+void
+grub_install_push_module (const char *val)
+{
+  modules.is_default = 0;
+  if (modules.n_entries + 1 >= modules.n_alloc)
+    {
+      modules.n_alloc <<= 1;
+      if (modules.n_alloc < 16)
+	modules.n_alloc = 16;
+      modules.entries = xrealloc (modules.entries,
+				  modules.n_alloc * sizeof (modules.entries));
+    }
+  modules.entries[modules.n_entries++] = xstrdup (val);
+  modules.entries[modules.n_entries] = NULL;
+}
+
+static void
+handle_install_list (struct install_list *il, const char *val,
+		     int default_all)
+{
+  const char *ptr;
+  char **ce;
+  il->is_default = 0;
+  free (il->entries);
+  il->entries = NULL;
+  il->n_entries = 0;
+  if (strcmp (val, "all") == 0 && default_all)
+    {
+      il->is_default = 1;
+      return;
+    }
+  ptr = val;
+  while (1)
+    {
+      while (*ptr && grub_isspace (*ptr))
+	ptr++;
+      if (!*ptr)
+	break;
+      while (*ptr && !grub_isspace (*ptr))
+	ptr++;
+      il->n_entries++;
+    }
+  il->n_alloc = il->n_entries + 1;
+  il->entries = xmalloc (il->n_alloc * sizeof (il->entries[0]));
+  for (ce = il->entries; ; ce++)
+    {
+      const char *bptr;
+      while (*ptr && grub_isspace (*ptr))
+	ptr++;
+      if (!*ptr)
+	break;
+      bptr = ptr;
+      while (*ptr && !grub_isspace (*ptr))
+	ptr++;
+      *ce = xmalloc (ptr - bptr + 1);
+      memcpy (*ce, bptr, ptr - bptr);
+      (*ce)[ptr - bptr] = '\0';
+      ce++;
+    }
+  *ce = NULL;
+}
+
+static char *compress_gzip[] = { (char *) "gzip", (char *) "--best",
+				 (char *) "--stdout", NULL };
+static char *compress_xz[] = { (char *) "xz",
+			       (char *) "--lzma2=dict=128KiB",
+			       (char *) "--check=none",
+			     (char *) "--stdout", NULL };
+static char *compress_lzo[] = {(char *) "lzop",
+			       (char *) "-9", 
+			       (char *) "-c", NULL };
+static char **pubkeys;
+static size_t npubkeys;
+
+int
+grub_install_parse (int key, char *arg)
+{
+  switch (key)
+    {
+    case 'k':
+      pubkeys = xrealloc (pubkeys,
+			  sizeof (pubkeys[0])
+			  * (npubkeys + 1));
+      pubkeys[npubkeys++] = xstrdup (arg);
+      return 1;
+
+    case GRUB_INSTALL_OPTIONS_DIRECTORY:
+    case GRUB_INSTALL_OPTIONS_DIRECTORY2:
+      free (grub_install_source_directory);
+      grub_install_source_directory = xstrdup (arg);
+      return 1;
+    case GRUB_INSTALL_OPTIONS_INSTALL_MODULES:
+      handle_install_list (&install_modules, arg, 0);
+      return 1;
+    case GRUB_INSTALL_OPTIONS_MODULES:
+      handle_install_list (&modules, arg, 0);
+      return 1;
+    case GRUB_INSTALL_OPTIONS_INSTALL_LOCALES:
+      handle_install_list (&install_locales, arg, 0);
+      return 1;
+    case GRUB_INSTALL_OPTIONS_INSTALL_THEMES:
+      handle_install_list (&install_themes, arg, 0);
+      return 1;
+    case GRUB_INSTALL_OPTIONS_INSTALL_FONTS:
+      handle_install_list (&install_fonts, arg, 0);
+      return 1;
+    case GRUB_INSTALL_OPTIONS_INSTALL_COMPRESS:
+      if (strcmp (arg, "no") == 0)
+	{
+	  compress_argv = NULL;
+	  return 1;
+	}
+      if (strcmp (arg, "gz") == 0)
+	{
+	  compress_argv = compress_gzip;
+	  return 1;
+	}
+      if (strcmp (arg, "xz") == 0)
+	{
+	  compress_argv = compress_xz;
+	  return 1;
+	}
+      if (strcmp (arg, "lzo") == 0)
+	{
+	  compress_argv = compress_lzo;
+	  return 1;
+	}
+      grub_util_error (_("Unrecognized compression `%s'"), arg);
+    case GRUB_INSTALL_OPTIONS_GRUB_MKIMAGE:
+      return 1;
+    default:
+      return 0;
+    }
+}
+
+void
+grub_install_args_finish (void)
+{
+  if (compress_argv == compress_gzip)
+    grub_install_push_module ("gzio");
+  if (compress_argv == compress_xz)
+    {
+      grub_install_push_module ("xzio");
+      grub_install_push_module ("gcry_crc");
+    }
+  if (compress_argv == compress_lzo)
+    {
+      grub_install_push_module ("lzopio");
+      grub_install_push_module ("adler32");
+      grub_install_push_module ("gcry_crc");
+    }
+}
+
+void
+grub_install_make_image_wrap (const char *dir, const char *prefix,
+			      const char *outname, char *memdisk_path,
+			      char *config_path,
+			      const char *mkimage_target, int note,
+			      grub_compression_t comp)
+{
+  FILE *fp = stdout;
+  struct grub_install_image_target_desc *tgt;
+  fp = fopen (outname, "wb");
+  if (! fp)
+    grub_util_error (_("cannot open `%s': %s"), outname,
+		     strerror (errno));
+  tgt = grub_install_get_image_target (mkimage_target);
+  if (!tgt)
+    grub_util_error (_("unknown target format %s\n"), mkimage_target);
+
+
+
+  grub_install_generate_image (dir, prefix, fp, outname,
+			       modules.entries, memdisk_path,
+			       pubkeys, npubkeys, config_path, tgt,
+			       note, comp);
+  fflush (fp);
+  fsync (fileno (fp));
+  fclose (fp);
+}
+
+static void
+copy_by_ext (const char *srcd,
+	     const char *dstd,
+	     const char *extf,
+	     int req)
+{
+  DIR *d;
+  struct dirent *de;
+
+  d = opendir (srcd);
+  if (!d && !req)
+    return;
+  if (!d)
+    grub_util_error (_("cannot open directory `%s': %s"),
+		     srcd, strerror (errno));
+
+  while ((de = readdir (d)))
+    {
+      const char *ext = strrchr (de->d_name, '.');
+      if (ext && strcmp (ext, extf) == 0)
+	{
+	  char *srcf = grub_install_concat (2, srcd, de->d_name);
+	  char *dstf = grub_install_concat (2, dstd, de->d_name);
+	  grub_install_compress_file (srcf, dstf, 1);
+	  free (srcf);
+	  free (dstf);
+	}
+    }
+  closedir (d);
+}
+
+static void
+copy_all (const char *srcd,
+	     const char *dstd)
+{
+  DIR *d;
+  struct dirent *de;
+
+  d = opendir (srcd);
+  if (!d)
+    grub_util_error (_("cannot open directory `%s': %s"),
+		     srcd, strerror (errno));
+
+  while ((de = readdir (d)))
+    {
+      char *srcf;
+      char *dstf;
+      if (strcmp (de->d_name, ".") == 0
+	  || strcmp (de->d_name, "..") == 0)
+	continue;
+      srcf = grub_install_concat (2, srcd, de->d_name);
+      dstf = grub_install_concat (2, dstd, de->d_name);
+      grub_install_compress_file (srcf, dstf, 1);
+      free (srcf);
+      free (dstf);
+    }
+  closedir (d);
+}
+
+static void
+copy_locales (const char *dstd)
+{
+  DIR *d;
+  struct dirent *de;
+
+  d = opendir (LOCALEDIR);
+  if (!d)
+    grub_util_error (_("cannot open directory `%s': %s"),
+		     LOCALEDIR, strerror (errno));
+
+  while ((de = readdir (d)))
+    {
+      char *srcf = grub_install_concat_ext (3, LOCALEDIR, de->d_name,
+						   PACKAGE, ".mo");
+      char *dstf = grub_install_concat_ext (2, dstd, de->d_name, ".mo");
+      grub_install_compress_file (srcf, dstf, 0);
+      free (srcf);
+      free (dstf);
+    }
+  closedir (d);
+}
+
+static struct
+{
+  enum grub_install_plat val;
+  const char *cpu;
+  const char *platform;
+} platforms[] =
+  {
+    { GRUB_INSTALL_PLATFORM_I386_PC,          "i386",    "pc"        },
+    { GRUB_INSTALL_PLATFORM_I386_EFI,         "i386",    "efi"       },
+    { GRUB_INSTALL_PLATFORM_I386_QEMU,        "i386",    "qemu"      },
+    { GRUB_INSTALL_PLATFORM_I386_COREBOOT,    "i386",    "coreboot"  },
+    { GRUB_INSTALL_PLATFORM_I386_MULTIBOOT,   "i386",    "multiboot" },
+    { GRUB_INSTALL_PLATFORM_I386_IEEE1275,    "i386",    "ieee1275"  },
+    { GRUB_INSTALL_PLATFORM_X86_64_EFI,       "x86_64",  "efi"       },
+    { GRUB_INSTALL_PLATFORM_MIPSEL_LOONGSON,  "mipsel",  "loongson"  },
+    { GRUB_INSTALL_PLATFORM_MIPSEL_QEMU_MIPS, "mipsel",  "qemu_mips" },
+    { GRUB_INSTALL_PLATFORM_MIPS_QEMU_MIPS,   "mips",    "qemu_mips" },
+    { GRUB_INSTALL_PLATFORM_MIPSEL_ARC,       "mipsel",  "arc"       },
+    { GRUB_INSTALL_PLATFORM_MIPS_ARC,         "mips",    "arc"       },
+    { GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275, "sparc64", "ieee1275"  },
+    { GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275, "powerpc", "ieee1275"  },
+    { GRUB_INSTALL_PLATFORM_IA64_EFI,         "ia64",    "efi"       },
+    { GRUB_INSTALL_PLATFORM_ARM_EFI,          "arm",     "efi"       },
+    { GRUB_INSTALL_PLATFORM_ARM_UBOOT,        "arm",     "uboot"     },
+  }; 
+
+char *
+grub_install_get_platform_name (enum grub_install_plat platid)
+{
+  return xasprintf ("%s-%s", platforms[platid].cpu,
+		    platforms[platid].platform);
+}
+
+const char *
+grub_install_get_platform_cpu (enum grub_install_plat platid)
+{
+  return platforms[platid].cpu;
+}
+
+const char *
+grub_install_get_platform_platform (enum grub_install_plat platid)
+{
+  return platforms[platid].platform;
+}
+
+int
+grub_install_is_regular_file (const char *dir)
+{
+  struct stat st;
+  if (stat (dir, &st) < 0)
+    return 0;
+  return S_ISREG (st.st_mode);
+}
+
+void
+grub_install_copy_files (const char *src,
+			 const char *dst,
+			 enum grub_install_plat platid)
+{
+  char *dst_platform, *dst_locale, *dst_fonts;
+  char *platform = xasprintf ("%s-%s", platforms[platid].cpu,
+			      platforms[platid].platform);
+  const char *pkgdatadir = secure_getenv ("pkgdatadir");
+  if (!pkgdatadir)
+    pkgdatadir = GRUB_DATADIR "/" PACKAGE;
+
+  dst_platform = grub_install_concat (2, dst, platform);
+  dst_locale = grub_install_concat (2, dst, "locale");
+  dst_fonts = grub_install_concat (2, dst, "fonts");
+  grub_install_mkdir_p (dst_platform);
+  grub_install_mkdir_p (dst_locale);
+  clean_grub_dir (dst);
+  clean_grub_dir (dst_platform);
+  clean_grub_dir (dst_locale);
+
+  if (install_modules.is_default)
+    copy_by_ext (src, dst_platform, ".mod", 1);
+  else
+    {
+      struct grub_util_path_list *path_list, *p;
+
+      path_list = grub_util_resolve_dependencies (src, "moddep.lst",
+						  install_modules.entries);
+      for (p = path_list; p; p = p->next)
+	{
+	  char *srcf = grub_install_concat_ext (2, src, p->name, ".mo");
+	  char *dstf = grub_install_concat_ext (2, dst, p->name, ".mo");
+	  grub_install_compress_file (srcf, dstf, 1);
+	  free (srcf);
+	  free (dstf);
+	}
+    }
+
+  const char *pkglib_DATA[] = {"efiemu32.o", "efiemu64.o",
+			       "moddep.lst", "command.lst",
+			       "fs.lst", "partmap.lst",
+			       "parttool.lst",
+			       "video.lst", "crypto.lst",
+			       "terminal.lst" };
+  size_t i;
+
+  for (i = 0; i < ARRAY_SIZE (pkglib_DATA); i++)
+    {
+      char *srcf = grub_install_concat (2, src, pkglib_DATA[i]);
+      char *dstf = grub_install_concat (2, dst_platform, pkglib_DATA[i]);
+      if (i == 0 || i == 1)
+	grub_install_compress_file (srcf, dstf, 0);
+      else
+	grub_install_compress_file (srcf, dstf, 1);
+      free (srcf);
+      free (dstf);
+    }
+
+  if (install_locales.is_default)
+    {
+      char *srcd = grub_install_concat (2, src, "po");
+      copy_by_ext (srcd, dst_locale, ".mo", 0);
+      copy_locales (dst_locale);
+      free (srcd);
+    }
+  else
+    {
+      for (i = 0; i < install_locales.n_entries; i++)
+	{
+	  char *srcf = grub_install_concat_ext (3, src,
+						"po",
+						install_locales.entries[i],
+						".mo");
+	  char *dstf = grub_install_concat_ext (2, dst_locale,
+						install_locales.entries[i],
+						".mo");
+	  if (grub_install_compress_file (srcf, dstf, 0))
+	    {
+	      free (srcf);
+	      free (dstf);
+	      continue;
+	    }
+	  free (srcf);
+	  srcf = grub_install_concat_ext (4,
+						 LOCALEDIR,
+						 install_locales.entries[i],
+						 "LC_MESSAGES",
+						 PACKAGE,
+						 ".mo");
+	  if (grub_install_compress_file (srcf, dstf, 0))
+	    {
+	      free (srcf);
+	      free (dstf);
+	      continue;
+	    }
+	  grub_util_error (_("cannot find locale `%s'"),
+			   install_locales.entries[i]);
+	}
+    }
+
+  if (install_themes.is_default)
+    {
+      install_themes.is_default = 0;
+      install_themes.n_entries = 1;
+      install_themes.entries = xmalloc (2 * sizeof (install_themes.entries[0]));
+      install_themes.entries[0] = xstrdup ("starfield");
+      install_themes.entries[1] = NULL;
+    }
+
+  for (i = 0; i < install_themes.n_entries; i++)
+    {
+      char *srcf = grub_install_concat (4, pkgdatadir, "themes",
+					install_themes.entries[i],
+					"theme.txt");
+      if (grub_install_is_regular_file (srcf))
+	{
+	  char *srcd = grub_install_concat (3, pkgdatadir, "themes",
+					    install_themes.entries[i]);
+	  char *dstd = grub_install_concat (3, dst, "themes",
+					    install_themes.entries[i]);
+	  copy_all (srcd, dstd);
+	  free (srcd);
+	  free (dstd);
+	}
+    }
+
+  if (install_fonts.is_default)
+    {
+      install_fonts.is_default = 0;
+      install_fonts.n_entries = 1;
+      install_fonts.entries = xmalloc (2 * sizeof (install_fonts.entries[0]));
+      install_fonts.entries[0] = xstrdup ("unicode");
+      install_fonts.entries[1] = NULL;
+    }
+
+  for (i = 0; i < install_fonts.n_entries; i++)
+    {
+      char *srcf = grub_install_concat_ext (2, pkgdatadir,
+						   install_fonts.entries[i],
+						   ".pf2");
+      char *dstf = grub_install_concat_ext (2, dst_fonts,
+						   install_fonts.entries[i],
+						   ".pf2");
+
+      grub_install_compress_file (srcf, dstf, 0);
+      free (srcf);
+      free (dstf);
+    }
+}
+
+enum grub_install_plat
+grub_install_get_target (const char *src)
+{
+  char *fn;
+  FILE *f;
+  char buf[2048];
+  size_t r;
+  char *c, *pl, *p;
+  size_t i;
+  fn = grub_install_concat (2, src, "modinfo.sh");
+  f = fopen (fn, "r");
+  if (!f)
+    grub_util_error (_("%s doesn't exist. Please specify --target or --directory"), 
+		     fn);
+  r = fread (buf, 1, sizeof (buf) - 1, f);
+  buf[r] = '\0';
+  c = strstr (buf, "grub_modinfo_target_cpu=");
+  if (!c || (c != buf && !grub_isspace (*(c-1))))
+    grub_util_error (_("invalid modinfo file `%s'"), fn);
+  pl = strstr (buf, "grub_modinfo_platform=");
+  if (!pl || (pl != buf && !grub_isspace (*(pl-1))))
+    grub_util_error (_("invalid modinfo file `%s'"), fn);
+  c += sizeof ("grub_modinfo_target_cpu=") - 1;
+  pl += sizeof ("grub_modinfo_platform=") - 1;
+  for (p = c; *p && !grub_isspace (*p); p++);
+  *p = '\0';
+  for (p = pl; *p && !grub_isspace (*p); p++);
+  *p = '\0';
+
+  for (i = 0; i < ARRAY_SIZE (platforms); i++)
+    if (strcmp (platforms[i].cpu, c) == 0
+	&& strcmp (platforms[i].platform, pl) == 0)
+      return platforms[i].val;
+  grub_util_error (_("Unknown platform `%s-%s'"), c, pl);
+}

=== added file 'util/grub-install.c'
--- util/grub-install.c	1970-01-01 00:00:00 +0000
+++ util/grub-install.c	2013-10-04 14:37:48 +0000
@@ -0,0 +1,1684 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010,2011,2012,2013 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 <config.h>
+#include <grub/types.h>
+#include <grub/emu/misc.h>
+#include <grub/util/misc.h>
+#include <grub/misc.h>
+#include <grub/device.h>
+#include <grub/disk.h>
+#include <grub/file.h>
+#include <grub/fs.h>
+#include <grub/env.h>
+#include <grub/term.h>
+#include <grub/mm.h>
+#include <grub/lib/hexdump.h>
+#include <grub/crypto.h>
+#include <grub/command.h>
+#include <grub/i18n.h>
+#include <grub/zfs/zfs.h>
+#include <grub/util/install.h>
+#include <grub/emu/getroot.h>
+#include <grub/diskfilter.h>
+#include <grub/cryptodisk.h>
+#include <grub/legacy_parse.h>
+#include <grub/gpt_partition.h>
+
+#include <string.h>
+#include <dirent.h>
+
+#include "argp.h"
+
+#include "progname.h"
+
+static char *target;
+static int removable = 0;
+static int recheck = 0;
+static int update_nvram = 1;
+static char *install_device = NULL;
+static char *debug_image = NULL;
+static char *rootdir = NULL;
+static char *bootdir = NULL;
+static int efi_quiet = 0;
+static int allow_floppy = 0;
+static int force_file_id = 0;
+static char *disk_module = NULL;
+static char *efidir = NULL;
+static int force = 0;
+static int have_abstractions = 0;
+static int have_cryptodisk = 0;
+static char * bootloader_id;
+static int have_load_cfg = 0;
+static FILE * load_cfg_f = NULL;
+static char *load_cfg;
+
+enum
+  {
+    OPTION_BOOT_DIRECTORY = 0x301,
+    OPTION_ROOT_DIRECTORY,
+    OPTION_TARGET,
+    OPTION_SETUP,
+    OPTION_MKRELPATH, 
+    OPTION_MKDEVICEMAP, 
+    OPTION_PROBE, 
+    OPTION_EDITENV, 
+    OPTION_ALLOW_FLOPPY, 
+    OPTION_RECHECK, 
+    OPTION_FORCE,
+    OPTION_FORCE_FILE_ID,
+    OPTION_MODULE, 
+    OPTION_NO_NVRAM, 
+    OPTION_REMOVABLE, 
+    OPTION_BOOTLOADER_ID, 
+    OPTION_EFI_DIRECTORY,
+    OPTION_FONT,
+    OPTION_DEBUG,
+    OPTION_DEBUG_IMAGE,
+    OPTION_NO_FLOPPY,
+    OPTION_DISK_MODULE
+  };
+
+static error_t 
+argp_parser (int key, char *arg, struct argp_state *state)
+{
+  if (grub_install_parse (key, arg))
+    return 0;
+  switch (key)
+    {
+    case OPTION_FORCE_FILE_ID:
+      force_file_id = 1;
+      return 0;
+      /* Accept and ignore for compatibility.  */
+    case OPTION_FONT:
+    case OPTION_SETUP:
+    case OPTION_MKRELPATH:
+    case OPTION_PROBE:
+    case OPTION_EDITENV:
+    case OPTION_MKDEVICEMAP:
+    case OPTION_NO_FLOPPY:
+      return 0;
+    case OPTION_ROOT_DIRECTORY:
+      /* Accept for compatibility.  */
+      free (rootdir);
+      rootdir = xstrdup (arg);
+      return 0;
+
+    case OPTION_BOOT_DIRECTORY:
+      free (bootdir);
+      bootdir = xstrdup (arg);
+      return 0;
+
+    case OPTION_EFI_DIRECTORY:
+      free (efidir);
+      efidir = xstrdup (arg);
+      return 0;
+
+    case OPTION_DISK_MODULE:
+      free (disk_module);
+      disk_module = xstrdup (arg);
+      return 0;
+
+    case OPTION_TARGET:
+      free (target);
+      target = xstrdup (arg);
+      return 0;
+
+    case OPTION_DEBUG_IMAGE:
+      free (debug_image);
+      debug_image = xstrdup (arg);
+      return 0;
+
+    case OPTION_NO_NVRAM:
+      update_nvram = 0;
+      return 0;
+
+    case OPTION_FORCE:
+      force = 1;
+      return 0;
+
+    case OPTION_RECHECK:
+      recheck = 1;
+      return 0;
+
+    case OPTION_REMOVABLE:
+      removable = 1;
+      return 0;
+
+    case OPTION_ALLOW_FLOPPY:
+      allow_floppy = 1;
+      return 0;
+
+    case OPTION_DEBUG:
+      verbosity++;
+      return 0;
+
+    case OPTION_BOOTLOADER_ID:
+      free (bootloader_id);
+      bootloader_id = xstrdup (arg);
+      return 0;
+
+    case ARGP_KEY_ARG:
+      if (install_device)
+	grub_util_error ("%s", _("More than one install device?"));
+      install_device = xstrdup (arg);
+      return 0;
+
+    default:
+      return ARGP_ERR_UNKNOWN;
+    }
+}
+
+
+static struct argp_option options[] = {
+  GRUB_INSTALL_OPTIONS,
+  {"boot-directory", OPTION_BOOT_DIRECTORY, N_("DIR"),
+   0, N_("install GRUB images under the directory DIR/%s instead of the %s directory"), 2},
+  {"root-directory", OPTION_ROOT_DIRECTORY, N_("DIR"),
+   OPTION_HIDDEN, 0, 2},
+  {"font", OPTION_FONT, N_("FILE"),
+   OPTION_HIDDEN, 0, 2},
+  {"target", OPTION_TARGET, N_("TARGET"),
+   /* TRANSLATORS: "TARGET" as in "target platform".  */
+   0, N_("install GRUB for TARGET platform [default=%s]"), 2},
+  {"grub-setup", OPTION_SETUP, "FILE", OPTION_HIDDEN, 0, 2},
+  {"grub-mkrelpath", OPTION_MKRELPATH, "FILE", OPTION_HIDDEN, 0, 2},
+  {"grub-mkdevicemap", OPTION_MKDEVICEMAP, "FILE", OPTION_HIDDEN, 0, 2},
+  {"grub-probe", OPTION_PROBE, "FILE", OPTION_HIDDEN, 0, 2},
+  {"grub-editenv", OPTION_EDITENV, "FILE", OPTION_HIDDEN, 0, 2},
+  {"allow-floppy", OPTION_ALLOW_FLOPPY, 0, 0,
+   /* TRANSLATORS: "may break" doesn't just mean that option wouldn't have any
+      effect but that it will make the resulting install unbootable from HDD. */
+   N_("make the drive also bootable as floppy (default for fdX devices)."
+      " May break on some BIOSes."), 2},
+  {"recheck", OPTION_RECHECK, 0, 0,
+   N_("delete device map if it already exists"), 2},
+  {"force", OPTION_FORCE, 0, 0,
+   N_("install even if problems are detected"), 2},
+  {"force-file-id", OPTION_FORCE_FILE_ID, 0, 0,
+   N_("use identifier file even if UUID is available"), 2},
+  {"disk-module", OPTION_MODULE, N_("MODULE"), 0,
+   N_("disk module to use (biosdisk or native). "
+      "This option is only available on BIOS target."), 2},
+  {"no-nvram", OPTION_NO_NVRAM, 0, 0,
+   N_("don't update the `boot-device' NVRAM variable. "
+      "This option is only available on IEEE1275 targets."), 2},
+
+  {"debug", OPTION_DEBUG, 0, OPTION_HIDDEN, 0, 2},
+  {"no-floppy", OPTION_NO_FLOPPY, 0, OPTION_HIDDEN, 0, 2},
+  {"debug-image", OPTION_DEBUG_IMAGE, "STR", OPTION_HIDDEN, 0, 2},
+  {"removable", OPTION_REMOVABLE, 0, 0,
+   N_("the installation device is removable. "
+      "This option is only available on EFI."), 2},
+  {"bootloader-id", OPTION_BOOTLOADER_ID, N_("ID"), 0,
+   N_("the ID of bootloader. This option is only available on EFI."), 2},
+  {"efi-directory", OPTION_EFI_DIRECTORY, N_("DIR"), 0,
+   N_("use DIR as the EFI System Partition root."), 2},
+  {0, 0, 0, 0, 0, 0}
+};
+
+static int
+is_directory (const char *dir)
+{
+  struct stat st;
+  if (stat (dir, &st) < 0)
+    return 0;
+  return S_ISDIR (st.st_mode);
+}
+
+#ifdef __linux__
+static int
+is_not_empty_directory (const char *dir)
+{
+  DIR *d;
+  struct dirent *de;
+
+  d = opendir (dir);
+  if (!d)
+    return 0;
+  while ((de = readdir (d)))
+    {
+      if (strcmp (de->d_name, ".") == 0
+	  || strcmp (de->d_name, "..") == 0)
+	continue;
+      closedir (d);
+      return 1;
+    }
+
+  closedir (d);
+  return 0;
+}
+
+
+#include <sys/utsname.h>
+
+static int
+is_64_kernel (void)
+{
+  struct utsname un;
+
+  if (uname (&un) < 0)
+    return 0;
+
+  return strcmp (un.machine, "x86_64") == 0;
+}
+
+#endif
+
+static const char *
+get_default_platform (void)
+{
+#ifdef __powerpc__
+   return "powerpc-ieee1275";
+#elif defined (__sparc__) || defined (__sparc64__)
+   return "sparc64-ieee1275";
+#elif defined (__MIPSEL__)
+   return "mipsel-loongson";
+#elif defined (__MIPSEB__)
+   return "mips-arc";
+#elif defined (__ia64__)
+   return "ia64-efi";
+#elif defined (__arm__)
+   return "arm-uboot";
+#elif defined (__amd64__) || defined (__x86_64__) || defined (__i386__)
+   /*
+     On Linux, we need the efivars kernel modules.
+     If no EFI is available this module just does nothing
+     besides a small hello and if we detect efi we'll load it
+     anyway later. So it should be safe to
+     try to load it here.
+   */
+#ifdef __linux__
+   grub_util_exec ((char * []){ (char *) "modprobe", (char *) "-q",
+	 (char *) "efivars", NULL });
+#endif
+   if (is_not_empty_directory ("/sys/firmware/efi"))
+     {
+       if (is_64_kernel ())
+	 return "x86_64-efi";
+       else
+	 return "i386-efi";
+     }
+   else if (is_not_empty_directory ("/proc/device-tree"))
+     return "i386-ieee1275";
+   else
+     return "i386-pc";
+#else
+   return NULL;
+#endif
+}
+
+static char *
+help_filter (int key, const char *text, void *input __attribute__ ((unused)))
+{
+  switch (key)
+    {
+    case OPTION_BOOT_DIRECTORY:
+      return xasprintf (text, GRUB_DIR_NAME, GRUB_BOOT_DIR_NAME "/" GRUB_DIR_NAME);
+    case OPTION_TARGET:
+      return xasprintf (text, get_default_platform ());
+    case ARGP_KEY_HELP_POST_DOC:
+      return xasprintf (text, program_name, GRUB_BOOT_DIR_NAME "/" GRUB_DIR_NAME);
+    default:
+      return grub_install_help_filter (key, text, input);
+    }
+}
+
+/* TRANSLATORS: INSTALL_DEVICE isn't an identifier and is the DEVICE you
+   install to.  */
+struct argp argp = {
+  options, argp_parser, N_("[OPTION] [INSTALL_DEVICE]"),
+  N_("Install GRUB on your drive.")"\v"
+  N_("INSTALL_DEVICE must be system device filename.\n"
+     "%s copies GRUB images into %s.  On some platforms, it"
+     " may also install GRUB into the boot sector."), 
+  NULL, help_filter, NULL
+};
+
+static int
+probe_raid_level (grub_disk_t disk)
+{
+  /* disk might be NULL in the case of a LVM physical volume with no LVM
+     signature.  Ignore such cases here.  */
+  if (!disk)
+    return -1;
+
+  if (disk->dev->id != GRUB_DISK_DEVICE_DISKFILTER_ID)
+    return -1;
+
+  if (disk->name[0] != 'm' || disk->name[1] != 'd')
+    return -1;
+
+  if (!((struct grub_diskfilter_lv *) disk->data)->segments)
+    return -1;
+  return ((struct grub_diskfilter_lv *) disk->data)->segments->type;
+}
+
+static void
+probe_mods (grub_disk_t disk)
+{
+  grub_partition_t part;
+  grub_disk_memberlist_t list = NULL, tmp;
+  int raid_level;
+
+  if (disk->partition == NULL)
+    grub_util_info ("no partition map found for %s", disk->name);
+
+  for (part = disk->partition; part; part = part->parent)
+    {
+      char buf[50];
+      if (strcmp (part->partmap->name, "openbsd") == 0
+	  || strcmp (part->partmap->name, "netbsd") == 0)
+	{
+	  grub_install_push_module ("part_bsd");
+	  continue;
+	}
+      snprintf (buf, sizeof (buf), "part_%s", part->partmap->name);
+      grub_install_push_module (buf);
+    }
+
+  if (disk->dev->id == GRUB_DISK_DEVICE_DISKFILTER_ID)
+    {
+      grub_diskfilter_get_partmap (disk, grub_install_push_module);
+      have_abstractions = 1;
+    }
+
+  if (disk->dev->id == GRUB_DISK_DEVICE_DISKFILTER_ID
+      && (grub_memcmp (disk->name, "lvm/", sizeof ("lvm/") - 1) == 0 ||
+	  grub_memcmp (disk->name, "lvmid/", sizeof ("lvmid/") - 1) == 0))
+    grub_install_push_module ("lvm");
+
+  if (disk->dev->id == GRUB_DISK_DEVICE_DISKFILTER_ID
+      && grub_memcmp (disk->name, "ldm/", sizeof ("ldm/") - 1) == 0)
+    grub_install_push_module ("ldm");
+
+  if (disk->dev->id == GRUB_DISK_DEVICE_CRYPTODISK_ID)
+    {
+      grub_util_cryptodisk_get_abstraction (disk,
+					    grub_install_push_module);
+      have_abstractions = 1;
+      have_cryptodisk = 1;
+    }
+
+  raid_level = probe_raid_level (disk);
+  if (raid_level >= 0)
+    {
+      grub_install_push_module ("diskfilter");
+      if (disk->dev->raidname)
+	grub_install_push_module (disk->dev->raidname (disk));
+    }
+  if (raid_level == 5)
+    grub_install_push_module ("raid5rec");
+  if (raid_level == 6)
+    grub_install_push_module ("raid6rec");
+
+  /* In case of LVM/RAID, check the member devices as well.  */
+  if (disk->dev->memberlist)
+    list = disk->dev->memberlist (disk);
+  while (list)
+    {
+      probe_mods (list->disk);
+      tmp = list->next;
+      free (list);
+      list = tmp;
+    }
+}
+
+static int
+have_bootdev (enum grub_install_plat pl)
+{
+  switch (pl)
+    {
+    case GRUB_INSTALL_PLATFORM_I386_PC:
+    case GRUB_INSTALL_PLATFORM_I386_EFI:
+    case GRUB_INSTALL_PLATFORM_X86_64_EFI:
+    case GRUB_INSTALL_PLATFORM_IA64_EFI:
+    case GRUB_INSTALL_PLATFORM_ARM_EFI:
+    case GRUB_INSTALL_PLATFORM_I386_IEEE1275:
+    case GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275:
+    case GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275:
+    case GRUB_INSTALL_PLATFORM_MIPSEL_ARC:
+    case GRUB_INSTALL_PLATFORM_MIPS_ARC:
+      return 1;
+
+    case GRUB_INSTALL_PLATFORM_I386_QEMU:
+    case GRUB_INSTALL_PLATFORM_I386_COREBOOT:
+    case GRUB_INSTALL_PLATFORM_I386_MULTIBOOT:
+    case GRUB_INSTALL_PLATFORM_MIPSEL_QEMU_MIPS:
+    case GRUB_INSTALL_PLATFORM_MIPS_QEMU_MIPS:
+
+    case GRUB_INSTALL_PLATFORM_MIPSEL_LOONGSON:
+    case GRUB_INSTALL_PLATFORM_ARM_UBOOT:
+      return 0;
+    }
+  return 0;
+}
+
+static void
+probe_cryptodisk_uuid (grub_disk_t disk)
+{
+  grub_disk_memberlist_t list = NULL, tmp;
+
+  /* In case of LVM/RAID, check the member devices as well.  */
+  if (disk->dev->memberlist)
+    {
+      list = disk->dev->memberlist (disk);
+    }
+  while (list)
+    {
+      probe_cryptodisk_uuid (list->disk);
+      tmp = list->next;
+      free (list);
+      list = tmp;
+    }
+  if (disk->dev->id == GRUB_DISK_DEVICE_CRYPTODISK_ID)
+    {
+      const char *uuid = grub_util_cryptodisk_get_uuid (disk);
+      if (!load_cfg_f)
+	load_cfg_f = fopen (load_cfg, "wb");
+      have_load_cfg = 1;
+
+      fprintf (load_cfg_f, "cryptomount -u %s\n",
+	      uuid);
+    }
+}
+
+static int
+is_same_disk (const char *a, const char *b)
+{
+  while (1)
+    {
+      if ((*a == ',' || *a == '\0') && (*b == ',' || *b == '\0'))
+	return 1;
+      if (*a != *b)
+	return 0;
+      if (*a == '\\')
+	{
+	  if (a[1] != b[1])
+	    return 0;
+	  a += 2;
+	  b += 2;
+	  continue;
+	}
+      a++;
+      b++;
+    }
+}
+
+char *
+get_rndstr (void)
+{
+  grub_uint8_t rnd[15];
+  const size_t sz = sizeof (rnd) * GRUB_CHAR_BIT / 5;
+  char * ret = xmalloc (sz + 1);
+  size_t i;
+  if (grub_get_random (rnd, sizeof (rnd)))
+    grub_util_error ("%s", _("couldn't retrieve random data"));
+  for (i = 0; i < sz; i++)
+    {
+      grub_size_t b = i * 5;
+      grub_uint8_t r;
+      grub_size_t f1 = GRUB_CHAR_BIT - b % GRUB_CHAR_BIT;
+      grub_size_t f2;
+      if (f1 > 5)
+	f1 = 5;
+      f2 = 5 - f1;
+      r = (rnd[b / GRUB_CHAR_BIT] >> (b % GRUB_CHAR_BIT)) & ((1 << f1) - 1);
+      if (f2)
+	r |= (rnd[b / GRUB_CHAR_BIT + 1] & ((1 << f2) - 1)) << f1;
+      if (r < 10)
+	ret[i] = '0' + r;
+      else
+	ret[i] = 'a' + (r - 10);
+    }
+  ret[sz] = '\0';
+  return ret;
+}
+
+static char *
+escape (const char *in)
+{
+  char *ptr;
+  char *ret;
+  int overhead = 0;
+
+  for (ptr = (char*)in; *ptr; ptr++)
+    if (*ptr == '\'')
+      overhead += 3;
+  ret = grub_malloc (ptr - in + overhead + 1);
+  if (!ret)
+    return NULL;
+
+  grub_strchrsub (ret, in, '\'', "'\\''");
+  return ret;
+}
+
+static int is_cryptodisk_enabled = 0;
+static char *grub_distributor = 0;
+
+static int
+load_config (void)
+{
+  char *fn = grub_install_concat (3, GRUB_SYSCONFDIR,
+				  "default", "grub");
+  FILE *f = fopen (fn, "r");
+  const char *v;
+  v = secure_getenv ("GRUB_ENABLE_CRYPTODISK");
+  if (v && v[0] == 'y' && v[1] == '\0')
+    is_cryptodisk_enabled = 1;
+
+  v = secure_getenv ("GRUB_DISTRIBUTOR");
+  if (v)
+    grub_distributor = xstrdup (v);
+
+  if (f)
+    {
+      /* FIXME: GRUB_DISTRIBUTOR, GRUB_ENABLE_CRYPTODISK.  */
+      fclose (f);
+    }
+  return 0;
+}
+
+static void
+device_map_check_duplicates (const char *dev_map)
+{
+  FILE *fp;
+  char buf[1024];	/* XXX */
+  size_t alloced = 8;
+  size_t filled = 0;
+  char **d;
+  size_t i;
+
+  d = xmalloc (alloced * sizeof (d[0]));
+
+  if (dev_map[0] == '\0')
+    return;
+
+  fp = fopen (dev_map, "r");
+  if (! fp)
+    return;
+
+  while (fgets (buf, sizeof (buf), fp))
+    {
+      char *p = buf;
+      char *e;
+
+      /* Skip leading spaces.  */
+      while (*p && grub_isspace (*p))
+	p++;
+
+      /* If the first character is `#' or NUL, skip this line.  */
+      if (*p == '\0' || *p == '#')
+	continue;
+
+      if (*p != '(')
+	continue;
+
+      p++;
+
+      e = p;
+      p = strchr (p, ')');
+      if (! p)
+	continue;
+
+      if (filled >= alloced)
+	{
+	  alloced *= 2;
+	  d = xrealloc (d, alloced * sizeof (d[0]));
+	}
+
+      *p = '\0';
+
+      d[filled++] = xstrdup (e);
+    }
+
+  fclose (fp);
+
+  qsort (d, sizeof (d[0]), filled, (int (*) (const void *, const void *))strcmp);
+
+  for (i = 0; i + 1 < filled; i++)
+    if (strcmp (d[i], d[i+1]) == 0)
+      {
+	grub_util_error ("the drive %s is defined multiple times in the device map %s",
+			 d[i], dev_map);
+      }
+
+  for (i = 0; i < filled; i++)
+    free (d[i]);
+
+  free (d);
+}
+
+static grub_err_t
+write_to_disk (grub_device_t dev, const char *fn)
+{
+  char *core_img;
+  size_t core_size;
+  grub_err_t err;
+
+  core_size = grub_util_get_image_size (fn);
+
+  core_img = grub_util_read_image (fn);    
+
+  err = grub_disk_write (dev->disk, 0, 0,
+			 core_size, core_img);
+  free (core_img);
+  return err;
+}
+
+static int
+is_prep_partition (grub_device_t dev)
+{
+  if (!dev->disk)
+    return 0;
+  if (!dev->disk->partition)
+    return 0;
+  if (strcmp(dev->disk->partition->partmap->name, "msdos") == 0)
+    return (dev->disk->partition->msdostype == 0x41);
+
+  if (strcmp (dev->disk->partition->partmap->name, "gpt") == 0)
+    {
+      struct grub_gpt_partentry gptdata;
+      grub_partition_t p = dev->disk->partition;
+      int ret = 0;
+      dev->disk->partition = dev->disk->partition->parent;
+
+      if (grub_disk_read (dev->disk, p->offset, p->index,
+			  sizeof (gptdata), &gptdata) == 0)
+	{
+	  const grub_gpt_part_type_t template = {
+	    grub_cpu_to_le32_compile_time (0x9e1a2d38),
+	    grub_cpu_to_le16_compile_time (0xc612),
+	    grub_cpu_to_le16_compile_time (0x4316),
+	    { 0xaa, 0x26, 0x8b, 0x49, 0x52, 0x1e, 0x5a, 0x8b }
+	  };
+
+	  ret = grub_memcmp (&template, &gptdata.type,
+			     sizeof (template)) == 0;
+	}
+      dev->disk->partition = p;
+      return ret;
+    }
+
+  return 0;
+}
+
+static int
+is_prep_empty (grub_device_t dev)
+{
+  grub_disk_addr_t dsize, addr;
+  grub_uint32_t buffer[32768];
+
+  dsize = grub_disk_get_size (dev->disk);
+  for (addr = 0; addr < dsize;
+       addr += sizeof (buffer) / GRUB_DISK_SECTOR_SIZE)
+    {
+      grub_size_t sz = sizeof (buffer);
+      grub_uint32_t *ptr;
+
+      if (sizeof (buffer) / GRUB_DISK_SECTOR_SIZE > dsize - addr)
+	sz = (dsize - addr) * GRUB_DISK_SECTOR_SIZE;
+      grub_disk_read (dev->disk, addr, 0, sz, buffer);
+
+      if (addr == 0 && grub_memcmp (buffer, ELFMAG, SELFMAG) == 0)
+	return 1;
+
+      for (ptr = buffer; ptr < buffer + sz / sizeof (*buffer); ptr++)
+	if (*ptr)
+	  return 0;
+    }
+
+  return 1;
+}
+
+static void
+remove_old_efi_entries (const char *efi_distributor)
+{
+  int fd;
+  pid_t pid = grub_util_exec_pipe ((char * []){ (char *) "efibootmgr", NULL }, &fd);
+  char *line = NULL;
+  size_t len = 0;
+
+  if (!pid)
+    {
+      grub_util_warn (_("Unable to open stream from %s: %s"),
+		      "efibootmgr", strerror (errno));
+      return;
+    }
+
+  FILE *fp = fdopen (fd, "r");
+  if (!fp)
+    {
+      grub_util_warn (_("Unable to open stream from %s: %s"),
+		      "efibootmgr", strerror (errno));
+      return;
+    }
+
+  line = xmalloc (80);
+  len = 80;
+  while (1)
+    {
+      int ret;
+      char *bootnum;
+      ret = getline (&line, &len, fp);
+      if (ret == -1)
+	break;
+      if (grub_memcmp (line, "Boot", sizeof ("Boot") - 1) != 0
+	  || line[sizeof ("Boot") - 1] < '0'
+	  || line[sizeof ("Boot") - 1] > '9')
+	continue;
+      if (!strcasestr (line, efi_distributor))
+	continue;
+      bootnum = line + sizeof ("Boot") - 1;
+      bootnum[4] = '\0';
+      if (efi_quiet)
+	grub_util_exec ((char * []){ (char *) "efibootmgr", (char *) "--quiet",
+	      (char *) "-b", bootnum, (char *) "-B", NULL });
+      else
+	grub_util_exec ((char * []){ (char *) "efibootmgr",
+	      (char *) "-b", bootnum, (char *) "-B", NULL });
+    }
+
+  free (line);
+}
+
+static char *
+get_ofpathname (const char *dev)
+{
+  char *ret = xmalloc (2 * PATH_MAX);
+  char *end = ret + 2 * PATH_MAX - 1;
+  int fd;
+  pid_t pid;
+  char *ptr = ret;
+
+  pid = grub_util_exec_pipe ((char * []){ (char *) "ofpathname",
+	(char *) dev, NULL }, &fd);
+  if (!pid)
+    goto fail;
+
+  FILE *fp = fdopen (fd, "r");
+  if (!fp)
+    goto fail;
+
+  while (!feof (fp) && ptr < end)
+    {
+      size_t r;
+      r = fread (ptr, 1, end - ptr, fp);
+      ptr += r;
+    }
+
+  fclose (fp);
+
+  return ret;
+
+ fail:
+  grub_util_error (_("couldn't find IEEE1275 device tree path for %s.\nYou will have to set `boot-device' variable manually"),
+		   dev);
+}
+
+int
+main (int argc, char *argv[])
+{
+  int is_efi = 0;
+  const char *efi_distributor;
+  const char *efi_file = NULL;
+  char **grub_devices;
+  grub_fs_t grub_fs;
+  grub_device_t grub_dev = NULL;
+  enum grub_install_plat platform;
+  char *grubdir, *device_map;
+  char **curdev, **curdrive;
+  char **grub_drives;
+  char *relative_grubdir;
+  char **efidir_device_names;
+  grub_device_t efidir_grub_dev;
+  char *efidir_grub_devname;
+
+  set_program_name (argv[0]);
+
+  grub_util_init_nls ();
+
+  argp_parse (&argp, argc, argv, 0, 0, 0);
+
+  grub_install_args_finish ();
+
+  if (verbosity > 1)
+    grub_env_set ("debug", "all");
+
+  load_config ();
+
+  if (!bootloader_id && grub_distributor)
+    {
+      char *ptr;
+      bootloader_id = xstrdup (grub_distributor);
+      for (ptr = bootloader_id; *ptr && *ptr != ' '; ptr++)
+	if (*ptr >= 'A' && *ptr <= 'Z')
+	  *ptr = *ptr - 'A' + 'a';
+      *ptr = '\0';
+    }
+  if (!bootloader_id || bootloader_id[0] == '\0')
+    {
+      free (bootloader_id);
+      bootloader_id = xstrdup ("grub");
+    }
+
+  if (!grub_install_source_directory)
+    {
+      if (!target)
+	{
+	  const char * t;
+	  t = get_default_platform ();
+	  if (!t)
+	    grub_util_error ("%s", 
+			     _("Unable to determine your platform."
+			       " Use --target.")
+			     );
+	  target = xstrdup (t); 
+	}
+      grub_install_source_directory
+	= grub_install_concat (3, GRUB_LIBDIR, PACKAGE, target);
+    }
+
+  platform = grub_install_get_target (grub_install_source_directory);
+
+  switch (platform)
+    {
+    case GRUB_INSTALL_PLATFORM_I386_PC:
+      if (!disk_module)
+	disk_module = xstrdup ("biosdisk");
+      break;
+    case GRUB_INSTALL_PLATFORM_I386_EFI:
+    case GRUB_INSTALL_PLATFORM_X86_64_EFI:
+    case GRUB_INSTALL_PLATFORM_ARM_EFI:
+    case GRUB_INSTALL_PLATFORM_IA64_EFI:
+    case GRUB_INSTALL_PLATFORM_I386_IEEE1275:
+    case GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275:
+    case GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275:
+    case GRUB_INSTALL_PLATFORM_MIPSEL_ARC:
+    case GRUB_INSTALL_PLATFORM_MIPS_ARC:
+    case GRUB_INSTALL_PLATFORM_ARM_UBOOT:
+      break;
+
+    case GRUB_INSTALL_PLATFORM_I386_QEMU:
+    case GRUB_INSTALL_PLATFORM_I386_COREBOOT:
+    case GRUB_INSTALL_PLATFORM_I386_MULTIBOOT:
+    case GRUB_INSTALL_PLATFORM_MIPSEL_LOONGSON:
+    case GRUB_INSTALL_PLATFORM_MIPSEL_QEMU_MIPS:
+    case GRUB_INSTALL_PLATFORM_MIPS_QEMU_MIPS:
+      disk_module = xstrdup ("native");
+      break;
+    }
+
+  switch (platform)
+    {
+    case GRUB_INSTALL_PLATFORM_I386_PC:
+    case GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275:
+      if (!install_device)
+	grub_util_error ("%s", _("install device isn't specified"));
+      break;
+    case GRUB_INSTALL_PLATFORM_MIPS_ARC:
+    case GRUB_INSTALL_PLATFORM_MIPSEL_ARC:
+    case GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275:
+      break;
+    case GRUB_INSTALL_PLATFORM_I386_EFI:
+    case GRUB_INSTALL_PLATFORM_X86_64_EFI:
+    case GRUB_INSTALL_PLATFORM_ARM_EFI:
+    case GRUB_INSTALL_PLATFORM_IA64_EFI:
+    case GRUB_INSTALL_PLATFORM_I386_IEEE1275:
+    case GRUB_INSTALL_PLATFORM_ARM_UBOOT:
+    case GRUB_INSTALL_PLATFORM_I386_QEMU:
+    case GRUB_INSTALL_PLATFORM_I386_COREBOOT:
+    case GRUB_INSTALL_PLATFORM_I386_MULTIBOOT:
+    case GRUB_INSTALL_PLATFORM_MIPSEL_LOONGSON:
+    case GRUB_INSTALL_PLATFORM_MIPSEL_QEMU_MIPS:
+    case GRUB_INSTALL_PLATFORM_MIPS_QEMU_MIPS:
+      free (install_device);
+      install_device = NULL;
+      break;
+    }
+
+  if (!bootdir)
+    bootdir = grub_install_concat (3, "/", rootdir, GRUB_BOOT_DIR_NAME);
+
+  {
+    char * t = grub_install_concat (2, bootdir, GRUB_DIR_NAME);
+    grub_install_mkdir_p (t);
+    grubdir = canonicalize_file_name (t);
+    if (!grubdir)
+      grub_util_error (_("failed to get canonical path of `%s'"), t);
+    free (t);
+  }
+  device_map = grub_install_concat (2, grubdir, "device.map");
+
+  if (recheck)
+    unlink (device_map);
+
+
+  device_map_check_duplicates (device_map);
+  grub_util_biosdisk_init (device_map);
+
+  /* Initialize all modules. */
+  grub_init_all ();
+  grub_gcry_init_all ();
+  switch (platform)
+    {
+    case GRUB_INSTALL_PLATFORM_I386_EFI:
+    case GRUB_INSTALL_PLATFORM_X86_64_EFI:
+    case GRUB_INSTALL_PLATFORM_ARM_EFI:
+    case GRUB_INSTALL_PLATFORM_IA64_EFI:
+      is_efi = 1;
+      break;
+    default:
+      is_efi = 0;
+      break;
+    }
+
+  /* Find the EFI System Partition.  */
+
+  if (is_efi)
+    {
+      grub_fs_t fs;
+      free (install_device);
+      install_device = NULL;
+      if (!efidir)
+	{
+	  char *d = grub_install_concat (2, bootdir, "efi");
+	  char *dr = NULL;
+	  if (!is_directory (d))
+	    {
+	      free (d);
+	      d = grub_install_concat (2, bootdir, "EFI");
+	    }
+	  /*
+	    The EFI System Partition may have been given directly using
+	    --root-directory.
+	  */
+	  if (!is_directory (d)
+	      && rootdir && grub_strcmp (rootdir, "/") != 0)
+	    {
+	      free (d);
+	      d = xstrdup (rootdir);
+	    }
+	  if (is_directory (d))
+	    dr = grub_make_system_path_relative_to_its_root (d);
+	  /* Is it a mount point? */
+	  if (dr && dr[0] == '\0')
+	    efidir = d;
+	  else
+	    free (d);
+	  free (dr);
+	}
+      if (!efidir)
+	grub_util_error ("%s", _("cannot find EFI directory"));
+      efidir_device_names = grub_guess_root_devices (efidir);
+      if (!efidir_device_names || !efidir_device_names[0])
+	grub_util_error (_("cannot find a device for %s (is /dev mounted?)"),
+			     efidir);
+      install_device = efidir_device_names[0];
+
+      for (curdev = efidir_device_names; *curdev; curdev++)
+	  grub_util_pull_device (*curdev);
+      
+      efidir_grub_devname = grub_util_get_grub_dev (efidir_device_names[0]);
+      if (!efidir_grub_devname)
+	grub_util_error (_("cannot find a GRUB drive for %s.  Check your device.map"),
+			 efidir_device_names[0]);
+
+      efidir_grub_dev = grub_device_open (efidir_grub_devname);
+      if (! efidir_grub_dev)
+	grub_util_error ("%s", grub_errmsg);
+
+      fs = grub_fs_probe (efidir_grub_dev);
+      if (! fs)
+	grub_util_error ("%s", grub_errmsg);
+
+      if (grub_strcmp (fs->name, "fat") != 0)
+	grub_util_error (_("%s doesn't look like an EFI partition.\n"), efidir);
+
+      /* The EFI specification requires that an EFI System Partition must
+	 contain an "EFI" subdirectory, and that OS loaders are stored in
+	 subdirectories below EFI.  Vendors are expected to pick names that do
+	 not collide with other vendors.  To minimise collisions, we use the
+	 name of our distributor if possible.
+      */
+      char *t;
+      efi_distributor = bootloader_id;
+      if (removable)
+	{
+	  /* The specification makes stricter requirements of removable
+	     devices, in order that only one image can be automatically loaded
+	     from them.  The image must always reside under /EFI/BOOT, and it
+	     must have a specific file name depending on the architecture.
+	  */
+	  efi_distributor = "BOOT";
+	  switch (platform)
+	    {
+	    case GRUB_INSTALL_PLATFORM_I386_EFI:
+	      efi_file = "BOOTIA32.EFI";
+	      break;
+	    case GRUB_INSTALL_PLATFORM_X86_64_EFI:
+	      efi_file = "BOOTX64.EFI";
+	      break;
+	    case GRUB_INSTALL_PLATFORM_IA64_EFI:
+	      efi_file = "BOOTIA64.EFI";
+	      break;
+	    case GRUB_INSTALL_PLATFORM_ARM_EFI:
+	      efi_file = "BOOTARM.EFI";
+	      break;
+	    default:
+	      grub_util_error ("%s", _("You've found a bug"));
+	      break;
+	    }
+	}
+      else
+	{
+	  /* It is convenient for each architecture to have a different
+	     efi_file, so that different versions can be installed in parallel.
+	  */
+	  switch (platform)
+	    {
+	    case GRUB_INSTALL_PLATFORM_I386_EFI:
+	      efi_file = "grubia32.efi";
+	      break;
+	    case GRUB_INSTALL_PLATFORM_X86_64_EFI:
+	      efi_file = "grubx64.efi";
+	      break;
+	    case GRUB_INSTALL_PLATFORM_IA64_EFI:
+	      efi_file = "grubia64.efi";
+	      break;
+	    case GRUB_INSTALL_PLATFORM_ARM_EFI:
+	      efi_file = "grubarm.efi";
+	      break;
+	    default:
+	      efi_file = "grub.efi";
+	      break;
+	    }
+	}
+      t = grub_install_concat (3, efidir, "EFI", efi_distributor);
+      free (efidir);
+      efidir = t;
+      grub_install_mkdir_p (efidir);
+    }
+
+  grub_install_copy_files (grub_install_source_directory,
+			   grubdir, platform);
+
+  char *envfile = grub_install_concat (2, grubdir, "grubenv");
+  if (!grub_install_is_regular_file (envfile))
+    grub_install_create_envblk_file (envfile);
+
+  size_t ndev = 0;
+
+  /* Write device to a variable so we don't have to traverse /dev every time.  */
+  grub_devices = grub_guess_root_devices (grubdir);
+  if (!grub_devices || !grub_devices[0])
+    grub_util_error (_("cannot find a device for %s (is /dev mounted?)"),
+		     grubdir);
+
+  for (curdev = grub_devices; *curdev; curdev++)
+    {
+      grub_util_pull_device (*curdev);
+      ndev++;
+    }
+
+  grub_drives = xmalloc (sizeof (grub_drives[0]) * (ndev + 1)); 
+
+  for (curdev = grub_devices, curdrive = grub_drives; *curdev; curdev++,
+       curdrive++)
+    {
+      *curdrive = grub_util_get_grub_dev (*curdev);
+      if (! *curdrive)
+	grub_util_error (_("cannot find a GRUB drive for %s.  Check your device.map"),
+			 *curdev);
+    }
+  *curdrive = 0;
+
+  grub_dev = grub_device_open (grub_drives[0]);
+  if (! grub_dev)
+    grub_util_error ("%s", grub_errmsg);
+
+  grub_fs = grub_fs_probe (grub_dev);
+  if (! grub_fs)
+    grub_util_error ("%s", grub_errmsg);
+
+  grub_install_push_module (grub_fs->name);
+
+  if (grub_dev->disk)
+    probe_mods (grub_dev->disk);
+
+  for (curdrive = grub_drives + 1; *curdrive; curdrive++)
+    {
+      grub_device_t dev = grub_device_open (*curdrive);
+      if (!dev)
+	continue;
+      if (dev->disk)
+	probe_mods (dev->disk);
+      grub_device_close (dev);
+    }
+
+  if (!is_cryptodisk_enabled && have_cryptodisk)
+    grub_util_error (_("attempt to install to cryptodisk without cryptodisk enabled. "
+		       "Set `%s' in file `%s'."), "GRUB_ENABLE_CRYPTODISK=1", GRUB_SYSCONFDIR "/default/grub");
+
+  if (disk_module && grub_strcmp (disk_module, "ata") == 0)
+    grub_install_push_module ("pata");
+  else if (disk_module && grub_strcmp (disk_module, "native") == 0)
+    {
+      grub_install_push_module ("pata");
+      grub_install_push_module ("ahci");
+      grub_install_push_module ("ohci");
+      grub_install_push_module ("uhci");
+      grub_install_push_module ("usbms");
+    }
+  else if (disk_module && disk_module[0])
+    grub_install_push_module (disk_module);
+
+  relative_grubdir = grub_make_system_path_relative_to_its_root (grubdir);
+  if (relative_grubdir[0] == '\0')
+    {
+      free (relative_grubdir);
+      relative_grubdir = xstrdup ("/");
+    }
+
+  char *platname =  grub_install_get_platform_name (platform);
+  char *platdir;
+  {
+    char *t = grub_install_concat (2, grubdir,
+				   platname);
+    platdir = canonicalize_file_name (t);
+    if (!platdir)
+      grub_util_error (_("failed to get canonical path of `%s'"),
+		       t);
+    free (t);
+  }
+  load_cfg = grub_install_concat (2, platdir,
+				  "load.cfg");
+
+  unlink (load_cfg);
+
+  if (debug_image && debug_image[0])
+    {
+      load_cfg_f = fopen (load_cfg, "wb");
+      have_load_cfg = 1;
+      fprintf (load_cfg_f, "set debug='%s'\n",
+	      debug_image);
+    }
+  char *prefix_drive = NULL;
+  char *install_drive = NULL;
+
+  if (install_device)
+    {
+      if (install_device[0] == '('
+	  && install_device[grub_strlen (install_device) - 1] == ')')
+	install_drive = xstrdup (install_device);
+      else
+	{
+	  grub_util_pull_device (install_device);
+	  install_drive = grub_util_get_grub_dev (install_device);
+	  if (!install_drive)
+	    grub_util_error (_("cannot find a GRUB drive for %s.  Check your device.map"),
+			     install_device);
+	}
+    }
+
+  if (!have_abstractions)
+    {
+      if ((disk_module && grub_strcmp (disk_module, "biosdisk") != 0)
+	  || grub_drives[1]
+	  || (!install_drive
+	      && platform != GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275)
+	  || (install_drive && !is_same_disk (grub_drives[0], install_drive))
+	  || !have_bootdev (platform))
+	{
+	  char *uuid = NULL;
+	  /*  generic method (used on coreboot and ata mod).  */
+	  if (!force_file_id && grub_fs->uuid && grub_fs->uuid (grub_dev,
+								&uuid))
+	    {
+	      grub_print_error ();
+	      grub_errno = 0;
+	      uuid = NULL;
+	    }
+
+	  if (!load_cfg_f)
+	    load_cfg_f = fopen (load_cfg, "wb");
+	  have_load_cfg = 1;
+	  if (uuid)
+	    {
+	      fprintf (load_cfg_f, "search.fs_uuid %s root ",
+		      uuid);
+	      grub_install_push_module ("search_fs_uuid");
+	    }
+	  else
+	    {
+	      char *rndstr = get_rndstr ();
+	      char *fl = grub_install_concat (3, grubdir,
+						     "uuid", rndstr);
+	      char *fldir = grub_install_concat (2, grubdir,
+							"uuid");
+	      char *relfl;
+	      FILE *flf;
+	      grub_install_mkdir_p (fldir);
+	      flf = fopen (fl, "w");
+	      if (!flf)
+		grub_util_error ("Can't create file: %s", strerror (errno));
+	      fclose (flf);
+	      relfl = grub_make_system_path_relative_to_its_root (fl);
+	      fprintf (load_cfg_f, "search.file %s root ",
+		       relfl);
+	      grub_install_push_module ("search_fs_file");
+	    }
+	  if (disk_module && disk_module[0] && grub_strcmp (disk_module, "biosdisk") != 0)
+	    {
+	      /* FIXME: hints="`echo "${grub_device}" | xargs "$grub_probe" --device-map="${device_map}" --target=baremetal_hints --device`"
+	      */
+	    }
+	  else
+	    switch (platform)
+	      {
+	      case GRUB_INSTALL_PLATFORM_I386_PC:
+		/* FIXME: hints="`echo "${grub_device}" | xargs "$grub_probe" --device-map="${device_map}" --target=bios_hints --device`"*/
+		break;
+	      case GRUB_INSTALL_PLATFORM_I386_EFI:
+	      case GRUB_INSTALL_PLATFORM_X86_64_EFI:
+	      case GRUB_INSTALL_PLATFORM_ARM_EFI:
+	      case GRUB_INSTALL_PLATFORM_IA64_EFI:
+		/* FIXME:             hints="`echo "${grub_device}" | xargs "$grub_probe" --device-map="${device_map}" --target=efi_hints --device`"*/
+		break;
+	      case GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275:
+	      case GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275:
+	      case GRUB_INSTALL_PLATFORM_I386_IEEE1275:
+		/* FIXME:             hints="`echo "${grub_device}" | xargs "$grub_probe" --device-map="${device_map}" --target=ieee1275_hints --device`"*/
+		break;
+	      case GRUB_INSTALL_PLATFORM_MIPSEL_LOONGSON:
+	      case GRUB_INSTALL_PLATFORM_I386_QEMU:
+	      case GRUB_INSTALL_PLATFORM_I386_COREBOOT:
+	      case GRUB_INSTALL_PLATFORM_I386_MULTIBOOT:
+	      case GRUB_INSTALL_PLATFORM_MIPSEL_QEMU_MIPS:
+	      case GRUB_INSTALL_PLATFORM_MIPS_QEMU_MIPS:
+		/* FIXME:             hints="`echo "${grub_device}" | xargs "$grub_probe" --device-map="${device_map}" --target=baremetal_hints --device`"*(*/
+		break;
+	      case GRUB_INSTALL_PLATFORM_MIPS_ARC:
+	      case GRUB_INSTALL_PLATFORM_MIPSEL_ARC:
+	      case GRUB_INSTALL_PLATFORM_ARM_UBOOT:
+		grub_util_warn ("%s", _("no hints available for your platform. Expect reduced performance"));
+		break;
+	      }
+	  fprintf (load_cfg_f, "\n");
+	  char *escaped_relpath = escape (relative_grubdir);
+	  fprintf (load_cfg_f, "set prefix=($root)'%s'\n",
+		   escaped_relpath);
+	}
+      else
+	{
+	  /* We need to hardcode the partition number in the core image's prefix.  */
+	  char *p;
+	  for (p = grub_drives[0]; *p; )
+	    {
+	      if (*p == '\\' && p[1])
+		{
+		  p += 2;
+		  continue;
+		}
+	      if (*p == ',' || *p == '\0')
+		break;
+	      p++;
+	    }
+	  prefix_drive = xasprintf ("(%s)", p);
+	}
+    }
+  else
+    {
+      if (is_cryptodisk_enabled)
+	{
+	  if (grub_dev->disk)
+	    probe_cryptodisk_uuid (grub_dev->disk);
+
+	  for (curdrive = grub_drives + 1; *curdrive; curdrive++)
+	    {
+	      grub_device_t dev = grub_device_open (*curdrive);
+	      if (!dev)
+		continue;
+	      if (dev->disk)
+		probe_cryptodisk_uuid (dev->disk);
+	      grub_device_close (dev);
+	    }
+	}
+      prefix_drive = xasprintf ("(%s)", grub_drives[0]);
+    }
+
+  char mkimage_target[200];
+  const char *core_name = NULL;
+
+  switch (platform)
+    {
+    case GRUB_INSTALL_PLATFORM_I386_EFI:
+    case GRUB_INSTALL_PLATFORM_X86_64_EFI:
+    case GRUB_INSTALL_PLATFORM_ARM_EFI:
+    case GRUB_INSTALL_PLATFORM_IA64_EFI:
+      core_name = "core.efi";
+      snprintf (mkimage_target, sizeof (mkimage_target),
+		"%s-%s",
+		grub_install_get_platform_cpu (platform),
+		grub_install_get_platform_platform (platform));
+      break;
+    case GRUB_INSTALL_PLATFORM_MIPSEL_LOONGSON:
+    case GRUB_INSTALL_PLATFORM_MIPSEL_QEMU_MIPS:
+    case GRUB_INSTALL_PLATFORM_MIPS_QEMU_MIPS:
+      core_name = "core.elf";
+      snprintf (mkimage_target, sizeof (mkimage_target),
+		"%s-%s-elf",
+		grub_install_get_platform_cpu (platform),
+		grub_install_get_platform_platform (platform));
+      break;
+
+    case GRUB_INSTALL_PLATFORM_I386_COREBOOT:
+    case GRUB_INSTALL_PLATFORM_I386_MULTIBOOT:
+    case GRUB_INSTALL_PLATFORM_I386_IEEE1275:
+    case GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275:
+      core_name = "core.elf";
+      snprintf (mkimage_target, sizeof (mkimage_target),
+		"%s-%s",
+		grub_install_get_platform_cpu (platform),
+		grub_install_get_platform_platform (platform));
+      break;
+
+
+    case GRUB_INSTALL_PLATFORM_I386_PC:
+    case GRUB_INSTALL_PLATFORM_MIPSEL_ARC:
+    case GRUB_INSTALL_PLATFORM_MIPS_ARC:
+    case GRUB_INSTALL_PLATFORM_ARM_UBOOT:
+    case GRUB_INSTALL_PLATFORM_I386_QEMU:
+      snprintf (mkimage_target, sizeof (mkimage_target),
+		"%s-%s",
+		grub_install_get_platform_cpu (platform),
+		grub_install_get_platform_platform (platform));
+      core_name = "core.img";
+      break;
+    case GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275:
+      strcpy (mkimage_target, "sparc64-ieee1275-raw");
+      core_name = "core.img";
+      break;
+    }
+
+  if (!core_name)
+    grub_util_error ("%s", _("You've found a bug"));
+
+  if (load_cfg_f)
+    fclose (load_cfg_f);
+
+  char *imgfile = grub_install_concat (2, platdir,
+				       core_name);
+  char *prefix = xasprintf ("%s%s", prefix_drive ? : "",
+			    relative_grubdir);
+  grub_install_make_image_wrap (/* source dir  */ grub_install_source_directory,
+				       /*prefix */ prefix,
+				       /* output */ imgfile,
+				       /* memdisk */ NULL,
+				have_load_cfg ? load_cfg : NULL,
+				       /* image target */ mkimage_target,
+				0, GRUB_COMPRESSION_AUTO);
+  /* Backward-compatibility kludges.  */
+  switch (platform)
+    {
+    case GRUB_INSTALL_PLATFORM_MIPSEL_LOONGSON:
+      {
+	char *dst = grub_install_concat (2, bootdir, "grub.elf");
+	grub_install_copy_file (imgfile, dst);
+	free (dst);
+      }
+      break;
+
+    case GRUB_INSTALL_PLATFORM_I386_IEEE1275:
+    case GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275:
+      {
+	char *dst = grub_install_concat (2, grubdir, "grub");
+	grub_install_copy_file (imgfile, dst);
+	free (dst);
+      }
+      break;
+
+    case GRUB_INSTALL_PLATFORM_I386_EFI:
+    case GRUB_INSTALL_PLATFORM_X86_64_EFI:
+      {
+	char *dst = grub_install_concat (2, platdir, "grub.efi");
+	grub_install_make_image_wrap (/* source dir  */ grub_install_source_directory,
+				      /* prefix */ "",
+				       /* output */ dst,
+				       /* memdisk */ NULL,
+				      have_load_cfg ? load_cfg : NULL,
+				       /* image target */ mkimage_target,
+				      0, GRUB_COMPRESSION_AUTO);
+      }
+      break;
+    case GRUB_INSTALL_PLATFORM_ARM_EFI:
+    case GRUB_INSTALL_PLATFORM_IA64_EFI:
+    case GRUB_INSTALL_PLATFORM_MIPSEL_QEMU_MIPS:
+    case GRUB_INSTALL_PLATFORM_MIPS_QEMU_MIPS:
+    case GRUB_INSTALL_PLATFORM_I386_COREBOOT:
+    case GRUB_INSTALL_PLATFORM_I386_MULTIBOOT:
+    case GRUB_INSTALL_PLATFORM_I386_PC:
+    case GRUB_INSTALL_PLATFORM_MIPSEL_ARC:
+    case GRUB_INSTALL_PLATFORM_MIPS_ARC:
+    case GRUB_INSTALL_PLATFORM_ARM_UBOOT:
+    case GRUB_INSTALL_PLATFORM_I386_QEMU:
+    case GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275:
+      break;
+    }
+
+  /* Perform the platform-dependent install */
+
+  switch (platform)
+    {
+    case GRUB_INSTALL_PLATFORM_I386_PC:
+      {
+	char *boot_img_src = grub_install_concat (2, 
+						  grub_install_source_directory,
+						  "boot.img");
+	char *boot_img = grub_install_concat (2, platdir,
+					      "boot.img");
+	grub_install_copy_file (boot_img_src, boot_img);
+
+	grub_util_info ("grub_bios_setup %s %s %s --directory='%s' --device-map='%s' '%s'",
+			allow_floppy ? "--allow-floppy " : "",
+			verbosity ? "--verbose " : "",
+			force ? "--force " : "",
+			platdir,
+			device_map,
+			install_device);
+			
+	/*  Now perform the installation.  */
+	grub_bios_setup (platdir, NULL, NULL,
+			 install_drive, force,
+			 1, allow_floppy);
+	break;
+      }
+    case GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275:
+      {
+	char *boot_img_src = grub_install_concat (2, 
+						  grub_install_source_directory,
+						  "boot.img");
+	char *boot_img = grub_install_concat (2, platdir,
+					      "boot.img");
+	grub_install_copy_file (boot_img_src, boot_img);
+
+	grub_util_info ("grub_sparc_setup %s %s %s --directory='%s' --device-map='%s' '%s'",
+			allow_floppy ? "--allow-floppy " : "",
+			verbosity ? "--verbose " : "",
+			force ? "--force " : "",
+			platdir,
+			device_map,
+			install_drive);
+			
+	/*  Now perform the installation.  */
+	grub_sparc_setup (platdir, NULL, NULL,
+			  install_device, force,
+			  1, allow_floppy);
+	break;
+      }
+
+    case GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275:
+      /* If a install device is defined, copy the core.elf to PReP partition.  */
+      if (install_device && install_device[0])
+	{
+	  grub_device_t ins_dev;
+	  ins_dev = grub_device_open (install_drive);
+	  if (!ins_dev || !is_prep_partition (ins_dev))
+	    {
+	      grub_util_error ("%s", _("the chosen partition is not a PReP partition"));
+	    }
+	  if (is_prep_empty (ins_dev))
+	    {
+	      if (write_to_disk (ins_dev, imgfile))
+		grub_util_error ("%s", _("failed to copy Grub to the PReP partition"));
+	    }
+	  else
+	    {
+	      char *s = xasprintf ("dd if=/dev/zero of=%s", install_device);
+	      grub_util_error ("the PReP partition is not empty. If you are sure you want to use it, run dd to clear it: `%s'",
+			       s);
+	    }
+	  grub_device_close (ins_dev);
+      }
+      /* fallthrough.  */
+    case GRUB_INSTALL_PLATFORM_I386_IEEE1275:
+      if (update_nvram)
+	{
+	  char *boot_device;
+
+	  if (grub_util_exec_redirect_null ((char * []){ (char *) "ofpathname", (char *) "--version", NULL }))
+	    {
+	      /* TRANSLATORS: This message is shown when required executable `%s'
+		 isn't found.  */
+	      grub_util_error (_("%s: not found"), "ofpathname");
+	    }
+
+	  /* Get the Open Firmware device tree path translation.  */
+	  if (platform != GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275 || !install_device
+	      || install_device[0] == '\0')
+	    {
+	      char *relpath = grub_make_system_path_relative_to_its_root (imgfile);
+	      char *ptr;
+	      char *dev = grub_util_get_os_disk (grub_devices[0]);
+	      char *ofpath;
+	      int partno = grub_dev->disk->partition ? grub_dev->disk->partition->number + 1 : 0;
+
+	      for (ptr = relpath; *ptr; ptr++)
+		if (*ptr == '/')
+		  *ptr = '\\';
+	      ofpath = get_ofpathname (dev);
+	      boot_device = xasprintf ("%s:%d,%s",
+				       ofpath, partno, relpath);
+	    }
+	  else
+	    {
+	      char *dev = grub_util_get_os_disk (install_device);
+	      boot_device = get_ofpathname (dev);
+	    }
+	  if (grub_util_exec ((char * []){ (char *) "nvsetenv", (char *) "boot-device",
+		  boot_device, NULL }))
+	    {
+	      char *cmd = xasprintf ("setenv boot-device %s", boot_device);
+	      grub_util_error ("`nvsetenv' failed. \nYou will have to set `boot-device' variable manually.  At the IEEE1275 prompt, type:\n  %s\n", 
+			       cmd);
+	    }
+	}
+      break;
+    case GRUB_INSTALL_PLATFORM_MIPS_ARC:
+      grub_util_exec ((char * []){ (char *) "dvhtool", (char *) "-d",
+	    install_device, (char *) "--unix-to-vh", 
+	    imgfile,
+	    (char *) "grub", NULL });
+      grub_util_warn ("%s", _("You will have to set `SystemPartition' and `OSLoader' manually."));
+
+      break;
+
+    case GRUB_INSTALL_PLATFORM_I386_EFI:
+      {
+	char *dst = grub_install_concat (2, efidir, "grub.efi");
+	/* For old macs. Suggested by Peter Jones.  */
+	grub_install_copy_file (imgfile, dst);
+	free (dst);
+      }
+
+    case GRUB_INSTALL_PLATFORM_X86_64_EFI:
+    case GRUB_INSTALL_PLATFORM_ARM_EFI:
+    case GRUB_INSTALL_PLATFORM_IA64_EFI:
+      {
+	char *dst = grub_install_concat (2, efidir, efi_file);
+	grub_install_copy_file (imgfile, dst);
+	free (dst);
+      }
+      if (!removable)
+	{
+	  /* Try to make this image bootable using the EFI Boot Manager, if available.  */
+
+	  if (grub_util_exec_redirect_null ((char * []){ (char *) "efibootmgr", (char *) "--version", NULL }))
+	    {
+	      /* TRANSLATORS: This message is shown when required executable `%s'
+		 isn't found.  */
+	      grub_util_error (_("%s: not found"), "efibootmgr");
+	    }
+	  if (!efi_distributor || efi_distributor[0] == '\0')
+	    grub_util_error ("%s", "EFI distributor id isn't specified.");
+
+	  /* On Linux, we need the efivars kernel modules.  */
+#ifdef __linux__
+	  grub_util_exec ((char * []){ (char *) "modprobe", (char *) "-q",
+		(char *) "efivars", NULL });
+#endif
+	  /* Delete old entries from the same distributor.  */
+	  remove_old_efi_entries (efi_distributor);
+
+	  char * efidir_disk = grub_util_get_os_disk (efidir_device_names[0]);
+	  int efidir_part = efidir_grub_dev->disk->partition ? efidir_grub_dev->disk->partition->number + 1 : 1;
+	  char * efifile_path = xasprintf ("\\EFI\\%s\\%s",
+					   efi_distributor,
+					   efi_file);
+	  char *efidir_part_str = xasprintf ("%d", efidir_part);
+
+	  grub_util_exec ((char * []){ (char *) "efibootmgr", (char *) "--quiet",
+		(char *) "-c", (char *) "-d", efidir_disk,
+		(char *) "-p", efidir_part_str, (char *) "-w",
+		(char *) "-L", bootloader_id, (char *) "-l", 
+		efifile_path, NULL });
+	  free (efidir_part_str);
+	}
+      break;
+
+    case GRUB_INSTALL_PLATFORM_MIPSEL_LOONGSON:
+    case GRUB_INSTALL_PLATFORM_MIPSEL_QEMU_MIPS:
+    case GRUB_INSTALL_PLATFORM_MIPS_QEMU_MIPS:
+    case GRUB_INSTALL_PLATFORM_I386_COREBOOT:
+    case GRUB_INSTALL_PLATFORM_I386_MULTIBOOT:
+    case GRUB_INSTALL_PLATFORM_MIPSEL_ARC:
+    case GRUB_INSTALL_PLATFORM_ARM_UBOOT:
+    case GRUB_INSTALL_PLATFORM_I386_QEMU:
+      grub_util_warn ("%s",
+		      _("WARNING: no platform-specific install was performed"));
+      break;
+    }
+
+  fprintf (stderr, "%s\n", _("Installation finished. No error reported."));
+
+  /* Free resources.  */
+  grub_gcry_fini_all ();
+  grub_fini_all ();
+
+  return 0;
+}

=== modified file 'util/grub-mkimage.c'
--- util/grub-mkimage.c	2013-08-23 07:01:11 +0000
+++ util/grub-mkimage.c	2013-10-04 00:39:55 +0000
@@ -43,1786 +43,14 @@
 #include <grub/uboot/image.h>
 #include <grub/arm/reloc.h>
 #include <grub/ia64/reloc.h>
+#include <grub/util/install.h>
+#include <grub/misc.h>
 
 #define _GNU_SOURCE	1
 #include <argp.h>
 
 #include "progname.h"
 
-#define ALIGN_ADDR(x) (ALIGN_UP((x), image_target->voidp_sizeof))
-
-#ifdef HAVE_LIBLZMA
-#include <lzma.h>
-#endif
-
-#define TARGET_NO_FIELD 0xffffffff
-
-typedef enum {
-  COMPRESSION_AUTO, COMPRESSION_NONE, COMPRESSION_XZ, COMPRESSION_LZMA
-} grub_compression_t;
-
-struct image_target_desc
-{
-  const char *dirname;
-  const char *names[6];
-  grub_size_t voidp_sizeof;
-  int bigendian;
-  enum {
-    IMAGE_I386_PC, IMAGE_EFI, IMAGE_COREBOOT,
-    IMAGE_SPARC64_AOUT, IMAGE_SPARC64_RAW, IMAGE_SPARC64_CDCORE,
-    IMAGE_I386_IEEE1275,
-    IMAGE_LOONGSON_ELF, IMAGE_QEMU, IMAGE_PPC, IMAGE_YEELOONG_FLASH,
-    IMAGE_FULOONG2F_FLASH, IMAGE_I386_PC_PXE, IMAGE_MIPS_ARC,
-    IMAGE_QEMU_MIPS_FLASH, IMAGE_UBOOT
-  } id;
-  enum
-    {
-      PLATFORM_FLAGS_NONE = 0,
-      PLATFORM_FLAGS_DECOMPRESSORS = 2,
-      PLATFORM_FLAGS_MODULES_BEFORE_KERNEL = 4,
-    } flags;
-  unsigned total_module_size;
-  unsigned decompressor_compressed_size;
-  unsigned decompressor_uncompressed_size;
-  unsigned decompressor_uncompressed_addr;
-  unsigned link_align;
-  grub_uint16_t elf_target;
-  unsigned section_align;
-  signed vaddr_offset;
-  grub_uint64_t link_addr;
-  unsigned mod_gap, mod_align;
-  grub_compression_t default_compression;
-  grub_uint16_t pe_target;
-};
-
-#define EFI32_HEADER_SIZE ALIGN_UP (GRUB_PE32_MSDOS_STUB_SIZE		\
-				    + GRUB_PE32_SIGNATURE_SIZE		\
-				    + sizeof (struct grub_pe32_coff_header) \
-				    + sizeof (struct grub_pe32_optional_header) \
-				    + 4 * sizeof (struct grub_pe32_section_table), \
-				    GRUB_PE32_SECTION_ALIGNMENT)
-
-#define EFI64_HEADER_SIZE ALIGN_UP (GRUB_PE32_MSDOS_STUB_SIZE		\
-				    + GRUB_PE32_SIGNATURE_SIZE		\
-				    + sizeof (struct grub_pe32_coff_header) \
-				    + sizeof (struct grub_pe64_optional_header) \
-				    + 4 * sizeof (struct grub_pe32_section_table), \
-				    GRUB_PE32_SECTION_ALIGNMENT)
-
-struct image_target_desc image_targets[] =
-  {
-    {
-      .dirname = "i386-coreboot",
-      .names = { "i386-coreboot", NULL },
-      .voidp_sizeof = 4,
-      .bigendian = 0,
-      .id = IMAGE_COREBOOT,
-      .flags = PLATFORM_FLAGS_NONE,
-      .total_module_size = TARGET_NO_FIELD,
-      .decompressor_compressed_size = TARGET_NO_FIELD,
-      .decompressor_uncompressed_size = TARGET_NO_FIELD,
-      .decompressor_uncompressed_addr = TARGET_NO_FIELD,
-      .section_align = 1,
-      .vaddr_offset = 0,
-      .link_addr = GRUB_KERNEL_I386_COREBOOT_LINK_ADDR,
-      .elf_target = EM_386,
-      .link_align = 4,
-      .mod_gap = GRUB_KERNEL_I386_COREBOOT_MOD_GAP,
-      .mod_align = GRUB_KERNEL_I386_COREBOOT_MOD_ALIGN
-    },
-    {
-      .dirname = "i386-multiboot",
-      .names = { "i386-multiboot", NULL},
-      .voidp_sizeof = 4,
-      .bigendian = 0,
-      .id = IMAGE_COREBOOT,
-      .flags = PLATFORM_FLAGS_NONE,
-      .total_module_size = TARGET_NO_FIELD,
-      .decompressor_compressed_size = TARGET_NO_FIELD,
-      .decompressor_uncompressed_size = TARGET_NO_FIELD,
-      .decompressor_uncompressed_addr = TARGET_NO_FIELD,
-      .section_align = 1,
-      .vaddr_offset = 0,
-      .link_addr = GRUB_KERNEL_I386_COREBOOT_LINK_ADDR,
-      .elf_target = EM_386,
-      .link_align = 4,
-      .mod_gap = GRUB_KERNEL_I386_COREBOOT_MOD_GAP,
-      .mod_align = GRUB_KERNEL_I386_COREBOOT_MOD_ALIGN
-    },
-    {
-      .dirname = "i386-pc",
-      .names = { "i386-pc", NULL },
-      .voidp_sizeof = 4,
-      .bigendian = 0,
-      .id = IMAGE_I386_PC, 
-      .flags = PLATFORM_FLAGS_DECOMPRESSORS,
-      .total_module_size = TARGET_NO_FIELD,
-      .decompressor_compressed_size = GRUB_DECOMPRESSOR_I386_PC_COMPRESSED_SIZE,
-      .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_I386_PC_UNCOMPRESSED_SIZE,
-      .decompressor_uncompressed_addr = TARGET_NO_FIELD,
-      .section_align = 1,
-      .vaddr_offset = 0,
-      .link_addr = GRUB_KERNEL_I386_PC_LINK_ADDR,
-      .default_compression = COMPRESSION_LZMA
-    },
-    {
-      .dirname = "i386-pc",
-      .names = { "i386-pc-pxe", NULL },
-      .voidp_sizeof = 4,
-      .bigendian = 0,
-      .id = IMAGE_I386_PC_PXE, 
-      .flags = PLATFORM_FLAGS_DECOMPRESSORS,
-      .total_module_size = TARGET_NO_FIELD,
-      .decompressor_compressed_size = GRUB_DECOMPRESSOR_I386_PC_COMPRESSED_SIZE,
-      .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_I386_PC_UNCOMPRESSED_SIZE,
-      .decompressor_uncompressed_addr = TARGET_NO_FIELD,
-      .section_align = 1,
-      .vaddr_offset = 0,
-      .link_addr = GRUB_KERNEL_I386_PC_LINK_ADDR,
-      .default_compression = COMPRESSION_LZMA
-    },
-    {
-      .dirname = "i386-efi",
-      .names = { "i386-efi", NULL },
-      .voidp_sizeof = 4,
-      .bigendian = 0,
-      .id = IMAGE_EFI,
-      .flags = PLATFORM_FLAGS_NONE,
-      .total_module_size = TARGET_NO_FIELD,
-      .decompressor_compressed_size = TARGET_NO_FIELD,
-      .decompressor_uncompressed_size = TARGET_NO_FIELD,
-      .decompressor_uncompressed_addr = TARGET_NO_FIELD,
-      .section_align = GRUB_PE32_SECTION_ALIGNMENT,
-      .vaddr_offset = EFI32_HEADER_SIZE,
-      .pe_target = GRUB_PE32_MACHINE_I386,
-      .elf_target = EM_386,
-    },
-    {
-      .dirname = "i386-ieee1275",
-      .names = { "i386-ieee1275", NULL },
-      .voidp_sizeof = 4,
-      .bigendian = 0,
-      .id = IMAGE_I386_IEEE1275, 
-      .flags = PLATFORM_FLAGS_NONE,
-      .total_module_size = TARGET_NO_FIELD,
-      .decompressor_compressed_size = TARGET_NO_FIELD,
-      .decompressor_uncompressed_size = TARGET_NO_FIELD,
-      .decompressor_uncompressed_addr = TARGET_NO_FIELD,
-      .section_align = 1,
-      .vaddr_offset = 0,
-      .link_addr = GRUB_KERNEL_I386_IEEE1275_LINK_ADDR,
-      .elf_target = EM_386,
-      .mod_gap = GRUB_KERNEL_I386_IEEE1275_MOD_GAP,
-      .mod_align = GRUB_KERNEL_I386_IEEE1275_MOD_ALIGN,
-      .link_align = 4,
-    },
-    {
-      .dirname = "i386-qemu",
-      .names = { "i386-qemu", NULL },
-      .voidp_sizeof = 4,
-      .bigendian = 0,
-      .id = IMAGE_QEMU, 
-      .flags = PLATFORM_FLAGS_NONE,
-      .total_module_size = TARGET_NO_FIELD,
-      .decompressor_compressed_size = TARGET_NO_FIELD,
-      .decompressor_uncompressed_size = TARGET_NO_FIELD,
-      .decompressor_uncompressed_addr = TARGET_NO_FIELD,
-      .section_align = 1,
-      .vaddr_offset = 0,
-      .link_addr = GRUB_KERNEL_I386_QEMU_LINK_ADDR
-    },
-    {
-      .dirname = "x86_64-efi",
-      .names = { "x86_64-efi", NULL },
-      .voidp_sizeof = 8,
-      .bigendian = 0, 
-      .id = IMAGE_EFI, 
-      .flags = PLATFORM_FLAGS_NONE,
-      .total_module_size = TARGET_NO_FIELD,
-      .decompressor_compressed_size = TARGET_NO_FIELD,
-      .decompressor_uncompressed_size = TARGET_NO_FIELD,
-      .decompressor_uncompressed_addr = TARGET_NO_FIELD,
-      .section_align = GRUB_PE32_SECTION_ALIGNMENT,
-      .vaddr_offset = EFI64_HEADER_SIZE,
-      .pe_target = GRUB_PE32_MACHINE_X86_64,
-      .elf_target = EM_X86_64,
-    },
-    {
-      .dirname = "mipsel-loongson",
-      .names = { "mipsel-yeeloong-flash", NULL },
-      .voidp_sizeof = 4,
-      .bigendian = 0,
-      .id = IMAGE_YEELOONG_FLASH, 
-      .flags = PLATFORM_FLAGS_DECOMPRESSORS,
-      .total_module_size = GRUB_KERNEL_MIPS_LOONGSON_TOTAL_MODULE_SIZE,
-      .decompressor_compressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_COMPRESSED_SIZE,
-      .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_SIZE,
-      .decompressor_uncompressed_addr = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_ADDR,
-      .section_align = 1,
-      .vaddr_offset = 0,
-      .link_addr = GRUB_KERNEL_MIPS_LOONGSON_LINK_ADDR,
-      .elf_target = EM_MIPS,
-      .link_align = GRUB_KERNEL_MIPS_LOONGSON_LINK_ALIGN,
-      .default_compression = COMPRESSION_NONE
-    },
-    {
-      .dirname = "mipsel-loongson",
-      .names = { "mipsel-fuloong2f-flash", NULL },
-      .voidp_sizeof = 4,
-      .bigendian = 0,
-      .id = IMAGE_FULOONG2F_FLASH, 
-      .flags = PLATFORM_FLAGS_DECOMPRESSORS,
-      .total_module_size = GRUB_KERNEL_MIPS_LOONGSON_TOTAL_MODULE_SIZE,
-      .decompressor_compressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_COMPRESSED_SIZE,
-      .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_SIZE,
-      .decompressor_uncompressed_addr = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_ADDR,
-      .section_align = 1,
-      .vaddr_offset = 0,
-      .link_addr = GRUB_KERNEL_MIPS_LOONGSON_LINK_ADDR,
-      .elf_target = EM_MIPS,
-      .link_align = GRUB_KERNEL_MIPS_LOONGSON_LINK_ALIGN,
-      .default_compression = COMPRESSION_NONE
-    },
-    {
-      .dirname = "mipsel-loongson",
-      .names = { "mipsel-loongson-elf", "mipsel-yeeloong-elf",
-		 "mipsel-fuloong2f-elf", "mipsel-fuloong2e-elf",
-		 "mipsel-fuloong-elf", NULL },
-      .voidp_sizeof = 4,
-      .bigendian = 0,
-      .id = IMAGE_LOONGSON_ELF, 
-      .flags = PLATFORM_FLAGS_DECOMPRESSORS,
-      .total_module_size = GRUB_KERNEL_MIPS_LOONGSON_TOTAL_MODULE_SIZE,
-      .decompressor_compressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_COMPRESSED_SIZE,
-      .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_SIZE,
-      .decompressor_uncompressed_addr = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_ADDR,
-      .section_align = 1,
-      .vaddr_offset = 0,
-      .link_addr = GRUB_KERNEL_MIPS_LOONGSON_LINK_ADDR,
-      .elf_target = EM_MIPS,
-      .link_align = GRUB_KERNEL_MIPS_LOONGSON_LINK_ALIGN,
-      .default_compression = COMPRESSION_NONE
-    },
-    {
-      .dirname = "powerpc-ieee1275",
-      .names = { "powerpc-ieee1275", NULL },
-      .voidp_sizeof = 4,
-      .bigendian = 1,
-      .id = IMAGE_PPC, 
-      .flags = PLATFORM_FLAGS_NONE,
-      .total_module_size = TARGET_NO_FIELD,
-      .decompressor_compressed_size = TARGET_NO_FIELD,
-      .decompressor_uncompressed_size = TARGET_NO_FIELD,
-      .decompressor_uncompressed_addr = TARGET_NO_FIELD,
-      .section_align = 1,
-      .vaddr_offset = 0,
-      .link_addr = GRUB_KERNEL_POWERPC_IEEE1275_LINK_ADDR,
-      .elf_target = EM_PPC,
-      .mod_gap = GRUB_KERNEL_POWERPC_IEEE1275_MOD_GAP,
-      .mod_align = GRUB_KERNEL_POWERPC_IEEE1275_MOD_ALIGN,
-      .link_align = 4
-    },
-    {
-      .dirname = "sparc64-ieee1275",
-      .names = { "sparc64-ieee1275-raw", NULL },
-      .voidp_sizeof = 8,
-      .bigendian = 1, 
-      .id = IMAGE_SPARC64_RAW,
-      .flags = PLATFORM_FLAGS_NONE,
-      .total_module_size = GRUB_KERNEL_SPARC64_IEEE1275_TOTAL_MODULE_SIZE,
-      .decompressor_compressed_size = TARGET_NO_FIELD,
-      .decompressor_uncompressed_size = TARGET_NO_FIELD,
-      .decompressor_uncompressed_addr = TARGET_NO_FIELD,
-      .section_align = 1,
-      .vaddr_offset = 0,
-      .link_addr = GRUB_KERNEL_SPARC64_IEEE1275_LINK_ADDR
-    },
-    {
-      .dirname = "sparc64-ieee1275",
-      .names = { "sparc64-ieee1275-cdcore", NULL },
-      .voidp_sizeof = 8,
-      .bigendian = 1, 
-      .id = IMAGE_SPARC64_CDCORE,
-      .flags = PLATFORM_FLAGS_NONE,
-      .total_module_size = GRUB_KERNEL_SPARC64_IEEE1275_TOTAL_MODULE_SIZE,
-      .decompressor_compressed_size = TARGET_NO_FIELD,
-      .decompressor_uncompressed_size = TARGET_NO_FIELD,
-      .decompressor_uncompressed_addr = TARGET_NO_FIELD,
-      .section_align = 1,
-      .vaddr_offset = 0,
-      .link_addr = GRUB_KERNEL_SPARC64_IEEE1275_LINK_ADDR
-    },
-    {
-      .dirname = "sparc64-ieee1275",
-      .names = { "sparc64-ieee1275-aout", NULL },
-      .voidp_sizeof = 8,
-      .bigendian = 1,
-      .id = IMAGE_SPARC64_AOUT,
-      .flags = PLATFORM_FLAGS_NONE,
-      .total_module_size = GRUB_KERNEL_SPARC64_IEEE1275_TOTAL_MODULE_SIZE,
-      .decompressor_compressed_size = TARGET_NO_FIELD,
-      .decompressor_uncompressed_size = TARGET_NO_FIELD,
-      .decompressor_uncompressed_addr = TARGET_NO_FIELD,
-      .section_align = 1,
-      .vaddr_offset = 0,
-      .link_addr = GRUB_KERNEL_SPARC64_IEEE1275_LINK_ADDR
-    },
-    {
-      .dirname = "ia64-efi",
-      .names = {"ia64-efi", NULL},
-      .voidp_sizeof = 8,
-      .bigendian = 0, 
-      .id = IMAGE_EFI, 
-      .flags = PLATFORM_FLAGS_NONE,
-      .total_module_size = TARGET_NO_FIELD,
-      .decompressor_compressed_size = TARGET_NO_FIELD,
-      .decompressor_uncompressed_size = TARGET_NO_FIELD,
-      .decompressor_uncompressed_addr = TARGET_NO_FIELD,
-      .section_align = GRUB_PE32_SECTION_ALIGNMENT,
-      .vaddr_offset = EFI64_HEADER_SIZE,
-      .pe_target = GRUB_PE32_MACHINE_IA64,
-      .elf_target = EM_IA_64,
-    },
-    {
-      .dirname = "mips-arc",
-      .names = {"mips-arc", NULL},
-      .voidp_sizeof = 4,
-      .bigendian = 1,
-      .id = IMAGE_MIPS_ARC, 
-      .flags = PLATFORM_FLAGS_DECOMPRESSORS,
-      .total_module_size = GRUB_KERNEL_MIPS_ARC_TOTAL_MODULE_SIZE,
-      .decompressor_compressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_COMPRESSED_SIZE,
-      .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_SIZE,
-      .decompressor_uncompressed_addr = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_ADDR,
-      .section_align = 1,
-      .vaddr_offset = 0,
-      .link_addr = GRUB_KERNEL_MIPS_ARC_LINK_ADDR,
-      .elf_target = EM_MIPS,
-      .link_align = GRUB_KERNEL_MIPS_ARC_LINK_ALIGN,
-      .default_compression = COMPRESSION_NONE
-    },
-    {
-      .dirname = "mipsel-arc",
-      .names = {"mipsel-arc", NULL},
-      .voidp_sizeof = 4,
-      .bigendian = 0,
-      .id = IMAGE_MIPS_ARC, 
-      .flags = PLATFORM_FLAGS_DECOMPRESSORS,
-      .total_module_size = GRUB_KERNEL_MIPS_ARC_TOTAL_MODULE_SIZE,
-      .decompressor_compressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_COMPRESSED_SIZE,
-      .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_SIZE,
-      .decompressor_uncompressed_addr = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_ADDR,
-      .section_align = 1,
-      .vaddr_offset = 0,
-      .link_addr = GRUB_KERNEL_MIPSEL_ARC_LINK_ADDR,
-      .elf_target = EM_MIPS,
-      .link_align = GRUB_KERNEL_MIPS_ARC_LINK_ALIGN,
-      .default_compression = COMPRESSION_NONE
-    },
-    {
-      .dirname = "mipsel-qemu_mips",
-      .names = { "mipsel-qemu_mips-elf", NULL },
-      .voidp_sizeof = 4,
-      .bigendian = 0,
-      .id = IMAGE_LOONGSON_ELF, 
-      .flags = PLATFORM_FLAGS_DECOMPRESSORS,
-      .total_module_size = GRUB_KERNEL_MIPS_QEMU_MIPS_TOTAL_MODULE_SIZE,
-      .decompressor_compressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_COMPRESSED_SIZE,
-      .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_SIZE,
-      .decompressor_uncompressed_addr = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_ADDR,
-      .section_align = 1,
-      .vaddr_offset = 0,
-      .link_addr = GRUB_KERNEL_MIPS_QEMU_MIPS_LINK_ADDR,
-      .elf_target = EM_MIPS,
-      .link_align = GRUB_KERNEL_MIPS_QEMU_MIPS_LINK_ALIGN,
-      .default_compression = COMPRESSION_NONE
-    },
-    {
-      .dirname = "mips-qemu_mips",
-      .names = { "mips-qemu_mips-flash", NULL },
-      .voidp_sizeof = 4,
-      .bigendian = 1,
-      .id = IMAGE_QEMU_MIPS_FLASH, 
-      .flags = PLATFORM_FLAGS_DECOMPRESSORS,
-      .total_module_size = GRUB_KERNEL_MIPS_QEMU_MIPS_TOTAL_MODULE_SIZE,
-      .decompressor_compressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_COMPRESSED_SIZE,
-      .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_SIZE,
-      .decompressor_uncompressed_addr = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_ADDR,
-      .section_align = 1,
-      .vaddr_offset = 0,
-      .link_addr = GRUB_KERNEL_MIPS_QEMU_MIPS_LINK_ADDR,
-      .elf_target = EM_MIPS,
-      .link_align = GRUB_KERNEL_MIPS_QEMU_MIPS_LINK_ALIGN,
-      .default_compression = COMPRESSION_NONE
-    },
-    {
-      .dirname = "mipsel-qemu_mips",
-      .names = { "mipsel-qemu_mips-flash", NULL },
-      .voidp_sizeof = 4,
-      .bigendian = 0,
-      .id = IMAGE_QEMU_MIPS_FLASH, 
-      .flags = PLATFORM_FLAGS_DECOMPRESSORS,
-      .total_module_size = GRUB_KERNEL_MIPS_QEMU_MIPS_TOTAL_MODULE_SIZE,
-      .decompressor_compressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_COMPRESSED_SIZE,
-      .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_SIZE,
-      .decompressor_uncompressed_addr = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_ADDR,
-      .section_align = 1,
-      .vaddr_offset = 0,
-      .link_addr = GRUB_KERNEL_MIPS_QEMU_MIPS_LINK_ADDR,
-      .elf_target = EM_MIPS,
-      .link_align = GRUB_KERNEL_MIPS_QEMU_MIPS_LINK_ALIGN,
-      .default_compression = COMPRESSION_NONE
-    },
-    {
-      .dirname = "mips-qemu_mips",
-      .names = { "mips-qemu_mips-elf", NULL },
-      .voidp_sizeof = 4,
-      .bigendian = 1,
-      .id = IMAGE_LOONGSON_ELF, 
-      .flags = PLATFORM_FLAGS_DECOMPRESSORS,
-      .total_module_size = GRUB_KERNEL_MIPS_QEMU_MIPS_TOTAL_MODULE_SIZE,
-      .decompressor_compressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_COMPRESSED_SIZE,
-      .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_SIZE,
-      .decompressor_uncompressed_addr = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_ADDR,
-      .section_align = 1,
-      .vaddr_offset = 0,
-      .link_addr = GRUB_KERNEL_MIPS_QEMU_MIPS_LINK_ADDR,
-      .elf_target = EM_MIPS,
-      .link_align = GRUB_KERNEL_MIPS_QEMU_MIPS_LINK_ALIGN,
-      .default_compression = COMPRESSION_NONE
-    },
-    {
-      .dirname = "arm-uboot",
-      .names = { "arm-uboot", NULL },
-      .voidp_sizeof = 4,
-      .bigendian = 0,
-      .id = IMAGE_UBOOT, 
-      .flags = PLATFORM_FLAGS_NONE,
-      .total_module_size = GRUB_KERNEL_ARM_UBOOT_TOTAL_MODULE_SIZE,
-      .decompressor_compressed_size = TARGET_NO_FIELD,
-      .decompressor_uncompressed_size = TARGET_NO_FIELD,
-      .decompressor_uncompressed_addr = TARGET_NO_FIELD,
-      .section_align = GRUB_KERNEL_ARM_UBOOT_MOD_ALIGN,
-      .vaddr_offset = 0,
-      .link_addr = GRUB_KERNEL_ARM_UBOOT_LINK_ADDR,
-      .elf_target = EM_ARM,
-      .mod_gap = GRUB_KERNEL_ARM_UBOOT_MOD_GAP,
-      .mod_align = GRUB_KERNEL_ARM_UBOOT_MOD_ALIGN,
-      .link_align = 4
-    },
-    {
-      .dirname = "arm-efi",
-      .names = { "arm-efi", NULL },
-      .voidp_sizeof = 4,
-      .bigendian = 0, 
-      .id = IMAGE_EFI, 
-      .flags = PLATFORM_FLAGS_NONE,
-      .total_module_size = TARGET_NO_FIELD,
-      .decompressor_compressed_size = TARGET_NO_FIELD,
-      .decompressor_uncompressed_size = TARGET_NO_FIELD,
-      .decompressor_uncompressed_addr = TARGET_NO_FIELD,
-      .section_align = GRUB_PE32_SECTION_ALIGNMENT,
-      .vaddr_offset = ALIGN_UP (GRUB_PE32_MSDOS_STUB_SIZE
-                                + GRUB_PE32_SIGNATURE_SIZE
-                                + sizeof (struct grub_pe32_coff_header)
-                                + sizeof (struct grub_pe32_optional_header)
-                                + 4 * sizeof (struct grub_pe32_section_table),
-                                GRUB_PE32_SECTION_ALIGNMENT),
-      .pe_target = GRUB_PE32_MACHINE_ARMTHUMB_MIXED,
-      .elf_target = EM_ARM,
-    },
-  };
-
-#define grub_target_to_host32(x) (grub_target_to_host32_real (image_target, (x)))
-#define grub_host_to_target32(x) (grub_host_to_target32_real (image_target, (x)))
-#define grub_target_to_host64(x) (grub_target_to_host64_real (image_target, (x)))
-#define grub_host_to_target64(x) (grub_host_to_target64_real (image_target, (x)))
-#define grub_host_to_target_addr(x) (grub_host_to_target_addr_real (image_target, (x)))
-#define grub_target_to_host16(x) (grub_target_to_host16_real (image_target, (x)))
-#define grub_host_to_target16(x) (grub_host_to_target16_real (image_target, (x)))
-
-static inline grub_uint32_t
-grub_target_to_host32_real (struct image_target_desc *image_target, grub_uint32_t in)
-{
-  if (image_target->bigendian)
-    return grub_be_to_cpu32 (in);
-  else
-    return grub_le_to_cpu32 (in);
-}
-
-static inline grub_uint64_t
-grub_target_to_host64_real (struct image_target_desc *image_target, grub_uint64_t in)
-{
-  if (image_target->bigendian)
-    return grub_be_to_cpu64 (in);
-  else
-    return grub_le_to_cpu64 (in);
-}
-
-static inline grub_uint64_t
-grub_host_to_target64_real (struct image_target_desc *image_target, grub_uint64_t in)
-{
-  if (image_target->bigendian)
-    return grub_cpu_to_be64 (in);
-  else
-    return grub_cpu_to_le64 (in);
-}
-
-static inline grub_uint32_t
-grub_host_to_target32_real (struct image_target_desc *image_target, grub_uint32_t in)
-{
-  if (image_target->bigendian)
-    return grub_cpu_to_be32 (in);
-  else
-    return grub_cpu_to_le32 (in);
-}
-
-static inline grub_uint16_t
-grub_target_to_host16_real (struct image_target_desc *image_target, grub_uint16_t in)
-{
-  if (image_target->bigendian)
-    return grub_be_to_cpu16 (in);
-  else
-    return grub_le_to_cpu16 (in);
-}
-
-static inline grub_uint16_t
-grub_host_to_target16_real (struct image_target_desc *image_target, grub_uint16_t in)
-{
-  if (image_target->bigendian)
-    return grub_cpu_to_be16 (in);
-  else
-    return grub_cpu_to_le16 (in);
-}
-
-static inline grub_uint64_t
-grub_host_to_target_addr_real (struct image_target_desc *image_target, grub_uint64_t in)
-{
-  if (image_target->voidp_sizeof == 8)
-    return grub_host_to_target64_real (image_target, in);
-  else
-    return grub_host_to_target32_real (image_target, in);
-}
-
-static inline grub_uint64_t
-grub_target_to_host_real (struct image_target_desc *image_target, grub_uint64_t in)
-{
-  if (image_target->voidp_sizeof == 8)
-    return grub_target_to_host64_real (image_target, in);
-  else
-    return grub_target_to_host32_real (image_target, in);
-}
-
-#define GRUB_IEEE1275_NOTE_NAME "PowerPC"
-#define GRUB_IEEE1275_NOTE_TYPE 0x1275
-
-/* These structures are defined according to the CHRP binding to IEEE1275,
-   "Client Program Format" section.  */
-
-struct grub_ieee1275_note_hdr
-{
-  grub_uint32_t namesz;
-  grub_uint32_t descsz;
-  grub_uint32_t type;
-  char name[sizeof (GRUB_IEEE1275_NOTE_NAME)];
-};
-
-struct grub_ieee1275_note_desc
-{
-  grub_uint32_t real_mode;
-  grub_uint32_t real_base;
-  grub_uint32_t real_size;
-  grub_uint32_t virt_base;
-  grub_uint32_t virt_size;
-  grub_uint32_t load_base;
-};
-
-struct grub_ieee1275_note
-{
-  struct grub_ieee1275_note_hdr header;
-  struct grub_ieee1275_note_desc descriptor;
-};
-
-#define grub_target_to_host(val) grub_target_to_host_real(image_target, (val))
-
-#include <grub/lib/LzmaEnc.h>
-
-static void *SzAlloc(void *p, size_t size) { p = p; return xmalloc(size); }
-static void SzFree(void *p, void *address) { p = p; free(address); }
-static ISzAlloc g_Alloc = { SzAlloc, SzFree };
-
-static void
-compress_kernel_lzma (char *kernel_img, size_t kernel_size,
-		      char **core_img, size_t *core_size)
-{
-  CLzmaEncProps props;
-  unsigned char out_props[5];
-  size_t out_props_size = 5;
-
-  LzmaEncProps_Init(&props);
-  props.dictSize = 1 << 16;
-  props.lc = 3;
-  props.lp = 0;
-  props.pb = 2;
-  props.numThreads = 1;
-
-  *core_img = xmalloc (kernel_size);
-
-  *core_size = kernel_size;
-  if (LzmaEncode ((unsigned char *) *core_img, core_size,
-		  (unsigned char *) kernel_img,
-		  kernel_size,
-		  &props, out_props, &out_props_size,
-		  0, NULL, &g_Alloc, &g_Alloc) != SZ_OK)
-    grub_util_error ("%s", _("cannot compress the kernel image"));
-}
-
-#ifdef HAVE_LIBLZMA
-static void
-compress_kernel_xz (char *kernel_img, size_t kernel_size,
-		    char **core_img, size_t *core_size)
-{
-  lzma_stream strm = LZMA_STREAM_INIT;
-  lzma_ret xzret;
-  lzma_options_lzma lzopts = {
-    .dict_size = 1 << 16,
-    .preset_dict = NULL,
-    .preset_dict_size = 0,
-    .lc = 3,
-    .lp = 0,
-    .pb = 2,
-    .mode = LZMA_MODE_NORMAL,
-    .nice_len = 64,
-    .mf = LZMA_MF_BT4,
-    .depth = 0,
-  };
-  lzma_filter fltrs[] = {
-    { .id = LZMA_FILTER_LZMA2, .options = &lzopts},
-    { .id = LZMA_VLI_UNKNOWN, .options = NULL}
-  };
-
-  xzret = lzma_stream_encoder (&strm, fltrs, LZMA_CHECK_NONE);
-  if (xzret != LZMA_OK)
-    grub_util_error ("%s", _("cannot compress the kernel image"));
-
-  *core_img = xmalloc (kernel_size);
-
-  *core_size = kernel_size;
-  strm.next_in = (unsigned char *) kernel_img;
-  strm.avail_in = kernel_size;
-  strm.next_out = (unsigned char *) *core_img;
-  strm.avail_out = *core_size;
-
-  while (1)
-    {
-      xzret = lzma_code (&strm, LZMA_FINISH);
-      if (xzret == LZMA_OK)
-	continue;
-      if (xzret == LZMA_STREAM_END)
-	break;
-      grub_util_error ("%s", _("cannot compress the kernel image"));
-    }
-
-  *core_size -= strm.avail_out;
-}
-#endif
-
-static void
-compress_kernel (struct image_target_desc *image_target, char *kernel_img,
-		 size_t kernel_size, char **core_img, size_t *core_size,
-		 grub_compression_t comp)
-{
-  if (image_target->flags & PLATFORM_FLAGS_DECOMPRESSORS
-      && (comp == COMPRESSION_LZMA))
-    {
-      compress_kernel_lzma (kernel_img, kernel_size, core_img,
-			    core_size);
-      return;
-    }
-
-#ifdef HAVE_LIBLZMA
- if (image_target->flags & PLATFORM_FLAGS_DECOMPRESSORS
-     && (comp == COMPRESSION_XZ))
-   {
-     compress_kernel_xz (kernel_img, kernel_size, core_img,
-			 core_size);
-     return;
-   }
-#endif
-
- if (image_target->flags & PLATFORM_FLAGS_DECOMPRESSORS
-     && (comp != COMPRESSION_NONE))
-   grub_util_error (_("unknown compression %d\n"), comp);
-
-  *core_img = xmalloc (kernel_size);
-  memcpy (*core_img, kernel_img, kernel_size);
-  *core_size = kernel_size;
-}
-
-struct fixup_block_list
-{
-  struct fixup_block_list *next;
-  int state;
-  struct grub_pe32_fixup_block b;
-};
-
-#pragma GCC diagnostic ignored "-Wcast-align"
-
-#define MKIMAGE_ELF32 1
-#include "grub-mkimagexx.c"
-#undef MKIMAGE_ELF32
-
-#define MKIMAGE_ELF64 1
-#include "grub-mkimagexx.c"
-#undef MKIMAGE_ELF64
-
-static void
-generate_image (const char *dir, const char *prefix,
-		FILE *out, const char *outname, char *mods[],
-		char *memdisk_path, char **pubkey_paths, size_t npubkeys,
-		char *config_path, struct image_target_desc *image_target, int note,
-		grub_compression_t comp)
-{
-  char *kernel_img, *core_img;
-  size_t kernel_size, total_module_size, core_size, exec_size;
-  size_t memdisk_size = 0, config_size = 0, config_size_pure = 0;
-  size_t prefix_size = 0;
-  char *kernel_path;
-  size_t offset;
-  struct grub_util_path_list *path_list, *p, *next;
-  grub_size_t bss_size;
-  grub_uint64_t start_address;
-  void *rel_section = 0;
-  grub_size_t reloc_size = 0, align;
-  size_t decompress_size = 0;
-
-  if (comp == COMPRESSION_AUTO)
-    comp = image_target->default_compression;
-
-  if (image_target->id == IMAGE_I386_PC
-      || image_target->id == IMAGE_I386_PC_PXE)
-    comp = COMPRESSION_LZMA;
-
-  path_list = grub_util_resolve_dependencies (dir, "moddep.lst", mods);
-
-  kernel_path = grub_util_get_path (dir, "kernel.img");
-
-  if (image_target->voidp_sizeof == 8)
-    total_module_size = sizeof (struct grub_module_info64);
-  else
-    total_module_size = sizeof (struct grub_module_info32);
-
-  {
-    size_t i;
-    for (i = 0; i < npubkeys; i++)
-      {
-	size_t curs;
-	curs = ALIGN_ADDR (grub_util_get_image_size (pubkey_paths[i]));
-	grub_util_info ("the size of public key %zd is 0x%llx",
-			i, (unsigned long long) curs);
-	total_module_size += curs + sizeof (struct grub_module_header);
-      }
-  }
-
-  if (memdisk_path)
-    {
-      memdisk_size = ALIGN_UP(grub_util_get_image_size (memdisk_path), 512);
-      grub_util_info ("the size of memory disk is 0x%llx",
-		      (unsigned long long) memdisk_size);
-      total_module_size += memdisk_size + sizeof (struct grub_module_header);
-    }
-
-  if (config_path)
-    {
-      config_size_pure = grub_util_get_image_size (config_path) + 1;
-      config_size = ALIGN_ADDR (config_size_pure);
-      grub_util_info ("the size of config file is 0x%llx",
-		      (unsigned long long) config_size);
-      total_module_size += config_size + sizeof (struct grub_module_header);
-    }
-
-  if (prefix)
-    {
-      prefix_size = ALIGN_ADDR (strlen (prefix) + 1);
-      total_module_size += prefix_size + sizeof (struct grub_module_header);
-    }
-
-  for (p = path_list; p; p = p->next)
-    total_module_size += (ALIGN_ADDR (grub_util_get_image_size (p->name))
-			  + sizeof (struct grub_module_header));
-
-  grub_util_info ("the total module size is 0x%llx",
-		  (unsigned long long) total_module_size);
-
-  if (image_target->voidp_sizeof == 4)
-    kernel_img = load_image32 (kernel_path, &exec_size, &kernel_size, &bss_size,
-			       total_module_size, &start_address, &rel_section,
-			       &reloc_size, &align, image_target);
-  else
-    kernel_img = load_image64 (kernel_path, &exec_size, &kernel_size, &bss_size,
-			       total_module_size, &start_address, &rel_section,
-			       &reloc_size, &align, image_target);
-
-  if ((image_target->flags & PLATFORM_FLAGS_DECOMPRESSORS)
-      && (image_target->total_module_size != TARGET_NO_FIELD))
-    *((grub_uint32_t *) (kernel_img + image_target->total_module_size))
-      = grub_host_to_target32 (total_module_size);
-
-  if (image_target->flags & PLATFORM_FLAGS_MODULES_BEFORE_KERNEL)
-    memmove (kernel_img + total_module_size, kernel_img, kernel_size);
-
-  if (image_target->voidp_sizeof == 8)
-    {
-      /* Fill in the grub_module_info structure.  */
-      struct grub_module_info64 *modinfo;
-      if (image_target->flags & PLATFORM_FLAGS_MODULES_BEFORE_KERNEL)
-	modinfo = (struct grub_module_info64 *) kernel_img;
-      else
-	modinfo = (struct grub_module_info64 *) (kernel_img + kernel_size);
-      memset (modinfo, 0, sizeof (struct grub_module_info64));
-      modinfo->magic = grub_host_to_target32 (GRUB_MODULE_MAGIC);
-      modinfo->offset = grub_host_to_target_addr (sizeof (struct grub_module_info64));
-      modinfo->size = grub_host_to_target_addr (total_module_size);
-      if (image_target->flags & PLATFORM_FLAGS_MODULES_BEFORE_KERNEL)
-	offset = sizeof (struct grub_module_info64);
-      else
-	offset = kernel_size + sizeof (struct grub_module_info64);
-    }
-  else
-    {
-      /* Fill in the grub_module_info structure.  */
-      struct grub_module_info32 *modinfo;
-      if (image_target->flags & PLATFORM_FLAGS_MODULES_BEFORE_KERNEL)
-	modinfo = (struct grub_module_info32 *) kernel_img;
-      else
-	modinfo = (struct grub_module_info32 *) (kernel_img + kernel_size);
-      memset (modinfo, 0, sizeof (struct grub_module_info32));
-      modinfo->magic = grub_host_to_target32 (GRUB_MODULE_MAGIC);
-      modinfo->offset = grub_host_to_target_addr (sizeof (struct grub_module_info32));
-      modinfo->size = grub_host_to_target_addr (total_module_size);
-      if (image_target->flags & PLATFORM_FLAGS_MODULES_BEFORE_KERNEL)
-	offset = sizeof (struct grub_module_info32);
-      else
-	offset = kernel_size + sizeof (struct grub_module_info32);
-    }
-
-  for (p = path_list; p; p = p->next)
-    {
-      struct grub_module_header *header;
-      size_t mod_size, orig_size;
-
-      orig_size = grub_util_get_image_size (p->name);
-      mod_size = ALIGN_ADDR (orig_size);
-
-      header = (struct grub_module_header *) (kernel_img + offset);
-      memset (header, 0, sizeof (struct grub_module_header));
-      header->type = grub_host_to_target32 (OBJ_TYPE_ELF);
-      header->size = grub_host_to_target32 (mod_size + sizeof (*header));
-      offset += sizeof (*header);
-      memset (kernel_img + offset + orig_size, 0, mod_size - orig_size);
-
-      grub_util_load_image (p->name, kernel_img + offset);
-      offset += mod_size;
-    }
-
-  {
-    size_t i;
-    for (i = 0; i < npubkeys; i++)
-      {
-	size_t curs;
-	struct grub_module_header *header;
-
-	curs = grub_util_get_image_size (pubkey_paths[i]);
-
-	header = (struct grub_module_header *) (kernel_img + offset);
-	memset (header, 0, sizeof (struct grub_module_header));
-	header->type = grub_host_to_target32 (OBJ_TYPE_PUBKEY);
-	header->size = grub_host_to_target32 (curs + sizeof (*header));
-	offset += sizeof (*header);
-
-	grub_util_load_image (pubkey_paths[i], kernel_img + offset);
-	offset += ALIGN_ADDR (curs);
-      }
-  }
-
-  if (memdisk_path)
-    {
-      struct grub_module_header *header;
-
-      header = (struct grub_module_header *) (kernel_img + offset);
-      memset (header, 0, sizeof (struct grub_module_header));
-      header->type = grub_host_to_target32 (OBJ_TYPE_MEMDISK);
-      header->size = grub_host_to_target32 (memdisk_size + sizeof (*header));
-      offset += sizeof (*header);
-
-      grub_util_load_image (memdisk_path, kernel_img + offset);
-      offset += memdisk_size;
-    }
-
-  if (config_path)
-    {
-      struct grub_module_header *header;
-
-      header = (struct grub_module_header *) (kernel_img + offset);
-      memset (header, 0, sizeof (struct grub_module_header));
-      header->type = grub_host_to_target32 (OBJ_TYPE_CONFIG);
-      header->size = grub_host_to_target32 (config_size + sizeof (*header));
-      offset += sizeof (*header);
-
-      grub_util_load_image (config_path, kernel_img + offset);
-      *(kernel_img + offset + config_size_pure - 1) = 0;
-      offset += config_size;
-    }
-
-  if (prefix)
-    {
-      struct grub_module_header *header;
-
-      header = (struct grub_module_header *) (kernel_img + offset);
-      memset (header, 0, sizeof (struct grub_module_header));
-      header->type = grub_host_to_target32 (OBJ_TYPE_PREFIX);
-      header->size = grub_host_to_target32 (prefix_size + sizeof (*header));
-      offset += sizeof (*header);
-
-      grub_memset (kernel_img + offset, 0, prefix_size);
-      grub_strcpy (kernel_img + offset, prefix);
-      offset += prefix_size;
-    }
-
-  grub_util_info ("kernel_img=%p, kernel_size=0x%llx", kernel_img,
-		  (unsigned long long) kernel_size);
-  compress_kernel (image_target, kernel_img, kernel_size + total_module_size,
-		   &core_img, &core_size, comp);
-  free (kernel_img);
-
-  grub_util_info ("the core size is 0x%llx", (unsigned long long) core_size);
-
-  if (!(image_target->flags & PLATFORM_FLAGS_DECOMPRESSORS) 
-      && image_target->total_module_size != TARGET_NO_FIELD)
-    *((grub_uint32_t *) (core_img + image_target->total_module_size))
-      = grub_host_to_target32 (total_module_size);
-
-  if (image_target->flags & PLATFORM_FLAGS_DECOMPRESSORS)
-    {
-      char *full_img;
-      size_t full_size;
-      char *decompress_path, *decompress_img;
-      const char *name;
-
-      switch (comp)
-	{
-	case COMPRESSION_XZ:
-	  name = "xz_decompress.img";
-	  break;
-	case COMPRESSION_LZMA:
-	  name = "lzma_decompress.img";
-	  break;
-	case COMPRESSION_NONE:
-	  name = "none_decompress.img";
-	  break;
-	default:
-	  grub_util_error (_("unknown compression %d\n"), comp);
-	}
-      
-      decompress_path = grub_util_get_path (dir, name);
-      decompress_size = grub_util_get_image_size (decompress_path);
-      decompress_img = grub_util_read_image (decompress_path);
-
-      if ((image_target->id == IMAGE_I386_PC
-	   || image_target->id == IMAGE_I386_PC_PXE)
-	  && decompress_size > GRUB_KERNEL_I386_PC_LINK_ADDR - 0x8200)
-	grub_util_error ("%s", _("Decompressor is too big"));
-
-      if (image_target->decompressor_compressed_size != TARGET_NO_FIELD)
-	*((grub_uint32_t *) (decompress_img
-			     + image_target->decompressor_compressed_size))
-	  = grub_host_to_target32 (core_size);
-
-      if (image_target->decompressor_uncompressed_size != TARGET_NO_FIELD)
-	*((grub_uint32_t *) (decompress_img
-			     + image_target->decompressor_uncompressed_size))
-	  = grub_host_to_target32 (kernel_size + total_module_size);
-
-      if (image_target->decompressor_uncompressed_addr != TARGET_NO_FIELD)
-	{
-	  if (image_target->flags & PLATFORM_FLAGS_MODULES_BEFORE_KERNEL)
-	    *((grub_uint32_t *) (decompress_img + image_target->decompressor_uncompressed_addr))
-	      = grub_host_to_target_addr (image_target->link_addr - total_module_size);
-	  else
-	    *((grub_uint32_t *) (decompress_img + image_target->decompressor_uncompressed_addr))
-	      = grub_host_to_target_addr (image_target->link_addr);
-	}
-      full_size = core_size + decompress_size;
-
-      full_img = xmalloc (full_size);
-      memset (full_img, 0, full_size); 
-
-      memcpy (full_img, decompress_img, decompress_size);
-
-      memcpy (full_img + decompress_size, core_img, core_size);
-
-      memset (full_img + decompress_size + core_size, 0,
-	      full_size - (decompress_size + core_size));
-
-      free (core_img);
-      core_img = full_img;
-      core_size = full_size;
-    }
-
-  switch (image_target->id)
-    {
-    case IMAGE_I386_PC:
-    case IMAGE_I386_PC_PXE:
-	if (GRUB_KERNEL_I386_PC_LINK_ADDR + core_size > 0x78000
-	    || (core_size > (0xffff << GRUB_DISK_SECTOR_BITS))
-	    || (kernel_size + bss_size + GRUB_KERNEL_I386_PC_LINK_ADDR > 0x68000))
-	  grub_util_error (_("core image is too big (0x%x > 0x%x)"),
-			   GRUB_KERNEL_I386_PC_LINK_ADDR + (unsigned) core_size,
-			   0x78000);
-	/* fallthrough */
-    case IMAGE_COREBOOT:
-    case IMAGE_QEMU:
-	if (kernel_size + bss_size + GRUB_KERNEL_I386_PC_LINK_ADDR > 0x68000)
-	  grub_util_error (_("kernel image is too big (0x%x > 0x%x)"),
-			   (unsigned) kernel_size + (unsigned) bss_size
-			   + GRUB_KERNEL_I386_PC_LINK_ADDR,
-			   0x68000);
-	break;
-    case IMAGE_LOONGSON_ELF:
-    case IMAGE_YEELOONG_FLASH:
-    case IMAGE_FULOONG2F_FLASH:
-    case IMAGE_EFI:
-    case IMAGE_MIPS_ARC:
-    case IMAGE_QEMU_MIPS_FLASH:
-      break;
-    case IMAGE_SPARC64_AOUT:
-    case IMAGE_SPARC64_RAW:
-    case IMAGE_SPARC64_CDCORE:
-    case IMAGE_I386_IEEE1275:
-    case IMAGE_PPC:
-    case IMAGE_UBOOT:
-      break;
-    }
-
-  switch (image_target->id)
-    {
-    case IMAGE_I386_PC:
-    case IMAGE_I386_PC_PXE:
-      {
-	unsigned num;
-	char *boot_path, *boot_img;
-	size_t boot_size;
-
-	num = ((core_size + GRUB_DISK_SECTOR_SIZE - 1) >> GRUB_DISK_SECTOR_BITS);
-	if (image_target->id == IMAGE_I386_PC_PXE)
-	  {
-	    char *pxeboot_path, *pxeboot_img;
-	    size_t pxeboot_size;
-	    grub_uint32_t *ptr;
-	    
-	    pxeboot_path = grub_util_get_path (dir, "pxeboot.img");
-	    pxeboot_size = grub_util_get_image_size (pxeboot_path);
-	    pxeboot_img = grub_util_read_image (pxeboot_path);
-	    
-	    grub_util_write_image (pxeboot_img, pxeboot_size, out,
-				   outname);
-	    free (pxeboot_img);
-	    free (pxeboot_path);
-
-	    /* Remove Multiboot header to avoid confusing ipxe.  */
-	    for (ptr = (grub_uint32_t *) core_img;
-		 ptr < (grub_uint32_t *) (core_img + MULTIBOOT_SEARCH); ptr++)
-	      if (*ptr == grub_host_to_target32 (MULTIBOOT_HEADER_MAGIC)
-		  && grub_target_to_host32 (ptr[0])
-		  + grub_target_to_host32 (ptr[1])
-		  + grub_target_to_host32 (ptr[2]) == 0)
-		{
-		  *ptr = 0;
-		  break;
-		}
-	  }
-
-	boot_path = grub_util_get_path (dir, "diskboot.img");
-	boot_size = grub_util_get_image_size (boot_path);
-	if (boot_size != GRUB_DISK_SECTOR_SIZE)
-	  grub_util_error (_("diskboot.img size must be %u bytes"),
-			   GRUB_DISK_SECTOR_SIZE);
-
-	boot_img = grub_util_read_image (boot_path);
-
-	{
-	  struct grub_pc_bios_boot_blocklist *block;
-	  block = (struct grub_pc_bios_boot_blocklist *) (boot_img
-							  + GRUB_DISK_SECTOR_SIZE
-							  - sizeof (*block));
-	  block->len = grub_host_to_target16 (num);
-
-	  /* This is filled elsewhere.  Verify it just in case.  */
-	  assert (block->segment
-		  == grub_host_to_target16 (GRUB_BOOT_I386_PC_KERNEL_SEG
-					    + (GRUB_DISK_SECTOR_SIZE >> 4)));
-	}
-
-	grub_util_write_image (boot_img, boot_size, out, outname);
-	free (boot_img);
-	free (boot_path);
-      }
-      break;
-    case IMAGE_EFI:
-      {
-	void *pe_img;
-	grub_uint8_t *header;
-	void *sections;
-	size_t pe_size;
-	struct grub_pe32_coff_header *c;
-	struct grub_pe32_section_table *text_section, *data_section;
-	struct grub_pe32_section_table *mods_section, *reloc_section;
-	static const grub_uint8_t stub[] = GRUB_PE32_MSDOS_STUB;
-	int header_size;
-	int reloc_addr;
-
-	if (image_target->voidp_sizeof == 4)
-	  header_size = EFI32_HEADER_SIZE;
-	else
-	  header_size = EFI64_HEADER_SIZE;
-
-	reloc_addr = ALIGN_UP (header_size + core_size,
-			       image_target->section_align);
-
-	pe_size = ALIGN_UP (reloc_addr + reloc_size,
-			    image_target->section_align);
-	pe_img = xmalloc (reloc_addr + reloc_size);
-	memset (pe_img, 0, header_size);
-	memcpy ((char *) pe_img + header_size, core_img, core_size);
-	memcpy ((char *) pe_img + reloc_addr, rel_section, reloc_size);
-	header = pe_img;
-
-	/* The magic.  */
-	memcpy (header, stub, GRUB_PE32_MSDOS_STUB_SIZE);
-	memcpy (header + GRUB_PE32_MSDOS_STUB_SIZE, "PE\0\0",
-		GRUB_PE32_SIGNATURE_SIZE);
-
-	/* The COFF file header.  */
-	c = (struct grub_pe32_coff_header *) (header + GRUB_PE32_MSDOS_STUB_SIZE
-					      + GRUB_PE32_SIGNATURE_SIZE);
-	c->machine = grub_host_to_target16 (image_target->pe_target);
-
-	c->num_sections = grub_host_to_target16 (4);
-	c->time = grub_host_to_target32 (time (0));
-	c->characteristics = grub_host_to_target16 (GRUB_PE32_EXECUTABLE_IMAGE
-						    | GRUB_PE32_LINE_NUMS_STRIPPED
-						    | ((image_target->voidp_sizeof == 4)
-						       ? GRUB_PE32_32BIT_MACHINE
-						       : 0)
-						    | GRUB_PE32_LOCAL_SYMS_STRIPPED
-						    | GRUB_PE32_DEBUG_STRIPPED);
-
-	/* The PE Optional header.  */
-	if (image_target->voidp_sizeof == 4)
-	  {
-	    struct grub_pe32_optional_header *o;
-
-	    c->optional_header_size = grub_host_to_target16 (sizeof (struct grub_pe32_optional_header));
-
-	    o = (struct grub_pe32_optional_header *)
-	      (header + GRUB_PE32_MSDOS_STUB_SIZE + GRUB_PE32_SIGNATURE_SIZE
-	       + sizeof (struct grub_pe32_coff_header));
-	    o->magic = grub_host_to_target16 (GRUB_PE32_PE32_MAGIC);
-	    o->code_size = grub_host_to_target32 (exec_size);
-	    o->data_size = grub_cpu_to_le32 (reloc_addr - exec_size
-					     - header_size);
-	    o->bss_size = grub_cpu_to_le32 (bss_size);
-	    o->entry_addr = grub_cpu_to_le32 (start_address);
-	    o->code_base = grub_cpu_to_le32 (header_size);
-
-	    o->data_base = grub_host_to_target32 (header_size + exec_size);
-
-	    o->image_base = 0;
-	    o->section_alignment = grub_host_to_target32 (image_target->section_align);
-	    o->file_alignment = grub_host_to_target32 (image_target->section_align);
-	    o->image_size = grub_host_to_target32 (pe_size);
-	    o->header_size = grub_host_to_target32 (header_size);
-	    o->subsystem = grub_host_to_target16 (GRUB_PE32_SUBSYSTEM_EFI_APPLICATION);
-
-	    /* Do these really matter? */
-	    o->stack_reserve_size = grub_host_to_target32 (0x10000);
-	    o->stack_commit_size = grub_host_to_target32 (0x10000);
-	    o->heap_reserve_size = grub_host_to_target32 (0x10000);
-	    o->heap_commit_size = grub_host_to_target32 (0x10000);
-    
-	    o->num_data_directories = grub_host_to_target32 (GRUB_PE32_NUM_DATA_DIRECTORIES);
-
-	    o->base_relocation_table.rva = grub_host_to_target32 (reloc_addr);
-	    o->base_relocation_table.size = grub_host_to_target32 (reloc_size);
-	    sections = o + 1;
-	  }
-	else
-	  {
-	    struct grub_pe64_optional_header *o;
-
-	    c->optional_header_size = grub_host_to_target16 (sizeof (struct grub_pe64_optional_header));
-
-	    o = (struct grub_pe64_optional_header *) 
-	      (header + GRUB_PE32_MSDOS_STUB_SIZE + GRUB_PE32_SIGNATURE_SIZE
-	       + sizeof (struct grub_pe32_coff_header));
-	    o->magic = grub_host_to_target16 (GRUB_PE32_PE64_MAGIC);
-	    o->code_size = grub_host_to_target32 (exec_size);
-	    o->data_size = grub_cpu_to_le32 (reloc_addr - exec_size
-					     - header_size);
-	    o->bss_size = grub_cpu_to_le32 (bss_size);
-	    o->entry_addr = grub_cpu_to_le32 (start_address);
-	    o->code_base = grub_cpu_to_le32 (header_size);
-	    o->image_base = 0;
-	    o->section_alignment = grub_host_to_target32 (image_target->section_align);
-	    o->file_alignment = grub_host_to_target32 (image_target->section_align);
-	    o->image_size = grub_host_to_target32 (pe_size);
-	    o->header_size = grub_host_to_target32 (header_size);
-	    o->subsystem = grub_host_to_target16 (GRUB_PE32_SUBSYSTEM_EFI_APPLICATION);
-
-	    /* Do these really matter? */
-	    o->stack_reserve_size = grub_host_to_target64 (0x10000);
-	    o->stack_commit_size = grub_host_to_target64 (0x10000);
-	    o->heap_reserve_size = grub_host_to_target64 (0x10000);
-	    o->heap_commit_size = grub_host_to_target64 (0x10000);
-    
-	    o->num_data_directories
-	      = grub_host_to_target32 (GRUB_PE32_NUM_DATA_DIRECTORIES);
-
-	    o->base_relocation_table.rva = grub_host_to_target32 (reloc_addr);
-	    o->base_relocation_table.size = grub_host_to_target32 (reloc_size);
-	    sections = o + 1;
-	  }
-	/* The sections.  */
-	text_section = sections;
-	strcpy (text_section->name, ".text");
-	text_section->virtual_size = grub_cpu_to_le32 (exec_size);
-	text_section->virtual_address = grub_cpu_to_le32 (header_size);
-	text_section->raw_data_size = grub_cpu_to_le32 (exec_size);
-	text_section->raw_data_offset = grub_cpu_to_le32 (header_size);
-	text_section->characteristics = grub_cpu_to_le32 (GRUB_PE32_SCN_CNT_CODE
-							  | GRUB_PE32_SCN_MEM_EXECUTE
-							  | GRUB_PE32_SCN_MEM_READ);
-
-	data_section = text_section + 1;
-	strcpy (data_section->name, ".data");
-	data_section->virtual_size = grub_cpu_to_le32 (kernel_size - exec_size);
-	data_section->virtual_address = grub_cpu_to_le32 (header_size + exec_size);
-	data_section->raw_data_size = grub_cpu_to_le32 (kernel_size - exec_size);
-	data_section->raw_data_offset = grub_cpu_to_le32 (header_size + exec_size);
-	data_section->characteristics
-	  = grub_cpu_to_le32 (GRUB_PE32_SCN_CNT_INITIALIZED_DATA
-			      | GRUB_PE32_SCN_MEM_READ
-			      | GRUB_PE32_SCN_MEM_WRITE);
-
-#if 0
-	bss_section = data_section + 1;
-	strcpy (bss_section->name, ".bss");
-	bss_section->virtual_size = grub_cpu_to_le32 (bss_size);
-	bss_section->virtual_address = grub_cpu_to_le32 (header_size + kernel_size);
-	bss_section->raw_data_size = 0;
-	bss_section->raw_data_offset = 0;
-	bss_section->characteristics
-	  = grub_cpu_to_le32 (GRUB_PE32_SCN_MEM_READ
-			      | GRUB_PE32_SCN_MEM_WRITE
-			      | GRUB_PE32_SCN_ALIGN_64BYTES
-			      | GRUB_PE32_SCN_CNT_INITIALIZED_DATA
-			      | 0x80);
-#endif
-    
-	mods_section = data_section + 1;
-	strcpy (mods_section->name, "mods");
-	mods_section->virtual_size = grub_cpu_to_le32 (reloc_addr - kernel_size - header_size);
-	mods_section->virtual_address = grub_cpu_to_le32 (header_size + kernel_size + bss_size);
-	mods_section->raw_data_size = grub_cpu_to_le32 (reloc_addr - kernel_size - header_size);
-	mods_section->raw_data_offset = grub_cpu_to_le32 (header_size + kernel_size);
-	mods_section->characteristics
-	  = grub_cpu_to_le32 (GRUB_PE32_SCN_CNT_INITIALIZED_DATA
-			      | GRUB_PE32_SCN_MEM_READ
-			      | GRUB_PE32_SCN_MEM_WRITE);
-
-	reloc_section = mods_section + 1;
-	strcpy (reloc_section->name, ".reloc");
-	reloc_section->virtual_size = grub_cpu_to_le32 (reloc_size);
-	reloc_section->virtual_address = grub_cpu_to_le32 (reloc_addr + bss_size);
-	reloc_section->raw_data_size = grub_cpu_to_le32 (reloc_size);
-	reloc_section->raw_data_offset = grub_cpu_to_le32 (reloc_addr);
-	reloc_section->characteristics
-	  = grub_cpu_to_le32 (GRUB_PE32_SCN_CNT_INITIALIZED_DATA
-			      | GRUB_PE32_SCN_MEM_DISCARDABLE
-			      | GRUB_PE32_SCN_MEM_READ);
-	free (core_img);
-	core_img = pe_img;
-	core_size = pe_size;
-      }
-      break;
-    case IMAGE_QEMU:
-      {
-	char *rom_img;
-	size_t rom_size;
-	char *boot_path, *boot_img;
-	size_t boot_size;
-
-	boot_path = grub_util_get_path (dir, "boot.img");
-	boot_size = grub_util_get_image_size (boot_path);
-	boot_img = grub_util_read_image (boot_path);
-
-	/* Rom sizes must be 64k-aligned.  */
-	rom_size = ALIGN_UP (core_size + boot_size, 64 * 1024);
-
-	rom_img = xmalloc (rom_size);
-	memset (rom_img, 0, rom_size);
-
-	*((grub_int32_t *) (core_img + GRUB_KERNEL_I386_QEMU_CORE_ENTRY_ADDR))
-	  = grub_host_to_target32 ((grub_uint32_t) -rom_size);
-
-	memcpy (rom_img, core_img, core_size);
-
-	*((grub_int32_t *) (boot_img + GRUB_BOOT_I386_QEMU_CORE_ENTRY_ADDR))
-	  = grub_host_to_target32 ((grub_uint32_t) -rom_size);
-
-	memcpy (rom_img + rom_size - boot_size, boot_img, boot_size);
-
-	free (core_img);
-	core_img = rom_img;
-	core_size = rom_size;
-
-	free (boot_img);
-	free (boot_path);
-      }
-      break;
-    case IMAGE_SPARC64_AOUT:
-      {
-	void *aout_img;
-	size_t aout_size;
-	struct grub_aout32_header *aout_head;
-
-	aout_size = core_size + sizeof (*aout_head);
-	aout_img = xmalloc (aout_size);
-	aout_head = aout_img;
-	grub_memset (aout_head, 0, sizeof (*aout_head));
-	aout_head->a_midmag = grub_host_to_target32 ((AOUT_MID_SUN << 16)
-						     | AOUT32_OMAGIC);
-	aout_head->a_text = grub_host_to_target32 (core_size);
-	aout_head->a_entry
-	  = grub_host_to_target32 (GRUB_BOOT_SPARC64_IEEE1275_IMAGE_ADDRESS);
-	memcpy ((char *) aout_img + sizeof (*aout_head), core_img, core_size);
-
-	free (core_img);
-	core_img = aout_img;
-	core_size = aout_size;
-      }
-      break;
-    case IMAGE_SPARC64_RAW:
-      {
-	unsigned int num;
-	char *boot_path, *boot_img;
-	size_t boot_size;
-
-	num = ((core_size + GRUB_DISK_SECTOR_SIZE - 1) >> GRUB_DISK_SECTOR_BITS);
-	num <<= GRUB_DISK_SECTOR_BITS;
-
-	boot_path = grub_util_get_path (dir, "diskboot.img");
-	boot_size = grub_util_get_image_size (boot_path);
-	if (boot_size != GRUB_DISK_SECTOR_SIZE)
-	  grub_util_error (_("diskboot.img size must be %u bytes"),
-			   GRUB_DISK_SECTOR_SIZE);
-
-	boot_img = grub_util_read_image (boot_path);
-
-	*((grub_uint32_t *) (boot_img + GRUB_DISK_SECTOR_SIZE
-			     - GRUB_BOOT_SPARC64_IEEE1275_LIST_SIZE + 8))
-	  = grub_host_to_target32 (num);
-
-	grub_util_write_image (boot_img, boot_size, out, outname);
-	free (boot_img);
-	free (boot_path);
-      }
-      break;
-    case IMAGE_SPARC64_CDCORE:
-      break;
-    case IMAGE_YEELOONG_FLASH:
-    case IMAGE_FULOONG2F_FLASH:
-    {
-      char *rom_img;
-      size_t rom_size;
-      char *boot_path, *boot_img;
-      size_t boot_size;
-      grub_uint8_t context[GRUB_MD_SHA512->contextsize];
-      /* fwstart.img is the only part which can't be tested by using *-elf
-	 target. Check it against the checksum. */
-      const grub_uint8_t yeeloong_fwstart_good_hash[512 / 8] = 
-	{
-	  0x5f, 0x67, 0x46, 0x57, 0x31, 0x30, 0xc5, 0x0a,
-	  0xe9, 0x98, 0x18, 0xc9, 0xf3, 0xca, 0x45, 0xa5,
-	  0x75, 0x64, 0x6b, 0xbb, 0x24, 0xcd, 0xb4, 0xbc,
-	  0xf2, 0x3e, 0x23, 0xf9, 0xc2, 0x6a, 0x8c, 0xde,
-	  0x3b, 0x94, 0x9c, 0xcc, 0xa5, 0xa7, 0x58, 0xb1,
-	  0xbe, 0x8b, 0x3d, 0x73, 0x98, 0x18, 0x7e, 0x68,
-	  0x5e, 0x5f, 0x23, 0x7d, 0x7a, 0xe8, 0x51, 0xf7,
-	  0x1a, 0xaf, 0x2f, 0x54, 0x11, 0x2e, 0x5c, 0x25
-	};
-      const grub_uint8_t fuloong2f_fwstart_good_hash[512 / 8] = 
-	{ 
-	  0x76, 0x9b, 0xad, 0x6e, 0xa2, 0x39, 0x47, 0x62,
-	  0x1f, 0xc9, 0x3a, 0x6d, 0x05, 0x5c, 0x43, 0x5c,
-	  0x29, 0x4a, 0x7e, 0x08, 0x2a, 0x31, 0x8f, 0x5d,
-	  0x02, 0x84, 0xa0, 0x85, 0xf2, 0xd1, 0xb9, 0x53,
-	  0xa2, 0xbc, 0xf2, 0xe1, 0x39, 0x1e, 0x51, 0xb5,
-	  0xaf, 0xec, 0x9e, 0xf2, 0xf1, 0xf3, 0x0a, 0x2f,
-	  0xe6, 0xf1, 0x08, 0x89, 0xbe, 0xbc, 0x73, 0xab,
-	  0x46, 0x50, 0xd6, 0x21, 0xce, 0x8e, 0x24, 0xa7
-	};
-      const grub_uint8_t *fwstart_good_hash;
-            
-      if (image_target->id == IMAGE_FULOONG2F_FLASH)
-	{
-	  fwstart_good_hash = fuloong2f_fwstart_good_hash;
-	  boot_path = grub_util_get_path (dir, "fwstart_fuloong2f.img");
-	}
-      else
-	{
-	  fwstart_good_hash = yeeloong_fwstart_good_hash;
-	  boot_path = grub_util_get_path (dir, "fwstart.img");
-	}
-
-      boot_size = grub_util_get_image_size (boot_path);
-      boot_img = grub_util_read_image (boot_path);
-
-      grub_memset (context, 0, sizeof (context));
-      GRUB_MD_SHA512->init (context);
-      GRUB_MD_SHA512->write (context, boot_img, boot_size);
-      GRUB_MD_SHA512->final (context);
-      if (grub_memcmp (GRUB_MD_SHA512->read (context), fwstart_good_hash,
-		       GRUB_MD_SHA512->mdlen) != 0)
-	/* TRANSLATORS: fwstart.img may still be good, just it wasn't checked.  */
-	grub_util_warn ("%s",
-			_("fwstart.img doesn't match the known good version. "
-			  "proceed at your own risk"));
-
-      if (core_size + boot_size > 512 * 1024)
-	grub_util_error ("%s", _("firmware image is too big"));
-      rom_size = 512 * 1024;
-
-      rom_img = xmalloc (rom_size);
-      memset (rom_img, 0, rom_size); 
-
-      memcpy (rom_img, boot_img, boot_size);
-
-      memcpy (rom_img + boot_size, core_img, core_size);
-
-      memset (rom_img + boot_size + core_size, 0,
-	      rom_size - (boot_size + core_size));
-
-      free (core_img);
-      core_img = rom_img;
-      core_size = rom_size;
-    }
-    break;
-    case IMAGE_QEMU_MIPS_FLASH:
-    {
-      char *rom_img;
-      size_t rom_size;
-
-      if (core_size > 512 * 1024)
-	grub_util_error ("%s", _("firmware image is too big"));
-      rom_size = 512 * 1024;
-
-      rom_img = xmalloc (rom_size);
-      memset (rom_img, 0, rom_size); 
-
-      memcpy (rom_img, core_img, core_size);
-
-      memset (rom_img + core_size, 0,
-	      rom_size - core_size);
-
-      free (core_img);
-      core_img = rom_img;
-      core_size = rom_size;
-    }
-    break;
-
-    case IMAGE_UBOOT:
-    {
-      struct grub_uboot_image_header *hdr;
-      GRUB_PROPERLY_ALIGNED_ARRAY (crc32_context, GRUB_MD_CRC32->contextsize);
-
-      hdr = xmalloc (core_size + sizeof (struct grub_uboot_image_header));
-      memcpy (hdr + 1, core_img, core_size);
-
-      memset (hdr, 0, sizeof (*hdr));
-      hdr->ih_magic = grub_cpu_to_be32_compile_time (GRUB_UBOOT_IH_MAGIC);
-      hdr->ih_time = grub_cpu_to_be32 (time (0));
-      hdr->ih_size = grub_cpu_to_be32 (core_size);
-      hdr->ih_load = grub_cpu_to_be32 (image_target->link_addr);
-      hdr->ih_ep = grub_cpu_to_be32 (image_target->link_addr);
-      hdr->ih_type = GRUB_UBOOT_IH_TYPE_KERNEL;
-      hdr->ih_os = GRUB_UBOOT_IH_OS_LINUX;
-      hdr->ih_arch = GRUB_UBOOT_IH_ARCH_ARM;
-      hdr->ih_comp = GRUB_UBOOT_IH_COMP_NONE;
-
-      GRUB_MD_CRC32->init(crc32_context);
-      GRUB_MD_CRC32->write(crc32_context, hdr + 1, core_size);
-      GRUB_MD_CRC32->final(crc32_context);
-      hdr->ih_dcrc = grub_get_unaligned32 (GRUB_MD_CRC32->read (crc32_context));
-
-      GRUB_MD_CRC32->init(crc32_context);
-      GRUB_MD_CRC32->write(crc32_context, hdr, sizeof (*hdr));
-      GRUB_MD_CRC32->final(crc32_context);
-      hdr->ih_hcrc = grub_get_unaligned32 (GRUB_MD_CRC32->read (crc32_context));
-
-      free (core_img);
-      core_img = (char *) hdr;
-      core_size += sizeof (struct grub_uboot_image_header);
-    }
-    break;
-
-    case IMAGE_MIPS_ARC:
-      {
-	char *ecoff_img;
-	struct ecoff_header {
-	  grub_uint16_t magic;
-	  grub_uint16_t nsec;
-	  grub_uint32_t time;
-	  grub_uint32_t syms;
-	  grub_uint32_t nsyms;
-	  grub_uint16_t opt;
-	  grub_uint16_t flags;
-	  grub_uint16_t magic2;
-	  grub_uint16_t version;
-	  grub_uint32_t textsize;
-	  grub_uint32_t datasize;
-	  grub_uint32_t bsssize;
-	  grub_uint32_t entry;
-	  grub_uint32_t text_start;
-	  grub_uint32_t data_start;
-	  grub_uint32_t bss_start;
-	  grub_uint32_t gprmask;
-	  grub_uint32_t cprmask[4];
-	  grub_uint32_t gp_value;
-	};
-	struct ecoff_section
-	{
-	  char name[8];
-	  grub_uint32_t paddr;
-	  grub_uint32_t vaddr;
-	  grub_uint32_t size;
-	  grub_uint32_t file_offset;
-	  grub_uint32_t reloc;
-	  grub_uint32_t gp;
-	  grub_uint16_t nreloc;
-	  grub_uint16_t ngp;
-	  grub_uint32_t flags;
-	};
-	struct ecoff_header *head;
-	struct ecoff_section *section;
-	grub_uint32_t target_addr;
-	size_t program_size;
-
-	program_size = ALIGN_ADDR (core_size);
-	if (comp == COMPRESSION_NONE)
-	  target_addr = (image_target->link_addr - decompress_size);
-	else
-	  target_addr = ALIGN_UP (image_target->link_addr
-				  + kernel_size + total_module_size, 32);
-
-	ecoff_img = xmalloc (program_size + sizeof (*head) + sizeof (*section));
-	grub_memset (ecoff_img, 0, program_size + sizeof (*head) + sizeof (*section));
-	head = (void *) ecoff_img;
-	section = (void *) (head + 1);
-	head->magic = image_target->bigendian ? grub_host_to_target16 (0x160)
-	  : grub_host_to_target16 (0x166);
-	head->nsec = grub_host_to_target16 (1);
-	head->time = grub_host_to_target32 (0);
-	head->opt = grub_host_to_target16 (0x38);
-	head->flags = image_target->bigendian
-	  ? grub_host_to_target16 (0x207)
-	  : grub_host_to_target16 (0x103);
-	head->magic2 = grub_host_to_target16 (0x107);
-	head->textsize = grub_host_to_target32 (program_size);
-	head->entry = grub_host_to_target32 (target_addr);
-	head->text_start = grub_host_to_target32 (target_addr);
-	head->data_start = grub_host_to_target32 (target_addr + program_size);
-	grub_memcpy (section->name, ".text", sizeof (".text") - 1); 
-	section->vaddr = grub_host_to_target32 (target_addr);
-	section->size = grub_host_to_target32 (program_size);
-	section->file_offset = grub_host_to_target32 (sizeof (*head) + sizeof (*section));
-	if (!image_target->bigendian)
-	  {
-	    section->paddr = grub_host_to_target32 (0xaa60);
-	    section->flags = grub_host_to_target32 (0x20);
-	  }
-	memcpy (section + 1, core_img, core_size);
-	free (core_img);
-	core_img = ecoff_img;
-	core_size = program_size + sizeof (*head) + sizeof (*section);
-      }
-      break;
-    case IMAGE_LOONGSON_ELF:
-    case IMAGE_PPC:
-    case IMAGE_COREBOOT:
-    case IMAGE_I386_IEEE1275:
-      {
-	char *elf_img;
-	size_t program_size;
-	Elf32_Ehdr *ehdr;
-	Elf32_Phdr *phdr;
-	grub_uint32_t target_addr;
-	int header_size, footer_size = 0;
-	int phnum = 1;
-	
-	if (image_target->id != IMAGE_LOONGSON_ELF)
-	  phnum += 2;
-
-	if (note)
-	  {
-	    phnum++;
-	    footer_size += sizeof (struct grub_ieee1275_note);
-	  }
-	header_size = ALIGN_ADDR (sizeof (*ehdr) + phnum * sizeof (*phdr));
-
-	program_size = ALIGN_ADDR (core_size);
-
-	elf_img = xmalloc (program_size + header_size + footer_size);
-	memset (elf_img, 0, program_size + header_size);
-	memcpy (elf_img  + header_size, core_img, core_size);
-	ehdr = (void *) elf_img;
-	phdr = (void *) (elf_img + sizeof (*ehdr));
-	memcpy (ehdr->e_ident, ELFMAG, SELFMAG);
-	ehdr->e_ident[EI_CLASS] = ELFCLASS32;
-	if (!image_target->bigendian)
-	  ehdr->e_ident[EI_DATA] = ELFDATA2LSB;
-	else
-	  ehdr->e_ident[EI_DATA] = ELFDATA2MSB;
-	ehdr->e_ident[EI_VERSION] = EV_CURRENT;
-	ehdr->e_ident[EI_OSABI] = ELFOSABI_NONE;
-	ehdr->e_type = grub_host_to_target16 (ET_EXEC);
-	ehdr->e_machine = grub_host_to_target16 (image_target->elf_target);
-	ehdr->e_version = grub_host_to_target32 (EV_CURRENT);
-
-	ehdr->e_phoff = grub_host_to_target32 ((char *) phdr - (char *) ehdr);
-	ehdr->e_phentsize = grub_host_to_target16 (sizeof (*phdr));
-	ehdr->e_phnum = grub_host_to_target16 (phnum);
-
-	/* No section headers.  */
-	ehdr->e_shoff = grub_host_to_target32 (0);
-	if (image_target->id == IMAGE_LOONGSON_ELF)
-	  ehdr->e_shentsize = grub_host_to_target16 (0);
-	else
-	  ehdr->e_shentsize = grub_host_to_target16 (sizeof (Elf32_Shdr));
-	ehdr->e_shnum = grub_host_to_target16 (0);
-	ehdr->e_shstrndx = grub_host_to_target16 (0);
-
-	ehdr->e_ehsize = grub_host_to_target16 (sizeof (*ehdr));
-
-	phdr->p_type = grub_host_to_target32 (PT_LOAD);
-	phdr->p_offset = grub_host_to_target32 (header_size);
-	phdr->p_flags = grub_host_to_target32 (PF_R | PF_W | PF_X);
-
-	if (image_target->id == IMAGE_LOONGSON_ELF)
-	  {
-	    if (comp == COMPRESSION_NONE)
-	      target_addr = (image_target->link_addr - decompress_size);
-	    else
-	      target_addr = ALIGN_UP (image_target->link_addr
-				      + kernel_size + total_module_size, 32);
-	  }
-	else
-	  target_addr = image_target->link_addr;
-	ehdr->e_entry = grub_host_to_target32 (target_addr);
-	phdr->p_vaddr = grub_host_to_target32 (target_addr);
-	phdr->p_paddr = grub_host_to_target32 (target_addr);
-	phdr->p_align = grub_host_to_target32 (align > image_target->link_align ? align : image_target->link_align);
-	if (image_target->id == IMAGE_LOONGSON_ELF)
-	  ehdr->e_flags = grub_host_to_target32 (0x1000 | EF_MIPS_NOREORDER 
-						 | EF_MIPS_PIC | EF_MIPS_CPIC);
-	else
-	  ehdr->e_flags = 0;
-	if (image_target->id == IMAGE_LOONGSON_ELF)
-	  {
-	    phdr->p_filesz = grub_host_to_target32 (core_size);
-	    phdr->p_memsz = grub_host_to_target32 (core_size);
-	  }
-	else
-	  {
-	    grub_uint32_t target_addr_mods;
-	    phdr->p_filesz = grub_host_to_target32 (kernel_size);
-	    phdr->p_memsz = grub_host_to_target32 (kernel_size + bss_size);
-
-	    phdr++;
-	    phdr->p_type = grub_host_to_target32 (PT_GNU_STACK);
-	    phdr->p_offset = grub_host_to_target32 (header_size + kernel_size);
-	    phdr->p_paddr = phdr->p_vaddr = phdr->p_filesz = phdr->p_memsz = 0;
-	    phdr->p_flags = grub_host_to_target32 (PF_R | PF_W | PF_X);
-	    phdr->p_align = grub_host_to_target32 (image_target->link_align);
-
-	    phdr++;
-	    phdr->p_type = grub_host_to_target32 (PT_LOAD);
-	    phdr->p_offset = grub_host_to_target32 (header_size + kernel_size);
-	    phdr->p_flags = grub_host_to_target32 (PF_R | PF_W | PF_X);
-	    phdr->p_filesz = phdr->p_memsz
-	      = grub_host_to_target32 (core_size - kernel_size);
-
-	    if (image_target->id == IMAGE_COREBOOT)
-	      target_addr_mods = GRUB_KERNEL_I386_COREBOOT_MODULES_ADDR;
-	    else
-	      target_addr_mods = ALIGN_UP (target_addr + kernel_size + bss_size
-					   + image_target->mod_gap,
-					   image_target->mod_align);
-	    phdr->p_vaddr = grub_host_to_target32 (target_addr_mods);
-	    phdr->p_paddr = grub_host_to_target32 (target_addr_mods);
-	    phdr->p_align = grub_host_to_target32 (image_target->link_align);
-	  }
-
-	if (note)
-	  {
-	    int note_size = sizeof (struct grub_ieee1275_note);
-	    struct grub_ieee1275_note *note_ptr = (struct grub_ieee1275_note *) 
-	      (elf_img + program_size + header_size);
-
-	    grub_util_info ("adding CHRP NOTE segment");
-
-	    note_ptr->header.namesz = grub_host_to_target32 (sizeof (GRUB_IEEE1275_NOTE_NAME));
-	    note_ptr->header.descsz = grub_host_to_target32 (note_size);
-	    note_ptr->header.type = grub_host_to_target32 (GRUB_IEEE1275_NOTE_TYPE);
-	    strcpy (note_ptr->header.name, GRUB_IEEE1275_NOTE_NAME);
-	    note_ptr->descriptor.real_mode = grub_host_to_target32 (0xffffffff);
-	    note_ptr->descriptor.real_base = grub_host_to_target32 (0x00c00000);
-	    note_ptr->descriptor.real_size = grub_host_to_target32 (0xffffffff);
-	    note_ptr->descriptor.virt_base = grub_host_to_target32 (0xffffffff);
-	    note_ptr->descriptor.virt_size = grub_host_to_target32 (0xffffffff);
-	    note_ptr->descriptor.load_base = grub_host_to_target32 (0x00004000);
-
-	    phdr++;
-	    phdr->p_type = grub_host_to_target32 (PT_NOTE);
-	    phdr->p_flags = grub_host_to_target32 (PF_R);
-	    phdr->p_align = grub_host_to_target32 (image_target->voidp_sizeof);
-	    phdr->p_vaddr = 0;
-	    phdr->p_paddr = 0;
-	    phdr->p_filesz = grub_host_to_target32 (note_size);
-	    phdr->p_memsz = 0;
-	    phdr->p_offset = grub_host_to_target32 (header_size + program_size);
-	  }
-
-	free (core_img);
-	core_img = elf_img;
-	core_size = program_size + header_size + footer_size;
-      }
-      break;
-    }
-
-  grub_util_write_image (core_img, core_size, out, outname);
-  free (core_img);
-  free (kernel_path);
-
-  while (path_list)
-    {
-      next = path_list->next;
-      free ((void *) path_list->name);
-      free (path_list);
-      path_list = next;
-    }
-}
-
 \f
 
 static struct argp_option options[] = {
@@ -1860,22 +88,7 @@
       return xasprintf (text, DEFAULT_DIRECTORY);
     case 'O':
       {
-	int format_len = 0;
-	char *formats;
-	char *ptr;
-	char *ret;
-	unsigned i;
-	for (i = 0; i < ARRAY_SIZE (image_targets); i++)
-	  format_len += strlen (image_targets[i].names[0]) + 2;
-	ptr = formats = xmalloc (format_len);
-	for (i = 0; i < ARRAY_SIZE (image_targets); i++)
-	  {
-	    strcpy (ptr, image_targets[i].names[0]);
-	    ptr += strlen (image_targets[i].names[0]);
-	    *ptr++ = ',';
-	    *ptr++ = ' ';
-	  }
-	ptr[-2] = 0;
+	char *formats = grub_install_get_image_targets_string (), *ret;
 	ret = xasprintf ("%s\n%s %s", _("generate an image in FORMAT"),
 			 _("available formats:"), formats);
 	free (formats);
@@ -1900,10 +113,11 @@
   char *font;
   char *config;
   int note;
-  struct image_target_desc *image_target;
+  struct grub_install_image_target_desc *image_target;
   grub_compression_t comp;
 };
 
+
 static error_t
 argp_parser (int key, char *arg, struct argp_state *state)
 {
@@ -1922,12 +136,7 @@
 
     case 'O':
       {
-	unsigned i, j;
-	for (i = 0; i < ARRAY_SIZE (image_targets); i++)
-	  for (j = 0; image_targets[i].names[j]
-		 && j < ARRAY_SIZE (image_targets[i].names); j++)
-	    if (strcmp (arg, image_targets[i].names[j]) == 0)
-	      arguments->image_target = &image_targets[i];
+	arguments->image_target = grub_install_get_image_target (arg);
 	if (!arguments->image_target)
 	  {
 	    printf (_("unknown target format %s\n"), arg);
@@ -1977,16 +186,16 @@
       if (grub_strcmp (arg, "xz") == 0)
 	{
 #ifdef HAVE_LIBLZMA
-	  arguments->comp = COMPRESSION_XZ;
+	  arguments->comp = GRUB_COMPRESSION_XZ;
 #else
 	  grub_util_error ("%s",
 			   _("grub-mkimage is compiled without XZ support"));
 #endif
 	}
       else if (grub_strcmp (arg, "none") == 0)
-	arguments->comp = COMPRESSION_NONE;
+	arguments->comp = GRUB_COMPRESSION_NONE;
       else if (grub_strcmp (arg, "auto") == 0)
-	arguments->comp = COMPRESSION_AUTO;
+	arguments->comp = GRUB_COMPRESSION_AUTO;
       else
 	grub_util_error (_("Unknown compression format %s"), arg);
       break;
@@ -2029,7 +238,7 @@
   grub_util_init_nls ();
 
   memset (&arguments, 0, sizeof (struct arguments));
-  arguments.comp = COMPRESSION_AUTO;
+  arguments.comp = GRUB_COMPRESSION_AUTO;
   arguments.modules_max = argc + 1;
   arguments.modules = xmalloc ((arguments.modules_max + 1)
 			     * sizeof (arguments.modules[0]));
@@ -2061,21 +270,24 @@
 
   if (!arguments.dir)
     {
+      const char *dn = grub_util_get_target_dirname (arguments.image_target);
       arguments.dir = xmalloc (sizeof (GRUB_PKGLIBDIR)
-			       + grub_strlen (arguments.image_target->dirname)
+			       + grub_strlen (dn)
 			       + 1);
       memcpy (arguments.dir, GRUB_PKGLIBDIR,
 	      sizeof (GRUB_PKGLIBDIR) - 1);
       *(arguments.dir + sizeof (GRUB_PKGLIBDIR) - 1) = '/';
-      strcpy (arguments.dir + sizeof (GRUB_PKGLIBDIR),
-	      arguments.image_target->dirname);
+      strcpy (arguments.dir + sizeof (GRUB_PKGLIBDIR), dn);
     }
 
-  generate_image (arguments.dir, arguments.prefix ? : DEFAULT_DIRECTORY, fp,
-		  arguments.output,
-		  arguments.modules, arguments.memdisk, arguments.pubkeys,
-		  arguments.npubkeys, arguments.config,
-		  arguments.image_target, arguments.note, arguments.comp);
+  grub_install_generate_image (arguments.dir,
+			       arguments.prefix ? : DEFAULT_DIRECTORY, fp,
+			       arguments.output,
+			       arguments.modules, arguments.memdisk,
+			       arguments.pubkeys,
+			       arguments.npubkeys, arguments.config,
+			       arguments.image_target, arguments.note,
+			       arguments.comp);
 
   fflush (fp);
   fsync (fileno (fp));

=== modified file 'util/grub-mkimagexx.c'
--- util/grub-mkimagexx.c	2013-08-23 07:01:11 +0000
+++ util/grub-mkimagexx.c	2013-10-04 00:39:55 +0000
@@ -67,7 +67,7 @@
 			   Elf_Shdr *symtab_section, Elf_Addr *section_addresses,
 			   Elf_Half section_entsize, Elf_Half num_sections,
 			   void *jumpers, Elf_Addr jumpers_addr,
-			   struct image_target_desc *image_target)
+			   struct grub_install_image_target_desc *image_target)
 {
   Elf_Word symtab_size, sym_size, num_syms;
   Elf_Off symtab_offset;
@@ -140,7 +140,7 @@
 /* Return the address of a symbol at the index I in the section S.  */
 static Elf_Addr
 SUFFIX (get_symbol_address) (Elf_Ehdr *e, Elf_Shdr *s, Elf_Word i,
-			     struct image_target_desc *image_target)
+			     struct grub_install_image_target_desc *image_target)
 {
   Elf_Sym *sym;
 
@@ -153,7 +153,7 @@
 /* Return the address of a modified value.  */
 static Elf_Addr *
 SUFFIX (get_target_address) (Elf_Ehdr *e, Elf_Shdr *s, Elf_Addr offset,
-		    struct image_target_desc *image_target)
+		    struct grub_install_image_target_desc *image_target)
 {
   return (Elf_Addr *) ((char *) e + grub_target_to_host (s->sh_offset) + offset);
 }
@@ -161,7 +161,7 @@
 #ifdef MKIMAGE_ELF64
 static Elf_Addr
 SUFFIX (count_funcs) (Elf_Ehdr *e, Elf_Shdr *symtab_section,
-		      struct image_target_desc *image_target)
+		      struct grub_install_image_target_desc *image_target)
 {
   Elf_Word symtab_size, sym_size, num_syms;
   Elf_Off symtab_offset;
@@ -195,7 +195,7 @@
 			     const char *strtab,
 			     char *pe_target, Elf_Addr tramp_off,
 			     Elf_Addr got_off,
-			     struct image_target_desc *image_target)
+			     struct grub_install_image_target_desc *image_target)
 {
   Elf_Half i;
   Elf_Shdr *s;
@@ -472,7 +472,7 @@
 static Elf_Addr
 SUFFIX (add_fixup_entry) (struct fixup_block_list **cblock, grub_uint16_t type,
 			  Elf_Addr addr, int flush, Elf_Addr current_address,
-			  struct image_target_desc *image_target)
+			  struct grub_install_image_target_desc *image_target)
 {
   struct grub_pe32_fixup_block *b;
 
@@ -569,7 +569,7 @@
 			     Elf_Half section_entsize, Elf_Half num_sections,
 			     const char *strtab,
 			     Elf_Addr jumpers, grub_size_t njumpers,
-			     struct image_target_desc *image_target)
+			     struct grub_install_image_target_desc *image_target)
 {
   unsigned i;
   Elf_Shdr *s;
@@ -755,7 +755,7 @@
 /* Determine if this section is a text section. Return false if this
    section is not allocated.  */
 static int
-SUFFIX (is_text_section) (Elf_Shdr *s, struct image_target_desc *image_target)
+SUFFIX (is_text_section) (Elf_Shdr *s, struct grub_install_image_target_desc *image_target)
 {
   if (image_target->id != IMAGE_EFI 
       && grub_target_to_host32 (s->sh_type) != SHT_PROGBITS)
@@ -768,7 +768,7 @@
    BSS is also a data section, since the converter initializes BSS
    when producing PE32 to avoid a bug in EFI implementations.  */
 static int
-SUFFIX (is_data_section) (Elf_Shdr *s, struct image_target_desc *image_target)
+SUFFIX (is_data_section) (Elf_Shdr *s, struct grub_install_image_target_desc *image_target)
 {
   if (image_target->id != IMAGE_EFI 
       && grub_target_to_host32 (s->sh_type) != SHT_PROGBITS)
@@ -779,7 +779,7 @@
 
 /* Return if the ELF header is valid.  */
 static int
-SUFFIX (check_elf_header) (Elf_Ehdr *e, size_t size, struct image_target_desc *image_target)
+SUFFIX (check_elf_header) (Elf_Ehdr *e, size_t size, struct grub_install_image_target_desc *image_target)
 {
   if (size < sizeof (*e)
       || e->e_ident[EI_MAG0] != ELFMAG0
@@ -802,7 +802,7 @@
 			  Elf_Half num_sections, const char *strtab,
 			  grub_size_t *exec_size, grub_size_t *kernel_sz,
 			  grub_size_t *all_align,
-			  struct image_target_desc *image_target)
+			  struct grub_install_image_target_desc *image_target)
 {
   int i;
   Elf_Addr current_address;
@@ -884,7 +884,7 @@
 		     grub_size_t total_module_size, grub_uint64_t *start,
 		     void **reloc_section, grub_size_t *reloc_size,
 		     grub_size_t *align,
-		     struct image_target_desc *image_target)
+		     struct grub_install_image_target_desc *image_target)
 {
   char *kernel_img, *out_img;
   const char *strtab;

=== modified file 'util/grub-setup.c'
--- util/grub-setup.c	2013-04-04 06:55:06 +0000
+++ util/grub-setup.c	2013-10-04 00:39:55 +0000
@@ -31,14 +31,6 @@
 #include <grub/term.h>
 #include <grub/i18n.h>
 #include <grub/util/lvm.h>
-#ifdef GRUB_SETUP_SPARC64
-#include <grub/util/ofpath.h>
-#include <grub/sparc64/ieee1275/boot.h>
-#include <grub/sparc64/ieee1275/kernel.h>
-#else
-#include <grub/i386/pc/boot.h>
-#include <grub/i386/pc/kernel.h>
-#endif
 
 #include <stdio.h>
 #include <unistd.h>
@@ -53,6 +45,7 @@
 #include <grub/reed_solomon.h>
 #include <grub/msdos_partition.h>
 #include <include/grub/crypto.h>
+#include <grub/util/install.h>
 
 #ifdef __linux__
 #include <sys/ioctl.h>
@@ -63,917 +56,6 @@
 #define _GNU_SOURCE	1
 #include <argp.h>
 
-/* On SPARC this program fills in various fields inside of the 'boot' and 'core'
- * image files.
- *
- * The 'boot' image needs to know the OBP path name of the root
- * device.  It also needs to know the initial block number of
- * 'core' (which is 'diskboot' concatenated with 'kernel' and
- * all the modules, this is created by grub-mkimage).  This resulting
- * 'boot' image is 512 bytes in size and is placed in the second block
- * of a partition.
- *
- * The initial 'diskboot' block acts as a loader for the actual GRUB
- * kernel.  It contains the loading code and then a block list.
- *
- * The block list of 'core' starts at the end of the 'diskboot' image
- * and works it's way backwards towards the end of the code of 'diskboot'.
- *
- * We patch up the images with the necessary values and write out the
- * result.
- */
-
-#define DEFAULT_BOOT_FILE	"boot.img"
-#define DEFAULT_CORE_FILE	"core.img"
-
-#ifdef GRUB_SETUP_SPARC64
-#define grub_target_to_host16(x)	grub_be_to_cpu16(x)
-#define grub_target_to_host32(x)	grub_be_to_cpu32(x)
-#define grub_target_to_host64(x)	grub_be_to_cpu64(x)
-#define grub_host_to_target16(x)	grub_cpu_to_be16(x)
-#define grub_host_to_target32(x)	grub_cpu_to_be32(x)
-#define grub_host_to_target64(x)	grub_cpu_to_be64(x)
-#elif defined (GRUB_SETUP_BIOS)
-#define grub_target_to_host16(x)	grub_le_to_cpu16(x)
-#define grub_target_to_host32(x)	grub_le_to_cpu32(x)
-#define grub_target_to_host64(x)	grub_le_to_cpu64(x)
-#define grub_host_to_target16(x)	grub_cpu_to_le16(x)
-#define grub_host_to_target32(x)	grub_cpu_to_le32(x)
-#define grub_host_to_target64(x)	grub_cpu_to_le64(x)
-#else
-#error Complete this
-#endif
-
-static void
-write_rootdev (grub_device_t root_dev,
-	       char *boot_img, grub_uint64_t first_sector)
-{
-#ifdef GRUB_SETUP_BIOS
-  {
-    grub_uint8_t *boot_drive;
-    void *kernel_sector;
-    boot_drive = (grub_uint8_t *) (boot_img + GRUB_BOOT_MACHINE_BOOT_DRIVE);
-    kernel_sector = (boot_img + GRUB_BOOT_MACHINE_KERNEL_SECTOR);
-
-    /* FIXME: can this be skipped?  */
-    *boot_drive = 0xFF;
-
-    grub_set_unaligned64 (kernel_sector, grub_cpu_to_le64 (first_sector));
-  }
-#endif
-#ifdef GRUB_SETUP_SPARC64
-  {
-    void *kernel_byte;
-    kernel_byte = (boot_img + GRUB_BOOT_AOUT_HEADER_SIZE
-		   + GRUB_BOOT_MACHINE_KERNEL_BYTE);
-    grub_set_unaligned64 (kernel_byte,
-			  grub_cpu_to_be64 (first_sector << GRUB_DISK_SECTOR_BITS));
-  }
-#endif
-}
-
-#ifdef GRUB_SETUP_SPARC64
-#define BOOT_SECTOR 1
-#else
-#define BOOT_SECTOR 0
-#endif
-
-/* Helper for setup.  */
-static void
-save_first_sector (grub_disk_addr_t sector, unsigned offset, unsigned length,
-		   void *data)
-{
-  grub_disk_addr_t *first_sector = data;
-  grub_util_info ("the first sector is <%" PRIuGRUB_UINT64_T ",%u,%u>",
-		  sector, offset, length);
-
-  if (offset != 0 || length != GRUB_DISK_SECTOR_SIZE)
-    grub_util_error ("%s", _("the first sector of the core file is not sector-aligned"));
-
-  *first_sector = sector;
-}
-
-struct blocklists
-{
-  struct grub_boot_blocklist *first_block, *block;
-#ifdef GRUB_SETUP_BIOS
-  grub_uint16_t current_segment;
-#endif
-  grub_uint16_t last_length;
-};
-
-/* Helper for setup.  */
-static void
-save_blocklists (grub_disk_addr_t sector, unsigned offset, unsigned length,
-		 void *data)
-{
-  struct blocklists *bl = data;
-  struct grub_boot_blocklist *prev = bl->block + 1;
-
-  grub_util_info ("saving <%" PRIuGRUB_UINT64_T ",%u,%u>",
-		  sector, offset, length);
-
-  if (offset != 0 || bl->last_length != GRUB_DISK_SECTOR_SIZE)
-    grub_util_error ("%s", _("non-sector-aligned data is found in the core file"));
-
-  if (bl->block != bl->first_block
-      && (grub_target_to_host64 (prev->start)
-	  + grub_target_to_host16 (prev->len)) == sector)
-    {
-      grub_uint16_t t = grub_target_to_host16 (prev->len) + 1;
-      prev->len = grub_host_to_target16 (t);
-    }
-  else
-    {
-      bl->block->start = grub_host_to_target64 (sector);
-      bl->block->len = grub_host_to_target16 (1);
-#ifdef GRUB_SETUP_BIOS
-      bl->block->segment = grub_host_to_target16 (bl->current_segment);
-#endif
-
-      bl->block--;
-      if (bl->block->len)
-	grub_util_error ("%s", _("the sectors of the core file are too fragmented"));
-    }
-
-  bl->last_length = length;
-#ifdef GRUB_SETUP_BIOS
-  bl->current_segment += GRUB_DISK_SECTOR_SIZE >> 4;
-#endif
-}
-
-#ifdef GRUB_SETUP_BIOS
-/* Context for setup/identify_partmap.  */
-struct identify_partmap_ctx
-{
-  grub_partition_map_t dest_partmap;
-  grub_partition_t container;
-  int multiple_partmaps;
-};
-
-/* Helper for setup.
-   Unlike root_dev, with dest_dev we're interested in the partition map even
-   if dest_dev itself is a whole disk.  */
-static int
-identify_partmap (grub_disk_t disk __attribute__ ((unused)),
-		  const grub_partition_t p, void *data)
-{
-  struct identify_partmap_ctx *ctx = data;
-
-  if (p->parent != ctx->container)
-    return 0;
-  /* NetBSD and OpenBSD subpartitions have metadata inside a partition,
-     so they are safe to ignore.
-   */
-  if (grub_strcmp (p->partmap->name, "netbsd") == 0
-      || grub_strcmp (p->partmap->name, "openbsd") == 0)
-    return 0;
-  if (ctx->dest_partmap == NULL)
-    {
-      ctx->dest_partmap = p->partmap;
-      return 0;
-    }
-  if (ctx->dest_partmap == p->partmap)
-    return 0;
-  ctx->multiple_partmaps = 1;
-  return 1;
-}
-#endif
-
-static void
-setup (const char *dir,
-       const char *boot_file, const char *core_file,
-       const char *dest, int force,
-       int fs_probe, int allow_floppy)
-{
-  char *boot_path, *core_path, *core_path_dev, *core_path_dev_full;
-  char *boot_img, *core_img;
-  char *root = 0;
-  size_t boot_size, core_size;
-#ifdef GRUB_SETUP_BIOS
-  grub_uint16_t core_sectors;
-#endif
-  grub_device_t root_dev = 0, dest_dev, core_dev;
-  struct blocklists bl;
-  char *tmp_img;
-  grub_disk_addr_t first_sector = (grub_disk_addr_t)-1;
-  FILE *fp;
-
-#ifdef GRUB_SETUP_BIOS
-  bl.current_segment =
-    GRUB_BOOT_I386_PC_KERNEL_SEG + (GRUB_DISK_SECTOR_SIZE >> 4);
-#endif
-  bl.last_length = GRUB_DISK_SECTOR_SIZE;
-
-  /* Read the boot image by the OS service.  */
-  boot_path = grub_util_get_path (dir, boot_file);
-  boot_size = grub_util_get_image_size (boot_path);
-  if (boot_size != GRUB_DISK_SECTOR_SIZE)
-    grub_util_error (_("the size of `%s' is not %u"),
-		     boot_path, GRUB_DISK_SECTOR_SIZE);
-  boot_img = grub_util_read_image (boot_path);
-  free (boot_path);
-
-  core_path = grub_util_get_path (dir, core_file);
-  core_size = grub_util_get_image_size (core_path);
-#ifdef GRUB_SETUP_BIOS
-  core_sectors = ((core_size + GRUB_DISK_SECTOR_SIZE - 1)
-		  >> GRUB_DISK_SECTOR_BITS);
-#endif
-  if (core_size < GRUB_DISK_SECTOR_SIZE)
-    grub_util_error (_("the size of `%s' is too small"), core_path);
-#ifdef GRUB_SETUP_BIOS
-  if (core_size > 0xFFFF * GRUB_DISK_SECTOR_SIZE)
-    grub_util_error (_("the size of `%s' is too large"), core_path);
-#endif
-
-  core_img = grub_util_read_image (core_path);
-
-  /* Have FIRST_BLOCK to point to the first blocklist.  */
-  bl.first_block = (struct grub_boot_blocklist *) (core_img
-						   + GRUB_DISK_SECTOR_SIZE
-						   - sizeof (*bl.block));
-  grub_util_info ("root is `%s', dest is `%s'", root, dest);
-
-  grub_util_info ("Opening dest");
-  dest_dev = grub_device_open (dest);
-  if (! dest_dev)
-    grub_util_error ("%s", grub_errmsg);
-
-  core_dev = dest_dev;
-
-  {
-    char **root_devices = grub_guess_root_devices (dir);
-    char **cur;
-    int found = 0;
-
-    for (cur = root_devices; *cur; cur++)
-      {
-	char *drive;
-	grub_device_t try_dev;
-
-	drive = grub_util_get_grub_dev (*cur);
-	if (!drive)
-	  continue;
-	try_dev = grub_device_open (drive);
-	if (! try_dev)
-	  continue;
-	if (!found && try_dev->disk->id == dest_dev->disk->id
-	    && try_dev->disk->dev->id == dest_dev->disk->dev->id)
-	  {
-	    if (root_dev)
-	      grub_device_close (root_dev);
-	    free (root);
-	    root_dev = try_dev;
-	    root = drive;
-	    found = 1;
-	    continue;
-	  }
-	if (!root_dev)
-	  {
-	    root_dev = try_dev;
-	    root = drive;
-	    continue;
-	  }
-	grub_device_close (try_dev);	
-	free (drive);
-      }
-    if (!root_dev)
-      {
-	grub_util_error ("guessing the root device failed, because of `%s'",
-			 grub_errmsg);
-      }
-    grub_util_info ("guessed root_dev `%s' from "
-		    "dir `%s'", root_dev->disk->name, dir);
-  }
-
-  grub_util_info ("setting the root device to `%s'", root);
-  if (grub_env_set ("root", root) != GRUB_ERR_NONE)
-    grub_util_error ("%s", grub_errmsg);
-
-#ifdef GRUB_SETUP_BIOS
-  /* Read the original sector from the disk.  */
-  tmp_img = xmalloc (GRUB_DISK_SECTOR_SIZE);
-  if (grub_disk_read (dest_dev->disk, 0, 0, GRUB_DISK_SECTOR_SIZE, tmp_img))
-    grub_util_error ("%s", grub_errmsg);
-#endif
-
-#ifdef GRUB_SETUP_BIOS
-  {
-    grub_uint8_t *boot_drive_check;
-    boot_drive_check = (grub_uint8_t *) (boot_img
-					  + GRUB_BOOT_MACHINE_DRIVE_CHECK);
-    /* Copy the possible DOS BPB.  */
-    memcpy (boot_img + GRUB_BOOT_MACHINE_BPB_START,
-	    tmp_img + GRUB_BOOT_MACHINE_BPB_START,
-	    GRUB_BOOT_MACHINE_BPB_END - GRUB_BOOT_MACHINE_BPB_START);
-
-    /* If DEST_DRIVE is a hard disk, enable the workaround, which is
-       for buggy BIOSes which don't pass boot drive correctly. Instead,
-       they pass 0x00 or 0x01 even when booted from 0x80.  */
-    if (!allow_floppy && !grub_util_biosdisk_is_floppy (dest_dev->disk))
-      {
-	/* Replace the jmp (2 bytes) with double nop's.  */
-	boot_drive_check[0] = 0x90;
-	boot_drive_check[1] = 0x90;
-      }
-  }
-#endif
-
-#ifdef GRUB_SETUP_BIOS
-  {
-    struct identify_partmap_ctx ctx = {
-      .dest_partmap = NULL,
-      .container = dest_dev->disk->partition,
-      .multiple_partmaps = 0
-    };
-    int is_ldm;
-    grub_err_t err;
-    grub_disk_addr_t *sectors;
-    int i;
-    grub_fs_t fs;
-    unsigned int nsec, maxsec;
-
-    grub_partition_iterate (dest_dev->disk, identify_partmap, &ctx);
-
-    if (ctx.container
-	&& grub_strcmp (ctx.container->partmap->name, "msdos") == 0
-	&& ctx.dest_partmap
-	&& (ctx.container->msdostype == GRUB_PC_PARTITION_TYPE_NETBSD
-	    || ctx.container->msdostype == GRUB_PC_PARTITION_TYPE_OPENBSD))
-      {
-	grub_util_warn ("%s", _("Attempting to install GRUB to a disk with multiple partition labels or both partition label and filesystem.  This is not supported yet."));
-	goto unable_to_embed;
-      }
-
-    fs = grub_fs_probe (dest_dev);
-    if (!fs)
-      grub_errno = GRUB_ERR_NONE;
-
-    is_ldm = grub_util_is_ldm (dest_dev->disk);
-
-    if (fs_probe)
-      {
-	if (!fs && !ctx.dest_partmap)
-	  grub_util_error (_("unable to identify a filesystem in %s; safety check can't be performed"),
-			   dest_dev->disk->name);
-	if (fs && !fs->reserved_first_sector)
-	  /* TRANSLATORS: Filesystem may reserve the space just GRUB isn't sure about it.  */
-	  grub_util_error (_("%s appears to contain a %s filesystem which isn't known to "
-			     "reserve space for DOS-style boot.  Installing GRUB there could "
-			     "result in FILESYSTEM DESTRUCTION if valuable data is overwritten "
-			     "by grub-setup (--skip-fs-probe disables this "
-			     "check, use at your own risk)"), dest_dev->disk->name, fs->name);
-
-	if (ctx.dest_partmap && strcmp (ctx.dest_partmap->name, "msdos") != 0
-	    && strcmp (ctx.dest_partmap->name, "gpt") != 0
-	    && strcmp (ctx.dest_partmap->name, "bsd") != 0
-	    && strcmp (ctx.dest_partmap->name, "netbsd") != 0
-	    && strcmp (ctx.dest_partmap->name, "openbsd") != 0
-	    && strcmp (ctx.dest_partmap->name, "sunpc") != 0)
-	  /* TRANSLATORS: Partition map may reserve the space just GRUB isn't sure about it.  */
-	  grub_util_error (_("%s appears to contain a %s partition map which isn't known to "
-			     "reserve space for DOS-style boot.  Installing GRUB there could "
-			     "result in FILESYSTEM DESTRUCTION if valuable data is overwritten "
-			     "by grub-setup (--skip-fs-probe disables this "
-			     "check, use at your own risk)"), dest_dev->disk->name, ctx.dest_partmap->name);
-	if (is_ldm && ctx.dest_partmap && strcmp (ctx.dest_partmap->name, "msdos") != 0
-	    && strcmp (ctx.dest_partmap->name, "gpt") != 0)
-	  grub_util_error (_("%s appears to contain a %s partition map and "
-			     "LDM which isn't known to be a safe combination."
-			     "  Installing GRUB there could "
-			     "result in FILESYSTEM DESTRUCTION if valuable data"
-			     " is overwritten "
-			     "by grub-setup (--skip-fs-probe disables this "
-			     "check, use at your own risk)"),
-			   dest_dev->disk->name, ctx.dest_partmap->name);
-
-      }
-
-    /* Copy the partition table.  */
-    if (ctx.dest_partmap ||
-        (!allow_floppy && !grub_util_biosdisk_is_floppy (dest_dev->disk)))
-      memcpy (boot_img + GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC,
-	      tmp_img + GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC,
-	      GRUB_BOOT_MACHINE_PART_END - GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC);
-
-    free (tmp_img);
-    
-    if (! ctx.dest_partmap && ! fs && !is_ldm)
-      {
-	grub_util_warn ("%s", _("Attempting to install GRUB to a partitionless disk or to a partition.  This is a BAD idea."));
-	goto unable_to_embed;
-      }
-    if (ctx.multiple_partmaps || (ctx.dest_partmap && fs) || (is_ldm && fs))
-      {
-	grub_util_warn ("%s", _("Attempting to install GRUB to a disk with multiple partition labels.  This is not supported yet."));
-	goto unable_to_embed;
-      }
-
-    if (ctx.dest_partmap && !ctx.dest_partmap->embed)
-      {
-	grub_util_warn (_("Partition style `%s' doesn't support embedding"),
-			ctx.dest_partmap->name);
-	goto unable_to_embed;
-      }
-
-    if (fs && !fs->embed)
-      {
-	grub_util_warn (_("File system `%s' doesn't support embedding"),
-			fs->name);
-	goto unable_to_embed;
-      }
-
-    nsec = core_sectors;
-
-    maxsec = 2 * core_sectors;
-    if (maxsec > ((0x78000 - GRUB_KERNEL_I386_PC_LINK_ADDR)
-		>> GRUB_DISK_SECTOR_BITS))
-      maxsec = ((0x78000 - GRUB_KERNEL_I386_PC_LINK_ADDR)
-		>> GRUB_DISK_SECTOR_BITS);
-
-    if (is_ldm)
-      err = grub_util_ldm_embed (dest_dev->disk, &nsec, maxsec,
-				 GRUB_EMBED_PCBIOS, &sectors);
-    else if (ctx.dest_partmap)
-      err = ctx.dest_partmap->embed (dest_dev->disk, &nsec, maxsec,
-				     GRUB_EMBED_PCBIOS, &sectors);
-    else
-      err = fs->embed (dest_dev, &nsec, maxsec,
-		       GRUB_EMBED_PCBIOS, &sectors);
-    if (!err && nsec < core_sectors)
-      {
-	err = grub_error (GRUB_ERR_OUT_OF_RANGE,
-			  N_("Your embedding area is unusually small.  "
-			     "core.img won't fit in it."));
-      }
-    
-    if (err)
-      {
-	grub_util_warn ("%s", grub_errmsg);
-	grub_errno = GRUB_ERR_NONE;
-	goto unable_to_embed;
-      }
-
-    assert (nsec <= maxsec);
-
-    /* Clean out the blocklists.  */
-    bl.block = bl.first_block;
-    while (bl.block->len)
-      {
-	grub_memset (bl.block, 0, sizeof (bl.block));
-      
-	bl.block--;
-
-	if ((char *) bl.block <= core_img)
-	  grub_util_error ("%s", _("no terminator in the core image"));
-      }
-
-    save_first_sector (sectors[0] + grub_partition_get_start (ctx.container),
-		       0, GRUB_DISK_SECTOR_SIZE, &first_sector);
-
-    bl.block = bl.first_block;
-    for (i = 1; i < nsec; i++)
-      save_blocklists (sectors[i] + grub_partition_get_start (ctx.container),
-		       0, GRUB_DISK_SECTOR_SIZE, &bl);
-
-    /* Make sure that the last blocklist is a terminator.  */
-    if (bl.block == bl.first_block)
-      bl.block--;
-    bl.block->start = 0;
-    bl.block->len = 0;
-    bl.block->segment = 0;
-
-    write_rootdev (root_dev, boot_img, first_sector);
-
-    core_img = realloc (core_img, nsec * GRUB_DISK_SECTOR_SIZE);
-    bl.first_block = (struct grub_boot_blocklist *) (core_img
-						     + GRUB_DISK_SECTOR_SIZE
-						     - sizeof (*bl.block));
-
-    grub_size_t no_rs_length;
-    grub_set_unaligned32 ((core_img + GRUB_DISK_SECTOR_SIZE
-			   + GRUB_KERNEL_I386_PC_REED_SOLOMON_REDUNDANCY),
-			  grub_host_to_target32 (nsec * GRUB_DISK_SECTOR_SIZE - core_size));
-    no_rs_length = grub_target_to_host16 
-      (grub_get_unaligned16 (core_img
-			     + GRUB_DISK_SECTOR_SIZE
-			     + GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_LENGTH));
-
-    if (no_rs_length == 0xffff)
-      grub_util_error ("%s", _("core.img version mismatch"));
-
-    void *tmp = xmalloc (core_size);
-    grub_memcpy (tmp, core_img, core_size);
-    grub_reed_solomon_add_redundancy (core_img + no_rs_length + GRUB_DISK_SECTOR_SIZE,
-				      core_size - no_rs_length - GRUB_DISK_SECTOR_SIZE,
-				      nsec * GRUB_DISK_SECTOR_SIZE
-				      - core_size);
-    assert (grub_memcmp (tmp, core_img, core_size) == 0);
-    free (tmp);
-
-    /* Write the core image onto the disk.  */
-    for (i = 0; i < nsec; i++)
-      grub_disk_write (dest_dev->disk, sectors[i], 0,
-		       GRUB_DISK_SECTOR_SIZE,
-		       core_img + i * GRUB_DISK_SECTOR_SIZE);
-
-    grub_free (sectors);
-
-    goto finish;
-  }
-
-unable_to_embed:
-#endif
-
-  if (dest_dev->disk->dev->id != root_dev->disk->dev->id)
-    grub_util_error ("%s", _("embedding is not possible, but this is required for "
-			     "RAID and LVM install"));
-
-  {
-    grub_fs_t fs;
-    fs = grub_fs_probe (root_dev);
-    if (!fs)
-      grub_util_error (_("can't determine filesystem on %s"), root);
-
-    if (!fs->blocklist_install)
-      grub_util_error (_("filesystem `%s' doesn't support blocklists"),
-		       fs->name);
-  }
-
-#ifdef GRUB_SETUP_BIOS
-  if (dest_dev->disk->id != root_dev->disk->id
-      || dest_dev->disk->dev->id != root_dev->disk->dev->id)
-    /* TRANSLATORS: cross-disk refers to /boot being on one disk
-       but MBR on another.  */
-    grub_util_error ("%s", _("embedding is not possible, but this is required for "
-			     "cross-disk install"));
-#else
-  core_dev = root_dev;
-#endif
-
-  grub_util_warn ("%s", _("Embedding is not possible.  GRUB can only be installed in this "
-			  "setup by using blocklists.  However, blocklists are UNRELIABLE and "
-			  "their use is discouraged."));
-  if (! force)
-    /* TRANSLATORS: Here GRUB refuses to continue with blocklist install.  */
-    grub_util_error ("%s", _("will not proceed with blocklists"));
-
-  /* The core image must be put on a filesystem unfortunately.  */
-  grub_util_info ("will leave the core image on the filesystem");
-
-  /* Make sure that GRUB reads the identical image as the OS.  */
-  tmp_img = xmalloc (core_size);
-  core_path_dev_full = grub_util_get_path (dir, core_file);
-  core_path_dev = grub_make_system_path_relative_to_its_root (core_path_dev_full);
-  free (core_path_dev_full);
-
-  grub_util_biosdisk_flush (root_dev->disk);
-
-#ifndef __linux__
-
-#define MAX_TRIES	5
-  {
-    int i;
-    for (i = 0; i < MAX_TRIES; i++)
-      {
-	grub_file_t file;
-
-	grub_util_info ((i == 0) ? _("attempting to read the core image `%s' from GRUB")
-			: _("attempting to read the core image `%s' from GRUB again"),
-			core_path_dev);
-
-	grub_disk_cache_invalidate_all ();
-
-	grub_file_filter_disable_compression ();
-	file = grub_file_open (core_path_dev);
-	if (file)
-	  {
-	    if (grub_file_size (file) != core_size)
-	      grub_util_info ("succeeded in opening the core image but the size is different (%d != %d)",
-			      (int) grub_file_size (file), (int) core_size);
-	    else if (grub_file_read (file, tmp_img, core_size)
-		     != (grub_ssize_t) core_size)
-	      grub_util_info ("succeeded in opening the core image but cannot read %d bytes",
-			      (int) core_size);
-	    else if (memcmp (core_img, tmp_img, core_size) != 0)
-	      {
-#if 0
-		FILE *dump;
-		FILE *dump2;
-
-		dump = fopen ("dump.img", "wb");
-		if (dump)
-		  {
-		    fwrite (tmp_img, 1, core_size, dump);
-		    fclose (dump);
-		  }
-
-		dump2 = fopen ("dump2.img", "wb");
-		if (dump2)
-		  {
-		    fwrite (core_img, 1, core_size, dump2);
-		    fclose (dump2);
-		  }
-
-#endif
-		grub_util_info ("succeeded in opening the core image but the data is different");
-	      }
-	    else
-	      {
-		grub_file_close (file);
-		break;
-	      }
-
-	    grub_file_close (file);
-	  }
-	else
-	  grub_util_info ("couldn't open the core image");
-
-	if (grub_errno)
-	  grub_util_info ("error message = %s", grub_errmsg);
-
-	grub_errno = GRUB_ERR_NONE;
-	grub_util_biosdisk_flush (root_dev->disk);
-	sleep (1);
-      }
-
-    if (i == MAX_TRIES)
-      grub_util_error (_("cannot read `%s' correctly"), core_path_dev);
-  }
-
-#endif
-
-  /* Clean out the blocklists.  */
-  bl.block = bl.first_block;
-  while (bl.block->len)
-    {
-      bl.block->start = 0;
-      bl.block->len = 0;
-#ifdef GRUB_SETUP_BIOS
-      bl.block->segment = 0;
-#endif
-
-      bl.block--;
-
-      if ((char *) bl.block <= core_img)
-	grub_util_error ("%s", _("no terminator in the core image"));
-    }
-
-  bl.block = bl.first_block;
-
-#ifdef __linux__
-  {
-    grub_partition_t container = root_dev->disk->partition;
-    grub_uint64_t container_start = grub_partition_get_start (container);
-    struct fiemap fie1;
-    int fd;
-
-    /* Write the first two sectors of the core image onto the disk.  */
-    grub_util_info ("opening the core image `%s'", core_path);
-    fp = fopen (core_path, "rb");
-    if (! fp)
-      grub_util_error (_("cannot open `%s': %s"), core_path,
-		       strerror (errno));
-    fd = fileno (fp);
-
-    grub_memset (&fie1, 0, sizeof (fie1));
-    fie1.fm_length = core_size;
-    fie1.fm_flags = FIEMAP_FLAG_SYNC;
-
-    if (ioctl (fd, FS_IOC_FIEMAP, &fie1) < 0)
-      {
-	int nblocks, i, j;
-	int bsize;
-	int mul;
-
-	grub_util_info ("FIEMAP failed. Reverting to FIBMAP");
-
-	if (ioctl (fd, FIGETBSZ, &bsize) < 0)
-	  grub_util_error (_("can't retrieve blocklists: %s"),
-			   strerror (errno));
-	if (bsize & (GRUB_DISK_SECTOR_SIZE - 1))
-	  grub_util_error ("%s", _("blocksize is not divisible by 512"));
-	mul = bsize >> GRUB_DISK_SECTOR_BITS;
-	nblocks = (core_size + bsize - 1) / bsize;
-	if (mul == 0 || nblocks == 0)
-	  grub_util_error ("%s", _("can't retrieve blocklists"));
-	for (i = 0; i < nblocks; i++)
-	  {
-	    unsigned blk = i;
-	    if (ioctl (fd, FIBMAP, &blk) < 0)
-	      grub_util_error (_("can't retrieve blocklists: %s"),
-			       strerror (errno));
-	    
-	    for (j = 0; j < mul; j++)
-	      {
-		int rest = core_size - ((i * mul + j) << GRUB_DISK_SECTOR_BITS);
-		if (rest <= 0)
-		  break;
-		if (rest > GRUB_DISK_SECTOR_SIZE)
-		  rest = GRUB_DISK_SECTOR_SIZE;
-		if (i == 0 && j == 0)
-		  save_first_sector (((grub_uint64_t) blk) * mul
-				     + container_start,
-				     0, rest, &first_sector);
-		else
-		  save_blocklists (((grub_uint64_t) blk) * mul + j
-				   + container_start,
-				   0, rest, &bl);
-	      }
-	  }
-      }
-    else
-      {
-	struct fiemap *fie2;
-	int i, j;
-	fie2 = xmalloc (sizeof (*fie2)
-			+ fie1.fm_mapped_extents
-			* sizeof (fie1.fm_extents[1]));
-	memset (fie2, 0, sizeof (*fie2)
-		+ fie1.fm_mapped_extents * sizeof (fie2->fm_extents[1]));
-	fie2->fm_length = core_size;
-	fie2->fm_flags = FIEMAP_FLAG_SYNC;
-	fie2->fm_extent_count = fie1.fm_mapped_extents;
-	if (ioctl (fd, FS_IOC_FIEMAP, fie2) < 0)
-	  grub_util_error (_("can't retrieve blocklists: %s"),
-			   strerror (errno));
-	for (i = 0; i < fie2->fm_mapped_extents; i++)
-	  {
-	    for (j = 0;
-		 j < ((fie2->fm_extents[i].fe_length
-		       + GRUB_DISK_SECTOR_SIZE - 1)
-		      >> GRUB_DISK_SECTOR_BITS);
-		 j++)
-	      {
-		size_t len = (fie2->fm_extents[i].fe_length
-			      - j * GRUB_DISK_SECTOR_SIZE);
-		if (len > GRUB_DISK_SECTOR_SIZE)
-		  len = GRUB_DISK_SECTOR_SIZE;
-		if (first_sector == (grub_disk_addr_t)-1)
-		  save_first_sector ((fie2->fm_extents[i].fe_physical
-				      >> GRUB_DISK_SECTOR_BITS)
-				     + j + container_start,
-				     fie2->fm_extents[i].fe_physical
-				     & (GRUB_DISK_SECTOR_SIZE - 1), len,
-				     &first_sector);
-		else
-		  save_blocklists ((fie2->fm_extents[i].fe_physical
-				    >> GRUB_DISK_SECTOR_BITS)
-				   + j + container_start,
-				   fie2->fm_extents[i].fe_physical
-				   & (GRUB_DISK_SECTOR_SIZE - 1), len, &bl);
-
-
-	      }
-	  }
-	if (first_sector == (grub_disk_addr_t)-1)
-	  grub_util_error ("%s", _("can't retrieve blocklists"));
-      }
-    fclose (fp);
-  }
-#else
-  {
-    grub_file_t file;
-    /* Now read the core image to determine where the sectors are.  */
-    grub_file_filter_disable_compression ();
-    file = grub_file_open (core_path_dev);
-    if (! file)
-      grub_util_error ("%s", grub_errmsg);
-
-    file->read_hook = save_first_sector;
-    file->read_hook_data = &first_sector;
-    if (grub_file_read (file, tmp_img, GRUB_DISK_SECTOR_SIZE)
-	!= GRUB_DISK_SECTOR_SIZE)
-      grub_util_error ("%s", _("failed to read the first sector of the core image"));
-
-    bl.block = bl.first_block;
-    file->read_hook = save_blocklists;
-    file->read_hook_data = &bl;
-    if (grub_file_read (file, tmp_img, core_size - GRUB_DISK_SECTOR_SIZE)
-	!= (grub_ssize_t) core_size - GRUB_DISK_SECTOR_SIZE)
-      grub_util_error ("%s", _("failed to read the rest sectors of the core image"));
-    grub_file_close (file);
-  }
-#endif
-
-#ifdef GRUB_SETUP_SPARC64
-  {
-    char *boot_devpath;
-    boot_devpath = (char *) (boot_img
-			     + GRUB_BOOT_AOUT_HEADER_SIZE
-			     + GRUB_BOOT_MACHINE_BOOT_DEVPATH);
-    if (dest_dev->disk->id != root_dev->disk->id
-	|| dest_dev->disk->dev->id != root_dev->disk->dev->id)
-      {
-	const char *dest_ofpath;
-	dest_ofpath
-	  = grub_util_devname_to_ofpath (grub_util_biosdisk_get_osdev (root_dev->disk));
-	grub_util_info ("dest_ofpath is `%s'", dest_ofpath);
-	strncpy (boot_devpath, dest_ofpath,
-		 GRUB_BOOT_MACHINE_BOOT_DEVPATH_END
-		 - GRUB_BOOT_MACHINE_BOOT_DEVPATH - 1);
-	boot_devpath[GRUB_BOOT_MACHINE_BOOT_DEVPATH_END
-		   - GRUB_BOOT_MACHINE_BOOT_DEVPATH - 1] = 0;
-      }
-    else
-      {
-	grub_util_info ("non cross-disk install");
-	memset (boot_devpath, 0, GRUB_BOOT_MACHINE_BOOT_DEVPATH_END
-		- GRUB_BOOT_MACHINE_BOOT_DEVPATH);
-      }
-    grub_util_info ("boot device path %s", boot_devpath);
-  }
-#endif
-
-  free (core_path_dev);
-  free (tmp_img);
-
-  write_rootdev (root_dev, boot_img, first_sector);
-
-  /* Write the first two sectors of the core image onto the disk.  */
-  grub_util_info ("opening the core image `%s'", core_path);
-  fp = fopen (core_path, "r+b");
-  if (! fp)
-    grub_util_error (_("cannot open `%s': %s"), core_path,
-		     strerror (errno));
-
-  grub_util_write_image (core_img, GRUB_DISK_SECTOR_SIZE * 2, fp, core_path);
-  fflush (fp);
-  fsync (fileno (fp));
-  fclose (fp);
-  grub_util_biosdisk_flush (root_dev->disk);
-
-  grub_disk_cache_invalidate_all ();
-
-  {
-    char *buf, *ptr = core_img;
-    size_t len = core_size;
-    grub_uint64_t blk;
-    grub_partition_t container = core_dev->disk->partition;
-    grub_err_t err;
-
-    core_dev->disk->partition = 0;
-
-    buf = xmalloc (core_size);
-    blk = first_sector;
-    err = grub_disk_read (core_dev->disk, blk, 0, GRUB_DISK_SECTOR_SIZE, buf);
-    if (err)
-      grub_util_error (_("cannot read `%s': %s"), core_dev->disk->name,
-		       grub_errmsg);
-    if (grub_memcmp (buf, ptr, GRUB_DISK_SECTOR_SIZE) != 0)
-      grub_util_error ("%s", _("blocklists are invalid"));
-
-    ptr += GRUB_DISK_SECTOR_SIZE;
-    len -= GRUB_DISK_SECTOR_SIZE;
-
-    bl.block = bl.first_block;
-    while (bl.block->len)
-      {
-	size_t cur = grub_target_to_host16 (bl.block->len) << GRUB_DISK_SECTOR_BITS;
-	blk = grub_target_to_host64 (bl.block->start);
-
-	if (cur > len)
-	  cur = len;
-
-	err = grub_disk_read (core_dev->disk, blk, 0, cur, buf);
-	if (err)
-	  grub_util_error (_("cannot read `%s': %s"), core_dev->disk->name,
-			   grub_errmsg);
-
-	if (grub_memcmp (buf, ptr, cur) != 0)
-	  grub_util_error ("%s", _("blocklists are invalid"));
-
-	ptr += cur;
-	len -= cur;
-	bl.block--;
-	
-	if ((char *) bl.block <= core_img)
-	  grub_util_error ("%s", _("no terminator in the core image"));
-      }
-    core_dev->disk->partition = container;
-    free (buf);
-  }
-
-#ifdef GRUB_SETUP_BIOS
- finish:
-#endif
-
-  /* Write the boot image onto the disk.  */
-  if (grub_disk_write (dest_dev->disk, BOOT_SECTOR,
-		       0, GRUB_DISK_SECTOR_SIZE, boot_img))
-    grub_util_error ("%s", grub_errmsg);
-
-  grub_util_biosdisk_flush (root_dev->disk);
-  grub_util_biosdisk_flush (dest_dev->disk);
-
-  free (core_path);
-  free (core_img);
-  free (boot_img);
-  grub_device_close (dest_dev);
-  grub_device_close (root_dev);
-}
-
 static struct argp_option options[] = {
   {"boot-image",  'b', N_("FILE"), 0,
    N_("use FILE as the boot image [default=%s]"), 0},
@@ -1002,10 +84,10 @@
   switch (key)
     {
       case 'b':
-        return xasprintf (text, DEFAULT_BOOT_FILE);
+        return xasprintf (text, "boot.img");
 
       case 'c':
-        return xasprintf (text, DEFAULT_CORE_FILE);
+        return xasprintf (text, "core.img");
 
       case 'd':
         return xasprintf (text, DEFAULT_DIRECTORY);
@@ -1199,12 +281,18 @@
       grub_util_info ("Using `%s' as GRUB device", dest_dev);
     }
 
+  char *boot_path;
+
+  boot_path = grub_util_get_path (arguments.dir ? : DEFAULT_DIRECTORY,
+				  arguments.boot_file ? : "boot.img");
+
   /* Do the real work.  */
-  setup (arguments.dir ? : DEFAULT_DIRECTORY,
-	 arguments.boot_file ? : DEFAULT_BOOT_FILE,
-	 arguments.core_file ? : DEFAULT_CORE_FILE,
-	 dest_dev, arguments.force,
-	 arguments.fs_probe, arguments.allow_floppy);
+  GRUB_SETUP_FUNC (arguments.dir ? : DEFAULT_DIRECTORY,
+		   boot_path,
+		   arguments.core_file,
+		   dest_dev, arguments.force,
+		   arguments.fs_probe, arguments.allow_floppy);
+  free (boot_path);
 
   /* Free resources.  */
   grub_fini_all ();

=== added file 'util/mkimage.c'
--- util/mkimage.c	1970-01-01 00:00:00 +0000
+++ util/mkimage.c	2013-10-04 00:39:55 +0000
@@ -0,0 +1,1861 @@
+/* grub-mkimage.c - make a bootable image */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010  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 <config.h>
+#include <grub/types.h>
+#include <grub/elf.h>
+#include <grub/aout.h>
+#include <grub/i18n.h>
+#include <grub/kernel.h>
+#include <grub/disk.h>
+#include <grub/emu/misc.h>
+#include <grub/util/misc.h>
+#include <grub/util/resolve.h>
+#include <grub/misc.h>
+#include <grub/offsets.h>
+#include <grub/crypto.h>
+#include <grub/dl.h>
+#include <time.h>
+#include <multiboot.h>
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <grub/efi/pe32.h>
+#include <grub/uboot/image.h>
+#include <grub/arm/reloc.h>
+#include <grub/ia64/reloc.h>
+#include <grub/util/install.h>
+
+#include "progname.h"
+
+#define ALIGN_ADDR(x) (ALIGN_UP((x), image_target->voidp_sizeof))
+
+#ifdef HAVE_LIBLZMA
+#include <lzma.h>
+#endif
+
+#define TARGET_NO_FIELD 0xffffffff
+
+struct grub_install_image_target_desc
+{
+  const char *dirname;
+  const char *names[6];
+  grub_size_t voidp_sizeof;
+  int bigendian;
+  enum {
+    IMAGE_I386_PC, IMAGE_EFI, IMAGE_COREBOOT,
+    IMAGE_SPARC64_AOUT, IMAGE_SPARC64_RAW, IMAGE_SPARC64_CDCORE,
+    IMAGE_I386_IEEE1275,
+    IMAGE_LOONGSON_ELF, IMAGE_QEMU, IMAGE_PPC, IMAGE_YEELOONG_FLASH,
+    IMAGE_FULOONG2F_FLASH, IMAGE_I386_PC_PXE, IMAGE_MIPS_ARC,
+    IMAGE_QEMU_MIPS_FLASH, IMAGE_UBOOT
+  } id;
+  enum
+    {
+      PLATFORM_FLAGS_NONE = 0,
+      PLATFORM_FLAGS_DECOMPRESSORS = 2,
+      PLATFORM_FLAGS_MODULES_BEFORE_KERNEL = 4,
+    } flags;
+  unsigned total_module_size;
+  unsigned decompressor_compressed_size;
+  unsigned decompressor_uncompressed_size;
+  unsigned decompressor_uncompressed_addr;
+  unsigned link_align;
+  grub_uint16_t elf_target;
+  unsigned section_align;
+  signed vaddr_offset;
+  grub_uint64_t link_addr;
+  unsigned mod_gap, mod_align;
+  grub_compression_t default_compression;
+  grub_uint16_t pe_target;
+};
+
+#define EFI32_HEADER_SIZE ALIGN_UP (GRUB_PE32_MSDOS_STUB_SIZE		\
+				    + GRUB_PE32_SIGNATURE_SIZE		\
+				    + sizeof (struct grub_pe32_coff_header) \
+				    + sizeof (struct grub_pe32_optional_header) \
+				    + 4 * sizeof (struct grub_pe32_section_table), \
+				    GRUB_PE32_SECTION_ALIGNMENT)
+
+#define EFI64_HEADER_SIZE ALIGN_UP (GRUB_PE32_MSDOS_STUB_SIZE		\
+				    + GRUB_PE32_SIGNATURE_SIZE		\
+				    + sizeof (struct grub_pe32_coff_header) \
+				    + sizeof (struct grub_pe64_optional_header) \
+				    + 4 * sizeof (struct grub_pe32_section_table), \
+				    GRUB_PE32_SECTION_ALIGNMENT)
+
+struct grub_install_image_target_desc image_targets[] =
+  {
+    {
+      .dirname = "i386-coreboot",
+      .names = { "i386-coreboot", NULL },
+      .voidp_sizeof = 4,
+      .bigendian = 0,
+      .id = IMAGE_COREBOOT,
+      .flags = PLATFORM_FLAGS_NONE,
+      .total_module_size = TARGET_NO_FIELD,
+      .decompressor_compressed_size = TARGET_NO_FIELD,
+      .decompressor_uncompressed_size = TARGET_NO_FIELD,
+      .decompressor_uncompressed_addr = TARGET_NO_FIELD,
+      .section_align = 1,
+      .vaddr_offset = 0,
+      .link_addr = GRUB_KERNEL_I386_COREBOOT_LINK_ADDR,
+      .elf_target = EM_386,
+      .link_align = 4,
+      .mod_gap = GRUB_KERNEL_I386_COREBOOT_MOD_GAP,
+      .mod_align = GRUB_KERNEL_I386_COREBOOT_MOD_ALIGN
+    },
+    {
+      .dirname = "i386-multiboot",
+      .names = { "i386-multiboot", NULL},
+      .voidp_sizeof = 4,
+      .bigendian = 0,
+      .id = IMAGE_COREBOOT,
+      .flags = PLATFORM_FLAGS_NONE,
+      .total_module_size = TARGET_NO_FIELD,
+      .decompressor_compressed_size = TARGET_NO_FIELD,
+      .decompressor_uncompressed_size = TARGET_NO_FIELD,
+      .decompressor_uncompressed_addr = TARGET_NO_FIELD,
+      .section_align = 1,
+      .vaddr_offset = 0,
+      .link_addr = GRUB_KERNEL_I386_COREBOOT_LINK_ADDR,
+      .elf_target = EM_386,
+      .link_align = 4,
+      .mod_gap = GRUB_KERNEL_I386_COREBOOT_MOD_GAP,
+      .mod_align = GRUB_KERNEL_I386_COREBOOT_MOD_ALIGN
+    },
+    {
+      .dirname = "i386-pc",
+      .names = { "i386-pc", NULL },
+      .voidp_sizeof = 4,
+      .bigendian = 0,
+      .id = IMAGE_I386_PC, 
+      .flags = PLATFORM_FLAGS_DECOMPRESSORS,
+      .total_module_size = TARGET_NO_FIELD,
+      .decompressor_compressed_size = GRUB_DECOMPRESSOR_I386_PC_COMPRESSED_SIZE,
+      .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_I386_PC_UNCOMPRESSED_SIZE,
+      .decompressor_uncompressed_addr = TARGET_NO_FIELD,
+      .section_align = 1,
+      .vaddr_offset = 0,
+      .link_addr = GRUB_KERNEL_I386_PC_LINK_ADDR,
+      .default_compression = GRUB_COMPRESSION_LZMA
+    },
+    {
+      .dirname = "i386-pc",
+      .names = { "i386-pc-pxe", NULL },
+      .voidp_sizeof = 4,
+      .bigendian = 0,
+      .id = IMAGE_I386_PC_PXE, 
+      .flags = PLATFORM_FLAGS_DECOMPRESSORS,
+      .total_module_size = TARGET_NO_FIELD,
+      .decompressor_compressed_size = GRUB_DECOMPRESSOR_I386_PC_COMPRESSED_SIZE,
+      .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_I386_PC_UNCOMPRESSED_SIZE,
+      .decompressor_uncompressed_addr = TARGET_NO_FIELD,
+      .section_align = 1,
+      .vaddr_offset = 0,
+      .link_addr = GRUB_KERNEL_I386_PC_LINK_ADDR,
+      .default_compression = GRUB_COMPRESSION_LZMA
+    },
+    {
+      .dirname = "i386-efi",
+      .names = { "i386-efi", NULL },
+      .voidp_sizeof = 4,
+      .bigendian = 0,
+      .id = IMAGE_EFI,
+      .flags = PLATFORM_FLAGS_NONE,
+      .total_module_size = TARGET_NO_FIELD,
+      .decompressor_compressed_size = TARGET_NO_FIELD,
+      .decompressor_uncompressed_size = TARGET_NO_FIELD,
+      .decompressor_uncompressed_addr = TARGET_NO_FIELD,
+      .section_align = GRUB_PE32_SECTION_ALIGNMENT,
+      .vaddr_offset = EFI32_HEADER_SIZE,
+      .pe_target = GRUB_PE32_MACHINE_I386,
+      .elf_target = EM_386,
+    },
+    {
+      .dirname = "i386-ieee1275",
+      .names = { "i386-ieee1275", NULL },
+      .voidp_sizeof = 4,
+      .bigendian = 0,
+      .id = IMAGE_I386_IEEE1275, 
+      .flags = PLATFORM_FLAGS_NONE,
+      .total_module_size = TARGET_NO_FIELD,
+      .decompressor_compressed_size = TARGET_NO_FIELD,
+      .decompressor_uncompressed_size = TARGET_NO_FIELD,
+      .decompressor_uncompressed_addr = TARGET_NO_FIELD,
+      .section_align = 1,
+      .vaddr_offset = 0,
+      .link_addr = GRUB_KERNEL_I386_IEEE1275_LINK_ADDR,
+      .elf_target = EM_386,
+      .mod_gap = GRUB_KERNEL_I386_IEEE1275_MOD_GAP,
+      .mod_align = GRUB_KERNEL_I386_IEEE1275_MOD_ALIGN,
+      .link_align = 4,
+    },
+    {
+      .dirname = "i386-qemu",
+      .names = { "i386-qemu", NULL },
+      .voidp_sizeof = 4,
+      .bigendian = 0,
+      .id = IMAGE_QEMU, 
+      .flags = PLATFORM_FLAGS_NONE,
+      .total_module_size = TARGET_NO_FIELD,
+      .decompressor_compressed_size = TARGET_NO_FIELD,
+      .decompressor_uncompressed_size = TARGET_NO_FIELD,
+      .decompressor_uncompressed_addr = TARGET_NO_FIELD,
+      .section_align = 1,
+      .vaddr_offset = 0,
+      .link_addr = GRUB_KERNEL_I386_QEMU_LINK_ADDR
+    },
+    {
+      .dirname = "x86_64-efi",
+      .names = { "x86_64-efi", NULL },
+      .voidp_sizeof = 8,
+      .bigendian = 0, 
+      .id = IMAGE_EFI, 
+      .flags = PLATFORM_FLAGS_NONE,
+      .total_module_size = TARGET_NO_FIELD,
+      .decompressor_compressed_size = TARGET_NO_FIELD,
+      .decompressor_uncompressed_size = TARGET_NO_FIELD,
+      .decompressor_uncompressed_addr = TARGET_NO_FIELD,
+      .section_align = GRUB_PE32_SECTION_ALIGNMENT,
+      .vaddr_offset = EFI64_HEADER_SIZE,
+      .pe_target = GRUB_PE32_MACHINE_X86_64,
+      .elf_target = EM_X86_64,
+    },
+    {
+      .dirname = "mipsel-loongson",
+      .names = { "mipsel-yeeloong-flash", NULL },
+      .voidp_sizeof = 4,
+      .bigendian = 0,
+      .id = IMAGE_YEELOONG_FLASH, 
+      .flags = PLATFORM_FLAGS_DECOMPRESSORS,
+      .total_module_size = GRUB_KERNEL_MIPS_LOONGSON_TOTAL_MODULE_SIZE,
+      .decompressor_compressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_COMPRESSED_SIZE,
+      .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_SIZE,
+      .decompressor_uncompressed_addr = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_ADDR,
+      .section_align = 1,
+      .vaddr_offset = 0,
+      .link_addr = GRUB_KERNEL_MIPS_LOONGSON_LINK_ADDR,
+      .elf_target = EM_MIPS,
+      .link_align = GRUB_KERNEL_MIPS_LOONGSON_LINK_ALIGN,
+      .default_compression = GRUB_COMPRESSION_NONE
+    },
+    {
+      .dirname = "mipsel-loongson",
+      .names = { "mipsel-fuloong2f-flash", NULL },
+      .voidp_sizeof = 4,
+      .bigendian = 0,
+      .id = IMAGE_FULOONG2F_FLASH, 
+      .flags = PLATFORM_FLAGS_DECOMPRESSORS,
+      .total_module_size = GRUB_KERNEL_MIPS_LOONGSON_TOTAL_MODULE_SIZE,
+      .decompressor_compressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_COMPRESSED_SIZE,
+      .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_SIZE,
+      .decompressor_uncompressed_addr = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_ADDR,
+      .section_align = 1,
+      .vaddr_offset = 0,
+      .link_addr = GRUB_KERNEL_MIPS_LOONGSON_LINK_ADDR,
+      .elf_target = EM_MIPS,
+      .link_align = GRUB_KERNEL_MIPS_LOONGSON_LINK_ALIGN,
+      .default_compression = GRUB_COMPRESSION_NONE
+    },
+    {
+      .dirname = "mipsel-loongson",
+      .names = { "mipsel-loongson-elf", "mipsel-yeeloong-elf",
+		 "mipsel-fuloong2f-elf", "mipsel-fuloong2e-elf",
+		 "mipsel-fuloong-elf", NULL },
+      .voidp_sizeof = 4,
+      .bigendian = 0,
+      .id = IMAGE_LOONGSON_ELF, 
+      .flags = PLATFORM_FLAGS_DECOMPRESSORS,
+      .total_module_size = GRUB_KERNEL_MIPS_LOONGSON_TOTAL_MODULE_SIZE,
+      .decompressor_compressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_COMPRESSED_SIZE,
+      .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_SIZE,
+      .decompressor_uncompressed_addr = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_ADDR,
+      .section_align = 1,
+      .vaddr_offset = 0,
+      .link_addr = GRUB_KERNEL_MIPS_LOONGSON_LINK_ADDR,
+      .elf_target = EM_MIPS,
+      .link_align = GRUB_KERNEL_MIPS_LOONGSON_LINK_ALIGN,
+      .default_compression = GRUB_COMPRESSION_NONE
+    },
+    {
+      .dirname = "powerpc-ieee1275",
+      .names = { "powerpc-ieee1275", NULL },
+      .voidp_sizeof = 4,
+      .bigendian = 1,
+      .id = IMAGE_PPC, 
+      .flags = PLATFORM_FLAGS_NONE,
+      .total_module_size = TARGET_NO_FIELD,
+      .decompressor_compressed_size = TARGET_NO_FIELD,
+      .decompressor_uncompressed_size = TARGET_NO_FIELD,
+      .decompressor_uncompressed_addr = TARGET_NO_FIELD,
+      .section_align = 1,
+      .vaddr_offset = 0,
+      .link_addr = GRUB_KERNEL_POWERPC_IEEE1275_LINK_ADDR,
+      .elf_target = EM_PPC,
+      .mod_gap = GRUB_KERNEL_POWERPC_IEEE1275_MOD_GAP,
+      .mod_align = GRUB_KERNEL_POWERPC_IEEE1275_MOD_ALIGN,
+      .link_align = 4
+    },
+    {
+      .dirname = "sparc64-ieee1275",
+      .names = { "sparc64-ieee1275-raw", NULL },
+      .voidp_sizeof = 8,
+      .bigendian = 1, 
+      .id = IMAGE_SPARC64_RAW,
+      .flags = PLATFORM_FLAGS_NONE,
+      .total_module_size = GRUB_KERNEL_SPARC64_IEEE1275_TOTAL_MODULE_SIZE,
+      .decompressor_compressed_size = TARGET_NO_FIELD,
+      .decompressor_uncompressed_size = TARGET_NO_FIELD,
+      .decompressor_uncompressed_addr = TARGET_NO_FIELD,
+      .section_align = 1,
+      .vaddr_offset = 0,
+      .link_addr = GRUB_KERNEL_SPARC64_IEEE1275_LINK_ADDR
+    },
+    {
+      .dirname = "sparc64-ieee1275",
+      .names = { "sparc64-ieee1275-cdcore", NULL },
+      .voidp_sizeof = 8,
+      .bigendian = 1, 
+      .id = IMAGE_SPARC64_CDCORE,
+      .flags = PLATFORM_FLAGS_NONE,
+      .total_module_size = GRUB_KERNEL_SPARC64_IEEE1275_TOTAL_MODULE_SIZE,
+      .decompressor_compressed_size = TARGET_NO_FIELD,
+      .decompressor_uncompressed_size = TARGET_NO_FIELD,
+      .decompressor_uncompressed_addr = TARGET_NO_FIELD,
+      .section_align = 1,
+      .vaddr_offset = 0,
+      .link_addr = GRUB_KERNEL_SPARC64_IEEE1275_LINK_ADDR
+    },
+    {
+      .dirname = "sparc64-ieee1275",
+      .names = { "sparc64-ieee1275-aout", NULL },
+      .voidp_sizeof = 8,
+      .bigendian = 1,
+      .id = IMAGE_SPARC64_AOUT,
+      .flags = PLATFORM_FLAGS_NONE,
+      .total_module_size = GRUB_KERNEL_SPARC64_IEEE1275_TOTAL_MODULE_SIZE,
+      .decompressor_compressed_size = TARGET_NO_FIELD,
+      .decompressor_uncompressed_size = TARGET_NO_FIELD,
+      .decompressor_uncompressed_addr = TARGET_NO_FIELD,
+      .section_align = 1,
+      .vaddr_offset = 0,
+      .link_addr = GRUB_KERNEL_SPARC64_IEEE1275_LINK_ADDR
+    },
+    {
+      .dirname = "ia64-efi",
+      .names = {"ia64-efi", NULL},
+      .voidp_sizeof = 8,
+      .bigendian = 0, 
+      .id = IMAGE_EFI, 
+      .flags = PLATFORM_FLAGS_NONE,
+      .total_module_size = TARGET_NO_FIELD,
+      .decompressor_compressed_size = TARGET_NO_FIELD,
+      .decompressor_uncompressed_size = TARGET_NO_FIELD,
+      .decompressor_uncompressed_addr = TARGET_NO_FIELD,
+      .section_align = GRUB_PE32_SECTION_ALIGNMENT,
+      .vaddr_offset = EFI64_HEADER_SIZE,
+      .pe_target = GRUB_PE32_MACHINE_IA64,
+      .elf_target = EM_IA_64,
+    },
+    {
+      .dirname = "mips-arc",
+      .names = {"mips-arc", NULL},
+      .voidp_sizeof = 4,
+      .bigendian = 1,
+      .id = IMAGE_MIPS_ARC, 
+      .flags = PLATFORM_FLAGS_DECOMPRESSORS,
+      .total_module_size = GRUB_KERNEL_MIPS_ARC_TOTAL_MODULE_SIZE,
+      .decompressor_compressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_COMPRESSED_SIZE,
+      .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_SIZE,
+      .decompressor_uncompressed_addr = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_ADDR,
+      .section_align = 1,
+      .vaddr_offset = 0,
+      .link_addr = GRUB_KERNEL_MIPS_ARC_LINK_ADDR,
+      .elf_target = EM_MIPS,
+      .link_align = GRUB_KERNEL_MIPS_ARC_LINK_ALIGN,
+      .default_compression = GRUB_COMPRESSION_NONE
+    },
+    {
+      .dirname = "mipsel-arc",
+      .names = {"mipsel-arc", NULL},
+      .voidp_sizeof = 4,
+      .bigendian = 0,
+      .id = IMAGE_MIPS_ARC, 
+      .flags = PLATFORM_FLAGS_DECOMPRESSORS,
+      .total_module_size = GRUB_KERNEL_MIPS_ARC_TOTAL_MODULE_SIZE,
+      .decompressor_compressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_COMPRESSED_SIZE,
+      .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_SIZE,
+      .decompressor_uncompressed_addr = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_ADDR,
+      .section_align = 1,
+      .vaddr_offset = 0,
+      .link_addr = GRUB_KERNEL_MIPSEL_ARC_LINK_ADDR,
+      .elf_target = EM_MIPS,
+      .link_align = GRUB_KERNEL_MIPS_ARC_LINK_ALIGN,
+      .default_compression = GRUB_COMPRESSION_NONE
+    },
+    {
+      .dirname = "mipsel-qemu_mips",
+      .names = { "mipsel-qemu_mips-elf", NULL },
+      .voidp_sizeof = 4,
+      .bigendian = 0,
+      .id = IMAGE_LOONGSON_ELF, 
+      .flags = PLATFORM_FLAGS_DECOMPRESSORS,
+      .total_module_size = GRUB_KERNEL_MIPS_QEMU_MIPS_TOTAL_MODULE_SIZE,
+      .decompressor_compressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_COMPRESSED_SIZE,
+      .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_SIZE,
+      .decompressor_uncompressed_addr = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_ADDR,
+      .section_align = 1,
+      .vaddr_offset = 0,
+      .link_addr = GRUB_KERNEL_MIPS_QEMU_MIPS_LINK_ADDR,
+      .elf_target = EM_MIPS,
+      .link_align = GRUB_KERNEL_MIPS_QEMU_MIPS_LINK_ALIGN,
+      .default_compression = GRUB_COMPRESSION_NONE
+    },
+    {
+      .dirname = "mips-qemu_mips",
+      .names = { "mips-qemu_mips-flash", NULL },
+      .voidp_sizeof = 4,
+      .bigendian = 1,
+      .id = IMAGE_QEMU_MIPS_FLASH, 
+      .flags = PLATFORM_FLAGS_DECOMPRESSORS,
+      .total_module_size = GRUB_KERNEL_MIPS_QEMU_MIPS_TOTAL_MODULE_SIZE,
+      .decompressor_compressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_COMPRESSED_SIZE,
+      .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_SIZE,
+      .decompressor_uncompressed_addr = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_ADDR,
+      .section_align = 1,
+      .vaddr_offset = 0,
+      .link_addr = GRUB_KERNEL_MIPS_QEMU_MIPS_LINK_ADDR,
+      .elf_target = EM_MIPS,
+      .link_align = GRUB_KERNEL_MIPS_QEMU_MIPS_LINK_ALIGN,
+      .default_compression = GRUB_COMPRESSION_NONE
+    },
+    {
+      .dirname = "mipsel-qemu_mips",
+      .names = { "mipsel-qemu_mips-flash", NULL },
+      .voidp_sizeof = 4,
+      .bigendian = 0,
+      .id = IMAGE_QEMU_MIPS_FLASH, 
+      .flags = PLATFORM_FLAGS_DECOMPRESSORS,
+      .total_module_size = GRUB_KERNEL_MIPS_QEMU_MIPS_TOTAL_MODULE_SIZE,
+      .decompressor_compressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_COMPRESSED_SIZE,
+      .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_SIZE,
+      .decompressor_uncompressed_addr = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_ADDR,
+      .section_align = 1,
+      .vaddr_offset = 0,
+      .link_addr = GRUB_KERNEL_MIPS_QEMU_MIPS_LINK_ADDR,
+      .elf_target = EM_MIPS,
+      .link_align = GRUB_KERNEL_MIPS_QEMU_MIPS_LINK_ALIGN,
+      .default_compression = GRUB_COMPRESSION_NONE
+    },
+    {
+      .dirname = "mips-qemu_mips",
+      .names = { "mips-qemu_mips-elf", NULL },
+      .voidp_sizeof = 4,
+      .bigendian = 1,
+      .id = IMAGE_LOONGSON_ELF, 
+      .flags = PLATFORM_FLAGS_DECOMPRESSORS,
+      .total_module_size = GRUB_KERNEL_MIPS_QEMU_MIPS_TOTAL_MODULE_SIZE,
+      .decompressor_compressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_COMPRESSED_SIZE,
+      .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_SIZE,
+      .decompressor_uncompressed_addr = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_ADDR,
+      .section_align = 1,
+      .vaddr_offset = 0,
+      .link_addr = GRUB_KERNEL_MIPS_QEMU_MIPS_LINK_ADDR,
+      .elf_target = EM_MIPS,
+      .link_align = GRUB_KERNEL_MIPS_QEMU_MIPS_LINK_ALIGN,
+      .default_compression = GRUB_COMPRESSION_NONE
+    },
+    {
+      .dirname = "arm-uboot",
+      .names = { "arm-uboot", NULL },
+      .voidp_sizeof = 4,
+      .bigendian = 0,
+      .id = IMAGE_UBOOT, 
+      .flags = PLATFORM_FLAGS_NONE,
+      .total_module_size = GRUB_KERNEL_ARM_UBOOT_TOTAL_MODULE_SIZE,
+      .decompressor_compressed_size = TARGET_NO_FIELD,
+      .decompressor_uncompressed_size = TARGET_NO_FIELD,
+      .decompressor_uncompressed_addr = TARGET_NO_FIELD,
+      .section_align = GRUB_KERNEL_ARM_UBOOT_MOD_ALIGN,
+      .vaddr_offset = 0,
+      .link_addr = GRUB_KERNEL_ARM_UBOOT_LINK_ADDR,
+      .elf_target = EM_ARM,
+      .mod_gap = GRUB_KERNEL_ARM_UBOOT_MOD_GAP,
+      .mod_align = GRUB_KERNEL_ARM_UBOOT_MOD_ALIGN,
+      .link_align = 4
+    },
+    {
+      .dirname = "arm-efi",
+      .names = { "arm-efi", NULL },
+      .voidp_sizeof = 4,
+      .bigendian = 0, 
+      .id = IMAGE_EFI, 
+      .flags = PLATFORM_FLAGS_NONE,
+      .total_module_size = TARGET_NO_FIELD,
+      .decompressor_compressed_size = TARGET_NO_FIELD,
+      .decompressor_uncompressed_size = TARGET_NO_FIELD,
+      .decompressor_uncompressed_addr = TARGET_NO_FIELD,
+      .section_align = GRUB_PE32_SECTION_ALIGNMENT,
+      .vaddr_offset = ALIGN_UP (GRUB_PE32_MSDOS_STUB_SIZE
+                                + GRUB_PE32_SIGNATURE_SIZE
+                                + sizeof (struct grub_pe32_coff_header)
+                                + sizeof (struct grub_pe32_optional_header)
+                                + 4 * sizeof (struct grub_pe32_section_table),
+                                GRUB_PE32_SECTION_ALIGNMENT),
+      .pe_target = GRUB_PE32_MACHINE_ARMTHUMB_MIXED,
+      .elf_target = EM_ARM,
+    },
+  };
+
+#define grub_target_to_host32(x) (grub_target_to_host32_real (image_target, (x)))
+#define grub_host_to_target32(x) (grub_host_to_target32_real (image_target, (x)))
+#define grub_target_to_host64(x) (grub_target_to_host64_real (image_target, (x)))
+#define grub_host_to_target64(x) (grub_host_to_target64_real (image_target, (x)))
+#define grub_host_to_target_addr(x) (grub_host_to_target_addr_real (image_target, (x)))
+#define grub_target_to_host16(x) (grub_target_to_host16_real (image_target, (x)))
+#define grub_host_to_target16(x) (grub_host_to_target16_real (image_target, (x)))
+
+static inline grub_uint32_t
+grub_target_to_host32_real (struct grub_install_image_target_desc *image_target, grub_uint32_t in)
+{
+  if (image_target->bigendian)
+    return grub_be_to_cpu32 (in);
+  else
+    return grub_le_to_cpu32 (in);
+}
+
+static inline grub_uint64_t
+grub_target_to_host64_real (struct grub_install_image_target_desc *image_target, grub_uint64_t in)
+{
+  if (image_target->bigendian)
+    return grub_be_to_cpu64 (in);
+  else
+    return grub_le_to_cpu64 (in);
+}
+
+static inline grub_uint64_t
+grub_host_to_target64_real (struct grub_install_image_target_desc *image_target, grub_uint64_t in)
+{
+  if (image_target->bigendian)
+    return grub_cpu_to_be64 (in);
+  else
+    return grub_cpu_to_le64 (in);
+}
+
+static inline grub_uint32_t
+grub_host_to_target32_real (struct grub_install_image_target_desc *image_target, grub_uint32_t in)
+{
+  if (image_target->bigendian)
+    return grub_cpu_to_be32 (in);
+  else
+    return grub_cpu_to_le32 (in);
+}
+
+static inline grub_uint16_t
+grub_target_to_host16_real (struct grub_install_image_target_desc *image_target, grub_uint16_t in)
+{
+  if (image_target->bigendian)
+    return grub_be_to_cpu16 (in);
+  else
+    return grub_le_to_cpu16 (in);
+}
+
+static inline grub_uint16_t
+grub_host_to_target16_real (struct grub_install_image_target_desc *image_target, grub_uint16_t in)
+{
+  if (image_target->bigendian)
+    return grub_cpu_to_be16 (in);
+  else
+    return grub_cpu_to_le16 (in);
+}
+
+static inline grub_uint64_t
+grub_host_to_target_addr_real (struct grub_install_image_target_desc *image_target, grub_uint64_t in)
+{
+  if (image_target->voidp_sizeof == 8)
+    return grub_host_to_target64_real (image_target, in);
+  else
+    return grub_host_to_target32_real (image_target, in);
+}
+
+static inline grub_uint64_t
+grub_target_to_host_real (struct grub_install_image_target_desc *image_target, grub_uint64_t in)
+{
+  if (image_target->voidp_sizeof == 8)
+    return grub_target_to_host64_real (image_target, in);
+  else
+    return grub_target_to_host32_real (image_target, in);
+}
+
+#define GRUB_IEEE1275_NOTE_NAME "PowerPC"
+#define GRUB_IEEE1275_NOTE_TYPE 0x1275
+
+/* These structures are defined according to the CHRP binding to IEEE1275,
+   "Client Program Format" section.  */
+
+struct grub_ieee1275_note_hdr
+{
+  grub_uint32_t namesz;
+  grub_uint32_t descsz;
+  grub_uint32_t type;
+  char name[sizeof (GRUB_IEEE1275_NOTE_NAME)];
+};
+
+struct grub_ieee1275_note_desc
+{
+  grub_uint32_t real_mode;
+  grub_uint32_t real_base;
+  grub_uint32_t real_size;
+  grub_uint32_t virt_base;
+  grub_uint32_t virt_size;
+  grub_uint32_t load_base;
+};
+
+struct grub_ieee1275_note
+{
+  struct grub_ieee1275_note_hdr header;
+  struct grub_ieee1275_note_desc descriptor;
+};
+
+#define grub_target_to_host(val) grub_target_to_host_real(image_target, (val))
+
+#include <grub/lib/LzmaEnc.h>
+
+static void *SzAlloc(void *p, size_t size) { p = p; return xmalloc(size); }
+static void SzFree(void *p, void *address) { p = p; free(address); }
+static ISzAlloc g_Alloc = { SzAlloc, SzFree };
+
+static void
+compress_kernel_lzma (char *kernel_img, size_t kernel_size,
+		      char **core_img, size_t *core_size)
+{
+  CLzmaEncProps props;
+  unsigned char out_props[5];
+  size_t out_props_size = 5;
+
+  LzmaEncProps_Init(&props);
+  props.dictSize = 1 << 16;
+  props.lc = 3;
+  props.lp = 0;
+  props.pb = 2;
+  props.numThreads = 1;
+
+  *core_img = xmalloc (kernel_size);
+
+  *core_size = kernel_size;
+  if (LzmaEncode ((unsigned char *) *core_img, core_size,
+		  (unsigned char *) kernel_img,
+		  kernel_size,
+		  &props, out_props, &out_props_size,
+		  0, NULL, &g_Alloc, &g_Alloc) != SZ_OK)
+    grub_util_error ("%s", _("cannot compress the kernel image"));
+}
+
+#ifdef HAVE_LIBLZMA
+static void
+compress_kernel_xz (char *kernel_img, size_t kernel_size,
+		    char **core_img, size_t *core_size)
+{
+  lzma_stream strm = LZMA_STREAM_INIT;
+  lzma_ret xzret;
+  lzma_options_lzma lzopts = {
+    .dict_size = 1 << 16,
+    .preset_dict = NULL,
+    .preset_dict_size = 0,
+    .lc = 3,
+    .lp = 0,
+    .pb = 2,
+    .mode = LZMA_MODE_NORMAL,
+    .nice_len = 64,
+    .mf = LZMA_MF_BT4,
+    .depth = 0,
+  };
+  lzma_filter fltrs[] = {
+    { .id = LZMA_FILTER_LZMA2, .options = &lzopts},
+    { .id = LZMA_VLI_UNKNOWN, .options = NULL}
+  };
+
+  xzret = lzma_stream_encoder (&strm, fltrs, LZMA_CHECK_NONE);
+  if (xzret != LZMA_OK)
+    grub_util_error ("%s", _("cannot compress the kernel image"));
+
+  *core_img = xmalloc (kernel_size);
+
+  *core_size = kernel_size;
+  strm.next_in = (unsigned char *) kernel_img;
+  strm.avail_in = kernel_size;
+  strm.next_out = (unsigned char *) *core_img;
+  strm.avail_out = *core_size;
+
+  while (1)
+    {
+      xzret = lzma_code (&strm, LZMA_FINISH);
+      if (xzret == LZMA_OK)
+	continue;
+      if (xzret == LZMA_STREAM_END)
+	break;
+      grub_util_error ("%s", _("cannot compress the kernel image"));
+    }
+
+  *core_size -= strm.avail_out;
+}
+#endif
+
+static void
+compress_kernel (struct grub_install_image_target_desc *image_target, char *kernel_img,
+		 size_t kernel_size, char **core_img, size_t *core_size,
+		 grub_compression_t comp)
+{
+  if (image_target->flags & PLATFORM_FLAGS_DECOMPRESSORS
+      && (comp == GRUB_COMPRESSION_LZMA))
+    {
+      compress_kernel_lzma (kernel_img, kernel_size, core_img,
+			    core_size);
+      return;
+    }
+
+#ifdef HAVE_LIBLZMA
+ if (image_target->flags & PLATFORM_FLAGS_DECOMPRESSORS
+     && (comp == GRUB_COMPRESSION_XZ))
+   {
+     compress_kernel_xz (kernel_img, kernel_size, core_img,
+			 core_size);
+     return;
+   }
+#endif
+
+ if (image_target->flags & PLATFORM_FLAGS_DECOMPRESSORS
+     && (comp != GRUB_COMPRESSION_NONE))
+   grub_util_error (_("unknown compression %d\n"), comp);
+
+  *core_img = xmalloc (kernel_size);
+  memcpy (*core_img, kernel_img, kernel_size);
+  *core_size = kernel_size;
+}
+
+struct fixup_block_list
+{
+  struct fixup_block_list *next;
+  int state;
+  struct grub_pe32_fixup_block b;
+};
+
+#pragma GCC diagnostic ignored "-Wcast-align"
+
+#define MKIMAGE_ELF32 1
+#include "grub-mkimagexx.c"
+#undef MKIMAGE_ELF32
+
+#define MKIMAGE_ELF64 1
+#include "grub-mkimagexx.c"
+#undef MKIMAGE_ELF64
+
+struct grub_install_image_target_desc *
+grub_install_get_image_target (const char *arg)
+{
+  unsigned i, j;
+  for (i = 0; i < ARRAY_SIZE (image_targets); i++)
+    for (j = 0; image_targets[i].names[j]
+	   && j < ARRAY_SIZE (image_targets[i].names); j++)
+      if (strcmp (arg, image_targets[i].names[j]) == 0)
+	return &image_targets[i];
+  return NULL;
+}
+
+const char *
+grub_util_get_target_dirname (struct grub_install_image_target_desc *t)
+{
+  return t->dirname;
+}
+
+
+char *
+grub_install_get_image_targets_string (void)
+{
+  int format_len = 0;
+  char *formats;
+  char *ptr;
+  unsigned i;
+  for (i = 0; i < ARRAY_SIZE (image_targets); i++)
+    format_len += strlen (image_targets[i].names[0]) + 2;
+  ptr = formats = xmalloc (format_len);
+  for (i = 0; i < ARRAY_SIZE (image_targets); i++)
+    {
+      strcpy (ptr, image_targets[i].names[0]);
+      ptr += strlen (image_targets[i].names[0]);
+      *ptr++ = ',';
+      *ptr++ = ' ';
+    }
+  ptr[-2] = 0;
+
+  return formats;
+}
+
+void
+grub_install_generate_image (const char *dir, const char *prefix,
+			     FILE *out, const char *outname, char *mods[],
+			     char *memdisk_path, char **pubkey_paths, size_t npubkeys,
+			     char *config_path, struct grub_install_image_target_desc *image_target, int note,
+			     grub_compression_t comp)
+{
+  char *kernel_img, *core_img;
+  size_t kernel_size, total_module_size, core_size, exec_size;
+  size_t memdisk_size = 0, config_size = 0, config_size_pure = 0;
+  size_t prefix_size = 0;
+  char *kernel_path;
+  size_t offset;
+  struct grub_util_path_list *path_list, *p, *next;
+  grub_size_t bss_size;
+  grub_uint64_t start_address;
+  void *rel_section = 0;
+  grub_size_t reloc_size = 0, align;
+  size_t decompress_size = 0;
+
+  if (comp == GRUB_COMPRESSION_AUTO)
+    comp = image_target->default_compression;
+
+  if (image_target->id == IMAGE_I386_PC
+      || image_target->id == IMAGE_I386_PC_PXE)
+    comp = GRUB_COMPRESSION_LZMA;
+
+  path_list = grub_util_resolve_dependencies (dir, "moddep.lst", mods);
+
+  kernel_path = grub_util_get_path (dir, "kernel.img");
+
+  if (image_target->voidp_sizeof == 8)
+    total_module_size = sizeof (struct grub_module_info64);
+  else
+    total_module_size = sizeof (struct grub_module_info32);
+
+  {
+    size_t i;
+    for (i = 0; i < npubkeys; i++)
+      {
+	size_t curs;
+	curs = ALIGN_ADDR (grub_util_get_image_size (pubkey_paths[i]));
+	grub_util_info ("the size of public key %zd is 0x%llx",
+			i, (unsigned long long) curs);
+	total_module_size += curs + sizeof (struct grub_module_header);
+      }
+  }
+
+  if (memdisk_path)
+    {
+      memdisk_size = ALIGN_UP(grub_util_get_image_size (memdisk_path), 512);
+      grub_util_info ("the size of memory disk is 0x%llx",
+		      (unsigned long long) memdisk_size);
+      total_module_size += memdisk_size + sizeof (struct grub_module_header);
+    }
+
+  if (config_path)
+    {
+      config_size_pure = grub_util_get_image_size (config_path) + 1;
+      config_size = ALIGN_ADDR (config_size_pure);
+      grub_util_info ("the size of config file is 0x%llx",
+		      (unsigned long long) config_size);
+      total_module_size += config_size + sizeof (struct grub_module_header);
+    }
+
+  if (prefix)
+    {
+      prefix_size = ALIGN_ADDR (strlen (prefix) + 1);
+      total_module_size += prefix_size + sizeof (struct grub_module_header);
+    }
+
+  for (p = path_list; p; p = p->next)
+    total_module_size += (ALIGN_ADDR (grub_util_get_image_size (p->name))
+			  + sizeof (struct grub_module_header));
+
+  grub_util_info ("the total module size is 0x%llx",
+		  (unsigned long long) total_module_size);
+
+  if (image_target->voidp_sizeof == 4)
+    kernel_img = load_image32 (kernel_path, &exec_size, &kernel_size, &bss_size,
+			       total_module_size, &start_address, &rel_section,
+			       &reloc_size, &align, image_target);
+  else
+    kernel_img = load_image64 (kernel_path, &exec_size, &kernel_size, &bss_size,
+			       total_module_size, &start_address, &rel_section,
+			       &reloc_size, &align, image_target);
+
+  if ((image_target->flags & PLATFORM_FLAGS_DECOMPRESSORS)
+      && (image_target->total_module_size != TARGET_NO_FIELD))
+    *((grub_uint32_t *) (kernel_img + image_target->total_module_size))
+      = grub_host_to_target32 (total_module_size);
+
+  if (image_target->flags & PLATFORM_FLAGS_MODULES_BEFORE_KERNEL)
+    memmove (kernel_img + total_module_size, kernel_img, kernel_size);
+
+  if (image_target->voidp_sizeof == 8)
+    {
+      /* Fill in the grub_module_info structure.  */
+      struct grub_module_info64 *modinfo;
+      if (image_target->flags & PLATFORM_FLAGS_MODULES_BEFORE_KERNEL)
+	modinfo = (struct grub_module_info64 *) kernel_img;
+      else
+	modinfo = (struct grub_module_info64 *) (kernel_img + kernel_size);
+      memset (modinfo, 0, sizeof (struct grub_module_info64));
+      modinfo->magic = grub_host_to_target32 (GRUB_MODULE_MAGIC);
+      modinfo->offset = grub_host_to_target_addr (sizeof (struct grub_module_info64));
+      modinfo->size = grub_host_to_target_addr (total_module_size);
+      if (image_target->flags & PLATFORM_FLAGS_MODULES_BEFORE_KERNEL)
+	offset = sizeof (struct grub_module_info64);
+      else
+	offset = kernel_size + sizeof (struct grub_module_info64);
+    }
+  else
+    {
+      /* Fill in the grub_module_info structure.  */
+      struct grub_module_info32 *modinfo;
+      if (image_target->flags & PLATFORM_FLAGS_MODULES_BEFORE_KERNEL)
+	modinfo = (struct grub_module_info32 *) kernel_img;
+      else
+	modinfo = (struct grub_module_info32 *) (kernel_img + kernel_size);
+      memset (modinfo, 0, sizeof (struct grub_module_info32));
+      modinfo->magic = grub_host_to_target32 (GRUB_MODULE_MAGIC);
+      modinfo->offset = grub_host_to_target_addr (sizeof (struct grub_module_info32));
+      modinfo->size = grub_host_to_target_addr (total_module_size);
+      if (image_target->flags & PLATFORM_FLAGS_MODULES_BEFORE_KERNEL)
+	offset = sizeof (struct grub_module_info32);
+      else
+	offset = kernel_size + sizeof (struct grub_module_info32);
+    }
+
+  for (p = path_list; p; p = p->next)
+    {
+      struct grub_module_header *header;
+      size_t mod_size, orig_size;
+
+      orig_size = grub_util_get_image_size (p->name);
+      mod_size = ALIGN_ADDR (orig_size);
+
+      header = (struct grub_module_header *) (kernel_img + offset);
+      memset (header, 0, sizeof (struct grub_module_header));
+      header->type = grub_host_to_target32 (OBJ_TYPE_ELF);
+      header->size = grub_host_to_target32 (mod_size + sizeof (*header));
+      offset += sizeof (*header);
+      memset (kernel_img + offset + orig_size, 0, mod_size - orig_size);
+
+      grub_util_load_image (p->name, kernel_img + offset);
+      offset += mod_size;
+    }
+
+  {
+    size_t i;
+    for (i = 0; i < npubkeys; i++)
+      {
+	size_t curs;
+	struct grub_module_header *header;
+
+	curs = grub_util_get_image_size (pubkey_paths[i]);
+
+	header = (struct grub_module_header *) (kernel_img + offset);
+	memset (header, 0, sizeof (struct grub_module_header));
+	header->type = grub_host_to_target32 (OBJ_TYPE_PUBKEY);
+	header->size = grub_host_to_target32 (curs + sizeof (*header));
+	offset += sizeof (*header);
+
+	grub_util_load_image (pubkey_paths[i], kernel_img + offset);
+	offset += ALIGN_ADDR (curs);
+      }
+  }
+
+  if (memdisk_path)
+    {
+      struct grub_module_header *header;
+
+      header = (struct grub_module_header *) (kernel_img + offset);
+      memset (header, 0, sizeof (struct grub_module_header));
+      header->type = grub_host_to_target32 (OBJ_TYPE_MEMDISK);
+      header->size = grub_host_to_target32 (memdisk_size + sizeof (*header));
+      offset += sizeof (*header);
+
+      grub_util_load_image (memdisk_path, kernel_img + offset);
+      offset += memdisk_size;
+    }
+
+  if (config_path)
+    {
+      struct grub_module_header *header;
+
+      header = (struct grub_module_header *) (kernel_img + offset);
+      memset (header, 0, sizeof (struct grub_module_header));
+      header->type = grub_host_to_target32 (OBJ_TYPE_CONFIG);
+      header->size = grub_host_to_target32 (config_size + sizeof (*header));
+      offset += sizeof (*header);
+
+      grub_util_load_image (config_path, kernel_img + offset);
+      *(kernel_img + offset + config_size_pure - 1) = 0;
+      offset += config_size;
+    }
+
+  if (prefix)
+    {
+      struct grub_module_header *header;
+
+      header = (struct grub_module_header *) (kernel_img + offset);
+      memset (header, 0, sizeof (struct grub_module_header));
+      header->type = grub_host_to_target32 (OBJ_TYPE_PREFIX);
+      header->size = grub_host_to_target32 (prefix_size + sizeof (*header));
+      offset += sizeof (*header);
+
+      grub_memset (kernel_img + offset, 0, prefix_size);
+      grub_strcpy (kernel_img + offset, prefix);
+      offset += prefix_size;
+    }
+
+  grub_util_info ("kernel_img=%p, kernel_size=0x%llx", kernel_img,
+		  (unsigned long long) kernel_size);
+  compress_kernel (image_target, kernel_img, kernel_size + total_module_size,
+		   &core_img, &core_size, comp);
+  free (kernel_img);
+
+  grub_util_info ("the core size is 0x%llx", (unsigned long long) core_size);
+
+  if (!(image_target->flags & PLATFORM_FLAGS_DECOMPRESSORS) 
+      && image_target->total_module_size != TARGET_NO_FIELD)
+    *((grub_uint32_t *) (core_img + image_target->total_module_size))
+      = grub_host_to_target32 (total_module_size);
+
+  if (image_target->flags & PLATFORM_FLAGS_DECOMPRESSORS)
+    {
+      char *full_img;
+      size_t full_size;
+      char *decompress_path, *decompress_img;
+      const char *name;
+
+      switch (comp)
+	{
+	case GRUB_COMPRESSION_XZ:
+	  name = "xz_decompress.img";
+	  break;
+	case GRUB_COMPRESSION_LZMA:
+	  name = "lzma_decompress.img";
+	  break;
+	case GRUB_COMPRESSION_NONE:
+	  name = "none_decompress.img";
+	  break;
+	default:
+	  grub_util_error (_("unknown compression %d\n"), comp);
+	}
+      
+      decompress_path = grub_util_get_path (dir, name);
+      decompress_size = grub_util_get_image_size (decompress_path);
+      decompress_img = grub_util_read_image (decompress_path);
+
+      if ((image_target->id == IMAGE_I386_PC
+	   || image_target->id == IMAGE_I386_PC_PXE)
+	  && decompress_size > GRUB_KERNEL_I386_PC_LINK_ADDR - 0x8200)
+	grub_util_error ("%s", _("Decompressor is too big"));
+
+      if (image_target->decompressor_compressed_size != TARGET_NO_FIELD)
+	*((grub_uint32_t *) (decompress_img
+			     + image_target->decompressor_compressed_size))
+	  = grub_host_to_target32 (core_size);
+
+      if (image_target->decompressor_uncompressed_size != TARGET_NO_FIELD)
+	*((grub_uint32_t *) (decompress_img
+			     + image_target->decompressor_uncompressed_size))
+	  = grub_host_to_target32 (kernel_size + total_module_size);
+
+      if (image_target->decompressor_uncompressed_addr != TARGET_NO_FIELD)
+	{
+	  if (image_target->flags & PLATFORM_FLAGS_MODULES_BEFORE_KERNEL)
+	    *((grub_uint32_t *) (decompress_img + image_target->decompressor_uncompressed_addr))
+	      = grub_host_to_target_addr (image_target->link_addr - total_module_size);
+	  else
+	    *((grub_uint32_t *) (decompress_img + image_target->decompressor_uncompressed_addr))
+	      = grub_host_to_target_addr (image_target->link_addr);
+	}
+      full_size = core_size + decompress_size;
+
+      full_img = xmalloc (full_size);
+      memset (full_img, 0, full_size); 
+
+      memcpy (full_img, decompress_img, decompress_size);
+
+      memcpy (full_img + decompress_size, core_img, core_size);
+
+      memset (full_img + decompress_size + core_size, 0,
+	      full_size - (decompress_size + core_size));
+
+      free (core_img);
+      core_img = full_img;
+      core_size = full_size;
+    }
+
+  switch (image_target->id)
+    {
+    case IMAGE_I386_PC:
+    case IMAGE_I386_PC_PXE:
+	if (GRUB_KERNEL_I386_PC_LINK_ADDR + core_size > 0x78000
+	    || (core_size > (0xffff << GRUB_DISK_SECTOR_BITS))
+	    || (kernel_size + bss_size + GRUB_KERNEL_I386_PC_LINK_ADDR > 0x68000))
+	  grub_util_error (_("core image is too big (0x%x > 0x%x)"),
+			   GRUB_KERNEL_I386_PC_LINK_ADDR + (unsigned) core_size,
+			   0x78000);
+	/* fallthrough */
+    case IMAGE_COREBOOT:
+    case IMAGE_QEMU:
+	if (kernel_size + bss_size + GRUB_KERNEL_I386_PC_LINK_ADDR > 0x68000)
+	  grub_util_error (_("kernel image is too big (0x%x > 0x%x)"),
+			   (unsigned) kernel_size + (unsigned) bss_size
+			   + GRUB_KERNEL_I386_PC_LINK_ADDR,
+			   0x68000);
+	break;
+    case IMAGE_LOONGSON_ELF:
+    case IMAGE_YEELOONG_FLASH:
+    case IMAGE_FULOONG2F_FLASH:
+    case IMAGE_EFI:
+    case IMAGE_MIPS_ARC:
+    case IMAGE_QEMU_MIPS_FLASH:
+      break;
+    case IMAGE_SPARC64_AOUT:
+    case IMAGE_SPARC64_RAW:
+    case IMAGE_SPARC64_CDCORE:
+    case IMAGE_I386_IEEE1275:
+    case IMAGE_PPC:
+    case IMAGE_UBOOT:
+      break;
+    }
+
+  switch (image_target->id)
+    {
+    case IMAGE_I386_PC:
+    case IMAGE_I386_PC_PXE:
+      {
+	unsigned num;
+	char *boot_path, *boot_img;
+	size_t boot_size;
+
+	num = ((core_size + GRUB_DISK_SECTOR_SIZE - 1) >> GRUB_DISK_SECTOR_BITS);
+	if (image_target->id == IMAGE_I386_PC_PXE)
+	  {
+	    char *pxeboot_path, *pxeboot_img;
+	    size_t pxeboot_size;
+	    grub_uint32_t *ptr;
+	    
+	    pxeboot_path = grub_util_get_path (dir, "pxeboot.img");
+	    pxeboot_size = grub_util_get_image_size (pxeboot_path);
+	    pxeboot_img = grub_util_read_image (pxeboot_path);
+	    
+	    grub_util_write_image (pxeboot_img, pxeboot_size, out,
+				   outname);
+	    free (pxeboot_img);
+	    free (pxeboot_path);
+
+	    /* Remove Multiboot header to avoid confusing ipxe.  */
+	    for (ptr = (grub_uint32_t *) core_img;
+		 ptr < (grub_uint32_t *) (core_img + MULTIBOOT_SEARCH); ptr++)
+	      if (*ptr == grub_host_to_target32 (MULTIBOOT_HEADER_MAGIC)
+		  && grub_target_to_host32 (ptr[0])
+		  + grub_target_to_host32 (ptr[1])
+		  + grub_target_to_host32 (ptr[2]) == 0)
+		{
+		  *ptr = 0;
+		  break;
+		}
+	  }
+
+	boot_path = grub_util_get_path (dir, "diskboot.img");
+	boot_size = grub_util_get_image_size (boot_path);
+	if (boot_size != GRUB_DISK_SECTOR_SIZE)
+	  grub_util_error (_("diskboot.img size must be %u bytes"),
+			   GRUB_DISK_SECTOR_SIZE);
+
+	boot_img = grub_util_read_image (boot_path);
+
+	{
+	  struct grub_pc_bios_boot_blocklist *block;
+	  block = (struct grub_pc_bios_boot_blocklist *) (boot_img
+							  + GRUB_DISK_SECTOR_SIZE
+							  - sizeof (*block));
+	  block->len = grub_host_to_target16 (num);
+
+	  /* This is filled elsewhere.  Verify it just in case.  */
+	  assert (block->segment
+		  == grub_host_to_target16 (GRUB_BOOT_I386_PC_KERNEL_SEG
+					    + (GRUB_DISK_SECTOR_SIZE >> 4)));
+	}
+
+	grub_util_write_image (boot_img, boot_size, out, outname);
+	free (boot_img);
+	free (boot_path);
+      }
+      break;
+    case IMAGE_EFI:
+      {
+	void *pe_img;
+	grub_uint8_t *header;
+	void *sections;
+	size_t pe_size;
+	struct grub_pe32_coff_header *c;
+	struct grub_pe32_section_table *text_section, *data_section;
+	struct grub_pe32_section_table *mods_section, *reloc_section;
+	static const grub_uint8_t stub[] = GRUB_PE32_MSDOS_STUB;
+	int header_size;
+	int reloc_addr;
+
+	if (image_target->voidp_sizeof == 4)
+	  header_size = EFI32_HEADER_SIZE;
+	else
+	  header_size = EFI64_HEADER_SIZE;
+
+	reloc_addr = ALIGN_UP (header_size + core_size,
+			       image_target->section_align);
+
+	pe_size = ALIGN_UP (reloc_addr + reloc_size,
+			    image_target->section_align);
+	pe_img = xmalloc (reloc_addr + reloc_size);
+	memset (pe_img, 0, header_size);
+	memcpy ((char *) pe_img + header_size, core_img, core_size);
+	memcpy ((char *) pe_img + reloc_addr, rel_section, reloc_size);
+	header = pe_img;
+
+	/* The magic.  */
+	memcpy (header, stub, GRUB_PE32_MSDOS_STUB_SIZE);
+	memcpy (header + GRUB_PE32_MSDOS_STUB_SIZE, "PE\0\0",
+		GRUB_PE32_SIGNATURE_SIZE);
+
+	/* The COFF file header.  */
+	c = (struct grub_pe32_coff_header *) (header + GRUB_PE32_MSDOS_STUB_SIZE
+					      + GRUB_PE32_SIGNATURE_SIZE);
+	c->machine = grub_host_to_target16 (image_target->pe_target);
+
+	c->num_sections = grub_host_to_target16 (4);
+	c->time = grub_host_to_target32 (time (0));
+	c->characteristics = grub_host_to_target16 (GRUB_PE32_EXECUTABLE_IMAGE
+						    | GRUB_PE32_LINE_NUMS_STRIPPED
+						    | ((image_target->voidp_sizeof == 4)
+						       ? GRUB_PE32_32BIT_MACHINE
+						       : 0)
+						    | GRUB_PE32_LOCAL_SYMS_STRIPPED
+						    | GRUB_PE32_DEBUG_STRIPPED);
+
+	/* The PE Optional header.  */
+	if (image_target->voidp_sizeof == 4)
+	  {
+	    struct grub_pe32_optional_header *o;
+
+	    c->optional_header_size = grub_host_to_target16 (sizeof (struct grub_pe32_optional_header));
+
+	    o = (struct grub_pe32_optional_header *)
+	      (header + GRUB_PE32_MSDOS_STUB_SIZE + GRUB_PE32_SIGNATURE_SIZE
+	       + sizeof (struct grub_pe32_coff_header));
+	    o->magic = grub_host_to_target16 (GRUB_PE32_PE32_MAGIC);
+	    o->code_size = grub_host_to_target32 (exec_size);
+	    o->data_size = grub_cpu_to_le32 (reloc_addr - exec_size
+					     - header_size);
+	    o->bss_size = grub_cpu_to_le32 (bss_size);
+	    o->entry_addr = grub_cpu_to_le32 (start_address);
+	    o->code_base = grub_cpu_to_le32 (header_size);
+
+	    o->data_base = grub_host_to_target32 (header_size + exec_size);
+
+	    o->image_base = 0;
+	    o->section_alignment = grub_host_to_target32 (image_target->section_align);
+	    o->file_alignment = grub_host_to_target32 (image_target->section_align);
+	    o->image_size = grub_host_to_target32 (pe_size);
+	    o->header_size = grub_host_to_target32 (header_size);
+	    o->subsystem = grub_host_to_target16 (GRUB_PE32_SUBSYSTEM_EFI_APPLICATION);
+
+	    /* Do these really matter? */
+	    o->stack_reserve_size = grub_host_to_target32 (0x10000);
+	    o->stack_commit_size = grub_host_to_target32 (0x10000);
+	    o->heap_reserve_size = grub_host_to_target32 (0x10000);
+	    o->heap_commit_size = grub_host_to_target32 (0x10000);
+    
+	    o->num_data_directories = grub_host_to_target32 (GRUB_PE32_NUM_DATA_DIRECTORIES);
+
+	    o->base_relocation_table.rva = grub_host_to_target32 (reloc_addr);
+	    o->base_relocation_table.size = grub_host_to_target32 (reloc_size);
+	    sections = o + 1;
+	  }
+	else
+	  {
+	    struct grub_pe64_optional_header *o;
+
+	    c->optional_header_size = grub_host_to_target16 (sizeof (struct grub_pe64_optional_header));
+
+	    o = (struct grub_pe64_optional_header *) 
+	      (header + GRUB_PE32_MSDOS_STUB_SIZE + GRUB_PE32_SIGNATURE_SIZE
+	       + sizeof (struct grub_pe32_coff_header));
+	    o->magic = grub_host_to_target16 (GRUB_PE32_PE64_MAGIC);
+	    o->code_size = grub_host_to_target32 (exec_size);
+	    o->data_size = grub_cpu_to_le32 (reloc_addr - exec_size
+					     - header_size);
+	    o->bss_size = grub_cpu_to_le32 (bss_size);
+	    o->entry_addr = grub_cpu_to_le32 (start_address);
+	    o->code_base = grub_cpu_to_le32 (header_size);
+	    o->image_base = 0;
+	    o->section_alignment = grub_host_to_target32 (image_target->section_align);
+	    o->file_alignment = grub_host_to_target32 (image_target->section_align);
+	    o->image_size = grub_host_to_target32 (pe_size);
+	    o->header_size = grub_host_to_target32 (header_size);
+	    o->subsystem = grub_host_to_target16 (GRUB_PE32_SUBSYSTEM_EFI_APPLICATION);
+
+	    /* Do these really matter? */
+	    o->stack_reserve_size = grub_host_to_target64 (0x10000);
+	    o->stack_commit_size = grub_host_to_target64 (0x10000);
+	    o->heap_reserve_size = grub_host_to_target64 (0x10000);
+	    o->heap_commit_size = grub_host_to_target64 (0x10000);
+    
+	    o->num_data_directories
+	      = grub_host_to_target32 (GRUB_PE32_NUM_DATA_DIRECTORIES);
+
+	    o->base_relocation_table.rva = grub_host_to_target32 (reloc_addr);
+	    o->base_relocation_table.size = grub_host_to_target32 (reloc_size);
+	    sections = o + 1;
+	  }
+	/* The sections.  */
+	text_section = sections;
+	strcpy (text_section->name, ".text");
+	text_section->virtual_size = grub_cpu_to_le32 (exec_size);
+	text_section->virtual_address = grub_cpu_to_le32 (header_size);
+	text_section->raw_data_size = grub_cpu_to_le32 (exec_size);
+	text_section->raw_data_offset = grub_cpu_to_le32 (header_size);
+	text_section->characteristics = grub_cpu_to_le32 (GRUB_PE32_SCN_CNT_CODE
+							  | GRUB_PE32_SCN_MEM_EXECUTE
+							  | GRUB_PE32_SCN_MEM_READ);
+
+	data_section = text_section + 1;
+	strcpy (data_section->name, ".data");
+	data_section->virtual_size = grub_cpu_to_le32 (kernel_size - exec_size);
+	data_section->virtual_address = grub_cpu_to_le32 (header_size + exec_size);
+	data_section->raw_data_size = grub_cpu_to_le32 (kernel_size - exec_size);
+	data_section->raw_data_offset = grub_cpu_to_le32 (header_size + exec_size);
+	data_section->characteristics
+	  = grub_cpu_to_le32 (GRUB_PE32_SCN_CNT_INITIALIZED_DATA
+			      | GRUB_PE32_SCN_MEM_READ
+			      | GRUB_PE32_SCN_MEM_WRITE);
+
+#if 0
+	bss_section = data_section + 1;
+	strcpy (bss_section->name, ".bss");
+	bss_section->virtual_size = grub_cpu_to_le32 (bss_size);
+	bss_section->virtual_address = grub_cpu_to_le32 (header_size + kernel_size);
+	bss_section->raw_data_size = 0;
+	bss_section->raw_data_offset = 0;
+	bss_section->characteristics
+	  = grub_cpu_to_le32 (GRUB_PE32_SCN_MEM_READ
+			      | GRUB_PE32_SCN_MEM_WRITE
+			      | GRUB_PE32_SCN_ALIGN_64BYTES
+			      | GRUB_PE32_SCN_CNT_INITIALIZED_DATA
+			      | 0x80);
+#endif
+    
+	mods_section = data_section + 1;
+	strcpy (mods_section->name, "mods");
+	mods_section->virtual_size = grub_cpu_to_le32 (reloc_addr - kernel_size - header_size);
+	mods_section->virtual_address = grub_cpu_to_le32 (header_size + kernel_size + bss_size);
+	mods_section->raw_data_size = grub_cpu_to_le32 (reloc_addr - kernel_size - header_size);
+	mods_section->raw_data_offset = grub_cpu_to_le32 (header_size + kernel_size);
+	mods_section->characteristics
+	  = grub_cpu_to_le32 (GRUB_PE32_SCN_CNT_INITIALIZED_DATA
+			      | GRUB_PE32_SCN_MEM_READ
+			      | GRUB_PE32_SCN_MEM_WRITE);
+
+	reloc_section = mods_section + 1;
+	strcpy (reloc_section->name, ".reloc");
+	reloc_section->virtual_size = grub_cpu_to_le32 (reloc_size);
+	reloc_section->virtual_address = grub_cpu_to_le32 (reloc_addr + bss_size);
+	reloc_section->raw_data_size = grub_cpu_to_le32 (reloc_size);
+	reloc_section->raw_data_offset = grub_cpu_to_le32 (reloc_addr);
+	reloc_section->characteristics
+	  = grub_cpu_to_le32 (GRUB_PE32_SCN_CNT_INITIALIZED_DATA
+			      | GRUB_PE32_SCN_MEM_DISCARDABLE
+			      | GRUB_PE32_SCN_MEM_READ);
+	free (core_img);
+	core_img = pe_img;
+	core_size = pe_size;
+      }
+      break;
+    case IMAGE_QEMU:
+      {
+	char *rom_img;
+	size_t rom_size;
+	char *boot_path, *boot_img;
+	size_t boot_size;
+
+	boot_path = grub_util_get_path (dir, "boot.img");
+	boot_size = grub_util_get_image_size (boot_path);
+	boot_img = grub_util_read_image (boot_path);
+
+	/* Rom sizes must be 64k-aligned.  */
+	rom_size = ALIGN_UP (core_size + boot_size, 64 * 1024);
+
+	rom_img = xmalloc (rom_size);
+	memset (rom_img, 0, rom_size);
+
+	*((grub_int32_t *) (core_img + GRUB_KERNEL_I386_QEMU_CORE_ENTRY_ADDR))
+	  = grub_host_to_target32 ((grub_uint32_t) -rom_size);
+
+	memcpy (rom_img, core_img, core_size);
+
+	*((grub_int32_t *) (boot_img + GRUB_BOOT_I386_QEMU_CORE_ENTRY_ADDR))
+	  = grub_host_to_target32 ((grub_uint32_t) -rom_size);
+
+	memcpy (rom_img + rom_size - boot_size, boot_img, boot_size);
+
+	free (core_img);
+	core_img = rom_img;
+	core_size = rom_size;
+
+	free (boot_img);
+	free (boot_path);
+      }
+      break;
+    case IMAGE_SPARC64_AOUT:
+      {
+	void *aout_img;
+	size_t aout_size;
+	struct grub_aout32_header *aout_head;
+
+	aout_size = core_size + sizeof (*aout_head);
+	aout_img = xmalloc (aout_size);
+	aout_head = aout_img;
+	grub_memset (aout_head, 0, sizeof (*aout_head));
+	aout_head->a_midmag = grub_host_to_target32 ((AOUT_MID_SUN << 16)
+						     | AOUT32_OMAGIC);
+	aout_head->a_text = grub_host_to_target32 (core_size);
+	aout_head->a_entry
+	  = grub_host_to_target32 (GRUB_BOOT_SPARC64_IEEE1275_IMAGE_ADDRESS);
+	memcpy ((char *) aout_img + sizeof (*aout_head), core_img, core_size);
+
+	free (core_img);
+	core_img = aout_img;
+	core_size = aout_size;
+      }
+      break;
+    case IMAGE_SPARC64_RAW:
+      {
+	unsigned int num;
+	char *boot_path, *boot_img;
+	size_t boot_size;
+
+	num = ((core_size + GRUB_DISK_SECTOR_SIZE - 1) >> GRUB_DISK_SECTOR_BITS);
+	num <<= GRUB_DISK_SECTOR_BITS;
+
+	boot_path = grub_util_get_path (dir, "diskboot.img");
+	boot_size = grub_util_get_image_size (boot_path);
+	if (boot_size != GRUB_DISK_SECTOR_SIZE)
+	  grub_util_error (_("diskboot.img size must be %u bytes"),
+			   GRUB_DISK_SECTOR_SIZE);
+
+	boot_img = grub_util_read_image (boot_path);
+
+	*((grub_uint32_t *) (boot_img + GRUB_DISK_SECTOR_SIZE
+			     - GRUB_BOOT_SPARC64_IEEE1275_LIST_SIZE + 8))
+	  = grub_host_to_target32 (num);
+
+	grub_util_write_image (boot_img, boot_size, out, outname);
+	free (boot_img);
+	free (boot_path);
+      }
+      break;
+    case IMAGE_SPARC64_CDCORE:
+      break;
+    case IMAGE_YEELOONG_FLASH:
+    case IMAGE_FULOONG2F_FLASH:
+    {
+      char *rom_img;
+      size_t rom_size;
+      char *boot_path, *boot_img;
+      size_t boot_size;
+      grub_uint8_t context[GRUB_MD_SHA512->contextsize];
+      /* fwstart.img is the only part which can't be tested by using *-elf
+	 target. Check it against the checksum. */
+      const grub_uint8_t yeeloong_fwstart_good_hash[512 / 8] = 
+	{
+	  0x5f, 0x67, 0x46, 0x57, 0x31, 0x30, 0xc5, 0x0a,
+	  0xe9, 0x98, 0x18, 0xc9, 0xf3, 0xca, 0x45, 0xa5,
+	  0x75, 0x64, 0x6b, 0xbb, 0x24, 0xcd, 0xb4, 0xbc,
+	  0xf2, 0x3e, 0x23, 0xf9, 0xc2, 0x6a, 0x8c, 0xde,
+	  0x3b, 0x94, 0x9c, 0xcc, 0xa5, 0xa7, 0x58, 0xb1,
+	  0xbe, 0x8b, 0x3d, 0x73, 0x98, 0x18, 0x7e, 0x68,
+	  0x5e, 0x5f, 0x23, 0x7d, 0x7a, 0xe8, 0x51, 0xf7,
+	  0x1a, 0xaf, 0x2f, 0x54, 0x11, 0x2e, 0x5c, 0x25
+	};
+      const grub_uint8_t fuloong2f_fwstart_good_hash[512 / 8] = 
+	{ 
+	  0x76, 0x9b, 0xad, 0x6e, 0xa2, 0x39, 0x47, 0x62,
+	  0x1f, 0xc9, 0x3a, 0x6d, 0x05, 0x5c, 0x43, 0x5c,
+	  0x29, 0x4a, 0x7e, 0x08, 0x2a, 0x31, 0x8f, 0x5d,
+	  0x02, 0x84, 0xa0, 0x85, 0xf2, 0xd1, 0xb9, 0x53,
+	  0xa2, 0xbc, 0xf2, 0xe1, 0x39, 0x1e, 0x51, 0xb5,
+	  0xaf, 0xec, 0x9e, 0xf2, 0xf1, 0xf3, 0x0a, 0x2f,
+	  0xe6, 0xf1, 0x08, 0x89, 0xbe, 0xbc, 0x73, 0xab,
+	  0x46, 0x50, 0xd6, 0x21, 0xce, 0x8e, 0x24, 0xa7
+	};
+      const grub_uint8_t *fwstart_good_hash;
+            
+      if (image_target->id == IMAGE_FULOONG2F_FLASH)
+	{
+	  fwstart_good_hash = fuloong2f_fwstart_good_hash;
+	  boot_path = grub_util_get_path (dir, "fwstart_fuloong2f.img");
+	}
+      else
+	{
+	  fwstart_good_hash = yeeloong_fwstart_good_hash;
+	  boot_path = grub_util_get_path (dir, "fwstart.img");
+	}
+
+      boot_size = grub_util_get_image_size (boot_path);
+      boot_img = grub_util_read_image (boot_path);
+
+      grub_memset (context, 0, sizeof (context));
+      GRUB_MD_SHA512->init (context);
+      GRUB_MD_SHA512->write (context, boot_img, boot_size);
+      GRUB_MD_SHA512->final (context);
+      if (grub_memcmp (GRUB_MD_SHA512->read (context), fwstart_good_hash,
+		       GRUB_MD_SHA512->mdlen) != 0)
+	/* TRANSLATORS: fwstart.img may still be good, just it wasn't checked.  */
+	grub_util_warn ("%s",
+			_("fwstart.img doesn't match the known good version. "
+			  "proceed at your own risk"));
+
+      if (core_size + boot_size > 512 * 1024)
+	grub_util_error ("%s", _("firmware image is too big"));
+      rom_size = 512 * 1024;
+
+      rom_img = xmalloc (rom_size);
+      memset (rom_img, 0, rom_size); 
+
+      memcpy (rom_img, boot_img, boot_size);
+
+      memcpy (rom_img + boot_size, core_img, core_size);
+
+      memset (rom_img + boot_size + core_size, 0,
+	      rom_size - (boot_size + core_size));
+
+      free (core_img);
+      core_img = rom_img;
+      core_size = rom_size;
+    }
+    break;
+    case IMAGE_QEMU_MIPS_FLASH:
+    {
+      char *rom_img;
+      size_t rom_size;
+
+      if (core_size > 512 * 1024)
+	grub_util_error ("%s", _("firmware image is too big"));
+      rom_size = 512 * 1024;
+
+      rom_img = xmalloc (rom_size);
+      memset (rom_img, 0, rom_size); 
+
+      memcpy (rom_img, core_img, core_size);
+
+      memset (rom_img + core_size, 0,
+	      rom_size - core_size);
+
+      free (core_img);
+      core_img = rom_img;
+      core_size = rom_size;
+    }
+    break;
+
+    case IMAGE_UBOOT:
+    {
+      struct grub_uboot_image_header *hdr;
+      GRUB_PROPERLY_ALIGNED_ARRAY (crc32_context, GRUB_MD_CRC32->contextsize);
+
+      hdr = xmalloc (core_size + sizeof (struct grub_uboot_image_header));
+      memcpy (hdr + 1, core_img, core_size);
+
+      memset (hdr, 0, sizeof (*hdr));
+      hdr->ih_magic = grub_cpu_to_be32_compile_time (GRUB_UBOOT_IH_MAGIC);
+      hdr->ih_time = grub_cpu_to_be32 (time (0));
+      hdr->ih_size = grub_cpu_to_be32 (core_size);
+      hdr->ih_load = grub_cpu_to_be32 (image_target->link_addr);
+      hdr->ih_ep = grub_cpu_to_be32 (image_target->link_addr);
+      hdr->ih_type = GRUB_UBOOT_IH_TYPE_KERNEL;
+      hdr->ih_os = GRUB_UBOOT_IH_OS_LINUX;
+      hdr->ih_arch = GRUB_UBOOT_IH_ARCH_ARM;
+      hdr->ih_comp = GRUB_UBOOT_IH_COMP_NONE;
+
+      GRUB_MD_CRC32->init(crc32_context);
+      GRUB_MD_CRC32->write(crc32_context, hdr + 1, core_size);
+      GRUB_MD_CRC32->final(crc32_context);
+      hdr->ih_dcrc = grub_get_unaligned32 (GRUB_MD_CRC32->read (crc32_context));
+
+      GRUB_MD_CRC32->init(crc32_context);
+      GRUB_MD_CRC32->write(crc32_context, hdr, sizeof (*hdr));
+      GRUB_MD_CRC32->final(crc32_context);
+      hdr->ih_hcrc = grub_get_unaligned32 (GRUB_MD_CRC32->read (crc32_context));
+
+      free (core_img);
+      core_img = (char *) hdr;
+      core_size += sizeof (struct grub_uboot_image_header);
+    }
+    break;
+
+    case IMAGE_MIPS_ARC:
+      {
+	char *ecoff_img;
+	struct ecoff_header {
+	  grub_uint16_t magic;
+	  grub_uint16_t nsec;
+	  grub_uint32_t time;
+	  grub_uint32_t syms;
+	  grub_uint32_t nsyms;
+	  grub_uint16_t opt;
+	  grub_uint16_t flags;
+	  grub_uint16_t magic2;
+	  grub_uint16_t version;
+	  grub_uint32_t textsize;
+	  grub_uint32_t datasize;
+	  grub_uint32_t bsssize;
+	  grub_uint32_t entry;
+	  grub_uint32_t text_start;
+	  grub_uint32_t data_start;
+	  grub_uint32_t bss_start;
+	  grub_uint32_t gprmask;
+	  grub_uint32_t cprmask[4];
+	  grub_uint32_t gp_value;
+	};
+	struct ecoff_section
+	{
+	  char name[8];
+	  grub_uint32_t paddr;
+	  grub_uint32_t vaddr;
+	  grub_uint32_t size;
+	  grub_uint32_t file_offset;
+	  grub_uint32_t reloc;
+	  grub_uint32_t gp;
+	  grub_uint16_t nreloc;
+	  grub_uint16_t ngp;
+	  grub_uint32_t flags;
+	};
+	struct ecoff_header *head;
+	struct ecoff_section *section;
+	grub_uint32_t target_addr;
+	size_t program_size;
+
+	program_size = ALIGN_ADDR (core_size);
+	if (comp == GRUB_COMPRESSION_NONE)
+	  target_addr = (image_target->link_addr - decompress_size);
+	else
+	  target_addr = ALIGN_UP (image_target->link_addr
+				  + kernel_size + total_module_size, 32);
+
+	ecoff_img = xmalloc (program_size + sizeof (*head) + sizeof (*section));
+	grub_memset (ecoff_img, 0, program_size + sizeof (*head) + sizeof (*section));
+	head = (void *) ecoff_img;
+	section = (void *) (head + 1);
+	head->magic = image_target->bigendian ? grub_host_to_target16 (0x160)
+	  : grub_host_to_target16 (0x166);
+	head->nsec = grub_host_to_target16 (1);
+	head->time = grub_host_to_target32 (0);
+	head->opt = grub_host_to_target16 (0x38);
+	head->flags = image_target->bigendian
+	  ? grub_host_to_target16 (0x207)
+	  : grub_host_to_target16 (0x103);
+	head->magic2 = grub_host_to_target16 (0x107);
+	head->textsize = grub_host_to_target32 (program_size);
+	head->entry = grub_host_to_target32 (target_addr);
+	head->text_start = grub_host_to_target32 (target_addr);
+	head->data_start = grub_host_to_target32 (target_addr + program_size);
+	grub_memcpy (section->name, ".text", sizeof (".text") - 1); 
+	section->vaddr = grub_host_to_target32 (target_addr);
+	section->size = grub_host_to_target32 (program_size);
+	section->file_offset = grub_host_to_target32 (sizeof (*head) + sizeof (*section));
+	if (!image_target->bigendian)
+	  {
+	    section->paddr = grub_host_to_target32 (0xaa60);
+	    section->flags = grub_host_to_target32 (0x20);
+	  }
+	memcpy (section + 1, core_img, core_size);
+	free (core_img);
+	core_img = ecoff_img;
+	core_size = program_size + sizeof (*head) + sizeof (*section);
+      }
+      break;
+    case IMAGE_LOONGSON_ELF:
+    case IMAGE_PPC:
+    case IMAGE_COREBOOT:
+    case IMAGE_I386_IEEE1275:
+      {
+	char *elf_img;
+	size_t program_size;
+	Elf32_Ehdr *ehdr;
+	Elf32_Phdr *phdr;
+	grub_uint32_t target_addr;
+	int header_size, footer_size = 0;
+	int phnum = 1;
+	
+	if (image_target->id != IMAGE_LOONGSON_ELF)
+	  phnum += 2;
+
+	if (note)
+	  {
+	    phnum++;
+	    footer_size += sizeof (struct grub_ieee1275_note);
+	  }
+	header_size = ALIGN_ADDR (sizeof (*ehdr) + phnum * sizeof (*phdr));
+
+	program_size = ALIGN_ADDR (core_size);
+
+	elf_img = xmalloc (program_size + header_size + footer_size);
+	memset (elf_img, 0, program_size + header_size);
+	memcpy (elf_img  + header_size, core_img, core_size);
+	ehdr = (void *) elf_img;
+	phdr = (void *) (elf_img + sizeof (*ehdr));
+	memcpy (ehdr->e_ident, ELFMAG, SELFMAG);
+	ehdr->e_ident[EI_CLASS] = ELFCLASS32;
+	if (!image_target->bigendian)
+	  ehdr->e_ident[EI_DATA] = ELFDATA2LSB;
+	else
+	  ehdr->e_ident[EI_DATA] = ELFDATA2MSB;
+	ehdr->e_ident[EI_VERSION] = EV_CURRENT;
+	ehdr->e_ident[EI_OSABI] = ELFOSABI_NONE;
+	ehdr->e_type = grub_host_to_target16 (ET_EXEC);
+	ehdr->e_machine = grub_host_to_target16 (image_target->elf_target);
+	ehdr->e_version = grub_host_to_target32 (EV_CURRENT);
+
+	ehdr->e_phoff = grub_host_to_target32 ((char *) phdr - (char *) ehdr);
+	ehdr->e_phentsize = grub_host_to_target16 (sizeof (*phdr));
+	ehdr->e_phnum = grub_host_to_target16 (phnum);
+
+	/* No section headers.  */
+	ehdr->e_shoff = grub_host_to_target32 (0);
+	if (image_target->id == IMAGE_LOONGSON_ELF)
+	  ehdr->e_shentsize = grub_host_to_target16 (0);
+	else
+	  ehdr->e_shentsize = grub_host_to_target16 (sizeof (Elf32_Shdr));
+	ehdr->e_shnum = grub_host_to_target16 (0);
+	ehdr->e_shstrndx = grub_host_to_target16 (0);
+
+	ehdr->e_ehsize = grub_host_to_target16 (sizeof (*ehdr));
+
+	phdr->p_type = grub_host_to_target32 (PT_LOAD);
+	phdr->p_offset = grub_host_to_target32 (header_size);
+	phdr->p_flags = grub_host_to_target32 (PF_R | PF_W | PF_X);
+
+	if (image_target->id == IMAGE_LOONGSON_ELF)
+	  {
+	    if (comp == GRUB_COMPRESSION_NONE)
+	      target_addr = (image_target->link_addr - decompress_size);
+	    else
+	      target_addr = ALIGN_UP (image_target->link_addr
+				      + kernel_size + total_module_size, 32);
+	  }
+	else
+	  target_addr = image_target->link_addr;
+	ehdr->e_entry = grub_host_to_target32 (target_addr);
+	phdr->p_vaddr = grub_host_to_target32 (target_addr);
+	phdr->p_paddr = grub_host_to_target32 (target_addr);
+	phdr->p_align = grub_host_to_target32 (align > image_target->link_align ? align : image_target->link_align);
+	if (image_target->id == IMAGE_LOONGSON_ELF)
+	  ehdr->e_flags = grub_host_to_target32 (0x1000 | EF_MIPS_NOREORDER 
+						 | EF_MIPS_PIC | EF_MIPS_CPIC);
+	else
+	  ehdr->e_flags = 0;
+	if (image_target->id == IMAGE_LOONGSON_ELF)
+	  {
+	    phdr->p_filesz = grub_host_to_target32 (core_size);
+	    phdr->p_memsz = grub_host_to_target32 (core_size);
+	  }
+	else
+	  {
+	    grub_uint32_t target_addr_mods;
+	    phdr->p_filesz = grub_host_to_target32 (kernel_size);
+	    phdr->p_memsz = grub_host_to_target32 (kernel_size + bss_size);
+
+	    phdr++;
+	    phdr->p_type = grub_host_to_target32 (PT_GNU_STACK);
+	    phdr->p_offset = grub_host_to_target32 (header_size + kernel_size);
+	    phdr->p_paddr = phdr->p_vaddr = phdr->p_filesz = phdr->p_memsz = 0;
+	    phdr->p_flags = grub_host_to_target32 (PF_R | PF_W | PF_X);
+	    phdr->p_align = grub_host_to_target32 (image_target->link_align);
+
+	    phdr++;
+	    phdr->p_type = grub_host_to_target32 (PT_LOAD);
+	    phdr->p_offset = grub_host_to_target32 (header_size + kernel_size);
+	    phdr->p_flags = grub_host_to_target32 (PF_R | PF_W | PF_X);
+	    phdr->p_filesz = phdr->p_memsz
+	      = grub_host_to_target32 (core_size - kernel_size);
+
+	    if (image_target->id == IMAGE_COREBOOT)
+	      target_addr_mods = GRUB_KERNEL_I386_COREBOOT_MODULES_ADDR;
+	    else
+	      target_addr_mods = ALIGN_UP (target_addr + kernel_size + bss_size
+					   + image_target->mod_gap,
+					   image_target->mod_align);
+	    phdr->p_vaddr = grub_host_to_target32 (target_addr_mods);
+	    phdr->p_paddr = grub_host_to_target32 (target_addr_mods);
+	    phdr->p_align = grub_host_to_target32 (image_target->link_align);
+	  }
+
+	if (note)
+	  {
+	    int note_size = sizeof (struct grub_ieee1275_note);
+	    struct grub_ieee1275_note *note_ptr = (struct grub_ieee1275_note *) 
+	      (elf_img + program_size + header_size);
+
+	    grub_util_info ("adding CHRP NOTE segment");
+
+	    note_ptr->header.namesz = grub_host_to_target32 (sizeof (GRUB_IEEE1275_NOTE_NAME));
+	    note_ptr->header.descsz = grub_host_to_target32 (note_size);
+	    note_ptr->header.type = grub_host_to_target32 (GRUB_IEEE1275_NOTE_TYPE);
+	    strcpy (note_ptr->header.name, GRUB_IEEE1275_NOTE_NAME);
+	    note_ptr->descriptor.real_mode = grub_host_to_target32 (0xffffffff);
+	    note_ptr->descriptor.real_base = grub_host_to_target32 (0x00c00000);
+	    note_ptr->descriptor.real_size = grub_host_to_target32 (0xffffffff);
+	    note_ptr->descriptor.virt_base = grub_host_to_target32 (0xffffffff);
+	    note_ptr->descriptor.virt_size = grub_host_to_target32 (0xffffffff);
+	    note_ptr->descriptor.load_base = grub_host_to_target32 (0x00004000);
+
+	    phdr++;
+	    phdr->p_type = grub_host_to_target32 (PT_NOTE);
+	    phdr->p_flags = grub_host_to_target32 (PF_R);
+	    phdr->p_align = grub_host_to_target32 (image_target->voidp_sizeof);
+	    phdr->p_vaddr = 0;
+	    phdr->p_paddr = 0;
+	    phdr->p_filesz = grub_host_to_target32 (note_size);
+	    phdr->p_memsz = 0;
+	    phdr->p_offset = grub_host_to_target32 (header_size + program_size);
+	  }
+
+	free (core_img);
+	core_img = elf_img;
+	core_size = program_size + header_size + footer_size;
+      }
+      break;
+    }
+
+  grub_util_write_image (core_img, core_size, out, outname);
+  free (core_img);
+  free (kernel_path);
+
+  while (path_list)
+    {
+      next = path_list->next;
+      free ((void *) path_list->name);
+      free (path_list);
+      path_list = next;
+    }
+}
+
+\f

=== added file 'util/setup.c'
--- util/setup.c	1970-01-01 00:00:00 +0000
+++ util/setup.c	2013-10-04 02:06:06 +0000
@@ -0,0 +1,987 @@
+/* grub-setup.c - make GRUB usable */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010,2011  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 <config.h>
+#include <grub/types.h>
+#include <grub/emu/misc.h>
+#include <grub/util/misc.h>
+#include <grub/device.h>
+#include <grub/disk.h>
+#include <grub/file.h>
+#include <grub/fs.h>
+#include <grub/partition.h>
+#include <grub/env.h>
+#include <grub/emu/hostdisk.h>
+#include <grub/term.h>
+#include <grub/i18n.h>
+#include <grub/util/lvm.h>
+#ifdef GRUB_SETUP_SPARC64
+#include <grub/util/ofpath.h>
+#include <grub/sparc64/ieee1275/boot.h>
+#include <grub/sparc64/ieee1275/kernel.h>
+#else
+#include <grub/i386/pc/boot.h>
+#include <grub/i386/pc/kernel.h>
+#endif
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <assert.h>
+#include <grub/emu/getroot.h>
+#include "progname.h"
+#include <grub/reed_solomon.h>
+#include <grub/msdos_partition.h>
+#include <include/grub/crypto.h>
+#include <grub/util/install.h>
+
+#ifdef __linux__
+#include <sys/ioctl.h>
+#include <linux/fs.h>
+#include <linux/fiemap.h>
+#endif
+
+#include <errno.h>
+
+/* On SPARC this program fills in various fields inside of the 'boot' and 'core'
+ * image files.
+ *
+ * The 'boot' image needs to know the OBP path name of the root
+ * device.  It also needs to know the initial block number of
+ * 'core' (which is 'diskboot' concatenated with 'kernel' and
+ * all the modules, this is created by grub-mkimage).  This resulting
+ * 'boot' image is 512 bytes in size and is placed in the second block
+ * of a partition.
+ *
+ * The initial 'diskboot' block acts as a loader for the actual GRUB
+ * kernel.  It contains the loading code and then a block list.
+ *
+ * The block list of 'core' starts at the end of the 'diskboot' image
+ * and works it's way backwards towards the end of the code of 'diskboot'.
+ *
+ * We patch up the images with the necessary values and write out the
+ * result.
+ */
+
+#define DEFAULT_CORE_FILE	"core.img"
+#define DEFAULT_BOOT_FILE	"boot.img"
+
+#ifdef GRUB_SETUP_SPARC64
+#define grub_target_to_host16(x)	grub_be_to_cpu16(x)
+#define grub_target_to_host32(x)	grub_be_to_cpu32(x)
+#define grub_target_to_host64(x)	grub_be_to_cpu64(x)
+#define grub_host_to_target16(x)	grub_cpu_to_be16(x)
+#define grub_host_to_target32(x)	grub_cpu_to_be32(x)
+#define grub_host_to_target64(x)	grub_cpu_to_be64(x)
+#elif defined (GRUB_SETUP_BIOS)
+#define grub_target_to_host16(x)	grub_le_to_cpu16(x)
+#define grub_target_to_host32(x)	grub_le_to_cpu32(x)
+#define grub_target_to_host64(x)	grub_le_to_cpu64(x)
+#define grub_host_to_target16(x)	grub_cpu_to_le16(x)
+#define grub_host_to_target32(x)	grub_cpu_to_le32(x)
+#define grub_host_to_target64(x)	grub_cpu_to_le64(x)
+#else
+#error Complete this
+#endif
+
+static void
+write_rootdev (grub_device_t root_dev,
+	       char *boot_img, grub_uint64_t first_sector)
+{
+#ifdef GRUB_SETUP_BIOS
+  {
+    grub_uint8_t *boot_drive;
+    void *kernel_sector;
+    boot_drive = (grub_uint8_t *) (boot_img + GRUB_BOOT_MACHINE_BOOT_DRIVE);
+    kernel_sector = (boot_img + GRUB_BOOT_MACHINE_KERNEL_SECTOR);
+
+    /* FIXME: can this be skipped?  */
+    *boot_drive = 0xFF;
+
+    grub_set_unaligned64 (kernel_sector, grub_cpu_to_le64 (first_sector));
+  }
+#endif
+#ifdef GRUB_SETUP_SPARC64
+  {
+    void *kernel_byte;
+    kernel_byte = (boot_img + GRUB_BOOT_AOUT_HEADER_SIZE
+		   + GRUB_BOOT_MACHINE_KERNEL_BYTE);
+    grub_set_unaligned64 (kernel_byte,
+			  grub_cpu_to_be64 (first_sector << GRUB_DISK_SECTOR_BITS));
+  }
+#endif
+}
+
+#ifdef GRUB_SETUP_SPARC64
+#define BOOT_SECTOR 1
+#else
+#define BOOT_SECTOR 0
+#endif
+
+/* Helper for setup.  */
+static void
+save_first_sector (grub_disk_addr_t sector, unsigned offset, unsigned length,
+		   void *data)
+{
+  grub_disk_addr_t *first_sector = data;
+  grub_util_info ("the first sector is <%" PRIuGRUB_UINT64_T ",%u,%u>",
+		  sector, offset, length);
+
+  if (offset != 0 || length != GRUB_DISK_SECTOR_SIZE)
+    grub_util_error ("%s", _("the first sector of the core file is not sector-aligned"));
+
+  *first_sector = sector;
+}
+
+struct blocklists
+{
+  struct grub_boot_blocklist *first_block, *block;
+#ifdef GRUB_SETUP_BIOS
+  grub_uint16_t current_segment;
+#endif
+  grub_uint16_t last_length;
+};
+
+/* Helper for setup.  */
+static void
+save_blocklists (grub_disk_addr_t sector, unsigned offset, unsigned length,
+		 void *data)
+{
+  struct blocklists *bl = data;
+  struct grub_boot_blocklist *prev = bl->block + 1;
+
+  grub_util_info ("saving <%" PRIuGRUB_UINT64_T ",%u,%u>",
+		  sector, offset, length);
+
+  if (offset != 0 || bl->last_length != GRUB_DISK_SECTOR_SIZE)
+    grub_util_error ("%s", _("non-sector-aligned data is found in the core file"));
+
+  if (bl->block != bl->first_block
+      && (grub_target_to_host64 (prev->start)
+	  + grub_target_to_host16 (prev->len)) == sector)
+    {
+      grub_uint16_t t = grub_target_to_host16 (prev->len) + 1;
+      prev->len = grub_host_to_target16 (t);
+    }
+  else
+    {
+      bl->block->start = grub_host_to_target64 (sector);
+      bl->block->len = grub_host_to_target16 (1);
+#ifdef GRUB_SETUP_BIOS
+      bl->block->segment = grub_host_to_target16 (bl->current_segment);
+#endif
+
+      bl->block--;
+      if (bl->block->len)
+	grub_util_error ("%s", _("the sectors of the core file are too fragmented"));
+    }
+
+  bl->last_length = length;
+#ifdef GRUB_SETUP_BIOS
+  bl->current_segment += GRUB_DISK_SECTOR_SIZE >> 4;
+#endif
+}
+
+#ifdef GRUB_SETUP_BIOS
+/* Context for setup/identify_partmap.  */
+struct identify_partmap_ctx
+{
+  grub_partition_map_t dest_partmap;
+  grub_partition_t container;
+  int multiple_partmaps;
+};
+
+/* Helper for setup.
+   Unlike root_dev, with dest_dev we're interested in the partition map even
+   if dest_dev itself is a whole disk.  */
+static int
+identify_partmap (grub_disk_t disk __attribute__ ((unused)),
+		  const grub_partition_t p, void *data)
+{
+  struct identify_partmap_ctx *ctx = data;
+
+  if (p->parent != ctx->container)
+    return 0;
+  /* NetBSD and OpenBSD subpartitions have metadata inside a partition,
+     so they are safe to ignore.
+   */
+  if (grub_strcmp (p->partmap->name, "netbsd") == 0
+      || grub_strcmp (p->partmap->name, "openbsd") == 0)
+    return 0;
+  if (ctx->dest_partmap == NULL)
+    {
+      ctx->dest_partmap = p->partmap;
+      return 0;
+    }
+  if (ctx->dest_partmap == p->partmap)
+    return 0;
+  ctx->multiple_partmaps = 1;
+  return 1;
+}
+#endif
+
+#ifdef GRUB_SETUP_BIOS
+#define SETUP grub_bios_setup
+#elif GRUB_SETUP_SPARC64
+#define SETUP grub_sparc_setup
+#else
+#error "Shouldn't happen"
+#endif
+
+void
+SETUP (const char *dir,
+       const char *boot_file, const char *core_file,
+       const char *dest, int force,
+       int fs_probe, int allow_floppy)
+{
+  char *core_path, *core_path_dev, *core_path_dev_full;
+  char *boot_img, *core_img, *boot_path;
+  char *root = 0;
+  size_t boot_size, core_size;
+#ifdef GRUB_SETUP_BIOS
+  grub_uint16_t core_sectors;
+#endif
+  grub_device_t root_dev = 0, dest_dev, core_dev;
+  struct blocklists bl;
+  char *tmp_img;
+  grub_disk_addr_t first_sector = (grub_disk_addr_t)-1;
+  FILE *fp;
+
+  if (!core_file)
+    core_file = DEFAULT_CORE_FILE;
+  if (!boot_file)
+    boot_file = DEFAULT_BOOT_FILE;
+
+#ifdef GRUB_SETUP_BIOS
+  bl.current_segment =
+    GRUB_BOOT_I386_PC_KERNEL_SEG + (GRUB_DISK_SECTOR_SIZE >> 4);
+#endif
+  bl.last_length = GRUB_DISK_SECTOR_SIZE;
+
+  /* Read the boot image by the OS service.  */
+  boot_path = grub_util_get_path (dir, boot_file);
+  boot_size = grub_util_get_image_size (boot_path);
+  if (boot_size != GRUB_DISK_SECTOR_SIZE)
+    grub_util_error (_("the size of `%s' is not %u"),
+		     boot_path, GRUB_DISK_SECTOR_SIZE);
+  boot_img = grub_util_read_image (boot_path);
+
+  core_path = grub_util_get_path (dir, core_file);
+  core_size = grub_util_get_image_size (core_path);
+#ifdef GRUB_SETUP_BIOS
+  core_sectors = ((core_size + GRUB_DISK_SECTOR_SIZE - 1)
+		  >> GRUB_DISK_SECTOR_BITS);
+#endif
+  if (core_size < GRUB_DISK_SECTOR_SIZE)
+    grub_util_error (_("the size of `%s' is too small"), core_path);
+#ifdef GRUB_SETUP_BIOS
+  if (core_size > 0xFFFF * GRUB_DISK_SECTOR_SIZE)
+    grub_util_error (_("the size of `%s' is too large"), core_path);
+#endif
+
+  core_img = grub_util_read_image (core_path);
+
+  /* Have FIRST_BLOCK to point to the first blocklist.  */
+  bl.first_block = (struct grub_boot_blocklist *) (core_img
+						   + GRUB_DISK_SECTOR_SIZE
+						   - sizeof (*bl.block));
+  grub_util_info ("root is `%s', dest is `%s'", root, dest);
+
+  grub_util_info ("Opening dest");
+  dest_dev = grub_device_open (dest);
+  if (! dest_dev)
+    grub_util_error ("%s", grub_errmsg);
+
+  core_dev = dest_dev;
+
+  {
+    char **root_devices = grub_guess_root_devices (dir);
+    char **cur;
+    int found = 0;
+
+    for (cur = root_devices; *cur; cur++)
+      {
+	char *drive;
+	grub_device_t try_dev;
+
+	drive = grub_util_get_grub_dev (*cur);
+	if (!drive)
+	  continue;
+	try_dev = grub_device_open (drive);
+	if (! try_dev)
+	  continue;
+	if (!found && try_dev->disk->id == dest_dev->disk->id
+	    && try_dev->disk->dev->id == dest_dev->disk->dev->id)
+	  {
+	    if (root_dev)
+	      grub_device_close (root_dev);
+	    free (root);
+	    root_dev = try_dev;
+	    root = drive;
+	    found = 1;
+	    continue;
+	  }
+	if (!root_dev)
+	  {
+	    root_dev = try_dev;
+	    root = drive;
+	    continue;
+	  }
+	grub_device_close (try_dev);	
+	free (drive);
+      }
+    if (!root_dev)
+      {
+	grub_util_error ("guessing the root device failed, because of `%s'",
+			 grub_errmsg);
+      }
+    grub_util_info ("guessed root_dev `%s' from "
+		    "dir `%s'", root_dev->disk->name, dir);
+  }
+
+  grub_util_info ("setting the root device to `%s'", root);
+  if (grub_env_set ("root", root) != GRUB_ERR_NONE)
+    grub_util_error ("%s", grub_errmsg);
+
+#ifdef GRUB_SETUP_BIOS
+  /* Read the original sector from the disk.  */
+  tmp_img = xmalloc (GRUB_DISK_SECTOR_SIZE);
+  if (grub_disk_read (dest_dev->disk, 0, 0, GRUB_DISK_SECTOR_SIZE, tmp_img))
+    grub_util_error ("%s", grub_errmsg);
+#endif
+
+#ifdef GRUB_SETUP_BIOS
+  {
+    grub_uint8_t *boot_drive_check;
+    boot_drive_check = (grub_uint8_t *) (boot_img
+					  + GRUB_BOOT_MACHINE_DRIVE_CHECK);
+    /* Copy the possible DOS BPB.  */
+    memcpy (boot_img + GRUB_BOOT_MACHINE_BPB_START,
+	    tmp_img + GRUB_BOOT_MACHINE_BPB_START,
+	    GRUB_BOOT_MACHINE_BPB_END - GRUB_BOOT_MACHINE_BPB_START);
+
+    /* If DEST_DRIVE is a hard disk, enable the workaround, which is
+       for buggy BIOSes which don't pass boot drive correctly. Instead,
+       they pass 0x00 or 0x01 even when booted from 0x80.  */
+    if (!allow_floppy && !grub_util_biosdisk_is_floppy (dest_dev->disk))
+      {
+	/* Replace the jmp (2 bytes) with double nop's.  */
+	boot_drive_check[0] = 0x90;
+	boot_drive_check[1] = 0x90;
+      }
+  }
+#endif
+
+#ifdef GRUB_SETUP_BIOS
+  {
+    struct identify_partmap_ctx ctx = {
+      .dest_partmap = NULL,
+      .container = dest_dev->disk->partition,
+      .multiple_partmaps = 0
+    };
+    int is_ldm;
+    grub_err_t err;
+    grub_disk_addr_t *sectors;
+    int i;
+    grub_fs_t fs;
+    unsigned int nsec, maxsec;
+
+    grub_partition_iterate (dest_dev->disk, identify_partmap, &ctx);
+
+    if (ctx.container
+	&& grub_strcmp (ctx.container->partmap->name, "msdos") == 0
+	&& ctx.dest_partmap
+	&& (ctx.container->msdostype == GRUB_PC_PARTITION_TYPE_NETBSD
+	    || ctx.container->msdostype == GRUB_PC_PARTITION_TYPE_OPENBSD))
+      {
+	grub_util_warn ("%s", _("Attempting to install GRUB to a disk with multiple partition labels or both partition label and filesystem.  This is not supported yet."));
+	goto unable_to_embed;
+      }
+
+    fs = grub_fs_probe (dest_dev);
+    if (!fs)
+      grub_errno = GRUB_ERR_NONE;
+
+    is_ldm = grub_util_is_ldm (dest_dev->disk);
+
+    if (fs_probe)
+      {
+	if (!fs && !ctx.dest_partmap)
+	  grub_util_error (_("unable to identify a filesystem in %s; safety check can't be performed"),
+			   dest_dev->disk->name);
+	if (fs && !fs->reserved_first_sector)
+	  /* TRANSLATORS: Filesystem may reserve the space just GRUB isn't sure about it.  */
+	  grub_util_error (_("%s appears to contain a %s filesystem which isn't known to "
+			     "reserve space for DOS-style boot.  Installing GRUB there could "
+			     "result in FILESYSTEM DESTRUCTION if valuable data is overwritten "
+			     "by grub-setup (--skip-fs-probe disables this "
+			     "check, use at your own risk)"), dest_dev->disk->name, fs->name);
+
+	if (ctx.dest_partmap && strcmp (ctx.dest_partmap->name, "msdos") != 0
+	    && strcmp (ctx.dest_partmap->name, "gpt") != 0
+	    && strcmp (ctx.dest_partmap->name, "bsd") != 0
+	    && strcmp (ctx.dest_partmap->name, "netbsd") != 0
+	    && strcmp (ctx.dest_partmap->name, "openbsd") != 0
+	    && strcmp (ctx.dest_partmap->name, "sunpc") != 0)
+	  /* TRANSLATORS: Partition map may reserve the space just GRUB isn't sure about it.  */
+	  grub_util_error (_("%s appears to contain a %s partition map which isn't known to "
+			     "reserve space for DOS-style boot.  Installing GRUB there could "
+			     "result in FILESYSTEM DESTRUCTION if valuable data is overwritten "
+			     "by grub-setup (--skip-fs-probe disables this "
+			     "check, use at your own risk)"), dest_dev->disk->name, ctx.dest_partmap->name);
+	if (is_ldm && ctx.dest_partmap && strcmp (ctx.dest_partmap->name, "msdos") != 0
+	    && strcmp (ctx.dest_partmap->name, "gpt") != 0)
+	  grub_util_error (_("%s appears to contain a %s partition map and "
+			     "LDM which isn't known to be a safe combination."
+			     "  Installing GRUB there could "
+			     "result in FILESYSTEM DESTRUCTION if valuable data"
+			     " is overwritten "
+			     "by grub-setup (--skip-fs-probe disables this "
+			     "check, use at your own risk)"),
+			   dest_dev->disk->name, ctx.dest_partmap->name);
+
+      }
+
+    /* Copy the partition table.  */
+    if (ctx.dest_partmap ||
+        (!allow_floppy && !grub_util_biosdisk_is_floppy (dest_dev->disk)))
+      memcpy (boot_img + GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC,
+	      tmp_img + GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC,
+	      GRUB_BOOT_MACHINE_PART_END - GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC);
+
+    free (tmp_img);
+    
+    if (! ctx.dest_partmap && ! fs && !is_ldm)
+      {
+	grub_util_warn ("%s", _("Attempting to install GRUB to a partitionless disk or to a partition.  This is a BAD idea."));
+	goto unable_to_embed;
+      }
+    if (ctx.multiple_partmaps || (ctx.dest_partmap && fs) || (is_ldm && fs))
+      {
+	grub_util_warn ("%s", _("Attempting to install GRUB to a disk with multiple partition labels.  This is not supported yet."));
+	goto unable_to_embed;
+      }
+
+    if (ctx.dest_partmap && !ctx.dest_partmap->embed)
+      {
+	grub_util_warn (_("Partition style `%s' doesn't support embedding"),
+			ctx.dest_partmap->name);
+	goto unable_to_embed;
+      }
+
+    if (fs && !fs->embed)
+      {
+	grub_util_warn (_("File system `%s' doesn't support embedding"),
+			fs->name);
+	goto unable_to_embed;
+      }
+
+    nsec = core_sectors;
+
+    maxsec = 2 * core_sectors;
+    if (maxsec > ((0x78000 - GRUB_KERNEL_I386_PC_LINK_ADDR)
+		>> GRUB_DISK_SECTOR_BITS))
+      maxsec = ((0x78000 - GRUB_KERNEL_I386_PC_LINK_ADDR)
+		>> GRUB_DISK_SECTOR_BITS);
+
+    if (is_ldm)
+      err = grub_util_ldm_embed (dest_dev->disk, &nsec, maxsec,
+				 GRUB_EMBED_PCBIOS, &sectors);
+    else if (ctx.dest_partmap)
+      err = ctx.dest_partmap->embed (dest_dev->disk, &nsec, maxsec,
+				     GRUB_EMBED_PCBIOS, &sectors);
+    else
+      err = fs->embed (dest_dev, &nsec, maxsec,
+		       GRUB_EMBED_PCBIOS, &sectors);
+    if (!err && nsec < core_sectors)
+      {
+	err = grub_error (GRUB_ERR_OUT_OF_RANGE,
+			  N_("Your embedding area is unusually small.  "
+			     "core.img won't fit in it."));
+      }
+    
+    if (err)
+      {
+	grub_util_warn ("%s", grub_errmsg);
+	grub_errno = GRUB_ERR_NONE;
+	goto unable_to_embed;
+      }
+
+    assert (nsec <= maxsec);
+
+    /* Clean out the blocklists.  */
+    bl.block = bl.first_block;
+    while (bl.block->len)
+      {
+	grub_memset (bl.block, 0, sizeof (bl.block));
+      
+	bl.block--;
+
+	if ((char *) bl.block <= core_img)
+	  grub_util_error ("%s", _("no terminator in the core image"));
+      }
+
+    save_first_sector (sectors[0] + grub_partition_get_start (ctx.container),
+		       0, GRUB_DISK_SECTOR_SIZE, &first_sector);
+
+    bl.block = bl.first_block;
+    for (i = 1; i < nsec; i++)
+      save_blocklists (sectors[i] + grub_partition_get_start (ctx.container),
+		       0, GRUB_DISK_SECTOR_SIZE, &bl);
+
+    /* Make sure that the last blocklist is a terminator.  */
+    if (bl.block == bl.first_block)
+      bl.block--;
+    bl.block->start = 0;
+    bl.block->len = 0;
+    bl.block->segment = 0;
+
+    write_rootdev (root_dev, boot_img, first_sector);
+
+    core_img = realloc (core_img, nsec * GRUB_DISK_SECTOR_SIZE);
+    bl.first_block = (struct grub_boot_blocklist *) (core_img
+						     + GRUB_DISK_SECTOR_SIZE
+						     - sizeof (*bl.block));
+
+    grub_size_t no_rs_length;
+    grub_set_unaligned32 ((core_img + GRUB_DISK_SECTOR_SIZE
+			   + GRUB_KERNEL_I386_PC_REED_SOLOMON_REDUNDANCY),
+			  grub_host_to_target32 (nsec * GRUB_DISK_SECTOR_SIZE - core_size));
+    no_rs_length = grub_target_to_host16 
+      (grub_get_unaligned16 (core_img
+			     + GRUB_DISK_SECTOR_SIZE
+			     + GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_LENGTH));
+
+    if (no_rs_length == 0xffff)
+      grub_util_error ("%s", _("core.img version mismatch"));
+
+    void *tmp = xmalloc (core_size);
+    grub_memcpy (tmp, core_img, core_size);
+    grub_reed_solomon_add_redundancy (core_img + no_rs_length + GRUB_DISK_SECTOR_SIZE,
+				      core_size - no_rs_length - GRUB_DISK_SECTOR_SIZE,
+				      nsec * GRUB_DISK_SECTOR_SIZE
+				      - core_size);
+    assert (grub_memcmp (tmp, core_img, core_size) == 0);
+    free (tmp);
+
+    /* Write the core image onto the disk.  */
+    for (i = 0; i < nsec; i++)
+      grub_disk_write (dest_dev->disk, sectors[i], 0,
+		       GRUB_DISK_SECTOR_SIZE,
+		       core_img + i * GRUB_DISK_SECTOR_SIZE);
+
+    grub_free (sectors);
+
+    goto finish;
+  }
+
+unable_to_embed:
+#endif
+
+  if (dest_dev->disk->dev->id != root_dev->disk->dev->id)
+    grub_util_error ("%s", _("embedding is not possible, but this is required for "
+			     "RAID and LVM install"));
+
+  {
+    grub_fs_t fs;
+    fs = grub_fs_probe (root_dev);
+    if (!fs)
+      grub_util_error (_("can't determine filesystem on %s"), root);
+
+    if (!fs->blocklist_install)
+      grub_util_error (_("filesystem `%s' doesn't support blocklists"),
+		       fs->name);
+  }
+
+#ifdef GRUB_SETUP_BIOS
+  if (dest_dev->disk->id != root_dev->disk->id
+      || dest_dev->disk->dev->id != root_dev->disk->dev->id)
+    /* TRANSLATORS: cross-disk refers to /boot being on one disk
+       but MBR on another.  */
+    grub_util_error ("%s", _("embedding is not possible, but this is required for "
+			     "cross-disk install"));
+#else
+  core_dev = root_dev;
+#endif
+
+  grub_util_warn ("%s", _("Embedding is not possible.  GRUB can only be installed in this "
+			  "setup by using blocklists.  However, blocklists are UNRELIABLE and "
+			  "their use is discouraged."));
+  if (! force)
+    /* TRANSLATORS: Here GRUB refuses to continue with blocklist install.  */
+    grub_util_error ("%s", _("will not proceed with blocklists"));
+
+  /* The core image must be put on a filesystem unfortunately.  */
+  grub_util_info ("will leave the core image on the filesystem");
+
+  /* Make sure that GRUB reads the identical image as the OS.  */
+  tmp_img = xmalloc (core_size);
+  core_path_dev_full = grub_util_get_path (dir, core_file);
+  core_path_dev = grub_make_system_path_relative_to_its_root (core_path_dev_full);
+  free (core_path_dev_full);
+
+  grub_util_biosdisk_flush (root_dev->disk);
+
+#ifndef __linux__
+
+#define MAX_TRIES	5
+  {
+    int i;
+    for (i = 0; i < MAX_TRIES; i++)
+      {
+	grub_file_t file;
+
+	grub_util_info ((i == 0) ? _("attempting to read the core image `%s' from GRUB")
+			: _("attempting to read the core image `%s' from GRUB again"),
+			core_path_dev);
+
+	grub_disk_cache_invalidate_all ();
+
+	grub_file_filter_disable_compression ();
+	file = grub_file_open (core_path_dev);
+	if (file)
+	  {
+	    if (grub_file_size (file) != core_size)
+	      grub_util_info ("succeeded in opening the core image but the size is different (%d != %d)",
+			      (int) grub_file_size (file), (int) core_size);
+	    else if (grub_file_read (file, tmp_img, core_size)
+		     != (grub_ssize_t) core_size)
+	      grub_util_info ("succeeded in opening the core image but cannot read %d bytes",
+			      (int) core_size);
+	    else if (memcmp (core_img, tmp_img, core_size) != 0)
+	      {
+#if 0
+		FILE *dump;
+		FILE *dump2;
+
+		dump = fopen ("dump.img", "wb");
+		if (dump)
+		  {
+		    fwrite (tmp_img, 1, core_size, dump);
+		    fclose (dump);
+		  }
+
+		dump2 = fopen ("dump2.img", "wb");
+		if (dump2)
+		  {
+		    fwrite (core_img, 1, core_size, dump2);
+		    fclose (dump2);
+		  }
+
+#endif
+		grub_util_info ("succeeded in opening the core image but the data is different");
+	      }
+	    else
+	      {
+		grub_file_close (file);
+		break;
+	      }
+
+	    grub_file_close (file);
+	  }
+	else
+	  grub_util_info ("couldn't open the core image");
+
+	if (grub_errno)
+	  grub_util_info ("error message = %s", grub_errmsg);
+
+	grub_errno = GRUB_ERR_NONE;
+	grub_util_biosdisk_flush (root_dev->disk);
+	sleep (1);
+      }
+
+    if (i == MAX_TRIES)
+      grub_util_error (_("cannot read `%s' correctly"), core_path_dev);
+  }
+
+#endif
+
+  /* Clean out the blocklists.  */
+  bl.block = bl.first_block;
+  while (bl.block->len)
+    {
+      bl.block->start = 0;
+      bl.block->len = 0;
+#ifdef GRUB_SETUP_BIOS
+      bl.block->segment = 0;
+#endif
+
+      bl.block--;
+
+      if ((char *) bl.block <= core_img)
+	grub_util_error ("%s", _("no terminator in the core image"));
+    }
+
+  bl.block = bl.first_block;
+
+#ifdef __linux__
+  {
+    grub_partition_t container = root_dev->disk->partition;
+    grub_uint64_t container_start = grub_partition_get_start (container);
+    struct fiemap fie1;
+    int fd;
+
+    /* Write the first two sectors of the core image onto the disk.  */
+    grub_util_info ("opening the core image `%s'", core_path);
+    fp = fopen (core_path, "rb");
+    if (! fp)
+      grub_util_error (_("cannot open `%s': %s"), core_path,
+		       strerror (errno));
+    fd = fileno (fp);
+
+    grub_memset (&fie1, 0, sizeof (fie1));
+    fie1.fm_length = core_size;
+    fie1.fm_flags = FIEMAP_FLAG_SYNC;
+
+    if (ioctl (fd, FS_IOC_FIEMAP, &fie1) < 0)
+      {
+	int nblocks, i, j;
+	int bsize;
+	int mul;
+
+	grub_util_info ("FIEMAP failed. Reverting to FIBMAP");
+
+	if (ioctl (fd, FIGETBSZ, &bsize) < 0)
+	  grub_util_error (_("can't retrieve blocklists: %s"),
+			   strerror (errno));
+	if (bsize & (GRUB_DISK_SECTOR_SIZE - 1))
+	  grub_util_error ("%s", _("blocksize is not divisible by 512"));
+	mul = bsize >> GRUB_DISK_SECTOR_BITS;
+	nblocks = (core_size + bsize - 1) / bsize;
+	if (mul == 0 || nblocks == 0)
+	  grub_util_error ("%s", _("can't retrieve blocklists"));
+	for (i = 0; i < nblocks; i++)
+	  {
+	    unsigned blk = i;
+	    if (ioctl (fd, FIBMAP, &blk) < 0)
+	      grub_util_error (_("can't retrieve blocklists: %s"),
+			       strerror (errno));
+	    
+	    for (j = 0; j < mul; j++)
+	      {
+		int rest = core_size - ((i * mul + j) << GRUB_DISK_SECTOR_BITS);
+		if (rest <= 0)
+		  break;
+		if (rest > GRUB_DISK_SECTOR_SIZE)
+		  rest = GRUB_DISK_SECTOR_SIZE;
+		if (i == 0 && j == 0)
+		  save_first_sector (((grub_uint64_t) blk) * mul
+				     + container_start,
+				     0, rest, &first_sector);
+		else
+		  save_blocklists (((grub_uint64_t) blk) * mul + j
+				   + container_start,
+				   0, rest, &bl);
+	      }
+	  }
+      }
+    else
+      {
+	struct fiemap *fie2;
+	int i, j;
+	fie2 = xmalloc (sizeof (*fie2)
+			+ fie1.fm_mapped_extents
+			* sizeof (fie1.fm_extents[1]));
+	memset (fie2, 0, sizeof (*fie2)
+		+ fie1.fm_mapped_extents * sizeof (fie2->fm_extents[1]));
+	fie2->fm_length = core_size;
+	fie2->fm_flags = FIEMAP_FLAG_SYNC;
+	fie2->fm_extent_count = fie1.fm_mapped_extents;
+	if (ioctl (fd, FS_IOC_FIEMAP, fie2) < 0)
+	  grub_util_error (_("can't retrieve blocklists: %s"),
+			   strerror (errno));
+	for (i = 0; i < fie2->fm_mapped_extents; i++)
+	  {
+	    for (j = 0;
+		 j < ((fie2->fm_extents[i].fe_length
+		       + GRUB_DISK_SECTOR_SIZE - 1)
+		      >> GRUB_DISK_SECTOR_BITS);
+		 j++)
+	      {
+		size_t len = (fie2->fm_extents[i].fe_length
+			      - j * GRUB_DISK_SECTOR_SIZE);
+		if (len > GRUB_DISK_SECTOR_SIZE)
+		  len = GRUB_DISK_SECTOR_SIZE;
+		if (first_sector == (grub_disk_addr_t)-1)
+		  save_first_sector ((fie2->fm_extents[i].fe_physical
+				      >> GRUB_DISK_SECTOR_BITS)
+				     + j + container_start,
+				     fie2->fm_extents[i].fe_physical
+				     & (GRUB_DISK_SECTOR_SIZE - 1), len,
+				     &first_sector);
+		else
+		  save_blocklists ((fie2->fm_extents[i].fe_physical
+				    >> GRUB_DISK_SECTOR_BITS)
+				   + j + container_start,
+				   fie2->fm_extents[i].fe_physical
+				   & (GRUB_DISK_SECTOR_SIZE - 1), len, &bl);
+
+
+	      }
+	  }
+	if (first_sector == (grub_disk_addr_t)-1)
+	  grub_util_error ("%s", _("can't retrieve blocklists"));
+      }
+    fclose (fp);
+  }
+#else
+  {
+    grub_file_t file;
+    /* Now read the core image to determine where the sectors are.  */
+    grub_file_filter_disable_compression ();
+    file = grub_file_open (core_path_dev);
+    if (! file)
+      grub_util_error ("%s", grub_errmsg);
+
+    file->read_hook = save_first_sector;
+    file->read_hook_data = &first_sector;
+    if (grub_file_read (file, tmp_img, GRUB_DISK_SECTOR_SIZE)
+	!= GRUB_DISK_SECTOR_SIZE)
+      grub_util_error ("%s", _("failed to read the first sector of the core image"));
+
+    bl.block = bl.first_block;
+    file->read_hook = save_blocklists;
+    file->read_hook_data = &bl;
+    if (grub_file_read (file, tmp_img, core_size - GRUB_DISK_SECTOR_SIZE)
+	!= (grub_ssize_t) core_size - GRUB_DISK_SECTOR_SIZE)
+      grub_util_error ("%s", _("failed to read the rest sectors of the core image"));
+    grub_file_close (file);
+  }
+#endif
+
+#ifdef GRUB_SETUP_SPARC64
+  {
+    char *boot_devpath;
+    boot_devpath = (char *) (boot_img
+			     + GRUB_BOOT_AOUT_HEADER_SIZE
+			     + GRUB_BOOT_MACHINE_BOOT_DEVPATH);
+    if (dest_dev->disk->id != root_dev->disk->id
+	|| dest_dev->disk->dev->id != root_dev->disk->dev->id)
+      {
+	const char *dest_ofpath;
+	dest_ofpath
+	  = grub_util_devname_to_ofpath (grub_util_biosdisk_get_osdev (root_dev->disk));
+	grub_util_info ("dest_ofpath is `%s'", dest_ofpath);
+	strncpy (boot_devpath, dest_ofpath,
+		 GRUB_BOOT_MACHINE_BOOT_DEVPATH_END
+		 - GRUB_BOOT_MACHINE_BOOT_DEVPATH - 1);
+	boot_devpath[GRUB_BOOT_MACHINE_BOOT_DEVPATH_END
+		   - GRUB_BOOT_MACHINE_BOOT_DEVPATH - 1] = 0;
+      }
+    else
+      {
+	grub_util_info ("non cross-disk install");
+	memset (boot_devpath, 0, GRUB_BOOT_MACHINE_BOOT_DEVPATH_END
+		- GRUB_BOOT_MACHINE_BOOT_DEVPATH);
+      }
+    grub_util_info ("boot device path %s", boot_devpath);
+  }
+#endif
+
+  free (core_path_dev);
+  free (tmp_img);
+
+  write_rootdev (root_dev, boot_img, first_sector);
+
+  /* Write the first two sectors of the core image onto the disk.  */
+  grub_util_info ("opening the core image `%s'", core_path);
+  fp = fopen (core_path, "r+b");
+  if (! fp)
+    grub_util_error (_("cannot open `%s': %s"), core_path,
+		     strerror (errno));
+
+  grub_util_write_image (core_img, GRUB_DISK_SECTOR_SIZE * 2, fp, core_path);
+  fflush (fp);
+  fsync (fileno (fp));
+  fclose (fp);
+  grub_util_biosdisk_flush (root_dev->disk);
+
+  grub_disk_cache_invalidate_all ();
+
+  {
+    char *buf, *ptr = core_img;
+    size_t len = core_size;
+    grub_uint64_t blk;
+    grub_partition_t container = core_dev->disk->partition;
+    grub_err_t err;
+
+    core_dev->disk->partition = 0;
+
+    buf = xmalloc (core_size);
+    blk = first_sector;
+    err = grub_disk_read (core_dev->disk, blk, 0, GRUB_DISK_SECTOR_SIZE, buf);
+    if (err)
+      grub_util_error (_("cannot read `%s': %s"), core_dev->disk->name,
+		       grub_errmsg);
+    if (grub_memcmp (buf, ptr, GRUB_DISK_SECTOR_SIZE) != 0)
+      grub_util_error ("%s", _("blocklists are invalid"));
+
+    ptr += GRUB_DISK_SECTOR_SIZE;
+    len -= GRUB_DISK_SECTOR_SIZE;
+
+    bl.block = bl.first_block;
+    while (bl.block->len)
+      {
+	size_t cur = grub_target_to_host16 (bl.block->len) << GRUB_DISK_SECTOR_BITS;
+	blk = grub_target_to_host64 (bl.block->start);
+
+	if (cur > len)
+	  cur = len;
+
+	err = grub_disk_read (core_dev->disk, blk, 0, cur, buf);
+	if (err)
+	  grub_util_error (_("cannot read `%s': %s"), core_dev->disk->name,
+			   grub_errmsg);
+
+	if (grub_memcmp (buf, ptr, cur) != 0)
+	  grub_util_error ("%s", _("blocklists are invalid"));
+
+	ptr += cur;
+	len -= cur;
+	bl.block--;
+	
+	if ((char *) bl.block <= core_img)
+	  grub_util_error ("%s", _("no terminator in the core image"));
+      }
+    core_dev->disk->partition = container;
+    free (buf);
+  }
+
+#ifdef GRUB_SETUP_BIOS
+ finish:
+#endif
+
+  /* Write the boot image onto the disk.  */
+  if (grub_disk_write (dest_dev->disk, BOOT_SECTOR,
+		       0, GRUB_DISK_SECTOR_SIZE, boot_img))
+    grub_util_error ("%s", grub_errmsg);
+
+  grub_util_biosdisk_flush (root_dev->disk);
+  grub_util_biosdisk_flush (dest_dev->disk);
+
+  free (core_path);
+  free (core_img);
+  free (boot_img);
+  grub_device_close (dest_dev);
+  grub_device_close (root_dev);
+}

=== added file 'util/setup_bios.c'
--- util/setup_bios.c	1970-01-01 00:00:00 +0000
+++ util/setup_bios.c	2013-10-04 00:39:55 +0000
@@ -0,0 +1,2 @@
+#define GRUB_SETUP_BIOS 1
+#include "setup.c"

=== added file 'util/setup_sparc.c'
--- util/setup_sparc.c	1970-01-01 00:00:00 +0000
+++ util/setup_sparc.c	2013-10-04 00:39:55 +0000
@@ -0,0 +1,2 @@
+#define GRUB_SETUP_SPARC64 1
+#include "setup.c"


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 291 bytes --]

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

* Re: [RFC] grub-install C rewrite
  2013-09-26 18:49       ` Vladimir 'φ-coder/phcoder' Serbinenko
  2013-09-26 20:22         ` Lennart Sorensen
@ 2013-09-27  3:10         ` Andrey Borzenkov
  1 sibling, 0 replies; 20+ messages in thread
From: Andrey Borzenkov @ 2013-09-27  3:10 UTC (permalink / raw)
  To: grub-devel

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

В Thu, 26 Sep 2013 20:49:52 +0200
Vladimir 'φ-coder/phcoder' Serbinenko <phcoder@gmail.com> пишет:

> On 26.09.2013 16:44, Lennart Sorensen wrote:
> >> windows is low priority and more of a bonus. The problems of handling
> >> anything that looks like a list (e.g. list of devices where / resides on
> >> in case of btrfs) and code becoming hairy to handle those cases is
> >> bigger reason.
> > 
> > Sure lists can be a hassle.
> > 
> > I didn't check lately, but does grub-install understand a list of devices
> > to install to yet?
> > 
> > ie:  grub-install /dev/sda /dev/sdb
> > 
> > After all if I have software raid, both those devices contain /boot and
> > are valid to boot from.  And since on things like IBM powerpc,
> > grub-install likes to update the firmware with the list of boot devices,
> > they do all have to be specified at once or you end up with the wrong
> > list (which so far I have worked around by manually fixing the firmware
> > settings after updating grub, which doesn't happen very often lately).
> > 
> > So calling grub-install for each device in turn (as I believe Debian
> > does on x86 if you tell it multiple boot devices), does not actually
> > give the correct result.
> > 

This will break in blocklist install because every time core.img is
recreated, but I do not see why it should not work if embedding is
possible. Challenge is to atomically detect whether this is possible or
not for all devices before you have clobbered half of them.

Although right now we first rewrite /boot/grub and then try to install;
if installation fails, /boot/grub no more matches embedded core.img
anyway.

> This is interesting testcase which wasn't brought before. This would
> potentially involve creating several core.img or forcing UUID when using
> multiple devices. Again, pretty easy in C and hairy in bash due to list
> handling.

Why it would require separate core.img? core.img needs to know how
access /boot/grub, and /boot/grub remains the same. Same with UUID. Or
do I miss something here?

> 
> It's also possible to have options --dry-run (doesn't really do the
> changes, except, perhaps, "mkdir -p") and --gen-script which would
> generate a list of commands which when executed would do exactly as if
> grub-install was run. So you can do
> grub-install --dry-run --gen-script=/tmp/myinstall ...
> <change /tmp/myinstall to will>
> /tmp/myinstall
> This has additional advantage of see which commands are really executed
> without having to understand the whole command flow.
> 

That would definitely be useful irrespectively of which language is
used to implement. In particular, this would allow to see list of
modules required for a system.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

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

* Re: [RFC] grub-install C rewrite
  2013-09-26 20:51           ` Chris Murphy
@ 2013-09-26 22:15             ` Vladimir 'φ-coder/phcoder' Serbinenko
  0 siblings, 0 replies; 20+ messages in thread
From: Vladimir 'φ-coder/phcoder' Serbinenko @ 2013-09-26 22:15 UTC (permalink / raw)
  To: The development of GNU GRUB

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

On 26.09.2013 22:51, Chris Murphy wrote:
> 
> On Sep 26, 2013, at 2:22 PM, Lennart Sorensen <lsorense@csclub.uwaterloo.ca> wrote:
> 
>> On Thu, Sep 26, 2013 at 08:49:52PM +0200, Vladimir 'φ-coder/phcoder' Serbinenko wrote:
>>> This is interesting testcase which wasn't brought before. This would
>>> potentially involve creating several core.img or forcing UUID when using
>>> multiple devices. Again, pretty easy in C and hairy in bash due to list
>>> handling.
>>
>> No, one core.img is fine.  The boot disk is the boot disk in each case
>> (so on x86 device 0x80).  The same core.img gets inserted too all the
>> devices, so that if it happens to be the boot disk, it works.  Since the
>> partition is raid1, the same UUID is everywhere.  I do not expect
>> booting from a raid5 device to be possible as the boot partition (althoug
>> hperhaps grub is smart enough to read the kernel from an md raid5 device
>> these days).
> 
> It is. Even raid6 is possible. The limitation is the BIOS being able to present all member devices to grub for it to assemble the raid in order to find /boot. But I don't know if it can work on a degraded array by rebuilding parity. If not, I see no point in /boot on raid5/6.
> 
> The case of btrfs raid0/1/10 is interesting. It's possible to boot all of these with GRUB2, I've tried up to 4 disks for those raid levels, and includes support for subvolumes/snapshots. I haven't extensively tried to break it with many snapshots, deletions, etc. So I don't know how resilient it is. The ability to boot raid1/10 with a missing member is useful. And it's actually a more complex setup to incorporate md raid and ext4 on those same disks for a separate /boot; or possibly losing ability to boot if /boot is on a single disk, which also complicates the layout. For such a layout, core.img is needed for each disk.
> 
> Open question is if on BIOS hardware, if a 1MB BIOSBoot is preferred over the 64KB Btrfs bootloader pad? I don't know off hand if each member disk, or subsequently added disks, each have this 64KB pad or just the first member.
> 
This is besides the point. I'm fine to discuss such things but in a
separate thread.
> 
> Chris Murphy
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> https://lists.gnu.org/mailman/listinfo/grub-devel
> 



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 291 bytes --]

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

* Re: [RFC] grub-install C rewrite
  2013-09-26 20:22         ` Lennart Sorensen
  2013-09-26 20:29           ` Vladimir 'φ-coder/phcoder' Serbinenko
@ 2013-09-26 20:51           ` Chris Murphy
  2013-09-26 22:15             ` Vladimir 'φ-coder/phcoder' Serbinenko
  1 sibling, 1 reply; 20+ messages in thread
From: Chris Murphy @ 2013-09-26 20:51 UTC (permalink / raw)
  To: The development of GNU GRUB


On Sep 26, 2013, at 2:22 PM, Lennart Sorensen <lsorense@csclub.uwaterloo.ca> wrote:

> On Thu, Sep 26, 2013 at 08:49:52PM +0200, Vladimir 'φ-coder/phcoder' Serbinenko wrote:
>> This is interesting testcase which wasn't brought before. This would
>> potentially involve creating several core.img or forcing UUID when using
>> multiple devices. Again, pretty easy in C and hairy in bash due to list
>> handling.
> 
> No, one core.img is fine.  The boot disk is the boot disk in each case
> (so on x86 device 0x80).  The same core.img gets inserted too all the
> devices, so that if it happens to be the boot disk, it works.  Since the
> partition is raid1, the same UUID is everywhere.  I do not expect
> booting from a raid5 device to be possible as the boot partition (althoug
> hperhaps grub is smart enough to read the kernel from an md raid5 device
> these days).

It is. Even raid6 is possible. The limitation is the BIOS being able to present all member devices to grub for it to assemble the raid in order to find /boot. But I don't know if it can work on a degraded array by rebuilding parity. If not, I see no point in /boot on raid5/6.

The case of btrfs raid0/1/10 is interesting. It's possible to boot all of these with GRUB2, I've tried up to 4 disks for those raid levels, and includes support for subvolumes/snapshots. I haven't extensively tried to break it with many snapshots, deletions, etc. So I don't know how resilient it is. The ability to boot raid1/10 with a missing member is useful. And it's actually a more complex setup to incorporate md raid and ext4 on those same disks for a separate /boot; or possibly losing ability to boot if /boot is on a single disk, which also complicates the layout. For such a layout, core.img is needed for each disk.

Open question is if on BIOS hardware, if a 1MB BIOSBoot is preferred over the 64KB Btrfs bootloader pad? I don't know off hand if each member disk, or subsequently added disks, each have this 64KB pad or just the first member.


Chris Murphy

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

* Re: [RFC] grub-install C rewrite
  2013-09-26 20:22         ` Lennart Sorensen
@ 2013-09-26 20:29           ` Vladimir 'φ-coder/phcoder' Serbinenko
  2013-09-26 20:51           ` Chris Murphy
  1 sibling, 0 replies; 20+ messages in thread
From: Vladimir 'φ-coder/phcoder' Serbinenko @ 2013-09-26 20:29 UTC (permalink / raw)
  To: The development of GNU GRUB

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

On 26.09.2013 22:22, Lennart Sorensen wrote:
> On Thu, Sep 26, 2013 at 08:49:52PM +0200, Vladimir 'φ-coder/phcoder' Serbinenko wrote:
>> This is interesting testcase which wasn't brought before. This would
>> potentially involve creating several core.img or forcing UUID when using
>> multiple devices. Again, pretty easy in C and hairy in bash due to list
>> handling.
> 
> No, one core.img is fine.  The boot disk is the boot disk in each case
> (so on x86 device 0x80).
We don't rely on it being 0x80 and it may not be 0x80 at all.
> Since the
> partition is raid1, the same UUID is everywhere.
UUID would be the same but for whole other reason. It's the same because
even with different install device you still have same device for $grubdir.
The problem comes from the possibility to avoid UUID entirely on some
devices but not others.
>  I do not expect
> booting from a raid5 device to be possible as the boot partition
This works. Your expectations are too low.
> 
>> It's surely sth we can do. grub-install does only following that is
>> affecting system:
>> 1) mkdir -p
>> 2) copy files. We can write exact copy commands
>> 3) grub-mkimage. We can do the same.
>> 4) grub-setup. Ditto
>> 5) Create load.cfg. Ditto.
>> 6) calling external commands.
>>  We can have 4 levels of verbosity:
>> 0) quiet,
>> 1) write to stderr the commands
>> 2) like 1 but show grub_util_info
>> 3) additionally show grub_dprintf
>>
>> It's also possible to have options --dry-run (doesn't really do the
>> changes, except, perhaps, "mkdir -p") and --gen-script which would
>> generate a list of commands which when executed would do exactly as if
>> grub-install was run. So you can do
>> grub-install --dry-run --gen-script=/tmp/myinstall ...
>> <change /tmp/myinstall to will>
>> /tmp/myinstall
>> This has additional advantage of see which commands are really executed
>> without having to understand the whole command flow.
> 



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 291 bytes --]

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

* Re: [RFC] grub-install C rewrite
  2013-09-26 18:49       ` Vladimir 'φ-coder/phcoder' Serbinenko
@ 2013-09-26 20:22         ` Lennart Sorensen
  2013-09-26 20:29           ` Vladimir 'φ-coder/phcoder' Serbinenko
  2013-09-26 20:51           ` Chris Murphy
  2013-09-27  3:10         ` Andrey Borzenkov
  1 sibling, 2 replies; 20+ messages in thread
From: Lennart Sorensen @ 2013-09-26 20:22 UTC (permalink / raw)
  To: The development of GNU GRUB

On Thu, Sep 26, 2013 at 08:49:52PM +0200, Vladimir 'φ-coder/phcoder' Serbinenko wrote:
> This is interesting testcase which wasn't brought before. This would
> potentially involve creating several core.img or forcing UUID when using
> multiple devices. Again, pretty easy in C and hairy in bash due to list
> handling.

No, one core.img is fine.  The boot disk is the boot disk in each case
(so on x86 device 0x80).  The same core.img gets inserted too all the
devices, so that if it happens to be the boot disk, it works.  Since the
partition is raid1, the same UUID is everywhere.  I do not expect
booting from a raid5 device to be possible as the boot partition (althoug
hperhaps grub is smart enough to read the kernel from an md raid5 device
these days).

> It's surely sth we can do. grub-install does only following that is
> affecting system:
> 1) mkdir -p
> 2) copy files. We can write exact copy commands
> 3) grub-mkimage. We can do the same.
> 4) grub-setup. Ditto
> 5) Create load.cfg. Ditto.
> 6) calling external commands.
>  We can have 4 levels of verbosity:
> 0) quiet,
> 1) write to stderr the commands
> 2) like 1 but show grub_util_info
> 3) additionally show grub_dprintf
> 
> It's also possible to have options --dry-run (doesn't really do the
> changes, except, perhaps, "mkdir -p") and --gen-script which would
> generate a list of commands which when executed would do exactly as if
> grub-install was run. So you can do
> grub-install --dry-run --gen-script=/tmp/myinstall ...
> <change /tmp/myinstall to will>
> /tmp/myinstall
> This has additional advantage of see which commands are really executed
> without having to understand the whole command flow.

-- 
Len Sorensen


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

* Re: [RFC] grub-install C rewrite
  2013-09-26 18:51     ` Vladimir 'φ-coder/phcoder' Serbinenko
  2013-09-26 18:56       ` Darren J Moffat
@ 2013-09-26 18:57       ` Seth Goldberg
  1 sibling, 0 replies; 20+ messages in thread
From: Seth Goldberg @ 2013-09-26 18:57 UTC (permalink / raw)
  To: The development of GNU GRUB

[-- Attachment #1: Type: TEXT/PLAIN, Size: 1032 bytes --]



Quoting Vladimir 'φ-coder/phcoder' Serbinenko, who wrote the following on...:

> On 26.09.2013 19:10, Seth Goldberg wrote:
>>
>>  Ditto here.  I'd prefer it stay *sh.
>>
> Even if it would mean to go with bash?
> Solaris was one of the worst platforms for making grub-install work
> there due to its very limited shell and standard tools behaving
> differently. Frankly I wouldn't be surprised if it got broken for
> solaris again.
> I see Solaris as one of platforms which can benefit a lot from this move.

  My motivation was mainly from a maintenance perspective, but it really 
depends on how well-structured the C is.  In the past, some essential code 
(*cough* relocator) was implemented monolithically and was extremely difficult 
to understand.  There are certainly a lot of positives to implementing it in C 
(the tons of forks from the file-copies can be eliminated, for example).

  NB: bash is a first-class shell on Solaris these days, so I'm not too 
concerned about that.

  Thanks,
  --S

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

* Re: [RFC] grub-install C rewrite
  2013-09-26 18:51     ` Vladimir 'φ-coder/phcoder' Serbinenko
@ 2013-09-26 18:56       ` Darren J Moffat
  2013-09-26 18:57       ` Seth Goldberg
  1 sibling, 0 replies; 20+ messages in thread
From: Darren J Moffat @ 2013-09-26 18:56 UTC (permalink / raw)
  To: The development of GNU GRUB
  Cc: Vladimir 'φ-coder/phcoder' Serbinenko



On 09/26/13 19:51, Vladimir 'φ-coder/phcoder' Serbinenko wrote:
> On 26.09.2013 19:10, Seth Goldberg wrote:
>>
>>   Ditto here.  I'd prefer it stay *sh.
>>
> Even if it would mean to go with bash?
> Solaris was one of the worst platforms for making grub-install work
> there due to its very limited shell and standard tools behaving
> differently. Frankly I wouldn't be surprised if it got broken for
> solaris again.
> I see Solaris as one of platforms which can benefit a lot from this move.

bash is always installed on Solaris 11 onwards (11.1 is when it moved 
from legacy GRUB to GRU2) - not least of which because it is root's 
login shell.

-- 
Darren J Moffat


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

* Re: [RFC] grub-install C rewrite
  2013-09-26 17:10   ` Seth Goldberg
@ 2013-09-26 18:51     ` Vladimir 'φ-coder/phcoder' Serbinenko
  2013-09-26 18:56       ` Darren J Moffat
  2013-09-26 18:57       ` Seth Goldberg
  0 siblings, 2 replies; 20+ messages in thread
From: Vladimir 'φ-coder/phcoder' Serbinenko @ 2013-09-26 18:51 UTC (permalink / raw)
  To: The development of GNU GRUB

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

On 26.09.2013 19:10, Seth Goldberg wrote:
> 
>  Ditto here.  I'd prefer it stay *sh.
> 
Even if it would mean to go with bash?
Solaris was one of the worst platforms for making grub-install work
there due to its very limited shell and standard tools behaving
differently. Frankly I wouldn't be surprised if it got broken for
solaris again.
I see Solaris as one of platforms which can benefit a lot from this move.
>  --S
> 
> On Sep 26, 2013, at 6:35 AM, Lennart Sorensen wrote:
> 
>> On Thu, Sep 26, 2013 at 03:08:54PM +0200, Vladimir 'φ-coder/phcoder' Serbinenko wrote:
>>> Hello, all. Recently I made some order in hostdisk.c and getroot.c
>>> involving splitting in OS-specific parts.
>>> In the same time I added WinAPI version of getroot/hostdisk allowing
>>> grub-probe to work on windows natively
>>> Also on-going is AROS-specific parts.
>>> Windows and AROS are not friendly with bash.
>>> The attempt to make both multiple files of same type work and handling
>>> whitespaces/newlines/... in filenames would result in very ugly code
>>> with loads of evals.
>>> Current code may have subtle assumptions on behaviour of common tools
>>> like sed and on locale (E.g. "[a-z]" doesn't cover u if locale is Estonian).
>>> So to check viability I rewrote grub-install in C. This is mostly proof
>>> of concept with loads of FIXMEs but I could boot i386-pc install made
>>> with it. In many aspects (static variables, some tests, general
>>> structure) it's reminiscent of sh version of grub-install it's based on.
>>> Some functionality is likely to stay OS-specific, e.g. executing
>>> compressors or determining firmware.
>>>
>>> I'd like to know the opinion of other people on possible switchover. If
>>> switched then it'll have to be all grub-install, grub-mkrescue,
>>> grub-mknetdir and grub-mkstandalone.
>>> I'd like to hear from other people.
>>
>> Given the number of times I have had to edit grub-install in the past to
>> get it to work right on a powerpc machine (I think it is now working OK),
>> I would hate to have had that be C code.  After all it really is mainly
>> a wrapper around other grub tools.
>>
>> I think windows not having bash is a rather low priority to most people
>> compared to actually be able to work with grub on the platforms where
>> it is pretty much the only choice.
>>
>> So personally, based on my experience, I hate this idea.
>>
>> -- 
>> Len Sorensen
>>
>> _______________________________________________
>> Grub-devel mailing list
>> Grub-devel@gnu.org
>> https://lists.gnu.org/mailman/listinfo/grub-devel
> 
> 
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> https://lists.gnu.org/mailman/listinfo/grub-devel
> 



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 291 bytes --]

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

* Re: [RFC] grub-install C rewrite
  2013-09-26 14:44     ` Lennart Sorensen
@ 2013-09-26 18:49       ` Vladimir 'φ-coder/phcoder' Serbinenko
  2013-09-26 20:22         ` Lennart Sorensen
  2013-09-27  3:10         ` Andrey Borzenkov
  0 siblings, 2 replies; 20+ messages in thread
From: Vladimir 'φ-coder/phcoder' Serbinenko @ 2013-09-26 18:49 UTC (permalink / raw)
  To: The development of GNU GRUB

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

On 26.09.2013 16:44, Lennart Sorensen wrote:
>> windows is low priority and more of a bonus. The problems of handling
>> anything that looks like a list (e.g. list of devices where / resides on
>> in case of btrfs) and code becoming hairy to handle those cases is
>> bigger reason.
> 
> Sure lists can be a hassle.
> 
> I didn't check lately, but does grub-install understand a list of devices
> to install to yet?
> 
> ie:  grub-install /dev/sda /dev/sdb
> 
> After all if I have software raid, both those devices contain /boot and
> are valid to boot from.  And since on things like IBM powerpc,
> grub-install likes to update the firmware with the list of boot devices,
> they do all have to be specified at once or you end up with the wrong
> list (which so far I have worked around by manually fixing the firmware
> settings after updating grub, which doesn't happen very often lately).
> 
> So calling grub-install for each device in turn (as I believe Debian
> does on x86 if you tell it multiple boot devices), does not actually
> give the correct result.
> 
This is interesting testcase which wasn't brought before. This would
potentially involve creating several core.img or forcing UUID when using
multiple devices. Again, pretty easy in C and hairy in bash due to list
handling.
> So really my main objection is that it is much harder to debug and fix
> C code than it is to fix a script calling a bunch of external commands.
> 
> At the very least a C version of grub-install must have an option to
> list every command it is attempting to execute externally.  Certainly
> adding 'set -x' to grub-install has often been helpful.

It's surely sth we can do. grub-install does only following that is
affecting system:
1) mkdir -p
2) copy files. We can write exact copy commands
3) grub-mkimage. We can do the same.
4) grub-setup. Ditto
5) Create load.cfg. Ditto.
6) calling external commands.
 We can have 4 levels of verbosity:
0) quiet,
1) write to stderr the commands
2) like 1 but show grub_util_info
3) additionally show grub_dprintf

It's also possible to have options --dry-run (doesn't really do the
changes, except, perhaps, "mkdir -p") and --gen-script which would
generate a list of commands which when executed would do exactly as if
grub-install was run. So you can do
grub-install --dry-run --gen-script=/tmp/myinstall ...
<change /tmp/myinstall to will>
/tmp/myinstall
This has additional advantage of see which commands are really executed
without having to understand the whole command flow.


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 291 bytes --]

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

* Re: [RFC] grub-install C rewrite
  2013-09-26 13:35 ` Lennart Sorensen
  2013-09-26 13:59   ` Vladimir 'φ-coder/phcoder' Serbinenko
@ 2013-09-26 17:10   ` Seth Goldberg
  2013-09-26 18:51     ` Vladimir 'φ-coder/phcoder' Serbinenko
  1 sibling, 1 reply; 20+ messages in thread
From: Seth Goldberg @ 2013-09-26 17:10 UTC (permalink / raw)
  To: The development of GNU GRUB


 Ditto here.  I'd prefer it stay *sh.

 --S

On Sep 26, 2013, at 6:35 AM, Lennart Sorensen wrote:

> On Thu, Sep 26, 2013 at 03:08:54PM +0200, Vladimir 'φ-coder/phcoder' Serbinenko wrote:
>> Hello, all. Recently I made some order in hostdisk.c and getroot.c
>> involving splitting in OS-specific parts.
>> In the same time I added WinAPI version of getroot/hostdisk allowing
>> grub-probe to work on windows natively
>> Also on-going is AROS-specific parts.
>> Windows and AROS are not friendly with bash.
>> The attempt to make both multiple files of same type work and handling
>> whitespaces/newlines/... in filenames would result in very ugly code
>> with loads of evals.
>> Current code may have subtle assumptions on behaviour of common tools
>> like sed and on locale (E.g. "[a-z]" doesn't cover u if locale is Estonian).
>> So to check viability I rewrote grub-install in C. This is mostly proof
>> of concept with loads of FIXMEs but I could boot i386-pc install made
>> with it. In many aspects (static variables, some tests, general
>> structure) it's reminiscent of sh version of grub-install it's based on.
>> Some functionality is likely to stay OS-specific, e.g. executing
>> compressors or determining firmware.
>> 
>> I'd like to know the opinion of other people on possible switchover. If
>> switched then it'll have to be all grub-install, grub-mkrescue,
>> grub-mknetdir and grub-mkstandalone.
>> I'd like to hear from other people.
> 
> Given the number of times I have had to edit grub-install in the past to
> get it to work right on a powerpc machine (I think it is now working OK),
> I would hate to have had that be C code.  After all it really is mainly
> a wrapper around other grub tools.
> 
> I think windows not having bash is a rather low priority to most people
> compared to actually be able to work with grub on the platforms where
> it is pretty much the only choice.
> 
> So personally, based on my experience, I hate this idea.
> 
> -- 
> Len Sorensen
> 
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> https://lists.gnu.org/mailman/listinfo/grub-devel



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

* Re: [RFC] grub-install C rewrite
  2013-09-26 14:49 ` Andrey Borzenkov
@ 2013-09-26 15:01   ` Vladimir 'φ-coder/phcoder' Serbinenko
  0 siblings, 0 replies; 20+ messages in thread
From: Vladimir 'φ-coder/phcoder' Serbinenko @ 2013-09-26 15:01 UTC (permalink / raw)
  To: The development of GNU GRUB

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


> If we agree on bash as common denominator, bash has arrays which
> make this straightforward. Unless we want to continue support for bash
> 1.x.
> 
This would step up the requirements. BSDs commonly have no bash
installed. AROS probably has no bash available at all.
AROS uses GRUB as its bootloader but currently use their own code in C
to install.



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 291 bytes --]

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

* Re: [RFC] grub-install C rewrite
  2013-09-26 13:08 Vladimir 'φ-coder/phcoder' Serbinenko
  2013-09-26 13:35 ` Lennart Sorensen
@ 2013-09-26 14:49 ` Andrey Borzenkov
  2013-09-26 15:01   ` Vladimir 'φ-coder/phcoder' Serbinenko
  2013-10-06 14:54 ` Vladimir 'φ-coder/phcoder' Serbinenko
  2 siblings, 1 reply; 20+ messages in thread
From: Andrey Borzenkov @ 2013-09-26 14:49 UTC (permalink / raw)
  To: grub-devel

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

В Thu, 26 Sep 2013 15:08:54 +0200
Vladimir 'φ-coder/phcoder' Serbinenko <phcoder@gmail.com> пишет:

> Hello, all. Recently I made some order in hostdisk.c and getroot.c
> involving splitting in OS-specific parts.
> In the same time I added WinAPI version of getroot/hostdisk allowing
> grub-probe to work on windows natively
> Also on-going is AROS-specific parts.
> Windows and AROS are not friendly with bash.
> The attempt to make both multiple files of same type work and handling
> whitespaces/newlines/... in filenames would result in very ugly code
> with loads of evals.

If we agree on bash as common denominator, bash has arrays which
make this straightforward. Unless we want to continue support for bash
1.x.

> Current code may have subtle assumptions on behaviour of common tools
> like sed and on locale (E.g. "[a-z]" doesn't cover u if locale is Estonian).
> So to check viability I rewrote grub-install in C. This is mostly proof
> of concept with loads of FIXMEs but I could boot i386-pc install made
> with it. In many aspects (static variables, some tests, general
> structure) it's reminiscent of sh version of grub-install it's based on.
> Some functionality is likely to stay OS-specific, e.g. executing
> compressors or determining firmware.
> 
> I'd like to know the opinion of other people on possible switchover. If
> switched then it'll have to be all grub-install, grub-mkrescue,
> grub-mknetdir and grub-mkstandalone.
> I'd like to hear from other people.


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

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

* Re: [RFC] grub-install C rewrite
  2013-09-26 13:59   ` Vladimir 'φ-coder/phcoder' Serbinenko
@ 2013-09-26 14:44     ` Lennart Sorensen
  2013-09-26 18:49       ` Vladimir 'φ-coder/phcoder' Serbinenko
  0 siblings, 1 reply; 20+ messages in thread
From: Lennart Sorensen @ 2013-09-26 14:44 UTC (permalink / raw)
  To: The development of GNU GRUB

On Thu, Sep 26, 2013 at 03:59:03PM +0200, Vladimir 'φ-coder/phcoder' Serbinenko wrote:
> What kind of changes was it? Could we make them into some (possibly
> hidden) options?

Well for quite a while the logic was assuming apple powerpc, and it
needed rework to make it work on the IBM powerpc systems.

To some extent I think grub-install as a script is a great source of
info on what steps have to be taken to install grub, so you can do it
manually if something isn't working.

> windows is low priority and more of a bonus. The problems of handling
> anything that looks like a list (e.g. list of devices where / resides on
> in case of btrfs) and code becoming hairy to handle those cases is
> bigger reason.

Sure lists can be a hassle.

I didn't check lately, but does grub-install understand a list of devices
to install to yet?

ie:  grub-install /dev/sda /dev/sdb

After all if I have software raid, both those devices contain /boot and
are valid to boot from.  And since on things like IBM powerpc,
grub-install likes to update the firmware with the list of boot devices,
they do all have to be specified at once or you end up with the wrong
list (which so far I have worked around by manually fixing the firmware
settings after updating grub, which doesn't happen very often lately).

So calling grub-install for each device in turn (as I believe Debian
does on x86 if you tell it multiple boot devices), does not actually
give the correct result.

Of course when grub-install is a script, it is easy to fiddle with it
to make it handle such a case.

So really my main objection is that it is much harder to debug and fix
C code than it is to fix a script calling a bunch of external commands.

At the very least a C version of grub-install must have an option to
list every command it is attempting to execute externally.  Certainly
adding 'set -x' to grub-install has often been helpful.

-- 
Len Sorensen


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

* Re: [RFC] grub-install C rewrite
  2013-09-26 13:35 ` Lennart Sorensen
@ 2013-09-26 13:59   ` Vladimir 'φ-coder/phcoder' Serbinenko
  2013-09-26 14:44     ` Lennart Sorensen
  2013-09-26 17:10   ` Seth Goldberg
  1 sibling, 1 reply; 20+ messages in thread
From: Vladimir 'φ-coder/phcoder' Serbinenko @ 2013-09-26 13:59 UTC (permalink / raw)
  To: The development of GNU GRUB

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

On 26.09.2013 15:35, Lennart Sorensen wrote:
> On Thu, Sep 26, 2013 at 03:08:54PM +0200, Vladimir 'φ-coder/phcoder' Serbinenko wrote:
>> Hello, all. Recently I made some order in hostdisk.c and getroot.c
>> involving splitting in OS-specific parts.
>> In the same time I added WinAPI version of getroot/hostdisk allowing
>> grub-probe to work on windows natively
>> Also on-going is AROS-specific parts.
>> Windows and AROS are not friendly with bash.
>> The attempt to make both multiple files of same type work and handling
>> whitespaces/newlines/... in filenames would result in very ugly code
>> with loads of evals.
>> Current code may have subtle assumptions on behaviour of common tools
>> like sed and on locale (E.g. "[a-z]" doesn't cover u if locale is Estonian).
>> So to check viability I rewrote grub-install in C. This is mostly proof
>> of concept with loads of FIXMEs but I could boot i386-pc install made
>> with it. In many aspects (static variables, some tests, general
>> structure) it's reminiscent of sh version of grub-install it's based on.
>> Some functionality is likely to stay OS-specific, e.g. executing
>> compressors or determining firmware.
>>
>> I'd like to know the opinion of other people on possible switchover. If
>> switched then it'll have to be all grub-install, grub-mkrescue,
>> grub-mknetdir and grub-mkstandalone.
>> I'd like to hear from other people.
> 
> Given the number of times I have had to edit grub-install in the past to
> get it to work right on a powerpc machine (I think it is now working OK),
> I would hate to have had that be C code.  After all it really is mainly
> a wrapper around other grub tools.
> 
What kind of changes was it? Could we make them into some (possibly
hidden) options?
> I think windows not having bash is a rather low priority to most people
> compared to actually be able to work with grub on the platforms where
> it is pretty much the only choice.
> 
windows is low priority and more of a bonus. The problems of handling
anything that looks like a list (e.g. list of devices where / resides on
in case of btrfs) and code becoming hairy to handle those cases is
bigger reason.
> So personally, based on my experience, I hate this idea.
> 



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 291 bytes --]

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

* Re: [RFC] grub-install C rewrite
  2013-09-26 13:08 Vladimir 'φ-coder/phcoder' Serbinenko
@ 2013-09-26 13:35 ` Lennart Sorensen
  2013-09-26 13:59   ` Vladimir 'φ-coder/phcoder' Serbinenko
  2013-09-26 17:10   ` Seth Goldberg
  2013-09-26 14:49 ` Andrey Borzenkov
  2013-10-06 14:54 ` Vladimir 'φ-coder/phcoder' Serbinenko
  2 siblings, 2 replies; 20+ messages in thread
From: Lennart Sorensen @ 2013-09-26 13:35 UTC (permalink / raw)
  To: The development of GNU GRUB

On Thu, Sep 26, 2013 at 03:08:54PM +0200, Vladimir 'φ-coder/phcoder' Serbinenko wrote:
> Hello, all. Recently I made some order in hostdisk.c and getroot.c
> involving splitting in OS-specific parts.
> In the same time I added WinAPI version of getroot/hostdisk allowing
> grub-probe to work on windows natively
> Also on-going is AROS-specific parts.
> Windows and AROS are not friendly with bash.
> The attempt to make both multiple files of same type work and handling
> whitespaces/newlines/... in filenames would result in very ugly code
> with loads of evals.
> Current code may have subtle assumptions on behaviour of common tools
> like sed and on locale (E.g. "[a-z]" doesn't cover u if locale is Estonian).
> So to check viability I rewrote grub-install in C. This is mostly proof
> of concept with loads of FIXMEs but I could boot i386-pc install made
> with it. In many aspects (static variables, some tests, general
> structure) it's reminiscent of sh version of grub-install it's based on.
> Some functionality is likely to stay OS-specific, e.g. executing
> compressors or determining firmware.
> 
> I'd like to know the opinion of other people on possible switchover. If
> switched then it'll have to be all grub-install, grub-mkrescue,
> grub-mknetdir and grub-mkstandalone.
> I'd like to hear from other people.

Given the number of times I have had to edit grub-install in the past to
get it to work right on a powerpc machine (I think it is now working OK),
I would hate to have had that be C code.  After all it really is mainly
a wrapper around other grub tools.

I think windows not having bash is a rather low priority to most people
compared to actually be able to work with grub on the platforms where
it is pretty much the only choice.

So personally, based on my experience, I hate this idea.

-- 
Len Sorensen


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

* [RFC] grub-install C rewrite
@ 2013-09-26 13:08 Vladimir 'φ-coder/phcoder' Serbinenko
  2013-09-26 13:35 ` Lennart Sorensen
                   ` (2 more replies)
  0 siblings, 3 replies; 20+ messages in thread
From: Vladimir 'φ-coder/phcoder' Serbinenko @ 2013-09-26 13:08 UTC (permalink / raw)
  To: The development of GRUB 2


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

Hello, all. Recently I made some order in hostdisk.c and getroot.c
involving splitting in OS-specific parts.
In the same time I added WinAPI version of getroot/hostdisk allowing
grub-probe to work on windows natively
Also on-going is AROS-specific parts.
Windows and AROS are not friendly with bash.
The attempt to make both multiple files of same type work and handling
whitespaces/newlines/... in filenames would result in very ugly code
with loads of evals.
Current code may have subtle assumptions on behaviour of common tools
like sed and on locale (E.g. "[a-z]" doesn't cover u if locale is Estonian).
So to check viability I rewrote grub-install in C. This is mostly proof
of concept with loads of FIXMEs but I could boot i386-pc install made
with it. In many aspects (static variables, some tests, general
structure) it's reminiscent of sh version of grub-install it's based on.
Some functionality is likely to stay OS-specific, e.g. executing
compressors or determining firmware.

I'd like to know the opinion of other people on possible switchover. If
switched then it'll have to be all grub-install, grub-mkrescue,
grub-mknetdir and grub-mkstandalone.
I'd like to hear from other people.

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1.2: install_c.diff --]
[-- Type: text/x-diff; name="install_c.diff", Size: 293476 bytes --]

=== modified file 'Makefile.util.def'
--- Makefile.util.def	2013-09-23 12:09:56 +0000
+++ Makefile.util.def	2013-09-25 17:00:37 +0000
@@ -159,6 +159,7 @@
   mansection = 1;
 
   common = util/grub-mkimage.c;
+  common = util/mkimage.c;
   common = util/resolve.c;
   common = grub-core/kern/emu/argp_common.c;
 
@@ -222,6 +223,7 @@
 
   common = util/grub-mkpasswd-pbkdf2.c;
   common = grub-core/kern/emu/argp_common.c;
+  common = util/random.c;
 
   ldadd = libgrubmods.a;
   ldadd = libgrubgcry.a;
@@ -307,6 +309,7 @@
   installdir = sbin;
   mansection = 8;
   common = util/grub-setup.c;
+  common = util/setup_bios.c;
   common = grub-core/kern/emu/argp_common.c;
   common = grub-core/lib/reed_solomon.c;
 
@@ -315,7 +318,7 @@
   ldadd = libgrubgcry.a;
   ldadd = grub-core/gnulib/libgnu.a;
   ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
-  cppflags = '-DGRUB_SETUP_BIOS=1';
+  cppflags = '-DGRUB_SETUP_FUNC=grub_bios_setup';
 };
 
 program = {
@@ -323,6 +326,7 @@
   installdir = sbin;
   mansection = 8;
   common = util/grub-setup.c;
+  common = util/setup_sparc.c;
   common = grub-core/kern/emu/argp_common.c;
   common = grub-core/lib/reed_solomon.c;
   common = util/ieee1275/ofpath.c;
@@ -332,7 +336,7 @@
   ldadd = libgrubgcry.a;
   ldadd = grub-core/gnulib/libgnu.a;
   ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
-  cppflags = '-DGRUB_SETUP_SPARC64=1';
+  cppflags = '-DGRUB_SETUP_FUNC=grub_sparc_setup';
 };
 
 program = {
@@ -463,14 +467,32 @@
   common = util/grub-mkstandalone.in;
 };
 
-script = {
+program = {
   mansection = 8;
   installdir = sbin;
   name = grub-install;
 
-  common = util/grub-install_header;
-  common = util/grub-install.in;
+  common = util/mkimage.c;
+  common = util/grub-install.c;
+  common = util/grub-install-common.c;
+  common = util/setup_bios.c;
+  common = util/setup_sparc.c;
+  common = grub-core/lib/reed_solomon.c;
+  common = util/random.c;
+  common = util/ieee1275/ofpath.c;
+
+  common = grub-core/kern/arm/dl_helper.c;
+
+  common = util/resolve.c;
   enable = noemu;
+  common = grub-core/kern/emu/argp_common.c;
+
+  ldadd = '$(LIBLZMA)';
+  ldadd = libgrubmods.a;
+  ldadd = libgrubgcry.a;
+  ldadd = libgrubkern.a;
+  ldadd = grub-core/gnulib/libgnu.a;
+  ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
 };
 
 script = {

=== modified file 'grub-core/disk/cryptodisk.c'
--- grub-core/disk/cryptodisk.c	2013-09-23 09:58:19 +0000
+++ grub-core/disk/cryptodisk.c	2013-09-25 02:49:50 +0000
@@ -746,31 +746,33 @@
 }
 
 void
-grub_util_cryptodisk_print_abstraction (grub_disk_t disk)
+grub_util_cryptodisk_get_abstraction (grub_disk_t disk,
+				      void (*cb) (const char *val))
 {
   grub_cryptodisk_t dev = (grub_cryptodisk_t) disk->data;
 
-  grub_printf ("cryptodisk %s ", dev->modname);
+  cb ("cryptodisk");
+  cb (dev->modname);
 
   if (dev->cipher)
-    grub_printf ("%s ", dev->cipher->cipher->modname);
+    cb (dev->cipher->cipher->modname);
   if (dev->secondary_cipher)
-    grub_printf ("%s ", dev->secondary_cipher->cipher->modname);
+    cb (dev->secondary_cipher->cipher->modname);
   if (dev->essiv_cipher)
-    grub_printf ("%s ", dev->essiv_cipher->cipher->modname);
+    cb (dev->essiv_cipher->cipher->modname);
   if (dev->hash)
-    grub_printf ("%s ", dev->hash->modname);
+    cb (dev->hash->modname);
   if (dev->essiv_hash)
-    grub_printf ("%s ", dev->essiv_hash->modname);
+    cb (dev->essiv_hash->modname);
   if (dev->iv_hash)
-    grub_printf ("%s ", dev->iv_hash->modname);
+    cb (dev->iv_hash->modname);
 }
 
-void
-grub_util_cryptodisk_print_uuid (grub_disk_t disk)
+const char *
+grub_util_cryptodisk_get_uuid (grub_disk_t disk)
 {
   grub_cryptodisk_t dev = (grub_cryptodisk_t) disk->data;
-  grub_printf ("%s ", dev->uuid);
+  return dev->uuid;
 }
 
 #endif

=== modified file 'grub-core/disk/diskfilter.c'
--- grub-core/disk/diskfilter.c	2013-09-20 18:37:03 +0000
+++ grub-core/disk/diskfilter.c	2013-09-25 01:49:58 +0000
@@ -353,7 +353,8 @@
 }
 
 void
-grub_diskfilter_print_partmap (grub_disk_t disk)
+grub_diskfilter_get_partmap (grub_disk_t disk,
+			     void (*cb) (const char *pm))
 {
   struct grub_diskfilter_lv *lv = disk->data;
   struct grub_diskfilter_pv *pv;
@@ -375,7 +376,7 @@
 	    continue;
 	  }
 	for (s = 0; pv->partmaps[s]; s++)
-	  grub_printf ("%s ", pv->partmaps[s]);
+	  cb (pv->partmaps[s]);
       }
 }
 

=== modified file 'include/grub/crypto.h'
--- include/grub/crypto.h	2013-08-22 14:03:47 +0000
+++ include/grub/crypto.h	2013-09-25 11:33:34 +0000
@@ -406,6 +406,10 @@
 #ifdef GRUB_UTIL
 void grub_gcry_init_all (void);
 void grub_gcry_fini_all (void);
+
+int
+grub_get_random (void *out, grub_size_t len);
+
 #endif
 
 #endif

=== modified file 'include/grub/cryptodisk.h'
--- include/grub/cryptodisk.h	2013-09-23 09:58:19 +0000
+++ include/grub/cryptodisk.h	2013-09-25 10:37:06 +0000
@@ -144,7 +144,9 @@
 grub_cryptodisk_cheat_insert (grub_cryptodisk_t newdev, const char *name,
 			      grub_disk_t source, const char *cheat);
 void
-grub_util_cryptodisk_print_abstraction (grub_disk_t disk);
+grub_util_cryptodisk_get_abstraction (grub_disk_t disk,
+				      void (*cb) (const char *val));
+
 char *
 grub_util_get_geli_uuid (const char *dev);
 #endif

=== modified file 'include/grub/diskfilter.h'
--- include/grub/diskfilter.h	2013-09-20 18:37:03 +0000
+++ include/grub/diskfilter.h	2013-09-25 10:35:02 +0000
@@ -201,7 +201,8 @@
 grub_diskfilter_get_pv_from_disk (grub_disk_t disk,
 				  struct grub_diskfilter_vg **vg);
 void
-grub_diskfilter_print_partmap (grub_disk_t disk);
+grub_diskfilter_get_partmap (grub_disk_t disk,
+			     void (*cb) (const char *val));
 #endif
 
 #endif /* ! GRUB_RAID_H */

=== modified file 'include/grub/emu/getroot.h'
--- include/grub/emu/getroot.h	2013-09-23 10:06:00 +0000
+++ include/grub/emu/getroot.h	2013-09-25 10:46:19 +0000
@@ -79,6 +79,8 @@
 #include <sys/types.h>
 pid_t
 grub_util_exec_pipe (char **argv, int *fd);
+void
+grub_util_exec (char **argv);
 #endif
 void
 grub_util_pull_lvm_by_command (const char *os_dev);

=== modified file 'include/grub/emu/hostdisk.h'
--- include/grub/emu/hostdisk.h	2013-09-24 17:17:24 +0000
+++ include/grub/emu/hostdisk.h	2013-09-25 10:36:17 +0000
@@ -65,7 +65,8 @@
 ssize_t grub_util_fd_write (grub_util_fd_t fd, const char *buf, size_t len);
 grub_err_t
 grub_cryptodisk_cheat_mount (const char *sourcedev, const char *cheat);
-void grub_util_cryptodisk_print_uuid (grub_disk_t disk);
+const char *
+grub_util_cryptodisk_get_uuid (grub_disk_t disk);
 char *
 grub_util_get_ldm (grub_disk_t disk, grub_disk_addr_t start);
 int

=== added file 'include/grub/util/install.h'
--- include/grub/util/install.h	1970-01-01 00:00:00 +0000
+++ include/grub/util/install.h	2013-09-25 18:25:47 +0000
@@ -0,0 +1,169 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2013  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_UTIL_INSTALL_HEADER
+#define GRUB_UTIL_INSTALL_HEADER	1
+
+#define GRUB_INSTALL_OPTIONS					  \
+  { "modules",      GRUB_INSTALL_OPTIONS_MODULES, N_("MODULES"),	  \
+    0, N_("pre-load specified modules MODULES"), 1 },			  \
+  { "install-modules", GRUB_INSTALL_OPTIONS_INSTALL_MODULES,	  \
+    N_("MODULES"), 0,							  \
+    N_("install only MODULES and their dependencies [default=all]"), 1 }, \
+  { "themes", GRUB_INSTALL_OPTIONS_INSTALL_THEMES, N_("THEMES"),   \
+    0, N_("install THEMES [default=%s]"), 1 },	 		          \
+  { "fonts", GRUB_INSTALL_OPTIONS_INSTALL_FONTS, N_("FONTS"),	  \
+    0, N_("install FONTS [default=%s]"), 1  },	  		          \
+  { "locales", GRUB_INSTALL_OPTIONS_INSTALL_LOCALES, N_("LOCALES"),\
+    0, N_("install only LOCALES [default=all]"), 1 },			  \
+  { "compress", GRUB_INSTALL_OPTIONS_INSTALL_COMPRESS,		  \
+    "no,xz,gz,lzo", OPTION_ARG_OPTIONAL,				  \
+    N_("compress GRUB files [optional]"), 1 },			          \
+    /* TRANSLATORS: platform here isn't identifier. It can be translated. */ \
+  { "directory", 'd', N_("DIR"), 0,					\
+    N_("use images and modules under DIR [default=%s/<platform>]"), 1 },  \
+  { "override-directory", GRUB_INSTALL_OPTIONS_DIRECTORY2,		\
+      N_("DIR"), OPTION_HIDDEN,						\
+    N_("use images and modules under DIR [default=%s/<platform>]"), 1 },  \
+  { "grub-mkimage", GRUB_INSTALL_OPTIONS_GRUB_MKIMAGE,		\
+      0, OPTION_HIDDEN, 0, 1 },						\
+    /* TRANSLATORS: "embed" is a verb (command description).  "*/	\
+  { "pubkey",   'k', N_("FILE"), 0,					\
+      N_("embed FILE as public key for signature checking"), 0}
+
+int
+grub_install_parse (int key, char *arg);
+
+void
+grub_install_push_module (const char *val);
+
+char *
+grub_install_help_filter (int key, const char *text,
+			  void *input __attribute__ ((unused)));
+
+enum grub_install_plat
+  {
+    GRUB_INSTALL_PLATFORM_I386_PC,
+    GRUB_INSTALL_PLATFORM_I386_EFI,
+    GRUB_INSTALL_PLATFORM_I386_QEMU,
+    GRUB_INSTALL_PLATFORM_I386_COREBOOT,
+    GRUB_INSTALL_PLATFORM_I386_MULTIBOOT,
+    GRUB_INSTALL_PLATFORM_I386_IEEE1275,
+    GRUB_INSTALL_PLATFORM_X86_64_EFI,
+    GRUB_INSTALL_PLATFORM_MIPSEL_LOONGSON,
+    GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275,
+    GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275,
+    GRUB_INSTALL_PLATFORM_MIPSEL_ARC,
+    GRUB_INSTALL_PLATFORM_MIPS_ARC,
+    GRUB_INSTALL_PLATFORM_IA64_EFI,
+    GRUB_INSTALL_PLATFORM_ARM_UBOOT,
+    GRUB_INSTALL_PLATFORM_ARM_EFI,
+    GRUB_INSTALL_PLATFORM_MIPSEL_QEMU_MIPS,
+    GRUB_INSTALL_PLATFORM_MIPS_QEMU_MIPS,
+  };
+
+enum grub_install_options {
+  GRUB_INSTALL_OPTIONS_DIRECTORY = 'd',
+  GRUB_INSTALL_OPTIONS_MODULES = 0x201,
+  GRUB_INSTALL_OPTIONS_INSTALL_MODULES,
+  GRUB_INSTALL_OPTIONS_INSTALL_THEMES,
+  GRUB_INSTALL_OPTIONS_INSTALL_FONTS,
+  GRUB_INSTALL_OPTIONS_INSTALL_LOCALES,
+  GRUB_INSTALL_OPTIONS_INSTALL_COMPRESS,
+  GRUB_INSTALL_OPTIONS_DIRECTORY2,
+  GRUB_INSTALL_OPTIONS_GRUB_MKIMAGE
+};
+
+void
+grub_install_args_finish (void);
+
+extern char *grub_install_source_directory;
+
+char *
+grub_install_concat_ext (size_t n, ...);
+char *
+grub_install_concat (size_t n, ...);
+
+enum grub_install_plat
+grub_install_get_target (const char *src);
+void
+grub_install_mkdir_p (const char *dst);
+
+void
+grub_install_copy_files (const char *src,
+			 const char *dst,
+			 enum grub_install_plat platid);
+char *
+grub_install_get_platform_name (enum grub_install_plat platid);
+
+const char *
+grub_install_get_platform_cpu (enum grub_install_plat platid);
+
+const char *
+grub_install_get_platform_platform (enum grub_install_plat platid);
+
+
+typedef enum {
+  GRUB_COMPRESSION_AUTO,
+  GRUB_COMPRESSION_NONE,
+  GRUB_COMPRESSION_XZ,
+  GRUB_COMPRESSION_LZMA
+} grub_compression_t;
+
+void
+grub_install_make_image_wrap (const char *dir, const char *prefix,
+			      const char *outname, char *memdisk_path,
+			      char *config_path,
+			      const char *format, int note,
+			      grub_compression_t comp);
+
+void
+grub_install_copy_file (const char *src,
+			const char *dst);
+
+struct grub_install_image_target_desc;
+
+void
+grub_install_generate_image (const char *dir, const char *prefix,
+			     FILE *out, const char *outname, char *mods[],
+			     char *memdisk_path, char **pubkey_paths,
+			     size_t npubkeys,
+			     char *config_path,
+			     struct grub_install_image_target_desc *image_target, int note,
+			     grub_compression_t comp);
+
+struct grub_install_image_target_desc *
+grub_install_get_image_target (const char *arg);
+void
+grub_bios_setup (const char *dir,
+		 const char *boot_file, const char *core_file,
+		 const char *dest, int force,
+		 int fs_probe, int allow_floppy);
+void
+grub_sparc_setup (const char *dir,
+		  const char *boot_file, const char *core_file,
+		  const char *dest, int force,
+		  int fs_probe, int allow_floppy);
+
+char *
+grub_install_get_image_targets_string (void);
+
+const char *
+grub_util_get_target_dirname (struct grub_install_image_target_desc *t);
+
+#endif

=== modified file 'util/getroot_unix.c'
--- util/getroot_unix.c	2013-09-24 17:19:31 +0000
+++ util/getroot_unix.c	2013-09-25 09:50:46 +0000
@@ -143,6 +143,32 @@
   return path;
 }
 
+void
+grub_util_exec (char **argv)
+{
+  pid_t mdadm_pid;
+
+  mdadm_pid = fork ();
+  if (mdadm_pid < 0)
+    grub_util_error (_("Unable to fork: %s"), strerror (errno));
+  else if (mdadm_pid == 0)
+    {
+      /* Child.  */
+
+      /* Close fd's.  */
+      grub_util_devmapper_cleanup ();
+      grub_diskfilter_fini ();
+
+      /* Ensure child is not localised.  */
+      setenv ("LC_ALL", "C", 1);
+
+      execvp (argv[0], argv);
+      exit (127);
+    }
+  else
+    return;
+}
+
 pid_t
 grub_util_exec_pipe (char **argv, int *fd)
 {

=== added file 'util/grub-install-common.c'
--- util/grub-install-common.c	1970-01-01 00:00:00 +0000
+++ util/grub-install-common.c	2013-09-25 21:51:40 +0000
@@ -0,0 +1,796 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010,2011,2012,2013 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 <config.h>
+#include <grub/types.h>
+#include <grub/emu/misc.h>
+#include <grub/util/misc.h>
+#include <grub/misc.h>
+#include <grub/device.h>
+#include <grub/disk.h>
+#include <grub/file.h>
+#include <grub/fs.h>
+#include <grub/env.h>
+#include <grub/term.h>
+#include <grub/mm.h>
+#include <grub/lib/hexdump.h>
+#include <grub/crypto.h>
+#include <grub/command.h>
+#include <grub/i18n.h>
+#include <grub/zfs/zfs.h>
+#include <grub/util/install.h>
+#include <grub/util/resolve.h>
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <dirent.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+char *
+grub_install_help_filter (int key, const char *text,
+				 void *input __attribute__ ((unused)))
+{
+  switch (key)
+    {
+    case GRUB_INSTALL_OPTIONS_INSTALL_THEMES:
+      return xasprintf(text, "starfield");
+    case GRUB_INSTALL_OPTIONS_INSTALL_FONTS:
+      return xasprintf(text, "unicode");
+    case GRUB_INSTALL_OPTIONS_DIRECTORY:
+    case GRUB_INSTALL_OPTIONS_DIRECTORY2:
+      return xasprintf(text, GRUB_LIBDIR PACKAGE);      
+    default:
+      return (char *) text;
+    }
+}
+
+static char **compress_argv;
+static char *copy_buf;
+
+#define COPY_BUF_SIZE 1048576
+
+static char *
+grub_install_concat_real (size_t n, int ext, va_list ap)
+{
+  size_t totlen = 0;
+  char **l = xmalloc ((n + ext) * sizeof (l[0]));
+  char *r, *p, *pi;
+  size_t i;
+  int first = 1;
+
+  for (i = 0; i < n + ext; i++)
+    {
+      l[i] = va_arg (ap, char *);
+      if (l[i])
+	totlen += strlen (l[i]) + 1;
+    }
+
+  r = xmalloc (totlen + 10);
+
+  p = r;
+  for (i = 0; i < n; i++)
+    {
+      pi = l[i];
+      if (!pi)
+	continue;
+      while (*pi == '/')
+	pi++;
+      if (p != r || (pi != l[i] && first))
+	*p++ = '/';
+      first = 0;
+      p = stpcpy (p, l[i]);
+      while (p != r && *(p - 1) == '/')
+	p--;
+    }
+
+  if (ext && l[i])
+    p = stpcpy (p, l[i]);
+
+  *p = '\0';
+
+  free (l);
+
+  return r;
+}
+
+char *
+grub_install_concat (size_t n, ...)
+{
+  va_list ap;
+  char *r;
+
+  va_start (ap, n);
+
+  r = grub_install_concat_real (n, 0, ap);
+
+  va_end (ap);
+
+  return r;
+}
+
+char *
+grub_install_concat_ext (size_t n, ...)
+{
+  va_list ap;
+  char *r;
+
+  va_start (ap, n);
+
+  r = grub_install_concat_real (n, 1, ap);
+
+  va_end (ap);
+
+  return r;
+}
+
+void
+grub_install_copy_file (const char *src,
+			 const char *dst)
+{
+  FILE *in, *out;
+  in = fopen (src, "rb");
+  if (!in)
+    {
+      grub_util_warn (_("cannot open `%s': %s"), src, strerror (errno));
+      return;
+    }
+  out = fopen (dst, "wb");
+  if (!out)
+    {
+      grub_util_warn (_("cannot open `%s': %s"), dst, strerror (errno));
+      fclose (in);
+      return;
+    }
+
+  if (!copy_buf)
+    copy_buf = xmalloc (COPY_BUF_SIZE);
+ 
+  while (1)
+    {
+      size_t r;
+      r = fread (copy_buf, 1, COPY_BUF_SIZE, in);
+      if (r == 0)
+	break;
+      fwrite (copy_buf, 1, r, out);
+    }
+  return;
+}
+
+int
+grub_install_compress_file (const char *in_name,
+				   const char *out_name,
+				   int is_needed)
+{
+  FILE *in, *out;
+  in = fopen (in_name, "rb");
+  if (!in && !is_needed && errno == ENOENT)
+    return 0;
+  if (!in)
+    {
+      grub_util_warn (_("cannot open `%s': %s"), in_name, strerror (errno));
+      return 0;
+    }
+  out = fopen (out_name, "wb");
+  if (!out)
+    {
+      grub_util_warn (_("cannot open `%s': %s"), out_name, strerror (errno));
+      fclose (in);
+      return 0;
+    }
+
+  if (!copy_buf)
+    copy_buf = xmalloc (COPY_BUF_SIZE);
+
+  if (compress_argv)
+    {
+      /* FIXME.  */ 
+      return 1;
+    }
+
+  while (1)
+    {
+      size_t r;
+      r = fread (copy_buf, 1, COPY_BUF_SIZE, in);
+      if (r == 0)
+	break;
+      fwrite (copy_buf, 1, r, out);
+    }
+  return 1;
+}
+
+static int
+is_path_separator (char c)
+{
+#if defined (__MINGW32__) || defined (__CYGWIN__)
+  if (c == '\\')
+    return 1;
+#endif
+  if (c == '/')
+    return 1;
+  return 0;
+}
+
+void
+grub_install_mkdir_p (const char *dst)
+{
+  char *t = xstrdup (dst);
+  char *p;
+  for (p = t; *p; p++)
+    {
+      if (is_path_separator (*p))
+	{
+	  char s = *p;
+	  *p = '\0';
+	  mkdir (t, 0700);
+	  *p = s;
+	}
+    }
+  mkdir (t, 0700);
+}
+
+static void
+clean_grub_dir (const char *di)
+{
+  DIR *d;
+  struct dirent *de;
+
+  d = opendir (di);
+  if (!d)
+    grub_util_error (_("cannot open directory `%s': %s"),
+		     di, strerror (errno));
+
+  while ((de = readdir (d)))
+    {
+      const char *ext = strrchr (de->d_name, '.');
+      if ((ext && (strcmp (ext, ".mod") == 0
+		   || strcmp (ext, ".lst") == 0
+		   || strcmp (ext, ".img") == 0
+		   || strcmp (ext, ".mo") == 0)
+	   && strcmp (de->d_name, "menu.lst") != 0)
+	  || strcmp (de->d_name, "efiemu32.o") == 0
+	  || strcmp (de->d_name, "efiemu64.o") == 0)
+	{
+	  char *x = grub_install_concat (2, di, de->d_name);
+	  if (unlink (x) < 0)
+	    grub_util_error ("cannont delete `%s': %s", x, strerror (errno));
+	  free (x);
+	}
+    }
+  closedir (d);
+}
+
+struct install_list
+{
+  int is_default;
+  char **entries;
+  size_t n_entries;
+  size_t n_alloc;
+};
+
+struct install_list install_modules = { 1, 0, 0, 0 };
+struct install_list modules = { 1, 0, 0, 0 };
+struct install_list install_locales = { 1, 0, 0, 0 };
+struct install_list install_fonts = { 1, 0, 0, 0 };
+struct install_list install_themes = { 1, 0, 0, 0 };
+char *grub_install_source_directory = NULL;
+
+void
+grub_install_push_module (const char *val)
+{
+  modules.is_default = 0;
+  if (modules.n_entries + 1 >= modules.n_alloc)
+    {
+      modules.n_alloc <<= 1;
+      if (modules.n_alloc < 16)
+	modules.n_alloc = 16;
+      modules.entries = xrealloc (modules.entries,
+				  modules.n_alloc * sizeof (modules.entries));
+    }
+  modules.entries[modules.n_entries++] = xstrdup (val);
+  modules.entries[modules.n_entries] = NULL;
+}
+
+static void
+handle_install_list (struct install_list *il, const char *val,
+		     int default_all)
+{
+  const char *ptr;
+  char **ce;
+  il->is_default = 0;
+  free (il->entries);
+  il->entries = NULL;
+  il->n_entries = 0;
+  if (strcmp (val, "all") == 0 && default_all)
+    {
+      il->is_default = 1;
+      return;
+    }
+  ptr = val;
+  while (1)
+    {
+      while (*ptr && grub_isspace (*ptr))
+	ptr++;
+      if (!*ptr)
+	break;
+      while (*ptr && !grub_isspace (*ptr))
+	ptr++;
+      il->n_entries++;
+    }
+  il->n_alloc = il->n_entries + 1;
+  il->entries = xmalloc (il->n_alloc * sizeof (il->entries[0]));
+  for (ce = il->entries; ; ce++)
+    {
+      const char *bptr;
+      while (*ptr && grub_isspace (*ptr))
+	ptr++;
+      if (!*ptr)
+	break;
+      bptr = ptr;
+      while (*ptr && !grub_isspace (*ptr))
+	ptr++;
+      *ce = xmalloc (ptr - bptr + 1);
+      memcpy (*ce, bptr, ptr - bptr);
+      (*ce)[ptr - bptr] = '\0';
+      ce++;
+    }
+  *ce = NULL;
+}
+
+static char *compress_gzip[] = { (char *) "gzip", (char *) "--best",
+				 (char *) "--stdout", NULL };
+static char *compress_xz[] = { (char *) "xz",
+			       (char *) "--lzma2=dict=128KiB",
+			       (char *) "--check=none",
+			     (char *) "--stdout", NULL };
+static char *compress_lzo[] = {(char *) "lzop",
+			       (char *) "-9", 
+			       (char *) "-c", NULL };
+static char **pubkeys;
+static size_t npubkeys;
+
+int
+grub_install_parse (int key, char *arg)
+{
+  switch (key)
+    {
+    case 'k':
+      pubkeys = xrealloc (pubkeys,
+			  sizeof (pubkeys[0])
+			  * (npubkeys + 1));
+      pubkeys[npubkeys++] = xstrdup (arg);
+      return 1;
+
+    case GRUB_INSTALL_OPTIONS_DIRECTORY:
+    case GRUB_INSTALL_OPTIONS_DIRECTORY2:
+      free (grub_install_source_directory);
+      grub_install_source_directory = xstrdup (arg);
+      return 1;
+    case GRUB_INSTALL_OPTIONS_MODULES:
+      handle_install_list (&install_modules, arg, 0);
+      return 1;
+    case GRUB_INSTALL_OPTIONS_INSTALL_LOCALES:
+      handle_install_list (&install_locales, arg, 0);
+      return 1;
+    case GRUB_INSTALL_OPTIONS_INSTALL_THEMES:
+      handle_install_list (&install_themes, arg, 0);
+      return 1;
+    case GRUB_INSTALL_OPTIONS_INSTALL_FONTS:
+      handle_install_list (&install_fonts, arg, 0);
+      return 1;
+    case GRUB_INSTALL_OPTIONS_INSTALL_COMPRESS:
+      if (strcmp (arg, "no") == 0)
+	{
+	  compress_argv = NULL;
+	  return 1;
+	}
+      if (strcmp (arg, "gz") == 0)
+	{
+	  compress_argv = compress_gzip;
+	  return 1;
+	}
+      if (strcmp (arg, "xz") == 0)
+	{
+	  compress_argv = compress_xz;
+	  return 1;
+	}
+      if (strcmp (arg, "lzo") == 0)
+	{
+	  compress_argv = compress_lzo;
+	  return 1;
+	}
+      grub_util_error (_("Unrecognized compression `%s'"), arg);
+    case GRUB_INSTALL_OPTIONS_GRUB_MKIMAGE:
+      return 1;
+    default:
+      return 0;
+    }
+}
+
+void
+grub_install_args_finish (void)
+{
+  if (compress_argv == compress_gzip)
+    grub_install_push_module ("gzio");
+  if (compress_argv == compress_xz)
+    {
+      grub_install_push_module ("xzio");
+      grub_install_push_module ("gcry_crc");
+    }
+  if (compress_argv == compress_lzo)
+    {
+      grub_install_push_module ("lzopio");
+      grub_install_push_module ("adler32");
+      grub_install_push_module ("gcry_crc");
+    }
+}
+
+void
+grub_install_make_image_wrap (const char *dir, const char *prefix,
+			      const char *outname, char *memdisk_path,
+			      char *config_path,
+			      const char *mkimage_target, int note,
+			      grub_compression_t comp)
+{
+  FILE *fp = stdout;
+  struct grub_install_image_target_desc *tgt;
+  fp = fopen (outname, "wb");
+  if (! fp)
+    grub_util_error (_("cannot open `%s': %s"), outname,
+		     strerror (errno));
+  tgt = grub_install_get_image_target (mkimage_target);
+  if (!tgt)
+    grub_util_error (_("unknown target format %s\n"), mkimage_target);
+
+
+
+  grub_install_generate_image (dir, prefix, fp, outname,
+			       modules.entries, memdisk_path,
+			       pubkeys, npubkeys, config_path, tgt,
+			       note, comp);
+  fflush (fp);
+  fsync (fileno (fp));
+  fclose (fp);
+}
+
+static void
+copy_by_ext (const char *srcd,
+	     const char *dstd,
+	     const char *extf,
+	     int req)
+{
+  DIR *d;
+  struct dirent *de;
+
+  d = opendir (srcd);
+  if (!d && !req)
+    return;
+  if (!d)
+    grub_util_error (_("cannot open directory `%s': %s"),
+		     srcd, strerror (errno));
+
+  while ((de = readdir (d)))
+    {
+      const char *ext = strrchr (de->d_name, '.');
+      if (ext && strcmp (ext, extf) == 0)
+	{
+	  char *srcf = grub_install_concat (2, srcd, de->d_name);
+	  char *dstf = grub_install_concat (2, dstd, de->d_name);
+	  grub_install_compress_file (srcf, dstf, 1);
+	  free (srcf);
+	  free (dstf);
+	}
+    }
+  closedir (d);
+}
+
+static void
+copy_all (const char *srcd,
+	     const char *dstd)
+{
+  DIR *d;
+  struct dirent *de;
+
+  d = opendir (srcd);
+  if (!d)
+    grub_util_error (_("cannot open directory `%s': %s"),
+		     srcd, strerror (errno));
+
+  while ((de = readdir (d)))
+    {
+      char *srcf = grub_install_concat (2, srcd, de->d_name);
+      char *dstf = grub_install_concat (2, dstd, de->d_name);
+      grub_install_compress_file (srcf, dstf, 1);
+      free (srcf);
+      free (dstf);
+    }
+  closedir (d);
+}
+
+static void
+copy_locales (const char *dstd)
+{
+  DIR *d;
+  struct dirent *de;
+
+  d = opendir (LOCALEDIR);
+  if (!d)
+    grub_util_error (_("cannot open directory `%s': %s"),
+		     LOCALEDIR, strerror (errno));
+
+  while ((de = readdir (d)))
+    {
+      /* FIXME: use concat */
+      char *srcf = grub_install_concat_ext (3, LOCALEDIR, de->d_name,
+						   PACKAGE, ".mo");
+      char *dstf = grub_install_concat_ext (2, dstd, de->d_name, ".mo");
+      grub_install_compress_file (srcf, dstf, 0);
+      free (srcf);
+      free (dstf);
+    }
+  closedir (d);
+}
+
+static struct
+{
+  enum grub_install_plat val;
+  const char *cpu;
+  const char *platform;
+} platforms[] =
+  {
+    { GRUB_INSTALL_PLATFORM_I386_PC,          "i386",    "pc"        },
+    { GRUB_INSTALL_PLATFORM_I386_EFI,         "i386",    "efi"       },
+    { GRUB_INSTALL_PLATFORM_I386_QEMU,        "i386",    "qemu"      },
+    { GRUB_INSTALL_PLATFORM_I386_COREBOOT,    "i386",    "coreboot"  },
+    { GRUB_INSTALL_PLATFORM_I386_MULTIBOOT,   "i386",    "multiboot" },
+    { GRUB_INSTALL_PLATFORM_I386_IEEE1275,    "i386",    "ieee1275"  },
+    { GRUB_INSTALL_PLATFORM_X86_64_EFI,       "x86_64",  "efi"       },
+    { GRUB_INSTALL_PLATFORM_MIPSEL_LOONGSON,  "mipsel",  "loongson"  },
+    { GRUB_INSTALL_PLATFORM_MIPSEL_QEMU_MIPS, "mipsel",  "qemu_mips" },
+    { GRUB_INSTALL_PLATFORM_MIPS_QEMU_MIPS,   "mips",    "qemu_mips" },
+    { GRUB_INSTALL_PLATFORM_MIPSEL_ARC,       "mipsel",  "arc"       },
+    { GRUB_INSTALL_PLATFORM_MIPS_ARC,         "mips",    "arc"       },
+    { GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275, "sparc64", "ieee1275"  },
+    { GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275, "powerpc", "ieee1275"  },
+    { GRUB_INSTALL_PLATFORM_IA64_EFI,         "ia64",    "efi"       },
+    { GRUB_INSTALL_PLATFORM_ARM_EFI,          "arm",     "efi"       },
+    { GRUB_INSTALL_PLATFORM_ARM_UBOOT,        "arm",     "uboot"     },
+  }; 
+
+char *
+grub_install_get_platform_name (enum grub_install_plat platid)
+{
+  return xasprintf ("%s-%s", platforms[platid].cpu,
+		    platforms[platid].platform);
+}
+
+const char *
+grub_install_get_platform_cpu (enum grub_install_plat platid)
+{
+  return platforms[platid].cpu;
+}
+
+const char *
+grub_install_get_platform_platform (enum grub_install_plat platid)
+{
+  return platforms[platid].platform;
+}
+
+static int
+is_regular_file (const char *dir)
+{
+  /* FIXME */
+  (void) dir;
+  return 0;
+}
+
+void
+grub_install_copy_files (const char *src,
+			 const char *dst,
+			 enum grub_install_plat platid)
+{
+  char *dst_platform, *dst_locale, *dst_fonts;
+  char *platform = xasprintf ("%s-%s", platforms[platid].cpu,
+			      platforms[platid].platform);
+  const char *pkgdatadir = secure_getenv ("pkgdatadir");
+  if (!pkgdatadir)
+    /* FIXME */
+    pkgdatadir = "@pkgdatadir@";
+
+  dst_platform = grub_install_concat (2, dst, platform);
+  dst_locale = grub_install_concat (2, dst, "locale");
+  dst_fonts = grub_install_concat (2, dst, "fonts");
+  grub_install_mkdir_p (dst_platform);
+  grub_install_mkdir_p (dst_locale);
+  clean_grub_dir (dst);
+  clean_grub_dir (dst_platform);
+  clean_grub_dir (dst_locale);
+
+  if (install_modules.is_default)
+    copy_by_ext (src, dst_platform, ".mod", 1);
+  else
+    {
+      struct grub_util_path_list *path_list, *p;
+
+      path_list = grub_util_resolve_dependencies (src, "moddep.lst",
+						  install_modules.entries);
+      for (p = path_list; p; p = p->next)
+	{
+	  /* FIXME: use concat */
+	  char *srcf = grub_install_concat_ext (2, src, p->name, ".mo");
+	  char *dstf = grub_install_concat_ext (2, dst, p->name, ".mo");
+	  grub_install_compress_file (srcf, dstf, 1);
+	  free (srcf);
+	  free (dstf);
+	}
+    }
+
+  const char *pkglib_DATA[] = {"efiemu32.o", "efiemu64.o",
+			       "moddep.lst", "command.lst",
+			       "fs.lst", "partmap.lst",
+			       "parttool.lst",
+			       "video.lst", "crypto.lst",
+			       "terminal.lst" };
+  size_t i;
+
+  for (i = 0; i < ARRAY_SIZE (pkglib_DATA); i++)
+    {
+      /* FIXME: use concat  */
+      char *srcf = grub_install_concat (2, src, pkglib_DATA[i]);
+      char *dstf = grub_install_concat (2, dst_platform, pkglib_DATA[i]);
+      if (i == 0 || i == 1)
+	grub_install_compress_file (srcf, dstf, 0);
+      else
+	grub_install_compress_file (srcf, dstf, 1);
+      free (srcf);
+      free (dstf);
+    }
+
+  if (install_locales.is_default)
+    {
+      char *srcd = grub_install_concat (2, src, "po");
+      copy_by_ext (srcd, dst_locale, ".mo", 0);
+      copy_locales (dst_locale);
+      free (srcd);
+    }
+  else
+    {
+      for (i = 0; i < install_locales.n_entries; i++)
+	{
+	  char *srcf = grub_install_concat_ext (3, src,
+						"po",
+						install_locales.entries[i],
+						".mo");
+	  char *dstf = grub_install_concat_ext (2, dst_locale,
+						install_locales.entries[i],
+						".mo");
+	  if (grub_install_compress_file (srcf, dstf, 0))
+	    {
+	      free (srcf);
+	      free (dstf);
+	      continue;
+	    }
+	  free (srcf);
+	  srcf = grub_install_concat_ext (4,
+						 LOCALEDIR,
+						 install_locales.entries[i],
+						 "LC_MESSAGES",
+						 PACKAGE,
+						 ".mo");
+	  if (grub_install_compress_file (srcf, dstf, 0))
+	    {
+	      free (srcf);
+	      free (dstf);
+	      continue;
+	    }
+	  grub_util_error (_("cannot find locale `%s'"),
+			   install_locales.entries[i]);
+	}
+    }
+
+  if (install_themes.is_default)
+    {
+      install_themes.is_default = 0;
+      install_themes.n_entries = 1;
+      install_themes.entries = xmalloc (2 * sizeof (install_themes.entries[0]));
+      install_themes.entries[0] = xstrdup ("starfield");
+      install_themes.entries[1] = NULL;
+    }
+
+  for (i = 0; i < install_themes.n_entries; i++)
+    {
+      char *srcf = grub_install_concat (4, pkgdatadir, "themes",
+					install_themes.entries[i],
+					"theme.txt");
+      if (is_regular_file (srcf))
+	{
+	  char *srcd = grub_install_concat (3, pkgdatadir, "themes",
+					    install_themes.entries[i]);
+	  char *dstd = grub_install_concat (3, dst, "themes",
+					    install_themes.entries[i]);
+	  copy_all (srcd, dstd);
+	  free (srcd);
+	  free (dstd);
+	}
+    }
+
+  if (install_fonts.is_default)
+    {
+      install_fonts.is_default = 0;
+      install_fonts.n_entries = 1;
+      install_fonts.entries = xmalloc (2 * sizeof (install_fonts.entries[0]));
+      install_fonts.entries[0] = xstrdup ("unicode");
+      install_fonts.entries[1] = NULL;
+    }
+
+  for (i = 0; i < install_fonts.n_entries; i++)
+    {
+      char *srcf = grub_install_concat_ext (2, pkgdatadir,
+						   install_fonts.entries[i],
+						   ".pf2");
+      char *dstf = grub_install_concat_ext (2, dst_fonts,
+						   install_fonts.entries[i],
+						   ".pf2");
+
+      grub_install_compress_file (srcf, dstf, 0);
+      free (srcf);
+      free (dstf);
+    }
+}
+
+enum grub_install_plat
+grub_install_get_target (const char *src)
+{
+  char *fn;
+  FILE *f;
+  char buf[2048];
+  size_t r;
+  char *c, *pl, *p;
+  size_t i;
+  fn = grub_install_concat (2, src, "modinfo.sh");
+  f = fopen (fn, "r");
+  if (!f)
+    grub_util_error (_("%s doesn't exist. Please specify --target or --directory"), 
+		     fn);
+  r = fread (buf, 1, sizeof (buf) - 1, f);
+  buf[r] = '\0';
+  c = strstr (buf, "grub_modinfo_target_cpu=");
+  if (!c || (c != buf && !grub_isspace (*(c-1))))
+    grub_util_error (_("invalid modinfo file `%s'"), fn);
+  pl = strstr (buf, "grub_modinfo_platform=");
+  if (!pl || (pl != buf && !grub_isspace (*(pl-1))))
+    grub_util_error (_("invalid modinfo file `%s'"), fn);
+  c += sizeof ("grub_modinfo_target_cpu=") - 1;
+  pl += sizeof ("grub_modinfo_platform=") - 1;
+  for (p = c; *p && !grub_isspace (*p); p++);
+  *p = '\0';
+  for (p = pl; *p && !grub_isspace (*p); p++);
+  *p = '\0';
+
+  for (i = 0; i < ARRAY_SIZE (platforms); i++)
+    if (strcmp (platforms[i].cpu, c) == 0
+	&& strcmp (platforms[i].platform, pl) == 0)
+      return platforms[i].val;
+  grub_util_error (_("Unknown platform `%s-%s'"), c, pl);
+}

=== added file 'util/grub-install.c'
--- util/grub-install.c	1970-01-01 00:00:00 +0000
+++ util/grub-install.c	2013-09-25 21:59:57 +0000
@@ -0,0 +1,1469 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010,2011,2012,2013 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 <config.h>
+#include <grub/types.h>
+#include <grub/emu/misc.h>
+#include <grub/util/misc.h>
+#include <grub/misc.h>
+#include <grub/device.h>
+#include <grub/disk.h>
+#include <grub/file.h>
+#include <grub/fs.h>
+#include <grub/env.h>
+#include <grub/term.h>
+#include <grub/mm.h>
+#include <grub/lib/hexdump.h>
+#include <grub/crypto.h>
+#include <grub/command.h>
+#include <grub/i18n.h>
+#include <grub/zfs/zfs.h>
+#include <grub/util/install.h>
+#include <grub/emu/getroot.h>
+#include <grub/diskfilter.h>
+#include <grub/cryptodisk.h>
+#include <grub/legacy_parse.h>
+
+#include <string.h>
+
+#include "argp.h"
+
+#include "progname.h"
+
+static char *target;
+static int removable = 0;
+static int recheck = 0;
+static int update_nvram = 1;
+static char *install_device = NULL;
+static char *debug_image = NULL;
+static char *rootdir = NULL;
+static char *bootdir = NULL;
+static int efi_quiet = 0;
+static int allow_floppy = 0;
+static int force_file_id = 0;
+static char *disk_module = NULL;
+static char *efidir = NULL;
+static int force = 0;
+static int have_abstractions = 0;
+static char * bootloader_id;
+static int have_load_cfg = 0;
+static FILE * load_cfg_f = NULL;
+static char *load_cfg;
+
+enum
+  {
+    OPTION_BOOT_DIRECTORY = 0x301,
+    OPTION_ROOT_DIRECTORY,
+    OPTION_TARGET,
+    OPTION_SETUP,
+    OPTION_MKRELPATH, 
+    OPTION_MKDEVICEMAP, 
+    OPTION_PROBE, 
+    OPTION_EDITENV, 
+    OPTION_ALLOW_FLOPPY, 
+    OPTION_RECHECK, 
+    OPTION_FORCE,
+    OPTION_FORCE_FILE_ID,
+    OPTION_MODULE, 
+    OPTION_NO_NVRAM, 
+    OPTION_REMOVABLE, 
+    OPTION_BOOTLOADER_ID, 
+    OPTION_EFI_DIRECTORY,
+    OPTION_FONT,
+    OPTION_DEBUG,
+    OPTION_DEBUG_IMAGE,
+    OPTION_NO_FLOPPY,
+    OPTION_DISK_MODULE
+  };
+
+static error_t 
+argp_parser (int key, char *arg, struct argp_state *state)
+{
+  if (grub_install_parse (key, arg))
+    return 0;
+  switch (key)
+    {
+    case OPTION_FORCE_FILE_ID:
+      force_file_id = 1;
+      return 0;
+      /* Accept and ignore for compatibility.  */
+    case OPTION_FONT:
+    case OPTION_SETUP:
+    case OPTION_MKRELPATH:
+    case OPTION_PROBE:
+    case OPTION_EDITENV:
+    case OPTION_MKDEVICEMAP:
+    case OPTION_NO_FLOPPY:
+      return 0;
+    case OPTION_ROOT_DIRECTORY:
+      /* Accept for compatibility.  */
+      free (rootdir);
+      rootdir = xstrdup (arg);
+      return 0;
+
+    case OPTION_BOOT_DIRECTORY:
+      free (bootdir);
+      bootdir = xstrdup (arg);
+      return 0;
+
+    case OPTION_EFI_DIRECTORY:
+      free (efidir);
+      efidir = xstrdup (arg);
+      return 0;
+
+    case OPTION_DISK_MODULE:
+      free (disk_module);
+      disk_module = xstrdup (arg);
+      return 0;
+
+    case OPTION_TARGET:
+      free (target);
+      target = xstrdup (arg);
+      return 0;
+
+    case OPTION_DEBUG_IMAGE:
+      free (debug_image);
+      debug_image = xstrdup (arg);
+      return 0;
+
+    case OPTION_NO_NVRAM:
+      update_nvram = 0;
+      return 0;
+
+    case OPTION_FORCE:
+      force = 0;
+      return 0;
+
+    case OPTION_RECHECK:
+      recheck = 1;
+      return 0;
+
+    case OPTION_REMOVABLE:
+      removable = 1;
+      return 0;
+
+    case OPTION_ALLOW_FLOPPY:
+      allow_floppy = 1;
+      return 0;
+
+    case OPTION_DEBUG:
+      verbosity++;
+      return 0;
+
+    case OPTION_BOOTLOADER_ID:
+      free (bootloader_id);
+      bootloader_id = xstrdup (arg);
+      return 0;
+
+    case ARGP_KEY_ARG:
+      if (install_device)
+	grub_util_error ("%s", _("More than one install device?"));
+      install_device = xstrdup (arg);
+      return 0;
+
+    default:
+      return ARGP_ERR_UNKNOWN;
+    }
+}
+
+
+static struct argp_option options[] = {
+  GRUB_INSTALL_OPTIONS,
+  {"boot-directory", OPTION_BOOT_DIRECTORY, N_("DIR"),
+   0, N_("install GRUB images under the directory DIR/%s instead of the %s directory"), 2},
+  {"root-directory", OPTION_ROOT_DIRECTORY, N_("DIR"),
+   OPTION_HIDDEN, 0, 2},
+  {"font", OPTION_FONT, N_("FILE"),
+   OPTION_HIDDEN, 0, 2},
+  {"target", OPTION_TARGET, N_("TARGET"),
+   /* TRANSLATORS: "TARGET" as in "target platform".  */
+   0, N_("install GRUB for TARGET platform [default=%s]"), 2},
+  {"grub-setup", OPTION_SETUP, N_("FILE"), OPTION_HIDDEN, 0, 2},
+  {"grub-mkrelpath", OPTION_MKRELPATH, N_("FILE"), OPTION_HIDDEN, 0, 2},
+  {"grub-mkdevicemap", OPTION_MKDEVICEMAP, N_("FILE"), OPTION_HIDDEN, 0, 2},
+  {"grub-probe", OPTION_PROBE, N_("FILE"), OPTION_HIDDEN, 0, 2},
+  {"grub-editenv", OPTION_EDITENV, N_("FILE"), OPTION_HIDDEN, 0, 2},
+  {"allow-floppy", OPTION_ALLOW_FLOPPY, 0, 0,
+   /* TRANSLATORS: "may break" doesn't just mean that option wouldn't have any
+      effect but that it will make the resulting install unbootable from HDD. */
+   N_("make the drive also bootable as floppy (default for fdX devices)."
+      " May break on some BIOSes."), 2},
+  {"recheck", OPTION_RECHECK, 0, 0,
+   N_("delete device map if it already exists"), 2},
+  {"force", OPTION_FORCE, 0, 0,
+   N_("install even if problems are detected"), 2},
+  {"force-file-id", OPTION_FORCE_FILE_ID, 0, 0,
+   N_("use identifier file even if UUID is available"), 2},
+  {"disk-module", OPTION_MODULE, N_("MODULE"), 0,
+   N_("disk module to use (biosdisk or native). "
+      "This option is only available on BIOS target."), 2},
+  {"no-nvram", OPTION_NO_NVRAM, 0, 0,
+   N_("don't update the `boot-device' NVRAM variable. "
+      "This option is only available on IEEE1275 targets."), 2},
+
+  {"debug", OPTION_DEBUG, 0, OPTION_HIDDEN, 0, 2},
+  {"no-floppy", OPTION_NO_FLOPPY, 0, OPTION_HIDDEN, 0, 2},
+  {"debug-image", OPTION_DEBUG_IMAGE, "STR", OPTION_HIDDEN, 0, 2},
+  {"removable", OPTION_REMOVABLE, 0, 0,
+   N_("the installation device is removable. "
+      "This option is only available on EFI."), 2},
+  {"bootloader-id", OPTION_BOOTLOADER_ID, N_("ID"), 0,
+   N_("the ID of bootloader. This option is only available on EFI."), 2},
+  {"efi-directory", OPTION_EFI_DIRECTORY, N_("DIR"), 0,
+   N_("use DIR as the EFI System Partition root."), 2},
+  {0, 0, 0, 0, 0, 0}
+};
+
+static int
+is_directory (const char *dir)
+{
+  /* FIXME */
+  (void) dir;
+  return 0;
+}
+
+#ifdef __linux__
+static int
+is_not_empty_directory (const char *dir)
+{
+  /* FIXME */
+  (void) dir;
+  return 0;
+}
+
+static int
+is_64_kernel (void)
+{
+  /* FIXME */
+  return 0;
+}
+
+#endif
+
+static const char *
+get_default_platform (void)
+{
+#ifdef __powerpc__
+   return "powerpc-ieee1275";
+#elif defined (__sparc__) || defined (__sparc64__)
+   return "sparc64-ieee1275";
+#elif defined (__MIPSEL__)
+   return "mipsel-loongson";
+#elif defined (__MIPSEB__)
+   return "mips-arc";
+#elif defined (__ia64__)
+   return "ia64-efi";
+#elif defined (__arm__)
+   return "arm-uboot";
+#elif defined (__amd64__) || defined (__x86_64__) || defined (__i386__)
+   /*
+     On Linux, we need the efivars kernel modules.
+     If no EFI is available this module just does nothing
+     besides a small hello and if we detect efi we'll load it
+     anyway later. So it should be safe to
+     try to load it here.
+   */
+#ifdef __linux__
+   grub_util_exec ((char * []){ (char *) "modprobe", (char *) "-q",
+	 (char *) "efivars", NULL });
+#endif
+   if (is_not_empty_directory ("/sys/firmware/efi"))
+     {
+       if (is_64_kernel ())
+	 return "x86_64-efi";
+       else
+	 return "i386-efi";
+     }
+   else if (is_not_empty_directory ("/proc/device-tree"))
+     return "i386-ieee1275";
+   else
+     return "i386-pc";
+#else
+   return NULL;
+#endif
+}
+
+static char *
+help_filter (int key, const char *text, void *input __attribute__ ((unused)))
+{
+  switch (key)
+    {
+    case OPTION_BOOT_DIRECTORY:
+      /* FIXME */
+      return xasprintf (text, "@grubdirname@", "$grubdir");
+    case OPTION_TARGET:
+      return xasprintf (text, get_default_platform ());
+    case ARGP_KEY_HELP_POST_DOC:
+      /* FIXME */
+      return xasprintf (text, program_name, "$grubdir");
+    default:
+      return grub_install_help_filter (key, text, input);
+    }
+}
+
+/* TRANSLATORS: INSTALL_DEVICE isn't an identifier and is the DEVICE you
+   install to.  */
+struct argp argp = {
+  options, argp_parser, N_("[OPTION] [INSTALL_DEVICE]"),
+  N_("Install GRUB on your drive.")"\v"
+  N_("INSTALL_DEVICE must be system device filename.\n"
+     "%s copies GRUB images into %s.  On some platforms, it"
+     " may also install GRUB into the boot sector."), 
+  NULL, help_filter, NULL
+};
+
+static int
+probe_raid_level (grub_disk_t disk)
+{
+  /* disk might be NULL in the case of a LVM physical volume with no LVM
+     signature.  Ignore such cases here.  */
+  if (!disk)
+    return -1;
+
+  if (disk->dev->id != GRUB_DISK_DEVICE_DISKFILTER_ID)
+    return -1;
+
+  if (disk->name[0] != 'm' || disk->name[1] != 'd')
+    return -1;
+
+  if (!((struct grub_diskfilter_lv *) disk->data)->segments)
+    return -1;
+  return ((struct grub_diskfilter_lv *) disk->data)->segments->type;
+}
+
+static void
+probe_mods (grub_disk_t disk)
+{
+  grub_partition_t part;
+  grub_disk_memberlist_t list = NULL, tmp;
+  int raid_level;
+
+  if (disk->partition == NULL)
+    grub_util_info ("no partition map found for %s", disk->name);
+
+  for (part = disk->partition; part; part = part->parent)
+    {
+      char buf[50];
+      if (strcmp (part->partmap->name, "openbsd") == 0
+	  || strcmp (part->partmap->name, "netbsd") == 0)
+	{
+	  grub_install_push_module ("part_bsd");
+	  continue;
+	}
+      snprintf (buf, sizeof (buf), "part_%s", part->partmap->name);
+      grub_install_push_module (buf);
+    }
+
+  if (disk->dev->id == GRUB_DISK_DEVICE_DISKFILTER_ID)
+    {
+      grub_diskfilter_get_partmap (disk, grub_install_push_module);
+      have_abstractions = 1;
+    }
+
+  if (disk->dev->id == GRUB_DISK_DEVICE_DISKFILTER_ID
+      && (grub_memcmp (disk->name, "lvm/", sizeof ("lvm/") - 1) == 0 ||
+	  grub_memcmp (disk->name, "lvmid/", sizeof ("lvmid/") - 1) == 0))
+    grub_install_push_module ("lvm");
+
+  if (disk->dev->id == GRUB_DISK_DEVICE_DISKFILTER_ID
+      && grub_memcmp (disk->name, "ldm/", sizeof ("ldm/") - 1) == 0)
+    grub_install_push_module ("ldm");
+
+  if (disk->dev->id == GRUB_DISK_DEVICE_CRYPTODISK_ID)
+    {
+      grub_util_cryptodisk_get_abstraction (disk,
+					    grub_install_push_module);
+      have_abstractions = 1;
+    }
+
+  raid_level = probe_raid_level (disk);
+  if (raid_level >= 0)
+    {
+      grub_install_push_module ("diskfilter");
+      if (disk->dev->raidname)
+	grub_install_push_module (disk->dev->raidname (disk));
+    }
+  if (raid_level == 5)
+    grub_install_push_module ("raid5rec");
+  if (raid_level == 6)
+    grub_install_push_module ("raid6rec");
+
+  /* In case of LVM/RAID, check the member devices as well.  */
+  if (disk->dev->memberlist)
+    list = disk->dev->memberlist (disk);
+  while (list)
+    {
+      probe_mods (list->disk);
+      tmp = list->next;
+      free (list);
+      list = tmp;
+    }
+}
+
+static int
+have_bootdev (enum grub_install_plat pl)
+{
+  switch (pl)
+    {
+    case GRUB_INSTALL_PLATFORM_I386_PC:
+    case GRUB_INSTALL_PLATFORM_I386_EFI:
+    case GRUB_INSTALL_PLATFORM_X86_64_EFI:
+    case GRUB_INSTALL_PLATFORM_IA64_EFI:
+    case GRUB_INSTALL_PLATFORM_ARM_EFI:
+    case GRUB_INSTALL_PLATFORM_I386_IEEE1275:
+    case GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275:
+    case GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275:
+    case GRUB_INSTALL_PLATFORM_MIPSEL_ARC:
+    case GRUB_INSTALL_PLATFORM_MIPS_ARC:
+      return 1;
+
+    case GRUB_INSTALL_PLATFORM_I386_QEMU:
+    case GRUB_INSTALL_PLATFORM_I386_COREBOOT:
+    case GRUB_INSTALL_PLATFORM_I386_MULTIBOOT:
+    case GRUB_INSTALL_PLATFORM_MIPSEL_QEMU_MIPS:
+    case GRUB_INSTALL_PLATFORM_MIPS_QEMU_MIPS:
+
+    case GRUB_INSTALL_PLATFORM_MIPSEL_LOONGSON:
+    case GRUB_INSTALL_PLATFORM_ARM_UBOOT:
+      return 0;
+    }
+  return 0;
+}
+
+static void
+probe_cryptodisk_uuid (grub_disk_t disk)
+{
+  grub_disk_memberlist_t list = NULL, tmp;
+
+  /* In case of LVM/RAID, check the member devices as well.  */
+  if (disk->dev->memberlist)
+    {
+      list = disk->dev->memberlist (disk);
+    }
+  while (list)
+    {
+      probe_cryptodisk_uuid (list->disk);
+      tmp = list->next;
+      free (list);
+      list = tmp;
+    }
+  if (disk->dev->id == GRUB_DISK_DEVICE_CRYPTODISK_ID)
+    {
+      const char *uuid = grub_util_cryptodisk_get_uuid (disk);
+      if (!load_cfg_f)
+	load_cfg_f = fopen (load_cfg, "wb");
+      have_load_cfg = 1;
+
+      fprintf (load_cfg_f, "cryptomount -u %s\n",
+	      uuid);
+    }
+}
+
+static int
+is_same_disk (const char *a, const char *b)
+{
+  while (1)
+    {
+      if ((*a == ',' || *a == '\0') && (*b == ',' || *b == '\0'))
+	return 1;
+      if (*a != *b)
+	return 0;
+      if (*a == '\\')
+	{
+	  if (a[1] != b[1])
+	    return 0;
+	  a += 2;
+	  b += 2;
+	  continue;
+	}
+      a++;
+      b++;
+    }
+}
+
+char *
+get_rndstr (void)
+{
+  grub_uint8_t rnd[15];
+  const size_t sz = sizeof (rnd) * GRUB_CHAR_BIT / 5;
+  char * ret = xmalloc (sz + 1);
+  size_t i;
+  if (grub_get_random (rnd, sizeof (rnd)))
+    grub_util_error ("%s", _("couldn't retrieve random data"));
+  for (i = 0; i < sz; i++)
+    {
+      grub_size_t b = i * 5;
+      grub_uint8_t r;
+      grub_size_t f1 = GRUB_CHAR_BIT - b % GRUB_CHAR_BIT;
+      grub_size_t f2;
+      if (f1 > 5)
+	f1 = 5;
+      f2 = 5 - f1;
+      r = (rnd[b / GRUB_CHAR_BIT] >> (b % GRUB_CHAR_BIT)) & ((1 << f1) - 1);
+      if (f2)
+	r |= (rnd[b / GRUB_CHAR_BIT + 1] & ((1 << f2) - 1)) << f1;
+      if (r < 10)
+	ret[i] = '0' + r;
+      else
+	ret[i] = 'a' + (r - 10);
+    }
+  ret[sz] = '\0';
+  return ret;
+}
+
+static char *
+escape (const char *in)
+{
+  char *ptr;
+  char *ret;
+  int overhead = 0;
+
+  for (ptr = (char*)in; *ptr; ptr++)
+    if (*ptr == '\'')
+      overhead += 3;
+  ret = grub_malloc (ptr - in + overhead + 1);
+  if (!ret)
+    return NULL;
+
+  grub_strchrsub (ret, in, '\'', "'\\''");
+  return ret;
+}
+
+
+static int
+is_cryptodisk_enabled (void)
+{
+  /* FIXME */
+  return 0;
+}
+
+int
+main (int argc, char *argv[])
+{
+  int is_efi = 0;
+  const char *efi_distributor = bootloader_id;
+  const char *efi_file = NULL;
+  char **grub_devices;
+  grub_fs_t grub_fs;
+  grub_device_t grub_dev = NULL;
+  enum grub_install_plat platform;
+  char *grubdir, *device_map;
+  char **curdev, **curdrive;
+  char **grub_drives;
+  char *relative_grubdir;
+
+  set_program_name (argv[0]);
+
+  grub_util_init_nls ();
+
+  argp_parse (&argp, argc, argv, 0, 0, 0);
+
+  grub_install_args_finish ();
+
+  if (verbosity > 1)
+    grub_env_set ("debug", "all");
+
+  /*
+    FIXME:
+    grubdir="`echo "/@bootdirname@/@grubdirname@" | sed 's,// *,/,g'`"
+    
+    # Get GRUB_DISTRIBUTOR.
+    if test -f "${sysconfdir}/default/grub" ; then
+    . "${sysconfdir}/default/grub"
+    fi
+
+    bootloader_id="$(echo "$GRUB_DISTRIBUTOR" | tr 'A-Z' 'a-z' | cut -d' ' -f1)"
+    if test -z "$bootloader_id"; then
+    bootloader_id=grub
+    fi
+  */
+
+  if (!grub_install_source_directory)
+    {
+      if (!target)
+	{
+	  const char * t;
+	  t = get_default_platform ();
+	  if (!t)
+	    grub_util_error ("%s", 
+			     _("Unable to determine your platform."
+			       " Use --target.")
+			     );
+	  target = xstrdup (t); 
+	}
+      grub_install_source_directory
+	= grub_install_concat (3, GRUB_LIBDIR, PACKAGE, target);
+    }
+
+  platform = grub_install_get_target (grub_install_source_directory);
+
+  switch (platform)
+    {
+    case GRUB_INSTALL_PLATFORM_I386_PC:
+      if (!disk_module)
+	disk_module = xstrdup ("biosdisk");
+      break;
+    case GRUB_INSTALL_PLATFORM_I386_EFI:
+    case GRUB_INSTALL_PLATFORM_X86_64_EFI:
+    case GRUB_INSTALL_PLATFORM_ARM_EFI:
+    case GRUB_INSTALL_PLATFORM_IA64_EFI:
+    case GRUB_INSTALL_PLATFORM_I386_IEEE1275:
+    case GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275:
+    case GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275:
+    case GRUB_INSTALL_PLATFORM_MIPSEL_ARC:
+    case GRUB_INSTALL_PLATFORM_MIPS_ARC:
+    case GRUB_INSTALL_PLATFORM_ARM_UBOOT:
+      break;
+
+    case GRUB_INSTALL_PLATFORM_I386_QEMU:
+    case GRUB_INSTALL_PLATFORM_I386_COREBOOT:
+    case GRUB_INSTALL_PLATFORM_I386_MULTIBOOT:
+    case GRUB_INSTALL_PLATFORM_MIPSEL_LOONGSON:
+    case GRUB_INSTALL_PLATFORM_MIPSEL_QEMU_MIPS:
+    case GRUB_INSTALL_PLATFORM_MIPS_QEMU_MIPS:
+      disk_module = xstrdup ("native");
+      break;
+    }
+
+  switch (platform)
+    {
+    case GRUB_INSTALL_PLATFORM_I386_PC:
+    case GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275:
+      if (!install_device
+	  && (platform == GRUB_INSTALL_PLATFORM_I386_PC
+	      || platform == GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275))
+	grub_util_error ("%s", _("Install device isn't specified."));
+      break;
+    case GRUB_INSTALL_PLATFORM_MIPS_ARC:
+    case GRUB_INSTALL_PLATFORM_MIPSEL_ARC:
+    case GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275:
+      break;
+    case GRUB_INSTALL_PLATFORM_I386_EFI:
+    case GRUB_INSTALL_PLATFORM_X86_64_EFI:
+    case GRUB_INSTALL_PLATFORM_ARM_EFI:
+    case GRUB_INSTALL_PLATFORM_IA64_EFI:
+    case GRUB_INSTALL_PLATFORM_I386_IEEE1275:
+    case GRUB_INSTALL_PLATFORM_ARM_UBOOT:
+    case GRUB_INSTALL_PLATFORM_I386_QEMU:
+    case GRUB_INSTALL_PLATFORM_I386_COREBOOT:
+    case GRUB_INSTALL_PLATFORM_I386_MULTIBOOT:
+    case GRUB_INSTALL_PLATFORM_MIPSEL_LOONGSON:
+    case GRUB_INSTALL_PLATFORM_MIPSEL_QEMU_MIPS:
+    case GRUB_INSTALL_PLATFORM_MIPS_QEMU_MIPS:
+      free (install_device);
+      install_device = NULL;
+      break;
+    }
+
+  if (!bootdir)
+    {
+      /* FIXME */
+      if (rootdir)
+	bootdir = grub_install_concat (2, rootdir, "@bootdirname@");
+      else
+	bootdir = xstrdup ("/@bootdirname@");
+    }
+
+  {
+    char * t = grub_install_concat (2, bootdir, "@grubdirname@");
+    grub_install_mkdir_p (t);
+    grubdir = canonicalize_file_name (t);
+    free (t);
+  }
+  device_map = grub_install_concat (2, grubdir, "device.map");
+
+  if (recheck)
+    unlink (device_map);
+
+  /*
+    FIXME
+    # Device map file is optional
+    if test -f "$device_map"; then
+    # Make sure that there is no duplicated entry.
+    tmp=`sed -n '/^([fh]d[0-9]*)/s/\(^(.*)\).* /\1/p' "$device_map"	\
+    | sort | uniq -d | sed -n 1p`
+    if test -n "$tmp"; then
+    gettext_printf "The drive %s is defined multiple times in the device map %s\n" "$tmp" "$device_map" 1>&2
+    exit 1
+    fi
+    else
+    device_map=
+    fi
+  */
+  grub_util_biosdisk_init (device_map);
+
+  /* Initialize all modules. */
+  grub_init_all ();
+  grub_gcry_init_all ();
+  switch (platform)
+    {
+    case GRUB_INSTALL_PLATFORM_I386_EFI:
+    case GRUB_INSTALL_PLATFORM_X86_64_EFI:
+    case GRUB_INSTALL_PLATFORM_ARM_EFI:
+    case GRUB_INSTALL_PLATFORM_IA64_EFI:
+      is_efi = 1;
+      break;
+    default:
+      is_efi = 0;
+      break;
+    }
+
+  /* Find the EFI System Partition.  */
+
+  if (is_efi)
+    {
+      char ** device_names;
+      char *gd;
+      grub_fs_t fs;
+      grub_device_t dev = NULL;
+      free (install_device);
+      install_device = NULL;
+      if (!efidir)
+	{
+	  char *d = grub_install_concat (2, bootdir, "efi");
+	  char *dr = NULL;
+	  if (!is_directory (d))
+	    {
+	      free (d);
+	      d = grub_install_concat (2, bootdir, "EFI");
+	    }
+	  /*
+	    The EFI System Partition may have been given directly using
+	    --root-directory.
+	  */
+	  if (!is_directory (d)
+	      && rootdir && grub_strcmp (rootdir, "/") != 0)
+	    {
+	      free (d);
+	      d = xstrdup (rootdir);
+	    }
+	  if (is_directory (d))
+	    dr = grub_make_system_path_relative_to_its_root (d);
+	  /* Is it a mount point? */
+	  if (dr && dr[0] == '\0')
+	    efidir = d;
+	  else
+	    free (d);
+	  free (dr);
+	}
+      if (!efidir)
+	grub_util_error ("%s", _("cannot find EFI directory"));
+      device_names = grub_guess_root_devices (efidir);
+      if (!device_names || !device_names[0])
+	grub_util_error (_("cannot find a device for %s (is /dev mounted?)"),
+			     efidir);
+      install_device = device_names[0];
+
+      for (curdev = device_names; *curdev; curdev++)
+	  grub_util_pull_device (*curdev);
+      
+      gd = grub_util_get_grub_dev (device_names[0]);
+      if (!gd)
+	grub_util_error (_("cannot find a GRUB drive for %s.  Check your device.map"),
+			 device_names[0]);
+
+      dev = grub_device_open (gd);
+      if (! dev)
+	grub_util_error ("%s", grub_errmsg);
+
+      fs = grub_fs_probe (dev);
+      if (! fs)
+	grub_util_error ("%s", grub_errmsg);
+
+      if (grub_strcmp (fs->name, "fat") != 0)
+	{
+	  printf (_("%s doesn't look like an EFI partition.\n"), efidir);
+	  free (efidir);
+	  efidir = 0;
+	}
+      free (device_names);
+      grub_device_close (dev);
+
+      if (efidir)
+	{
+	  /* The EFI specification requires that an EFI System Partition must
+	     contain an "EFI" subdirectory, and that OS loaders are stored in
+	     subdirectories below EFI.  Vendors are expected to pick names that do
+	     not collide with other vendors.  To minimise collisions, we use the
+	     name of our distributor if possible.
+	  */
+	  char *t;
+	  efi_distributor = bootloader_id;
+	  if (removable)
+	    {
+	      /* The specification makes stricter requirements of removable
+		 devices, in order that only one image can be automatically loaded
+		 from them.  The image must always reside under /EFI/BOOT, and it
+		 must have a specific file name depending on the architecture.
+	      */
+	      efi_distributor = "BOOT";
+	      switch (platform)
+		{
+		case GRUB_INSTALL_PLATFORM_I386_EFI:
+		  efi_file = "BOOTIA32.EFI";
+		  break;
+		case GRUB_INSTALL_PLATFORM_X86_64_EFI:
+		  efi_file = "BOOTX64.EFI";
+		  break;
+		case GRUB_INSTALL_PLATFORM_IA64_EFI:
+		  efi_file = "BOOTIA64.EFI";
+		  break;
+		case GRUB_INSTALL_PLATFORM_ARM_EFI:
+		  efi_file = "BOOTARM.EFI";
+		  break;
+		default:
+		  grub_util_error ("%s", _("You've found a bug"));
+		  break;
+		}
+	    }
+	  else
+	    {
+	      /* It is convenient for each architecture to have a different
+		 efi_file, so that different versions can be installed in parallel.
+	      */
+	      switch (platform)
+		{
+		case GRUB_INSTALL_PLATFORM_I386_EFI:
+		  efi_file = "grubia32.efi";
+		  break;
+		case GRUB_INSTALL_PLATFORM_X86_64_EFI:
+		  efi_file = "grubx64.efi";
+		  break;
+		case GRUB_INSTALL_PLATFORM_IA64_EFI:
+		  efi_file = "grubia64.efi";
+		  break;
+		case GRUB_INSTALL_PLATFORM_ARM_EFI:
+		  efi_file = "grubarm.efi";
+		  break;
+		default:
+		  efi_file = "grub.efi";
+		  break;
+		}
+	    }
+	  t = grub_install_concat (3, efidir, "EFI", efi_distributor);
+	  free (efidir);
+	  efidir = t;
+	  grub_install_mkdir_p (efidir);
+	}
+      else
+	{
+	  /* We don't know what's going on.  Fall back to traditional
+	     (non-specification-compliant) behaviour.  */
+	  efidir = xstrdup (grubdir);
+	  efi_distributor = "";
+	  efi_file = "grub.efi";
+	}
+    }
+
+  grub_install_copy_files (grub_install_source_directory,
+				  grubdir, platform);
+
+
+  /* FIXME 
+if ! test -f "${grubdir}"/grubenv; then
+    "$grub_editenv" "${grubdir}"/grubenv create
+fi
+*/
+
+  /* FIXME
+
+  # ... or if we can't figure out the abstraction module, for example if
+  # memberlist fails on an LVM volume group.
+  if abstractions="`"${grub_probe}" -t abstraction "$path"`" 2> /dev/null ; then 
+      :
+  else
+    return 1
+  fi
+
+  if [ x$GRUB_CRYPTODISK_ENABLE = xy ]; then
+      return 0
+  fi
+  
+  for abstraction in $abstractions; do
+      if [ "x$abstraction" = xcryptodisk ]; then
+	  return 1
+      fi
+  done
+
+if ! is_path_readable_by_grub "${grubdir}"; then
+    gettext_printf "Path \`%s' is not readable by GRUB on boot. Installation is impossible. Aborting.\n" "${grubdir}" 1>&2
+    exit 1
+fi
+
+*/
+
+  size_t ndev = 0;
+
+  /* Write device to a variable so we don't have to traverse /dev every time.  */
+  grub_devices = grub_guess_root_devices (grubdir);
+  if (!grub_devices || !grub_devices[0])
+    grub_util_error (_("cannot find a device for %s (is /dev mounted?)"),
+		     grubdir);
+
+  for (curdev = grub_devices; *curdev; curdev++)
+    {
+      grub_util_pull_device (*curdev);
+      ndev++;
+    }
+
+  grub_drives = xmalloc (sizeof (grub_drives[0]) * (ndev + 1)); 
+
+  for (curdev = grub_devices, curdrive = grub_drives; *curdev; curdev++,
+       curdrive++)
+    {
+      *curdrive = grub_util_get_grub_dev (*curdev);
+      if (! *curdrive)
+	grub_util_error (_("cannot find a GRUB drive for %s.  Check your device.map"),
+			 *curdev);
+    }
+  *curdrive = 0;
+
+  grub_dev = grub_device_open (grub_drives[0]);
+  if (! grub_dev)
+    grub_util_error ("%s", grub_errmsg);
+
+  grub_fs = grub_fs_probe (grub_dev);
+  if (! grub_fs)
+    grub_util_error ("%s", grub_errmsg);
+
+  grub_install_push_module (grub_fs->name);
+
+  if (grub_dev->disk)
+    probe_mods (grub_dev->disk);
+
+  for (curdrive = grub_drives + 1; *curdrive; curdrive++)
+    {
+      grub_device_t dev = grub_device_open (*curdrive);
+      if (!dev)
+	continue;
+      if (dev->disk)
+	probe_mods (dev->disk);
+      grub_device_close (dev);
+    }
+  if (disk_module && grub_strcmp (disk_module, "ata") == 0)
+    grub_install_push_module ("pata");
+  else if (disk_module && grub_strcmp (disk_module, "native") == 0)
+    {
+      grub_install_push_module ("pata");
+      grub_install_push_module ("ahci");
+      grub_install_push_module ("ohci");
+      grub_install_push_module ("uhci");
+      grub_install_push_module ("usbms");
+    }
+  else if (disk_module && disk_module[0])
+    grub_install_push_module (disk_module);
+
+  relative_grubdir = grub_make_system_path_relative_to_its_root (grubdir);
+  if (relative_grubdir[0] == '\0')
+    {
+      free (relative_grubdir);
+      relative_grubdir = xstrdup ("/");
+    }
+
+  char *platname =  grub_install_get_platform_name (platform);
+  load_cfg = grub_install_concat (3, grubdir,
+				  platname,
+				  "load.cfg");
+
+  unlink (load_cfg);
+
+  if (debug_image && debug_image[0])
+    {
+      load_cfg_f = fopen (load_cfg, "wb");
+      have_load_cfg = 1;
+      fprintf (load_cfg_f, "set debug='%s'\n",
+	      debug_image);
+    }
+  char *prefix_drive = NULL;
+  char *install_drive = NULL;
+
+  if (install_device)
+    {
+      if (install_device[0] == '('
+	  && install_device[grub_strlen (install_device) - 1] == ')')
+	install_drive = xstrdup (install_device);
+      else
+	{
+	  grub_util_pull_device (install_device);
+	  install_drive = grub_util_get_grub_dev (install_device);
+	  if (!install_drive)
+	    grub_util_error (_("cannot find a GRUB drive for %s.  Check your device.map"),
+			     install_device);
+	}
+    }
+
+  if (!have_abstractions)
+    {
+      /*
+
+    grub_drive="`echo "${grub_device}" | xargs "$grub_probe" --device-map="${device_map}" --target=drive --device`" || exit 1
+
+    # Strip partition number
+    grub_partition="`echo "${grub_drive}" | sed -e 's/^(\(\([^,\\\\]\|\\\\\\\\\|\\\\,\)*\)\(\(,[a-zA-Z0-9]*\)*\))$/\3/'`"
+    grub_drive="`echo "${grub_drive}" | sed -e 's/^(\(\([^,\\\\]\|\\\\\\\\\|\\\\,\)*\)\(\(,[a-zA-Z0-9]*\)*\))$/\1/'`"
+      */
+      if ((disk_module && grub_strcmp (disk_module, "biosdisk") != 0)
+	  || grub_drives[1]
+	  || (!install_drive
+	      && platform != GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275)
+	  || (install_drive && !is_same_disk (grub_drives[0], install_drive))
+	  || !have_bootdev (platform))
+	{
+	  char *uuid = NULL;
+	  /*  generic method (used on coreboot and ata mod).  */
+	  if (!force_file_id && grub_fs->uuid && grub_fs->uuid (grub_dev,
+								&uuid))
+	    {
+	      grub_print_error ();
+	      grub_errno = 0;
+	      uuid = NULL;
+	    }
+
+	  if (!load_cfg_f)
+	    load_cfg_f = fopen (load_cfg, "wb");
+	  have_load_cfg = 1;
+	  if (uuid)
+	    {
+	      fprintf (load_cfg_f, "search.fs_uuid %s root ",
+		      uuid);
+	      grub_install_push_module ("search_fs_uuid");
+	    }
+	  else
+	    {
+	      char *rndstr = get_rndstr ();
+	      char *fl = grub_install_concat (3, grubdir,
+						     "uuid", rndstr);
+	      char *fldir = grub_install_concat (2, grubdir,
+							"uuid");
+	      char *relfl;
+	      FILE *flf;
+	      grub_install_mkdir_p (fldir);
+	      flf = fopen (fl, "w");
+	      if (!flf)
+		grub_util_error ("Can't create file: %s", strerror (errno));
+	      fclose (flf);
+	      relfl = grub_make_system_path_relative_to_its_root (fl);
+	      fprintf (load_cfg_f, "search.file %s root ",
+		       relfl);
+	      grub_install_push_module ("search_fs_file");
+	    }
+	  /* FIXME
+	if [ x"$disk_module" != x ] && [ x"$disk_module" != xbiosdisk ]; then
+            hints="`echo "${grub_device}" | xargs "$grub_probe" --device-map="${device_map}" --target=baremetal_hints --device`"
+	elif [ x"$grub_modinfo_platform" = xpc ]; then
+            hints="`echo "${grub_device}" | xargs "$grub_probe" --device-map="${device_map}" --target=bios_hints --device`"
+	elif [ x"$grub_modinfo_platform" = xefi ]; then
+            hints="`echo "${grub_device}" | xargs "$grub_probe" --device-map="${device_map}" --target=efi_hints --device`"
+	elif [ x"$grub_modinfo_platform" = xieee1275 ]; then
+            hints="`echo "${grub_device}" | xargs "$grub_probe" --device-map="${device_map}" --target=ieee1275_hints --device`"
+	elif [ x"$grub_modinfo_platform" = xloongson ] || [ x"$grub_modinfo_platform" = xqemu ] || [ x"$grub_modinfo_platform" = xcoreboot ] || [ x"$grub_modinfo_platform" = xmultiboot ] || [ x"$grub_modinfo_platform" = xqemu-mips ]; then
+            hints="`echo "${grub_device}" | xargs "$grub_probe" --device-map="${device_map}" --target=baremetal_hints --device`"
+	else
+            gettext "No hints available for your platform. Expect reduced performance." 1>&2
+	    echo 1>&2
+	    hints=
+	    fi */
+	  fprintf (load_cfg_f, "\n");
+	  char *escaped_relpath = escape (relative_grubdir);
+	  fprintf (load_cfg_f, "set prefix=($root)'%s'\n",
+		   escaped_relpath);
+	}
+      else
+	{
+	  /* We need to hardcode the partition number in the core image's prefix.  */
+	  char *p;
+	  for (p = grub_drives[0]; *p; )
+	    {
+	      if (*p == '\\' && p[1])
+		{
+		  p += 2;
+		  continue;
+		}
+	      if (*p == ',' || *p == '\0')
+		break;
+	      p++;
+	    }
+	  prefix_drive = xasprintf ("(%s)", p);
+	}
+    }
+  else
+    {
+      if (is_cryptodisk_enabled ())
+	{
+	  if (grub_dev->disk)
+	    probe_cryptodisk_uuid (grub_dev->disk);
+
+	  for (curdrive = grub_drives + 1; *curdrive; curdrive++)
+	    {
+	      grub_device_t dev = grub_device_open (*curdrive);
+	      if (!dev)
+		continue;
+	      if (dev->disk)
+		probe_cryptodisk_uuid (dev->disk);
+	      grub_device_close (dev);
+	    }
+	}
+      prefix_drive = xasprintf ("(%s)", grub_drives[0]);
+    }
+
+  char mkimage_target[200];
+  const char *core_name = NULL;
+
+  switch (platform)
+    {
+    case GRUB_INSTALL_PLATFORM_I386_EFI:
+    case GRUB_INSTALL_PLATFORM_X86_64_EFI:
+    case GRUB_INSTALL_PLATFORM_ARM_EFI:
+    case GRUB_INSTALL_PLATFORM_IA64_EFI:
+      core_name = "core.efi";
+      snprintf (mkimage_target, sizeof (mkimage_target),
+		"%s-%s",
+		grub_install_get_platform_cpu (platform),
+		grub_install_get_platform_platform (platform));
+      break;
+    case GRUB_INSTALL_PLATFORM_MIPSEL_LOONGSON:
+    case GRUB_INSTALL_PLATFORM_MIPSEL_QEMU_MIPS:
+    case GRUB_INSTALL_PLATFORM_MIPS_QEMU_MIPS:
+      core_name = "core.elf";
+      snprintf (mkimage_target, sizeof (mkimage_target),
+		"%s-%s-elf",
+		grub_install_get_platform_cpu (platform),
+		grub_install_get_platform_platform (platform));
+      break;
+
+    case GRUB_INSTALL_PLATFORM_I386_COREBOOT:
+    case GRUB_INSTALL_PLATFORM_I386_MULTIBOOT:
+    case GRUB_INSTALL_PLATFORM_I386_IEEE1275:
+    case GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275:
+      core_name = "core.elf";
+      snprintf (mkimage_target, sizeof (mkimage_target),
+		"%s-%s",
+		grub_install_get_platform_cpu (platform),
+		grub_install_get_platform_platform (platform));
+      break;
+
+
+    case GRUB_INSTALL_PLATFORM_I386_PC:
+    case GRUB_INSTALL_PLATFORM_MIPSEL_ARC:
+    case GRUB_INSTALL_PLATFORM_MIPS_ARC:
+    case GRUB_INSTALL_PLATFORM_ARM_UBOOT:
+    case GRUB_INSTALL_PLATFORM_I386_QEMU:
+      snprintf (mkimage_target, sizeof (mkimage_target),
+		"%s-%s",
+		grub_install_get_platform_cpu (platform),
+		grub_install_get_platform_platform (platform));
+      core_name = "core.img";
+      break;
+    case GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275:
+      strcpy (mkimage_target, "sparc64-ieee1275-raw");
+      core_name = "core.img";
+      break;
+    }
+
+  if (!core_name)
+    grub_util_error ("%s", _("You've found a bug"));
+
+  if (load_cfg_f)
+    fclose (load_cfg_f);
+
+  char *imgfile = grub_install_concat (3, grubdir, platname,
+					      core_name);
+  char *prefix = xasprintf ("%s%s", prefix_drive ? : "",
+			    relative_grubdir);
+  grub_install_make_image_wrap (/* source dir  */ grub_install_source_directory,
+				       /*prefix */ prefix,
+				       /* output */ imgfile,
+				       /* memdisk */ NULL,
+				have_load_cfg ? load_cfg : NULL,
+				       /* image target */ mkimage_target,
+				0, GRUB_COMPRESSION_AUTO);
+  /* Backward-compatibility kludges.  */
+  switch (platform)
+    {
+    case GRUB_INSTALL_PLATFORM_MIPSEL_LOONGSON:
+      {
+	char *dst = grub_install_concat (2, bootdir, "grub.elf");
+	grub_install_copy_file (imgfile, dst);
+	free (dst);
+      }
+      break;
+
+    case GRUB_INSTALL_PLATFORM_I386_IEEE1275:
+    case GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275:
+      {
+	char *dst = grub_install_concat (2, grubdir, "grub");
+	grub_install_copy_file (imgfile, dst);
+	free (dst);
+      }
+      break;
+
+    case GRUB_INSTALL_PLATFORM_I386_EFI:
+    case GRUB_INSTALL_PLATFORM_X86_64_EFI:
+      {
+	char *dst = grub_install_concat (3, grubdir, platname,
+						"grub.efi");
+	grub_install_make_image_wrap (/* source dir  */ grub_install_source_directory,
+				      /* prefix */ "",
+				       /* output */ dst,
+				       /* memdisk */ NULL,
+				      have_load_cfg ? load_cfg : NULL,
+				       /* image target */ mkimage_target,
+				      0, GRUB_COMPRESSION_AUTO);
+      }
+      break;
+    case GRUB_INSTALL_PLATFORM_ARM_EFI:
+    case GRUB_INSTALL_PLATFORM_IA64_EFI:
+    case GRUB_INSTALL_PLATFORM_MIPSEL_QEMU_MIPS:
+    case GRUB_INSTALL_PLATFORM_MIPS_QEMU_MIPS:
+    case GRUB_INSTALL_PLATFORM_I386_COREBOOT:
+    case GRUB_INSTALL_PLATFORM_I386_MULTIBOOT:
+    case GRUB_INSTALL_PLATFORM_I386_PC:
+    case GRUB_INSTALL_PLATFORM_MIPSEL_ARC:
+    case GRUB_INSTALL_PLATFORM_MIPS_ARC:
+    case GRUB_INSTALL_PLATFORM_ARM_UBOOT:
+    case GRUB_INSTALL_PLATFORM_I386_QEMU:
+    case GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275:
+      break;
+    }
+
+  /* Perform the platform-dependent install */
+
+  switch (platform)
+    {
+    case GRUB_INSTALL_PLATFORM_I386_PC:
+      {
+	char *dir = grub_install_concat (2, grubdir, platname);
+	char *boot_img = grub_install_concat (2, grub_install_source_directory,
+					      "boot.img");
+	grub_util_info ("grub_bios_setup %s %s %s --directory='%s' --device-map='%s' '%s'",
+			allow_floppy ? "--allow-floppy " : "",
+			verbosity ? "--verbose " : "",
+			force ? "--force " : "",
+			dir,
+			device_map,
+			install_device);
+			
+	/*  Now perform the installation.  */
+	grub_bios_setup (dir, boot_img, NULL,
+			 install_drive, force,
+			 1, allow_floppy);
+	break;
+      }
+    case GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275:
+      {
+	char *dir = grub_install_concat (2, grubdir, platname);
+	char *boot_img = grub_install_concat (2, grub_install_source_directory,
+					      "boot.img");
+
+	grub_util_info ("grub_sparc_setup %s %s %s --directory='%s' --device-map='%s' '%s'",
+			allow_floppy ? "--allow-floppy " : "",
+			verbosity ? "--verbose " : "",
+			force ? "--force " : "",
+			dir,
+			device_map,
+			install_drive);
+			
+	/*  Now perform the installation.  */
+	grub_sparc_setup (dir, boot_img, NULL,
+			  install_device, force,
+			  1, allow_floppy);
+	break;
+      }
+
+    case GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275:
+      /*
+	FIXME
+    # If a install device is defined, copy the core.elf to PReP partition.
+    if [ "${grub_modinfo_target_cpu}-${grub_modinfo_platform}" = "powerpc-ieee1275" ] && [ -n "${install_device}" ]; then
+
+        if [ "$("${grub_probe}" -m "${device_map}" -d "${install_device}" -t msdos_parttype)" != "41" ] \
+            && [ "$("${grub_probe}" -m "${device_map}" -d "${install_device}" -t gpt_parttype)" != "9e1a2d38-c612-4316-aa26-8b49521e5a8b" ]; then
+            gettext "The chosen partition is not a PReP partition." 1>&2
+            echo 1>&2
+            exit 1
+        fi
+
+        if [ "$(file -s -b -L "${install_device}" | awk '{ print $1 }')" = ELF ] || [ x$("${grub_probe}" -m "${device_map}" -d "${install_device}" -t zero_check) = xtrue ]; then
+	        dd if="${grubdir}/${grub_modinfo_target_cpu}-$grub_modinfo_platform/core.${imgext}" of="${install_device}" status=noxfer || {
+	        gettext "Failed to copy Grub to the PReP partition." 1>&2
+	            echo 1>&2
+	            exit 1
+	        }
+        else
+	        gettext "The PReP partition is not empty. If you are sure you want to use it, run dd to clear it:" 1>&2
+	        echo 1>&2
+	        echo "  dd if=/dev/zero of=${install_device}"
+	        exit 1
+        fi
+    fi
+
+       */
+      /* fallthrough.  */
+    case GRUB_INSTALL_PLATFORM_I386_IEEE1275:
+      if (update_nvram)
+	{
+      /* FIXME
+	ofpathname="`which ofpathname`"
+	nvsetenv="`which nvsetenv`"
+	set "$ofpathname" dummy
+	if test -f "$1"; then
+	    :
+	else
+            # TRANSLATORS: This message is shown when required executable `%s'
+            # isn't found
+	    gettext_printf "%s: Not found.\n" "$1" 1>&2
+	    exit 1
+	fi
+	set "$nvsetenv" dummy
+	if test -f "$1"; then
+	    :
+	else
+            # TRANSLATORS: This message is shown when required executable `%s'
+            # isn't found
+	    gettext_printf "%s: Not found.\n" "$1" 1>&2
+	    exit 1
+	fi
+	if  [ "${grub_modinfo_target_cpu}-${grub_modinfo_platform}" != "powerpc-ieee1275" ] \
+	    || [ -z "${install_device}" ]; then
+         # Get the Open Firmware device tree path translation.
+	    dev="`echo $grub_device | sed -e 's/\/dev\///' -e 's/[0-9]\+//'`"
+	    partno="`echo $grub_device | sed -e 's/.*[^0-9]\([0-9]\+\)$/\1/'`"
+	    ofpath="`$ofpathname $dev`" || {
+	    # TRANSLATORS: "device tree path" is the name of the device
+            # for IEEE1275
+		gettext_printf "Couldn't find IEEE1275 device tree path for %s.\nYou will have to set \`boot-device' variable manually.\n" "$dev" 1>&2
+		exit 1
+	    }
+
+            # Point boot-device at the new grub install
+	    boot_device="$ofpath:$partno,"`"$grub_mkrelpath" "${grubdir}/${grub_modinfo_target_cpu}-$grub_modinfo_platform/core.${imgext}" | sed 's,/,\\\\,g'`
+
+	else
+
+	    dev="`echo "${install_device}" | sed -e 's/\/dev\///' -e 's/[0-9]\+//'`"
+	    boot_device="`$ofpathname "$dev"`" || {
+	    # TRANSLATORS: "device tree path" is the name of the device
+            # for IEEE1275
+		gettext_printf "Couldn't find IEEE1275 device tree path for %s.\nYou will have to set \`boot-device' variable manually.\n" "$dev" 1>&2
+		exit 1
+	    }
+	fi
+
+	"$nvsetenv" boot-device "$boot_device" || {
+	    # TRANSLATORS: The %s will be replaced by an external program name.
+	    gettext_printf "\`%s' failed.\n" "$nvsetenv" 1>&2
+	    gettext "You will have to set \`boot-device' variable manually.  At the IEEE1275 prompt, type:" 1>&2
+	    echo 1>&2
+	    echo "  setenv boot-device $boot_device" 1>&2
+	    exit 1
+	}
+*/
+	}
+      break;
+    case GRUB_INSTALL_PLATFORM_MIPS_ARC:
+      /* FIXME
+	     dvhtool -d "${install_device}" --unix-to-vh "${grubdir}/${grub_modinfo_target_cpu}-$grub_modinfo_platform/core.${imgext}" grub
+    echo 1>&2
+      */
+      grub_util_warn ("%s", _("You will have to set `SystemPartition' and `OSLoader' manually."));
+
+      break;
+
+    case GRUB_INSTALL_PLATFORM_I386_EFI:
+      {
+	char *dst = grub_install_concat (2, efidir, "grub.efi");
+	/* For old macs. Suggested by Peter Jones.  */
+	grub_install_copy_file (imgfile, dst);
+	free (dst);
+      }
+
+    case GRUB_INSTALL_PLATFORM_X86_64_EFI:
+    case GRUB_INSTALL_PLATFORM_ARM_EFI:
+    case GRUB_INSTALL_PLATFORM_IA64_EFI:
+      {
+	char *dst = grub_install_concat (2, efidir, efi_file);
+	grub_install_copy_file (imgfile, dst);
+	free (dst);
+      }
+      if (!removable)
+	{
+	  /* Try to make this image bootable using the EFI Boot Manager, if available.  */
+	  
+      /* FIXME
+	efibootmgr="`which efibootmgr`" || {
+            # TRANSLATORS: This message is shown when required executable `%s'
+            # isn't found
+	    gettext_printf "%s: Not found.\n" "efibootmgr" 1>&2
+	    exit 1
+	    } */
+	  if (!efi_distributor || efi_distributor[0] == '\0')
+	    grub_util_error ("%s", "EFI distributor id isn't specified.");
+
+	  /* On Linux, we need the efivars kernel modules.  */
+#ifdef __linux__
+	  grub_util_exec ((char * []){ (char *) "modprobe", (char *) "-q",
+		(char *) "efivars", NULL });
+#endif
+	  (void) efi_quiet;
+	  /* FIXME
+
+        # Delete old entries from the same distributor.
+	for bootnum in `efibootmgr | grep '^Boot[0-9]' | \
+	    fgrep -i " $efi_distributor" | cut -b5-8`; do
+	    efibootmgr $efi_quiet -b "$bootnum" -B
+	done
+
+        # Add a new entry for the image we just created.  efibootmgr needs to be
+        # given the disk device and partition number separately, so we have to
+        # fiddle about with grub-probe to get hold of this reasonably reliably.
+        # Use fresh device map text to avoid any problems with stale data, since
+        # all we need here is a one-to-one mapping.
+	efidir_drive="$("$grub_probe" --target=drive --device-map= "$efidir")"
+	efidir_disk="$("$grub_probe" --target=disk --device-map= "$efidir")"
+	if test -z "$efidir_drive" || test -z "$efidir_disk"; then
+	    gettext_printf "Can't find GRUB drive for %s; unable to create EFI Boot Manager entry.\n" "$efidir" >&2
+	else
+	    efidir_part="$(echo "$efidir_drive" | sed 's/^([^,]*,[^0-9]* //; s/[^0-9].* //')"
+	    efibootmgr $efi_quiet -c -d "$efidir_disk" -p "$efidir_part" -w \
+		-L "$bootloader_id" -l "\\EFI\\$efi_distributor\\$efi_file"
+	fi
+	  */
+	}
+      break;
+
+    case GRUB_INSTALL_PLATFORM_MIPSEL_LOONGSON:
+    case GRUB_INSTALL_PLATFORM_MIPSEL_QEMU_MIPS:
+    case GRUB_INSTALL_PLATFORM_MIPS_QEMU_MIPS:
+    case GRUB_INSTALL_PLATFORM_I386_COREBOOT:
+    case GRUB_INSTALL_PLATFORM_I386_MULTIBOOT:
+    case GRUB_INSTALL_PLATFORM_MIPSEL_ARC:
+    case GRUB_INSTALL_PLATFORM_ARM_UBOOT:
+    case GRUB_INSTALL_PLATFORM_I386_QEMU:
+      grub_util_warn ("%s",
+		      _("WARNING: no platform-specific install was performed"));
+      break;
+    }
+
+  fprintf (stderr, "%s\n", _("Installation finished. No error reported."));
+
+  /* Free resources.  */
+  grub_gcry_fini_all ();
+  grub_fini_all ();
+
+  return 0;
+}

=== modified file 'util/grub-mkimage.c'
--- util/grub-mkimage.c	2013-08-23 07:01:11 +0000
+++ util/grub-mkimage.c	2013-09-25 15:44:40 +0000
@@ -43,1786 +43,14 @@
 #include <grub/uboot/image.h>
 #include <grub/arm/reloc.h>
 #include <grub/ia64/reloc.h>
+#include <grub/util/install.h>
+#include <grub/misc.h>
 
 #define _GNU_SOURCE	1
 #include <argp.h>
 
 #include "progname.h"
 
-#define ALIGN_ADDR(x) (ALIGN_UP((x), image_target->voidp_sizeof))
-
-#ifdef HAVE_LIBLZMA
-#include <lzma.h>
-#endif
-
-#define TARGET_NO_FIELD 0xffffffff
-
-typedef enum {
-  COMPRESSION_AUTO, COMPRESSION_NONE, COMPRESSION_XZ, COMPRESSION_LZMA
-} grub_compression_t;
-
-struct image_target_desc
-{
-  const char *dirname;
-  const char *names[6];
-  grub_size_t voidp_sizeof;
-  int bigendian;
-  enum {
-    IMAGE_I386_PC, IMAGE_EFI, IMAGE_COREBOOT,
-    IMAGE_SPARC64_AOUT, IMAGE_SPARC64_RAW, IMAGE_SPARC64_CDCORE,
-    IMAGE_I386_IEEE1275,
-    IMAGE_LOONGSON_ELF, IMAGE_QEMU, IMAGE_PPC, IMAGE_YEELOONG_FLASH,
-    IMAGE_FULOONG2F_FLASH, IMAGE_I386_PC_PXE, IMAGE_MIPS_ARC,
-    IMAGE_QEMU_MIPS_FLASH, IMAGE_UBOOT
-  } id;
-  enum
-    {
-      PLATFORM_FLAGS_NONE = 0,
-      PLATFORM_FLAGS_DECOMPRESSORS = 2,
-      PLATFORM_FLAGS_MODULES_BEFORE_KERNEL = 4,
-    } flags;
-  unsigned total_module_size;
-  unsigned decompressor_compressed_size;
-  unsigned decompressor_uncompressed_size;
-  unsigned decompressor_uncompressed_addr;
-  unsigned link_align;
-  grub_uint16_t elf_target;
-  unsigned section_align;
-  signed vaddr_offset;
-  grub_uint64_t link_addr;
-  unsigned mod_gap, mod_align;
-  grub_compression_t default_compression;
-  grub_uint16_t pe_target;
-};
-
-#define EFI32_HEADER_SIZE ALIGN_UP (GRUB_PE32_MSDOS_STUB_SIZE		\
-				    + GRUB_PE32_SIGNATURE_SIZE		\
-				    + sizeof (struct grub_pe32_coff_header) \
-				    + sizeof (struct grub_pe32_optional_header) \
-				    + 4 * sizeof (struct grub_pe32_section_table), \
-				    GRUB_PE32_SECTION_ALIGNMENT)
-
-#define EFI64_HEADER_SIZE ALIGN_UP (GRUB_PE32_MSDOS_STUB_SIZE		\
-				    + GRUB_PE32_SIGNATURE_SIZE		\
-				    + sizeof (struct grub_pe32_coff_header) \
-				    + sizeof (struct grub_pe64_optional_header) \
-				    + 4 * sizeof (struct grub_pe32_section_table), \
-				    GRUB_PE32_SECTION_ALIGNMENT)
-
-struct image_target_desc image_targets[] =
-  {
-    {
-      .dirname = "i386-coreboot",
-      .names = { "i386-coreboot", NULL },
-      .voidp_sizeof = 4,
-      .bigendian = 0,
-      .id = IMAGE_COREBOOT,
-      .flags = PLATFORM_FLAGS_NONE,
-      .total_module_size = TARGET_NO_FIELD,
-      .decompressor_compressed_size = TARGET_NO_FIELD,
-      .decompressor_uncompressed_size = TARGET_NO_FIELD,
-      .decompressor_uncompressed_addr = TARGET_NO_FIELD,
-      .section_align = 1,
-      .vaddr_offset = 0,
-      .link_addr = GRUB_KERNEL_I386_COREBOOT_LINK_ADDR,
-      .elf_target = EM_386,
-      .link_align = 4,
-      .mod_gap = GRUB_KERNEL_I386_COREBOOT_MOD_GAP,
-      .mod_align = GRUB_KERNEL_I386_COREBOOT_MOD_ALIGN
-    },
-    {
-      .dirname = "i386-multiboot",
-      .names = { "i386-multiboot", NULL},
-      .voidp_sizeof = 4,
-      .bigendian = 0,
-      .id = IMAGE_COREBOOT,
-      .flags = PLATFORM_FLAGS_NONE,
-      .total_module_size = TARGET_NO_FIELD,
-      .decompressor_compressed_size = TARGET_NO_FIELD,
-      .decompressor_uncompressed_size = TARGET_NO_FIELD,
-      .decompressor_uncompressed_addr = TARGET_NO_FIELD,
-      .section_align = 1,
-      .vaddr_offset = 0,
-      .link_addr = GRUB_KERNEL_I386_COREBOOT_LINK_ADDR,
-      .elf_target = EM_386,
-      .link_align = 4,
-      .mod_gap = GRUB_KERNEL_I386_COREBOOT_MOD_GAP,
-      .mod_align = GRUB_KERNEL_I386_COREBOOT_MOD_ALIGN
-    },
-    {
-      .dirname = "i386-pc",
-      .names = { "i386-pc", NULL },
-      .voidp_sizeof = 4,
-      .bigendian = 0,
-      .id = IMAGE_I386_PC, 
-      .flags = PLATFORM_FLAGS_DECOMPRESSORS,
-      .total_module_size = TARGET_NO_FIELD,
-      .decompressor_compressed_size = GRUB_DECOMPRESSOR_I386_PC_COMPRESSED_SIZE,
-      .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_I386_PC_UNCOMPRESSED_SIZE,
-      .decompressor_uncompressed_addr = TARGET_NO_FIELD,
-      .section_align = 1,
-      .vaddr_offset = 0,
-      .link_addr = GRUB_KERNEL_I386_PC_LINK_ADDR,
-      .default_compression = COMPRESSION_LZMA
-    },
-    {
-      .dirname = "i386-pc",
-      .names = { "i386-pc-pxe", NULL },
-      .voidp_sizeof = 4,
-      .bigendian = 0,
-      .id = IMAGE_I386_PC_PXE, 
-      .flags = PLATFORM_FLAGS_DECOMPRESSORS,
-      .total_module_size = TARGET_NO_FIELD,
-      .decompressor_compressed_size = GRUB_DECOMPRESSOR_I386_PC_COMPRESSED_SIZE,
-      .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_I386_PC_UNCOMPRESSED_SIZE,
-      .decompressor_uncompressed_addr = TARGET_NO_FIELD,
-      .section_align = 1,
-      .vaddr_offset = 0,
-      .link_addr = GRUB_KERNEL_I386_PC_LINK_ADDR,
-      .default_compression = COMPRESSION_LZMA
-    },
-    {
-      .dirname = "i386-efi",
-      .names = { "i386-efi", NULL },
-      .voidp_sizeof = 4,
-      .bigendian = 0,
-      .id = IMAGE_EFI,
-      .flags = PLATFORM_FLAGS_NONE,
-      .total_module_size = TARGET_NO_FIELD,
-      .decompressor_compressed_size = TARGET_NO_FIELD,
-      .decompressor_uncompressed_size = TARGET_NO_FIELD,
-      .decompressor_uncompressed_addr = TARGET_NO_FIELD,
-      .section_align = GRUB_PE32_SECTION_ALIGNMENT,
-      .vaddr_offset = EFI32_HEADER_SIZE,
-      .pe_target = GRUB_PE32_MACHINE_I386,
-      .elf_target = EM_386,
-    },
-    {
-      .dirname = "i386-ieee1275",
-      .names = { "i386-ieee1275", NULL },
-      .voidp_sizeof = 4,
-      .bigendian = 0,
-      .id = IMAGE_I386_IEEE1275, 
-      .flags = PLATFORM_FLAGS_NONE,
-      .total_module_size = TARGET_NO_FIELD,
-      .decompressor_compressed_size = TARGET_NO_FIELD,
-      .decompressor_uncompressed_size = TARGET_NO_FIELD,
-      .decompressor_uncompressed_addr = TARGET_NO_FIELD,
-      .section_align = 1,
-      .vaddr_offset = 0,
-      .link_addr = GRUB_KERNEL_I386_IEEE1275_LINK_ADDR,
-      .elf_target = EM_386,
-      .mod_gap = GRUB_KERNEL_I386_IEEE1275_MOD_GAP,
-      .mod_align = GRUB_KERNEL_I386_IEEE1275_MOD_ALIGN,
-      .link_align = 4,
-    },
-    {
-      .dirname = "i386-qemu",
-      .names = { "i386-qemu", NULL },
-      .voidp_sizeof = 4,
-      .bigendian = 0,
-      .id = IMAGE_QEMU, 
-      .flags = PLATFORM_FLAGS_NONE,
-      .total_module_size = TARGET_NO_FIELD,
-      .decompressor_compressed_size = TARGET_NO_FIELD,
-      .decompressor_uncompressed_size = TARGET_NO_FIELD,
-      .decompressor_uncompressed_addr = TARGET_NO_FIELD,
-      .section_align = 1,
-      .vaddr_offset = 0,
-      .link_addr = GRUB_KERNEL_I386_QEMU_LINK_ADDR
-    },
-    {
-      .dirname = "x86_64-efi",
-      .names = { "x86_64-efi", NULL },
-      .voidp_sizeof = 8,
-      .bigendian = 0, 
-      .id = IMAGE_EFI, 
-      .flags = PLATFORM_FLAGS_NONE,
-      .total_module_size = TARGET_NO_FIELD,
-      .decompressor_compressed_size = TARGET_NO_FIELD,
-      .decompressor_uncompressed_size = TARGET_NO_FIELD,
-      .decompressor_uncompressed_addr = TARGET_NO_FIELD,
-      .section_align = GRUB_PE32_SECTION_ALIGNMENT,
-      .vaddr_offset = EFI64_HEADER_SIZE,
-      .pe_target = GRUB_PE32_MACHINE_X86_64,
-      .elf_target = EM_X86_64,
-    },
-    {
-      .dirname = "mipsel-loongson",
-      .names = { "mipsel-yeeloong-flash", NULL },
-      .voidp_sizeof = 4,
-      .bigendian = 0,
-      .id = IMAGE_YEELOONG_FLASH, 
-      .flags = PLATFORM_FLAGS_DECOMPRESSORS,
-      .total_module_size = GRUB_KERNEL_MIPS_LOONGSON_TOTAL_MODULE_SIZE,
-      .decompressor_compressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_COMPRESSED_SIZE,
-      .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_SIZE,
-      .decompressor_uncompressed_addr = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_ADDR,
-      .section_align = 1,
-      .vaddr_offset = 0,
-      .link_addr = GRUB_KERNEL_MIPS_LOONGSON_LINK_ADDR,
-      .elf_target = EM_MIPS,
-      .link_align = GRUB_KERNEL_MIPS_LOONGSON_LINK_ALIGN,
-      .default_compression = COMPRESSION_NONE
-    },
-    {
-      .dirname = "mipsel-loongson",
-      .names = { "mipsel-fuloong2f-flash", NULL },
-      .voidp_sizeof = 4,
-      .bigendian = 0,
-      .id = IMAGE_FULOONG2F_FLASH, 
-      .flags = PLATFORM_FLAGS_DECOMPRESSORS,
-      .total_module_size = GRUB_KERNEL_MIPS_LOONGSON_TOTAL_MODULE_SIZE,
-      .decompressor_compressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_COMPRESSED_SIZE,
-      .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_SIZE,
-      .decompressor_uncompressed_addr = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_ADDR,
-      .section_align = 1,
-      .vaddr_offset = 0,
-      .link_addr = GRUB_KERNEL_MIPS_LOONGSON_LINK_ADDR,
-      .elf_target = EM_MIPS,
-      .link_align = GRUB_KERNEL_MIPS_LOONGSON_LINK_ALIGN,
-      .default_compression = COMPRESSION_NONE
-    },
-    {
-      .dirname = "mipsel-loongson",
-      .names = { "mipsel-loongson-elf", "mipsel-yeeloong-elf",
-		 "mipsel-fuloong2f-elf", "mipsel-fuloong2e-elf",
-		 "mipsel-fuloong-elf", NULL },
-      .voidp_sizeof = 4,
-      .bigendian = 0,
-      .id = IMAGE_LOONGSON_ELF, 
-      .flags = PLATFORM_FLAGS_DECOMPRESSORS,
-      .total_module_size = GRUB_KERNEL_MIPS_LOONGSON_TOTAL_MODULE_SIZE,
-      .decompressor_compressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_COMPRESSED_SIZE,
-      .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_SIZE,
-      .decompressor_uncompressed_addr = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_ADDR,
-      .section_align = 1,
-      .vaddr_offset = 0,
-      .link_addr = GRUB_KERNEL_MIPS_LOONGSON_LINK_ADDR,
-      .elf_target = EM_MIPS,
-      .link_align = GRUB_KERNEL_MIPS_LOONGSON_LINK_ALIGN,
-      .default_compression = COMPRESSION_NONE
-    },
-    {
-      .dirname = "powerpc-ieee1275",
-      .names = { "powerpc-ieee1275", NULL },
-      .voidp_sizeof = 4,
-      .bigendian = 1,
-      .id = IMAGE_PPC, 
-      .flags = PLATFORM_FLAGS_NONE,
-      .total_module_size = TARGET_NO_FIELD,
-      .decompressor_compressed_size = TARGET_NO_FIELD,
-      .decompressor_uncompressed_size = TARGET_NO_FIELD,
-      .decompressor_uncompressed_addr = TARGET_NO_FIELD,
-      .section_align = 1,
-      .vaddr_offset = 0,
-      .link_addr = GRUB_KERNEL_POWERPC_IEEE1275_LINK_ADDR,
-      .elf_target = EM_PPC,
-      .mod_gap = GRUB_KERNEL_POWERPC_IEEE1275_MOD_GAP,
-      .mod_align = GRUB_KERNEL_POWERPC_IEEE1275_MOD_ALIGN,
-      .link_align = 4
-    },
-    {
-      .dirname = "sparc64-ieee1275",
-      .names = { "sparc64-ieee1275-raw", NULL },
-      .voidp_sizeof = 8,
-      .bigendian = 1, 
-      .id = IMAGE_SPARC64_RAW,
-      .flags = PLATFORM_FLAGS_NONE,
-      .total_module_size = GRUB_KERNEL_SPARC64_IEEE1275_TOTAL_MODULE_SIZE,
-      .decompressor_compressed_size = TARGET_NO_FIELD,
-      .decompressor_uncompressed_size = TARGET_NO_FIELD,
-      .decompressor_uncompressed_addr = TARGET_NO_FIELD,
-      .section_align = 1,
-      .vaddr_offset = 0,
-      .link_addr = GRUB_KERNEL_SPARC64_IEEE1275_LINK_ADDR
-    },
-    {
-      .dirname = "sparc64-ieee1275",
-      .names = { "sparc64-ieee1275-cdcore", NULL },
-      .voidp_sizeof = 8,
-      .bigendian = 1, 
-      .id = IMAGE_SPARC64_CDCORE,
-      .flags = PLATFORM_FLAGS_NONE,
-      .total_module_size = GRUB_KERNEL_SPARC64_IEEE1275_TOTAL_MODULE_SIZE,
-      .decompressor_compressed_size = TARGET_NO_FIELD,
-      .decompressor_uncompressed_size = TARGET_NO_FIELD,
-      .decompressor_uncompressed_addr = TARGET_NO_FIELD,
-      .section_align = 1,
-      .vaddr_offset = 0,
-      .link_addr = GRUB_KERNEL_SPARC64_IEEE1275_LINK_ADDR
-    },
-    {
-      .dirname = "sparc64-ieee1275",
-      .names = { "sparc64-ieee1275-aout", NULL },
-      .voidp_sizeof = 8,
-      .bigendian = 1,
-      .id = IMAGE_SPARC64_AOUT,
-      .flags = PLATFORM_FLAGS_NONE,
-      .total_module_size = GRUB_KERNEL_SPARC64_IEEE1275_TOTAL_MODULE_SIZE,
-      .decompressor_compressed_size = TARGET_NO_FIELD,
-      .decompressor_uncompressed_size = TARGET_NO_FIELD,
-      .decompressor_uncompressed_addr = TARGET_NO_FIELD,
-      .section_align = 1,
-      .vaddr_offset = 0,
-      .link_addr = GRUB_KERNEL_SPARC64_IEEE1275_LINK_ADDR
-    },
-    {
-      .dirname = "ia64-efi",
-      .names = {"ia64-efi", NULL},
-      .voidp_sizeof = 8,
-      .bigendian = 0, 
-      .id = IMAGE_EFI, 
-      .flags = PLATFORM_FLAGS_NONE,
-      .total_module_size = TARGET_NO_FIELD,
-      .decompressor_compressed_size = TARGET_NO_FIELD,
-      .decompressor_uncompressed_size = TARGET_NO_FIELD,
-      .decompressor_uncompressed_addr = TARGET_NO_FIELD,
-      .section_align = GRUB_PE32_SECTION_ALIGNMENT,
-      .vaddr_offset = EFI64_HEADER_SIZE,
-      .pe_target = GRUB_PE32_MACHINE_IA64,
-      .elf_target = EM_IA_64,
-    },
-    {
-      .dirname = "mips-arc",
-      .names = {"mips-arc", NULL},
-      .voidp_sizeof = 4,
-      .bigendian = 1,
-      .id = IMAGE_MIPS_ARC, 
-      .flags = PLATFORM_FLAGS_DECOMPRESSORS,
-      .total_module_size = GRUB_KERNEL_MIPS_ARC_TOTAL_MODULE_SIZE,
-      .decompressor_compressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_COMPRESSED_SIZE,
-      .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_SIZE,
-      .decompressor_uncompressed_addr = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_ADDR,
-      .section_align = 1,
-      .vaddr_offset = 0,
-      .link_addr = GRUB_KERNEL_MIPS_ARC_LINK_ADDR,
-      .elf_target = EM_MIPS,
-      .link_align = GRUB_KERNEL_MIPS_ARC_LINK_ALIGN,
-      .default_compression = COMPRESSION_NONE
-    },
-    {
-      .dirname = "mipsel-arc",
-      .names = {"mipsel-arc", NULL},
-      .voidp_sizeof = 4,
-      .bigendian = 0,
-      .id = IMAGE_MIPS_ARC, 
-      .flags = PLATFORM_FLAGS_DECOMPRESSORS,
-      .total_module_size = GRUB_KERNEL_MIPS_ARC_TOTAL_MODULE_SIZE,
-      .decompressor_compressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_COMPRESSED_SIZE,
-      .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_SIZE,
-      .decompressor_uncompressed_addr = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_ADDR,
-      .section_align = 1,
-      .vaddr_offset = 0,
-      .link_addr = GRUB_KERNEL_MIPSEL_ARC_LINK_ADDR,
-      .elf_target = EM_MIPS,
-      .link_align = GRUB_KERNEL_MIPS_ARC_LINK_ALIGN,
-      .default_compression = COMPRESSION_NONE
-    },
-    {
-      .dirname = "mipsel-qemu_mips",
-      .names = { "mipsel-qemu_mips-elf", NULL },
-      .voidp_sizeof = 4,
-      .bigendian = 0,
-      .id = IMAGE_LOONGSON_ELF, 
-      .flags = PLATFORM_FLAGS_DECOMPRESSORS,
-      .total_module_size = GRUB_KERNEL_MIPS_QEMU_MIPS_TOTAL_MODULE_SIZE,
-      .decompressor_compressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_COMPRESSED_SIZE,
-      .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_SIZE,
-      .decompressor_uncompressed_addr = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_ADDR,
-      .section_align = 1,
-      .vaddr_offset = 0,
-      .link_addr = GRUB_KERNEL_MIPS_QEMU_MIPS_LINK_ADDR,
-      .elf_target = EM_MIPS,
-      .link_align = GRUB_KERNEL_MIPS_QEMU_MIPS_LINK_ALIGN,
-      .default_compression = COMPRESSION_NONE
-    },
-    {
-      .dirname = "mips-qemu_mips",
-      .names = { "mips-qemu_mips-flash", NULL },
-      .voidp_sizeof = 4,
-      .bigendian = 1,
-      .id = IMAGE_QEMU_MIPS_FLASH, 
-      .flags = PLATFORM_FLAGS_DECOMPRESSORS,
-      .total_module_size = GRUB_KERNEL_MIPS_QEMU_MIPS_TOTAL_MODULE_SIZE,
-      .decompressor_compressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_COMPRESSED_SIZE,
-      .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_SIZE,
-      .decompressor_uncompressed_addr = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_ADDR,
-      .section_align = 1,
-      .vaddr_offset = 0,
-      .link_addr = GRUB_KERNEL_MIPS_QEMU_MIPS_LINK_ADDR,
-      .elf_target = EM_MIPS,
-      .link_align = GRUB_KERNEL_MIPS_QEMU_MIPS_LINK_ALIGN,
-      .default_compression = COMPRESSION_NONE
-    },
-    {
-      .dirname = "mipsel-qemu_mips",
-      .names = { "mipsel-qemu_mips-flash", NULL },
-      .voidp_sizeof = 4,
-      .bigendian = 0,
-      .id = IMAGE_QEMU_MIPS_FLASH, 
-      .flags = PLATFORM_FLAGS_DECOMPRESSORS,
-      .total_module_size = GRUB_KERNEL_MIPS_QEMU_MIPS_TOTAL_MODULE_SIZE,
-      .decompressor_compressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_COMPRESSED_SIZE,
-      .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_SIZE,
-      .decompressor_uncompressed_addr = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_ADDR,
-      .section_align = 1,
-      .vaddr_offset = 0,
-      .link_addr = GRUB_KERNEL_MIPS_QEMU_MIPS_LINK_ADDR,
-      .elf_target = EM_MIPS,
-      .link_align = GRUB_KERNEL_MIPS_QEMU_MIPS_LINK_ALIGN,
-      .default_compression = COMPRESSION_NONE
-    },
-    {
-      .dirname = "mips-qemu_mips",
-      .names = { "mips-qemu_mips-elf", NULL },
-      .voidp_sizeof = 4,
-      .bigendian = 1,
-      .id = IMAGE_LOONGSON_ELF, 
-      .flags = PLATFORM_FLAGS_DECOMPRESSORS,
-      .total_module_size = GRUB_KERNEL_MIPS_QEMU_MIPS_TOTAL_MODULE_SIZE,
-      .decompressor_compressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_COMPRESSED_SIZE,
-      .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_SIZE,
-      .decompressor_uncompressed_addr = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_ADDR,
-      .section_align = 1,
-      .vaddr_offset = 0,
-      .link_addr = GRUB_KERNEL_MIPS_QEMU_MIPS_LINK_ADDR,
-      .elf_target = EM_MIPS,
-      .link_align = GRUB_KERNEL_MIPS_QEMU_MIPS_LINK_ALIGN,
-      .default_compression = COMPRESSION_NONE
-    },
-    {
-      .dirname = "arm-uboot",
-      .names = { "arm-uboot", NULL },
-      .voidp_sizeof = 4,
-      .bigendian = 0,
-      .id = IMAGE_UBOOT, 
-      .flags = PLATFORM_FLAGS_NONE,
-      .total_module_size = GRUB_KERNEL_ARM_UBOOT_TOTAL_MODULE_SIZE,
-      .decompressor_compressed_size = TARGET_NO_FIELD,
-      .decompressor_uncompressed_size = TARGET_NO_FIELD,
-      .decompressor_uncompressed_addr = TARGET_NO_FIELD,
-      .section_align = GRUB_KERNEL_ARM_UBOOT_MOD_ALIGN,
-      .vaddr_offset = 0,
-      .link_addr = GRUB_KERNEL_ARM_UBOOT_LINK_ADDR,
-      .elf_target = EM_ARM,
-      .mod_gap = GRUB_KERNEL_ARM_UBOOT_MOD_GAP,
-      .mod_align = GRUB_KERNEL_ARM_UBOOT_MOD_ALIGN,
-      .link_align = 4
-    },
-    {
-      .dirname = "arm-efi",
-      .names = { "arm-efi", NULL },
-      .voidp_sizeof = 4,
-      .bigendian = 0, 
-      .id = IMAGE_EFI, 
-      .flags = PLATFORM_FLAGS_NONE,
-      .total_module_size = TARGET_NO_FIELD,
-      .decompressor_compressed_size = TARGET_NO_FIELD,
-      .decompressor_uncompressed_size = TARGET_NO_FIELD,
-      .decompressor_uncompressed_addr = TARGET_NO_FIELD,
-      .section_align = GRUB_PE32_SECTION_ALIGNMENT,
-      .vaddr_offset = ALIGN_UP (GRUB_PE32_MSDOS_STUB_SIZE
-                                + GRUB_PE32_SIGNATURE_SIZE
-                                + sizeof (struct grub_pe32_coff_header)
-                                + sizeof (struct grub_pe32_optional_header)
-                                + 4 * sizeof (struct grub_pe32_section_table),
-                                GRUB_PE32_SECTION_ALIGNMENT),
-      .pe_target = GRUB_PE32_MACHINE_ARMTHUMB_MIXED,
-      .elf_target = EM_ARM,
-    },
-  };
-
-#define grub_target_to_host32(x) (grub_target_to_host32_real (image_target, (x)))
-#define grub_host_to_target32(x) (grub_host_to_target32_real (image_target, (x)))
-#define grub_target_to_host64(x) (grub_target_to_host64_real (image_target, (x)))
-#define grub_host_to_target64(x) (grub_host_to_target64_real (image_target, (x)))
-#define grub_host_to_target_addr(x) (grub_host_to_target_addr_real (image_target, (x)))
-#define grub_target_to_host16(x) (grub_target_to_host16_real (image_target, (x)))
-#define grub_host_to_target16(x) (grub_host_to_target16_real (image_target, (x)))
-
-static inline grub_uint32_t
-grub_target_to_host32_real (struct image_target_desc *image_target, grub_uint32_t in)
-{
-  if (image_target->bigendian)
-    return grub_be_to_cpu32 (in);
-  else
-    return grub_le_to_cpu32 (in);
-}
-
-static inline grub_uint64_t
-grub_target_to_host64_real (struct image_target_desc *image_target, grub_uint64_t in)
-{
-  if (image_target->bigendian)
-    return grub_be_to_cpu64 (in);
-  else
-    return grub_le_to_cpu64 (in);
-}
-
-static inline grub_uint64_t
-grub_host_to_target64_real (struct image_target_desc *image_target, grub_uint64_t in)
-{
-  if (image_target->bigendian)
-    return grub_cpu_to_be64 (in);
-  else
-    return grub_cpu_to_le64 (in);
-}
-
-static inline grub_uint32_t
-grub_host_to_target32_real (struct image_target_desc *image_target, grub_uint32_t in)
-{
-  if (image_target->bigendian)
-    return grub_cpu_to_be32 (in);
-  else
-    return grub_cpu_to_le32 (in);
-}
-
-static inline grub_uint16_t
-grub_target_to_host16_real (struct image_target_desc *image_target, grub_uint16_t in)
-{
-  if (image_target->bigendian)
-    return grub_be_to_cpu16 (in);
-  else
-    return grub_le_to_cpu16 (in);
-}
-
-static inline grub_uint16_t
-grub_host_to_target16_real (struct image_target_desc *image_target, grub_uint16_t in)
-{
-  if (image_target->bigendian)
-    return grub_cpu_to_be16 (in);
-  else
-    return grub_cpu_to_le16 (in);
-}
-
-static inline grub_uint64_t
-grub_host_to_target_addr_real (struct image_target_desc *image_target, grub_uint64_t in)
-{
-  if (image_target->voidp_sizeof == 8)
-    return grub_host_to_target64_real (image_target, in);
-  else
-    return grub_host_to_target32_real (image_target, in);
-}
-
-static inline grub_uint64_t
-grub_target_to_host_real (struct image_target_desc *image_target, grub_uint64_t in)
-{
-  if (image_target->voidp_sizeof == 8)
-    return grub_target_to_host64_real (image_target, in);
-  else
-    return grub_target_to_host32_real (image_target, in);
-}
-
-#define GRUB_IEEE1275_NOTE_NAME "PowerPC"
-#define GRUB_IEEE1275_NOTE_TYPE 0x1275
-
-/* These structures are defined according to the CHRP binding to IEEE1275,
-   "Client Program Format" section.  */
-
-struct grub_ieee1275_note_hdr
-{
-  grub_uint32_t namesz;
-  grub_uint32_t descsz;
-  grub_uint32_t type;
-  char name[sizeof (GRUB_IEEE1275_NOTE_NAME)];
-};
-
-struct grub_ieee1275_note_desc
-{
-  grub_uint32_t real_mode;
-  grub_uint32_t real_base;
-  grub_uint32_t real_size;
-  grub_uint32_t virt_base;
-  grub_uint32_t virt_size;
-  grub_uint32_t load_base;
-};
-
-struct grub_ieee1275_note
-{
-  struct grub_ieee1275_note_hdr header;
-  struct grub_ieee1275_note_desc descriptor;
-};
-
-#define grub_target_to_host(val) grub_target_to_host_real(image_target, (val))
-
-#include <grub/lib/LzmaEnc.h>
-
-static void *SzAlloc(void *p, size_t size) { p = p; return xmalloc(size); }
-static void SzFree(void *p, void *address) { p = p; free(address); }
-static ISzAlloc g_Alloc = { SzAlloc, SzFree };
-
-static void
-compress_kernel_lzma (char *kernel_img, size_t kernel_size,
-		      char **core_img, size_t *core_size)
-{
-  CLzmaEncProps props;
-  unsigned char out_props[5];
-  size_t out_props_size = 5;
-
-  LzmaEncProps_Init(&props);
-  props.dictSize = 1 << 16;
-  props.lc = 3;
-  props.lp = 0;
-  props.pb = 2;
-  props.numThreads = 1;
-
-  *core_img = xmalloc (kernel_size);
-
-  *core_size = kernel_size;
-  if (LzmaEncode ((unsigned char *) *core_img, core_size,
-		  (unsigned char *) kernel_img,
-		  kernel_size,
-		  &props, out_props, &out_props_size,
-		  0, NULL, &g_Alloc, &g_Alloc) != SZ_OK)
-    grub_util_error ("%s", _("cannot compress the kernel image"));
-}
-
-#ifdef HAVE_LIBLZMA
-static void
-compress_kernel_xz (char *kernel_img, size_t kernel_size,
-		    char **core_img, size_t *core_size)
-{
-  lzma_stream strm = LZMA_STREAM_INIT;
-  lzma_ret xzret;
-  lzma_options_lzma lzopts = {
-    .dict_size = 1 << 16,
-    .preset_dict = NULL,
-    .preset_dict_size = 0,
-    .lc = 3,
-    .lp = 0,
-    .pb = 2,
-    .mode = LZMA_MODE_NORMAL,
-    .nice_len = 64,
-    .mf = LZMA_MF_BT4,
-    .depth = 0,
-  };
-  lzma_filter fltrs[] = {
-    { .id = LZMA_FILTER_LZMA2, .options = &lzopts},
-    { .id = LZMA_VLI_UNKNOWN, .options = NULL}
-  };
-
-  xzret = lzma_stream_encoder (&strm, fltrs, LZMA_CHECK_NONE);
-  if (xzret != LZMA_OK)
-    grub_util_error ("%s", _("cannot compress the kernel image"));
-
-  *core_img = xmalloc (kernel_size);
-
-  *core_size = kernel_size;
-  strm.next_in = (unsigned char *) kernel_img;
-  strm.avail_in = kernel_size;
-  strm.next_out = (unsigned char *) *core_img;
-  strm.avail_out = *core_size;
-
-  while (1)
-    {
-      xzret = lzma_code (&strm, LZMA_FINISH);
-      if (xzret == LZMA_OK)
-	continue;
-      if (xzret == LZMA_STREAM_END)
-	break;
-      grub_util_error ("%s", _("cannot compress the kernel image"));
-    }
-
-  *core_size -= strm.avail_out;
-}
-#endif
-
-static void
-compress_kernel (struct image_target_desc *image_target, char *kernel_img,
-		 size_t kernel_size, char **core_img, size_t *core_size,
-		 grub_compression_t comp)
-{
-  if (image_target->flags & PLATFORM_FLAGS_DECOMPRESSORS
-      && (comp == COMPRESSION_LZMA))
-    {
-      compress_kernel_lzma (kernel_img, kernel_size, core_img,
-			    core_size);
-      return;
-    }
-
-#ifdef HAVE_LIBLZMA
- if (image_target->flags & PLATFORM_FLAGS_DECOMPRESSORS
-     && (comp == COMPRESSION_XZ))
-   {
-     compress_kernel_xz (kernel_img, kernel_size, core_img,
-			 core_size);
-     return;
-   }
-#endif
-
- if (image_target->flags & PLATFORM_FLAGS_DECOMPRESSORS
-     && (comp != COMPRESSION_NONE))
-   grub_util_error (_("unknown compression %d\n"), comp);
-
-  *core_img = xmalloc (kernel_size);
-  memcpy (*core_img, kernel_img, kernel_size);
-  *core_size = kernel_size;
-}
-
-struct fixup_block_list
-{
-  struct fixup_block_list *next;
-  int state;
-  struct grub_pe32_fixup_block b;
-};
-
-#pragma GCC diagnostic ignored "-Wcast-align"
-
-#define MKIMAGE_ELF32 1
-#include "grub-mkimagexx.c"
-#undef MKIMAGE_ELF32
-
-#define MKIMAGE_ELF64 1
-#include "grub-mkimagexx.c"
-#undef MKIMAGE_ELF64
-
-static void
-generate_image (const char *dir, const char *prefix,
-		FILE *out, const char *outname, char *mods[],
-		char *memdisk_path, char **pubkey_paths, size_t npubkeys,
-		char *config_path, struct image_target_desc *image_target, int note,
-		grub_compression_t comp)
-{
-  char *kernel_img, *core_img;
-  size_t kernel_size, total_module_size, core_size, exec_size;
-  size_t memdisk_size = 0, config_size = 0, config_size_pure = 0;
-  size_t prefix_size = 0;
-  char *kernel_path;
-  size_t offset;
-  struct grub_util_path_list *path_list, *p, *next;
-  grub_size_t bss_size;
-  grub_uint64_t start_address;
-  void *rel_section = 0;
-  grub_size_t reloc_size = 0, align;
-  size_t decompress_size = 0;
-
-  if (comp == COMPRESSION_AUTO)
-    comp = image_target->default_compression;
-
-  if (image_target->id == IMAGE_I386_PC
-      || image_target->id == IMAGE_I386_PC_PXE)
-    comp = COMPRESSION_LZMA;
-
-  path_list = grub_util_resolve_dependencies (dir, "moddep.lst", mods);
-
-  kernel_path = grub_util_get_path (dir, "kernel.img");
-
-  if (image_target->voidp_sizeof == 8)
-    total_module_size = sizeof (struct grub_module_info64);
-  else
-    total_module_size = sizeof (struct grub_module_info32);
-
-  {
-    size_t i;
-    for (i = 0; i < npubkeys; i++)
-      {
-	size_t curs;
-	curs = ALIGN_ADDR (grub_util_get_image_size (pubkey_paths[i]));
-	grub_util_info ("the size of public key %zd is 0x%llx",
-			i, (unsigned long long) curs);
-	total_module_size += curs + sizeof (struct grub_module_header);
-      }
-  }
-
-  if (memdisk_path)
-    {
-      memdisk_size = ALIGN_UP(grub_util_get_image_size (memdisk_path), 512);
-      grub_util_info ("the size of memory disk is 0x%llx",
-		      (unsigned long long) memdisk_size);
-      total_module_size += memdisk_size + sizeof (struct grub_module_header);
-    }
-
-  if (config_path)
-    {
-      config_size_pure = grub_util_get_image_size (config_path) + 1;
-      config_size = ALIGN_ADDR (config_size_pure);
-      grub_util_info ("the size of config file is 0x%llx",
-		      (unsigned long long) config_size);
-      total_module_size += config_size + sizeof (struct grub_module_header);
-    }
-
-  if (prefix)
-    {
-      prefix_size = ALIGN_ADDR (strlen (prefix) + 1);
-      total_module_size += prefix_size + sizeof (struct grub_module_header);
-    }
-
-  for (p = path_list; p; p = p->next)
-    total_module_size += (ALIGN_ADDR (grub_util_get_image_size (p->name))
-			  + sizeof (struct grub_module_header));
-
-  grub_util_info ("the total module size is 0x%llx",
-		  (unsigned long long) total_module_size);
-
-  if (image_target->voidp_sizeof == 4)
-    kernel_img = load_image32 (kernel_path, &exec_size, &kernel_size, &bss_size,
-			       total_module_size, &start_address, &rel_section,
-			       &reloc_size, &align, image_target);
-  else
-    kernel_img = load_image64 (kernel_path, &exec_size, &kernel_size, &bss_size,
-			       total_module_size, &start_address, &rel_section,
-			       &reloc_size, &align, image_target);
-
-  if ((image_target->flags & PLATFORM_FLAGS_DECOMPRESSORS)
-      && (image_target->total_module_size != TARGET_NO_FIELD))
-    *((grub_uint32_t *) (kernel_img + image_target->total_module_size))
-      = grub_host_to_target32 (total_module_size);
-
-  if (image_target->flags & PLATFORM_FLAGS_MODULES_BEFORE_KERNEL)
-    memmove (kernel_img + total_module_size, kernel_img, kernel_size);
-
-  if (image_target->voidp_sizeof == 8)
-    {
-      /* Fill in the grub_module_info structure.  */
-      struct grub_module_info64 *modinfo;
-      if (image_target->flags & PLATFORM_FLAGS_MODULES_BEFORE_KERNEL)
-	modinfo = (struct grub_module_info64 *) kernel_img;
-      else
-	modinfo = (struct grub_module_info64 *) (kernel_img + kernel_size);
-      memset (modinfo, 0, sizeof (struct grub_module_info64));
-      modinfo->magic = grub_host_to_target32 (GRUB_MODULE_MAGIC);
-      modinfo->offset = grub_host_to_target_addr (sizeof (struct grub_module_info64));
-      modinfo->size = grub_host_to_target_addr (total_module_size);
-      if (image_target->flags & PLATFORM_FLAGS_MODULES_BEFORE_KERNEL)
-	offset = sizeof (struct grub_module_info64);
-      else
-	offset = kernel_size + sizeof (struct grub_module_info64);
-    }
-  else
-    {
-      /* Fill in the grub_module_info structure.  */
-      struct grub_module_info32 *modinfo;
-      if (image_target->flags & PLATFORM_FLAGS_MODULES_BEFORE_KERNEL)
-	modinfo = (struct grub_module_info32 *) kernel_img;
-      else
-	modinfo = (struct grub_module_info32 *) (kernel_img + kernel_size);
-      memset (modinfo, 0, sizeof (struct grub_module_info32));
-      modinfo->magic = grub_host_to_target32 (GRUB_MODULE_MAGIC);
-      modinfo->offset = grub_host_to_target_addr (sizeof (struct grub_module_info32));
-      modinfo->size = grub_host_to_target_addr (total_module_size);
-      if (image_target->flags & PLATFORM_FLAGS_MODULES_BEFORE_KERNEL)
-	offset = sizeof (struct grub_module_info32);
-      else
-	offset = kernel_size + sizeof (struct grub_module_info32);
-    }
-
-  for (p = path_list; p; p = p->next)
-    {
-      struct grub_module_header *header;
-      size_t mod_size, orig_size;
-
-      orig_size = grub_util_get_image_size (p->name);
-      mod_size = ALIGN_ADDR (orig_size);
-
-      header = (struct grub_module_header *) (kernel_img + offset);
-      memset (header, 0, sizeof (struct grub_module_header));
-      header->type = grub_host_to_target32 (OBJ_TYPE_ELF);
-      header->size = grub_host_to_target32 (mod_size + sizeof (*header));
-      offset += sizeof (*header);
-      memset (kernel_img + offset + orig_size, 0, mod_size - orig_size);
-
-      grub_util_load_image (p->name, kernel_img + offset);
-      offset += mod_size;
-    }
-
-  {
-    size_t i;
-    for (i = 0; i < npubkeys; i++)
-      {
-	size_t curs;
-	struct grub_module_header *header;
-
-	curs = grub_util_get_image_size (pubkey_paths[i]);
-
-	header = (struct grub_module_header *) (kernel_img + offset);
-	memset (header, 0, sizeof (struct grub_module_header));
-	header->type = grub_host_to_target32 (OBJ_TYPE_PUBKEY);
-	header->size = grub_host_to_target32 (curs + sizeof (*header));
-	offset += sizeof (*header);
-
-	grub_util_load_image (pubkey_paths[i], kernel_img + offset);
-	offset += ALIGN_ADDR (curs);
-      }
-  }
-
-  if (memdisk_path)
-    {
-      struct grub_module_header *header;
-
-      header = (struct grub_module_header *) (kernel_img + offset);
-      memset (header, 0, sizeof (struct grub_module_header));
-      header->type = grub_host_to_target32 (OBJ_TYPE_MEMDISK);
-      header->size = grub_host_to_target32 (memdisk_size + sizeof (*header));
-      offset += sizeof (*header);
-
-      grub_util_load_image (memdisk_path, kernel_img + offset);
-      offset += memdisk_size;
-    }
-
-  if (config_path)
-    {
-      struct grub_module_header *header;
-
-      header = (struct grub_module_header *) (kernel_img + offset);
-      memset (header, 0, sizeof (struct grub_module_header));
-      header->type = grub_host_to_target32 (OBJ_TYPE_CONFIG);
-      header->size = grub_host_to_target32 (config_size + sizeof (*header));
-      offset += sizeof (*header);
-
-      grub_util_load_image (config_path, kernel_img + offset);
-      *(kernel_img + offset + config_size_pure - 1) = 0;
-      offset += config_size;
-    }
-
-  if (prefix)
-    {
-      struct grub_module_header *header;
-
-      header = (struct grub_module_header *) (kernel_img + offset);
-      memset (header, 0, sizeof (struct grub_module_header));
-      header->type = grub_host_to_target32 (OBJ_TYPE_PREFIX);
-      header->size = grub_host_to_target32 (prefix_size + sizeof (*header));
-      offset += sizeof (*header);
-
-      grub_memset (kernel_img + offset, 0, prefix_size);
-      grub_strcpy (kernel_img + offset, prefix);
-      offset += prefix_size;
-    }
-
-  grub_util_info ("kernel_img=%p, kernel_size=0x%llx", kernel_img,
-		  (unsigned long long) kernel_size);
-  compress_kernel (image_target, kernel_img, kernel_size + total_module_size,
-		   &core_img, &core_size, comp);
-  free (kernel_img);
-
-  grub_util_info ("the core size is 0x%llx", (unsigned long long) core_size);
-
-  if (!(image_target->flags & PLATFORM_FLAGS_DECOMPRESSORS) 
-      && image_target->total_module_size != TARGET_NO_FIELD)
-    *((grub_uint32_t *) (core_img + image_target->total_module_size))
-      = grub_host_to_target32 (total_module_size);
-
-  if (image_target->flags & PLATFORM_FLAGS_DECOMPRESSORS)
-    {
-      char *full_img;
-      size_t full_size;
-      char *decompress_path, *decompress_img;
-      const char *name;
-
-      switch (comp)
-	{
-	case COMPRESSION_XZ:
-	  name = "xz_decompress.img";
-	  break;
-	case COMPRESSION_LZMA:
-	  name = "lzma_decompress.img";
-	  break;
-	case COMPRESSION_NONE:
-	  name = "none_decompress.img";
-	  break;
-	default:
-	  grub_util_error (_("unknown compression %d\n"), comp);
-	}
-      
-      decompress_path = grub_util_get_path (dir, name);
-      decompress_size = grub_util_get_image_size (decompress_path);
-      decompress_img = grub_util_read_image (decompress_path);
-
-      if ((image_target->id == IMAGE_I386_PC
-	   || image_target->id == IMAGE_I386_PC_PXE)
-	  && decompress_size > GRUB_KERNEL_I386_PC_LINK_ADDR - 0x8200)
-	grub_util_error ("%s", _("Decompressor is too big"));
-
-      if (image_target->decompressor_compressed_size != TARGET_NO_FIELD)
-	*((grub_uint32_t *) (decompress_img
-			     + image_target->decompressor_compressed_size))
-	  = grub_host_to_target32 (core_size);
-
-      if (image_target->decompressor_uncompressed_size != TARGET_NO_FIELD)
-	*((grub_uint32_t *) (decompress_img
-			     + image_target->decompressor_uncompressed_size))
-	  = grub_host_to_target32 (kernel_size + total_module_size);
-
-      if (image_target->decompressor_uncompressed_addr != TARGET_NO_FIELD)
-	{
-	  if (image_target->flags & PLATFORM_FLAGS_MODULES_BEFORE_KERNEL)
-	    *((grub_uint32_t *) (decompress_img + image_target->decompressor_uncompressed_addr))
-	      = grub_host_to_target_addr (image_target->link_addr - total_module_size);
-	  else
-	    *((grub_uint32_t *) (decompress_img + image_target->decompressor_uncompressed_addr))
-	      = grub_host_to_target_addr (image_target->link_addr);
-	}
-      full_size = core_size + decompress_size;
-
-      full_img = xmalloc (full_size);
-      memset (full_img, 0, full_size); 
-
-      memcpy (full_img, decompress_img, decompress_size);
-
-      memcpy (full_img + decompress_size, core_img, core_size);
-
-      memset (full_img + decompress_size + core_size, 0,
-	      full_size - (decompress_size + core_size));
-
-      free (core_img);
-      core_img = full_img;
-      core_size = full_size;
-    }
-
-  switch (image_target->id)
-    {
-    case IMAGE_I386_PC:
-    case IMAGE_I386_PC_PXE:
-	if (GRUB_KERNEL_I386_PC_LINK_ADDR + core_size > 0x78000
-	    || (core_size > (0xffff << GRUB_DISK_SECTOR_BITS))
-	    || (kernel_size + bss_size + GRUB_KERNEL_I386_PC_LINK_ADDR > 0x68000))
-	  grub_util_error (_("core image is too big (0x%x > 0x%x)"),
-			   GRUB_KERNEL_I386_PC_LINK_ADDR + (unsigned) core_size,
-			   0x78000);
-	/* fallthrough */
-    case IMAGE_COREBOOT:
-    case IMAGE_QEMU:
-	if (kernel_size + bss_size + GRUB_KERNEL_I386_PC_LINK_ADDR > 0x68000)
-	  grub_util_error (_("kernel image is too big (0x%x > 0x%x)"),
-			   (unsigned) kernel_size + (unsigned) bss_size
-			   + GRUB_KERNEL_I386_PC_LINK_ADDR,
-			   0x68000);
-	break;
-    case IMAGE_LOONGSON_ELF:
-    case IMAGE_YEELOONG_FLASH:
-    case IMAGE_FULOONG2F_FLASH:
-    case IMAGE_EFI:
-    case IMAGE_MIPS_ARC:
-    case IMAGE_QEMU_MIPS_FLASH:
-      break;
-    case IMAGE_SPARC64_AOUT:
-    case IMAGE_SPARC64_RAW:
-    case IMAGE_SPARC64_CDCORE:
-    case IMAGE_I386_IEEE1275:
-    case IMAGE_PPC:
-    case IMAGE_UBOOT:
-      break;
-    }
-
-  switch (image_target->id)
-    {
-    case IMAGE_I386_PC:
-    case IMAGE_I386_PC_PXE:
-      {
-	unsigned num;
-	char *boot_path, *boot_img;
-	size_t boot_size;
-
-	num = ((core_size + GRUB_DISK_SECTOR_SIZE - 1) >> GRUB_DISK_SECTOR_BITS);
-	if (image_target->id == IMAGE_I386_PC_PXE)
-	  {
-	    char *pxeboot_path, *pxeboot_img;
-	    size_t pxeboot_size;
-	    grub_uint32_t *ptr;
-	    
-	    pxeboot_path = grub_util_get_path (dir, "pxeboot.img");
-	    pxeboot_size = grub_util_get_image_size (pxeboot_path);
-	    pxeboot_img = grub_util_read_image (pxeboot_path);
-	    
-	    grub_util_write_image (pxeboot_img, pxeboot_size, out,
-				   outname);
-	    free (pxeboot_img);
-	    free (pxeboot_path);
-
-	    /* Remove Multiboot header to avoid confusing ipxe.  */
-	    for (ptr = (grub_uint32_t *) core_img;
-		 ptr < (grub_uint32_t *) (core_img + MULTIBOOT_SEARCH); ptr++)
-	      if (*ptr == grub_host_to_target32 (MULTIBOOT_HEADER_MAGIC)
-		  && grub_target_to_host32 (ptr[0])
-		  + grub_target_to_host32 (ptr[1])
-		  + grub_target_to_host32 (ptr[2]) == 0)
-		{
-		  *ptr = 0;
-		  break;
-		}
-	  }
-
-	boot_path = grub_util_get_path (dir, "diskboot.img");
-	boot_size = grub_util_get_image_size (boot_path);
-	if (boot_size != GRUB_DISK_SECTOR_SIZE)
-	  grub_util_error (_("diskboot.img size must be %u bytes"),
-			   GRUB_DISK_SECTOR_SIZE);
-
-	boot_img = grub_util_read_image (boot_path);
-
-	{
-	  struct grub_pc_bios_boot_blocklist *block;
-	  block = (struct grub_pc_bios_boot_blocklist *) (boot_img
-							  + GRUB_DISK_SECTOR_SIZE
-							  - sizeof (*block));
-	  block->len = grub_host_to_target16 (num);
-
-	  /* This is filled elsewhere.  Verify it just in case.  */
-	  assert (block->segment
-		  == grub_host_to_target16 (GRUB_BOOT_I386_PC_KERNEL_SEG
-					    + (GRUB_DISK_SECTOR_SIZE >> 4)));
-	}
-
-	grub_util_write_image (boot_img, boot_size, out, outname);
-	free (boot_img);
-	free (boot_path);
-      }
-      break;
-    case IMAGE_EFI:
-      {
-	void *pe_img;
-	grub_uint8_t *header;
-	void *sections;
-	size_t pe_size;
-	struct grub_pe32_coff_header *c;
-	struct grub_pe32_section_table *text_section, *data_section;
-	struct grub_pe32_section_table *mods_section, *reloc_section;
-	static const grub_uint8_t stub[] = GRUB_PE32_MSDOS_STUB;
-	int header_size;
-	int reloc_addr;
-
-	if (image_target->voidp_sizeof == 4)
-	  header_size = EFI32_HEADER_SIZE;
-	else
-	  header_size = EFI64_HEADER_SIZE;
-
-	reloc_addr = ALIGN_UP (header_size + core_size,
-			       image_target->section_align);
-
-	pe_size = ALIGN_UP (reloc_addr + reloc_size,
-			    image_target->section_align);
-	pe_img = xmalloc (reloc_addr + reloc_size);
-	memset (pe_img, 0, header_size);
-	memcpy ((char *) pe_img + header_size, core_img, core_size);
-	memcpy ((char *) pe_img + reloc_addr, rel_section, reloc_size);
-	header = pe_img;
-
-	/* The magic.  */
-	memcpy (header, stub, GRUB_PE32_MSDOS_STUB_SIZE);
-	memcpy (header + GRUB_PE32_MSDOS_STUB_SIZE, "PE\0\0",
-		GRUB_PE32_SIGNATURE_SIZE);
-
-	/* The COFF file header.  */
-	c = (struct grub_pe32_coff_header *) (header + GRUB_PE32_MSDOS_STUB_SIZE
-					      + GRUB_PE32_SIGNATURE_SIZE);
-	c->machine = grub_host_to_target16 (image_target->pe_target);
-
-	c->num_sections = grub_host_to_target16 (4);
-	c->time = grub_host_to_target32 (time (0));
-	c->characteristics = grub_host_to_target16 (GRUB_PE32_EXECUTABLE_IMAGE
-						    | GRUB_PE32_LINE_NUMS_STRIPPED
-						    | ((image_target->voidp_sizeof == 4)
-						       ? GRUB_PE32_32BIT_MACHINE
-						       : 0)
-						    | GRUB_PE32_LOCAL_SYMS_STRIPPED
-						    | GRUB_PE32_DEBUG_STRIPPED);
-
-	/* The PE Optional header.  */
-	if (image_target->voidp_sizeof == 4)
-	  {
-	    struct grub_pe32_optional_header *o;
-
-	    c->optional_header_size = grub_host_to_target16 (sizeof (struct grub_pe32_optional_header));
-
-	    o = (struct grub_pe32_optional_header *)
-	      (header + GRUB_PE32_MSDOS_STUB_SIZE + GRUB_PE32_SIGNATURE_SIZE
-	       + sizeof (struct grub_pe32_coff_header));
-	    o->magic = grub_host_to_target16 (GRUB_PE32_PE32_MAGIC);
-	    o->code_size = grub_host_to_target32 (exec_size);
-	    o->data_size = grub_cpu_to_le32 (reloc_addr - exec_size
-					     - header_size);
-	    o->bss_size = grub_cpu_to_le32 (bss_size);
-	    o->entry_addr = grub_cpu_to_le32 (start_address);
-	    o->code_base = grub_cpu_to_le32 (header_size);
-
-	    o->data_base = grub_host_to_target32 (header_size + exec_size);
-
-	    o->image_base = 0;
-	    o->section_alignment = grub_host_to_target32 (image_target->section_align);
-	    o->file_alignment = grub_host_to_target32 (image_target->section_align);
-	    o->image_size = grub_host_to_target32 (pe_size);
-	    o->header_size = grub_host_to_target32 (header_size);
-	    o->subsystem = grub_host_to_target16 (GRUB_PE32_SUBSYSTEM_EFI_APPLICATION);
-
-	    /* Do these really matter? */
-	    o->stack_reserve_size = grub_host_to_target32 (0x10000);
-	    o->stack_commit_size = grub_host_to_target32 (0x10000);
-	    o->heap_reserve_size = grub_host_to_target32 (0x10000);
-	    o->heap_commit_size = grub_host_to_target32 (0x10000);
-    
-	    o->num_data_directories = grub_host_to_target32 (GRUB_PE32_NUM_DATA_DIRECTORIES);
-
-	    o->base_relocation_table.rva = grub_host_to_target32 (reloc_addr);
-	    o->base_relocation_table.size = grub_host_to_target32 (reloc_size);
-	    sections = o + 1;
-	  }
-	else
-	  {
-	    struct grub_pe64_optional_header *o;
-
-	    c->optional_header_size = grub_host_to_target16 (sizeof (struct grub_pe64_optional_header));
-
-	    o = (struct grub_pe64_optional_header *) 
-	      (header + GRUB_PE32_MSDOS_STUB_SIZE + GRUB_PE32_SIGNATURE_SIZE
-	       + sizeof (struct grub_pe32_coff_header));
-	    o->magic = grub_host_to_target16 (GRUB_PE32_PE64_MAGIC);
-	    o->code_size = grub_host_to_target32 (exec_size);
-	    o->data_size = grub_cpu_to_le32 (reloc_addr - exec_size
-					     - header_size);
-	    o->bss_size = grub_cpu_to_le32 (bss_size);
-	    o->entry_addr = grub_cpu_to_le32 (start_address);
-	    o->code_base = grub_cpu_to_le32 (header_size);
-	    o->image_base = 0;
-	    o->section_alignment = grub_host_to_target32 (image_target->section_align);
-	    o->file_alignment = grub_host_to_target32 (image_target->section_align);
-	    o->image_size = grub_host_to_target32 (pe_size);
-	    o->header_size = grub_host_to_target32 (header_size);
-	    o->subsystem = grub_host_to_target16 (GRUB_PE32_SUBSYSTEM_EFI_APPLICATION);
-
-	    /* Do these really matter? */
-	    o->stack_reserve_size = grub_host_to_target64 (0x10000);
-	    o->stack_commit_size = grub_host_to_target64 (0x10000);
-	    o->heap_reserve_size = grub_host_to_target64 (0x10000);
-	    o->heap_commit_size = grub_host_to_target64 (0x10000);
-    
-	    o->num_data_directories
-	      = grub_host_to_target32 (GRUB_PE32_NUM_DATA_DIRECTORIES);
-
-	    o->base_relocation_table.rva = grub_host_to_target32 (reloc_addr);
-	    o->base_relocation_table.size = grub_host_to_target32 (reloc_size);
-	    sections = o + 1;
-	  }
-	/* The sections.  */
-	text_section = sections;
-	strcpy (text_section->name, ".text");
-	text_section->virtual_size = grub_cpu_to_le32 (exec_size);
-	text_section->virtual_address = grub_cpu_to_le32 (header_size);
-	text_section->raw_data_size = grub_cpu_to_le32 (exec_size);
-	text_section->raw_data_offset = grub_cpu_to_le32 (header_size);
-	text_section->characteristics = grub_cpu_to_le32 (GRUB_PE32_SCN_CNT_CODE
-							  | GRUB_PE32_SCN_MEM_EXECUTE
-							  | GRUB_PE32_SCN_MEM_READ);
-
-	data_section = text_section + 1;
-	strcpy (data_section->name, ".data");
-	data_section->virtual_size = grub_cpu_to_le32 (kernel_size - exec_size);
-	data_section->virtual_address = grub_cpu_to_le32 (header_size + exec_size);
-	data_section->raw_data_size = grub_cpu_to_le32 (kernel_size - exec_size);
-	data_section->raw_data_offset = grub_cpu_to_le32 (header_size + exec_size);
-	data_section->characteristics
-	  = grub_cpu_to_le32 (GRUB_PE32_SCN_CNT_INITIALIZED_DATA
-			      | GRUB_PE32_SCN_MEM_READ
-			      | GRUB_PE32_SCN_MEM_WRITE);
-
-#if 0
-	bss_section = data_section + 1;
-	strcpy (bss_section->name, ".bss");
-	bss_section->virtual_size = grub_cpu_to_le32 (bss_size);
-	bss_section->virtual_address = grub_cpu_to_le32 (header_size + kernel_size);
-	bss_section->raw_data_size = 0;
-	bss_section->raw_data_offset = 0;
-	bss_section->characteristics
-	  = grub_cpu_to_le32 (GRUB_PE32_SCN_MEM_READ
-			      | GRUB_PE32_SCN_MEM_WRITE
-			      | GRUB_PE32_SCN_ALIGN_64BYTES
-			      | GRUB_PE32_SCN_CNT_INITIALIZED_DATA
-			      | 0x80);
-#endif
-    
-	mods_section = data_section + 1;
-	strcpy (mods_section->name, "mods");
-	mods_section->virtual_size = grub_cpu_to_le32 (reloc_addr - kernel_size - header_size);
-	mods_section->virtual_address = grub_cpu_to_le32 (header_size + kernel_size + bss_size);
-	mods_section->raw_data_size = grub_cpu_to_le32 (reloc_addr - kernel_size - header_size);
-	mods_section->raw_data_offset = grub_cpu_to_le32 (header_size + kernel_size);
-	mods_section->characteristics
-	  = grub_cpu_to_le32 (GRUB_PE32_SCN_CNT_INITIALIZED_DATA
-			      | GRUB_PE32_SCN_MEM_READ
-			      | GRUB_PE32_SCN_MEM_WRITE);
-
-	reloc_section = mods_section + 1;
-	strcpy (reloc_section->name, ".reloc");
-	reloc_section->virtual_size = grub_cpu_to_le32 (reloc_size);
-	reloc_section->virtual_address = grub_cpu_to_le32 (reloc_addr + bss_size);
-	reloc_section->raw_data_size = grub_cpu_to_le32 (reloc_size);
-	reloc_section->raw_data_offset = grub_cpu_to_le32 (reloc_addr);
-	reloc_section->characteristics
-	  = grub_cpu_to_le32 (GRUB_PE32_SCN_CNT_INITIALIZED_DATA
-			      | GRUB_PE32_SCN_MEM_DISCARDABLE
-			      | GRUB_PE32_SCN_MEM_READ);
-	free (core_img);
-	core_img = pe_img;
-	core_size = pe_size;
-      }
-      break;
-    case IMAGE_QEMU:
-      {
-	char *rom_img;
-	size_t rom_size;
-	char *boot_path, *boot_img;
-	size_t boot_size;
-
-	boot_path = grub_util_get_path (dir, "boot.img");
-	boot_size = grub_util_get_image_size (boot_path);
-	boot_img = grub_util_read_image (boot_path);
-
-	/* Rom sizes must be 64k-aligned.  */
-	rom_size = ALIGN_UP (core_size + boot_size, 64 * 1024);
-
-	rom_img = xmalloc (rom_size);
-	memset (rom_img, 0, rom_size);
-
-	*((grub_int32_t *) (core_img + GRUB_KERNEL_I386_QEMU_CORE_ENTRY_ADDR))
-	  = grub_host_to_target32 ((grub_uint32_t) -rom_size);
-
-	memcpy (rom_img, core_img, core_size);
-
-	*((grub_int32_t *) (boot_img + GRUB_BOOT_I386_QEMU_CORE_ENTRY_ADDR))
-	  = grub_host_to_target32 ((grub_uint32_t) -rom_size);
-
-	memcpy (rom_img + rom_size - boot_size, boot_img, boot_size);
-
-	free (core_img);
-	core_img = rom_img;
-	core_size = rom_size;
-
-	free (boot_img);
-	free (boot_path);
-      }
-      break;
-    case IMAGE_SPARC64_AOUT:
-      {
-	void *aout_img;
-	size_t aout_size;
-	struct grub_aout32_header *aout_head;
-
-	aout_size = core_size + sizeof (*aout_head);
-	aout_img = xmalloc (aout_size);
-	aout_head = aout_img;
-	grub_memset (aout_head, 0, sizeof (*aout_head));
-	aout_head->a_midmag = grub_host_to_target32 ((AOUT_MID_SUN << 16)
-						     | AOUT32_OMAGIC);
-	aout_head->a_text = grub_host_to_target32 (core_size);
-	aout_head->a_entry
-	  = grub_host_to_target32 (GRUB_BOOT_SPARC64_IEEE1275_IMAGE_ADDRESS);
-	memcpy ((char *) aout_img + sizeof (*aout_head), core_img, core_size);
-
-	free (core_img);
-	core_img = aout_img;
-	core_size = aout_size;
-      }
-      break;
-    case IMAGE_SPARC64_RAW:
-      {
-	unsigned int num;
-	char *boot_path, *boot_img;
-	size_t boot_size;
-
-	num = ((core_size + GRUB_DISK_SECTOR_SIZE - 1) >> GRUB_DISK_SECTOR_BITS);
-	num <<= GRUB_DISK_SECTOR_BITS;
-
-	boot_path = grub_util_get_path (dir, "diskboot.img");
-	boot_size = grub_util_get_image_size (boot_path);
-	if (boot_size != GRUB_DISK_SECTOR_SIZE)
-	  grub_util_error (_("diskboot.img size must be %u bytes"),
-			   GRUB_DISK_SECTOR_SIZE);
-
-	boot_img = grub_util_read_image (boot_path);
-
-	*((grub_uint32_t *) (boot_img + GRUB_DISK_SECTOR_SIZE
-			     - GRUB_BOOT_SPARC64_IEEE1275_LIST_SIZE + 8))
-	  = grub_host_to_target32 (num);
-
-	grub_util_write_image (boot_img, boot_size, out, outname);
-	free (boot_img);
-	free (boot_path);
-      }
-      break;
-    case IMAGE_SPARC64_CDCORE:
-      break;
-    case IMAGE_YEELOONG_FLASH:
-    case IMAGE_FULOONG2F_FLASH:
-    {
-      char *rom_img;
-      size_t rom_size;
-      char *boot_path, *boot_img;
-      size_t boot_size;
-      grub_uint8_t context[GRUB_MD_SHA512->contextsize];
-      /* fwstart.img is the only part which can't be tested by using *-elf
-	 target. Check it against the checksum. */
-      const grub_uint8_t yeeloong_fwstart_good_hash[512 / 8] = 
-	{
-	  0x5f, 0x67, 0x46, 0x57, 0x31, 0x30, 0xc5, 0x0a,
-	  0xe9, 0x98, 0x18, 0xc9, 0xf3, 0xca, 0x45, 0xa5,
-	  0x75, 0x64, 0x6b, 0xbb, 0x24, 0xcd, 0xb4, 0xbc,
-	  0xf2, 0x3e, 0x23, 0xf9, 0xc2, 0x6a, 0x8c, 0xde,
-	  0x3b, 0x94, 0x9c, 0xcc, 0xa5, 0xa7, 0x58, 0xb1,
-	  0xbe, 0x8b, 0x3d, 0x73, 0x98, 0x18, 0x7e, 0x68,
-	  0x5e, 0x5f, 0x23, 0x7d, 0x7a, 0xe8, 0x51, 0xf7,
-	  0x1a, 0xaf, 0x2f, 0x54, 0x11, 0x2e, 0x5c, 0x25
-	};
-      const grub_uint8_t fuloong2f_fwstart_good_hash[512 / 8] = 
-	{ 
-	  0x76, 0x9b, 0xad, 0x6e, 0xa2, 0x39, 0x47, 0x62,
-	  0x1f, 0xc9, 0x3a, 0x6d, 0x05, 0x5c, 0x43, 0x5c,
-	  0x29, 0x4a, 0x7e, 0x08, 0x2a, 0x31, 0x8f, 0x5d,
-	  0x02, 0x84, 0xa0, 0x85, 0xf2, 0xd1, 0xb9, 0x53,
-	  0xa2, 0xbc, 0xf2, 0xe1, 0x39, 0x1e, 0x51, 0xb5,
-	  0xaf, 0xec, 0x9e, 0xf2, 0xf1, 0xf3, 0x0a, 0x2f,
-	  0xe6, 0xf1, 0x08, 0x89, 0xbe, 0xbc, 0x73, 0xab,
-	  0x46, 0x50, 0xd6, 0x21, 0xce, 0x8e, 0x24, 0xa7
-	};
-      const grub_uint8_t *fwstart_good_hash;
-            
-      if (image_target->id == IMAGE_FULOONG2F_FLASH)
-	{
-	  fwstart_good_hash = fuloong2f_fwstart_good_hash;
-	  boot_path = grub_util_get_path (dir, "fwstart_fuloong2f.img");
-	}
-      else
-	{
-	  fwstart_good_hash = yeeloong_fwstart_good_hash;
-	  boot_path = grub_util_get_path (dir, "fwstart.img");
-	}
-
-      boot_size = grub_util_get_image_size (boot_path);
-      boot_img = grub_util_read_image (boot_path);
-
-      grub_memset (context, 0, sizeof (context));
-      GRUB_MD_SHA512->init (context);
-      GRUB_MD_SHA512->write (context, boot_img, boot_size);
-      GRUB_MD_SHA512->final (context);
-      if (grub_memcmp (GRUB_MD_SHA512->read (context), fwstart_good_hash,
-		       GRUB_MD_SHA512->mdlen) != 0)
-	/* TRANSLATORS: fwstart.img may still be good, just it wasn't checked.  */
-	grub_util_warn ("%s",
-			_("fwstart.img doesn't match the known good version. "
-			  "proceed at your own risk"));
-
-      if (core_size + boot_size > 512 * 1024)
-	grub_util_error ("%s", _("firmware image is too big"));
-      rom_size = 512 * 1024;
-
-      rom_img = xmalloc (rom_size);
-      memset (rom_img, 0, rom_size); 
-
-      memcpy (rom_img, boot_img, boot_size);
-
-      memcpy (rom_img + boot_size, core_img, core_size);
-
-      memset (rom_img + boot_size + core_size, 0,
-	      rom_size - (boot_size + core_size));
-
-      free (core_img);
-      core_img = rom_img;
-      core_size = rom_size;
-    }
-    break;
-    case IMAGE_QEMU_MIPS_FLASH:
-    {
-      char *rom_img;
-      size_t rom_size;
-
-      if (core_size > 512 * 1024)
-	grub_util_error ("%s", _("firmware image is too big"));
-      rom_size = 512 * 1024;
-
-      rom_img = xmalloc (rom_size);
-      memset (rom_img, 0, rom_size); 
-
-      memcpy (rom_img, core_img, core_size);
-
-      memset (rom_img + core_size, 0,
-	      rom_size - core_size);
-
-      free (core_img);
-      core_img = rom_img;
-      core_size = rom_size;
-    }
-    break;
-
-    case IMAGE_UBOOT:
-    {
-      struct grub_uboot_image_header *hdr;
-      GRUB_PROPERLY_ALIGNED_ARRAY (crc32_context, GRUB_MD_CRC32->contextsize);
-
-      hdr = xmalloc (core_size + sizeof (struct grub_uboot_image_header));
-      memcpy (hdr + 1, core_img, core_size);
-
-      memset (hdr, 0, sizeof (*hdr));
-      hdr->ih_magic = grub_cpu_to_be32_compile_time (GRUB_UBOOT_IH_MAGIC);
-      hdr->ih_time = grub_cpu_to_be32 (time (0));
-      hdr->ih_size = grub_cpu_to_be32 (core_size);
-      hdr->ih_load = grub_cpu_to_be32 (image_target->link_addr);
-      hdr->ih_ep = grub_cpu_to_be32 (image_target->link_addr);
-      hdr->ih_type = GRUB_UBOOT_IH_TYPE_KERNEL;
-      hdr->ih_os = GRUB_UBOOT_IH_OS_LINUX;
-      hdr->ih_arch = GRUB_UBOOT_IH_ARCH_ARM;
-      hdr->ih_comp = GRUB_UBOOT_IH_COMP_NONE;
-
-      GRUB_MD_CRC32->init(crc32_context);
-      GRUB_MD_CRC32->write(crc32_context, hdr + 1, core_size);
-      GRUB_MD_CRC32->final(crc32_context);
-      hdr->ih_dcrc = grub_get_unaligned32 (GRUB_MD_CRC32->read (crc32_context));
-
-      GRUB_MD_CRC32->init(crc32_context);
-      GRUB_MD_CRC32->write(crc32_context, hdr, sizeof (*hdr));
-      GRUB_MD_CRC32->final(crc32_context);
-      hdr->ih_hcrc = grub_get_unaligned32 (GRUB_MD_CRC32->read (crc32_context));
-
-      free (core_img);
-      core_img = (char *) hdr;
-      core_size += sizeof (struct grub_uboot_image_header);
-    }
-    break;
-
-    case IMAGE_MIPS_ARC:
-      {
-	char *ecoff_img;
-	struct ecoff_header {
-	  grub_uint16_t magic;
-	  grub_uint16_t nsec;
-	  grub_uint32_t time;
-	  grub_uint32_t syms;
-	  grub_uint32_t nsyms;
-	  grub_uint16_t opt;
-	  grub_uint16_t flags;
-	  grub_uint16_t magic2;
-	  grub_uint16_t version;
-	  grub_uint32_t textsize;
-	  grub_uint32_t datasize;
-	  grub_uint32_t bsssize;
-	  grub_uint32_t entry;
-	  grub_uint32_t text_start;
-	  grub_uint32_t data_start;
-	  grub_uint32_t bss_start;
-	  grub_uint32_t gprmask;
-	  grub_uint32_t cprmask[4];
-	  grub_uint32_t gp_value;
-	};
-	struct ecoff_section
-	{
-	  char name[8];
-	  grub_uint32_t paddr;
-	  grub_uint32_t vaddr;
-	  grub_uint32_t size;
-	  grub_uint32_t file_offset;
-	  grub_uint32_t reloc;
-	  grub_uint32_t gp;
-	  grub_uint16_t nreloc;
-	  grub_uint16_t ngp;
-	  grub_uint32_t flags;
-	};
-	struct ecoff_header *head;
-	struct ecoff_section *section;
-	grub_uint32_t target_addr;
-	size_t program_size;
-
-	program_size = ALIGN_ADDR (core_size);
-	if (comp == COMPRESSION_NONE)
-	  target_addr = (image_target->link_addr - decompress_size);
-	else
-	  target_addr = ALIGN_UP (image_target->link_addr
-				  + kernel_size + total_module_size, 32);
-
-	ecoff_img = xmalloc (program_size + sizeof (*head) + sizeof (*section));
-	grub_memset (ecoff_img, 0, program_size + sizeof (*head) + sizeof (*section));
-	head = (void *) ecoff_img;
-	section = (void *) (head + 1);
-	head->magic = image_target->bigendian ? grub_host_to_target16 (0x160)
-	  : grub_host_to_target16 (0x166);
-	head->nsec = grub_host_to_target16 (1);
-	head->time = grub_host_to_target32 (0);
-	head->opt = grub_host_to_target16 (0x38);
-	head->flags = image_target->bigendian
-	  ? grub_host_to_target16 (0x207)
-	  : grub_host_to_target16 (0x103);
-	head->magic2 = grub_host_to_target16 (0x107);
-	head->textsize = grub_host_to_target32 (program_size);
-	head->entry = grub_host_to_target32 (target_addr);
-	head->text_start = grub_host_to_target32 (target_addr);
-	head->data_start = grub_host_to_target32 (target_addr + program_size);
-	grub_memcpy (section->name, ".text", sizeof (".text") - 1); 
-	section->vaddr = grub_host_to_target32 (target_addr);
-	section->size = grub_host_to_target32 (program_size);
-	section->file_offset = grub_host_to_target32 (sizeof (*head) + sizeof (*section));
-	if (!image_target->bigendian)
-	  {
-	    section->paddr = grub_host_to_target32 (0xaa60);
-	    section->flags = grub_host_to_target32 (0x20);
-	  }
-	memcpy (section + 1, core_img, core_size);
-	free (core_img);
-	core_img = ecoff_img;
-	core_size = program_size + sizeof (*head) + sizeof (*section);
-      }
-      break;
-    case IMAGE_LOONGSON_ELF:
-    case IMAGE_PPC:
-    case IMAGE_COREBOOT:
-    case IMAGE_I386_IEEE1275:
-      {
-	char *elf_img;
-	size_t program_size;
-	Elf32_Ehdr *ehdr;
-	Elf32_Phdr *phdr;
-	grub_uint32_t target_addr;
-	int header_size, footer_size = 0;
-	int phnum = 1;
-	
-	if (image_target->id != IMAGE_LOONGSON_ELF)
-	  phnum += 2;
-
-	if (note)
-	  {
-	    phnum++;
-	    footer_size += sizeof (struct grub_ieee1275_note);
-	  }
-	header_size = ALIGN_ADDR (sizeof (*ehdr) + phnum * sizeof (*phdr));
-
-	program_size = ALIGN_ADDR (core_size);
-
-	elf_img = xmalloc (program_size + header_size + footer_size);
-	memset (elf_img, 0, program_size + header_size);
-	memcpy (elf_img  + header_size, core_img, core_size);
-	ehdr = (void *) elf_img;
-	phdr = (void *) (elf_img + sizeof (*ehdr));
-	memcpy (ehdr->e_ident, ELFMAG, SELFMAG);
-	ehdr->e_ident[EI_CLASS] = ELFCLASS32;
-	if (!image_target->bigendian)
-	  ehdr->e_ident[EI_DATA] = ELFDATA2LSB;
-	else
-	  ehdr->e_ident[EI_DATA] = ELFDATA2MSB;
-	ehdr->e_ident[EI_VERSION] = EV_CURRENT;
-	ehdr->e_ident[EI_OSABI] = ELFOSABI_NONE;
-	ehdr->e_type = grub_host_to_target16 (ET_EXEC);
-	ehdr->e_machine = grub_host_to_target16 (image_target->elf_target);
-	ehdr->e_version = grub_host_to_target32 (EV_CURRENT);
-
-	ehdr->e_phoff = grub_host_to_target32 ((char *) phdr - (char *) ehdr);
-	ehdr->e_phentsize = grub_host_to_target16 (sizeof (*phdr));
-	ehdr->e_phnum = grub_host_to_target16 (phnum);
-
-	/* No section headers.  */
-	ehdr->e_shoff = grub_host_to_target32 (0);
-	if (image_target->id == IMAGE_LOONGSON_ELF)
-	  ehdr->e_shentsize = grub_host_to_target16 (0);
-	else
-	  ehdr->e_shentsize = grub_host_to_target16 (sizeof (Elf32_Shdr));
-	ehdr->e_shnum = grub_host_to_target16 (0);
-	ehdr->e_shstrndx = grub_host_to_target16 (0);
-
-	ehdr->e_ehsize = grub_host_to_target16 (sizeof (*ehdr));
-
-	phdr->p_type = grub_host_to_target32 (PT_LOAD);
-	phdr->p_offset = grub_host_to_target32 (header_size);
-	phdr->p_flags = grub_host_to_target32 (PF_R | PF_W | PF_X);
-
-	if (image_target->id == IMAGE_LOONGSON_ELF)
-	  {
-	    if (comp == COMPRESSION_NONE)
-	      target_addr = (image_target->link_addr - decompress_size);
-	    else
-	      target_addr = ALIGN_UP (image_target->link_addr
-				      + kernel_size + total_module_size, 32);
-	  }
-	else
-	  target_addr = image_target->link_addr;
-	ehdr->e_entry = grub_host_to_target32 (target_addr);
-	phdr->p_vaddr = grub_host_to_target32 (target_addr);
-	phdr->p_paddr = grub_host_to_target32 (target_addr);
-	phdr->p_align = grub_host_to_target32 (align > image_target->link_align ? align : image_target->link_align);
-	if (image_target->id == IMAGE_LOONGSON_ELF)
-	  ehdr->e_flags = grub_host_to_target32 (0x1000 | EF_MIPS_NOREORDER 
-						 | EF_MIPS_PIC | EF_MIPS_CPIC);
-	else
-	  ehdr->e_flags = 0;
-	if (image_target->id == IMAGE_LOONGSON_ELF)
-	  {
-	    phdr->p_filesz = grub_host_to_target32 (core_size);
-	    phdr->p_memsz = grub_host_to_target32 (core_size);
-	  }
-	else
-	  {
-	    grub_uint32_t target_addr_mods;
-	    phdr->p_filesz = grub_host_to_target32 (kernel_size);
-	    phdr->p_memsz = grub_host_to_target32 (kernel_size + bss_size);
-
-	    phdr++;
-	    phdr->p_type = grub_host_to_target32 (PT_GNU_STACK);
-	    phdr->p_offset = grub_host_to_target32 (header_size + kernel_size);
-	    phdr->p_paddr = phdr->p_vaddr = phdr->p_filesz = phdr->p_memsz = 0;
-	    phdr->p_flags = grub_host_to_target32 (PF_R | PF_W | PF_X);
-	    phdr->p_align = grub_host_to_target32 (image_target->link_align);
-
-	    phdr++;
-	    phdr->p_type = grub_host_to_target32 (PT_LOAD);
-	    phdr->p_offset = grub_host_to_target32 (header_size + kernel_size);
-	    phdr->p_flags = grub_host_to_target32 (PF_R | PF_W | PF_X);
-	    phdr->p_filesz = phdr->p_memsz
-	      = grub_host_to_target32 (core_size - kernel_size);
-
-	    if (image_target->id == IMAGE_COREBOOT)
-	      target_addr_mods = GRUB_KERNEL_I386_COREBOOT_MODULES_ADDR;
-	    else
-	      target_addr_mods = ALIGN_UP (target_addr + kernel_size + bss_size
-					   + image_target->mod_gap,
-					   image_target->mod_align);
-	    phdr->p_vaddr = grub_host_to_target32 (target_addr_mods);
-	    phdr->p_paddr = grub_host_to_target32 (target_addr_mods);
-	    phdr->p_align = grub_host_to_target32 (image_target->link_align);
-	  }
-
-	if (note)
-	  {
-	    int note_size = sizeof (struct grub_ieee1275_note);
-	    struct grub_ieee1275_note *note_ptr = (struct grub_ieee1275_note *) 
-	      (elf_img + program_size + header_size);
-
-	    grub_util_info ("adding CHRP NOTE segment");
-
-	    note_ptr->header.namesz = grub_host_to_target32 (sizeof (GRUB_IEEE1275_NOTE_NAME));
-	    note_ptr->header.descsz = grub_host_to_target32 (note_size);
-	    note_ptr->header.type = grub_host_to_target32 (GRUB_IEEE1275_NOTE_TYPE);
-	    strcpy (note_ptr->header.name, GRUB_IEEE1275_NOTE_NAME);
-	    note_ptr->descriptor.real_mode = grub_host_to_target32 (0xffffffff);
-	    note_ptr->descriptor.real_base = grub_host_to_target32 (0x00c00000);
-	    note_ptr->descriptor.real_size = grub_host_to_target32 (0xffffffff);
-	    note_ptr->descriptor.virt_base = grub_host_to_target32 (0xffffffff);
-	    note_ptr->descriptor.virt_size = grub_host_to_target32 (0xffffffff);
-	    note_ptr->descriptor.load_base = grub_host_to_target32 (0x00004000);
-
-	    phdr++;
-	    phdr->p_type = grub_host_to_target32 (PT_NOTE);
-	    phdr->p_flags = grub_host_to_target32 (PF_R);
-	    phdr->p_align = grub_host_to_target32 (image_target->voidp_sizeof);
-	    phdr->p_vaddr = 0;
-	    phdr->p_paddr = 0;
-	    phdr->p_filesz = grub_host_to_target32 (note_size);
-	    phdr->p_memsz = 0;
-	    phdr->p_offset = grub_host_to_target32 (header_size + program_size);
-	  }
-
-	free (core_img);
-	core_img = elf_img;
-	core_size = program_size + header_size + footer_size;
-      }
-      break;
-    }
-
-  grub_util_write_image (core_img, core_size, out, outname);
-  free (core_img);
-  free (kernel_path);
-
-  while (path_list)
-    {
-      next = path_list->next;
-      free ((void *) path_list->name);
-      free (path_list);
-      path_list = next;
-    }
-}
-
 \f
 
 static struct argp_option options[] = {
@@ -1860,22 +88,7 @@
       return xasprintf (text, DEFAULT_DIRECTORY);
     case 'O':
       {
-	int format_len = 0;
-	char *formats;
-	char *ptr;
-	char *ret;
-	unsigned i;
-	for (i = 0; i < ARRAY_SIZE (image_targets); i++)
-	  format_len += strlen (image_targets[i].names[0]) + 2;
-	ptr = formats = xmalloc (format_len);
-	for (i = 0; i < ARRAY_SIZE (image_targets); i++)
-	  {
-	    strcpy (ptr, image_targets[i].names[0]);
-	    ptr += strlen (image_targets[i].names[0]);
-	    *ptr++ = ',';
-	    *ptr++ = ' ';
-	  }
-	ptr[-2] = 0;
+	char *formats = grub_install_get_image_targets_string (), *ret;
 	ret = xasprintf ("%s\n%s %s", _("generate an image in FORMAT"),
 			 _("available formats:"), formats);
 	free (formats);
@@ -1900,10 +113,11 @@
   char *font;
   char *config;
   int note;
-  struct image_target_desc *image_target;
+  struct grub_install_image_target_desc *image_target;
   grub_compression_t comp;
 };
 
+
 static error_t
 argp_parser (int key, char *arg, struct argp_state *state)
 {
@@ -1922,12 +136,7 @@
 
     case 'O':
       {
-	unsigned i, j;
-	for (i = 0; i < ARRAY_SIZE (image_targets); i++)
-	  for (j = 0; image_targets[i].names[j]
-		 && j < ARRAY_SIZE (image_targets[i].names); j++)
-	    if (strcmp (arg, image_targets[i].names[j]) == 0)
-	      arguments->image_target = &image_targets[i];
+	arguments->image_target = grub_install_get_image_target (arg);
 	if (!arguments->image_target)
 	  {
 	    printf (_("unknown target format %s\n"), arg);
@@ -1977,16 +186,16 @@
       if (grub_strcmp (arg, "xz") == 0)
 	{
 #ifdef HAVE_LIBLZMA
-	  arguments->comp = COMPRESSION_XZ;
+	  arguments->comp = GRUB_COMPRESSION_XZ;
 #else
 	  grub_util_error ("%s",
 			   _("grub-mkimage is compiled without XZ support"));
 #endif
 	}
       else if (grub_strcmp (arg, "none") == 0)
-	arguments->comp = COMPRESSION_NONE;
+	arguments->comp = GRUB_COMPRESSION_NONE;
       else if (grub_strcmp (arg, "auto") == 0)
-	arguments->comp = COMPRESSION_AUTO;
+	arguments->comp = GRUB_COMPRESSION_AUTO;
       else
 	grub_util_error (_("Unknown compression format %s"), arg);
       break;
@@ -2029,7 +238,7 @@
   grub_util_init_nls ();
 
   memset (&arguments, 0, sizeof (struct arguments));
-  arguments.comp = COMPRESSION_AUTO;
+  arguments.comp = GRUB_COMPRESSION_AUTO;
   arguments.modules_max = argc + 1;
   arguments.modules = xmalloc ((arguments.modules_max + 1)
 			     * sizeof (arguments.modules[0]));
@@ -2061,21 +270,24 @@
 
   if (!arguments.dir)
     {
+      const char *dn = grub_util_get_target_dirname (arguments.image_target);
       arguments.dir = xmalloc (sizeof (GRUB_PKGLIBDIR)
-			       + grub_strlen (arguments.image_target->dirname)
+			       + grub_strlen (dn)
 			       + 1);
       memcpy (arguments.dir, GRUB_PKGLIBDIR,
 	      sizeof (GRUB_PKGLIBDIR) - 1);
       *(arguments.dir + sizeof (GRUB_PKGLIBDIR) - 1) = '/';
-      strcpy (arguments.dir + sizeof (GRUB_PKGLIBDIR),
-	      arguments.image_target->dirname);
+      strcpy (arguments.dir + sizeof (GRUB_PKGLIBDIR), dn);
     }
 
-  generate_image (arguments.dir, arguments.prefix ? : DEFAULT_DIRECTORY, fp,
-		  arguments.output,
-		  arguments.modules, arguments.memdisk, arguments.pubkeys,
-		  arguments.npubkeys, arguments.config,
-		  arguments.image_target, arguments.note, arguments.comp);
+  grub_install_generate_image (arguments.dir,
+			       arguments.prefix ? : DEFAULT_DIRECTORY, fp,
+			       arguments.output,
+			       arguments.modules, arguments.memdisk,
+			       arguments.pubkeys,
+			       arguments.npubkeys, arguments.config,
+			       arguments.image_target, arguments.note,
+			       arguments.comp);
 
   fflush (fp);
   fsync (fileno (fp));

=== modified file 'util/grub-mkimagexx.c'
--- util/grub-mkimagexx.c	2013-08-23 07:01:11 +0000
+++ util/grub-mkimagexx.c	2013-09-25 12:42:12 +0000
@@ -67,7 +67,7 @@
 			   Elf_Shdr *symtab_section, Elf_Addr *section_addresses,
 			   Elf_Half section_entsize, Elf_Half num_sections,
 			   void *jumpers, Elf_Addr jumpers_addr,
-			   struct image_target_desc *image_target)
+			   struct grub_install_image_target_desc *image_target)
 {
   Elf_Word symtab_size, sym_size, num_syms;
   Elf_Off symtab_offset;
@@ -140,7 +140,7 @@
 /* Return the address of a symbol at the index I in the section S.  */
 static Elf_Addr
 SUFFIX (get_symbol_address) (Elf_Ehdr *e, Elf_Shdr *s, Elf_Word i,
-			     struct image_target_desc *image_target)
+			     struct grub_install_image_target_desc *image_target)
 {
   Elf_Sym *sym;
 
@@ -153,7 +153,7 @@
 /* Return the address of a modified value.  */
 static Elf_Addr *
 SUFFIX (get_target_address) (Elf_Ehdr *e, Elf_Shdr *s, Elf_Addr offset,
-		    struct image_target_desc *image_target)
+		    struct grub_install_image_target_desc *image_target)
 {
   return (Elf_Addr *) ((char *) e + grub_target_to_host (s->sh_offset) + offset);
 }
@@ -161,7 +161,7 @@
 #ifdef MKIMAGE_ELF64
 static Elf_Addr
 SUFFIX (count_funcs) (Elf_Ehdr *e, Elf_Shdr *symtab_section,
-		      struct image_target_desc *image_target)
+		      struct grub_install_image_target_desc *image_target)
 {
   Elf_Word symtab_size, sym_size, num_syms;
   Elf_Off symtab_offset;
@@ -195,7 +195,7 @@
 			     const char *strtab,
 			     char *pe_target, Elf_Addr tramp_off,
 			     Elf_Addr got_off,
-			     struct image_target_desc *image_target)
+			     struct grub_install_image_target_desc *image_target)
 {
   Elf_Half i;
   Elf_Shdr *s;
@@ -472,7 +472,7 @@
 static Elf_Addr
 SUFFIX (add_fixup_entry) (struct fixup_block_list **cblock, grub_uint16_t type,
 			  Elf_Addr addr, int flush, Elf_Addr current_address,
-			  struct image_target_desc *image_target)
+			  struct grub_install_image_target_desc *image_target)
 {
   struct grub_pe32_fixup_block *b;
 
@@ -569,7 +569,7 @@
 			     Elf_Half section_entsize, Elf_Half num_sections,
 			     const char *strtab,
 			     Elf_Addr jumpers, grub_size_t njumpers,
-			     struct image_target_desc *image_target)
+			     struct grub_install_image_target_desc *image_target)
 {
   unsigned i;
   Elf_Shdr *s;
@@ -755,7 +755,7 @@
 /* Determine if this section is a text section. Return false if this
    section is not allocated.  */
 static int
-SUFFIX (is_text_section) (Elf_Shdr *s, struct image_target_desc *image_target)
+SUFFIX (is_text_section) (Elf_Shdr *s, struct grub_install_image_target_desc *image_target)
 {
   if (image_target->id != IMAGE_EFI 
       && grub_target_to_host32 (s->sh_type) != SHT_PROGBITS)
@@ -768,7 +768,7 @@
    BSS is also a data section, since the converter initializes BSS
    when producing PE32 to avoid a bug in EFI implementations.  */
 static int
-SUFFIX (is_data_section) (Elf_Shdr *s, struct image_target_desc *image_target)
+SUFFIX (is_data_section) (Elf_Shdr *s, struct grub_install_image_target_desc *image_target)
 {
   if (image_target->id != IMAGE_EFI 
       && grub_target_to_host32 (s->sh_type) != SHT_PROGBITS)
@@ -779,7 +779,7 @@
 
 /* Return if the ELF header is valid.  */
 static int
-SUFFIX (check_elf_header) (Elf_Ehdr *e, size_t size, struct image_target_desc *image_target)
+SUFFIX (check_elf_header) (Elf_Ehdr *e, size_t size, struct grub_install_image_target_desc *image_target)
 {
   if (size < sizeof (*e)
       || e->e_ident[EI_MAG0] != ELFMAG0
@@ -802,7 +802,7 @@
 			  Elf_Half num_sections, const char *strtab,
 			  grub_size_t *exec_size, grub_size_t *kernel_sz,
 			  grub_size_t *all_align,
-			  struct image_target_desc *image_target)
+			  struct grub_install_image_target_desc *image_target)
 {
   int i;
   Elf_Addr current_address;
@@ -884,7 +884,7 @@
 		     grub_size_t total_module_size, grub_uint64_t *start,
 		     void **reloc_section, grub_size_t *reloc_size,
 		     grub_size_t *align,
-		     struct image_target_desc *image_target)
+		     struct grub_install_image_target_desc *image_target)
 {
   char *kernel_img, *out_img;
   const char *strtab;

=== modified file 'util/grub-mkpasswd-pbkdf2.c'
--- util/grub-mkpasswd-pbkdf2.c	2013-09-22 01:28:32 +0000
+++ util/grub-mkpasswd-pbkdf2.c	2013-09-25 15:47:18 +0000
@@ -34,11 +34,6 @@
 
 #include <argp.h>
 
-#if defined (_WIN32) || defined (__CYGWIN__)
-#include <windows.h>
-#include <wincrypt.h>
-#endif
-
 #include "progname.h"
 
 static struct argp_option options[] = {
@@ -109,48 +104,6 @@
   *hex = 0;
 }
 
-static int
-grub_get_random (void *out, grub_size_t len)
-{
-#if ! defined (__linux__) && ! defined (__FreeBSD__) && ! defined (__OpenBSD__) && !defined (__GNU__) && ! defined (_WIN32) && !defined(__CYGWIN__)
-  /* TRANSLATORS: The generator might still be secure just GRUB isn't sure about it.  */
-  printf ("%s", _("WARNING: your random generator isn't known to be secure\n"));
-#warning "your random generator isn't known to be secure"
-#endif
-
-#if defined (_WIN32) || defined (__CYGWIN__)
-  HCRYPTPROV   hCryptProv;
-  if (!CryptAcquireContext (&hCryptProv,
-			    NULL,
-			    MS_DEF_PROV,
-			    PROV_RSA_FULL,
-			    CRYPT_VERIFYCONTEXT))
-    return 1;
-  if (!CryptGenRandom (hCryptProv, len, out))
-    {
-      CryptReleaseContext (hCryptProv, 0);
-      return 1;
-    }
-
-  CryptReleaseContext (hCryptProv, 0);
-
-  return 0;
-#else
-  FILE *f;
-  size_t rd;
-
-  f = fopen ("/dev/urandom", "rb");
-  if (!f)
-    return 1;
-  rd = fread (out, 1, len, f);
-  fclose (f);
-
-  if (rd != len)
-    return 1;
-  return 0;
-#endif
-}
-
 int
 main (int argc, char *argv[])
 {

=== modified file 'util/grub-probe.c'
--- util/grub-probe.c	2013-09-23 20:42:32 +0000
+++ util/grub-probe.c	2013-09-25 02:50:37 +0000
@@ -77,6 +77,12 @@
 static unsigned int argument_is_device = 0;
 
 static void
+do_print (const char *x)
+{
+  grub_printf ("%s ", x);
+}
+
+static void
 probe_partmap (grub_disk_t disk)
 {
   grub_partition_t part;
@@ -91,7 +97,7 @@
     printf ("%s ", part->partmap->name);
 
   if (disk->dev->id == GRUB_DISK_DEVICE_DISKFILTER_ID)
-    grub_diskfilter_print_partmap (disk);
+    grub_diskfilter_get_partmap (disk, do_print);
 
   /* In case of LVM/RAID, check the member devices as well.  */
   if (disk->dev->memberlist)
@@ -125,7 +131,10 @@
       list = tmp;
     }
   if (disk->dev->id == GRUB_DISK_DEVICE_CRYPTODISK_ID)
-    grub_util_cryptodisk_print_uuid (disk);
+    {
+      const char *uu = grub_util_cryptodisk_get_uuid (disk);
+      grub_printf ("%s ", uu);
+    }
 }
 
 static int
@@ -303,7 +312,7 @@
     printf ("ldm ");
 
   if (disk->dev->id == GRUB_DISK_DEVICE_CRYPTODISK_ID)
-    grub_util_cryptodisk_print_abstraction (disk);
+    grub_util_cryptodisk_get_abstraction (disk, do_print);
 
   raid_level = probe_raid_level (disk);
   if (raid_level >= 0)

=== modified file 'util/grub-setup.c'
--- util/grub-setup.c	2013-04-04 06:55:06 +0000
+++ util/grub-setup.c	2013-09-25 20:39:49 +0000
@@ -31,14 +31,6 @@
 #include <grub/term.h>
 #include <grub/i18n.h>
 #include <grub/util/lvm.h>
-#ifdef GRUB_SETUP_SPARC64
-#include <grub/util/ofpath.h>
-#include <grub/sparc64/ieee1275/boot.h>
-#include <grub/sparc64/ieee1275/kernel.h>
-#else
-#include <grub/i386/pc/boot.h>
-#include <grub/i386/pc/kernel.h>
-#endif
 
 #include <stdio.h>
 #include <unistd.h>
@@ -53,6 +45,7 @@
 #include <grub/reed_solomon.h>
 #include <grub/msdos_partition.h>
 #include <include/grub/crypto.h>
+#include <grub/util/install.h>
 
 #ifdef __linux__
 #include <sys/ioctl.h>
@@ -63,917 +56,6 @@
 #define _GNU_SOURCE	1
 #include <argp.h>
 
-/* On SPARC this program fills in various fields inside of the 'boot' and 'core'
- * image files.
- *
- * The 'boot' image needs to know the OBP path name of the root
- * device.  It also needs to know the initial block number of
- * 'core' (which is 'diskboot' concatenated with 'kernel' and
- * all the modules, this is created by grub-mkimage).  This resulting
- * 'boot' image is 512 bytes in size and is placed in the second block
- * of a partition.
- *
- * The initial 'diskboot' block acts as a loader for the actual GRUB
- * kernel.  It contains the loading code and then a block list.
- *
- * The block list of 'core' starts at the end of the 'diskboot' image
- * and works it's way backwards towards the end of the code of 'diskboot'.
- *
- * We patch up the images with the necessary values and write out the
- * result.
- */
-
-#define DEFAULT_BOOT_FILE	"boot.img"
-#define DEFAULT_CORE_FILE	"core.img"
-
-#ifdef GRUB_SETUP_SPARC64
-#define grub_target_to_host16(x)	grub_be_to_cpu16(x)
-#define grub_target_to_host32(x)	grub_be_to_cpu32(x)
-#define grub_target_to_host64(x)	grub_be_to_cpu64(x)
-#define grub_host_to_target16(x)	grub_cpu_to_be16(x)
-#define grub_host_to_target32(x)	grub_cpu_to_be32(x)
-#define grub_host_to_target64(x)	grub_cpu_to_be64(x)
-#elif defined (GRUB_SETUP_BIOS)
-#define grub_target_to_host16(x)	grub_le_to_cpu16(x)
-#define grub_target_to_host32(x)	grub_le_to_cpu32(x)
-#define grub_target_to_host64(x)	grub_le_to_cpu64(x)
-#define grub_host_to_target16(x)	grub_cpu_to_le16(x)
-#define grub_host_to_target32(x)	grub_cpu_to_le32(x)
-#define grub_host_to_target64(x)	grub_cpu_to_le64(x)
-#else
-#error Complete this
-#endif
-
-static void
-write_rootdev (grub_device_t root_dev,
-	       char *boot_img, grub_uint64_t first_sector)
-{
-#ifdef GRUB_SETUP_BIOS
-  {
-    grub_uint8_t *boot_drive;
-    void *kernel_sector;
-    boot_drive = (grub_uint8_t *) (boot_img + GRUB_BOOT_MACHINE_BOOT_DRIVE);
-    kernel_sector = (boot_img + GRUB_BOOT_MACHINE_KERNEL_SECTOR);
-
-    /* FIXME: can this be skipped?  */
-    *boot_drive = 0xFF;
-
-    grub_set_unaligned64 (kernel_sector, grub_cpu_to_le64 (first_sector));
-  }
-#endif
-#ifdef GRUB_SETUP_SPARC64
-  {
-    void *kernel_byte;
-    kernel_byte = (boot_img + GRUB_BOOT_AOUT_HEADER_SIZE
-		   + GRUB_BOOT_MACHINE_KERNEL_BYTE);
-    grub_set_unaligned64 (kernel_byte,
-			  grub_cpu_to_be64 (first_sector << GRUB_DISK_SECTOR_BITS));
-  }
-#endif
-}
-
-#ifdef GRUB_SETUP_SPARC64
-#define BOOT_SECTOR 1
-#else
-#define BOOT_SECTOR 0
-#endif
-
-/* Helper for setup.  */
-static void
-save_first_sector (grub_disk_addr_t sector, unsigned offset, unsigned length,
-		   void *data)
-{
-  grub_disk_addr_t *first_sector = data;
-  grub_util_info ("the first sector is <%" PRIuGRUB_UINT64_T ",%u,%u>",
-		  sector, offset, length);
-
-  if (offset != 0 || length != GRUB_DISK_SECTOR_SIZE)
-    grub_util_error ("%s", _("the first sector of the core file is not sector-aligned"));
-
-  *first_sector = sector;
-}
-
-struct blocklists
-{
-  struct grub_boot_blocklist *first_block, *block;
-#ifdef GRUB_SETUP_BIOS
-  grub_uint16_t current_segment;
-#endif
-  grub_uint16_t last_length;
-};
-
-/* Helper for setup.  */
-static void
-save_blocklists (grub_disk_addr_t sector, unsigned offset, unsigned length,
-		 void *data)
-{
-  struct blocklists *bl = data;
-  struct grub_boot_blocklist *prev = bl->block + 1;
-
-  grub_util_info ("saving <%" PRIuGRUB_UINT64_T ",%u,%u>",
-		  sector, offset, length);
-
-  if (offset != 0 || bl->last_length != GRUB_DISK_SECTOR_SIZE)
-    grub_util_error ("%s", _("non-sector-aligned data is found in the core file"));
-
-  if (bl->block != bl->first_block
-      && (grub_target_to_host64 (prev->start)
-	  + grub_target_to_host16 (prev->len)) == sector)
-    {
-      grub_uint16_t t = grub_target_to_host16 (prev->len) + 1;
-      prev->len = grub_host_to_target16 (t);
-    }
-  else
-    {
-      bl->block->start = grub_host_to_target64 (sector);
-      bl->block->len = grub_host_to_target16 (1);
-#ifdef GRUB_SETUP_BIOS
-      bl->block->segment = grub_host_to_target16 (bl->current_segment);
-#endif
-
-      bl->block--;
-      if (bl->block->len)
-	grub_util_error ("%s", _("the sectors of the core file are too fragmented"));
-    }
-
-  bl->last_length = length;
-#ifdef GRUB_SETUP_BIOS
-  bl->current_segment += GRUB_DISK_SECTOR_SIZE >> 4;
-#endif
-}
-
-#ifdef GRUB_SETUP_BIOS
-/* Context for setup/identify_partmap.  */
-struct identify_partmap_ctx
-{
-  grub_partition_map_t dest_partmap;
-  grub_partition_t container;
-  int multiple_partmaps;
-};
-
-/* Helper for setup.
-   Unlike root_dev, with dest_dev we're interested in the partition map even
-   if dest_dev itself is a whole disk.  */
-static int
-identify_partmap (grub_disk_t disk __attribute__ ((unused)),
-		  const grub_partition_t p, void *data)
-{
-  struct identify_partmap_ctx *ctx = data;
-
-  if (p->parent != ctx->container)
-    return 0;
-  /* NetBSD and OpenBSD subpartitions have metadata inside a partition,
-     so they are safe to ignore.
-   */
-  if (grub_strcmp (p->partmap->name, "netbsd") == 0
-      || grub_strcmp (p->partmap->name, "openbsd") == 0)
-    return 0;
-  if (ctx->dest_partmap == NULL)
-    {
-      ctx->dest_partmap = p->partmap;
-      return 0;
-    }
-  if (ctx->dest_partmap == p->partmap)
-    return 0;
-  ctx->multiple_partmaps = 1;
-  return 1;
-}
-#endif
-
-static void
-setup (const char *dir,
-       const char *boot_file, const char *core_file,
-       const char *dest, int force,
-       int fs_probe, int allow_floppy)
-{
-  char *boot_path, *core_path, *core_path_dev, *core_path_dev_full;
-  char *boot_img, *core_img;
-  char *root = 0;
-  size_t boot_size, core_size;
-#ifdef GRUB_SETUP_BIOS
-  grub_uint16_t core_sectors;
-#endif
-  grub_device_t root_dev = 0, dest_dev, core_dev;
-  struct blocklists bl;
-  char *tmp_img;
-  grub_disk_addr_t first_sector = (grub_disk_addr_t)-1;
-  FILE *fp;
-
-#ifdef GRUB_SETUP_BIOS
-  bl.current_segment =
-    GRUB_BOOT_I386_PC_KERNEL_SEG + (GRUB_DISK_SECTOR_SIZE >> 4);
-#endif
-  bl.last_length = GRUB_DISK_SECTOR_SIZE;
-
-  /* Read the boot image by the OS service.  */
-  boot_path = grub_util_get_path (dir, boot_file);
-  boot_size = grub_util_get_image_size (boot_path);
-  if (boot_size != GRUB_DISK_SECTOR_SIZE)
-    grub_util_error (_("the size of `%s' is not %u"),
-		     boot_path, GRUB_DISK_SECTOR_SIZE);
-  boot_img = grub_util_read_image (boot_path);
-  free (boot_path);
-
-  core_path = grub_util_get_path (dir, core_file);
-  core_size = grub_util_get_image_size (core_path);
-#ifdef GRUB_SETUP_BIOS
-  core_sectors = ((core_size + GRUB_DISK_SECTOR_SIZE - 1)
-		  >> GRUB_DISK_SECTOR_BITS);
-#endif
-  if (core_size < GRUB_DISK_SECTOR_SIZE)
-    grub_util_error (_("the size of `%s' is too small"), core_path);
-#ifdef GRUB_SETUP_BIOS
-  if (core_size > 0xFFFF * GRUB_DISK_SECTOR_SIZE)
-    grub_util_error (_("the size of `%s' is too large"), core_path);
-#endif
-
-  core_img = grub_util_read_image (core_path);
-
-  /* Have FIRST_BLOCK to point to the first blocklist.  */
-  bl.first_block = (struct grub_boot_blocklist *) (core_img
-						   + GRUB_DISK_SECTOR_SIZE
-						   - sizeof (*bl.block));
-  grub_util_info ("root is `%s', dest is `%s'", root, dest);
-
-  grub_util_info ("Opening dest");
-  dest_dev = grub_device_open (dest);
-  if (! dest_dev)
-    grub_util_error ("%s", grub_errmsg);
-
-  core_dev = dest_dev;
-
-  {
-    char **root_devices = grub_guess_root_devices (dir);
-    char **cur;
-    int found = 0;
-
-    for (cur = root_devices; *cur; cur++)
-      {
-	char *drive;
-	grub_device_t try_dev;
-
-	drive = grub_util_get_grub_dev (*cur);
-	if (!drive)
-	  continue;
-	try_dev = grub_device_open (drive);
-	if (! try_dev)
-	  continue;
-	if (!found && try_dev->disk->id == dest_dev->disk->id
-	    && try_dev->disk->dev->id == dest_dev->disk->dev->id)
-	  {
-	    if (root_dev)
-	      grub_device_close (root_dev);
-	    free (root);
-	    root_dev = try_dev;
-	    root = drive;
-	    found = 1;
-	    continue;
-	  }
-	if (!root_dev)
-	  {
-	    root_dev = try_dev;
-	    root = drive;
-	    continue;
-	  }
-	grub_device_close (try_dev);	
-	free (drive);
-      }
-    if (!root_dev)
-      {
-	grub_util_error ("guessing the root device failed, because of `%s'",
-			 grub_errmsg);
-      }
-    grub_util_info ("guessed root_dev `%s' from "
-		    "dir `%s'", root_dev->disk->name, dir);
-  }
-
-  grub_util_info ("setting the root device to `%s'", root);
-  if (grub_env_set ("root", root) != GRUB_ERR_NONE)
-    grub_util_error ("%s", grub_errmsg);
-
-#ifdef GRUB_SETUP_BIOS
-  /* Read the original sector from the disk.  */
-  tmp_img = xmalloc (GRUB_DISK_SECTOR_SIZE);
-  if (grub_disk_read (dest_dev->disk, 0, 0, GRUB_DISK_SECTOR_SIZE, tmp_img))
-    grub_util_error ("%s", grub_errmsg);
-#endif
-
-#ifdef GRUB_SETUP_BIOS
-  {
-    grub_uint8_t *boot_drive_check;
-    boot_drive_check = (grub_uint8_t *) (boot_img
-					  + GRUB_BOOT_MACHINE_DRIVE_CHECK);
-    /* Copy the possible DOS BPB.  */
-    memcpy (boot_img + GRUB_BOOT_MACHINE_BPB_START,
-	    tmp_img + GRUB_BOOT_MACHINE_BPB_START,
-	    GRUB_BOOT_MACHINE_BPB_END - GRUB_BOOT_MACHINE_BPB_START);
-
-    /* If DEST_DRIVE is a hard disk, enable the workaround, which is
-       for buggy BIOSes which don't pass boot drive correctly. Instead,
-       they pass 0x00 or 0x01 even when booted from 0x80.  */
-    if (!allow_floppy && !grub_util_biosdisk_is_floppy (dest_dev->disk))
-      {
-	/* Replace the jmp (2 bytes) with double nop's.  */
-	boot_drive_check[0] = 0x90;
-	boot_drive_check[1] = 0x90;
-      }
-  }
-#endif
-
-#ifdef GRUB_SETUP_BIOS
-  {
-    struct identify_partmap_ctx ctx = {
-      .dest_partmap = NULL,
-      .container = dest_dev->disk->partition,
-      .multiple_partmaps = 0
-    };
-    int is_ldm;
-    grub_err_t err;
-    grub_disk_addr_t *sectors;
-    int i;
-    grub_fs_t fs;
-    unsigned int nsec, maxsec;
-
-    grub_partition_iterate (dest_dev->disk, identify_partmap, &ctx);
-
-    if (ctx.container
-	&& grub_strcmp (ctx.container->partmap->name, "msdos") == 0
-	&& ctx.dest_partmap
-	&& (ctx.container->msdostype == GRUB_PC_PARTITION_TYPE_NETBSD
-	    || ctx.container->msdostype == GRUB_PC_PARTITION_TYPE_OPENBSD))
-      {
-	grub_util_warn ("%s", _("Attempting to install GRUB to a disk with multiple partition labels or both partition label and filesystem.  This is not supported yet."));
-	goto unable_to_embed;
-      }
-
-    fs = grub_fs_probe (dest_dev);
-    if (!fs)
-      grub_errno = GRUB_ERR_NONE;
-
-    is_ldm = grub_util_is_ldm (dest_dev->disk);
-
-    if (fs_probe)
-      {
-	if (!fs && !ctx.dest_partmap)
-	  grub_util_error (_("unable to identify a filesystem in %s; safety check can't be performed"),
-			   dest_dev->disk->name);
-	if (fs && !fs->reserved_first_sector)
-	  /* TRANSLATORS: Filesystem may reserve the space just GRUB isn't sure about it.  */
-	  grub_util_error (_("%s appears to contain a %s filesystem which isn't known to "
-			     "reserve space for DOS-style boot.  Installing GRUB there could "
-			     "result in FILESYSTEM DESTRUCTION if valuable data is overwritten "
-			     "by grub-setup (--skip-fs-probe disables this "
-			     "check, use at your own risk)"), dest_dev->disk->name, fs->name);
-
-	if (ctx.dest_partmap && strcmp (ctx.dest_partmap->name, "msdos") != 0
-	    && strcmp (ctx.dest_partmap->name, "gpt") != 0
-	    && strcmp (ctx.dest_partmap->name, "bsd") != 0
-	    && strcmp (ctx.dest_partmap->name, "netbsd") != 0
-	    && strcmp (ctx.dest_partmap->name, "openbsd") != 0
-	    && strcmp (ctx.dest_partmap->name, "sunpc") != 0)
-	  /* TRANSLATORS: Partition map may reserve the space just GRUB isn't sure about it.  */
-	  grub_util_error (_("%s appears to contain a %s partition map which isn't known to "
-			     "reserve space for DOS-style boot.  Installing GRUB there could "
-			     "result in FILESYSTEM DESTRUCTION if valuable data is overwritten "
-			     "by grub-setup (--skip-fs-probe disables this "
-			     "check, use at your own risk)"), dest_dev->disk->name, ctx.dest_partmap->name);
-	if (is_ldm && ctx.dest_partmap && strcmp (ctx.dest_partmap->name, "msdos") != 0
-	    && strcmp (ctx.dest_partmap->name, "gpt") != 0)
-	  grub_util_error (_("%s appears to contain a %s partition map and "
-			     "LDM which isn't known to be a safe combination."
-			     "  Installing GRUB there could "
-			     "result in FILESYSTEM DESTRUCTION if valuable data"
-			     " is overwritten "
-			     "by grub-setup (--skip-fs-probe disables this "
-			     "check, use at your own risk)"),
-			   dest_dev->disk->name, ctx.dest_partmap->name);
-
-      }
-
-    /* Copy the partition table.  */
-    if (ctx.dest_partmap ||
-        (!allow_floppy && !grub_util_biosdisk_is_floppy (dest_dev->disk)))
-      memcpy (boot_img + GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC,
-	      tmp_img + GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC,
-	      GRUB_BOOT_MACHINE_PART_END - GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC);
-
-    free (tmp_img);
-    
-    if (! ctx.dest_partmap && ! fs && !is_ldm)
-      {
-	grub_util_warn ("%s", _("Attempting to install GRUB to a partitionless disk or to a partition.  This is a BAD idea."));
-	goto unable_to_embed;
-      }
-    if (ctx.multiple_partmaps || (ctx.dest_partmap && fs) || (is_ldm && fs))
-      {
-	grub_util_warn ("%s", _("Attempting to install GRUB to a disk with multiple partition labels.  This is not supported yet."));
-	goto unable_to_embed;
-      }
-
-    if (ctx.dest_partmap && !ctx.dest_partmap->embed)
-      {
-	grub_util_warn (_("Partition style `%s' doesn't support embedding"),
-			ctx.dest_partmap->name);
-	goto unable_to_embed;
-      }
-
-    if (fs && !fs->embed)
-      {
-	grub_util_warn (_("File system `%s' doesn't support embedding"),
-			fs->name);
-	goto unable_to_embed;
-      }
-
-    nsec = core_sectors;
-
-    maxsec = 2 * core_sectors;
-    if (maxsec > ((0x78000 - GRUB_KERNEL_I386_PC_LINK_ADDR)
-		>> GRUB_DISK_SECTOR_BITS))
-      maxsec = ((0x78000 - GRUB_KERNEL_I386_PC_LINK_ADDR)
-		>> GRUB_DISK_SECTOR_BITS);
-
-    if (is_ldm)
-      err = grub_util_ldm_embed (dest_dev->disk, &nsec, maxsec,
-				 GRUB_EMBED_PCBIOS, &sectors);
-    else if (ctx.dest_partmap)
-      err = ctx.dest_partmap->embed (dest_dev->disk, &nsec, maxsec,
-				     GRUB_EMBED_PCBIOS, &sectors);
-    else
-      err = fs->embed (dest_dev, &nsec, maxsec,
-		       GRUB_EMBED_PCBIOS, &sectors);
-    if (!err && nsec < core_sectors)
-      {
-	err = grub_error (GRUB_ERR_OUT_OF_RANGE,
-			  N_("Your embedding area is unusually small.  "
-			     "core.img won't fit in it."));
-      }
-    
-    if (err)
-      {
-	grub_util_warn ("%s", grub_errmsg);
-	grub_errno = GRUB_ERR_NONE;
-	goto unable_to_embed;
-      }
-
-    assert (nsec <= maxsec);
-
-    /* Clean out the blocklists.  */
-    bl.block = bl.first_block;
-    while (bl.block->len)
-      {
-	grub_memset (bl.block, 0, sizeof (bl.block));
-      
-	bl.block--;
-
-	if ((char *) bl.block <= core_img)
-	  grub_util_error ("%s", _("no terminator in the core image"));
-      }
-
-    save_first_sector (sectors[0] + grub_partition_get_start (ctx.container),
-		       0, GRUB_DISK_SECTOR_SIZE, &first_sector);
-
-    bl.block = bl.first_block;
-    for (i = 1; i < nsec; i++)
-      save_blocklists (sectors[i] + grub_partition_get_start (ctx.container),
-		       0, GRUB_DISK_SECTOR_SIZE, &bl);
-
-    /* Make sure that the last blocklist is a terminator.  */
-    if (bl.block == bl.first_block)
-      bl.block--;
-    bl.block->start = 0;
-    bl.block->len = 0;
-    bl.block->segment = 0;
-
-    write_rootdev (root_dev, boot_img, first_sector);
-
-    core_img = realloc (core_img, nsec * GRUB_DISK_SECTOR_SIZE);
-    bl.first_block = (struct grub_boot_blocklist *) (core_img
-						     + GRUB_DISK_SECTOR_SIZE
-						     - sizeof (*bl.block));
-
-    grub_size_t no_rs_length;
-    grub_set_unaligned32 ((core_img + GRUB_DISK_SECTOR_SIZE
-			   + GRUB_KERNEL_I386_PC_REED_SOLOMON_REDUNDANCY),
-			  grub_host_to_target32 (nsec * GRUB_DISK_SECTOR_SIZE - core_size));
-    no_rs_length = grub_target_to_host16 
-      (grub_get_unaligned16 (core_img
-			     + GRUB_DISK_SECTOR_SIZE
-			     + GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_LENGTH));
-
-    if (no_rs_length == 0xffff)
-      grub_util_error ("%s", _("core.img version mismatch"));
-
-    void *tmp = xmalloc (core_size);
-    grub_memcpy (tmp, core_img, core_size);
-    grub_reed_solomon_add_redundancy (core_img + no_rs_length + GRUB_DISK_SECTOR_SIZE,
-				      core_size - no_rs_length - GRUB_DISK_SECTOR_SIZE,
-				      nsec * GRUB_DISK_SECTOR_SIZE
-				      - core_size);
-    assert (grub_memcmp (tmp, core_img, core_size) == 0);
-    free (tmp);
-
-    /* Write the core image onto the disk.  */
-    for (i = 0; i < nsec; i++)
-      grub_disk_write (dest_dev->disk, sectors[i], 0,
-		       GRUB_DISK_SECTOR_SIZE,
-		       core_img + i * GRUB_DISK_SECTOR_SIZE);
-
-    grub_free (sectors);
-
-    goto finish;
-  }
-
-unable_to_embed:
-#endif
-
-  if (dest_dev->disk->dev->id != root_dev->disk->dev->id)
-    grub_util_error ("%s", _("embedding is not possible, but this is required for "
-			     "RAID and LVM install"));
-
-  {
-    grub_fs_t fs;
-    fs = grub_fs_probe (root_dev);
-    if (!fs)
-      grub_util_error (_("can't determine filesystem on %s"), root);
-
-    if (!fs->blocklist_install)
-      grub_util_error (_("filesystem `%s' doesn't support blocklists"),
-		       fs->name);
-  }
-
-#ifdef GRUB_SETUP_BIOS
-  if (dest_dev->disk->id != root_dev->disk->id
-      || dest_dev->disk->dev->id != root_dev->disk->dev->id)
-    /* TRANSLATORS: cross-disk refers to /boot being on one disk
-       but MBR on another.  */
-    grub_util_error ("%s", _("embedding is not possible, but this is required for "
-			     "cross-disk install"));
-#else
-  core_dev = root_dev;
-#endif
-
-  grub_util_warn ("%s", _("Embedding is not possible.  GRUB can only be installed in this "
-			  "setup by using blocklists.  However, blocklists are UNRELIABLE and "
-			  "their use is discouraged."));
-  if (! force)
-    /* TRANSLATORS: Here GRUB refuses to continue with blocklist install.  */
-    grub_util_error ("%s", _("will not proceed with blocklists"));
-
-  /* The core image must be put on a filesystem unfortunately.  */
-  grub_util_info ("will leave the core image on the filesystem");
-
-  /* Make sure that GRUB reads the identical image as the OS.  */
-  tmp_img = xmalloc (core_size);
-  core_path_dev_full = grub_util_get_path (dir, core_file);
-  core_path_dev = grub_make_system_path_relative_to_its_root (core_path_dev_full);
-  free (core_path_dev_full);
-
-  grub_util_biosdisk_flush (root_dev->disk);
-
-#ifndef __linux__
-
-#define MAX_TRIES	5
-  {
-    int i;
-    for (i = 0; i < MAX_TRIES; i++)
-      {
-	grub_file_t file;
-
-	grub_util_info ((i == 0) ? _("attempting to read the core image `%s' from GRUB")
-			: _("attempting to read the core image `%s' from GRUB again"),
-			core_path_dev);
-
-	grub_disk_cache_invalidate_all ();
-
-	grub_file_filter_disable_compression ();
-	file = grub_file_open (core_path_dev);
-	if (file)
-	  {
-	    if (grub_file_size (file) != core_size)
-	      grub_util_info ("succeeded in opening the core image but the size is different (%d != %d)",
-			      (int) grub_file_size (file), (int) core_size);
-	    else if (grub_file_read (file, tmp_img, core_size)
-		     != (grub_ssize_t) core_size)
-	      grub_util_info ("succeeded in opening the core image but cannot read %d bytes",
-			      (int) core_size);
-	    else if (memcmp (core_img, tmp_img, core_size) != 0)
-	      {
-#if 0
-		FILE *dump;
-		FILE *dump2;
-
-		dump = fopen ("dump.img", "wb");
-		if (dump)
-		  {
-		    fwrite (tmp_img, 1, core_size, dump);
-		    fclose (dump);
-		  }
-
-		dump2 = fopen ("dump2.img", "wb");
-		if (dump2)
-		  {
-		    fwrite (core_img, 1, core_size, dump2);
-		    fclose (dump2);
-		  }
-
-#endif
-		grub_util_info ("succeeded in opening the core image but the data is different");
-	      }
-	    else
-	      {
-		grub_file_close (file);
-		break;
-	      }
-
-	    grub_file_close (file);
-	  }
-	else
-	  grub_util_info ("couldn't open the core image");
-
-	if (grub_errno)
-	  grub_util_info ("error message = %s", grub_errmsg);
-
-	grub_errno = GRUB_ERR_NONE;
-	grub_util_biosdisk_flush (root_dev->disk);
-	sleep (1);
-      }
-
-    if (i == MAX_TRIES)
-      grub_util_error (_("cannot read `%s' correctly"), core_path_dev);
-  }
-
-#endif
-
-  /* Clean out the blocklists.  */
-  bl.block = bl.first_block;
-  while (bl.block->len)
-    {
-      bl.block->start = 0;
-      bl.block->len = 0;
-#ifdef GRUB_SETUP_BIOS
-      bl.block->segment = 0;
-#endif
-
-      bl.block--;
-
-      if ((char *) bl.block <= core_img)
-	grub_util_error ("%s", _("no terminator in the core image"));
-    }
-
-  bl.block = bl.first_block;
-
-#ifdef __linux__
-  {
-    grub_partition_t container = root_dev->disk->partition;
-    grub_uint64_t container_start = grub_partition_get_start (container);
-    struct fiemap fie1;
-    int fd;
-
-    /* Write the first two sectors of the core image onto the disk.  */
-    grub_util_info ("opening the core image `%s'", core_path);
-    fp = fopen (core_path, "rb");
-    if (! fp)
-      grub_util_error (_("cannot open `%s': %s"), core_path,
-		       strerror (errno));
-    fd = fileno (fp);
-
-    grub_memset (&fie1, 0, sizeof (fie1));
-    fie1.fm_length = core_size;
-    fie1.fm_flags = FIEMAP_FLAG_SYNC;
-
-    if (ioctl (fd, FS_IOC_FIEMAP, &fie1) < 0)
-      {
-	int nblocks, i, j;
-	int bsize;
-	int mul;
-
-	grub_util_info ("FIEMAP failed. Reverting to FIBMAP");
-
-	if (ioctl (fd, FIGETBSZ, &bsize) < 0)
-	  grub_util_error (_("can't retrieve blocklists: %s"),
-			   strerror (errno));
-	if (bsize & (GRUB_DISK_SECTOR_SIZE - 1))
-	  grub_util_error ("%s", _("blocksize is not divisible by 512"));
-	mul = bsize >> GRUB_DISK_SECTOR_BITS;
-	nblocks = (core_size + bsize - 1) / bsize;
-	if (mul == 0 || nblocks == 0)
-	  grub_util_error ("%s", _("can't retrieve blocklists"));
-	for (i = 0; i < nblocks; i++)
-	  {
-	    unsigned blk = i;
-	    if (ioctl (fd, FIBMAP, &blk) < 0)
-	      grub_util_error (_("can't retrieve blocklists: %s"),
-			       strerror (errno));
-	    
-	    for (j = 0; j < mul; j++)
-	      {
-		int rest = core_size - ((i * mul + j) << GRUB_DISK_SECTOR_BITS);
-		if (rest <= 0)
-		  break;
-		if (rest > GRUB_DISK_SECTOR_SIZE)
-		  rest = GRUB_DISK_SECTOR_SIZE;
-		if (i == 0 && j == 0)
-		  save_first_sector (((grub_uint64_t) blk) * mul
-				     + container_start,
-				     0, rest, &first_sector);
-		else
-		  save_blocklists (((grub_uint64_t) blk) * mul + j
-				   + container_start,
-				   0, rest, &bl);
-	      }
-	  }
-      }
-    else
-      {
-	struct fiemap *fie2;
-	int i, j;
-	fie2 = xmalloc (sizeof (*fie2)
-			+ fie1.fm_mapped_extents
-			* sizeof (fie1.fm_extents[1]));
-	memset (fie2, 0, sizeof (*fie2)
-		+ fie1.fm_mapped_extents * sizeof (fie2->fm_extents[1]));
-	fie2->fm_length = core_size;
-	fie2->fm_flags = FIEMAP_FLAG_SYNC;
-	fie2->fm_extent_count = fie1.fm_mapped_extents;
-	if (ioctl (fd, FS_IOC_FIEMAP, fie2) < 0)
-	  grub_util_error (_("can't retrieve blocklists: %s"),
-			   strerror (errno));
-	for (i = 0; i < fie2->fm_mapped_extents; i++)
-	  {
-	    for (j = 0;
-		 j < ((fie2->fm_extents[i].fe_length
-		       + GRUB_DISK_SECTOR_SIZE - 1)
-		      >> GRUB_DISK_SECTOR_BITS);
-		 j++)
-	      {
-		size_t len = (fie2->fm_extents[i].fe_length
-			      - j * GRUB_DISK_SECTOR_SIZE);
-		if (len > GRUB_DISK_SECTOR_SIZE)
-		  len = GRUB_DISK_SECTOR_SIZE;
-		if (first_sector == (grub_disk_addr_t)-1)
-		  save_first_sector ((fie2->fm_extents[i].fe_physical
-				      >> GRUB_DISK_SECTOR_BITS)
-				     + j + container_start,
-				     fie2->fm_extents[i].fe_physical
-				     & (GRUB_DISK_SECTOR_SIZE - 1), len,
-				     &first_sector);
-		else
-		  save_blocklists ((fie2->fm_extents[i].fe_physical
-				    >> GRUB_DISK_SECTOR_BITS)
-				   + j + container_start,
-				   fie2->fm_extents[i].fe_physical
-				   & (GRUB_DISK_SECTOR_SIZE - 1), len, &bl);
-
-
-	      }
-	  }
-	if (first_sector == (grub_disk_addr_t)-1)
-	  grub_util_error ("%s", _("can't retrieve blocklists"));
-      }
-    fclose (fp);
-  }
-#else
-  {
-    grub_file_t file;
-    /* Now read the core image to determine where the sectors are.  */
-    grub_file_filter_disable_compression ();
-    file = grub_file_open (core_path_dev);
-    if (! file)
-      grub_util_error ("%s", grub_errmsg);
-
-    file->read_hook = save_first_sector;
-    file->read_hook_data = &first_sector;
-    if (grub_file_read (file, tmp_img, GRUB_DISK_SECTOR_SIZE)
-	!= GRUB_DISK_SECTOR_SIZE)
-      grub_util_error ("%s", _("failed to read the first sector of the core image"));
-
-    bl.block = bl.first_block;
-    file->read_hook = save_blocklists;
-    file->read_hook_data = &bl;
-    if (grub_file_read (file, tmp_img, core_size - GRUB_DISK_SECTOR_SIZE)
-	!= (grub_ssize_t) core_size - GRUB_DISK_SECTOR_SIZE)
-      grub_util_error ("%s", _("failed to read the rest sectors of the core image"));
-    grub_file_close (file);
-  }
-#endif
-
-#ifdef GRUB_SETUP_SPARC64
-  {
-    char *boot_devpath;
-    boot_devpath = (char *) (boot_img
-			     + GRUB_BOOT_AOUT_HEADER_SIZE
-			     + GRUB_BOOT_MACHINE_BOOT_DEVPATH);
-    if (dest_dev->disk->id != root_dev->disk->id
-	|| dest_dev->disk->dev->id != root_dev->disk->dev->id)
-      {
-	const char *dest_ofpath;
-	dest_ofpath
-	  = grub_util_devname_to_ofpath (grub_util_biosdisk_get_osdev (root_dev->disk));
-	grub_util_info ("dest_ofpath is `%s'", dest_ofpath);
-	strncpy (boot_devpath, dest_ofpath,
-		 GRUB_BOOT_MACHINE_BOOT_DEVPATH_END
-		 - GRUB_BOOT_MACHINE_BOOT_DEVPATH - 1);
-	boot_devpath[GRUB_BOOT_MACHINE_BOOT_DEVPATH_END
-		   - GRUB_BOOT_MACHINE_BOOT_DEVPATH - 1] = 0;
-      }
-    else
-      {
-	grub_util_info ("non cross-disk install");
-	memset (boot_devpath, 0, GRUB_BOOT_MACHINE_BOOT_DEVPATH_END
-		- GRUB_BOOT_MACHINE_BOOT_DEVPATH);
-      }
-    grub_util_info ("boot device path %s", boot_devpath);
-  }
-#endif
-
-  free (core_path_dev);
-  free (tmp_img);
-
-  write_rootdev (root_dev, boot_img, first_sector);
-
-  /* Write the first two sectors of the core image onto the disk.  */
-  grub_util_info ("opening the core image `%s'", core_path);
-  fp = fopen (core_path, "r+b");
-  if (! fp)
-    grub_util_error (_("cannot open `%s': %s"), core_path,
-		     strerror (errno));
-
-  grub_util_write_image (core_img, GRUB_DISK_SECTOR_SIZE * 2, fp, core_path);
-  fflush (fp);
-  fsync (fileno (fp));
-  fclose (fp);
-  grub_util_biosdisk_flush (root_dev->disk);
-
-  grub_disk_cache_invalidate_all ();
-
-  {
-    char *buf, *ptr = core_img;
-    size_t len = core_size;
-    grub_uint64_t blk;
-    grub_partition_t container = core_dev->disk->partition;
-    grub_err_t err;
-
-    core_dev->disk->partition = 0;
-
-    buf = xmalloc (core_size);
-    blk = first_sector;
-    err = grub_disk_read (core_dev->disk, blk, 0, GRUB_DISK_SECTOR_SIZE, buf);
-    if (err)
-      grub_util_error (_("cannot read `%s': %s"), core_dev->disk->name,
-		       grub_errmsg);
-    if (grub_memcmp (buf, ptr, GRUB_DISK_SECTOR_SIZE) != 0)
-      grub_util_error ("%s", _("blocklists are invalid"));
-
-    ptr += GRUB_DISK_SECTOR_SIZE;
-    len -= GRUB_DISK_SECTOR_SIZE;
-
-    bl.block = bl.first_block;
-    while (bl.block->len)
-      {
-	size_t cur = grub_target_to_host16 (bl.block->len) << GRUB_DISK_SECTOR_BITS;
-	blk = grub_target_to_host64 (bl.block->start);
-
-	if (cur > len)
-	  cur = len;
-
-	err = grub_disk_read (core_dev->disk, blk, 0, cur, buf);
-	if (err)
-	  grub_util_error (_("cannot read `%s': %s"), core_dev->disk->name,
-			   grub_errmsg);
-
-	if (grub_memcmp (buf, ptr, cur) != 0)
-	  grub_util_error ("%s", _("blocklists are invalid"));
-
-	ptr += cur;
-	len -= cur;
-	bl.block--;
-	
-	if ((char *) bl.block <= core_img)
-	  grub_util_error ("%s", _("no terminator in the core image"));
-      }
-    core_dev->disk->partition = container;
-    free (buf);
-  }
-
-#ifdef GRUB_SETUP_BIOS
- finish:
-#endif
-
-  /* Write the boot image onto the disk.  */
-  if (grub_disk_write (dest_dev->disk, BOOT_SECTOR,
-		       0, GRUB_DISK_SECTOR_SIZE, boot_img))
-    grub_util_error ("%s", grub_errmsg);
-
-  grub_util_biosdisk_flush (root_dev->disk);
-  grub_util_biosdisk_flush (dest_dev->disk);
-
-  free (core_path);
-  free (core_img);
-  free (boot_img);
-  grub_device_close (dest_dev);
-  grub_device_close (root_dev);
-}
-
 static struct argp_option options[] = {
   {"boot-image",  'b', N_("FILE"), 0,
    N_("use FILE as the boot image [default=%s]"), 0},
@@ -1002,10 +84,10 @@
   switch (key)
     {
       case 'b':
-        return xasprintf (text, DEFAULT_BOOT_FILE);
+        return xasprintf (text, "boot.img");
 
       case 'c':
-        return xasprintf (text, DEFAULT_CORE_FILE);
+        return xasprintf (text, "core.img");
 
       case 'd':
         return xasprintf (text, DEFAULT_DIRECTORY);
@@ -1199,12 +281,18 @@
       grub_util_info ("Using `%s' as GRUB device", dest_dev);
     }
 
+  char *boot_path;
+
+  boot_path = grub_util_get_path (arguments.dir ? : DEFAULT_DIRECTORY,
+				  arguments.boot_file ? : "boot.img");
+
   /* Do the real work.  */
-  setup (arguments.dir ? : DEFAULT_DIRECTORY,
-	 arguments.boot_file ? : DEFAULT_BOOT_FILE,
-	 arguments.core_file ? : DEFAULT_CORE_FILE,
-	 dest_dev, arguments.force,
-	 arguments.fs_probe, arguments.allow_floppy);
+  GRUB_SETUP_FUNC (arguments.dir ? : DEFAULT_DIRECTORY,
+		   boot_path,
+		   arguments.core_file,
+		   dest_dev, arguments.force,
+		   arguments.fs_probe, arguments.allow_floppy);
+  free (boot_path);
 
   /* Free resources.  */
   grub_fini_all ();

=== added file 'util/mkimage.c'
--- util/mkimage.c	1970-01-01 00:00:00 +0000
+++ util/mkimage.c	2013-09-25 15:45:06 +0000
@@ -0,0 +1,1861 @@
+/* grub-mkimage.c - make a bootable image */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010  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 <config.h>
+#include <grub/types.h>
+#include <grub/elf.h>
+#include <grub/aout.h>
+#include <grub/i18n.h>
+#include <grub/kernel.h>
+#include <grub/disk.h>
+#include <grub/emu/misc.h>
+#include <grub/util/misc.h>
+#include <grub/util/resolve.h>
+#include <grub/misc.h>
+#include <grub/offsets.h>
+#include <grub/crypto.h>
+#include <grub/dl.h>
+#include <time.h>
+#include <multiboot.h>
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <grub/efi/pe32.h>
+#include <grub/uboot/image.h>
+#include <grub/arm/reloc.h>
+#include <grub/ia64/reloc.h>
+#include <grub/util/install.h>
+
+#include "progname.h"
+
+#define ALIGN_ADDR(x) (ALIGN_UP((x), image_target->voidp_sizeof))
+
+#ifdef HAVE_LIBLZMA
+#include <lzma.h>
+#endif
+
+#define TARGET_NO_FIELD 0xffffffff
+
+struct grub_install_image_target_desc
+{
+  const char *dirname;
+  const char *names[6];
+  grub_size_t voidp_sizeof;
+  int bigendian;
+  enum {
+    IMAGE_I386_PC, IMAGE_EFI, IMAGE_COREBOOT,
+    IMAGE_SPARC64_AOUT, IMAGE_SPARC64_RAW, IMAGE_SPARC64_CDCORE,
+    IMAGE_I386_IEEE1275,
+    IMAGE_LOONGSON_ELF, IMAGE_QEMU, IMAGE_PPC, IMAGE_YEELOONG_FLASH,
+    IMAGE_FULOONG2F_FLASH, IMAGE_I386_PC_PXE, IMAGE_MIPS_ARC,
+    IMAGE_QEMU_MIPS_FLASH, IMAGE_UBOOT
+  } id;
+  enum
+    {
+      PLATFORM_FLAGS_NONE = 0,
+      PLATFORM_FLAGS_DECOMPRESSORS = 2,
+      PLATFORM_FLAGS_MODULES_BEFORE_KERNEL = 4,
+    } flags;
+  unsigned total_module_size;
+  unsigned decompressor_compressed_size;
+  unsigned decompressor_uncompressed_size;
+  unsigned decompressor_uncompressed_addr;
+  unsigned link_align;
+  grub_uint16_t elf_target;
+  unsigned section_align;
+  signed vaddr_offset;
+  grub_uint64_t link_addr;
+  unsigned mod_gap, mod_align;
+  grub_compression_t default_compression;
+  grub_uint16_t pe_target;
+};
+
+#define EFI32_HEADER_SIZE ALIGN_UP (GRUB_PE32_MSDOS_STUB_SIZE		\
+				    + GRUB_PE32_SIGNATURE_SIZE		\
+				    + sizeof (struct grub_pe32_coff_header) \
+				    + sizeof (struct grub_pe32_optional_header) \
+				    + 4 * sizeof (struct grub_pe32_section_table), \
+				    GRUB_PE32_SECTION_ALIGNMENT)
+
+#define EFI64_HEADER_SIZE ALIGN_UP (GRUB_PE32_MSDOS_STUB_SIZE		\
+				    + GRUB_PE32_SIGNATURE_SIZE		\
+				    + sizeof (struct grub_pe32_coff_header) \
+				    + sizeof (struct grub_pe64_optional_header) \
+				    + 4 * sizeof (struct grub_pe32_section_table), \
+				    GRUB_PE32_SECTION_ALIGNMENT)
+
+struct grub_install_image_target_desc image_targets[] =
+  {
+    {
+      .dirname = "i386-coreboot",
+      .names = { "i386-coreboot", NULL },
+      .voidp_sizeof = 4,
+      .bigendian = 0,
+      .id = IMAGE_COREBOOT,
+      .flags = PLATFORM_FLAGS_NONE,
+      .total_module_size = TARGET_NO_FIELD,
+      .decompressor_compressed_size = TARGET_NO_FIELD,
+      .decompressor_uncompressed_size = TARGET_NO_FIELD,
+      .decompressor_uncompressed_addr = TARGET_NO_FIELD,
+      .section_align = 1,
+      .vaddr_offset = 0,
+      .link_addr = GRUB_KERNEL_I386_COREBOOT_LINK_ADDR,
+      .elf_target = EM_386,
+      .link_align = 4,
+      .mod_gap = GRUB_KERNEL_I386_COREBOOT_MOD_GAP,
+      .mod_align = GRUB_KERNEL_I386_COREBOOT_MOD_ALIGN
+    },
+    {
+      .dirname = "i386-multiboot",
+      .names = { "i386-multiboot", NULL},
+      .voidp_sizeof = 4,
+      .bigendian = 0,
+      .id = IMAGE_COREBOOT,
+      .flags = PLATFORM_FLAGS_NONE,
+      .total_module_size = TARGET_NO_FIELD,
+      .decompressor_compressed_size = TARGET_NO_FIELD,
+      .decompressor_uncompressed_size = TARGET_NO_FIELD,
+      .decompressor_uncompressed_addr = TARGET_NO_FIELD,
+      .section_align = 1,
+      .vaddr_offset = 0,
+      .link_addr = GRUB_KERNEL_I386_COREBOOT_LINK_ADDR,
+      .elf_target = EM_386,
+      .link_align = 4,
+      .mod_gap = GRUB_KERNEL_I386_COREBOOT_MOD_GAP,
+      .mod_align = GRUB_KERNEL_I386_COREBOOT_MOD_ALIGN
+    },
+    {
+      .dirname = "i386-pc",
+      .names = { "i386-pc", NULL },
+      .voidp_sizeof = 4,
+      .bigendian = 0,
+      .id = IMAGE_I386_PC, 
+      .flags = PLATFORM_FLAGS_DECOMPRESSORS,
+      .total_module_size = TARGET_NO_FIELD,
+      .decompressor_compressed_size = GRUB_DECOMPRESSOR_I386_PC_COMPRESSED_SIZE,
+      .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_I386_PC_UNCOMPRESSED_SIZE,
+      .decompressor_uncompressed_addr = TARGET_NO_FIELD,
+      .section_align = 1,
+      .vaddr_offset = 0,
+      .link_addr = GRUB_KERNEL_I386_PC_LINK_ADDR,
+      .default_compression = GRUB_COMPRESSION_LZMA
+    },
+    {
+      .dirname = "i386-pc",
+      .names = { "i386-pc-pxe", NULL },
+      .voidp_sizeof = 4,
+      .bigendian = 0,
+      .id = IMAGE_I386_PC_PXE, 
+      .flags = PLATFORM_FLAGS_DECOMPRESSORS,
+      .total_module_size = TARGET_NO_FIELD,
+      .decompressor_compressed_size = GRUB_DECOMPRESSOR_I386_PC_COMPRESSED_SIZE,
+      .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_I386_PC_UNCOMPRESSED_SIZE,
+      .decompressor_uncompressed_addr = TARGET_NO_FIELD,
+      .section_align = 1,
+      .vaddr_offset = 0,
+      .link_addr = GRUB_KERNEL_I386_PC_LINK_ADDR,
+      .default_compression = GRUB_COMPRESSION_LZMA
+    },
+    {
+      .dirname = "i386-efi",
+      .names = { "i386-efi", NULL },
+      .voidp_sizeof = 4,
+      .bigendian = 0,
+      .id = IMAGE_EFI,
+      .flags = PLATFORM_FLAGS_NONE,
+      .total_module_size = TARGET_NO_FIELD,
+      .decompressor_compressed_size = TARGET_NO_FIELD,
+      .decompressor_uncompressed_size = TARGET_NO_FIELD,
+      .decompressor_uncompressed_addr = TARGET_NO_FIELD,
+      .section_align = GRUB_PE32_SECTION_ALIGNMENT,
+      .vaddr_offset = EFI32_HEADER_SIZE,
+      .pe_target = GRUB_PE32_MACHINE_I386,
+      .elf_target = EM_386,
+    },
+    {
+      .dirname = "i386-ieee1275",
+      .names = { "i386-ieee1275", NULL },
+      .voidp_sizeof = 4,
+      .bigendian = 0,
+      .id = IMAGE_I386_IEEE1275, 
+      .flags = PLATFORM_FLAGS_NONE,
+      .total_module_size = TARGET_NO_FIELD,
+      .decompressor_compressed_size = TARGET_NO_FIELD,
+      .decompressor_uncompressed_size = TARGET_NO_FIELD,
+      .decompressor_uncompressed_addr = TARGET_NO_FIELD,
+      .section_align = 1,
+      .vaddr_offset = 0,
+      .link_addr = GRUB_KERNEL_I386_IEEE1275_LINK_ADDR,
+      .elf_target = EM_386,
+      .mod_gap = GRUB_KERNEL_I386_IEEE1275_MOD_GAP,
+      .mod_align = GRUB_KERNEL_I386_IEEE1275_MOD_ALIGN,
+      .link_align = 4,
+    },
+    {
+      .dirname = "i386-qemu",
+      .names = { "i386-qemu", NULL },
+      .voidp_sizeof = 4,
+      .bigendian = 0,
+      .id = IMAGE_QEMU, 
+      .flags = PLATFORM_FLAGS_NONE,
+      .total_module_size = TARGET_NO_FIELD,
+      .decompressor_compressed_size = TARGET_NO_FIELD,
+      .decompressor_uncompressed_size = TARGET_NO_FIELD,
+      .decompressor_uncompressed_addr = TARGET_NO_FIELD,
+      .section_align = 1,
+      .vaddr_offset = 0,
+      .link_addr = GRUB_KERNEL_I386_QEMU_LINK_ADDR
+    },
+    {
+      .dirname = "x86_64-efi",
+      .names = { "x86_64-efi", NULL },
+      .voidp_sizeof = 8,
+      .bigendian = 0, 
+      .id = IMAGE_EFI, 
+      .flags = PLATFORM_FLAGS_NONE,
+      .total_module_size = TARGET_NO_FIELD,
+      .decompressor_compressed_size = TARGET_NO_FIELD,
+      .decompressor_uncompressed_size = TARGET_NO_FIELD,
+      .decompressor_uncompressed_addr = TARGET_NO_FIELD,
+      .section_align = GRUB_PE32_SECTION_ALIGNMENT,
+      .vaddr_offset = EFI64_HEADER_SIZE,
+      .pe_target = GRUB_PE32_MACHINE_X86_64,
+      .elf_target = EM_X86_64,
+    },
+    {
+      .dirname = "mipsel-loongson",
+      .names = { "mipsel-yeeloong-flash", NULL },
+      .voidp_sizeof = 4,
+      .bigendian = 0,
+      .id = IMAGE_YEELOONG_FLASH, 
+      .flags = PLATFORM_FLAGS_DECOMPRESSORS,
+      .total_module_size = GRUB_KERNEL_MIPS_LOONGSON_TOTAL_MODULE_SIZE,
+      .decompressor_compressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_COMPRESSED_SIZE,
+      .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_SIZE,
+      .decompressor_uncompressed_addr = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_ADDR,
+      .section_align = 1,
+      .vaddr_offset = 0,
+      .link_addr = GRUB_KERNEL_MIPS_LOONGSON_LINK_ADDR,
+      .elf_target = EM_MIPS,
+      .link_align = GRUB_KERNEL_MIPS_LOONGSON_LINK_ALIGN,
+      .default_compression = GRUB_COMPRESSION_NONE
+    },
+    {
+      .dirname = "mipsel-loongson",
+      .names = { "mipsel-fuloong2f-flash", NULL },
+      .voidp_sizeof = 4,
+      .bigendian = 0,
+      .id = IMAGE_FULOONG2F_FLASH, 
+      .flags = PLATFORM_FLAGS_DECOMPRESSORS,
+      .total_module_size = GRUB_KERNEL_MIPS_LOONGSON_TOTAL_MODULE_SIZE,
+      .decompressor_compressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_COMPRESSED_SIZE,
+      .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_SIZE,
+      .decompressor_uncompressed_addr = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_ADDR,
+      .section_align = 1,
+      .vaddr_offset = 0,
+      .link_addr = GRUB_KERNEL_MIPS_LOONGSON_LINK_ADDR,
+      .elf_target = EM_MIPS,
+      .link_align = GRUB_KERNEL_MIPS_LOONGSON_LINK_ALIGN,
+      .default_compression = GRUB_COMPRESSION_NONE
+    },
+    {
+      .dirname = "mipsel-loongson",
+      .names = { "mipsel-loongson-elf", "mipsel-yeeloong-elf",
+		 "mipsel-fuloong2f-elf", "mipsel-fuloong2e-elf",
+		 "mipsel-fuloong-elf", NULL },
+      .voidp_sizeof = 4,
+      .bigendian = 0,
+      .id = IMAGE_LOONGSON_ELF, 
+      .flags = PLATFORM_FLAGS_DECOMPRESSORS,
+      .total_module_size = GRUB_KERNEL_MIPS_LOONGSON_TOTAL_MODULE_SIZE,
+      .decompressor_compressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_COMPRESSED_SIZE,
+      .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_SIZE,
+      .decompressor_uncompressed_addr = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_ADDR,
+      .section_align = 1,
+      .vaddr_offset = 0,
+      .link_addr = GRUB_KERNEL_MIPS_LOONGSON_LINK_ADDR,
+      .elf_target = EM_MIPS,
+      .link_align = GRUB_KERNEL_MIPS_LOONGSON_LINK_ALIGN,
+      .default_compression = GRUB_COMPRESSION_NONE
+    },
+    {
+      .dirname = "powerpc-ieee1275",
+      .names = { "powerpc-ieee1275", NULL },
+      .voidp_sizeof = 4,
+      .bigendian = 1,
+      .id = IMAGE_PPC, 
+      .flags = PLATFORM_FLAGS_NONE,
+      .total_module_size = TARGET_NO_FIELD,
+      .decompressor_compressed_size = TARGET_NO_FIELD,
+      .decompressor_uncompressed_size = TARGET_NO_FIELD,
+      .decompressor_uncompressed_addr = TARGET_NO_FIELD,
+      .section_align = 1,
+      .vaddr_offset = 0,
+      .link_addr = GRUB_KERNEL_POWERPC_IEEE1275_LINK_ADDR,
+      .elf_target = EM_PPC,
+      .mod_gap = GRUB_KERNEL_POWERPC_IEEE1275_MOD_GAP,
+      .mod_align = GRUB_KERNEL_POWERPC_IEEE1275_MOD_ALIGN,
+      .link_align = 4
+    },
+    {
+      .dirname = "sparc64-ieee1275",
+      .names = { "sparc64-ieee1275-raw", NULL },
+      .voidp_sizeof = 8,
+      .bigendian = 1, 
+      .id = IMAGE_SPARC64_RAW,
+      .flags = PLATFORM_FLAGS_NONE,
+      .total_module_size = GRUB_KERNEL_SPARC64_IEEE1275_TOTAL_MODULE_SIZE,
+      .decompressor_compressed_size = TARGET_NO_FIELD,
+      .decompressor_uncompressed_size = TARGET_NO_FIELD,
+      .decompressor_uncompressed_addr = TARGET_NO_FIELD,
+      .section_align = 1,
+      .vaddr_offset = 0,
+      .link_addr = GRUB_KERNEL_SPARC64_IEEE1275_LINK_ADDR
+    },
+    {
+      .dirname = "sparc64-ieee1275",
+      .names = { "sparc64-ieee1275-cdcore", NULL },
+      .voidp_sizeof = 8,
+      .bigendian = 1, 
+      .id = IMAGE_SPARC64_CDCORE,
+      .flags = PLATFORM_FLAGS_NONE,
+      .total_module_size = GRUB_KERNEL_SPARC64_IEEE1275_TOTAL_MODULE_SIZE,
+      .decompressor_compressed_size = TARGET_NO_FIELD,
+      .decompressor_uncompressed_size = TARGET_NO_FIELD,
+      .decompressor_uncompressed_addr = TARGET_NO_FIELD,
+      .section_align = 1,
+      .vaddr_offset = 0,
+      .link_addr = GRUB_KERNEL_SPARC64_IEEE1275_LINK_ADDR
+    },
+    {
+      .dirname = "sparc64-ieee1275",
+      .names = { "sparc64-ieee1275-aout", NULL },
+      .voidp_sizeof = 8,
+      .bigendian = 1,
+      .id = IMAGE_SPARC64_AOUT,
+      .flags = PLATFORM_FLAGS_NONE,
+      .total_module_size = GRUB_KERNEL_SPARC64_IEEE1275_TOTAL_MODULE_SIZE,
+      .decompressor_compressed_size = TARGET_NO_FIELD,
+      .decompressor_uncompressed_size = TARGET_NO_FIELD,
+      .decompressor_uncompressed_addr = TARGET_NO_FIELD,
+      .section_align = 1,
+      .vaddr_offset = 0,
+      .link_addr = GRUB_KERNEL_SPARC64_IEEE1275_LINK_ADDR
+    },
+    {
+      .dirname = "ia64-efi",
+      .names = {"ia64-efi", NULL},
+      .voidp_sizeof = 8,
+      .bigendian = 0, 
+      .id = IMAGE_EFI, 
+      .flags = PLATFORM_FLAGS_NONE,
+      .total_module_size = TARGET_NO_FIELD,
+      .decompressor_compressed_size = TARGET_NO_FIELD,
+      .decompressor_uncompressed_size = TARGET_NO_FIELD,
+      .decompressor_uncompressed_addr = TARGET_NO_FIELD,
+      .section_align = GRUB_PE32_SECTION_ALIGNMENT,
+      .vaddr_offset = EFI64_HEADER_SIZE,
+      .pe_target = GRUB_PE32_MACHINE_IA64,
+      .elf_target = EM_IA_64,
+    },
+    {
+      .dirname = "mips-arc",
+      .names = {"mips-arc", NULL},
+      .voidp_sizeof = 4,
+      .bigendian = 1,
+      .id = IMAGE_MIPS_ARC, 
+      .flags = PLATFORM_FLAGS_DECOMPRESSORS,
+      .total_module_size = GRUB_KERNEL_MIPS_ARC_TOTAL_MODULE_SIZE,
+      .decompressor_compressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_COMPRESSED_SIZE,
+      .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_SIZE,
+      .decompressor_uncompressed_addr = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_ADDR,
+      .section_align = 1,
+      .vaddr_offset = 0,
+      .link_addr = GRUB_KERNEL_MIPS_ARC_LINK_ADDR,
+      .elf_target = EM_MIPS,
+      .link_align = GRUB_KERNEL_MIPS_ARC_LINK_ALIGN,
+      .default_compression = GRUB_COMPRESSION_NONE
+    },
+    {
+      .dirname = "mipsel-arc",
+      .names = {"mipsel-arc", NULL},
+      .voidp_sizeof = 4,
+      .bigendian = 0,
+      .id = IMAGE_MIPS_ARC, 
+      .flags = PLATFORM_FLAGS_DECOMPRESSORS,
+      .total_module_size = GRUB_KERNEL_MIPS_ARC_TOTAL_MODULE_SIZE,
+      .decompressor_compressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_COMPRESSED_SIZE,
+      .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_SIZE,
+      .decompressor_uncompressed_addr = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_ADDR,
+      .section_align = 1,
+      .vaddr_offset = 0,
+      .link_addr = GRUB_KERNEL_MIPSEL_ARC_LINK_ADDR,
+      .elf_target = EM_MIPS,
+      .link_align = GRUB_KERNEL_MIPS_ARC_LINK_ALIGN,
+      .default_compression = GRUB_COMPRESSION_NONE
+    },
+    {
+      .dirname = "mipsel-qemu_mips",
+      .names = { "mipsel-qemu_mips-elf", NULL },
+      .voidp_sizeof = 4,
+      .bigendian = 0,
+      .id = IMAGE_LOONGSON_ELF, 
+      .flags = PLATFORM_FLAGS_DECOMPRESSORS,
+      .total_module_size = GRUB_KERNEL_MIPS_QEMU_MIPS_TOTAL_MODULE_SIZE,
+      .decompressor_compressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_COMPRESSED_SIZE,
+      .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_SIZE,
+      .decompressor_uncompressed_addr = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_ADDR,
+      .section_align = 1,
+      .vaddr_offset = 0,
+      .link_addr = GRUB_KERNEL_MIPS_QEMU_MIPS_LINK_ADDR,
+      .elf_target = EM_MIPS,
+      .link_align = GRUB_KERNEL_MIPS_QEMU_MIPS_LINK_ALIGN,
+      .default_compression = GRUB_COMPRESSION_NONE
+    },
+    {
+      .dirname = "mips-qemu_mips",
+      .names = { "mips-qemu_mips-flash", NULL },
+      .voidp_sizeof = 4,
+      .bigendian = 1,
+      .id = IMAGE_QEMU_MIPS_FLASH, 
+      .flags = PLATFORM_FLAGS_DECOMPRESSORS,
+      .total_module_size = GRUB_KERNEL_MIPS_QEMU_MIPS_TOTAL_MODULE_SIZE,
+      .decompressor_compressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_COMPRESSED_SIZE,
+      .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_SIZE,
+      .decompressor_uncompressed_addr = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_ADDR,
+      .section_align = 1,
+      .vaddr_offset = 0,
+      .link_addr = GRUB_KERNEL_MIPS_QEMU_MIPS_LINK_ADDR,
+      .elf_target = EM_MIPS,
+      .link_align = GRUB_KERNEL_MIPS_QEMU_MIPS_LINK_ALIGN,
+      .default_compression = GRUB_COMPRESSION_NONE
+    },
+    {
+      .dirname = "mipsel-qemu_mips",
+      .names = { "mipsel-qemu_mips-flash", NULL },
+      .voidp_sizeof = 4,
+      .bigendian = 0,
+      .id = IMAGE_QEMU_MIPS_FLASH, 
+      .flags = PLATFORM_FLAGS_DECOMPRESSORS,
+      .total_module_size = GRUB_KERNEL_MIPS_QEMU_MIPS_TOTAL_MODULE_SIZE,
+      .decompressor_compressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_COMPRESSED_SIZE,
+      .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_SIZE,
+      .decompressor_uncompressed_addr = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_ADDR,
+      .section_align = 1,
+      .vaddr_offset = 0,
+      .link_addr = GRUB_KERNEL_MIPS_QEMU_MIPS_LINK_ADDR,
+      .elf_target = EM_MIPS,
+      .link_align = GRUB_KERNEL_MIPS_QEMU_MIPS_LINK_ALIGN,
+      .default_compression = GRUB_COMPRESSION_NONE
+    },
+    {
+      .dirname = "mips-qemu_mips",
+      .names = { "mips-qemu_mips-elf", NULL },
+      .voidp_sizeof = 4,
+      .bigendian = 1,
+      .id = IMAGE_LOONGSON_ELF, 
+      .flags = PLATFORM_FLAGS_DECOMPRESSORS,
+      .total_module_size = GRUB_KERNEL_MIPS_QEMU_MIPS_TOTAL_MODULE_SIZE,
+      .decompressor_compressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_COMPRESSED_SIZE,
+      .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_SIZE,
+      .decompressor_uncompressed_addr = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_ADDR,
+      .section_align = 1,
+      .vaddr_offset = 0,
+      .link_addr = GRUB_KERNEL_MIPS_QEMU_MIPS_LINK_ADDR,
+      .elf_target = EM_MIPS,
+      .link_align = GRUB_KERNEL_MIPS_QEMU_MIPS_LINK_ALIGN,
+      .default_compression = GRUB_COMPRESSION_NONE
+    },
+    {
+      .dirname = "arm-uboot",
+      .names = { "arm-uboot", NULL },
+      .voidp_sizeof = 4,
+      .bigendian = 0,
+      .id = IMAGE_UBOOT, 
+      .flags = PLATFORM_FLAGS_NONE,
+      .total_module_size = GRUB_KERNEL_ARM_UBOOT_TOTAL_MODULE_SIZE,
+      .decompressor_compressed_size = TARGET_NO_FIELD,
+      .decompressor_uncompressed_size = TARGET_NO_FIELD,
+      .decompressor_uncompressed_addr = TARGET_NO_FIELD,
+      .section_align = GRUB_KERNEL_ARM_UBOOT_MOD_ALIGN,
+      .vaddr_offset = 0,
+      .link_addr = GRUB_KERNEL_ARM_UBOOT_LINK_ADDR,
+      .elf_target = EM_ARM,
+      .mod_gap = GRUB_KERNEL_ARM_UBOOT_MOD_GAP,
+      .mod_align = GRUB_KERNEL_ARM_UBOOT_MOD_ALIGN,
+      .link_align = 4
+    },
+    {
+      .dirname = "arm-efi",
+      .names = { "arm-efi", NULL },
+      .voidp_sizeof = 4,
+      .bigendian = 0, 
+      .id = IMAGE_EFI, 
+      .flags = PLATFORM_FLAGS_NONE,
+      .total_module_size = TARGET_NO_FIELD,
+      .decompressor_compressed_size = TARGET_NO_FIELD,
+      .decompressor_uncompressed_size = TARGET_NO_FIELD,
+      .decompressor_uncompressed_addr = TARGET_NO_FIELD,
+      .section_align = GRUB_PE32_SECTION_ALIGNMENT,
+      .vaddr_offset = ALIGN_UP (GRUB_PE32_MSDOS_STUB_SIZE
+                                + GRUB_PE32_SIGNATURE_SIZE
+                                + sizeof (struct grub_pe32_coff_header)
+                                + sizeof (struct grub_pe32_optional_header)
+                                + 4 * sizeof (struct grub_pe32_section_table),
+                                GRUB_PE32_SECTION_ALIGNMENT),
+      .pe_target = GRUB_PE32_MACHINE_ARMTHUMB_MIXED,
+      .elf_target = EM_ARM,
+    },
+  };
+
+#define grub_target_to_host32(x) (grub_target_to_host32_real (image_target, (x)))
+#define grub_host_to_target32(x) (grub_host_to_target32_real (image_target, (x)))
+#define grub_target_to_host64(x) (grub_target_to_host64_real (image_target, (x)))
+#define grub_host_to_target64(x) (grub_host_to_target64_real (image_target, (x)))
+#define grub_host_to_target_addr(x) (grub_host_to_target_addr_real (image_target, (x)))
+#define grub_target_to_host16(x) (grub_target_to_host16_real (image_target, (x)))
+#define grub_host_to_target16(x) (grub_host_to_target16_real (image_target, (x)))
+
+static inline grub_uint32_t
+grub_target_to_host32_real (struct grub_install_image_target_desc *image_target, grub_uint32_t in)
+{
+  if (image_target->bigendian)
+    return grub_be_to_cpu32 (in);
+  else
+    return grub_le_to_cpu32 (in);
+}
+
+static inline grub_uint64_t
+grub_target_to_host64_real (struct grub_install_image_target_desc *image_target, grub_uint64_t in)
+{
+  if (image_target->bigendian)
+    return grub_be_to_cpu64 (in);
+  else
+    return grub_le_to_cpu64 (in);
+}
+
+static inline grub_uint64_t
+grub_host_to_target64_real (struct grub_install_image_target_desc *image_target, grub_uint64_t in)
+{
+  if (image_target->bigendian)
+    return grub_cpu_to_be64 (in);
+  else
+    return grub_cpu_to_le64 (in);
+}
+
+static inline grub_uint32_t
+grub_host_to_target32_real (struct grub_install_image_target_desc *image_target, grub_uint32_t in)
+{
+  if (image_target->bigendian)
+    return grub_cpu_to_be32 (in);
+  else
+    return grub_cpu_to_le32 (in);
+}
+
+static inline grub_uint16_t
+grub_target_to_host16_real (struct grub_install_image_target_desc *image_target, grub_uint16_t in)
+{
+  if (image_target->bigendian)
+    return grub_be_to_cpu16 (in);
+  else
+    return grub_le_to_cpu16 (in);
+}
+
+static inline grub_uint16_t
+grub_host_to_target16_real (struct grub_install_image_target_desc *image_target, grub_uint16_t in)
+{
+  if (image_target->bigendian)
+    return grub_cpu_to_be16 (in);
+  else
+    return grub_cpu_to_le16 (in);
+}
+
+static inline grub_uint64_t
+grub_host_to_target_addr_real (struct grub_install_image_target_desc *image_target, grub_uint64_t in)
+{
+  if (image_target->voidp_sizeof == 8)
+    return grub_host_to_target64_real (image_target, in);
+  else
+    return grub_host_to_target32_real (image_target, in);
+}
+
+static inline grub_uint64_t
+grub_target_to_host_real (struct grub_install_image_target_desc *image_target, grub_uint64_t in)
+{
+  if (image_target->voidp_sizeof == 8)
+    return grub_target_to_host64_real (image_target, in);
+  else
+    return grub_target_to_host32_real (image_target, in);
+}
+
+#define GRUB_IEEE1275_NOTE_NAME "PowerPC"
+#define GRUB_IEEE1275_NOTE_TYPE 0x1275
+
+/* These structures are defined according to the CHRP binding to IEEE1275,
+   "Client Program Format" section.  */
+
+struct grub_ieee1275_note_hdr
+{
+  grub_uint32_t namesz;
+  grub_uint32_t descsz;
+  grub_uint32_t type;
+  char name[sizeof (GRUB_IEEE1275_NOTE_NAME)];
+};
+
+struct grub_ieee1275_note_desc
+{
+  grub_uint32_t real_mode;
+  grub_uint32_t real_base;
+  grub_uint32_t real_size;
+  grub_uint32_t virt_base;
+  grub_uint32_t virt_size;
+  grub_uint32_t load_base;
+};
+
+struct grub_ieee1275_note
+{
+  struct grub_ieee1275_note_hdr header;
+  struct grub_ieee1275_note_desc descriptor;
+};
+
+#define grub_target_to_host(val) grub_target_to_host_real(image_target, (val))
+
+#include <grub/lib/LzmaEnc.h>
+
+static void *SzAlloc(void *p, size_t size) { p = p; return xmalloc(size); }
+static void SzFree(void *p, void *address) { p = p; free(address); }
+static ISzAlloc g_Alloc = { SzAlloc, SzFree };
+
+static void
+compress_kernel_lzma (char *kernel_img, size_t kernel_size,
+		      char **core_img, size_t *core_size)
+{
+  CLzmaEncProps props;
+  unsigned char out_props[5];
+  size_t out_props_size = 5;
+
+  LzmaEncProps_Init(&props);
+  props.dictSize = 1 << 16;
+  props.lc = 3;
+  props.lp = 0;
+  props.pb = 2;
+  props.numThreads = 1;
+
+  *core_img = xmalloc (kernel_size);
+
+  *core_size = kernel_size;
+  if (LzmaEncode ((unsigned char *) *core_img, core_size,
+		  (unsigned char *) kernel_img,
+		  kernel_size,
+		  &props, out_props, &out_props_size,
+		  0, NULL, &g_Alloc, &g_Alloc) != SZ_OK)
+    grub_util_error ("%s", _("cannot compress the kernel image"));
+}
+
+#ifdef HAVE_LIBLZMA
+static void
+compress_kernel_xz (char *kernel_img, size_t kernel_size,
+		    char **core_img, size_t *core_size)
+{
+  lzma_stream strm = LZMA_STREAM_INIT;
+  lzma_ret xzret;
+  lzma_options_lzma lzopts = {
+    .dict_size = 1 << 16,
+    .preset_dict = NULL,
+    .preset_dict_size = 0,
+    .lc = 3,
+    .lp = 0,
+    .pb = 2,
+    .mode = LZMA_MODE_NORMAL,
+    .nice_len = 64,
+    .mf = LZMA_MF_BT4,
+    .depth = 0,
+  };
+  lzma_filter fltrs[] = {
+    { .id = LZMA_FILTER_LZMA2, .options = &lzopts},
+    { .id = LZMA_VLI_UNKNOWN, .options = NULL}
+  };
+
+  xzret = lzma_stream_encoder (&strm, fltrs, LZMA_CHECK_NONE);
+  if (xzret != LZMA_OK)
+    grub_util_error ("%s", _("cannot compress the kernel image"));
+
+  *core_img = xmalloc (kernel_size);
+
+  *core_size = kernel_size;
+  strm.next_in = (unsigned char *) kernel_img;
+  strm.avail_in = kernel_size;
+  strm.next_out = (unsigned char *) *core_img;
+  strm.avail_out = *core_size;
+
+  while (1)
+    {
+      xzret = lzma_code (&strm, LZMA_FINISH);
+      if (xzret == LZMA_OK)
+	continue;
+      if (xzret == LZMA_STREAM_END)
+	break;
+      grub_util_error ("%s", _("cannot compress the kernel image"));
+    }
+
+  *core_size -= strm.avail_out;
+}
+#endif
+
+static void
+compress_kernel (struct grub_install_image_target_desc *image_target, char *kernel_img,
+		 size_t kernel_size, char **core_img, size_t *core_size,
+		 grub_compression_t comp)
+{
+  if (image_target->flags & PLATFORM_FLAGS_DECOMPRESSORS
+      && (comp == GRUB_COMPRESSION_LZMA))
+    {
+      compress_kernel_lzma (kernel_img, kernel_size, core_img,
+			    core_size);
+      return;
+    }
+
+#ifdef HAVE_LIBLZMA
+ if (image_target->flags & PLATFORM_FLAGS_DECOMPRESSORS
+     && (comp == GRUB_COMPRESSION_XZ))
+   {
+     compress_kernel_xz (kernel_img, kernel_size, core_img,
+			 core_size);
+     return;
+   }
+#endif
+
+ if (image_target->flags & PLATFORM_FLAGS_DECOMPRESSORS
+     && (comp != GRUB_COMPRESSION_NONE))
+   grub_util_error (_("unknown compression %d\n"), comp);
+
+  *core_img = xmalloc (kernel_size);
+  memcpy (*core_img, kernel_img, kernel_size);
+  *core_size = kernel_size;
+}
+
+struct fixup_block_list
+{
+  struct fixup_block_list *next;
+  int state;
+  struct grub_pe32_fixup_block b;
+};
+
+#pragma GCC diagnostic ignored "-Wcast-align"
+
+#define MKIMAGE_ELF32 1
+#include "grub-mkimagexx.c"
+#undef MKIMAGE_ELF32
+
+#define MKIMAGE_ELF64 1
+#include "grub-mkimagexx.c"
+#undef MKIMAGE_ELF64
+
+struct grub_install_image_target_desc *
+grub_install_get_image_target (const char *arg)
+{
+  unsigned i, j;
+  for (i = 0; i < ARRAY_SIZE (image_targets); i++)
+    for (j = 0; image_targets[i].names[j]
+	   && j < ARRAY_SIZE (image_targets[i].names); j++)
+      if (strcmp (arg, image_targets[i].names[j]) == 0)
+	return &image_targets[i];
+  return NULL;
+}
+
+const char *
+grub_util_get_target_dirname (struct grub_install_image_target_desc *t)
+{
+  return t->dirname;
+}
+
+
+char *
+grub_install_get_image_targets_string (void)
+{
+  int format_len = 0;
+  char *formats;
+  char *ptr;
+  unsigned i;
+  for (i = 0; i < ARRAY_SIZE (image_targets); i++)
+    format_len += strlen (image_targets[i].names[0]) + 2;
+  ptr = formats = xmalloc (format_len);
+  for (i = 0; i < ARRAY_SIZE (image_targets); i++)
+    {
+      strcpy (ptr, image_targets[i].names[0]);
+      ptr += strlen (image_targets[i].names[0]);
+      *ptr++ = ',';
+      *ptr++ = ' ';
+    }
+  ptr[-2] = 0;
+
+  return formats;
+}
+
+void
+grub_install_generate_image (const char *dir, const char *prefix,
+			     FILE *out, const char *outname, char *mods[],
+			     char *memdisk_path, char **pubkey_paths, size_t npubkeys,
+			     char *config_path, struct grub_install_image_target_desc *image_target, int note,
+			     grub_compression_t comp)
+{
+  char *kernel_img, *core_img;
+  size_t kernel_size, total_module_size, core_size, exec_size;
+  size_t memdisk_size = 0, config_size = 0, config_size_pure = 0;
+  size_t prefix_size = 0;
+  char *kernel_path;
+  size_t offset;
+  struct grub_util_path_list *path_list, *p, *next;
+  grub_size_t bss_size;
+  grub_uint64_t start_address;
+  void *rel_section = 0;
+  grub_size_t reloc_size = 0, align;
+  size_t decompress_size = 0;
+
+  if (comp == GRUB_COMPRESSION_AUTO)
+    comp = image_target->default_compression;
+
+  if (image_target->id == IMAGE_I386_PC
+      || image_target->id == IMAGE_I386_PC_PXE)
+    comp = GRUB_COMPRESSION_LZMA;
+
+  path_list = grub_util_resolve_dependencies (dir, "moddep.lst", mods);
+
+  kernel_path = grub_util_get_path (dir, "kernel.img");
+
+  if (image_target->voidp_sizeof == 8)
+    total_module_size = sizeof (struct grub_module_info64);
+  else
+    total_module_size = sizeof (struct grub_module_info32);
+
+  {
+    size_t i;
+    for (i = 0; i < npubkeys; i++)
+      {
+	size_t curs;
+	curs = ALIGN_ADDR (grub_util_get_image_size (pubkey_paths[i]));
+	grub_util_info ("the size of public key %zd is 0x%llx",
+			i, (unsigned long long) curs);
+	total_module_size += curs + sizeof (struct grub_module_header);
+      }
+  }
+
+  if (memdisk_path)
+    {
+      memdisk_size = ALIGN_UP(grub_util_get_image_size (memdisk_path), 512);
+      grub_util_info ("the size of memory disk is 0x%llx",
+		      (unsigned long long) memdisk_size);
+      total_module_size += memdisk_size + sizeof (struct grub_module_header);
+    }
+
+  if (config_path)
+    {
+      config_size_pure = grub_util_get_image_size (config_path) + 1;
+      config_size = ALIGN_ADDR (config_size_pure);
+      grub_util_info ("the size of config file is 0x%llx",
+		      (unsigned long long) config_size);
+      total_module_size += config_size + sizeof (struct grub_module_header);
+    }
+
+  if (prefix)
+    {
+      prefix_size = ALIGN_ADDR (strlen (prefix) + 1);
+      total_module_size += prefix_size + sizeof (struct grub_module_header);
+    }
+
+  for (p = path_list; p; p = p->next)
+    total_module_size += (ALIGN_ADDR (grub_util_get_image_size (p->name))
+			  + sizeof (struct grub_module_header));
+
+  grub_util_info ("the total module size is 0x%llx",
+		  (unsigned long long) total_module_size);
+
+  if (image_target->voidp_sizeof == 4)
+    kernel_img = load_image32 (kernel_path, &exec_size, &kernel_size, &bss_size,
+			       total_module_size, &start_address, &rel_section,
+			       &reloc_size, &align, image_target);
+  else
+    kernel_img = load_image64 (kernel_path, &exec_size, &kernel_size, &bss_size,
+			       total_module_size, &start_address, &rel_section,
+			       &reloc_size, &align, image_target);
+
+  if ((image_target->flags & PLATFORM_FLAGS_DECOMPRESSORS)
+      && (image_target->total_module_size != TARGET_NO_FIELD))
+    *((grub_uint32_t *) (kernel_img + image_target->total_module_size))
+      = grub_host_to_target32 (total_module_size);
+
+  if (image_target->flags & PLATFORM_FLAGS_MODULES_BEFORE_KERNEL)
+    memmove (kernel_img + total_module_size, kernel_img, kernel_size);
+
+  if (image_target->voidp_sizeof == 8)
+    {
+      /* Fill in the grub_module_info structure.  */
+      struct grub_module_info64 *modinfo;
+      if (image_target->flags & PLATFORM_FLAGS_MODULES_BEFORE_KERNEL)
+	modinfo = (struct grub_module_info64 *) kernel_img;
+      else
+	modinfo = (struct grub_module_info64 *) (kernel_img + kernel_size);
+      memset (modinfo, 0, sizeof (struct grub_module_info64));
+      modinfo->magic = grub_host_to_target32 (GRUB_MODULE_MAGIC);
+      modinfo->offset = grub_host_to_target_addr (sizeof (struct grub_module_info64));
+      modinfo->size = grub_host_to_target_addr (total_module_size);
+      if (image_target->flags & PLATFORM_FLAGS_MODULES_BEFORE_KERNEL)
+	offset = sizeof (struct grub_module_info64);
+      else
+	offset = kernel_size + sizeof (struct grub_module_info64);
+    }
+  else
+    {
+      /* Fill in the grub_module_info structure.  */
+      struct grub_module_info32 *modinfo;
+      if (image_target->flags & PLATFORM_FLAGS_MODULES_BEFORE_KERNEL)
+	modinfo = (struct grub_module_info32 *) kernel_img;
+      else
+	modinfo = (struct grub_module_info32 *) (kernel_img + kernel_size);
+      memset (modinfo, 0, sizeof (struct grub_module_info32));
+      modinfo->magic = grub_host_to_target32 (GRUB_MODULE_MAGIC);
+      modinfo->offset = grub_host_to_target_addr (sizeof (struct grub_module_info32));
+      modinfo->size = grub_host_to_target_addr (total_module_size);
+      if (image_target->flags & PLATFORM_FLAGS_MODULES_BEFORE_KERNEL)
+	offset = sizeof (struct grub_module_info32);
+      else
+	offset = kernel_size + sizeof (struct grub_module_info32);
+    }
+
+  for (p = path_list; p; p = p->next)
+    {
+      struct grub_module_header *header;
+      size_t mod_size, orig_size;
+
+      orig_size = grub_util_get_image_size (p->name);
+      mod_size = ALIGN_ADDR (orig_size);
+
+      header = (struct grub_module_header *) (kernel_img + offset);
+      memset (header, 0, sizeof (struct grub_module_header));
+      header->type = grub_host_to_target32 (OBJ_TYPE_ELF);
+      header->size = grub_host_to_target32 (mod_size + sizeof (*header));
+      offset += sizeof (*header);
+      memset (kernel_img + offset + orig_size, 0, mod_size - orig_size);
+
+      grub_util_load_image (p->name, kernel_img + offset);
+      offset += mod_size;
+    }
+
+  {
+    size_t i;
+    for (i = 0; i < npubkeys; i++)
+      {
+	size_t curs;
+	struct grub_module_header *header;
+
+	curs = grub_util_get_image_size (pubkey_paths[i]);
+
+	header = (struct grub_module_header *) (kernel_img + offset);
+	memset (header, 0, sizeof (struct grub_module_header));
+	header->type = grub_host_to_target32 (OBJ_TYPE_PUBKEY);
+	header->size = grub_host_to_target32 (curs + sizeof (*header));
+	offset += sizeof (*header);
+
+	grub_util_load_image (pubkey_paths[i], kernel_img + offset);
+	offset += ALIGN_ADDR (curs);
+      }
+  }
+
+  if (memdisk_path)
+    {
+      struct grub_module_header *header;
+
+      header = (struct grub_module_header *) (kernel_img + offset);
+      memset (header, 0, sizeof (struct grub_module_header));
+      header->type = grub_host_to_target32 (OBJ_TYPE_MEMDISK);
+      header->size = grub_host_to_target32 (memdisk_size + sizeof (*header));
+      offset += sizeof (*header);
+
+      grub_util_load_image (memdisk_path, kernel_img + offset);
+      offset += memdisk_size;
+    }
+
+  if (config_path)
+    {
+      struct grub_module_header *header;
+
+      header = (struct grub_module_header *) (kernel_img + offset);
+      memset (header, 0, sizeof (struct grub_module_header));
+      header->type = grub_host_to_target32 (OBJ_TYPE_CONFIG);
+      header->size = grub_host_to_target32 (config_size + sizeof (*header));
+      offset += sizeof (*header);
+
+      grub_util_load_image (config_path, kernel_img + offset);
+      *(kernel_img + offset + config_size_pure - 1) = 0;
+      offset += config_size;
+    }
+
+  if (prefix)
+    {
+      struct grub_module_header *header;
+
+      header = (struct grub_module_header *) (kernel_img + offset);
+      memset (header, 0, sizeof (struct grub_module_header));
+      header->type = grub_host_to_target32 (OBJ_TYPE_PREFIX);
+      header->size = grub_host_to_target32 (prefix_size + sizeof (*header));
+      offset += sizeof (*header);
+
+      grub_memset (kernel_img + offset, 0, prefix_size);
+      grub_strcpy (kernel_img + offset, prefix);
+      offset += prefix_size;
+    }
+
+  grub_util_info ("kernel_img=%p, kernel_size=0x%llx", kernel_img,
+		  (unsigned long long) kernel_size);
+  compress_kernel (image_target, kernel_img, kernel_size + total_module_size,
+		   &core_img, &core_size, comp);
+  free (kernel_img);
+
+  grub_util_info ("the core size is 0x%llx", (unsigned long long) core_size);
+
+  if (!(image_target->flags & PLATFORM_FLAGS_DECOMPRESSORS) 
+      && image_target->total_module_size != TARGET_NO_FIELD)
+    *((grub_uint32_t *) (core_img + image_target->total_module_size))
+      = grub_host_to_target32 (total_module_size);
+
+  if (image_target->flags & PLATFORM_FLAGS_DECOMPRESSORS)
+    {
+      char *full_img;
+      size_t full_size;
+      char *decompress_path, *decompress_img;
+      const char *name;
+
+      switch (comp)
+	{
+	case GRUB_COMPRESSION_XZ:
+	  name = "xz_decompress.img";
+	  break;
+	case GRUB_COMPRESSION_LZMA:
+	  name = "lzma_decompress.img";
+	  break;
+	case GRUB_COMPRESSION_NONE:
+	  name = "none_decompress.img";
+	  break;
+	default:
+	  grub_util_error (_("unknown compression %d\n"), comp);
+	}
+      
+      decompress_path = grub_util_get_path (dir, name);
+      decompress_size = grub_util_get_image_size (decompress_path);
+      decompress_img = grub_util_read_image (decompress_path);
+
+      if ((image_target->id == IMAGE_I386_PC
+	   || image_target->id == IMAGE_I386_PC_PXE)
+	  && decompress_size > GRUB_KERNEL_I386_PC_LINK_ADDR - 0x8200)
+	grub_util_error ("%s", _("Decompressor is too big"));
+
+      if (image_target->decompressor_compressed_size != TARGET_NO_FIELD)
+	*((grub_uint32_t *) (decompress_img
+			     + image_target->decompressor_compressed_size))
+	  = grub_host_to_target32 (core_size);
+
+      if (image_target->decompressor_uncompressed_size != TARGET_NO_FIELD)
+	*((grub_uint32_t *) (decompress_img
+			     + image_target->decompressor_uncompressed_size))
+	  = grub_host_to_target32 (kernel_size + total_module_size);
+
+      if (image_target->decompressor_uncompressed_addr != TARGET_NO_FIELD)
+	{
+	  if (image_target->flags & PLATFORM_FLAGS_MODULES_BEFORE_KERNEL)
+	    *((grub_uint32_t *) (decompress_img + image_target->decompressor_uncompressed_addr))
+	      = grub_host_to_target_addr (image_target->link_addr - total_module_size);
+	  else
+	    *((grub_uint32_t *) (decompress_img + image_target->decompressor_uncompressed_addr))
+	      = grub_host_to_target_addr (image_target->link_addr);
+	}
+      full_size = core_size + decompress_size;
+
+      full_img = xmalloc (full_size);
+      memset (full_img, 0, full_size); 
+
+      memcpy (full_img, decompress_img, decompress_size);
+
+      memcpy (full_img + decompress_size, core_img, core_size);
+
+      memset (full_img + decompress_size + core_size, 0,
+	      full_size - (decompress_size + core_size));
+
+      free (core_img);
+      core_img = full_img;
+      core_size = full_size;
+    }
+
+  switch (image_target->id)
+    {
+    case IMAGE_I386_PC:
+    case IMAGE_I386_PC_PXE:
+	if (GRUB_KERNEL_I386_PC_LINK_ADDR + core_size > 0x78000
+	    || (core_size > (0xffff << GRUB_DISK_SECTOR_BITS))
+	    || (kernel_size + bss_size + GRUB_KERNEL_I386_PC_LINK_ADDR > 0x68000))
+	  grub_util_error (_("core image is too big (0x%x > 0x%x)"),
+			   GRUB_KERNEL_I386_PC_LINK_ADDR + (unsigned) core_size,
+			   0x78000);
+	/* fallthrough */
+    case IMAGE_COREBOOT:
+    case IMAGE_QEMU:
+	if (kernel_size + bss_size + GRUB_KERNEL_I386_PC_LINK_ADDR > 0x68000)
+	  grub_util_error (_("kernel image is too big (0x%x > 0x%x)"),
+			   (unsigned) kernel_size + (unsigned) bss_size
+			   + GRUB_KERNEL_I386_PC_LINK_ADDR,
+			   0x68000);
+	break;
+    case IMAGE_LOONGSON_ELF:
+    case IMAGE_YEELOONG_FLASH:
+    case IMAGE_FULOONG2F_FLASH:
+    case IMAGE_EFI:
+    case IMAGE_MIPS_ARC:
+    case IMAGE_QEMU_MIPS_FLASH:
+      break;
+    case IMAGE_SPARC64_AOUT:
+    case IMAGE_SPARC64_RAW:
+    case IMAGE_SPARC64_CDCORE:
+    case IMAGE_I386_IEEE1275:
+    case IMAGE_PPC:
+    case IMAGE_UBOOT:
+      break;
+    }
+
+  switch (image_target->id)
+    {
+    case IMAGE_I386_PC:
+    case IMAGE_I386_PC_PXE:
+      {
+	unsigned num;
+	char *boot_path, *boot_img;
+	size_t boot_size;
+
+	num = ((core_size + GRUB_DISK_SECTOR_SIZE - 1) >> GRUB_DISK_SECTOR_BITS);
+	if (image_target->id == IMAGE_I386_PC_PXE)
+	  {
+	    char *pxeboot_path, *pxeboot_img;
+	    size_t pxeboot_size;
+	    grub_uint32_t *ptr;
+	    
+	    pxeboot_path = grub_util_get_path (dir, "pxeboot.img");
+	    pxeboot_size = grub_util_get_image_size (pxeboot_path);
+	    pxeboot_img = grub_util_read_image (pxeboot_path);
+	    
+	    grub_util_write_image (pxeboot_img, pxeboot_size, out,
+				   outname);
+	    free (pxeboot_img);
+	    free (pxeboot_path);
+
+	    /* Remove Multiboot header to avoid confusing ipxe.  */
+	    for (ptr = (grub_uint32_t *) core_img;
+		 ptr < (grub_uint32_t *) (core_img + MULTIBOOT_SEARCH); ptr++)
+	      if (*ptr == grub_host_to_target32 (MULTIBOOT_HEADER_MAGIC)
+		  && grub_target_to_host32 (ptr[0])
+		  + grub_target_to_host32 (ptr[1])
+		  + grub_target_to_host32 (ptr[2]) == 0)
+		{
+		  *ptr = 0;
+		  break;
+		}
+	  }
+
+	boot_path = grub_util_get_path (dir, "diskboot.img");
+	boot_size = grub_util_get_image_size (boot_path);
+	if (boot_size != GRUB_DISK_SECTOR_SIZE)
+	  grub_util_error (_("diskboot.img size must be %u bytes"),
+			   GRUB_DISK_SECTOR_SIZE);
+
+	boot_img = grub_util_read_image (boot_path);
+
+	{
+	  struct grub_pc_bios_boot_blocklist *block;
+	  block = (struct grub_pc_bios_boot_blocklist *) (boot_img
+							  + GRUB_DISK_SECTOR_SIZE
+							  - sizeof (*block));
+	  block->len = grub_host_to_target16 (num);
+
+	  /* This is filled elsewhere.  Verify it just in case.  */
+	  assert (block->segment
+		  == grub_host_to_target16 (GRUB_BOOT_I386_PC_KERNEL_SEG
+					    + (GRUB_DISK_SECTOR_SIZE >> 4)));
+	}
+
+	grub_util_write_image (boot_img, boot_size, out, outname);
+	free (boot_img);
+	free (boot_path);
+      }
+      break;
+    case IMAGE_EFI:
+      {
+	void *pe_img;
+	grub_uint8_t *header;
+	void *sections;
+	size_t pe_size;
+	struct grub_pe32_coff_header *c;
+	struct grub_pe32_section_table *text_section, *data_section;
+	struct grub_pe32_section_table *mods_section, *reloc_section;
+	static const grub_uint8_t stub[] = GRUB_PE32_MSDOS_STUB;
+	int header_size;
+	int reloc_addr;
+
+	if (image_target->voidp_sizeof == 4)
+	  header_size = EFI32_HEADER_SIZE;
+	else
+	  header_size = EFI64_HEADER_SIZE;
+
+	reloc_addr = ALIGN_UP (header_size + core_size,
+			       image_target->section_align);
+
+	pe_size = ALIGN_UP (reloc_addr + reloc_size,
+			    image_target->section_align);
+	pe_img = xmalloc (reloc_addr + reloc_size);
+	memset (pe_img, 0, header_size);
+	memcpy ((char *) pe_img + header_size, core_img, core_size);
+	memcpy ((char *) pe_img + reloc_addr, rel_section, reloc_size);
+	header = pe_img;
+
+	/* The magic.  */
+	memcpy (header, stub, GRUB_PE32_MSDOS_STUB_SIZE);
+	memcpy (header + GRUB_PE32_MSDOS_STUB_SIZE, "PE\0\0",
+		GRUB_PE32_SIGNATURE_SIZE);
+
+	/* The COFF file header.  */
+	c = (struct grub_pe32_coff_header *) (header + GRUB_PE32_MSDOS_STUB_SIZE
+					      + GRUB_PE32_SIGNATURE_SIZE);
+	c->machine = grub_host_to_target16 (image_target->pe_target);
+
+	c->num_sections = grub_host_to_target16 (4);
+	c->time = grub_host_to_target32 (time (0));
+	c->characteristics = grub_host_to_target16 (GRUB_PE32_EXECUTABLE_IMAGE
+						    | GRUB_PE32_LINE_NUMS_STRIPPED
+						    | ((image_target->voidp_sizeof == 4)
+						       ? GRUB_PE32_32BIT_MACHINE
+						       : 0)
+						    | GRUB_PE32_LOCAL_SYMS_STRIPPED
+						    | GRUB_PE32_DEBUG_STRIPPED);
+
+	/* The PE Optional header.  */
+	if (image_target->voidp_sizeof == 4)
+	  {
+	    struct grub_pe32_optional_header *o;
+
+	    c->optional_header_size = grub_host_to_target16 (sizeof (struct grub_pe32_optional_header));
+
+	    o = (struct grub_pe32_optional_header *)
+	      (header + GRUB_PE32_MSDOS_STUB_SIZE + GRUB_PE32_SIGNATURE_SIZE
+	       + sizeof (struct grub_pe32_coff_header));
+	    o->magic = grub_host_to_target16 (GRUB_PE32_PE32_MAGIC);
+	    o->code_size = grub_host_to_target32 (exec_size);
+	    o->data_size = grub_cpu_to_le32 (reloc_addr - exec_size
+					     - header_size);
+	    o->bss_size = grub_cpu_to_le32 (bss_size);
+	    o->entry_addr = grub_cpu_to_le32 (start_address);
+	    o->code_base = grub_cpu_to_le32 (header_size);
+
+	    o->data_base = grub_host_to_target32 (header_size + exec_size);
+
+	    o->image_base = 0;
+	    o->section_alignment = grub_host_to_target32 (image_target->section_align);
+	    o->file_alignment = grub_host_to_target32 (image_target->section_align);
+	    o->image_size = grub_host_to_target32 (pe_size);
+	    o->header_size = grub_host_to_target32 (header_size);
+	    o->subsystem = grub_host_to_target16 (GRUB_PE32_SUBSYSTEM_EFI_APPLICATION);
+
+	    /* Do these really matter? */
+	    o->stack_reserve_size = grub_host_to_target32 (0x10000);
+	    o->stack_commit_size = grub_host_to_target32 (0x10000);
+	    o->heap_reserve_size = grub_host_to_target32 (0x10000);
+	    o->heap_commit_size = grub_host_to_target32 (0x10000);
+    
+	    o->num_data_directories = grub_host_to_target32 (GRUB_PE32_NUM_DATA_DIRECTORIES);
+
+	    o->base_relocation_table.rva = grub_host_to_target32 (reloc_addr);
+	    o->base_relocation_table.size = grub_host_to_target32 (reloc_size);
+	    sections = o + 1;
+	  }
+	else
+	  {
+	    struct grub_pe64_optional_header *o;
+
+	    c->optional_header_size = grub_host_to_target16 (sizeof (struct grub_pe64_optional_header));
+
+	    o = (struct grub_pe64_optional_header *) 
+	      (header + GRUB_PE32_MSDOS_STUB_SIZE + GRUB_PE32_SIGNATURE_SIZE
+	       + sizeof (struct grub_pe32_coff_header));
+	    o->magic = grub_host_to_target16 (GRUB_PE32_PE64_MAGIC);
+	    o->code_size = grub_host_to_target32 (exec_size);
+	    o->data_size = grub_cpu_to_le32 (reloc_addr - exec_size
+					     - header_size);
+	    o->bss_size = grub_cpu_to_le32 (bss_size);
+	    o->entry_addr = grub_cpu_to_le32 (start_address);
+	    o->code_base = grub_cpu_to_le32 (header_size);
+	    o->image_base = 0;
+	    o->section_alignment = grub_host_to_target32 (image_target->section_align);
+	    o->file_alignment = grub_host_to_target32 (image_target->section_align);
+	    o->image_size = grub_host_to_target32 (pe_size);
+	    o->header_size = grub_host_to_target32 (header_size);
+	    o->subsystem = grub_host_to_target16 (GRUB_PE32_SUBSYSTEM_EFI_APPLICATION);
+
+	    /* Do these really matter? */
+	    o->stack_reserve_size = grub_host_to_target64 (0x10000);
+	    o->stack_commit_size = grub_host_to_target64 (0x10000);
+	    o->heap_reserve_size = grub_host_to_target64 (0x10000);
+	    o->heap_commit_size = grub_host_to_target64 (0x10000);
+    
+	    o->num_data_directories
+	      = grub_host_to_target32 (GRUB_PE32_NUM_DATA_DIRECTORIES);
+
+	    o->base_relocation_table.rva = grub_host_to_target32 (reloc_addr);
+	    o->base_relocation_table.size = grub_host_to_target32 (reloc_size);
+	    sections = o + 1;
+	  }
+	/* The sections.  */
+	text_section = sections;
+	strcpy (text_section->name, ".text");
+	text_section->virtual_size = grub_cpu_to_le32 (exec_size);
+	text_section->virtual_address = grub_cpu_to_le32 (header_size);
+	text_section->raw_data_size = grub_cpu_to_le32 (exec_size);
+	text_section->raw_data_offset = grub_cpu_to_le32 (header_size);
+	text_section->characteristics = grub_cpu_to_le32 (GRUB_PE32_SCN_CNT_CODE
+							  | GRUB_PE32_SCN_MEM_EXECUTE
+							  | GRUB_PE32_SCN_MEM_READ);
+
+	data_section = text_section + 1;
+	strcpy (data_section->name, ".data");
+	data_section->virtual_size = grub_cpu_to_le32 (kernel_size - exec_size);
+	data_section->virtual_address = grub_cpu_to_le32 (header_size + exec_size);
+	data_section->raw_data_size = grub_cpu_to_le32 (kernel_size - exec_size);
+	data_section->raw_data_offset = grub_cpu_to_le32 (header_size + exec_size);
+	data_section->characteristics
+	  = grub_cpu_to_le32 (GRUB_PE32_SCN_CNT_INITIALIZED_DATA
+			      | GRUB_PE32_SCN_MEM_READ
+			      | GRUB_PE32_SCN_MEM_WRITE);
+
+#if 0
+	bss_section = data_section + 1;
+	strcpy (bss_section->name, ".bss");
+	bss_section->virtual_size = grub_cpu_to_le32 (bss_size);
+	bss_section->virtual_address = grub_cpu_to_le32 (header_size + kernel_size);
+	bss_section->raw_data_size = 0;
+	bss_section->raw_data_offset = 0;
+	bss_section->characteristics
+	  = grub_cpu_to_le32 (GRUB_PE32_SCN_MEM_READ
+			      | GRUB_PE32_SCN_MEM_WRITE
+			      | GRUB_PE32_SCN_ALIGN_64BYTES
+			      | GRUB_PE32_SCN_CNT_INITIALIZED_DATA
+			      | 0x80);
+#endif
+    
+	mods_section = data_section + 1;
+	strcpy (mods_section->name, "mods");
+	mods_section->virtual_size = grub_cpu_to_le32 (reloc_addr - kernel_size - header_size);
+	mods_section->virtual_address = grub_cpu_to_le32 (header_size + kernel_size + bss_size);
+	mods_section->raw_data_size = grub_cpu_to_le32 (reloc_addr - kernel_size - header_size);
+	mods_section->raw_data_offset = grub_cpu_to_le32 (header_size + kernel_size);
+	mods_section->characteristics
+	  = grub_cpu_to_le32 (GRUB_PE32_SCN_CNT_INITIALIZED_DATA
+			      | GRUB_PE32_SCN_MEM_READ
+			      | GRUB_PE32_SCN_MEM_WRITE);
+
+	reloc_section = mods_section + 1;
+	strcpy (reloc_section->name, ".reloc");
+	reloc_section->virtual_size = grub_cpu_to_le32 (reloc_size);
+	reloc_section->virtual_address = grub_cpu_to_le32 (reloc_addr + bss_size);
+	reloc_section->raw_data_size = grub_cpu_to_le32 (reloc_size);
+	reloc_section->raw_data_offset = grub_cpu_to_le32 (reloc_addr);
+	reloc_section->characteristics
+	  = grub_cpu_to_le32 (GRUB_PE32_SCN_CNT_INITIALIZED_DATA
+			      | GRUB_PE32_SCN_MEM_DISCARDABLE
+			      | GRUB_PE32_SCN_MEM_READ);
+	free (core_img);
+	core_img = pe_img;
+	core_size = pe_size;
+      }
+      break;
+    case IMAGE_QEMU:
+      {
+	char *rom_img;
+	size_t rom_size;
+	char *boot_path, *boot_img;
+	size_t boot_size;
+
+	boot_path = grub_util_get_path (dir, "boot.img");
+	boot_size = grub_util_get_image_size (boot_path);
+	boot_img = grub_util_read_image (boot_path);
+
+	/* Rom sizes must be 64k-aligned.  */
+	rom_size = ALIGN_UP (core_size + boot_size, 64 * 1024);
+
+	rom_img = xmalloc (rom_size);
+	memset (rom_img, 0, rom_size);
+
+	*((grub_int32_t *) (core_img + GRUB_KERNEL_I386_QEMU_CORE_ENTRY_ADDR))
+	  = grub_host_to_target32 ((grub_uint32_t) -rom_size);
+
+	memcpy (rom_img, core_img, core_size);
+
+	*((grub_int32_t *) (boot_img + GRUB_BOOT_I386_QEMU_CORE_ENTRY_ADDR))
+	  = grub_host_to_target32 ((grub_uint32_t) -rom_size);
+
+	memcpy (rom_img + rom_size - boot_size, boot_img, boot_size);
+
+	free (core_img);
+	core_img = rom_img;
+	core_size = rom_size;
+
+	free (boot_img);
+	free (boot_path);
+      }
+      break;
+    case IMAGE_SPARC64_AOUT:
+      {
+	void *aout_img;
+	size_t aout_size;
+	struct grub_aout32_header *aout_head;
+
+	aout_size = core_size + sizeof (*aout_head);
+	aout_img = xmalloc (aout_size);
+	aout_head = aout_img;
+	grub_memset (aout_head, 0, sizeof (*aout_head));
+	aout_head->a_midmag = grub_host_to_target32 ((AOUT_MID_SUN << 16)
+						     | AOUT32_OMAGIC);
+	aout_head->a_text = grub_host_to_target32 (core_size);
+	aout_head->a_entry
+	  = grub_host_to_target32 (GRUB_BOOT_SPARC64_IEEE1275_IMAGE_ADDRESS);
+	memcpy ((char *) aout_img + sizeof (*aout_head), core_img, core_size);
+
+	free (core_img);
+	core_img = aout_img;
+	core_size = aout_size;
+      }
+      break;
+    case IMAGE_SPARC64_RAW:
+      {
+	unsigned int num;
+	char *boot_path, *boot_img;
+	size_t boot_size;
+
+	num = ((core_size + GRUB_DISK_SECTOR_SIZE - 1) >> GRUB_DISK_SECTOR_BITS);
+	num <<= GRUB_DISK_SECTOR_BITS;
+
+	boot_path = grub_util_get_path (dir, "diskboot.img");
+	boot_size = grub_util_get_image_size (boot_path);
+	if (boot_size != GRUB_DISK_SECTOR_SIZE)
+	  grub_util_error (_("diskboot.img size must be %u bytes"),
+			   GRUB_DISK_SECTOR_SIZE);
+
+	boot_img = grub_util_read_image (boot_path);
+
+	*((grub_uint32_t *) (boot_img + GRUB_DISK_SECTOR_SIZE
+			     - GRUB_BOOT_SPARC64_IEEE1275_LIST_SIZE + 8))
+	  = grub_host_to_target32 (num);
+
+	grub_util_write_image (boot_img, boot_size, out, outname);
+	free (boot_img);
+	free (boot_path);
+      }
+      break;
+    case IMAGE_SPARC64_CDCORE:
+      break;
+    case IMAGE_YEELOONG_FLASH:
+    case IMAGE_FULOONG2F_FLASH:
+    {
+      char *rom_img;
+      size_t rom_size;
+      char *boot_path, *boot_img;
+      size_t boot_size;
+      grub_uint8_t context[GRUB_MD_SHA512->contextsize];
+      /* fwstart.img is the only part which can't be tested by using *-elf
+	 target. Check it against the checksum. */
+      const grub_uint8_t yeeloong_fwstart_good_hash[512 / 8] = 
+	{
+	  0x5f, 0x67, 0x46, 0x57, 0x31, 0x30, 0xc5, 0x0a,
+	  0xe9, 0x98, 0x18, 0xc9, 0xf3, 0xca, 0x45, 0xa5,
+	  0x75, 0x64, 0x6b, 0xbb, 0x24, 0xcd, 0xb4, 0xbc,
+	  0xf2, 0x3e, 0x23, 0xf9, 0xc2, 0x6a, 0x8c, 0xde,
+	  0x3b, 0x94, 0x9c, 0xcc, 0xa5, 0xa7, 0x58, 0xb1,
+	  0xbe, 0x8b, 0x3d, 0x73, 0x98, 0x18, 0x7e, 0x68,
+	  0x5e, 0x5f, 0x23, 0x7d, 0x7a, 0xe8, 0x51, 0xf7,
+	  0x1a, 0xaf, 0x2f, 0x54, 0x11, 0x2e, 0x5c, 0x25
+	};
+      const grub_uint8_t fuloong2f_fwstart_good_hash[512 / 8] = 
+	{ 
+	  0x76, 0x9b, 0xad, 0x6e, 0xa2, 0x39, 0x47, 0x62,
+	  0x1f, 0xc9, 0x3a, 0x6d, 0x05, 0x5c, 0x43, 0x5c,
+	  0x29, 0x4a, 0x7e, 0x08, 0x2a, 0x31, 0x8f, 0x5d,
+	  0x02, 0x84, 0xa0, 0x85, 0xf2, 0xd1, 0xb9, 0x53,
+	  0xa2, 0xbc, 0xf2, 0xe1, 0x39, 0x1e, 0x51, 0xb5,
+	  0xaf, 0xec, 0x9e, 0xf2, 0xf1, 0xf3, 0x0a, 0x2f,
+	  0xe6, 0xf1, 0x08, 0x89, 0xbe, 0xbc, 0x73, 0xab,
+	  0x46, 0x50, 0xd6, 0x21, 0xce, 0x8e, 0x24, 0xa7
+	};
+      const grub_uint8_t *fwstart_good_hash;
+            
+      if (image_target->id == IMAGE_FULOONG2F_FLASH)
+	{
+	  fwstart_good_hash = fuloong2f_fwstart_good_hash;
+	  boot_path = grub_util_get_path (dir, "fwstart_fuloong2f.img");
+	}
+      else
+	{
+	  fwstart_good_hash = yeeloong_fwstart_good_hash;
+	  boot_path = grub_util_get_path (dir, "fwstart.img");
+	}
+
+      boot_size = grub_util_get_image_size (boot_path);
+      boot_img = grub_util_read_image (boot_path);
+
+      grub_memset (context, 0, sizeof (context));
+      GRUB_MD_SHA512->init (context);
+      GRUB_MD_SHA512->write (context, boot_img, boot_size);
+      GRUB_MD_SHA512->final (context);
+      if (grub_memcmp (GRUB_MD_SHA512->read (context), fwstart_good_hash,
+		       GRUB_MD_SHA512->mdlen) != 0)
+	/* TRANSLATORS: fwstart.img may still be good, just it wasn't checked.  */
+	grub_util_warn ("%s",
+			_("fwstart.img doesn't match the known good version. "
+			  "proceed at your own risk"));
+
+      if (core_size + boot_size > 512 * 1024)
+	grub_util_error ("%s", _("firmware image is too big"));
+      rom_size = 512 * 1024;
+
+      rom_img = xmalloc (rom_size);
+      memset (rom_img, 0, rom_size); 
+
+      memcpy (rom_img, boot_img, boot_size);
+
+      memcpy (rom_img + boot_size, core_img, core_size);
+
+      memset (rom_img + boot_size + core_size, 0,
+	      rom_size - (boot_size + core_size));
+
+      free (core_img);
+      core_img = rom_img;
+      core_size = rom_size;
+    }
+    break;
+    case IMAGE_QEMU_MIPS_FLASH:
+    {
+      char *rom_img;
+      size_t rom_size;
+
+      if (core_size > 512 * 1024)
+	grub_util_error ("%s", _("firmware image is too big"));
+      rom_size = 512 * 1024;
+
+      rom_img = xmalloc (rom_size);
+      memset (rom_img, 0, rom_size); 
+
+      memcpy (rom_img, core_img, core_size);
+
+      memset (rom_img + core_size, 0,
+	      rom_size - core_size);
+
+      free (core_img);
+      core_img = rom_img;
+      core_size = rom_size;
+    }
+    break;
+
+    case IMAGE_UBOOT:
+    {
+      struct grub_uboot_image_header *hdr;
+      GRUB_PROPERLY_ALIGNED_ARRAY (crc32_context, GRUB_MD_CRC32->contextsize);
+
+      hdr = xmalloc (core_size + sizeof (struct grub_uboot_image_header));
+      memcpy (hdr + 1, core_img, core_size);
+
+      memset (hdr, 0, sizeof (*hdr));
+      hdr->ih_magic = grub_cpu_to_be32_compile_time (GRUB_UBOOT_IH_MAGIC);
+      hdr->ih_time = grub_cpu_to_be32 (time (0));
+      hdr->ih_size = grub_cpu_to_be32 (core_size);
+      hdr->ih_load = grub_cpu_to_be32 (image_target->link_addr);
+      hdr->ih_ep = grub_cpu_to_be32 (image_target->link_addr);
+      hdr->ih_type = GRUB_UBOOT_IH_TYPE_KERNEL;
+      hdr->ih_os = GRUB_UBOOT_IH_OS_LINUX;
+      hdr->ih_arch = GRUB_UBOOT_IH_ARCH_ARM;
+      hdr->ih_comp = GRUB_UBOOT_IH_COMP_NONE;
+
+      GRUB_MD_CRC32->init(crc32_context);
+      GRUB_MD_CRC32->write(crc32_context, hdr + 1, core_size);
+      GRUB_MD_CRC32->final(crc32_context);
+      hdr->ih_dcrc = grub_get_unaligned32 (GRUB_MD_CRC32->read (crc32_context));
+
+      GRUB_MD_CRC32->init(crc32_context);
+      GRUB_MD_CRC32->write(crc32_context, hdr, sizeof (*hdr));
+      GRUB_MD_CRC32->final(crc32_context);
+      hdr->ih_hcrc = grub_get_unaligned32 (GRUB_MD_CRC32->read (crc32_context));
+
+      free (core_img);
+      core_img = (char *) hdr;
+      core_size += sizeof (struct grub_uboot_image_header);
+    }
+    break;
+
+    case IMAGE_MIPS_ARC:
+      {
+	char *ecoff_img;
+	struct ecoff_header {
+	  grub_uint16_t magic;
+	  grub_uint16_t nsec;
+	  grub_uint32_t time;
+	  grub_uint32_t syms;
+	  grub_uint32_t nsyms;
+	  grub_uint16_t opt;
+	  grub_uint16_t flags;
+	  grub_uint16_t magic2;
+	  grub_uint16_t version;
+	  grub_uint32_t textsize;
+	  grub_uint32_t datasize;
+	  grub_uint32_t bsssize;
+	  grub_uint32_t entry;
+	  grub_uint32_t text_start;
+	  grub_uint32_t data_start;
+	  grub_uint32_t bss_start;
+	  grub_uint32_t gprmask;
+	  grub_uint32_t cprmask[4];
+	  grub_uint32_t gp_value;
+	};
+	struct ecoff_section
+	{
+	  char name[8];
+	  grub_uint32_t paddr;
+	  grub_uint32_t vaddr;
+	  grub_uint32_t size;
+	  grub_uint32_t file_offset;
+	  grub_uint32_t reloc;
+	  grub_uint32_t gp;
+	  grub_uint16_t nreloc;
+	  grub_uint16_t ngp;
+	  grub_uint32_t flags;
+	};
+	struct ecoff_header *head;
+	struct ecoff_section *section;
+	grub_uint32_t target_addr;
+	size_t program_size;
+
+	program_size = ALIGN_ADDR (core_size);
+	if (comp == GRUB_COMPRESSION_NONE)
+	  target_addr = (image_target->link_addr - decompress_size);
+	else
+	  target_addr = ALIGN_UP (image_target->link_addr
+				  + kernel_size + total_module_size, 32);
+
+	ecoff_img = xmalloc (program_size + sizeof (*head) + sizeof (*section));
+	grub_memset (ecoff_img, 0, program_size + sizeof (*head) + sizeof (*section));
+	head = (void *) ecoff_img;
+	section = (void *) (head + 1);
+	head->magic = image_target->bigendian ? grub_host_to_target16 (0x160)
+	  : grub_host_to_target16 (0x166);
+	head->nsec = grub_host_to_target16 (1);
+	head->time = grub_host_to_target32 (0);
+	head->opt = grub_host_to_target16 (0x38);
+	head->flags = image_target->bigendian
+	  ? grub_host_to_target16 (0x207)
+	  : grub_host_to_target16 (0x103);
+	head->magic2 = grub_host_to_target16 (0x107);
+	head->textsize = grub_host_to_target32 (program_size);
+	head->entry = grub_host_to_target32 (target_addr);
+	head->text_start = grub_host_to_target32 (target_addr);
+	head->data_start = grub_host_to_target32 (target_addr + program_size);
+	grub_memcpy (section->name, ".text", sizeof (".text") - 1); 
+	section->vaddr = grub_host_to_target32 (target_addr);
+	section->size = grub_host_to_target32 (program_size);
+	section->file_offset = grub_host_to_target32 (sizeof (*head) + sizeof (*section));
+	if (!image_target->bigendian)
+	  {
+	    section->paddr = grub_host_to_target32 (0xaa60);
+	    section->flags = grub_host_to_target32 (0x20);
+	  }
+	memcpy (section + 1, core_img, core_size);
+	free (core_img);
+	core_img = ecoff_img;
+	core_size = program_size + sizeof (*head) + sizeof (*section);
+      }
+      break;
+    case IMAGE_LOONGSON_ELF:
+    case IMAGE_PPC:
+    case IMAGE_COREBOOT:
+    case IMAGE_I386_IEEE1275:
+      {
+	char *elf_img;
+	size_t program_size;
+	Elf32_Ehdr *ehdr;
+	Elf32_Phdr *phdr;
+	grub_uint32_t target_addr;
+	int header_size, footer_size = 0;
+	int phnum = 1;
+	
+	if (image_target->id != IMAGE_LOONGSON_ELF)
+	  phnum += 2;
+
+	if (note)
+	  {
+	    phnum++;
+	    footer_size += sizeof (struct grub_ieee1275_note);
+	  }
+	header_size = ALIGN_ADDR (sizeof (*ehdr) + phnum * sizeof (*phdr));
+
+	program_size = ALIGN_ADDR (core_size);
+
+	elf_img = xmalloc (program_size + header_size + footer_size);
+	memset (elf_img, 0, program_size + header_size);
+	memcpy (elf_img  + header_size, core_img, core_size);
+	ehdr = (void *) elf_img;
+	phdr = (void *) (elf_img + sizeof (*ehdr));
+	memcpy (ehdr->e_ident, ELFMAG, SELFMAG);
+	ehdr->e_ident[EI_CLASS] = ELFCLASS32;
+	if (!image_target->bigendian)
+	  ehdr->e_ident[EI_DATA] = ELFDATA2LSB;
+	else
+	  ehdr->e_ident[EI_DATA] = ELFDATA2MSB;
+	ehdr->e_ident[EI_VERSION] = EV_CURRENT;
+	ehdr->e_ident[EI_OSABI] = ELFOSABI_NONE;
+	ehdr->e_type = grub_host_to_target16 (ET_EXEC);
+	ehdr->e_machine = grub_host_to_target16 (image_target->elf_target);
+	ehdr->e_version = grub_host_to_target32 (EV_CURRENT);
+
+	ehdr->e_phoff = grub_host_to_target32 ((char *) phdr - (char *) ehdr);
+	ehdr->e_phentsize = grub_host_to_target16 (sizeof (*phdr));
+	ehdr->e_phnum = grub_host_to_target16 (phnum);
+
+	/* No section headers.  */
+	ehdr->e_shoff = grub_host_to_target32 (0);
+	if (image_target->id == IMAGE_LOONGSON_ELF)
+	  ehdr->e_shentsize = grub_host_to_target16 (0);
+	else
+	  ehdr->e_shentsize = grub_host_to_target16 (sizeof (Elf32_Shdr));
+	ehdr->e_shnum = grub_host_to_target16 (0);
+	ehdr->e_shstrndx = grub_host_to_target16 (0);
+
+	ehdr->e_ehsize = grub_host_to_target16 (sizeof (*ehdr));
+
+	phdr->p_type = grub_host_to_target32 (PT_LOAD);
+	phdr->p_offset = grub_host_to_target32 (header_size);
+	phdr->p_flags = grub_host_to_target32 (PF_R | PF_W | PF_X);
+
+	if (image_target->id == IMAGE_LOONGSON_ELF)
+	  {
+	    if (comp == GRUB_COMPRESSION_NONE)
+	      target_addr = (image_target->link_addr - decompress_size);
+	    else
+	      target_addr = ALIGN_UP (image_target->link_addr
+				      + kernel_size + total_module_size, 32);
+	  }
+	else
+	  target_addr = image_target->link_addr;
+	ehdr->e_entry = grub_host_to_target32 (target_addr);
+	phdr->p_vaddr = grub_host_to_target32 (target_addr);
+	phdr->p_paddr = grub_host_to_target32 (target_addr);
+	phdr->p_align = grub_host_to_target32 (align > image_target->link_align ? align : image_target->link_align);
+	if (image_target->id == IMAGE_LOONGSON_ELF)
+	  ehdr->e_flags = grub_host_to_target32 (0x1000 | EF_MIPS_NOREORDER 
+						 | EF_MIPS_PIC | EF_MIPS_CPIC);
+	else
+	  ehdr->e_flags = 0;
+	if (image_target->id == IMAGE_LOONGSON_ELF)
+	  {
+	    phdr->p_filesz = grub_host_to_target32 (core_size);
+	    phdr->p_memsz = grub_host_to_target32 (core_size);
+	  }
+	else
+	  {
+	    grub_uint32_t target_addr_mods;
+	    phdr->p_filesz = grub_host_to_target32 (kernel_size);
+	    phdr->p_memsz = grub_host_to_target32 (kernel_size + bss_size);
+
+	    phdr++;
+	    phdr->p_type = grub_host_to_target32 (PT_GNU_STACK);
+	    phdr->p_offset = grub_host_to_target32 (header_size + kernel_size);
+	    phdr->p_paddr = phdr->p_vaddr = phdr->p_filesz = phdr->p_memsz = 0;
+	    phdr->p_flags = grub_host_to_target32 (PF_R | PF_W | PF_X);
+	    phdr->p_align = grub_host_to_target32 (image_target->link_align);
+
+	    phdr++;
+	    phdr->p_type = grub_host_to_target32 (PT_LOAD);
+	    phdr->p_offset = grub_host_to_target32 (header_size + kernel_size);
+	    phdr->p_flags = grub_host_to_target32 (PF_R | PF_W | PF_X);
+	    phdr->p_filesz = phdr->p_memsz
+	      = grub_host_to_target32 (core_size - kernel_size);
+
+	    if (image_target->id == IMAGE_COREBOOT)
+	      target_addr_mods = GRUB_KERNEL_I386_COREBOOT_MODULES_ADDR;
+	    else
+	      target_addr_mods = ALIGN_UP (target_addr + kernel_size + bss_size
+					   + image_target->mod_gap,
+					   image_target->mod_align);
+	    phdr->p_vaddr = grub_host_to_target32 (target_addr_mods);
+	    phdr->p_paddr = grub_host_to_target32 (target_addr_mods);
+	    phdr->p_align = grub_host_to_target32 (image_target->link_align);
+	  }
+
+	if (note)
+	  {
+	    int note_size = sizeof (struct grub_ieee1275_note);
+	    struct grub_ieee1275_note *note_ptr = (struct grub_ieee1275_note *) 
+	      (elf_img + program_size + header_size);
+
+	    grub_util_info ("adding CHRP NOTE segment");
+
+	    note_ptr->header.namesz = grub_host_to_target32 (sizeof (GRUB_IEEE1275_NOTE_NAME));
+	    note_ptr->header.descsz = grub_host_to_target32 (note_size);
+	    note_ptr->header.type = grub_host_to_target32 (GRUB_IEEE1275_NOTE_TYPE);
+	    strcpy (note_ptr->header.name, GRUB_IEEE1275_NOTE_NAME);
+	    note_ptr->descriptor.real_mode = grub_host_to_target32 (0xffffffff);
+	    note_ptr->descriptor.real_base = grub_host_to_target32 (0x00c00000);
+	    note_ptr->descriptor.real_size = grub_host_to_target32 (0xffffffff);
+	    note_ptr->descriptor.virt_base = grub_host_to_target32 (0xffffffff);
+	    note_ptr->descriptor.virt_size = grub_host_to_target32 (0xffffffff);
+	    note_ptr->descriptor.load_base = grub_host_to_target32 (0x00004000);
+
+	    phdr++;
+	    phdr->p_type = grub_host_to_target32 (PT_NOTE);
+	    phdr->p_flags = grub_host_to_target32 (PF_R);
+	    phdr->p_align = grub_host_to_target32 (image_target->voidp_sizeof);
+	    phdr->p_vaddr = 0;
+	    phdr->p_paddr = 0;
+	    phdr->p_filesz = grub_host_to_target32 (note_size);
+	    phdr->p_memsz = 0;
+	    phdr->p_offset = grub_host_to_target32 (header_size + program_size);
+	  }
+
+	free (core_img);
+	core_img = elf_img;
+	core_size = program_size + header_size + footer_size;
+      }
+      break;
+    }
+
+  grub_util_write_image (core_img, core_size, out, outname);
+  free (core_img);
+  free (kernel_path);
+
+  while (path_list)
+    {
+      next = path_list->next;
+      free ((void *) path_list->name);
+      free (path_list);
+      path_list = next;
+    }
+}
+
+\f

=== added file 'util/random.c'
--- util/random.c	1970-01-01 00:00:00 +0000
+++ util/random.c	2013-09-25 15:50:10 +0000
@@ -0,0 +1,5 @@
+#if defined (_WIN32) || defined (__CYGWIN__)
+#include "random_windows.c"
+#else
+#include "random_unix.c"
+#endif

=== added file 'util/random_unix.c'
--- util/random_unix.c	1970-01-01 00:00:00 +0000
+++ util/random_unix.c	2013-09-25 15:50:26 +0000
@@ -0,0 +1,53 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 1992-1999,2001,2003,2004,2005,2009,2010,2011,2012,2013 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 <config.h>
+
+#include <grub/types.h>
+#include <grub/crypto.h>
+#include <grub/auth.h>
+#include <grub/emu/misc.h>
+#include <grub/util/misc.h>
+#include <grub/i18n.h>
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int
+grub_get_random (void *out, grub_size_t len)
+{
+#if ! defined (__linux__) && ! defined (__FreeBSD__) && ! defined (__OpenBSD__) && !defined (__GNU__) && ! defined (_WIN32) && !defined(__CYGWIN__)
+  /* TRANSLATORS: The generator might still be secure just GRUB isn't sure about it.  */
+  printf ("%s", _("WARNING: your random generator isn't known to be secure\n"));
+#warning "your random generator isn't known to be secure"
+#endif
+  FILE *f;
+  size_t rd;
+
+  f = fopen ("/dev/urandom", "rb");
+  if (!f)
+    return 1;
+  rd = fread (out, 1, len, f);
+  fclose (f);
+
+  if (rd != len)
+    return 1;
+  return 0;
+}

=== added file 'util/random_windows.c'
--- util/random_windows.c	1970-01-01 00:00:00 +0000
+++ util/random_windows.c	2013-09-25 15:50:38 +0000
@@ -0,0 +1,55 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 1992-1999,2001,2003,2004,2005,2009,2010,2011,2012,2013 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 <config.h>
+
+#include <grub/types.h>
+#include <grub/crypto.h>
+#include <grub/auth.h>
+#include <grub/emu/misc.h>
+#include <grub/util/misc.h>
+#include <grub/i18n.h>
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <windows.h>
+#include <wincrypt.h>
+
+int
+grub_get_random (void *out, grub_size_t len)
+{
+  HCRYPTPROV   hCryptProv;
+  if (!CryptAcquireContext (&hCryptProv,
+			    NULL,
+			    MS_DEF_PROV,
+			    PROV_RSA_FULL,
+			    CRYPT_VERIFYCONTEXT))
+    return 1;
+  if (!CryptGenRandom (hCryptProv, len, out))
+    {
+      CryptReleaseContext (hCryptProv, 0);
+      return 1;
+    }
+
+  CryptReleaseContext (hCryptProv, 0);
+
+  return 0;
+}

=== added file 'util/setup.c'
--- util/setup.c	1970-01-01 00:00:00 +0000
+++ util/setup.c	2013-09-25 20:40:04 +0000
@@ -0,0 +1,983 @@
+/* grub-setup.c - make GRUB usable */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010,2011  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 <config.h>
+#include <grub/types.h>
+#include <grub/emu/misc.h>
+#include <grub/util/misc.h>
+#include <grub/device.h>
+#include <grub/disk.h>
+#include <grub/file.h>
+#include <grub/fs.h>
+#include <grub/partition.h>
+#include <grub/env.h>
+#include <grub/emu/hostdisk.h>
+#include <grub/term.h>
+#include <grub/i18n.h>
+#include <grub/util/lvm.h>
+#ifdef GRUB_SETUP_SPARC64
+#include <grub/util/ofpath.h>
+#include <grub/sparc64/ieee1275/boot.h>
+#include <grub/sparc64/ieee1275/kernel.h>
+#else
+#include <grub/i386/pc/boot.h>
+#include <grub/i386/pc/kernel.h>
+#endif
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <assert.h>
+#include <grub/emu/getroot.h>
+#include "progname.h"
+#include <grub/reed_solomon.h>
+#include <grub/msdos_partition.h>
+#include <include/grub/crypto.h>
+#include <grub/util/install.h>
+
+#ifdef __linux__
+#include <sys/ioctl.h>
+#include <linux/fs.h>
+#include <linux/fiemap.h>
+#endif
+
+#include <errno.h>
+
+/* On SPARC this program fills in various fields inside of the 'boot' and 'core'
+ * image files.
+ *
+ * The 'boot' image needs to know the OBP path name of the root
+ * device.  It also needs to know the initial block number of
+ * 'core' (which is 'diskboot' concatenated with 'kernel' and
+ * all the modules, this is created by grub-mkimage).  This resulting
+ * 'boot' image is 512 bytes in size and is placed in the second block
+ * of a partition.
+ *
+ * The initial 'diskboot' block acts as a loader for the actual GRUB
+ * kernel.  It contains the loading code and then a block list.
+ *
+ * The block list of 'core' starts at the end of the 'diskboot' image
+ * and works it's way backwards towards the end of the code of 'diskboot'.
+ *
+ * We patch up the images with the necessary values and write out the
+ * result.
+ */
+
+#define DEFAULT_CORE_FILE	"core.img"
+
+#ifdef GRUB_SETUP_SPARC64
+#define grub_target_to_host16(x)	grub_be_to_cpu16(x)
+#define grub_target_to_host32(x)	grub_be_to_cpu32(x)
+#define grub_target_to_host64(x)	grub_be_to_cpu64(x)
+#define grub_host_to_target16(x)	grub_cpu_to_be16(x)
+#define grub_host_to_target32(x)	grub_cpu_to_be32(x)
+#define grub_host_to_target64(x)	grub_cpu_to_be64(x)
+#elif defined (GRUB_SETUP_BIOS)
+#define grub_target_to_host16(x)	grub_le_to_cpu16(x)
+#define grub_target_to_host32(x)	grub_le_to_cpu32(x)
+#define grub_target_to_host64(x)	grub_le_to_cpu64(x)
+#define grub_host_to_target16(x)	grub_cpu_to_le16(x)
+#define grub_host_to_target32(x)	grub_cpu_to_le32(x)
+#define grub_host_to_target64(x)	grub_cpu_to_le64(x)
+#else
+#error Complete this
+#endif
+
+static void
+write_rootdev (grub_device_t root_dev,
+	       char *boot_img, grub_uint64_t first_sector)
+{
+#ifdef GRUB_SETUP_BIOS
+  {
+    grub_uint8_t *boot_drive;
+    void *kernel_sector;
+    boot_drive = (grub_uint8_t *) (boot_img + GRUB_BOOT_MACHINE_BOOT_DRIVE);
+    kernel_sector = (boot_img + GRUB_BOOT_MACHINE_KERNEL_SECTOR);
+
+    /* FIXME: can this be skipped?  */
+    *boot_drive = 0xFF;
+
+    grub_set_unaligned64 (kernel_sector, grub_cpu_to_le64 (first_sector));
+  }
+#endif
+#ifdef GRUB_SETUP_SPARC64
+  {
+    void *kernel_byte;
+    kernel_byte = (boot_img + GRUB_BOOT_AOUT_HEADER_SIZE
+		   + GRUB_BOOT_MACHINE_KERNEL_BYTE);
+    grub_set_unaligned64 (kernel_byte,
+			  grub_cpu_to_be64 (first_sector << GRUB_DISK_SECTOR_BITS));
+  }
+#endif
+}
+
+#ifdef GRUB_SETUP_SPARC64
+#define BOOT_SECTOR 1
+#else
+#define BOOT_SECTOR 0
+#endif
+
+/* Helper for setup.  */
+static void
+save_first_sector (grub_disk_addr_t sector, unsigned offset, unsigned length,
+		   void *data)
+{
+  grub_disk_addr_t *first_sector = data;
+  grub_util_info ("the first sector is <%" PRIuGRUB_UINT64_T ",%u,%u>",
+		  sector, offset, length);
+
+  if (offset != 0 || length != GRUB_DISK_SECTOR_SIZE)
+    grub_util_error ("%s", _("the first sector of the core file is not sector-aligned"));
+
+  *first_sector = sector;
+}
+
+struct blocklists
+{
+  struct grub_boot_blocklist *first_block, *block;
+#ifdef GRUB_SETUP_BIOS
+  grub_uint16_t current_segment;
+#endif
+  grub_uint16_t last_length;
+};
+
+/* Helper for setup.  */
+static void
+save_blocklists (grub_disk_addr_t sector, unsigned offset, unsigned length,
+		 void *data)
+{
+  struct blocklists *bl = data;
+  struct grub_boot_blocklist *prev = bl->block + 1;
+
+  grub_util_info ("saving <%" PRIuGRUB_UINT64_T ",%u,%u>",
+		  sector, offset, length);
+
+  if (offset != 0 || bl->last_length != GRUB_DISK_SECTOR_SIZE)
+    grub_util_error ("%s", _("non-sector-aligned data is found in the core file"));
+
+  if (bl->block != bl->first_block
+      && (grub_target_to_host64 (prev->start)
+	  + grub_target_to_host16 (prev->len)) == sector)
+    {
+      grub_uint16_t t = grub_target_to_host16 (prev->len) + 1;
+      prev->len = grub_host_to_target16 (t);
+    }
+  else
+    {
+      bl->block->start = grub_host_to_target64 (sector);
+      bl->block->len = grub_host_to_target16 (1);
+#ifdef GRUB_SETUP_BIOS
+      bl->block->segment = grub_host_to_target16 (bl->current_segment);
+#endif
+
+      bl->block--;
+      if (bl->block->len)
+	grub_util_error ("%s", _("the sectors of the core file are too fragmented"));
+    }
+
+  bl->last_length = length;
+#ifdef GRUB_SETUP_BIOS
+  bl->current_segment += GRUB_DISK_SECTOR_SIZE >> 4;
+#endif
+}
+
+#ifdef GRUB_SETUP_BIOS
+/* Context for setup/identify_partmap.  */
+struct identify_partmap_ctx
+{
+  grub_partition_map_t dest_partmap;
+  grub_partition_t container;
+  int multiple_partmaps;
+};
+
+/* Helper for setup.
+   Unlike root_dev, with dest_dev we're interested in the partition map even
+   if dest_dev itself is a whole disk.  */
+static int
+identify_partmap (grub_disk_t disk __attribute__ ((unused)),
+		  const grub_partition_t p, void *data)
+{
+  struct identify_partmap_ctx *ctx = data;
+
+  if (p->parent != ctx->container)
+    return 0;
+  /* NetBSD and OpenBSD subpartitions have metadata inside a partition,
+     so they are safe to ignore.
+   */
+  if (grub_strcmp (p->partmap->name, "netbsd") == 0
+      || grub_strcmp (p->partmap->name, "openbsd") == 0)
+    return 0;
+  if (ctx->dest_partmap == NULL)
+    {
+      ctx->dest_partmap = p->partmap;
+      return 0;
+    }
+  if (ctx->dest_partmap == p->partmap)
+    return 0;
+  ctx->multiple_partmaps = 1;
+  return 1;
+}
+#endif
+
+#ifdef GRUB_SETUP_BIOS
+#define SETUP grub_bios_setup
+#elif GRUB_SETUP_SPARC64
+#define SETUP grub_sparc_setup
+#else
+#error "Shouldn't happen"
+#endif
+
+void
+SETUP (const char *dir,
+       const char *boot_path, const char *core_file,
+       const char *dest, int force,
+       int fs_probe, int allow_floppy)
+{
+  char *core_path, *core_path_dev, *core_path_dev_full;
+  char *boot_img, *core_img;
+  char *root = 0;
+  size_t boot_size, core_size;
+#ifdef GRUB_SETUP_BIOS
+  grub_uint16_t core_sectors;
+#endif
+  grub_device_t root_dev = 0, dest_dev, core_dev;
+  struct blocklists bl;
+  char *tmp_img;
+  grub_disk_addr_t first_sector = (grub_disk_addr_t)-1;
+  FILE *fp;
+
+  if (!core_file)
+    core_file = DEFAULT_CORE_FILE;
+
+#ifdef GRUB_SETUP_BIOS
+  bl.current_segment =
+    GRUB_BOOT_I386_PC_KERNEL_SEG + (GRUB_DISK_SECTOR_SIZE >> 4);
+#endif
+  bl.last_length = GRUB_DISK_SECTOR_SIZE;
+
+  /* Read the boot image by the OS service.  */
+  boot_size = grub_util_get_image_size (boot_path);
+  if (boot_size != GRUB_DISK_SECTOR_SIZE)
+    grub_util_error (_("the size of `%s' is not %u"),
+		     boot_path, GRUB_DISK_SECTOR_SIZE);
+  boot_img = grub_util_read_image (boot_path);
+
+  core_path = grub_util_get_path (dir, core_file);
+  core_size = grub_util_get_image_size (core_path);
+#ifdef GRUB_SETUP_BIOS
+  core_sectors = ((core_size + GRUB_DISK_SECTOR_SIZE - 1)
+		  >> GRUB_DISK_SECTOR_BITS);
+#endif
+  if (core_size < GRUB_DISK_SECTOR_SIZE)
+    grub_util_error (_("the size of `%s' is too small"), core_path);
+#ifdef GRUB_SETUP_BIOS
+  if (core_size > 0xFFFF * GRUB_DISK_SECTOR_SIZE)
+    grub_util_error (_("the size of `%s' is too large"), core_path);
+#endif
+
+  core_img = grub_util_read_image (core_path);
+
+  /* Have FIRST_BLOCK to point to the first blocklist.  */
+  bl.first_block = (struct grub_boot_blocklist *) (core_img
+						   + GRUB_DISK_SECTOR_SIZE
+						   - sizeof (*bl.block));
+  grub_util_info ("root is `%s', dest is `%s'", root, dest);
+
+  grub_util_info ("Opening dest");
+  dest_dev = grub_device_open (dest);
+  if (! dest_dev)
+    grub_util_error ("%s", grub_errmsg);
+
+  core_dev = dest_dev;
+
+  {
+    char **root_devices = grub_guess_root_devices (dir);
+    char **cur;
+    int found = 0;
+
+    for (cur = root_devices; *cur; cur++)
+      {
+	char *drive;
+	grub_device_t try_dev;
+
+	drive = grub_util_get_grub_dev (*cur);
+	if (!drive)
+	  continue;
+	try_dev = grub_device_open (drive);
+	if (! try_dev)
+	  continue;
+	if (!found && try_dev->disk->id == dest_dev->disk->id
+	    && try_dev->disk->dev->id == dest_dev->disk->dev->id)
+	  {
+	    if (root_dev)
+	      grub_device_close (root_dev);
+	    free (root);
+	    root_dev = try_dev;
+	    root = drive;
+	    found = 1;
+	    continue;
+	  }
+	if (!root_dev)
+	  {
+	    root_dev = try_dev;
+	    root = drive;
+	    continue;
+	  }
+	grub_device_close (try_dev);	
+	free (drive);
+      }
+    if (!root_dev)
+      {
+	grub_util_error ("guessing the root device failed, because of `%s'",
+			 grub_errmsg);
+      }
+    grub_util_info ("guessed root_dev `%s' from "
+		    "dir `%s'", root_dev->disk->name, dir);
+  }
+
+  grub_util_info ("setting the root device to `%s'", root);
+  if (grub_env_set ("root", root) != GRUB_ERR_NONE)
+    grub_util_error ("%s", grub_errmsg);
+
+#ifdef GRUB_SETUP_BIOS
+  /* Read the original sector from the disk.  */
+  tmp_img = xmalloc (GRUB_DISK_SECTOR_SIZE);
+  if (grub_disk_read (dest_dev->disk, 0, 0, GRUB_DISK_SECTOR_SIZE, tmp_img))
+    grub_util_error ("%s", grub_errmsg);
+#endif
+
+#ifdef GRUB_SETUP_BIOS
+  {
+    grub_uint8_t *boot_drive_check;
+    boot_drive_check = (grub_uint8_t *) (boot_img
+					  + GRUB_BOOT_MACHINE_DRIVE_CHECK);
+    /* Copy the possible DOS BPB.  */
+    memcpy (boot_img + GRUB_BOOT_MACHINE_BPB_START,
+	    tmp_img + GRUB_BOOT_MACHINE_BPB_START,
+	    GRUB_BOOT_MACHINE_BPB_END - GRUB_BOOT_MACHINE_BPB_START);
+
+    /* If DEST_DRIVE is a hard disk, enable the workaround, which is
+       for buggy BIOSes which don't pass boot drive correctly. Instead,
+       they pass 0x00 or 0x01 even when booted from 0x80.  */
+    if (!allow_floppy && !grub_util_biosdisk_is_floppy (dest_dev->disk))
+      {
+	/* Replace the jmp (2 bytes) with double nop's.  */
+	boot_drive_check[0] = 0x90;
+	boot_drive_check[1] = 0x90;
+      }
+  }
+#endif
+
+#ifdef GRUB_SETUP_BIOS
+  {
+    struct identify_partmap_ctx ctx = {
+      .dest_partmap = NULL,
+      .container = dest_dev->disk->partition,
+      .multiple_partmaps = 0
+    };
+    int is_ldm;
+    grub_err_t err;
+    grub_disk_addr_t *sectors;
+    int i;
+    grub_fs_t fs;
+    unsigned int nsec, maxsec;
+
+    grub_partition_iterate (dest_dev->disk, identify_partmap, &ctx);
+
+    if (ctx.container
+	&& grub_strcmp (ctx.container->partmap->name, "msdos") == 0
+	&& ctx.dest_partmap
+	&& (ctx.container->msdostype == GRUB_PC_PARTITION_TYPE_NETBSD
+	    || ctx.container->msdostype == GRUB_PC_PARTITION_TYPE_OPENBSD))
+      {
+	grub_util_warn ("%s", _("Attempting to install GRUB to a disk with multiple partition labels or both partition label and filesystem.  This is not supported yet."));
+	goto unable_to_embed;
+      }
+
+    fs = grub_fs_probe (dest_dev);
+    if (!fs)
+      grub_errno = GRUB_ERR_NONE;
+
+    is_ldm = grub_util_is_ldm (dest_dev->disk);
+
+    if (fs_probe)
+      {
+	if (!fs && !ctx.dest_partmap)
+	  grub_util_error (_("unable to identify a filesystem in %s; safety check can't be performed"),
+			   dest_dev->disk->name);
+	if (fs && !fs->reserved_first_sector)
+	  /* TRANSLATORS: Filesystem may reserve the space just GRUB isn't sure about it.  */
+	  grub_util_error (_("%s appears to contain a %s filesystem which isn't known to "
+			     "reserve space for DOS-style boot.  Installing GRUB there could "
+			     "result in FILESYSTEM DESTRUCTION if valuable data is overwritten "
+			     "by grub-setup (--skip-fs-probe disables this "
+			     "check, use at your own risk)"), dest_dev->disk->name, fs->name);
+
+	if (ctx.dest_partmap && strcmp (ctx.dest_partmap->name, "msdos") != 0
+	    && strcmp (ctx.dest_partmap->name, "gpt") != 0
+	    && strcmp (ctx.dest_partmap->name, "bsd") != 0
+	    && strcmp (ctx.dest_partmap->name, "netbsd") != 0
+	    && strcmp (ctx.dest_partmap->name, "openbsd") != 0
+	    && strcmp (ctx.dest_partmap->name, "sunpc") != 0)
+	  /* TRANSLATORS: Partition map may reserve the space just GRUB isn't sure about it.  */
+	  grub_util_error (_("%s appears to contain a %s partition map which isn't known to "
+			     "reserve space for DOS-style boot.  Installing GRUB there could "
+			     "result in FILESYSTEM DESTRUCTION if valuable data is overwritten "
+			     "by grub-setup (--skip-fs-probe disables this "
+			     "check, use at your own risk)"), dest_dev->disk->name, ctx.dest_partmap->name);
+	if (is_ldm && ctx.dest_partmap && strcmp (ctx.dest_partmap->name, "msdos") != 0
+	    && strcmp (ctx.dest_partmap->name, "gpt") != 0)
+	  grub_util_error (_("%s appears to contain a %s partition map and "
+			     "LDM which isn't known to be a safe combination."
+			     "  Installing GRUB there could "
+			     "result in FILESYSTEM DESTRUCTION if valuable data"
+			     " is overwritten "
+			     "by grub-setup (--skip-fs-probe disables this "
+			     "check, use at your own risk)"),
+			   dest_dev->disk->name, ctx.dest_partmap->name);
+
+      }
+
+    /* Copy the partition table.  */
+    if (ctx.dest_partmap ||
+        (!allow_floppy && !grub_util_biosdisk_is_floppy (dest_dev->disk)))
+      memcpy (boot_img + GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC,
+	      tmp_img + GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC,
+	      GRUB_BOOT_MACHINE_PART_END - GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC);
+
+    free (tmp_img);
+    
+    if (! ctx.dest_partmap && ! fs && !is_ldm)
+      {
+	grub_util_warn ("%s", _("Attempting to install GRUB to a partitionless disk or to a partition.  This is a BAD idea."));
+	goto unable_to_embed;
+      }
+    if (ctx.multiple_partmaps || (ctx.dest_partmap && fs) || (is_ldm && fs))
+      {
+	grub_util_warn ("%s", _("Attempting to install GRUB to a disk with multiple partition labels.  This is not supported yet."));
+	goto unable_to_embed;
+      }
+
+    if (ctx.dest_partmap && !ctx.dest_partmap->embed)
+      {
+	grub_util_warn (_("Partition style `%s' doesn't support embedding"),
+			ctx.dest_partmap->name);
+	goto unable_to_embed;
+      }
+
+    if (fs && !fs->embed)
+      {
+	grub_util_warn (_("File system `%s' doesn't support embedding"),
+			fs->name);
+	goto unable_to_embed;
+      }
+
+    nsec = core_sectors;
+
+    maxsec = 2 * core_sectors;
+    if (maxsec > ((0x78000 - GRUB_KERNEL_I386_PC_LINK_ADDR)
+		>> GRUB_DISK_SECTOR_BITS))
+      maxsec = ((0x78000 - GRUB_KERNEL_I386_PC_LINK_ADDR)
+		>> GRUB_DISK_SECTOR_BITS);
+
+    if (is_ldm)
+      err = grub_util_ldm_embed (dest_dev->disk, &nsec, maxsec,
+				 GRUB_EMBED_PCBIOS, &sectors);
+    else if (ctx.dest_partmap)
+      err = ctx.dest_partmap->embed (dest_dev->disk, &nsec, maxsec,
+				     GRUB_EMBED_PCBIOS, &sectors);
+    else
+      err = fs->embed (dest_dev, &nsec, maxsec,
+		       GRUB_EMBED_PCBIOS, &sectors);
+    if (!err && nsec < core_sectors)
+      {
+	err = grub_error (GRUB_ERR_OUT_OF_RANGE,
+			  N_("Your embedding area is unusually small.  "
+			     "core.img won't fit in it."));
+      }
+    
+    if (err)
+      {
+	grub_util_warn ("%s", grub_errmsg);
+	grub_errno = GRUB_ERR_NONE;
+	goto unable_to_embed;
+      }
+
+    assert (nsec <= maxsec);
+
+    /* Clean out the blocklists.  */
+    bl.block = bl.first_block;
+    while (bl.block->len)
+      {
+	grub_memset (bl.block, 0, sizeof (bl.block));
+      
+	bl.block--;
+
+	if ((char *) bl.block <= core_img)
+	  grub_util_error ("%s", _("no terminator in the core image"));
+      }
+
+    save_first_sector (sectors[0] + grub_partition_get_start (ctx.container),
+		       0, GRUB_DISK_SECTOR_SIZE, &first_sector);
+
+    bl.block = bl.first_block;
+    for (i = 1; i < nsec; i++)
+      save_blocklists (sectors[i] + grub_partition_get_start (ctx.container),
+		       0, GRUB_DISK_SECTOR_SIZE, &bl);
+
+    /* Make sure that the last blocklist is a terminator.  */
+    if (bl.block == bl.first_block)
+      bl.block--;
+    bl.block->start = 0;
+    bl.block->len = 0;
+    bl.block->segment = 0;
+
+    write_rootdev (root_dev, boot_img, first_sector);
+
+    core_img = realloc (core_img, nsec * GRUB_DISK_SECTOR_SIZE);
+    bl.first_block = (struct grub_boot_blocklist *) (core_img
+						     + GRUB_DISK_SECTOR_SIZE
+						     - sizeof (*bl.block));
+
+    grub_size_t no_rs_length;
+    grub_set_unaligned32 ((core_img + GRUB_DISK_SECTOR_SIZE
+			   + GRUB_KERNEL_I386_PC_REED_SOLOMON_REDUNDANCY),
+			  grub_host_to_target32 (nsec * GRUB_DISK_SECTOR_SIZE - core_size));
+    no_rs_length = grub_target_to_host16 
+      (grub_get_unaligned16 (core_img
+			     + GRUB_DISK_SECTOR_SIZE
+			     + GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_LENGTH));
+
+    if (no_rs_length == 0xffff)
+      grub_util_error ("%s", _("core.img version mismatch"));
+
+    void *tmp = xmalloc (core_size);
+    grub_memcpy (tmp, core_img, core_size);
+    grub_reed_solomon_add_redundancy (core_img + no_rs_length + GRUB_DISK_SECTOR_SIZE,
+				      core_size - no_rs_length - GRUB_DISK_SECTOR_SIZE,
+				      nsec * GRUB_DISK_SECTOR_SIZE
+				      - core_size);
+    assert (grub_memcmp (tmp, core_img, core_size) == 0);
+    free (tmp);
+
+    /* Write the core image onto the disk.  */
+    for (i = 0; i < nsec; i++)
+      grub_disk_write (dest_dev->disk, sectors[i], 0,
+		       GRUB_DISK_SECTOR_SIZE,
+		       core_img + i * GRUB_DISK_SECTOR_SIZE);
+
+    grub_free (sectors);
+
+    goto finish;
+  }
+
+unable_to_embed:
+#endif
+
+  if (dest_dev->disk->dev->id != root_dev->disk->dev->id)
+    grub_util_error ("%s", _("embedding is not possible, but this is required for "
+			     "RAID and LVM install"));
+
+  {
+    grub_fs_t fs;
+    fs = grub_fs_probe (root_dev);
+    if (!fs)
+      grub_util_error (_("can't determine filesystem on %s"), root);
+
+    if (!fs->blocklist_install)
+      grub_util_error (_("filesystem `%s' doesn't support blocklists"),
+		       fs->name);
+  }
+
+#ifdef GRUB_SETUP_BIOS
+  if (dest_dev->disk->id != root_dev->disk->id
+      || dest_dev->disk->dev->id != root_dev->disk->dev->id)
+    /* TRANSLATORS: cross-disk refers to /boot being on one disk
+       but MBR on another.  */
+    grub_util_error ("%s", _("embedding is not possible, but this is required for "
+			     "cross-disk install"));
+#else
+  core_dev = root_dev;
+#endif
+
+  grub_util_warn ("%s", _("Embedding is not possible.  GRUB can only be installed in this "
+			  "setup by using blocklists.  However, blocklists are UNRELIABLE and "
+			  "their use is discouraged."));
+  if (! force)
+    /* TRANSLATORS: Here GRUB refuses to continue with blocklist install.  */
+    grub_util_error ("%s", _("will not proceed with blocklists"));
+
+  /* The core image must be put on a filesystem unfortunately.  */
+  grub_util_info ("will leave the core image on the filesystem");
+
+  /* Make sure that GRUB reads the identical image as the OS.  */
+  tmp_img = xmalloc (core_size);
+  core_path_dev_full = grub_util_get_path (dir, core_file);
+  core_path_dev = grub_make_system_path_relative_to_its_root (core_path_dev_full);
+  free (core_path_dev_full);
+
+  grub_util_biosdisk_flush (root_dev->disk);
+
+#ifndef __linux__
+
+#define MAX_TRIES	5
+  {
+    int i;
+    for (i = 0; i < MAX_TRIES; i++)
+      {
+	grub_file_t file;
+
+	grub_util_info ((i == 0) ? _("attempting to read the core image `%s' from GRUB")
+			: _("attempting to read the core image `%s' from GRUB again"),
+			core_path_dev);
+
+	grub_disk_cache_invalidate_all ();
+
+	grub_file_filter_disable_compression ();
+	file = grub_file_open (core_path_dev);
+	if (file)
+	  {
+	    if (grub_file_size (file) != core_size)
+	      grub_util_info ("succeeded in opening the core image but the size is different (%d != %d)",
+			      (int) grub_file_size (file), (int) core_size);
+	    else if (grub_file_read (file, tmp_img, core_size)
+		     != (grub_ssize_t) core_size)
+	      grub_util_info ("succeeded in opening the core image but cannot read %d bytes",
+			      (int) core_size);
+	    else if (memcmp (core_img, tmp_img, core_size) != 0)
+	      {
+#if 0
+		FILE *dump;
+		FILE *dump2;
+
+		dump = fopen ("dump.img", "wb");
+		if (dump)
+		  {
+		    fwrite (tmp_img, 1, core_size, dump);
+		    fclose (dump);
+		  }
+
+		dump2 = fopen ("dump2.img", "wb");
+		if (dump2)
+		  {
+		    fwrite (core_img, 1, core_size, dump2);
+		    fclose (dump2);
+		  }
+
+#endif
+		grub_util_info ("succeeded in opening the core image but the data is different");
+	      }
+	    else
+	      {
+		grub_file_close (file);
+		break;
+	      }
+
+	    grub_file_close (file);
+	  }
+	else
+	  grub_util_info ("couldn't open the core image");
+
+	if (grub_errno)
+	  grub_util_info ("error message = %s", grub_errmsg);
+
+	grub_errno = GRUB_ERR_NONE;
+	grub_util_biosdisk_flush (root_dev->disk);
+	sleep (1);
+      }
+
+    if (i == MAX_TRIES)
+      grub_util_error (_("cannot read `%s' correctly"), core_path_dev);
+  }
+
+#endif
+
+  /* Clean out the blocklists.  */
+  bl.block = bl.first_block;
+  while (bl.block->len)
+    {
+      bl.block->start = 0;
+      bl.block->len = 0;
+#ifdef GRUB_SETUP_BIOS
+      bl.block->segment = 0;
+#endif
+
+      bl.block--;
+
+      if ((char *) bl.block <= core_img)
+	grub_util_error ("%s", _("no terminator in the core image"));
+    }
+
+  bl.block = bl.first_block;
+
+#ifdef __linux__
+  {
+    grub_partition_t container = root_dev->disk->partition;
+    grub_uint64_t container_start = grub_partition_get_start (container);
+    struct fiemap fie1;
+    int fd;
+
+    /* Write the first two sectors of the core image onto the disk.  */
+    grub_util_info ("opening the core image `%s'", core_path);
+    fp = fopen (core_path, "rb");
+    if (! fp)
+      grub_util_error (_("cannot open `%s': %s"), core_path,
+		       strerror (errno));
+    fd = fileno (fp);
+
+    grub_memset (&fie1, 0, sizeof (fie1));
+    fie1.fm_length = core_size;
+    fie1.fm_flags = FIEMAP_FLAG_SYNC;
+
+    if (ioctl (fd, FS_IOC_FIEMAP, &fie1) < 0)
+      {
+	int nblocks, i, j;
+	int bsize;
+	int mul;
+
+	grub_util_info ("FIEMAP failed. Reverting to FIBMAP");
+
+	if (ioctl (fd, FIGETBSZ, &bsize) < 0)
+	  grub_util_error (_("can't retrieve blocklists: %s"),
+			   strerror (errno));
+	if (bsize & (GRUB_DISK_SECTOR_SIZE - 1))
+	  grub_util_error ("%s", _("blocksize is not divisible by 512"));
+	mul = bsize >> GRUB_DISK_SECTOR_BITS;
+	nblocks = (core_size + bsize - 1) / bsize;
+	if (mul == 0 || nblocks == 0)
+	  grub_util_error ("%s", _("can't retrieve blocklists"));
+	for (i = 0; i < nblocks; i++)
+	  {
+	    unsigned blk = i;
+	    if (ioctl (fd, FIBMAP, &blk) < 0)
+	      grub_util_error (_("can't retrieve blocklists: %s"),
+			       strerror (errno));
+	    
+	    for (j = 0; j < mul; j++)
+	      {
+		int rest = core_size - ((i * mul + j) << GRUB_DISK_SECTOR_BITS);
+		if (rest <= 0)
+		  break;
+		if (rest > GRUB_DISK_SECTOR_SIZE)
+		  rest = GRUB_DISK_SECTOR_SIZE;
+		if (i == 0 && j == 0)
+		  save_first_sector (((grub_uint64_t) blk) * mul
+				     + container_start,
+				     0, rest, &first_sector);
+		else
+		  save_blocklists (((grub_uint64_t) blk) * mul + j
+				   + container_start,
+				   0, rest, &bl);
+	      }
+	  }
+      }
+    else
+      {
+	struct fiemap *fie2;
+	int i, j;
+	fie2 = xmalloc (sizeof (*fie2)
+			+ fie1.fm_mapped_extents
+			* sizeof (fie1.fm_extents[1]));
+	memset (fie2, 0, sizeof (*fie2)
+		+ fie1.fm_mapped_extents * sizeof (fie2->fm_extents[1]));
+	fie2->fm_length = core_size;
+	fie2->fm_flags = FIEMAP_FLAG_SYNC;
+	fie2->fm_extent_count = fie1.fm_mapped_extents;
+	if (ioctl (fd, FS_IOC_FIEMAP, fie2) < 0)
+	  grub_util_error (_("can't retrieve blocklists: %s"),
+			   strerror (errno));
+	for (i = 0; i < fie2->fm_mapped_extents; i++)
+	  {
+	    for (j = 0;
+		 j < ((fie2->fm_extents[i].fe_length
+		       + GRUB_DISK_SECTOR_SIZE - 1)
+		      >> GRUB_DISK_SECTOR_BITS);
+		 j++)
+	      {
+		size_t len = (fie2->fm_extents[i].fe_length
+			      - j * GRUB_DISK_SECTOR_SIZE);
+		if (len > GRUB_DISK_SECTOR_SIZE)
+		  len = GRUB_DISK_SECTOR_SIZE;
+		if (first_sector == (grub_disk_addr_t)-1)
+		  save_first_sector ((fie2->fm_extents[i].fe_physical
+				      >> GRUB_DISK_SECTOR_BITS)
+				     + j + container_start,
+				     fie2->fm_extents[i].fe_physical
+				     & (GRUB_DISK_SECTOR_SIZE - 1), len,
+				     &first_sector);
+		else
+		  save_blocklists ((fie2->fm_extents[i].fe_physical
+				    >> GRUB_DISK_SECTOR_BITS)
+				   + j + container_start,
+				   fie2->fm_extents[i].fe_physical
+				   & (GRUB_DISK_SECTOR_SIZE - 1), len, &bl);
+
+
+	      }
+	  }
+	if (first_sector == (grub_disk_addr_t)-1)
+	  grub_util_error ("%s", _("can't retrieve blocklists"));
+      }
+    fclose (fp);
+  }
+#else
+  {
+    grub_file_t file;
+    /* Now read the core image to determine where the sectors are.  */
+    grub_file_filter_disable_compression ();
+    file = grub_file_open (core_path_dev);
+    if (! file)
+      grub_util_error ("%s", grub_errmsg);
+
+    file->read_hook = save_first_sector;
+    file->read_hook_data = &first_sector;
+    if (grub_file_read (file, tmp_img, GRUB_DISK_SECTOR_SIZE)
+	!= GRUB_DISK_SECTOR_SIZE)
+      grub_util_error ("%s", _("failed to read the first sector of the core image"));
+
+    bl.block = bl.first_block;
+    file->read_hook = save_blocklists;
+    file->read_hook_data = &bl;
+    if (grub_file_read (file, tmp_img, core_size - GRUB_DISK_SECTOR_SIZE)
+	!= (grub_ssize_t) core_size - GRUB_DISK_SECTOR_SIZE)
+      grub_util_error ("%s", _("failed to read the rest sectors of the core image"));
+    grub_file_close (file);
+  }
+#endif
+
+#ifdef GRUB_SETUP_SPARC64
+  {
+    char *boot_devpath;
+    boot_devpath = (char *) (boot_img
+			     + GRUB_BOOT_AOUT_HEADER_SIZE
+			     + GRUB_BOOT_MACHINE_BOOT_DEVPATH);
+    if (dest_dev->disk->id != root_dev->disk->id
+	|| dest_dev->disk->dev->id != root_dev->disk->dev->id)
+      {
+	const char *dest_ofpath;
+	dest_ofpath
+	  = grub_util_devname_to_ofpath (grub_util_biosdisk_get_osdev (root_dev->disk));
+	grub_util_info ("dest_ofpath is `%s'", dest_ofpath);
+	strncpy (boot_devpath, dest_ofpath,
+		 GRUB_BOOT_MACHINE_BOOT_DEVPATH_END
+		 - GRUB_BOOT_MACHINE_BOOT_DEVPATH - 1);
+	boot_devpath[GRUB_BOOT_MACHINE_BOOT_DEVPATH_END
+		   - GRUB_BOOT_MACHINE_BOOT_DEVPATH - 1] = 0;
+      }
+    else
+      {
+	grub_util_info ("non cross-disk install");
+	memset (boot_devpath, 0, GRUB_BOOT_MACHINE_BOOT_DEVPATH_END
+		- GRUB_BOOT_MACHINE_BOOT_DEVPATH);
+      }
+    grub_util_info ("boot device path %s", boot_devpath);
+  }
+#endif
+
+  free (core_path_dev);
+  free (tmp_img);
+
+  write_rootdev (root_dev, boot_img, first_sector);
+
+  /* Write the first two sectors of the core image onto the disk.  */
+  grub_util_info ("opening the core image `%s'", core_path);
+  fp = fopen (core_path, "r+b");
+  if (! fp)
+    grub_util_error (_("cannot open `%s': %s"), core_path,
+		     strerror (errno));
+
+  grub_util_write_image (core_img, GRUB_DISK_SECTOR_SIZE * 2, fp, core_path);
+  fflush (fp);
+  fsync (fileno (fp));
+  fclose (fp);
+  grub_util_biosdisk_flush (root_dev->disk);
+
+  grub_disk_cache_invalidate_all ();
+
+  {
+    char *buf, *ptr = core_img;
+    size_t len = core_size;
+    grub_uint64_t blk;
+    grub_partition_t container = core_dev->disk->partition;
+    grub_err_t err;
+
+    core_dev->disk->partition = 0;
+
+    buf = xmalloc (core_size);
+    blk = first_sector;
+    err = grub_disk_read (core_dev->disk, blk, 0, GRUB_DISK_SECTOR_SIZE, buf);
+    if (err)
+      grub_util_error (_("cannot read `%s': %s"), core_dev->disk->name,
+		       grub_errmsg);
+    if (grub_memcmp (buf, ptr, GRUB_DISK_SECTOR_SIZE) != 0)
+      grub_util_error ("%s", _("blocklists are invalid"));
+
+    ptr += GRUB_DISK_SECTOR_SIZE;
+    len -= GRUB_DISK_SECTOR_SIZE;
+
+    bl.block = bl.first_block;
+    while (bl.block->len)
+      {
+	size_t cur = grub_target_to_host16 (bl.block->len) << GRUB_DISK_SECTOR_BITS;
+	blk = grub_target_to_host64 (bl.block->start);
+
+	if (cur > len)
+	  cur = len;
+
+	err = grub_disk_read (core_dev->disk, blk, 0, cur, buf);
+	if (err)
+	  grub_util_error (_("cannot read `%s': %s"), core_dev->disk->name,
+			   grub_errmsg);
+
+	if (grub_memcmp (buf, ptr, cur) != 0)
+	  grub_util_error ("%s", _("blocklists are invalid"));
+
+	ptr += cur;
+	len -= cur;
+	bl.block--;
+	
+	if ((char *) bl.block <= core_img)
+	  grub_util_error ("%s", _("no terminator in the core image"));
+      }
+    core_dev->disk->partition = container;
+    free (buf);
+  }
+
+#ifdef GRUB_SETUP_BIOS
+ finish:
+#endif
+
+  /* Write the boot image onto the disk.  */
+  if (grub_disk_write (dest_dev->disk, BOOT_SECTOR,
+		       0, GRUB_DISK_SECTOR_SIZE, boot_img))
+    grub_util_error ("%s", grub_errmsg);
+
+  grub_util_biosdisk_flush (root_dev->disk);
+  grub_util_biosdisk_flush (dest_dev->disk);
+
+  free (core_path);
+  free (core_img);
+  free (boot_img);
+  grub_device_close (dest_dev);
+  grub_device_close (root_dev);
+}

=== added file 'util/setup_bios.c'
--- util/setup_bios.c	1970-01-01 00:00:00 +0000
+++ util/setup_bios.c	2013-09-25 13:01:02 +0000
@@ -0,0 +1,2 @@
+#define GRUB_SETUP_BIOS 1
+#include "setup.c"

=== added file 'util/setup_sparc.c'
--- util/setup_sparc.c	1970-01-01 00:00:00 +0000
+++ util/setup_sparc.c	2013-09-25 13:01:22 +0000
@@ -0,0 +1,2 @@
+#define GRUB_SETUP_SPARC64 1
+#include "setup.c"


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 291 bytes --]

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

end of thread, other threads:[~2013-10-06 18:05 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-09-26 17:52 [RFC] grub-install C rewrite Kalamatee
  -- strict thread matches above, loose matches on Subject: below --
2013-09-26 13:08 Vladimir 'φ-coder/phcoder' Serbinenko
2013-09-26 13:35 ` Lennart Sorensen
2013-09-26 13:59   ` Vladimir 'φ-coder/phcoder' Serbinenko
2013-09-26 14:44     ` Lennart Sorensen
2013-09-26 18:49       ` Vladimir 'φ-coder/phcoder' Serbinenko
2013-09-26 20:22         ` Lennart Sorensen
2013-09-26 20:29           ` Vladimir 'φ-coder/phcoder' Serbinenko
2013-09-26 20:51           ` Chris Murphy
2013-09-26 22:15             ` Vladimir 'φ-coder/phcoder' Serbinenko
2013-09-27  3:10         ` Andrey Borzenkov
2013-09-26 17:10   ` Seth Goldberg
2013-09-26 18:51     ` Vladimir 'φ-coder/phcoder' Serbinenko
2013-09-26 18:56       ` Darren J Moffat
2013-09-26 18:57       ` Seth Goldberg
2013-09-26 14:49 ` Andrey Borzenkov
2013-09-26 15:01   ` Vladimir 'φ-coder/phcoder' Serbinenko
2013-10-06 14:54 ` Vladimir 'φ-coder/phcoder' Serbinenko
2013-10-06 15:56   ` Andrey Borzenkov
2013-10-06 18:05     ` Vladimir 'φ-coder/phcoder' Serbinenko

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.