All of lore.kernel.org
 help / color / mirror / Atom feed
From: Leif Lindholm <leif.lindholm@arm.com>
To: grub-devel@gnu.org
Subject: [RFC] GRUB port for ARMv7-A U-Boot
Date: Mon, 22 Oct 2012 19:51:09 +0100	[thread overview]
Message-ID: <5085959D.4040407@arm.com> (raw)

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

Attached is a stripped-down version of what I have today uploaded to 
launchpad. The full set can be accessed through
bzr branch lp:~leif-lindholm/linaro-grub/arm-uboot

Missing from this patch is libfdt and the crc32-functions I mentioned
in my previous email, although they have not been stripped from the build 
configuration files.

This is a port of GRUB to the ARM architecture, running on top of the
U-Boot firmware. The "U-Boot API", created by Rafal Jaworowsky
<raj@semihalf.com>, for the FreeBSD Loader provides the hardware interface
layer. Console supported on serial port using the termios subsystem.
Block device support verified with SDcard and SATA.

Usage information:
- grub-mkimage generates a kernel with a U-Boot header masquerading it as a
   Linux kernel.
- U-Boot Environment variable grub_bootdev can be used to specify the root
   device.
- Block devices must be initialized by U-Boot before calling GRUB if they are
   to be accessible. (By calling "mmc rescan", "ide reset" or similar.)
- New "devicetree" command for loading a .dtb from a filesystem.

This has been verified on the following platforms:
- ARM Versatile Express (4xCortex-A9)
- Marvell Armada XP DB-78460-BP.
- Trim Slice

Imported code:
- The "U-Boot API".
- aeabi_* libgcc helper functions from linux/arch/arm/lib.

Limitations:
- Dynamic linker implemented only for ARMv7-A Thumb instruction set.
- Currently runs uncached, with MMU off.
- No support for ATAG parsing or rewriting, only supports device tree
   as a means of passing information to the Linux kernel. (If an ATAG
   list is passed from U-Boot, it can be passed on unmodified, but the
   "linux" command will not pass on command line parameters.)
- Currently a statically linked kernel, requires RAM at 0x08000000.

TODO:
- linux.init.arm, linux-initramfs.arm, bootcheck-linux-arm, grub-mkrescue

Potential future developments:
- Implement networking support.
- Make grub kernel a fully relocateable ELF.
- Implement chainloader.
- Enable caches/MMU.

Comments welcome.

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: armv7-uboot-stripped.patch --]
[-- Type: text/x-patch; name=armv7-uboot-stripped.patch, Size: 120081 bytes --]

=== modified file 'Makefile.util.def'
--- Makefile.util.def	2012-09-26 12:51:13 +0000
+++ Makefile.util.def	2012-10-22 18:29:17 +0000
@@ -469,6 +469,7 @@
   enable = mips_loongson;
   enable = ia64_efi;
   enable = powerpc_ieee1275;
+  enable = arm_uboot;
 };
 
 script = {

=== modified file 'conf/Makefile.common'
--- conf/Makefile.common	2012-04-18 21:37:25 +0000
+++ conf/Makefile.common	2012-10-22 18:29:17 +0000
@@ -37,6 +37,12 @@
   CFLAGS_PLATFORM += -mno-app-regs
   LDFLAGS_PLATFORM = -Wl,-melf64_sparc -mno-relax
 endif
+if COND_arm
+# Image entry point always in ARM (A32) state - ensure proper functionality if
+# the rest is built for the Thumb (T32) state.
+  CFLAGS_PLATFORM += -mthumb-interwork -mno-unaligned-access
+  CCASFLAGS_PLATFORM = -Wa,-mimplicit-it=thumb
+endif
 
 # Other options
 
@@ -58,6 +64,7 @@
 if ! COND_i386_multiboot
 if ! COND_i386_ieee1275
 if ! COND_x86_64_efi
+if ! COND_arm
 LDADD_KERNEL += -lgcc
 endif
 endif
@@ -66,9 +73,14 @@
 endif
 endif
 endif
+endif
 
 CFLAGS_KERNEL = $(CFLAGS_CPU) $(CFLAGS_PLATFORM) -ffreestanding
+if ! COND_arm
 LDFLAGS_KERNEL = $(LDFLAGS_CPU) $(LDFLAGS_PLATFORM) -nostdlib $(TARGET_LDFLAGS_OLDMAGIC) -static-libgcc
+else
+LDFLAGS_KERNEL = $(LDFLAGS_CPU) $(LDFLAGS_PLATFORM) -nostdlib $(TARGET_LDFLAGS_OLDMAGIC)
+endif
 CPPFLAGS_KERNEL = $(CPPFLAGS_CPU) $(CPPFLAGS_PLATFORM)
 CCASFLAGS_KERNEL = $(CCASFLAGS_CPU) $(CCASFLAGS_PLATFORM)
 if COND_CYGWIN
@@ -108,6 +120,8 @@
 CFLAGS_GNULIB = -Wno-undef -Wno-sign-compare -Wno-unused -Wno-unused-parameter -Wno-redundant-decls -Wno-unreachable-code -Wno-conversion -Wno-old-style-definition -Wno-unsafe-loop-optimizations
 CPPFLAGS_GNULIB = -I$(top_builddir)/grub-core/gnulib -I$(top_srcdir)/grub-core/gnulib
 
+CPPFLAGS_LIBFDT = -I$(top_srcdir)/grub-core/lib/libfdt
+
 CFLAGS_POSIX = -fno-builtin
 CPPFLAGS_POSIX = -I$(top_srcdir)/grub-core/lib/posix_wrap
 

=== modified file 'configure.ac'
--- configure.ac	2012-09-05 14:09:41 +0000
+++ configure.ac	2012-10-22 18:29:17 +0000
@@ -79,6 +79,9 @@
                 target_cpu=mips;
 		machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_CPU_MIPS=1";
 		;;
+  arm*)
+		target_cpu=arm;
+		;;
 esac
 
 # Specify the platform (such as firmware).
@@ -99,6 +102,7 @@
     mipsel-*) platform=loongson ;;
     mips-*) platform=arc ;;
     ia64-*) platform=efi ;;
+    arm-*) platform=uboot ;;
     *) AC_MSG_ERROR([unsupported CPU: "$target_cpu"]) ;;
   esac
 else
@@ -133,6 +137,7 @@
   mipsel-yeeloong) platform=loongson ;;
   mipsel-fuloong) platform=loongson ;;
   mipsel-loongson) ;;
+  arm-uboot) platform=uboot ;;
   *-emu) ;;
   *) AC_MSG_ERROR([platform "$platform" is not supported for target CPU "$target_cpu"]) ;;
 esac
@@ -164,6 +169,7 @@
   multiboot)	machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_MULTIBOOT=1" ;;
   efi)		machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_EFI=1" ;;
   ieee1275)	machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_IEEE1275=1" ;;
+  uboot)	machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_UBOOT=1" ;;
   qemu)		machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_QEMU=1" ;;
   pc)		machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_PCBIOS=1" ;;
   emu)		machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_EMU=1" ;;
@@ -172,6 +178,7 @@
   arc)	machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_ARC=1" ;;
 esac
 case "$target_cpu" in
+  arm)      	machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_ARM=1" ;;
   mips |mipsel)      	machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_MIPS=1" ;;
   sparc64)      machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_SPARC64=1" ;;
 esac
@@ -669,7 +676,8 @@
 CFLAGS="$TARGET_CFLAGS -nostdlib -Wl,--defsym,___main=0x8100 -Wno-error"
 fi
 CPPFLAGS="$TARGET_CPPFLAGS"
-if test x$target_cpu = xi386 || test x$target_cpu = xx86_64 ; then
+
+if test x$target_cpu = xi386 || test x$target_cpu = xx86_64 || test x$target_cpu = xarm ; then
 LIBS=
 else
 LIBS=-lgcc
@@ -1116,6 +1124,8 @@
 AM_CONDITIONAL([COND_mips], [test x$target_cpu = xmips -o x$target_cpu = xmipsel])
 AM_CONDITIONAL([COND_mipsel], [test x$target_cpu = xmipsel])
 AM_CONDITIONAL([COND_mipseb], [test x$target_cpu = xmips])
+AM_CONDITIONAL([COND_arm], [test x$target_cpu = xarm ])
+AM_CONDITIONAL([COND_arm_uboot], [test x$target_cpu = xarm -a x$platform = xuboot])
 
 AM_CONDITIONAL([COND_HOST_HURD], [test x$host_kernel = xhurd])
 AM_CONDITIONAL([COND_HOST_LINUX], [test x$host_kernel = xlinux])
@@ -1146,6 +1156,9 @@
 if test x${cpudir} = xmipsel; then
   cpudir=mips;
 fi
+if test x${cpudir} = xarmel; then
+  cpudir=arm;
+fi
 grub_CHECK_LINK_DIR
 if test x"$link_dir" = xyes ; then
   AC_CONFIG_LINKS([include/grub/cpu:include/grub/$cpudir])

=== modified file 'gentpl.py'
--- gentpl.py	2012-09-12 06:27:26 +0000
+++ gentpl.py	2012-10-22 18:29:17 +0000
@@ -23,7 +23,7 @@
                    "i386_multiboot", "i386_ieee1275", "x86_64_efi",
                    "mips_loongson", "sparc64_ieee1275",
                    "powerpc_ieee1275", "mips_arc", "ia64_efi",
-                   "mips_qemu_mips" ]
+                   "mips_qemu_mips", "arm_uboot" ]
 
 GROUPS = {}
 
@@ -36,10 +36,12 @@
 GROUPS["mips"]     = [ "mips_loongson", "mips_qemu_mips", "mips_arc" ]
 GROUPS["sparc64"]  = [ "sparc64_ieee1275" ]
 GROUPS["powerpc"]  = [ "powerpc_ieee1275" ]
+GROUPS["arm"]      = [ "arm_uboot" ]
 
 # Groups based on firmware
 GROUPS["efi"]  = [ "i386_efi", "x86_64_efi", "ia64_efi" ]
 GROUPS["ieee1275"]   = [ "i386_ieee1275", "sparc64_ieee1275", "powerpc_ieee1275" ]
+GROUPS["uboot"] = [ "arm_uboot" ]
 
 # emu is a special case so many core functionality isn't needed on this platform
 GROUPS["noemu"]   = GRUB_PLATFORMS[:]; GROUPS["noemu"].remove("emu")
@@ -57,10 +59,13 @@
 for i in GROUPS["videoinkernel"]: GROUPS["videomodules"].remove(i)
 
 # Similar for terminfo
-GROUPS["terminfoinkernel"] = ["mips_loongson", "mips_arc", "mips_qemu_mips" ] + GROUPS["ieee1275"];
+GROUPS["terminfoinkernel"] = ["mips_loongson", "mips_arc", "mips_qemu_mips" ] + GROUPS["ieee1275"] + GROUPS["uboot"];
 GROUPS["terminfomodule"]   = GRUB_PLATFORMS[:];
 for i in GROUPS["terminfoinkernel"]: GROUPS["terminfomodule"].remove(i)
 
+# Flattened Device Trees (FDT)
+GROUPS["fdt"] = [ "arm_uboot" ]
+
 # Miscelaneous groups schedulded to disappear in future
 GROUPS["i386_coreboot_multiboot_qemu"] = ["i386_coreboot", "i386_multiboot", "i386_qemu"]
 GROUPS["nopc"] = GRUB_PLATFORMS[:]; GROUPS["nopc"].remove("i386_pc")

=== modified file 'grub-core/Makefile.am'
--- grub-core/Makefile.am	2012-10-12 13:04:02 +0000
+++ grub-core/Makefile.am	2012-10-22 18:29:17 +0000
@@ -143,6 +143,11 @@
 KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/disk.h
 endif
 
+if COND_arm_uboot
+KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/uboot/uboot.h
+KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/uboot/disk.h
+endif
+
 if COND_mips
 KERNEL_HEADER_FILES += $(top_builddir)/include/grub/cpu/kernel.h
 endif

=== modified file 'grub-core/Makefile.core.def'
--- grub-core/Makefile.core.def	2012-09-08 07:40:24 +0000
+++ grub-core/Makefile.core.def	2012-10-22 18:29:17 +0000
@@ -67,6 +67,9 @@
   emu_cflags = '$(CFLAGS_GNULIB)';
   emu_cppflags = '$(CPPFLAGS_GNULIB)';
 
+  arm_uboot_ldflags       = '-Wl,-Ttext=0x08000000';
+  arm_uboot_stripflags    = '--strip-unneeded -K start -R .note -R .comment -R .note.gnu.gold-version';
+
   i386_pc_startup = kern/i386/pc/startup.S;
   i386_efi_startup = kern/i386/efi/startup.S;
   x86_64_efi_startup = kern/x86_64/efi/startup.S;
@@ -77,6 +80,7 @@
   mips_startup = kern/mips/startup.S;
   sparc64_ieee1275_startup = kern/sparc64/ieee1275/crt0.S;
   powerpc_ieee1275_startup = kern/powerpc/ieee1275/startup.S;
+  arm_uboot_startup = kern/arm/uboot/startup.S;
 
   common = kern/command.c;
   common = kern/corecmd.c;
@@ -199,6 +203,17 @@
   sparc64_ieee1275 = kern/sparc64/dl.c;
   sparc64_ieee1275 = kern/sparc64/ieee1275/ieee1275.c;
 
+  uboot = disk/uboot/ubootdisk.c;
+  uboot = kern/uboot/uboot.c;
+  uboot = kern/uboot/glue.c;
+  uboot = kern/uboot/crc32.c;
+  uboot = kern/uboot/init.c;
+  uboot = kern/uboot/hw.c;
+  uboot = term/uboot/console.c;
+
+  arm = kern/arm/dl.c;
+  arm = lib/arm/libgcc.S;
+
   emu = disk/host.c;
   emu = gnulib/progname.c;
   emu = gnulib/error.c;
@@ -595,6 +610,8 @@
 module = {
   name = cat;
   common = commands/cat.c;
+  arm = lib/arg.c;
+  arm = commands/extcmd.c;
 };
 
 module = {
@@ -665,6 +682,7 @@
   efi = lib/efi/halt.c;
   ieee1275 = lib/ieee1275/halt.c;
   emu = lib/emu/halt.c;
+  uboot = lib/uboot/halt.c;
 };
 
 module = {
@@ -678,6 +696,7 @@
   mips_arc = lib/mips/arc/reboot.c;
   mips_loongson = lib/mips/loongson/reboot.c;
   mips_qemu_mips = lib/mips/qemu_mips/reboot.c;
+  uboot = lib/uboot/reboot.c;
   common = commands/reboot.c;
 };
 
@@ -1300,6 +1319,7 @@
   name = datetime;
   cmos = lib/cmos_datetime.c;
   efi = lib/efi/datetime.c;
+  uboot = lib/uboot/datetime.c;
   sparc64_ieee1275 = lib/ieee1275/datetime.c;
   powerpc_ieee1275 = lib/ieee1275/datetime.c;
   sparc64_ieee1275 = lib/ieee1275/cmos.c;
@@ -1319,6 +1339,7 @@
   extra_dist = lib/powerpc/setjmp.S;
   extra_dist = lib/ia64/setjmp.S;
   extra_dist = lib/ia64/longjmp.S;
+  extra_dist = lib/arm/setjmp.S;
 };
 
 module = {
@@ -1389,6 +1410,19 @@
   enable = x86;
 };
 
+library = {
+  name = libfdtlib.a;
+  common = lib/libfdt/fdt.c;
+  common = lib/libfdt/fdt_ro.c;
+  common = lib/libfdt/fdt_rw.c;
+  common = lib/libfdt/fdt_strerror.c;
+  common = lib/libfdt/fdt_sw.c;
+  common = lib/libfdt/fdt_wip.c;
+  cppflags = '$(CPPFLAGS_LIBFDT)';
+
+  enable = arm;
+};
+
 module = {
   name = linux;
   x86 = loader/i386/linux.c;
@@ -1397,8 +1431,12 @@
   powerpc_ieee1275 = loader/powerpc/ieee1275/linux.c;
   sparc64_ieee1275 = loader/sparc64/ieee1275/linux.c;
   ia64_efi = loader/ia64/efi/linux.c;
+  arm_uboot = loader/arm/uboot/linux.c;
   common = lib/cmdline.c;
   enable = noemu;
+
+  fdt_cppflags = '$(CPPFLAGS_LIBFDT)';
+  fdt_ldadd = libfdtlib.a;
 };
 
 module = {

=== added directory 'grub-core/disk/uboot'
=== added file 'grub-core/disk/uboot/ubootdisk.c'
--- grub-core/disk/uboot/ubootdisk.c	1970-01-01 00:00:00 +0000
+++ grub-core/disk/uboot/ubootdisk.c	2012-10-22 18:29:17 +0000
@@ -0,0 +1,345 @@
+/* ubootdisk.c - disk subsystem support for U-Boot platforms */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2012  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/disk.h>
+#include <grub/err.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/partition.h>
+#include <grub/term.h>
+#include <grub/types.h>
+#include <grub/uboot/disk.h>
+#include <grub/uboot/uboot.h>
+
+static struct ubootdisk_data *fd_devices;
+static struct ubootdisk_data *hd_devices;
+static struct ubootdisk_data *cd_devices;
+
+/*
+ * grub_ubootdisk_register():
+ *   Called for each disk device enumerated as part of U-Boot initialization
+ *   code.
+ */
+grub_err_t
+grub_ubootdisk_register (struct device_info *newdev, int handle)
+{
+  struct ubootdisk_data *d;
+  enum disktype type;
+
+#define STOR_TYPE(x) ((x) & 0x0ff0)
+  switch (STOR_TYPE (newdev->type))
+    {
+    case DT_STOR_IDE:
+    case DT_STOR_SATA:
+      /* hd */
+      type = hd;
+      break;
+    case DT_STOR_MMC:
+    case DT_STOR_USB:
+      /* fd */
+      type = fd;
+      break;
+    default:
+      return GRUB_ERR_BAD_DEVICE;
+      break;
+    }
+
+  d = (struct ubootdisk_data *) grub_malloc (sizeof (struct ubootdisk_data));
+  if (!d)
+    return GRUB_ERR_OUT_OF_MEMORY;
+  d->handle = handle;
+  d->cookie = newdev->cookie;
+  d->opencount = 0;
+
+  switch (type)
+    {
+    case cd:
+      grub_dprintf ("ubootdisk", "registering cd device\n");
+      d->next = cd_devices;
+      cd_devices = d;
+
+      break;
+    case fd:
+      grub_dprintf ("ubootdisk", "registering fd device\n");
+      d->next = fd_devices;
+      fd_devices = d;
+
+      break;
+    case hd:
+      grub_dprintf ("ubootdisk", "registering hd device\n");
+      d->next = hd_devices;
+      hd_devices = d;
+
+      break;
+    default:
+      grub_free (d);
+      return GRUB_ERR_BAD_DEVICE;
+    }
+
+  return 0;
+}
+
+/*
+ * uboot_disk_iterate():
+ *   Itarator over enumerated disk devices.
+ */
+static int
+uboot_disk_iterate (int (*hook) (const char *name), grub_disk_pull_t pull)
+{
+  struct ubootdisk_data *d;
+  char buf[16];
+  int count;
+
+  switch (pull)
+    {
+    case GRUB_DISK_PULL_NONE:
+      /* "hd" - built-in mass-storage */
+      for (d = hd_devices, count = 0; d; d = d->next, count++)
+	{
+	  grub_snprintf (buf, sizeof (buf) - 1, "hd%d", count);
+	  grub_dprintf ("ubootdisk", "iterating %s\n", buf);
+	  if (hook (buf))
+	    return 1;
+	}
+      break;
+    case GRUB_DISK_PULL_REMOVABLE:
+      /* "floppy" - removable mass storage */
+      for (d = fd_devices, count = 0; d; d = d->next, count++)
+	{
+	  grub_snprintf (buf, sizeof (buf) - 1, "fd%d", count);
+	  grub_dprintf ("ubootdisk", "iterating %s\n", buf);
+	  if (hook (buf))
+	    return 1;
+	}
+
+      /* "cdrom" - removeable read-only storage */
+      for (d = cd_devices, count = 0; d; d = d->next, count++)
+	{
+	  grub_snprintf (buf, sizeof (buf) - 1, "cd%d", count);
+	  grub_dprintf ("ubootdisk", "iterating %s\n", buf);
+	  if (hook (buf))
+	    return 1;
+	}
+      break;
+    default:
+      return 0;
+    }
+
+  return 0;
+}
+
+/* Helper function for uboot_disk_open. */
+static struct ubootdisk_data *
+get_device (struct ubootdisk_data *devices, int num)
+{
+  struct ubootdisk_data *d;
+
+  for (d = devices; d && num; d = d->next, num--)
+    ;
+
+  if (num == 0)
+    return d;
+
+  return NULL;
+}
+
+/*
+ * uboot_disk_open():
+ *   Opens a disk device already enumerated.
+ */
+static grub_err_t
+uboot_disk_open (const char *name, struct grub_disk *disk)
+{
+  struct ubootdisk_data *d;
+  struct device_info *devinfo;
+  int num;
+  int retval;
+
+  grub_dprintf ("ubootdisk", "Opening '%s'\n", name);
+
+  num = grub_strtoul (name + 2, 0, 10);
+  if (grub_errno != GRUB_ERR_NONE)
+    {
+      grub_dprintf ("ubootdisk", "Opening '%s' failed, invalid number\n",
+		    name);
+      goto fail;
+    }
+
+  if (name[1] != 'd')
+    {
+      grub_dprintf ("ubootdisk", "Opening '%s' failed, invalid name\n", name);
+      goto fail;
+    }
+
+  switch (name[0])
+    {
+    case 'f':
+      d = get_device (fd_devices, num);
+      break;
+    case 'c':
+      d = get_device (cd_devices, num);
+      break;
+    case 'h':
+      d = get_device (hd_devices, num);
+      break;
+    default:
+      goto fail;
+    }
+
+  if (!d)
+    goto fail;
+
+  /*
+   * Subsystems may call open on the same device recursively - but U-Boot
+   * does not deal with this. So simply keep track of number of calls and
+   * return success if already open.
+   */
+  if (d->opencount > 0)
+    {
+      grub_dprintf ("ubootdisk", "(%s) already open\n", disk->name);
+      d->opencount++;
+      retval = 0;
+    }
+  else
+    {
+      retval = ub_dev_open (d->handle);
+      if (retval != 0)
+	goto fail;
+      d->opencount = 1;
+    }
+
+  grub_dprintf ("ubootdisk", "cookie: 0x%08x\n", (grub_addr_t) d->cookie);
+  disk->id = (grub_addr_t) d->cookie;
+
+  /* Device has previously been enumerated, so this should never fail */
+  if ((devinfo = ub_dev_get (d->handle)) == NULL)
+    goto fail;
+
+  d->block_size = devinfo->di_stor.block_size;
+  if (d->block_size == 0)
+    {
+      grub_printf ("%s: no block size!\n", __FUNCTION__);
+      return GRUB_ERR_IO;
+    }
+
+  for (disk->log_sector_size = 0;
+       (1U << disk->log_sector_size) < d->block_size;
+       disk->log_sector_size++);
+
+  grub_dprintf ("ubootdisk", "(%s) blocksize=%d, log_sector_size=%d\n",
+		disk->name, d->block_size, disk->log_sector_size);
+
+  disk->total_sectors = GRUB_DISK_SIZE_UNKNOWN;
+  disk->data = d;
+
+  return GRUB_ERR_NONE;
+
+fail:
+  return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no such device");
+}
+
+static void
+uboot_disk_close (struct grub_disk *disk)
+{
+  struct ubootdisk_data *d;
+  int retval;
+
+  d = disk->data;
+
+  /*
+   * In mirror of open function, keep track of number of calls to close and
+   * send on to U-Boot only when opencount would decrease to 0.
+   */
+  if (d->opencount > 1)
+    {
+      grub_dprintf ("ubootdisk", "Closed (%s)\n", disk->name);
+
+      d->opencount--;
+    }
+  else if (d->opencount == 1)
+    {
+      retval = ub_dev_close (d->handle);
+      d->opencount--;
+      grub_dprintf ("ubootdisk", "closed %s (%d)\n", disk->name, retval);
+    }
+  else
+    {
+      grub_dprintf ("ubootdisk", "device %s not open!\n", disk->name);
+    }
+}
+
+/*
+ * uboot_disk_read():
+ *   Called from within disk subsystem to read a sequence of blocks into the
+ *   disk cache. Maps directly on top of U-Boot API, only wrap in some error
+ *   handling.
+ */
+static grub_err_t
+uboot_disk_read (struct grub_disk *disk,
+		 grub_disk_addr_t offset, grub_size_t numblocks, char *buf)
+{
+  struct ubootdisk_data *d;
+  lbasize_t real_size;
+  int retval;
+
+  d = disk->data;
+
+  retval = ub_dev_read (d->handle, buf, numblocks, offset, &real_size);
+  grub_dprintf ("ubootdisk",
+		"retval=%d, numblocks=%d, real_size=%llu, sector=%llu\n",
+		retval, numblocks, (grub_uint64_t) real_size,
+		(grub_uint64_t) offset);
+  if (retval != 0)
+    return grub_error (GRUB_ERR_IO, "U-Boot disk read error");
+
+  return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+uboot_disk_write (struct grub_disk *disk __attribute__ ((unused)),
+		  grub_disk_addr_t sector __attribute__ ((unused)),
+		  grub_size_t size __attribute__ ((unused)),
+		  const char *buf __attribute__ ((unused)))
+{
+  grub_dprintf ("ubootdisk", "attempt to write\n");
+  return GRUB_ERR_NOT_IMPLEMENTED_YET;
+}
+
+static struct grub_disk_dev grub_ubootdisk_dev = {
+  .name = "ubootdisk",
+  .id = GRUB_DISK_DEVICE_UBOOTDISK_ID,
+  .iterate = uboot_disk_iterate,
+  .open = uboot_disk_open,
+  .close = uboot_disk_close,
+  .read = uboot_disk_read,
+  .write = uboot_disk_write,
+  .next = 0
+};
+
+void
+grub_ubootdisk_init (void)
+{
+  grub_disk_dev_register (&grub_ubootdisk_dev);
+}
+
+void
+grub_ubootdisk_fini (void)
+{
+  grub_disk_dev_unregister (&grub_ubootdisk_dev);
+}

=== added directory 'grub-core/kern/arm'
=== added file 'grub-core/kern/arm/dl.c'
--- grub-core/kern/arm/dl.c	1970-01-01 00:00:00 +0000
+++ grub-core/kern/arm/dl.c	2012-10-22 18:29:17 +0000
@@ -0,0 +1,327 @@
+/* dl.c - arch-dependent part of loadable module support */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2012  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/dl.h>
+#include <grub/elf.h>
+#include <grub/misc.h>
+#include <grub/err.h>
+#include <grub/mm.h>
+#include <grub/i18n.h>
+
+#if !defined(__thumb2__)
+#error "Relocations not implemented for A32 ("ARM") instruction set yet!"
+#endif
+
+#ifdef DL_DEBUG
+static const char *symstrtab;
+
+/*
+ * This is a bit of a hack, setting the symstrtab pointer to the last STRTAB
+ * section in the module (which is where symbol names are in the objects I've
+ * inspected manually). 
+ */
+static void
+set_symstrtab (Elf_Ehdr * e)
+{
+  int i;
+  Elf_Shdr *s;
+
+  symstrtab = NULL;
+
+  for (i = 0, s = (Elf_Shdr *) ((grub_uint32_t) e + e->e_shoff);
+       i < e->e_shnum;
+       i++, s = (Elf_Shdr *) ((grub_uint32_t) s + e->e_shentsize))
+    if (s->sh_type == SHT_STRTAB)
+      symstrtab = (void *) ((grub_addr_t) e + s->sh_offset);
+}
+
+static const char *
+get_symbolname (Elf_Sym * sym)
+{
+  const char *symbolname = symstrtab + sym->st_name;
+
+  return (*symbolname ? symbolname : NULL);
+}
+#endif /* DL_DEBUG */
+
+
+/*
+ * Simple relocation of 32-bit value (in literal pool)
+ */
+static grub_err_t
+reloc_abs32 (Elf_Word * addr, Elf_Sym * sym)
+{
+#ifdef DL_DEBUG
+  grub_printf ("%s: ABS32 @ 0x%08x -> %s @ 0x%08x\n",
+	       __FUNCTION__, (grub_addr_t) addr,
+	       get_symbolname (sym), sym->st_value);
+#endif
+
+  *addr += sym->st_value;
+
+  return GRUB_ERR_NONE;
+}
+
+/*
+ * R_ARM_THM_CALL/THM_JUMP24
+ *
+ * Deals with relocation of Thumb (T32) instruction set relative branches
+ * B.W, BL and BLX
+ *
+ * 32-bit Thumb instructions can be 16-bit aligned, and are fetched
+ * little-endian, requiring some additional fiddling.
+ */
+static grub_err_t
+reloc_thm_call (grub_uint16_t * addr, Elf_Sym * sym)
+{
+  grub_int32_t offset, offset_low, offset_high;
+  grub_uint32_t sign, j1, j2, is_blx;
+  grub_uint32_t insword, insmask;
+
+  /* Extract instruction word in alignment-safe manner */
+  insword = (*addr << 16) | *(addr + 1);
+  insmask = 0xf800d000;
+
+  /* B.W/BL or BLX? Affects range and expected target state */
+  if (((insword >> 12) & 0xd) == 0xc)
+    is_blx = 1;
+  else
+    is_blx = 0;
+
+  offset_low = -16777216;
+  offset_high = is_blx ? 16777212 : 16777214;
+
+#ifdef DL_DEBUG
+  grub_printf ("%s: %s @ 0x%08x -> %s @ 0x%08x\n",
+	       __FUNCTION__, is_blx ? "BLX" : "B(L)",
+	       (grub_addr_t) addr, get_symbolname (sym), sym->st_value);
+#endif
+
+  /* Extract bitfields from instruction words */
+  sign = (insword >> 26) & 1;
+  j1 = (insword >> 13) & 1;
+  j2 = (insword >> 11) & 1;
+  offset = (sign << 24) | ((~(j1 ^ sign) & 1) << 23) |
+    ((~(j2 ^ sign) & 1) << 22) |
+    ((insword & 0x03ff0000) >> 4) | ((insword & 0x000007ff) << 1);
+
+  /* Sign adjust and calculate offset */
+  if (offset & 0x01000000)
+    offset -= 0x02000000;
+  offset += sym->st_value - (grub_uint32_t) addr;
+
+  if ((offset < offset_low) || (offset > offset_high))
+    return grub_error (GRUB_ERR_OUT_OF_RANGE,
+		       N_("offset %d (0x%08x) is out of range"),
+		       offset, offset);
+
+  /* If BLX, target symbol must be ARM (target address LSB == 0) */
+  if (is_blx && (offset & 1))
+    return grub_error
+      (GRUB_ERR_BUG, N_("Relocation targeting wrong execution state"));
+
+  /* Reassemble instruction word */
+  sign = (offset >> 24) & 1;
+  j1 = sign ^ (~(offset >> 23) & 1);
+  j2 = sign ^ (~(offset >> 22) & 1);
+  insword = (insword & insmask) |
+    (sign << 26) |
+    (((offset >> 12) & 0x03ff) << 16) |
+    (j1 << 13) | (j2 << 11) | ((offset >> 1) & 0x07ff);
+
+  /* Write instruction word back in alignment-safe manner */
+  *(grub_uint16_t *) addr = (insword >> 16) & 0xffff;
+  *(grub_uint16_t *) (addr + 1) = insword & 0xffff;
+
+  return GRUB_ERR_NONE;
+}
+
+/*
+ * find_segment(): finds a module segment matching sh_info
+ */
+static grub_dl_segment_t
+find_segment (grub_dl_segment_t seg, Elf32_Word sh_info)
+{
+  for (; seg; seg = seg->next)
+    if (seg->section == sh_info)
+      return seg;
+
+  return NULL;
+}
+
+/*
+ * do_relocations():
+ *   Iterate over all relocations in section, calling appropriate functions
+ *   for patching.
+ */
+static grub_err_t
+do_relocations (Elf_Shdr * relhdr, Elf_Ehdr * e, grub_dl_t mod)
+{
+  grub_dl_segment_t seg;
+  Elf_Rel *rel;
+  Elf_Sym *sym;
+  int i, entnum;
+
+  entnum = relhdr->sh_size / sizeof (Elf_Rel);
+
+  /* Find the target segment for this relocation section. */
+  seg = find_segment (mod->segment, relhdr->sh_info);
+  if (!seg)
+    return grub_error (GRUB_ERR_EOF, N_("relocation segment not found"));
+
+  rel = (Elf_Rel *) ((grub_addr_t) e + relhdr->sh_offset);
+
+  /* Step through all relocations */
+  for (i = 0, sym = mod->symtab; i < entnum; i++)
+    {
+      Elf_Word *addr;
+      int relsym, reltype;
+      grub_err_t retval;
+
+      if (seg->size < rel[i].r_offset)
+	return grub_error (GRUB_ERR_BAD_MODULE,
+			   "reloc offset is out of the segment");
+      relsym = ELF_R_SYM (rel[i].r_info);
+      reltype = ELF_R_TYPE (rel[i].r_info);
+      addr = (Elf_Word *) ((grub_addr_t) seg->addr + rel[i].r_offset);
+
+      switch (reltype)
+	{
+	case R_ARM_ABS32:
+	  {
+	    /* Data will be naturally aligned */
+	    retval = reloc_abs32 (addr, &sym[relsym]);
+	    if (retval != GRUB_ERR_NONE)
+	      return retval;
+	  }
+	  break;
+	case R_ARM_THM_CALL:
+	case R_ARM_THM_JUMP24:
+	  {
+	    /* Thumb instructions can be 16-bit aligned */
+	    retval = reloc_thm_call ((grub_uint16_t *) addr, &sym[relsym]);
+	    if (retval != GRUB_ERR_NONE)
+	      return retval;
+	  }
+	  break;
+	default:
+	  return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
+			     N_("relocation 0x%x is not implemented yet"),
+			     reltype);
+	}
+    }
+
+  return GRUB_ERR_NONE;
+}
+
+
+/*
+ * Check if EHDR is a valid ELF header.
+ */
+grub_err_t
+grub_arch_dl_check_header (void *ehdr)
+{
+  Elf_Ehdr *e = ehdr;
+
+  /* Check the magic numbers.  */
+  if (e->e_ident[EI_CLASS] != ELFCLASS32
+      || e->e_ident[EI_DATA] != ELFDATA2LSB || e->e_machine != EM_ARM)
+    return grub_error (GRUB_ERR_BAD_OS,
+		       N_("invalid arch-dependent ELF magic"));
+
+  return GRUB_ERR_NONE;
+}
+
+/*
+ * Verify that provided ELF header contains reference to a symbol table
+ */
+static int
+has_symtab (Elf_Ehdr * e)
+{
+  int i;
+  Elf_Shdr *s;
+
+  for (i = 0, s = (Elf_Shdr *) ((grub_uint32_t) e + e->e_shoff);
+       i < e->e_shnum;
+       i++, s = (Elf_Shdr *) ((grub_uint32_t) s + e->e_shentsize))
+    if (s->sh_type == SHT_SYMTAB)
+      return 1;
+
+  return 0;
+}
+
+/*
+ * grub_arch_dl_relocate_symbols():
+ *   Only externally visible function in this file.
+ *   Locates the relocations section of the ELF object, and calls
+ *   do_relocations() to deal with it.
+ */
+grub_err_t
+grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
+{
+  Elf_Ehdr *e = ehdr;
+  Elf_Shdr *s;
+  unsigned i;
+
+  if (!has_symtab (e))
+    return grub_error (GRUB_ERR_BAD_MODULE, N_("no symbol table"));
+
+#ifdef DL_DEBUG
+  set_symstrtab (e);
+#endif
+
+#define FIRST_SHDR(x) ((Elf_Shdr *) ((grub_addr_t)(x) + (x)->e_shoff))
+#define NEXT_SHDR(x, y) ((Elf_Shdr *) ((grub_addr_t)(y) + (x)->e_shentsize))
+
+  for (i = 0, s = FIRST_SHDR (e); i < e->e_shnum; i++, s = NEXT_SHDR (e, s))
+    {
+      grub_err_t ret;
+
+      switch (s->sh_type)
+	{
+	case SHT_REL:
+	  {
+	    /* Relocations, no addends */
+	    ret = do_relocations (s, e, mod);
+	    if (ret != GRUB_ERR_NONE)
+	      return ret;
+	  }
+	  break;
+	case SHT_NULL:
+	case SHT_PROGBITS:
+	case SHT_SYMTAB:
+	case SHT_STRTAB:
+	case SHT_NOBITS:
+	case SHT_ARM_ATTRIBUTES:
+	  break;
+	case SHT_RELA:
+	default:
+	  {
+	    grub_printf ("unhandled section_type: %d (0x%08x)\n",
+			 s->sh_type, s->sh_type);
+	    return GRUB_ERR_NOT_IMPLEMENTED_YET;
+	  };
+	}
+    }
+
+#undef FIRST_SHDR
+#undef NEXT_SHDR
+
+  return GRUB_ERR_NONE;
+}

=== added directory 'grub-core/kern/arm/uboot'
=== added file 'grub-core/kern/arm/uboot/startup.S'
--- grub-core/kern/arm/uboot/startup.S	1970-01-01 00:00:00 +0000
+++ grub-core/kern/arm/uboot/startup.S	2012-10-22 18:29:17 +0000
@@ -0,0 +1,173 @@
+/*
+ * (C) Copyright 2012 ARM ltd.
+ *
+ * Based on U-boot example written by Rafal Jaworowski <raj@semihalf.com>
+ *
+ * This program 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 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+#include <grub/offsets.h>
+#include <grub/symbol.h>
+#include <grub/machine/kernel.h>
+
+/*
+ * GRUB is called from U-Boot as a Linux Kernel type image, which
+ * means among other things that it always enters in ARM state.
+ *
+ *
+ * Overview of GRUB image layout:
+ *
+ * _start:
+ *              Entry point (1 ARM branch instruction, to "codestart")
+ * grub_total_module_size:
+ *              Data field: Size of included module blob
+ *              (when generated by grub-mkimage)
+ * codestart:
+ *              Remainder of statically-linked executable code and data.
+ * __bss_start:
+ *              Start of included module blob.
+ *              Also where global/static variables are located.
+ * _end:
+ *              End of bss region (but not necessarily module blob).
+ * <overflow>:
+ *              Any part of the module blob that extends beyond _end.
+ * <modules>:
+ *              Loadable modules, post relocation.
+ * <stack>:     
+ * <heap>:
+ */
+	
+	.text
+	.arm
+FUNCTION(_start)
+.extern __bss_start
+.extern _end
+.extern uboot_machine_type
+.extern uboot_boot_data
+	b	codestart
+	
+	@ Size of final image integrated module blob - set by grub-mkimage
+	. = _start + GRUB_KERNEL_MACHINE_TOTAL_MODULE_SIZE
+VARIABLE(grub_total_module_size)
+	.long 	0
+
+FUNCTION(codestart)
+	@ Store context: Machine ID, atags/dtb, ...
+	@ U-Boot API signature is stored on the U-Boot heap
+	@ Stack pointer used as start address for signature probing
+	mov	r12, sp
+	ldr	sp, =entry_state
+	push	{r4-r12,lr}	@ store U-Boot context (sp in r12)
+
+	@ Put kernel parameters aside until we can store them (further down)
+	mov	r4, r1		@ machine type
+	mov	r5, r2		@ boot data
+
+	@ modules have been stored as a blob in BSS,
+	@ they need to be manually relocated
+	@ If everything fits within BSS, good
+	@ If not, relocate to __bss_start + grub_total_module_size
+	ldr	r0, =__bss_start		@ src
+	ldr	r1, =_end			@ dst = End of BSS
+	ldr	r2, grub_total_module_size	@ blob size
+	add	r3, r0, r2			@ blob end
+	cmp	r1, r3				@ _end < blob end?
+	movlt	r1, r3				@ dst = blob end + blob size
+	mov	r2, r1				@ end = dst
+	
+1:	ldr	r3, [r0], #4 			@ r3 = *src++ 
+	str	r3, [r1], #4			@ *dst++ = r3 
+	cmp	r0, r2				@ src == end ?
+	blt	1b
+	
+	@ Set up a new stack, beyond the end of copied modules.
+	ldr	r3, =GRUB_KERNEL_MACHINE_STACK_SIZE
+	add	r3, r1, r3	@ Place stack beyond end of modules
+	and	sp, r3, #~0x7	@ Ensure 8-byte alignment
+
+	@ Since we _are_ the C run-time, we need to manually zero the BSS
+	@ region before continuing
+	ldr	r0, =__bss_start
+	ldr	r1, =_end
+	mov	r2, #0
+1:	str	r2, [r0], #4
+	cmp	r0, r1
+	bne	1b
+
+	@ Global variables now accessible - store kernel parameters in memory
+	ldr     r12, =uboot_machine_type
+	str     r4, [r12]
+	ldr     r12, =uboot_boot_data
+	str     r5, [r12]
+	
+	b	grub_main
+
+	/*
+	 * uboot_syscall():
+	 *   This function is effectively a veneer, so it cannot
+	 *   modify the stack or corrupt any registers other than
+	 *   r12 (ip). Furthermore it needs to restore r8 for
+	 *   U-Boot (Global Data Pointer) and preserve it for Grub.
+	 */
+FUNCTION(uboot_syscall)
+	ldr	ip, =transition_space
+	stm	ip, {r8, lr}
+	ldr	ip, =gd_backup
+	ldr	r8, [ip]
+	ldr	ip, =uboot_syscall_ptr
+	mov	lr, pc
+	ldr	pc, [ip]
+	ldr	ip, =gd_backup
+	str	r8, [ip]
+	ldr	ip, =transition_space
+	ldm	ip, {r8, lr}
+	bx	lr
+	
+FUNCTION(uboot_return)
+	ldr	sp, =entry_state_end
+	pop	{r4-r12, lr}
+	mov	sp, r12
+	bx	lr
+
+	
+	.data
+	.align	3	@ 8-byte alignment for stack
+@ U-boot context stack space
+entry_state_end:	
+	.long	0	@ r4
+	.long	0	@ r5
+	.long	0	@ r6
+	.long	0	@ r7
+gd_backup:	
+	.long	0	@ r8 - U-Boot global data pointer
+	.long	0	@ r9
+	.long	0	@ r10
+	.long	0	@ r11
+VARIABLE(uboot_search_hint)@ U-Boot stack pointer - 
+	.long	0	@ also API signature address hint.
+	.long	0	@ lr
+entry_state:		@ backup for U-Boot context
+
+@ GRUB context stack space
+transition_space:	
+	.long	0	@ r8
+	.long	0	@ lr
+
+VARIABLE(uboot_syscall_ptr)
+	.long	0	@
+
+	.end

=== modified file 'grub-core/kern/main.c'
--- grub-core/kern/main.c	2012-06-22 09:51:48 +0000
+++ grub-core/kern/main.c	2012-10-22 18:29:17 +0000
@@ -30,8 +30,10 @@
 #include <grub/reader.h>
 #include <grub/parser.h>
 
-/* This is actualy platform-independant but used only on loongson and sparc.  */
-#if defined (GRUB_MACHINE_MIPS_LOONGSON) || defined (GRUB_MACHINE_MIPS_QEMU_MIPS) || defined (GRUB_MACHINE_SPARC64)
+/* This is actualy platform-independant but used only on some platforms.  */
+#if defined (GRUB_MACHINE_MIPS_LOONGSON) || \
+  defined (GRUB_MACHINE_MIPS_QEMU_MIPS) || defined (GRUB_MACHINE_SPARC64) || \
+  defined (GRUB_MACHINE_ARM)
 grub_addr_t
 grub_modules_get_end (void)
 {

=== added directory 'grub-core/kern/uboot'
=== added file 'grub-core/kern/uboot/glue.c'
--- grub-core/kern/uboot/glue.c	1970-01-01 00:00:00 +0000
+++ grub-core/kern/uboot/glue.c	2012-10-22 18:31:19 +0000
@@ -0,0 +1,475 @@
+/*
+ * (C) Copyright 2007-2008 Semihalf, Rafal Jaworowski <raj@semihalf.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program 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 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+#include <grub/types.h>
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/uboot/api_public.h>
+#include <grub/uboot/glue.h>
+
+extern int uboot_syscall (int, int *, ...);
+#define syscall(x, y, ...) uboot_syscall(x, y, __VA_ARGS__)
+
+typedef grub_uint32_t uint32_t;
+
+static int
+valid_sig (struct api_signature *sig)
+{
+  uint32_t checksum;
+  struct api_signature s;
+
+  if (sig == NULL)
+    return 0;
+  /*
+   * Clear the checksum field (in the local copy) so as to calculate the
+   * CRC with the same initial contents as at the time when the sig was
+   * produced
+   */
+  s = *sig;
+  s.checksum = 0;
+
+#if 0
+  checksum = crc32 (&s, sizeof (struct api_signature));
+#else
+  checksum = sig->checksum;
+#endif
+
+  if (checksum != sig->checksum)
+    return 0;
+
+  return 1;
+}
+
+/*
+ * Searches for the U-Boot API signature
+ *
+ * returns 1/0 depending on found/not found result
+ */
+int
+api_search_sig (struct api_signature **sig)
+{
+  unsigned char *sp;
+  uint32_t search_start = 0;
+  uint32_t search_end = 0;
+
+  if (sig == NULL)
+    return 0;
+
+  if (uboot_search_hint == 0)
+    uboot_search_hint = 255 * 1024 * 1024;
+
+  /* Extended search range to work around Trim Slice U-Boot issue */
+  search_start = (uboot_search_hint & ~0x000fffff) - 0x00500000;
+  search_end = search_start + API_SEARCH_LEN - API_SIG_MAGLEN;
+  search_end += 0x00500000;
+
+  sp = (unsigned char *) search_start;
+  while ((sp + API_SIG_MAGLEN) < (unsigned char *) search_end)
+    {
+      if (!memcmp (sp, API_SIG_MAGIC, API_SIG_MAGLEN))
+	{
+	  *sig = (struct api_signature *) (uint32_t) sp;
+	  if (valid_sig (*sig))
+	    return 1;
+	}
+      sp += API_SIG_MAGLEN;
+    }
+
+  *sig = NULL;
+  return 0;
+}
+
+/****************************************
+ *
+ * console
+ *
+ ****************************************/
+
+int
+ub_getc (void)
+{
+  int c;
+
+  if (!syscall (API_GETC, NULL, (uint32_t) & c))
+    return -1;
+
+  return c;
+}
+
+int
+ub_tstc (void)
+{
+  int t;
+
+  if (!syscall (API_TSTC, NULL, (uint32_t) & t))
+    return -1;
+
+  return t;
+}
+
+void
+ub_putc (char c)
+{
+  syscall (API_PUTC, NULL, (uint32_t) & c);
+}
+
+void
+ub_puts (const char *s)
+{
+  syscall (API_PUTS, NULL, (uint32_t) s);
+}
+
+/****************************************
+ *
+ * system
+ *
+ ****************************************/
+
+void
+ub_reset (void)
+{
+  syscall (API_RESET, NULL, 0);
+}
+
+static struct mem_region mr[UB_MAX_MR];
+static struct sys_info si;
+
+struct sys_info *
+ub_get_sys_info (void)
+{
+  int err = 0;
+
+  memset (&si, 0, sizeof (struct sys_info));
+  si.mr = mr;
+  si.mr_no = UB_MAX_MR;
+  memset (&mr, 0, sizeof (mr));
+
+  if (!syscall (API_GET_SYS_INFO, &err, (uint32_t) & si))
+    return NULL;
+
+  return ((err) ? NULL : &si);
+}
+
+/****************************************
+ *
+ * timing
+ *
+ ****************************************/
+
+void
+ub_udelay (unsigned long usec)
+{
+  syscall (API_UDELAY, NULL, &usec);
+}
+
+unsigned long
+ub_get_timer (unsigned long base)
+{
+  unsigned long cur;
+
+  if (!syscall (API_GET_TIMER, NULL, &cur, &base))
+    return 0;
+
+  return cur;
+}
+
+
+/****************************************************************************
+ *
+ * devices
+ *
+ * Devices are identified by handles: numbers 0, 1, 2, ..., UB_MAX_DEV-1
+ *
+ ***************************************************************************/
+
+static struct device_info devices[UB_MAX_DEV];
+
+struct device_info *
+ub_dev_get (int i)
+{
+  return ((i < 0 || i >= UB_MAX_DEV) ? NULL : &devices[i]);
+}
+
+/*
+ * Enumerates the devices: fills out device_info elements in the devices[]
+ * array.
+ *
+ * returns:		number of devices found
+ */
+int
+ub_dev_enum (void)
+{
+  struct device_info *di;
+  int n = 0;
+
+  memset (&devices, 0, sizeof (struct device_info) * UB_MAX_DEV);
+  di = &devices[0];
+
+  if (!syscall (API_DEV_ENUM, NULL, di))
+    return 0;
+
+  while (di->cookie != NULL)
+    {
+
+      if (++n >= UB_MAX_DEV)
+	break;
+
+      /* take another device_info */
+      di++;
+
+      /* pass on the previous cookie */
+      di->cookie = devices[n - 1].cookie;
+
+      if (!syscall (API_DEV_ENUM, NULL, di))
+	return 0;
+    }
+
+  return n;
+}
+
+/*
+ * handle:	0-based id of the device
+ *
+ * returns:	0 when OK, err otherwise
+ */
+int
+ub_dev_open (int handle)
+{
+  struct device_info *di;
+  int err = 0;
+
+  if (handle < 0 || handle >= UB_MAX_DEV)
+    return API_EINVAL;
+
+  di = &devices[handle];
+
+  if (!syscall (API_DEV_OPEN, &err, di))
+    return -1;
+
+  return err;
+}
+
+int
+ub_dev_close (int handle)
+{
+  struct device_info *di;
+
+  if (handle < 0 || handle >= UB_MAX_DEV)
+    return API_EINVAL;
+
+  di = &devices[handle];
+  if (!syscall (API_DEV_CLOSE, NULL, di))
+    return -1;
+
+  return 0;
+}
+
+/*
+ *
+ * Validates device for read/write, it has to:
+ *
+ * - have sane handle
+ * - be opened
+ *
+ * returns:	0/1 accordingly
+ */
+static int
+dev_valid (int handle)
+{
+  if (handle < 0 || handle >= UB_MAX_DEV)
+    return 0;
+
+  if (devices[handle].state != DEV_STA_OPEN)
+    return 0;
+
+  return 1;
+}
+
+static int
+dev_stor_valid (int handle)
+{
+  if (!dev_valid (handle))
+    return 0;
+
+  if (!(devices[handle].type & DEV_TYP_STOR))
+    return 0;
+
+  return 1;
+}
+
+int
+ub_dev_read (int handle, void *buf, lbasize_t len, lbastart_t start,
+	     lbasize_t * rlen)
+{
+  struct device_info *di;
+  lbasize_t act_len;
+  int err = 0;
+
+  if (!dev_stor_valid (handle))
+    return API_ENODEV;
+
+  di = &devices[handle];
+  if (!syscall (API_DEV_READ, &err, di, buf, &len, &start, &act_len))
+    return API_ESYSC;
+
+  if (!err && rlen)
+    *rlen = act_len;
+
+  return err;
+}
+
+static int
+dev_net_valid (int handle)
+{
+  if (!dev_valid (handle))
+    return 0;
+
+  if (devices[handle].type != DEV_TYP_NET)
+    return 0;
+
+  return 1;
+}
+
+int
+ub_dev_recv (int handle, void *buf, int len, int *rlen)
+{
+  struct device_info *di;
+  int err = 0, act_len;
+
+  if (!dev_net_valid (handle))
+    return API_ENODEV;
+
+  di = &devices[handle];
+  if (!syscall (API_DEV_READ, &err, di, buf, &len, &act_len))
+    return API_ESYSC;
+
+  if (!err && rlen)
+    *rlen = act_len;
+
+  return (err);
+}
+
+int
+ub_dev_send (int handle, void *buf, int len)
+{
+  struct device_info *di;
+  int err = 0;
+
+  if (!dev_net_valid (handle))
+    return API_ENODEV;
+
+  di = &devices[handle];
+  if (!syscall (API_DEV_WRITE, &err, di, buf, &len))
+    return API_ESYSC;
+
+  return err;
+}
+
+/****************************************
+ *
+ * env vars
+ *
+ ****************************************/
+
+char *
+ub_env_get (const char *name)
+{
+  char *value;
+
+  if (!syscall (API_ENV_GET, NULL, (uint32_t) name, (uint32_t) & value))
+    return NULL;
+
+  return value;
+}
+
+void
+ub_env_set (const char *name, char *value)
+{
+  syscall (API_ENV_SET, NULL, (uint32_t) name, (uint32_t) value);
+}
+
+static char env_name[256];
+
+const char *
+ub_env_enum (const char *last)
+{
+  const char *env, *str;
+  int i;
+
+  env = NULL;
+
+  /*
+   * It's OK to pass only the name piece as last (and not the whole
+   * 'name=val' string), since the API_ENUM_ENV call uses envmatch()
+   * internally, which handles such case
+   */
+  if (!syscall (API_ENV_ENUM, NULL, (uint32_t) last, (uint32_t) & env))
+    return NULL;
+
+  if (!env)
+    /* no more env. variables to enumerate */
+    return NULL;
+
+  /* next enumerated env var */
+  memset (env_name, 0, 256);
+  for (i = 0, str = env; *str != '=' && *str != '\0';)
+    env_name[i++] = *str++;
+
+  env_name[i] = '\0';
+
+  return env_name;
+}
+
+/****************************************
+ *
+ * display
+ *
+ ****************************************/
+
+int
+ub_display_get_info (int type, struct display_info *di)
+{
+  int err = 0;
+
+  if (!syscall (API_DISPLAY_GET_INFO, &err, (uint32_t) type, (uint32_t) di))
+    return API_ESYSC;
+
+  return err;
+}
+
+int
+ub_display_draw_bitmap (ulong bitmap, int x, int y)
+{
+  int err = 0;
+
+  if (!syscall (API_DISPLAY_DRAW_BITMAP, &err, bitmap, x, y))
+    return API_ESYSC;
+
+  return err;
+}
+
+void
+ub_display_clear (void)
+{
+  syscall (API_DISPLAY_CLEAR, NULL, 0);
+}

=== added file 'grub-core/kern/uboot/hw.c'
--- grub-core/kern/uboot/hw.c	1970-01-01 00:00:00 +0000
+++ grub-core/kern/uboot/hw.c	2012-10-22 18:29:17 +0000
@@ -0,0 +1,114 @@
+/* hw.c - U-Boot hardware discovery */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2012  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/kernel.h>
+#include <grub/memory.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/offsets.h>
+#include <grub/machine/kernel.h>
+#include <grub/uboot/disk.h>
+#include <grub/uboot/uboot.h>
+
+grub_addr_t start_of_ram;
+
+/* The minimal heap size we can live with. */
+#define HEAP_MIN_SIZE (unsigned long) (2 * 1024 * 1024)
+
+/*
+ * grub_uboot_probe_memory():
+ *   Queries U-Boot for available memory regions.
+ *
+ *   Sets up heap near the image in memory and sets up "start_of_ram".
+ */
+void
+grub_uboot_mm_init (void)
+{
+  struct sys_info *si = ub_get_sys_info ();
+
+  grub_mm_init_region ((void *) (grub_modules_get_end ()
+				 + GRUB_KERNEL_MACHINE_STACK_SIZE),
+		       HEAP_MIN_SIZE);
+
+  if (si && (si->mr_no != 0))
+    {
+      int i;
+      start_of_ram = GRUB_UINT_MAX;
+
+      for (i = 0; i < si->mr_no; i++)
+	if ((si->mr[i].flags & MR_ATTR_MASK) == MR_ATTR_DRAM)
+	  if (si->mr[i].start < start_of_ram)
+	    start_of_ram = si->mr[i].start;
+    }
+}
+
+/*
+ * grub_uboot_probe_hardware():
+ *   
+ */
+grub_err_t
+grub_uboot_probe_hardware (void)
+{
+  int devcount, i;
+
+  devcount = ub_dev_enum ();
+  grub_dprintf ("init", "%d devices found\n", devcount);
+
+  for (i = 0; i < devcount; i++)
+    {
+      struct device_info *devinfo = ub_dev_get (i);
+
+      grub_dprintf ("init", "device handle: %d\n", i);
+      grub_dprintf ("init", "  cookie\t= 0x%08x\n",
+		    (grub_uint32_t) devinfo->cookie);
+
+      if (devinfo->type & DEV_TYP_STOR)
+	{
+	  grub_dprintf ("init", "  type\t\t= DISK\n");
+	  grub_ubootdisk_register (devinfo, i);
+	}
+      else if (devinfo->type & DEV_TYP_NET)
+	{
+	  grub_dprintf ("init", "  type\t\t= NET (not supported yet)\n");
+	}
+      else
+	{
+	  grub_dprintf ("init", "%s: unknown device type", __FUNCTION__);
+	}
+    }
+
+  return GRUB_ERR_NONE;
+}
+
+grub_err_t
+grub_machine_mmap_iterate (grub_memory_hook_t hook)
+{
+  int i;
+  struct sys_info *si = ub_get_sys_info ();
+
+  if (!si || (si->mr_no < 1))
+    return GRUB_ERR_BUG;
+
+  /* Iterate and call `hook'.  */
+  for (i = 0; i < si->mr_no; i++)
+    if ((si->mr[i].flags & MR_ATTR_MASK) == MR_ATTR_DRAM)
+      hook (si->mr[i].start, si->mr[i].size, GRUB_MEMORY_AVAILABLE);
+
+  return GRUB_ERR_NONE;
+}

=== added file 'grub-core/kern/uboot/init.c'
--- grub-core/kern/uboot/init.c	1970-01-01 00:00:00 +0000
+++ grub-core/kern/uboot/init.c	2012-10-22 18:29:17 +0000
@@ -0,0 +1,165 @@
+/* init.c - generic U-Boot initialization and finalization */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2012  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include <grub/env.h>
+#include <grub/kernel.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/term.h>
+#include <grub/time.h>
+#include <grub/machine/kernel.h>
+#include <grub/uboot/console.h>
+#include <grub/uboot/disk.h>
+#include <grub/uboot/uboot.h>
+
+extern char __bss_start[];
+extern char _end[];
+extern grub_size_t grub_total_module_size;
+extern int (*uboot_syscall_ptr) (int, int *, ...);
+
+grub_addr_t grub_modbase;
+
+grub_uint32_t uboot_machine_type;
+grub_addr_t uboot_boot_data;
+
+static unsigned long timer_start;
+
+grub_uint32_t
+uboot_get_machine_type (void)
+{
+  return uboot_machine_type;
+}
+
+grub_addr_t
+uboot_get_boot_data (void)
+{
+  return uboot_boot_data;
+}
+
+static grub_uint64_t
+uboot_timer_ms (void)
+{
+  return (grub_uint64_t) ub_get_timer (timer_start);
+}
+
+void
+grub_machine_init (void)
+{
+  struct api_signature *sig;
+  grub_addr_t end;
+
+  /* First of all - establish connection with U-Boot */
+  if (!api_search_sig (&sig))
+    {
+      /* Don't even have a console to log errors to... */
+      grub_exit ();
+    }
+
+  uboot_syscall_ptr = sig->syscall;
+
+  if (sig->version > API_SIG_VERSION)
+    {
+      /* Try to print an error message */
+      ub_puts ("invalid U-Boot API version\n");
+    }
+
+  /*
+   * Modules were relocated to _end, or __bss_start + grub_total_module_size,
+   * whichever greater.
+   */
+  end = (grub_addr_t) __bss_start + grub_total_module_size;
+  if (end < (grub_addr_t) _end)
+    end = (grub_addr_t) _end;
+  grub_modbase = end;
+
+  /* Initialize the console so that GRUB can display messages.  */
+  grub_console_init_early ();
+
+  grub_dprintf ("init", "__bss_start: 0x%08x, end: 0x%08x, _end: 0x%08x\n",
+		(grub_addr_t) __bss_start,
+		(grub_addr_t) __bss_start + grub_total_module_size,
+		(grub_addr_t) _end);
+  grub_dprintf ("init", "grub_modbase: %p\n", (void *) grub_modbase);
+  grub_dprintf ("init", "grub_modules_get_end(): %p\n",
+		(void *) grub_modules_get_end ());
+
+  /* Enumerate memory and initialize the memory management system. */
+  grub_uboot_mm_init ();
+
+  /* Initialise full terminfo support */
+  grub_console_init_lately ();
+
+  /* Enumerate uboot devices */
+  grub_uboot_probe_hardware ();
+
+  /* Initialise timer */
+  timer_start = ub_get_timer (0);
+  grub_install_get_time_ms (uboot_timer_ms);
+
+  /* Initialize  */
+  grub_ubootdisk_init ();
+}
+
+
+void
+grub_machine_fini (void)
+{
+}
+
+/*
+ * grub_machine_get_bootlocation():
+ *   Called from kern/main.c, which expects a device name (minus parentheses)
+ *   and a filesystem path back, if any are known.
+ *   Any returned values must be pointers to dynamically allocated strings.
+ */
+void
+grub_machine_get_bootlocation (char **device, char **path)
+{
+  char *tmp;
+
+  tmp = ub_env_get ("grub_bootdev");
+  if (tmp)
+    {
+      *device = grub_malloc (grub_strlen (tmp) + 1);
+      if (*device == NULL)
+	return;
+      grub_strncpy (*device, tmp, grub_strlen (tmp) + 1);
+    }
+  else
+    *device = NULL;
+
+  tmp = ub_env_get ("grub_bootpath");
+  if (tmp)
+    {
+      *path = grub_malloc (grub_strlen (tmp) + 1);
+      if (*path == NULL)
+	return;
+      grub_strncpy (*path, tmp, grub_strlen (tmp) + 1);
+    }
+  else
+    *path = NULL;
+}
+
+void
+grub_uboot_fini (void)
+{
+  grub_ubootdisk_fini ();
+  grub_console_fini ();
+}

=== added file 'grub-core/kern/uboot/uboot.c'
--- grub-core/kern/uboot/uboot.c	1970-01-01 00:00:00 +0000
+++ grub-core/kern/uboot/uboot.c	2012-10-22 18:29:17 +0000
@@ -0,0 +1,27 @@
+/* uboot.c - generic U-Boot support */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2012  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/misc.h>
+#include <grub/uboot/uboot.h>
+
+void
+grub_exit (void)
+{
+  uboot_return (0);
+}

=== added directory 'grub-core/lib/arm'
=== added file 'grub-core/lib/arm/libgcc.S'
--- grub-core/lib/arm/libgcc.S	1970-01-01 00:00:00 +0000
+++ grub-core/lib/arm/libgcc.S	2012-10-22 18:29:17 +0000
@@ -0,0 +1,299 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2012  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/symbol.h>
+#include <grub/dl.h>
+
+	.file	"libgcc.S"
+	.syntax	unified
+#if !defined (__thumb2__)
+	.arm
+#define ARM(x...)	x
+#define THUMB(x...)
+#else
+	.thumb
+#define THUMB(x...)	x
+#define ARM(x...)
+#endif
+
+	
+#ifdef __ARMEB__
+#define al r1
+#define ah r0
+#else
+#define al r0
+#define ah r1
+#endif
+
+GRUB_MOD_LICENSE "GPLv3+"
+
+/*
+ *  helper functions - __aeabi* with macros imported from Linux kernel:
+ *    linux/arch/arm/lib/lib1funcs.S
+ *    linux/arch/arm/lib/ashldi3.S
+ *    linux/arch/arm/lib/ashrdi3.S
+ *    linux/arch/arm/lib/lshrdi3.S
+ */
+
+/*
+ * Taken from linux/arch/arm/lib/lib1funcs.S
+ * Retaining only ARMv5+ code paths
+ */
+.macro ARM_DIV_BODY dividend, divisor, result, curbit
+        clz     \curbit, \divisor
+        clz     \result, \dividend
+        sub     \result, \curbit, \result
+        mov     \curbit, #1
+        mov     \divisor, \divisor, lsl \result
+        mov     \curbit, \curbit, lsl \result
+        mov     \result, #0
+
+        @ Division loop
+1:      cmp     \dividend, \divisor
+        subhs   \dividend, \dividend, \divisor
+        orrhs   \result,   \result,   \curbit
+        cmp     \dividend, \divisor,  lsr #1
+        subhs   \dividend, \dividend, \divisor, lsr #1
+        orrhs   \result,   \result,   \curbit,  lsr #1
+        cmp     \dividend, \divisor,  lsr #2
+        subhs   \dividend, \dividend, \divisor, lsr #2
+        orrhs   \result,   \result,   \curbit,  lsr #2
+        cmp     \dividend, \divisor,  lsr #3
+        subhs   \dividend, \dividend, \divisor, lsr #3
+        orrhs   \result,   \result,   \curbit,  lsr #3
+        cmp     \dividend, #0                   @ Early termination?
+        movnes  \curbit,   \curbit,  lsr #4     @ No, any more bits to do?
+        movne   \divisor,  \divisor, lsr #4
+        bne     1b
+
+.endm
+
+.macro ARM_DIV2_ORDER divisor, order
+        clz     \order, \divisor
+        rsb     \order, \order, #31
+.endm
+
+.macro ARM_MOD_BODY dividend, divisor, order, spare
+        clz     \order, \divisor
+        clz     \spare, \dividend
+        sub     \order, \order, \spare
+        mov     \divisor, \divisor, lsl \order
+        @ Perform all needed substractions to keep only the reminder.
+        @ Do comparisons in batch of 4 first.
+        subs    \order, \order, #3              @ yes, 3 is intended here
+        blt     2f
+
+1:      cmp     \dividend, \divisor
+        subhs   \dividend, \dividend, \divisor
+        cmp     \dividend, \divisor,  lsr #1
+        subhs   \dividend, \dividend, \divisor, lsr #1
+        cmp     \dividend, \divisor,  lsr #2
+        subhs   \dividend, \dividend, \divisor, lsr #2
+        cmp     \dividend, \divisor,  lsr #3
+        subhs   \dividend, \dividend, \divisor, lsr #3
+        cmp     \dividend, #1
+        mov     \divisor, \divisor, lsr #4
+        subges  \order, \order, #4
+        bge     1b
+
+        tst     \order, #3
+        teqne   \dividend, #0
+        beq     5f
+
+        @ Either 1, 2 or 3 comparison/substractions are left.
+2:      cmn     \order, #2
+        blt     4f
+        beq     3f
+        cmp     \dividend, \divisor
+        subhs   \dividend, \dividend, \divisor
+        mov     \divisor,  \divisor,  lsr #1
+3:      cmp     \dividend, \divisor
+        subhs   \dividend, \dividend, \divisor
+        mov     \divisor,  \divisor,  lsr #1
+4:      cmp     \dividend, \divisor
+        subhs   \dividend, \dividend, \divisor
+5:
+.endm
+
+	.text
+FUNCTION(__aeabi_uidiv)
+       subs    r2, r1, #1
+        moveq   pc, lr
+        bcc     Ldiv0
+        cmp     r0, r1
+        bls     11f
+        tst     r1, r2
+        beq     12f
+
+        ARM_DIV_BODY r0, r1, r2, r3
+
+        mov     r0, r2
+        mov     pc, lr
+
+11:     moveq   r0, #1
+        movne   r0, #0
+	bx	lr
+
+12:     ARM_DIV2_ORDER r1, r2
+
+        mov     r0, r0, lsr r2
+	bx	lr
+
+FUNCTION(__aeabi_idiv)
+        cmp     r1, #0
+        eor     ip, r0, r1                      @ save the sign of the result.
+        beq     Ldiv0
+        rsbmi   r1, r1, #0                      @ loops below use unsigned.
+        subs    r2, r1, #1                      @ division by 1 or -1 ?
+        beq     10f
+        movs    r3, r0
+        rsbmi   r3, r0, #0                      @ positive dividend value
+        cmp     r3, r1
+        bls     11f
+        tst     r1, r2                          @ divisor is power of 2 ?
+        beq     12f
+
+        ARM_DIV_BODY r3, r1, r0, r2
+
+        cmp     ip, #0
+        rsbmi   r0, r0, #0
+	bx	lr
+
+10:     teq     ip, r0                          @ same sign ?
+        rsbmi   r0, r0, #0
+	bx	lr
+
+11:     movlo   r0, #0
+        moveq   r0, ip, asr #31
+        orreq   r0, r0, #1
+	bx	lr
+
+12:     ARM_DIV2_ORDER r1, r2
+
+        cmp     ip, #0
+        mov     r0, r3, lsr r2
+        rsbmi   r0, r0, #0
+	bx	lr
+
+FUNCTION(__aeabi_uidivmod)
+        stmfd   sp!, {r0, r1, ip, lr}
+        bl      __aeabi_uidiv
+        ldmfd   sp!, {r1, r2, ip, lr}
+        mul     r3, r0, r2
+        sub     r1, r1, r3
+	bx	lr
+
+FUNCTION(__aeabi_idivmod)
+        stmfd   sp!, {r0, r1, ip, lr}
+        bl      __aeabi_idiv
+        ldmfd   sp!, {r1, r2, ip, lr}
+        mul     r3, r0, r2
+        sub     r1, r1, r3
+	bx	lr
+
+@ (Don't) handle division by 0
+FUNCTION(Ldiv0)
+	push	{r4, lr}
+        mov     r0, #0                  @ About as wrong as it could be.
+	pop	{r4, pc}
+
+
+/*
+ * From linux/arch/arm/lib/?sh*3.S
+ */
+FUNCTION(__aeabi_lasr)
+        subs    r3, r2, #32
+        rsb     ip, r2, #32
+        movmi   al, al, lsr r2
+        movpl   al, ah, asr r3
+ ARM(   orrmi   al, al, ah, lsl ip      )
+ THUMB( lslmi   r3, ah, ip              )
+ THUMB( orrmi   al, al, r3              )
+        mov     ah, ah, asr r2
+	bx	lr
+
+FUNCTION(__aeabi_llsl)
+        subs    r3, r2, #32
+        rsb     ip, r2, #32
+        movmi   ah, ah, lsl r2
+        movpl   ah, al, lsl r3
+ ARM(   orrmi   ah, ah, al, lsr ip      )
+ THUMB( lsrmi   r3, al, ip              )
+ THUMB( orrmi   ah, ah, r3              )
+        mov     al, al, lsl r2
+	bx	lr
+
+FUNCTION(__aeabi_llsr)
+        subs    r3, r2, #32
+        rsb     ip, r2, #32
+        movmi   al, al, lsr r2
+        movpl   al, ah, lsr r3
+ ARM(   orrmi   al, al, ah, lsl ip      )
+ THUMB( lslmi   r3, ah, ip              )
+ THUMB( orrmi   al, al, r3              )
+        mov     ah, ah, lsr r2
+	bx	lr
+
+
+/*
+ * Simple cache maintenance functions
+ */
+
+@ r0 - *beg (inclusive)
+@ r1 - *end (exclusive)	
+clean_dcache_range:
+	@DCCMVAU
+1:	cmp	r0, r1
+	bge	2f
+	mcr	p15, 0, r0, c7, c11, 1
+	add	r0, r0, #32 @ assume 32-byte cache line
+2:	dsb
+	bx	lr
+
+@ r0 - *beg (inclusive)
+@ r1 - *end (exclusive)	
+invalidate_icache_range:
+	@ICIMVAU
+1:	cmp	r0, r1
+	bge	2f
+	mcr	p15, 0, r0, c7, c5, 1
+	@BPIMVA
+	mcr	p15, 0, r0, c7,	c5, 7
+	add	r0, r0, #32 @ assume 32-byte cache line
+	b	1b
+	dsb
+2:	isb
+	bx	lr
+	
+@void __clear_cache(char *beg, char *end);
+FUNCTION(__clear_cache)
+	push	{r4-r6, lr}
+	mov	r4, r0
+	mov	r5, r1
+	bl	clean_dcache_range
+	mov	r0, r4
+	mov	r1, r5
+	bl	invalidate_icache_range
+	pop	{r4-r6, pc}
+
+@void grub_arch_sync_caches (void *address, grub_size_t len)
+FUNCTION(grub_arch_sync_caches)
+	add	r1, r0, r1
+	b	__clear_cache
+
+	.end

=== added file 'grub-core/lib/arm/setjmp.S'
--- grub-core/lib/arm/setjmp.S	1970-01-01 00:00:00 +0000
+++ grub-core/lib/arm/setjmp.S	2012-10-22 18:29:17 +0000
@@ -0,0 +1,57 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2012  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/symbol.h>
+#include <grub/dl.h>
+
+	.file	"setjmp.S"
+	.syntax	unified
+#if !defined (__thumb2__)
+	.arm
+#define ARM(x...)	x
+#define THUMB(x...)
+#else
+	.thumb
+#define THUMB(x...)	x
+#define ARM(x...)
+#endif
+
+GRUB_MOD_LICENSE "GPLv3+"
+
+	.text
+
+/*
+ * int grub_setjmp (grub_jmp_buf env)
+ */
+FUNCTION(grub_setjmp)
+ THUMB(	mov	ip, sp			)
+ THUMB(	stm	r0, { r4-r11, ip, lr }	)
+ ARM(	stm	r0, { r4-r11, sp, lr }	)
+	mov	r0, #0
+	bx	lr
+
+/*
+ * int grub_longjmp (grub_jmp_buf env, int val)
+ */
+FUNCTION(grub_longjmp)
+ THUMB(	ldm	r0, { r4-r11, ip, lr }	)
+ THUMB(	mov	sp, ip			)
+ ARM(	ldm	r0, { r4-r11, sp, lr }	)
+	movs	r0, r1
+	moveq	r0, #1
+	bx	lr

=== modified file 'grub-core/lib/setjmp.S'
--- grub-core/lib/setjmp.S	2012-01-18 13:04:52 +0000
+++ grub-core/lib/setjmp.S	2012-10-22 18:29:17 +0000
@@ -11,6 +11,8 @@
 #elif defined(__ia64__)
 #include "./ia64/setjmp.S"
 #include "./ia64/longjmp.S"
+#elif defined(__arm__)
+#include "./arm/setjmp.S"
 #else
 #error "Unknown target cpu type"
 #endif

=== added directory 'grub-core/lib/uboot'
=== added file 'grub-core/lib/uboot/datetime.c'
--- grub-core/lib/uboot/datetime.c	1970-01-01 00:00:00 +0000
+++ grub-core/lib/uboot/datetime.c	2012-10-22 18:29:17 +0000
@@ -0,0 +1,41 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2012  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/types.h>
+#include <grub/symbol.h>
+#include <grub/uboot/uboot.h>
+#include <grub/datetime.h>
+#include <grub/dl.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+/* No simple platform-independent RTC access exists in U-Boot. */
+
+grub_err_t
+grub_get_datetime (struct grub_datetime *datetime __attribute__ ((unused)))
+{
+  return grub_error (GRUB_ERR_INVALID_COMMAND,
+		     "can\'t get datetime using U-Boot");
+}
+
+grub_err_t
+grub_set_datetime (struct grub_datetime * datetime __attribute__ ((unused)))
+{
+  return grub_error (GRUB_ERR_INVALID_COMMAND,
+		     "can\'t set datetime using U-Boot");
+}

=== added file 'grub-core/lib/uboot/halt.c'
--- grub-core/lib/uboot/halt.c	1970-01-01 00:00:00 +0000
+++ grub-core/lib/uboot/halt.c	2012-10-22 18:29:17 +0000
@@ -0,0 +1,31 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2012  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/kernel.h>
+
+void
+grub_halt (void)
+{
+  grub_machine_fini ();
+
+  /* Just stop here */
+
+  while (1);
+}

=== added file 'grub-core/lib/uboot/reboot.c'
--- grub-core/lib/uboot/reboot.c	1970-01-01 00:00:00 +0000
+++ grub-core/lib/uboot/reboot.c	2012-10-22 18:29:17 +0000
@@ -0,0 +1,30 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2012  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/kernel.h>
+#include <grub/misc.h>
+#include <grub/uboot/uboot.h>
+
+void
+grub_reboot (void)
+{
+  grub_machine_fini ();
+
+  ub_reset ();
+  while (1);
+}

=== added directory 'grub-core/loader/arm'
=== added directory 'grub-core/loader/arm/uboot'
=== added file 'grub-core/loader/arm/uboot/linux.c'
--- grub-core/loader/arm/uboot/linux.c	1970-01-01 00:00:00 +0000
+++ grub-core/loader/arm/uboot/linux.c	2012-10-22 18:29:17 +0000
@@ -0,0 +1,379 @@
+/* linux.c - boot Linux */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2012  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/dl.h>
+#include <grub/file.h>
+#include <grub/loader.h>
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/command.h>
+#include <grub/cache.h>
+#include <grub/cpu/linux.h>
+#include <grub/lib/cmdline.h>
+#include <grub/uboot/uboot.h>
+
+#include <libfdt.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static grub_dl_t my_mod;
+
+static grub_addr_t initrd_start;
+static grub_size_t initrd_end;
+
+static grub_addr_t linux_addr;
+static grub_size_t linux_size;
+
+static char *linux_args;
+
+static grub_addr_t firmware_boot_data;
+static grub_addr_t boot_data;
+static grub_uint32_t machine_type;
+
+/*
+ * linux_prepare_fdt():
+ *   Prepares a loaded FDT for being passed to Linux.
+ *   Merges in command line parameters and sets up initrd addresses.
+ */
+static grub_err_t
+linux_prepare_fdt (void)
+{
+  int node;
+  int retval;
+  int tmp_size;
+  void *tmp_fdt;
+
+  tmp_size = fdt_totalsize ((void *) boot_data) + FDT_ADDITIONAL_ENTRIES_SIZE;
+  tmp_fdt = grub_malloc (tmp_size);
+  if (!tmp_fdt)
+    return GRUB_ERR_OUT_OF_MEMORY;
+
+  fdt_open_into ((void *) boot_data, tmp_fdt, tmp_size);
+
+  /* Find or create '/chosen' node */
+  node = fdt_subnode_offset (tmp_fdt, 0, "chosen");
+  if (node < 0)
+    {
+      grub_printf ("No 'chosen' node in FDT - creating.\n");
+      node = fdt_add_subnode (tmp_fdt, 0, "chosen");
+      if (node < 0)
+	goto failure;
+    }
+
+  grub_printf ("linux_args: '%s'\n", linux_args);
+
+  /* Generate and set command line */
+  retval = fdt_setprop (tmp_fdt, node, "bootargs", linux_args,
+			grub_strlen (linux_args) + 1);
+  if (retval)
+    goto failure;
+
+  if (initrd_start && initrd_end)
+    {
+      /*
+       * We're using physical addresses, so even if we have LPAE, we're
+       * restricted to a 32-bit address space.
+       */
+      grub_uint32_t fdt_initrd_start = cpu_to_fdt32 (initrd_start);
+      grub_uint32_t fdt_initrd_end = cpu_to_fdt32 (initrd_end);
+
+      grub_dprintf ("loader", "Initrd @ 0x%08x-0x%08x\n",
+		    initrd_start, initrd_end);
+
+      retval = fdt_setprop (tmp_fdt, node, "linux,initrd-start",
+			    &fdt_initrd_start, sizeof (fdt_initrd_start));
+      if (retval)
+	goto failure;
+      retval = fdt_setprop (tmp_fdt, node, "linux,initrd-end",
+			    &fdt_initrd_end, sizeof (fdt_initrd_end));
+      if (retval)
+	goto failure;
+    }
+
+  /* Copy updated FDT to its launch location */
+  fdt_move (tmp_fdt, (void *) boot_data, fdt_totalsize (tmp_fdt));
+  grub_free (tmp_fdt);
+  fdt_pack ((void *) boot_data);
+
+  grub_dprintf ("loader", "FDT updated for Linux boot\n");
+
+  return GRUB_ERR_NONE;
+
+failure:
+  grub_free (tmp_fdt);
+  return GRUB_ERR_BAD_ARGUMENT;
+}
+
+static grub_err_t
+linux_boot (void)
+{
+  kernel_entry_t linuxmain;
+
+  grub_arch_sync_caches ((void *) linux_addr, linux_size);
+
+  grub_dprintf ("loader", "Kernel at: 0x%x\n", linux_addr);
+
+  if (!boot_data)
+    {
+      if (firmware_boot_data)
+	{
+	  grub_printf ("Using firmware-supplied boot data @ 0x%08x\n",
+		       firmware_boot_data);
+	  boot_data = firmware_boot_data;
+	}
+      else
+	{
+	  return GRUB_ERR_FILE_NOT_FOUND;
+	}
+    }
+
+  grub_dprintf ("loader", "Boot data at: 0x%x\n", boot_data);
+
+  if (fdt32_to_cpu (*(grub_uint32_t *) (boot_data)) == FDT_MAGIC)
+    {
+      grub_dprintf ("loader", "FDT @ 0x%08x\n", (grub_addr_t) boot_data);
+      if (linux_prepare_fdt () != GRUB_ERR_NONE)
+	{
+	  grub_dprintf ("loader", "linux_prepare_fdt() failed\n");
+	  return GRUB_ERR_FILE_NOT_FOUND;
+	}
+    }
+
+  grub_dprintf ("loader", "Jumping to Linux...\n");
+
+  /* Boot the kernel.
+   *   Arguments to kernel:
+   *     r0 - 0
+   *     r1 - machine type (passed from U-Boot)
+   *     r2 - address of DTB or ATAG list
+   */
+  linuxmain = (kernel_entry_t) linux_addr;
+  linuxmain (0, machine_type, (void *) boot_data);
+
+  return GRUB_ERR_NONE;
+}
+
+/*
+ * Only support zImage, so no relocations necessary
+ */
+static grub_err_t
+linux_load (const char *filename)
+{
+  grub_file_t file;
+  int size;
+
+  file = grub_file_open (filename);
+  if (!file)
+    return GRUB_ERR_FILE_NOT_FOUND;
+
+  size = grub_file_size (file);
+  if (size == 0)
+    return GRUB_ERR_FILE_READ_ERROR;
+
+  linux_addr = LINUX_ADDRESS;
+  grub_dprintf ("loader", "Loading Linux to 0x%08x\n",
+		(grub_addr_t) linux_addr);
+
+  if (grub_file_read (file, (void *) linux_addr, size) != size)
+    {
+      grub_printf ("Kernel read failed!\n");
+      return GRUB_ERR_FILE_READ_ERROR;
+    }
+
+  if (*(grub_uint32_t *) (linux_addr + LINUX_ZIMAGE_OFFSET)
+      != LINUX_ZIMAGE_MAGIC)
+    {
+      return grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("invalid zImage"));
+    }
+
+  linux_size = size;
+
+  return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+linux_unload (void)
+{
+  grub_dl_unref (my_mod);
+
+  grub_free (linux_args);
+  linux_args = NULL;
+
+  initrd_start = initrd_end = 0;
+
+  return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+		int argc, char *argv[])
+{
+  int size, retval;
+  grub_file_t file;
+  grub_dl_ref (my_mod);
+
+  if (argc == 0)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
+
+  file = grub_file_open (argv[0]);
+  if (!file)
+    goto fail;
+
+  retval = linux_load (argv[0]);
+  grub_file_close (file);
+  if (retval != GRUB_ERR_NONE)
+    goto fail;
+
+  grub_loader_set (linux_boot, linux_unload, 1);
+
+  size = grub_loader_cmdline_size (argc, argv);
+  linux_args = grub_malloc (size + sizeof (LINUX_IMAGE));
+  if (!linux_args)
+    goto fail;
+
+  /* Create kernel command line.  */
+  grub_memcpy (linux_args, LINUX_IMAGE, sizeof (LINUX_IMAGE));
+  grub_create_loader_cmdline (argc, argv,
+			      linux_args + sizeof (LINUX_IMAGE) - 1, size);
+
+  return GRUB_ERR_NONE;
+
+fail:
+  grub_dl_unref (my_mod);
+  return grub_errno;
+}
+
+static grub_err_t
+grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
+		 int argc, char *argv[])
+{
+  grub_file_t file;
+  int size;
+
+  if (argc == 0)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
+
+  file = grub_file_open (argv[0]);
+  if (!file)
+    return grub_errno;
+
+  size = grub_file_size (file);
+  if (size == 0)
+    goto fail;
+
+  initrd_start = LINUX_INITRD_ADDRESS;
+  grub_dprintf ("loader", "Loading initrd to 0x%08x\n",
+		(grub_addr_t) initrd_start);
+
+  if (grub_file_read (file, (void *) initrd_start, size) != size)
+    goto fail;
+
+  initrd_end = initrd_start + size;
+
+  return GRUB_ERR_NONE;
+
+fail:
+  grub_file_close (file);
+
+  return grub_errno;
+}
+
+static void *
+load_dtb (const char *path)
+{
+  grub_file_t dtb;
+  int size;
+  void *fdt = NULL;
+
+  dtb = grub_file_open (path);
+  if (!dtb)
+    return NULL;
+
+  size = grub_file_size (dtb);
+  if (size == 0)
+    goto out;
+
+  fdt = grub_malloc (size);
+  if (!fdt)
+    goto out;
+
+  if (grub_file_read (dtb, fdt, size) != size)
+    {
+      grub_free (fdt);
+      fdt = NULL;
+      goto out;
+    }
+
+  if (fdt_check_header (fdt) != 0)
+    {
+      grub_free (fdt);
+      fdt = NULL;
+    }
+
+out:
+  grub_file_close (dtb);
+
+  return fdt;
+}
+
+static grub_err_t
+grub_cmd_devicetree (grub_command_t cmd __attribute__ ((unused)),
+		     int argc, char *argv[])
+{
+  void *blob;
+
+  if (argc != 1)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
+
+  blob = load_dtb (argv[0]);
+  if (!blob)
+    return GRUB_ERR_FILE_NOT_FOUND;
+
+  boot_data = LINUX_FDT_ADDRESS;
+  grub_dprintf ("loader", "Loading device tree to 0x%08x\n",
+		(grub_addr_t) boot_data);
+  fdt_move (blob, (void *) boot_data, fdt_totalsize (blob));
+  grub_free (blob);
+
+  return GRUB_ERR_NONE;
+}
+
+static grub_command_t cmd_linux, cmd_initrd, cmd_devicetree;
+
+GRUB_MOD_INIT (linux)
+{
+  cmd_linux = grub_register_command ("linux", grub_cmd_linux,
+				     0, N_("Load Linux."));
+  cmd_initrd = grub_register_command ("initrd", grub_cmd_initrd,
+				      0, N_("Load initrd."));
+  cmd_devicetree = grub_register_command ("devicetree", grub_cmd_devicetree,
+					  0, N_("Load DTB file."));
+  my_mod = mod;
+  firmware_boot_data = uboot_get_boot_data ();
+
+  boot_data = (grub_addr_t) NULL;
+  machine_type = uboot_get_machine_type ();
+}
+
+GRUB_MOD_FINI (linux)
+{
+  grub_unregister_command (cmd_linux);
+  grub_unregister_command (cmd_initrd);
+  grub_unregister_command (cmd_devicetree);
+}

=== modified file 'grub-core/term/terminfo.c'
--- grub-core/term/terminfo.c	2012-09-18 09:52:19 +0000
+++ grub-core/term/terminfo.c	2012-10-22 18:29:17 +0000
@@ -746,7 +746,9 @@
 
 static grub_extcmd_t cmd;
 
-#if defined (GRUB_MACHINE_IEEE1275) || defined (GRUB_MACHINE_MIPS_LOONGSON) || defined (GRUB_MACHINE_MIPS_QEMU_MIPS) || defined (GRUB_MACHINE_ARC)
+#if defined (GRUB_MACHINE_IEEE1275) || defined (GRUB_MACHINE_MIPS_LOONGSON) || \
+  defined (GRUB_MACHINE_MIPS_QEMU_MIPS) || defined (GRUB_MACHINE_ARC) || \
+  defined (GRUB_MACHINE_UBOOT)
 void grub_terminfo_init (void)
 #else
 GRUB_MOD_INIT(terminfo)

=== added directory 'grub-core/term/uboot'
=== added file 'grub-core/term/uboot/console.c'
--- grub-core/term/uboot/console.c	1970-01-01 00:00:00 +0000
+++ grub-core/term/uboot/console.c	2012-10-22 18:29:17 +0000
@@ -0,0 +1,143 @@
+/* console.c - console interface layer for U-Boot platforms */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2012  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/term.h>
+#include <grub/misc.h>
+#include <grub/types.h>
+#include <grub/err.h>
+#include <grub/terminfo.h>
+#include <grub/uboot/uboot.h>
+#include <grub/uboot/console.h>
+
+static void
+put (struct grub_term_output *term __attribute__ ((unused)), const int c)
+{
+  ub_putc (c);
+}
+
+static int
+readkey (struct grub_term_input *term __attribute__ ((unused)))
+{
+  if (ub_tstc () > 0)
+    return ub_getc ();
+
+  return -1;
+}
+
+static void
+uboot_console_setcursor (struct grub_term_output *term
+			 __attribute__ ((unused)), int on
+			 __attribute__ ((unused)))
+{
+  grub_terminfo_setcursor (term, on);
+}
+
+static grub_err_t
+uboot_console_init_input (struct grub_term_input *term)
+{
+  return grub_terminfo_input_init (term);
+}
+
+extern struct grub_terminfo_output_state uboot_console_terminfo_output;
+
+static void
+uboot_console_dimensions (void)
+{
+  /* Use a small console by default.  */
+  if (!uboot_console_terminfo_output.width)
+    uboot_console_terminfo_output.width = 80;
+  if (!uboot_console_terminfo_output.height)
+    uboot_console_terminfo_output.height = 24;
+}
+
+static grub_err_t
+uboot_console_init_output (struct grub_term_output *term)
+{
+  uboot_console_dimensions ();
+
+  grub_terminfo_output_init (term);
+
+  return 0;
+}
+
+struct grub_terminfo_input_state uboot_console_terminfo_input = {
+  .readkey = readkey
+};
+
+struct grub_terminfo_output_state uboot_console_terminfo_output = {
+  .put = put,
+  .width = 80,
+  .height = 24
+};
+
+static struct grub_term_input uboot_console_term_input = {
+  .name = "console",
+  .init = uboot_console_init_input,
+  .getkey = grub_terminfo_getkey,
+  .data = &uboot_console_terminfo_input
+};
+
+static struct grub_term_output uboot_console_term_output = {
+  .name = "console",
+  .init = uboot_console_init_output,
+  .putchar = grub_terminfo_putchar,
+  .getwh = grub_terminfo_getwh,
+  .getxy = grub_terminfo_getxy,
+  .gotoxy = grub_terminfo_gotoxy,
+  .cls = grub_terminfo_cls,
+  .setcolorstate = grub_terminfo_setcolorstate,
+  .setcursor = uboot_console_setcursor,
+  .flags = GRUB_TERM_CODE_TYPE_ASCII,
+  .data = &uboot_console_terminfo_output,
+  .normal_color = GRUB_TERM_DEFAULT_NORMAL_COLOR,
+  .highlight_color = GRUB_TERM_DEFAULT_HIGHLIGHT_COLOR,
+};
+
+void
+grub_console_init_early (void)
+{
+  grub_term_register_input ("console", &uboot_console_term_input);
+  grub_term_register_output ("console", &uboot_console_term_output);
+}
+
+
+/*
+ * grub_console_init_lately():
+ *   Initializes terminfo formatting by registering terminal type.
+ *   Called after heap has been configured.
+ *   
+ */
+void
+grub_console_init_lately (void)
+{
+  const char *type;
+
+  /* See if explicitly set by U-Boot environment */
+  type = ub_env_get ("grub_term");
+  if (!type)
+    type = "vt100";
+
+  grub_terminfo_init ();
+  grub_terminfo_output_register (&uboot_console_term_output, type);
+}
+
+void
+grub_console_fini (void)
+{
+}

=== added directory 'include/grub/arm'
=== added file 'include/grub/arm/linux.h'
--- include/grub/arm/linux.h	1970-01-01 00:00:00 +0000
+++ include/grub/arm/linux.h	2012-10-22 18:29:17 +0000
@@ -0,0 +1,34 @@
+/* linux.h - ARM linux specific definitions */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2012  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_LINUX_CPU_HEADER
+#define GRUB_LINUX_CPU_HEADER 1
+
+#define LINUX_ZIMAGE_OFFSET 0x24
+#define LINUX_ZIMAGE_MAGIC  0x016f2818
+
+#define LINUX_ADDRESS        (start_of_ram + 0x8000)
+#define LINUX_INITRD_ADDRESS (start_of_ram + 0x02000000)
+#define LINUX_FDT_ADDRESS    (LINUX_INITRD_ADDRESS - 0x10000)
+
+#define FDT_ADDITIONAL_ENTRIES_SIZE	0x300
+
+typedef void (*kernel_entry_t) (int, unsigned long, void *);
+
+#endif /* ! GRUB_LINUX_CPU_HEADER */

=== added file 'include/grub/arm/time.h'
--- include/grub/arm/time.h	1970-01-01 00:00:00 +0000
+++ include/grub/arm/time.h	2012-10-22 18:29:17 +0000
@@ -0,0 +1,29 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2012  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 KERNEL_CPU_TIME_HEADER
+#define KERNEL_CPU_TIME_HEADER	1
+
+static __inline void
+grub_cpu_idle (void)
+{
+  /* FIXME: this can't work until we handle interrupts.  */
+/*  __asm__ __volatile__ ("wfi"); */
+}
+
+#endif /* ! KERNEL_CPU_TIME_HEADER */

=== added file 'include/grub/arm/types.h'
--- include/grub/arm/types.h	1970-01-01 00:00:00 +0000
+++ include/grub/arm/types.h	2012-10-22 18:29:17 +0000
@@ -0,0 +1,34 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2012  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_TYPES_CPU_HEADER
+#define GRUB_TYPES_CPU_HEADER	1
+
+/* The size of void *.  */
+#define GRUB_TARGET_SIZEOF_VOID_P	4
+
+/* The size of long.  */
+#define GRUB_TARGET_SIZEOF_LONG		4
+
+/* currently only support little-endian.  */
+#undef GRUB_TARGET_WORDS_BIGENDIAN
+
+/* Unaligned accesses only supported if MMU enabled */
+//#define GRUB_HAVE_UNALIGNED_ACCESS 1
+
+#endif /* ! GRUB_TYPES_CPU_HEADER */

=== added directory 'include/grub/arm/uboot'
=== added file 'include/grub/arm/uboot/kernel.h'
--- include/grub/arm/uboot/kernel.h	1970-01-01 00:00:00 +0000
+++ include/grub/arm/uboot/kernel.h	2012-10-22 18:29:17 +0000
@@ -0,0 +1,31 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2012 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_KERNEL_MACHINE_HEADER
+#define GRUB_KERNEL_MACHINE_HEADER	1
+
+#define GRUB_KERNEL_MACHINE_STACK_SIZE          0x40000
+
+#ifndef ASM_FILE
+
+#include <grub/symbol.h>
+#include <grub/types.h>
+
+#endif /* ! ASM_FILE */
+
+#endif /* ! GRUB_KERNEL_MACHINE_HEADER */

=== modified file 'include/grub/disk.h'
--- include/grub/disk.h	2012-02-09 22:15:27 +0000
+++ include/grub/disk.h	2012-10-22 18:29:17 +0000
@@ -27,21 +27,22 @@
 /* These are used to set a device id. When you add a new disk device,
    you must define a new id for it here.  */
 enum grub_disk_dev_id
-  {
-    GRUB_DISK_DEVICE_BIOSDISK_ID,
-    GRUB_DISK_DEVICE_OFDISK_ID,
-    GRUB_DISK_DEVICE_LOOPBACK_ID,
-    GRUB_DISK_DEVICE_EFIDISK_ID,
-    GRUB_DISK_DEVICE_DISKFILTER_ID,
-    GRUB_DISK_DEVICE_HOST_ID,
-    GRUB_DISK_DEVICE_ATA_ID,
-    GRUB_DISK_DEVICE_MEMDISK_ID,
-    GRUB_DISK_DEVICE_NAND_ID,
-    GRUB_DISK_DEVICE_SCSI_ID,
-    GRUB_DISK_DEVICE_CRYPTODISK_ID,
-    GRUB_DISK_DEVICE_ARCDISK_ID,
-    GRUB_DISK_DEVICE_HOSTDISK_ID,
-  };
+{
+  GRUB_DISK_DEVICE_BIOSDISK_ID,
+  GRUB_DISK_DEVICE_OFDISK_ID,
+  GRUB_DISK_DEVICE_LOOPBACK_ID,
+  GRUB_DISK_DEVICE_EFIDISK_ID,
+  GRUB_DISK_DEVICE_DISKFILTER_ID,
+  GRUB_DISK_DEVICE_HOST_ID,
+  GRUB_DISK_DEVICE_ATA_ID,
+  GRUB_DISK_DEVICE_MEMDISK_ID,
+  GRUB_DISK_DEVICE_NAND_ID,
+  GRUB_DISK_DEVICE_SCSI_ID,
+  GRUB_DISK_DEVICE_CRYPTODISK_ID,
+  GRUB_DISK_DEVICE_ARCDISK_ID,
+  GRUB_DISK_DEVICE_HOSTDISK_ID,
+  GRUB_DISK_DEVICE_UBOOTDISK_ID,
+};
 
 struct grub_disk;
 #ifdef GRUB_UTIL
@@ -49,12 +50,12 @@
 #endif
 
 typedef enum
-  { 
-    GRUB_DISK_PULL_NONE,
-    GRUB_DISK_PULL_REMOVABLE,
-    GRUB_DISK_PULL_RESCAN,
-    GRUB_DISK_PULL_MAX
-  } grub_disk_pull_t;
+{
+  GRUB_DISK_PULL_NONE,
+  GRUB_DISK_PULL_REMOVABLE,
+  GRUB_DISK_PULL_RESCAN,
+  GRUB_DISK_PULL_MAX
+} grub_disk_pull_t;
 
 /* Disk device.  */
 struct grub_disk_dev
@@ -66,26 +67,25 @@
   enum grub_disk_dev_id id;
 
   /* Call HOOK with each device name, until HOOK returns non-zero.  */
-  int (*iterate) (int (*hook) (const char *name),
-		  grub_disk_pull_t pull);
+  int (*iterate) (int (*hook) (const char *name), grub_disk_pull_t pull);
 
   /* Open the device named NAME, and set up DISK.  */
-  grub_err_t (*open) (const char *name, struct grub_disk *disk);
+    grub_err_t (*open) (const char *name, struct grub_disk * disk);
 
   /* Close the disk DISK.  */
-  void (*close) (struct grub_disk *disk);
+  void (*close) (struct grub_disk * disk);
 
   /* Read SIZE sectors from the sector SECTOR of the disk DISK into BUF.  */
-  grub_err_t (*read) (struct grub_disk *disk, grub_disk_addr_t sector,
-		      grub_size_t size, char *buf);
+    grub_err_t (*read) (struct grub_disk * disk, grub_disk_addr_t sector,
+			grub_size_t size, char *buf);
 
   /* Write SIZE sectors from BUF into the sector SECTOR of the disk DISK.  */
-  grub_err_t (*write) (struct grub_disk *disk, grub_disk_addr_t sector,
-		       grub_size_t size, const char *buf);
+    grub_err_t (*write) (struct grub_disk * disk, grub_disk_addr_t sector,
+			 grub_size_t size, const char *buf);
 
 #ifdef GRUB_UTIL
-  struct grub_disk_memberlist *(*memberlist) (struct grub_disk *disk);
-  const char * (*raidname) (struct grub_disk *disk);
+  struct grub_disk_memberlist *(*memberlist) (struct grub_disk * disk);
+  const char *(*raidname) (struct grub_disk * disk);
 #endif
 
   /* The next disk device.  */
@@ -121,7 +121,7 @@
   /* Called when a sector was read. OFFSET is between 0 and
      the sector size minus 1, and LENGTH is between 0 and the sector size.  */
   void NESTED_FUNC_ATTR (*read_hook) (grub_disk_addr_t sector,
-		     unsigned offset, unsigned length);
+				      unsigned offset, unsigned length);
 
   /* Device-specific data.  */
   void *data;
@@ -155,8 +155,8 @@
 /* This is called from the memory manager.  */
 void grub_disk_cache_invalidate_all (void);
 
-void EXPORT_FUNC(grub_disk_dev_register) (grub_disk_dev_t dev);
-void EXPORT_FUNC(grub_disk_dev_unregister) (grub_disk_dev_t dev);
+void EXPORT_FUNC (grub_disk_dev_register) (grub_disk_dev_t dev);
+void EXPORT_FUNC (grub_disk_dev_unregister) (grub_disk_dev_t dev);
 static inline int
 grub_disk_dev_iterate (int (*hook) (const char *name))
 {
@@ -171,28 +171,27 @@
   return 0;
 }
 
-grub_disk_t EXPORT_FUNC(grub_disk_open) (const char *name);
-void EXPORT_FUNC(grub_disk_close) (grub_disk_t disk);
-grub_err_t EXPORT_FUNC(grub_disk_read) (grub_disk_t disk,
-					grub_disk_addr_t sector,
-					grub_off_t offset,
-					grub_size_t size,
-					void *buf);
-grub_err_t EXPORT_FUNC(grub_disk_write) (grub_disk_t disk,
+grub_disk_t EXPORT_FUNC (grub_disk_open) (const char *name);
+void EXPORT_FUNC (grub_disk_close) (grub_disk_t disk);
+grub_err_t EXPORT_FUNC (grub_disk_read) (grub_disk_t disk,
 					 grub_disk_addr_t sector,
 					 grub_off_t offset,
-					 grub_size_t size,
-					 const void *buf);
+					 grub_size_t size, void *buf);
+grub_err_t EXPORT_FUNC (grub_disk_write) (grub_disk_t disk,
+					  grub_disk_addr_t sector,
+					  grub_off_t offset,
+					  grub_size_t size, const void *buf);
 
-grub_uint64_t EXPORT_FUNC(grub_disk_get_size) (grub_disk_t disk);
+grub_uint64_t EXPORT_FUNC (grub_disk_get_size) (grub_disk_t disk);
 
 #if DISK_CACHE_STATS
 void
-EXPORT_FUNC(grub_disk_cache_get_performance) (unsigned long *hits, unsigned long *misses);
+EXPORT_FUNC (grub_disk_cache_get_performance) (unsigned long *hits,
+					       unsigned long *misses);
 #endif
 
-extern void (* EXPORT_VAR(grub_disk_firmware_fini)) (void);
-extern int EXPORT_VAR(grub_disk_firmware_is_tainted);
+extern void (*EXPORT_VAR (grub_disk_firmware_fini)) (void);
+extern int EXPORT_VAR (grub_disk_firmware_is_tainted);
 
 #if defined (GRUB_UTIL)
 void grub_lvm_init (void);

=== modified file 'include/grub/elf.h'
--- include/grub/elf.h	2012-06-18 19:09:57 +0000
+++ include/grub/elf.h	2012-10-22 18:29:17 +0000
@@ -145,6 +145,7 @@
 #define ELFOSABI_TRU64		10	/* Compaq TRU64 UNIX.  */
 #define ELFOSABI_MODESTO	11	/* Novell Modesto.  */
 #define ELFOSABI_OPENBSD	12	/* OpenBSD.  */
+#define ELFOSABI_ARM_AEABI	64	/* ARM EABI */
 #define ELFOSABI_ARM		97	/* ARM */
 #define ELFOSABI_STANDALONE	255	/* Standalone (embedded) application */
 
@@ -2005,15 +2006,18 @@
 /* ARM specific declarations */
 
 /* Processor specific flags for the ELF header e_flags field.  */
-#define EF_ARM_RELEXEC     0x01
-#define EF_ARM_HASENTRY    0x02
-#define EF_ARM_INTERWORK   0x04
-#define EF_ARM_APCS_26     0x08
-#define EF_ARM_APCS_FLOAT  0x10
-#define EF_ARM_PIC         0x20
-#define EF_ARM_ALIGN8      0x40		/* 8-bit structure alignment is in use */
-#define EF_ARM_NEW_ABI     0x80
-#define EF_ARM_OLD_ABI     0x100
+#define EF_ARM_RELEXEC     	0x01
+#define EF_ARM_HASENTRY    	0x02
+#define EF_ARM_INTERWORK   	0x04
+#define EF_ARM_APCS_26     	0x08
+#define EF_ARM_APCS_FLOAT  	0x10
+#define EF_ARM_PIC         	0x20
+#define EF_ARM_ALIGN8      	0x40 /* 8-bit structure alignment is in use */
+#define EF_ARM_NEW_ABI     	0x80
+#define EF_ARM_OLD_ABI     	0x100
+#define EF_ARM_SOFT_FLOAT	0x200
+#define EF_ARM_VFP_FLOAT	0x400
+#define EF_ARM_MAVERICK_FLOAT	0x800
 
 /* Other constants defined in the ARM ELF spec. version B-01.  */
 /* NB. These conflict with values defined above.  */
@@ -2022,13 +2026,21 @@
 #define EF_ARM_MAPSYMSFIRST	0x10
 #define EF_ARM_EABIMASK		0XFF000000
 
+/* Constants defined in AAELF.  */
+#define EF_ARM_BE8	    0x00800000
+#define EF_ARM_LE8	    0x00400000
+
 #define EF_ARM_EABI_VERSION(flags) ((flags) & EF_ARM_EABIMASK)
 #define EF_ARM_EABI_UNKNOWN  0x00000000
 #define EF_ARM_EABI_VER1     0x01000000
 #define EF_ARM_EABI_VER2     0x02000000
+#define EF_ARM_EABI_VER3     0x03000000
+#define EF_ARM_EABI_VER4     0x04000000
+#define EF_ARM_EABI_VER5     0x05000000
 
 /* Additional symbol types for Thumb */
-#define STT_ARM_TFUNC      0xd
+#define STT_ARM_TFUNC	     STT_LOPROC /* A Thumb function.  */
+#define STT_ARM_16BIT	     STT_HIPROC /* A Thumb label.  */
 
 /* ARM-specific values for sh_flags */
 #define SHF_ARM_ENTRYSECT  0x10000000   /* Section contains an entry point */
@@ -2038,6 +2050,17 @@
 /* ARM-specific program header flags */
 #define PF_ARM_SB          0x10000000   /* Segment contains the location
 					   addressed by the static base */
+#define PF_ARM_PI	   0x20000000   /* Position-independent segment.  */
+#define PF_ARM_ABS	   0x40000000   /* Absolute segment.  */
+
+/* Processor specific values for the Phdr p_type field.  */
+#define PT_ARM_EXIDX		(PT_LOPROC + 1)	/* ARM unwind segment.  */
+
+/* Processor specific values for the Shdr sh_type field.  */
+#define SHT_ARM_EXIDX		(SHT_LOPROC + 1) /* ARM unwind section.  */
+#define SHT_ARM_PREEMPTMAP	(SHT_LOPROC + 2) /* Preemption details.  */
+#define SHT_ARM_ATTRIBUTES	(SHT_LOPROC + 3) /* ARM attributes section.  */
+
 
 /* ARM relocs.  */
 #define R_ARM_NONE		0	/* No reloc */
@@ -2050,7 +2073,7 @@
 #define R_ARM_THM_ABS5		7
 #define R_ARM_ABS8		8	/* Direct 8 bit */
 #define R_ARM_SBREL32		9
-#define R_ARM_THM_PC22		10
+#define R_ARM_THM_CALL		10
 #define R_ARM_THM_PC8		11
 #define R_ARM_AMP_VCALL9	12
 #define R_ARM_SWI24		13
@@ -2065,16 +2088,36 @@
 #define R_ARM_GOTPC		25	/* 32 bit PC relative offset to GOT */
 #define R_ARM_GOT32		26	/* 32 bit GOT entry */
 #define R_ARM_PLT32		27	/* 32 bit PLT address */
+#define R_ARM_CALL		28
+#define R_ARM_JUMP24		29
+#define R_ARM_THM_JUMP24	30
+#define R_ARM_BASE_ABS		31
 #define R_ARM_ALU_PCREL_7_0	32
 #define R_ARM_ALU_PCREL_15_8	33
 #define R_ARM_ALU_PCREL_23_15	34
 #define R_ARM_LDR_SBREL_11_0	35
 #define R_ARM_ALU_SBREL_19_12	36
 #define R_ARM_ALU_SBREL_27_20	37
+#define R_ARM_TLS_GOTDESC	90
+#define R_ARM_TLS_CALL		91
+#define R_ARM_TLS_DESCSEQ	92
+#define R_ARM_THM_TLS_CALL	93
 #define R_ARM_GNU_VTENTRY	100
 #define R_ARM_GNU_VTINHERIT	101
 #define R_ARM_THM_PC11		102	/* thumb unconditional branch */
 #define R_ARM_THM_PC9		103	/* thumb conditional branch */
+#define R_ARM_TLS_GD32		104	/* PC-rel 32 bit for global dynamic
+					   thread local data */
+#define R_ARM_TLS_LDM32		105	/* PC-rel 32 bit for local dynamic
+					   thread local data */
+#define R_ARM_TLS_LDO32		106	/* 32 bit offset relative to TLS
+					   block */
+#define R_ARM_TLS_IE32		107	/* PC-rel 32 bit for GOT entry of
+					   static TLS block offset */
+#define R_ARM_TLS_LE32		108	/* 32 bit offset relative to static
+					   TLS block */
+#define	R_ARM_THM_TLS_DESCSEQ	129
+#define R_ARM_IRELATIVE		160
 #define R_ARM_RXPC25		249
 #define R_ARM_RSBREL32		250
 #define R_ARM_THM_RPC22		251

=== modified file 'include/grub/libgcc.h'
--- include/grub/libgcc.h	2012-02-29 14:28:02 +0000
+++ include/grub/libgcc.h	2012-10-22 18:29:17 +0000
@@ -24,59 +24,59 @@
 
 /* On x86 these functions aren't really needed. Save some space.  */
 #if !defined (__i386__) && !defined (__x86_64__)
-# ifdef HAVE___ASHLDI3
+#ifdef HAVE___ASHLDI3
 void EXPORT_FUNC (__ashldi3) (void);
-# endif
-# ifdef HAVE___ASHRDI3
+#endif
+#ifdef HAVE___ASHRDI3
 void EXPORT_FUNC (__ashrdi3) (void);
-# endif
-# ifdef HAVE___LSHRDI3
+#endif
+#ifdef HAVE___LSHRDI3
 void EXPORT_FUNC (__lshrdi3) (void);
-# endif
-# ifdef HAVE___UCMPDI2
+#endif
+#ifdef HAVE___UCMPDI2
 void EXPORT_FUNC (__ucmpdi2) (void);
-# endif
-# ifdef HAVE___BSWAPSI2
+#endif
+#ifdef HAVE___BSWAPSI2
 void EXPORT_FUNC (__bswapsi2) (void);
-# endif
-# ifdef HAVE___BSWAPDI2
+#endif
+#ifdef HAVE___BSWAPDI2
 void EXPORT_FUNC (__bswapdi2) (void);
-# endif
-# ifdef HAVE___UDIVSI3
+#endif
+#ifdef HAVE___UDIVSI3
 void EXPORT_FUNC (__udivsi3) (void);
-# endif
-# ifdef HAVE___UMODSI3
+#endif
+#ifdef HAVE___UMODSI3
 void EXPORT_FUNC (__umodsi3) (void);
-# endif
-# ifdef HAVE___UMODDI3
+#endif
+#ifdef HAVE___UMODDI3
 void EXPORT_FUNC (__umoddi3) (void);
-# endif
-# ifdef HAVE___UDIVDI3
+#endif
+#ifdef HAVE___UDIVDI3
 void EXPORT_FUNC (__udivdi3) (void);
-# endif
-# ifdef HAVE___MODDI3
+#endif
+#ifdef HAVE___MODDI3
 void EXPORT_FUNC (__moddi3) (void);
-# endif
-# ifdef HAVE___DIVDI3
+#endif
+#ifdef HAVE___DIVDI3
 void EXPORT_FUNC (__divdi3) (void);
-# endif
-# ifdef HAVE___DIVSI3
+#endif
+#ifdef HAVE___DIVSI3
 void EXPORT_FUNC (__divsi3) (void);
-# endif
-# ifdef HAVE___MODSI3
+#endif
+#ifdef HAVE___MODSI3
 void EXPORT_FUNC (__modsi3) (void);
-# endif
-# ifdef HAVE___CTZDI2
+#endif
+#ifdef HAVE___CTZDI2
 void EXPORT_FUNC (__ctzdi2) (void);
-# endif
-# ifdef HAVE___CTZSI2
+#endif
+#ifdef HAVE___CTZSI2
 void EXPORT_FUNC (__ctzsi2) (void);
-# endif
+#endif
 #endif
 
-# ifdef HAVE___IA64_TRAMPOLINE
+#ifdef HAVE___IA64_TRAMPOLINE
 void EXPORT_FUNC (__ia64_trampoline) (void);
-# endif
+#endif
 
 #ifdef HAVE___TRAMPOLINE_SETUP
 void EXPORT_FUNC (__trampoline_setup) (void);
@@ -120,3 +120,14 @@
 void EXPORT_FUNC (_savegpr_30) (void);
 void EXPORT_FUNC (_savegpr_31) (void);
 #endif
+
+#if defined (__arm__)
+void EXPORT_FUNC (__aeabi_idiv) (void);
+void EXPORT_FUNC (__aeabi_idivmod) (void);
+void EXPORT_FUNC (__aeabi_lasr) (void);
+void EXPORT_FUNC (__aeabi_llsl) (void);
+void EXPORT_FUNC (__aeabi_llsr) (void);
+void EXPORT_FUNC (__aeabi_uidiv) (void);
+void EXPORT_FUNC (__aeabi_uidivmod) (void);
+void EXPORT_FUNC (__clear_cache) (void *, void *);
+#endif

=== modified file 'include/grub/offsets.h'
--- include/grub/offsets.h	2012-01-29 22:20:02 +0000
+++ include/grub/offsets.h	2012-10-22 18:29:17 +0000
@@ -102,6 +102,7 @@
 #define GRUB_KERNEL_I386_IEEE1275_MOD_GAP 0x0
 #define GRUB_KERNEL_I386_COREBOOT_MOD_GAP 0x0
 #define GRUB_KERNEL_SPARC64_IEEE1275_MOD_GAP 0x0
+#define GRUB_KERNEL_ARM_UBOOT_MOD_GAP 0x0
 
 #define GRUB_KERNEL_POWERPC_IEEE1275_MOD_ALIGN 0x1000
 #define GRUB_KERNEL_SPARC64_IEEE1275_MOD_ALIGN 0x1
@@ -110,6 +111,10 @@
 #define GRUB_KERNEL_MIPS_ARC_MOD_ALIGN 0x1
 #define GRUB_KERNEL_MIPS_QEMU_MIPS_MOD_ALIGN 0x1
 
+#define GRUB_KERNEL_ARM_UBOOT_MOD_ALIGN 	0x1
+#define GRUB_KERNEL_ARM_UBOOT_TOTAL_MODULE_SIZE	0x4
+#define GRUB_KERNEL_ARM_UBOOT_LINK_ADDR		0x08000000
+
 /* Minimal gap between _end and the start of the modules.  It's a hack
    for PowerMac to prevent "CLAIM failed" error.  The real fix is to
    rewrite grub-mkimage to generate valid ELF files.  */

=== modified file 'include/grub/symbol.h'
--- include/grub/symbol.h	2012-05-28 15:49:18 +0000
+++ include/grub/symbol.h	2012-10-22 18:29:17 +0000
@@ -29,12 +29,16 @@
 
 #if HAVE_ASM_USCORE
 #ifdef ASM_FILE
-# define EXT_C(sym)	_ ## sym
-#else
-# define EXT_C(sym)	"_" sym
-#endif
-#else
-# define EXT_C(sym)	sym
+#ifndef (__arm__)
+#define EXT_C(sym)	_ ## sym
+#else
+#define EXT_C(sym)	% ## sym
+#endif
+#else
+#define EXT_C(sym)	"_" sym
+#endif
+#else
+#define EXT_C(sym)	sym
 #endif
 
 #if defined (__APPLE__)
@@ -52,8 +56,8 @@
 
 /* Mark an exported symbol.  */
 #ifndef GRUB_SYMBOL_GENERATOR
-# define EXPORT_FUNC(x)	x
-# define EXPORT_VAR(x)	x
+#define EXPORT_FUNC(x)	x
+#define EXPORT_VAR(x)	x
 #endif /* ! GRUB_SYMBOL_GENERATOR */
 
 #endif /* ! GRUB_SYMBOL_HEADER */

=== added directory 'include/grub/uboot'
=== added file 'include/grub/uboot/api_public.h'
--- include/grub/uboot/api_public.h	1970-01-01 00:00:00 +0000
+++ include/grub/uboot/api_public.h	2012-10-22 18:29:17 +0000
@@ -0,0 +1,175 @@
+/*
+ * (C) Copyright 2007-2008 Semihalf
+ *
+ * Written by: Rafal Jaworowski <raj@semihalf.com>
+ *
+ * This file is dual licensed; you can use it under the terms of
+ * either the GPL, or the BSD license, at your option.
+ *
+ * I. GPL:
+ *
+ * This file 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 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This file 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Alternatively,
+ *
+ * II. BSD license:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _API_PUBLIC_H_
+#define _API_PUBLIC_H_
+
+#define API_EINVAL		1	/* invalid argument(s)	*/
+#define API_ENODEV		2	/* no device		*/
+#define API_ENOMEM		3	/* no memory		*/
+#define API_EBUSY		4	/* busy, occupied etc.	*/
+#define API_EIO			5	/* I/O error		*/
+#define API_ESYSC		6	/* syscall error	*/
+
+typedef	int (*scp_t)(int, int *, ...);
+
+typedef grub_uint16_t uint16_t;
+typedef grub_uint32_t uint32_t;
+
+#define API_SIG_VERSION	1
+#define API_SIG_MAGIC	"UBootAPI"
+#define API_SIG_MAGLEN	8
+
+struct api_signature {
+	char		magic[API_SIG_MAGLEN];	/* magic string */
+	uint16_t	version;		/* API version */
+	uint32_t	checksum;		/* checksum of this sig struct */
+	scp_t		syscall;		/* entry point to the API */
+};
+
+enum {
+	API_RSVD = 0,
+	API_GETC,
+	API_PUTC,
+	API_TSTC,
+	API_PUTS,
+	API_RESET,
+	API_GET_SYS_INFO,
+	API_UDELAY,
+	API_GET_TIMER,
+	API_DEV_ENUM,
+	API_DEV_OPEN,
+	API_DEV_CLOSE,
+	API_DEV_READ,
+	API_DEV_WRITE,
+	API_ENV_ENUM,
+	API_ENV_GET,
+	API_ENV_SET,
+	API_DISPLAY_GET_INFO,
+	API_DISPLAY_DRAW_BITMAP,
+	API_DISPLAY_CLEAR,
+	API_MAXCALL
+};
+
+#define MR_ATTR_FLASH	0x0001
+#define MR_ATTR_DRAM	0x0002
+#define MR_ATTR_SRAM	0x0003
+#define MR_ATTR_MASK	0x000f
+
+struct mem_region {
+	unsigned long	start;
+	unsigned long	size;
+	int		flags;
+};
+
+struct sys_info {
+	unsigned long		clk_bus;
+	unsigned long		clk_cpu;
+	unsigned long		bar;
+	struct mem_region	*mr;
+	int			mr_no;	/* number of memory regions */
+};
+
+#undef CONFIG_SYS_64BIT_LBA
+#ifdef CONFIG_SYS_64BIT_LBA
+typedef	u_int64_t lbasize_t;
+#else
+typedef unsigned long lbasize_t;
+#endif
+typedef unsigned long lbastart_t;
+
+#define DEV_TYP_NONE	0x0000
+#define DEV_TYP_NET	0x0001
+
+#define DEV_TYP_STOR	0x0002
+#define DT_STOR_IDE	0x0010
+#define DT_STOR_SCSI	0x0020
+#define DT_STOR_USB	0x0040
+#define DT_STOR_MMC	0x0080
+#define DT_STOR_SATA	0x0100
+
+#define DEV_STA_CLOSED	0x0000		/* invalid, closed */
+#define DEV_STA_OPEN	0x0001		/* open i.e. active */
+
+struct device_info {
+	int	type;
+	void	*cookie;
+
+	union {
+		struct {
+			lbasize_t	block_count;	/* no of blocks */
+			unsigned long	block_size;	/* size of one block */
+		} storage;
+
+		struct {
+			unsigned char	hwaddr[6];
+		} net;
+	} info;
+#define di_stor info.storage
+#define di_net info.net
+
+	int	state;
+};
+
+#define DISPLAY_TYPE_LCD	0x0001
+#define DISPLAY_TYPE_VIDEO	0x0002
+
+struct display_info {
+	int type;
+	/* screen size in pixels */
+	int pixel_width;
+	int pixel_height;
+	/* screen size in rows and columns of text */
+	int screen_rows;
+	int screen_cols;
+};
+
+#endif /* _API_PUBLIC_H_ */

=== added file 'include/grub/uboot/console.h'
--- include/grub/uboot/console.h	1970-01-01 00:00:00 +0000
+++ include/grub/uboot/console.h	2012-10-22 18:29:17 +0000
@@ -0,0 +1,29 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2012  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_CONSOLE_MACHINE_HEADER
+#define GRUB_CONSOLE_MACHINE_HEADER 1
+
+/* Initialize the console system.  */
+void grub_console_init_early (void);
+void grub_console_init_lately (void);
+
+/* Exit the console system.  */
+void grub_console_fini (void);
+
+#endif /* ! GRUB_CONSOLE_MACHINE_HEADER */

=== added file 'include/grub/uboot/disk.h'
--- include/grub/uboot/disk.h	1970-01-01 00:00:00 +0000
+++ include/grub/uboot/disk.h	2012-10-22 18:29:17 +0000
@@ -0,0 +1,44 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2012  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_UBOOT_DISK_HEADER
+#define GRUB_UBOOT_DISK_HEADER	1
+
+#include <grub/symbol.h>
+#include <grub/disk.h>
+#include <grub/uboot/uboot.h>
+
+void grub_ubootdisk_init (void);
+void grub_ubootdisk_fini (void);
+
+enum disktype
+{ cd, fd, hd };
+
+struct ubootdisk_data
+{
+  struct ubootdisk_data *next;
+  void *cookie;
+  int handle;
+  int opencount;
+  enum disktype type;
+  grub_uint32_t block_size;
+};
+
+grub_err_t grub_ubootdisk_register (struct device_info *newdev, int handle);
+
+#endif /* ! GRUB_UBOOT_DISK_HEADER */

=== added file 'include/grub/uboot/glue.h'
--- include/grub/uboot/glue.h	1970-01-01 00:00:00 +0000
+++ include/grub/uboot/glue.h	2012-10-22 18:29:17 +0000
@@ -0,0 +1,86 @@
+/*
+ * (C) Copyright 2007 Semihalf
+ *
+ * Written by: Rafal Jaworowski <raj@semihalf.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program 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 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+/*
+ * This is the header file for conveniency wrapper routines (API glue)
+ */
+
+#ifndef _API_GLUE_H_
+#define _API_GLUE_H_
+
+#include <grub/uboot/api_public.h>
+typedef grub_uint32_t ulong;
+
+#define API_SEARCH_LEN		(3 * 1024 * 1024)	/* 3MB search range */
+
+#define UB_MAX_MR	5	/* max mem regions number */
+#define UB_MAX_DEV	6	/* max devices number */
+
+extern grub_uint32_t uboot_search_hint;
+
+int	api_search_sig(struct api_signature **sig);
+
+/*
+ * The ub_ library calls are part of the application, not U-Boot code!  They
+ * are front-end wrappers that are used by the consumer application: they
+ * prepare arguments for particular syscall and jump to the low level
+ * syscall()
+ */
+
+/* console */
+int	ub_getc(void);
+int	ub_tstc(void);
+void	ub_putc(char c);
+void	ub_puts(const char *s);
+
+/* system */
+void	EXPORT_FUNC(ub_reset) (void);
+struct sys_info *	ub_get_sys_info(void);
+
+/* time */
+void		ub_udelay(unsigned long);
+unsigned long	ub_get_timer(unsigned long);
+
+/* env vars */
+char *		ub_env_get(const char *name);
+void		ub_env_set(const char *name, char *value);
+const char *	ub_env_enum(const char *last);
+
+/* devices */
+int			ub_dev_enum(void);
+int	EXPORT_FUNC(ub_dev_open)(int handle);
+int	EXPORT_FUNC(ub_dev_close)(int handle);
+int			ub_dev_read(int handle, void *buf, lbasize_t len,
+				lbastart_t start, lbasize_t *rlen);
+int	EXPORT_FUNC(ub_dev_send)(int handle, void *buf, int len);
+int	EXPORT_FUNC(ub_dev_recv)(int handle, void *buf, int len, int *rlen);
+struct device_info *	ub_dev_get(int);
+
+/* display */
+int ub_display_get_info(int type, struct display_info *di);
+int ub_display_draw_bitmap(ulong bitmap, int x, int y);
+void ub_display_clear(void);
+
+#endif /* _API_GLUE_H_ */

=== added file 'include/grub/uboot/uboot.h'
--- include/grub/uboot/uboot.h	1970-01-01 00:00:00 +0000
+++ include/grub/uboot/uboot.h	2012-10-22 18:29:17 +0000
@@ -0,0 +1,41 @@
+/* uboot.h - declare variables and functions for U-Boot support */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2012 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_UBOOT_UBOOT_HEADER
+#define GRUB_UBOOT_UBOOT_HEADER	1
+
+#include <grub/types.h>
+#include <grub/dl.h>
+#include <grub/uboot/glue.h>
+
+/* Functions.  */
+void grub_uboot_mm_init (void);
+void grub_uboot_init (void);
+void grub_uboot_fini (void);
+
+void uboot_return (int) __attribute__ ((noreturn));
+
+grub_err_t grub_uboot_probe_hardware (void);
+
+extern grub_addr_t EXPORT_VAR (start_of_ram);
+
+grub_uint32_t EXPORT_FUNC (uboot_get_machine_type) (void);
+grub_addr_t EXPORT_FUNC (uboot_get_boot_data) (void);
+
+#endif /* ! GRUB_UBOOT_UBOOT_HEADER */

=== modified file 'util/grub-install.in'
--- util/grub-install.in	2012-09-24 17:50:35 +0000
+++ util/grub-install.in	2012-10-22 18:29:17 +0000
@@ -321,6 +321,8 @@
 		    target=i386-pc
 		fi
 		;;
+	    x"arm"*)
+		target="arm-uboot";;
 	    *)
 		gettext "Unable to determine your platform. Use --target." ;
 		echo	;;
@@ -340,7 +342,7 @@
     if [ x$disk_module = xunspecified ]; then
 	disk_module=biosdisk
     fi
-elif [ "${grub_modinfo_platform}" = "ieee1275" ] || [ "${grub_modinfo_platform}" = "efi" ] || [ "${grub_modinfo_platform}" = "arc" ] ; then
+elif [ "${grub_modinfo_platform}" = "ieee1275" ] || [ "${grub_modinfo_platform}" = "efi" ] || [ "${grub_modinfo_platform}" = "arc" ] || [ "${grub_modinfo_platform}" = "uboot" ] ; then
     disk_module=
 else
     disk_module=native

=== modified file 'util/grub-mkimage.c'
--- util/grub-mkimage.c	2012-06-26 01:38:10 +0000
+++ util/grub-mkimage.c	2012-10-22 18:29:17 +0000
@@ -69,7 +69,7 @@
     IMAGE_SPARC64_AOUT, IMAGE_SPARC64_RAW, 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_QEMU_MIPS_FLASH, IMAGE_UBOOT,
   } id;
   enum
     {
@@ -453,6 +453,25 @@
       .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 = 1,
+      .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
+    },
   };
 
 #define grub_target_to_host32(x) (grub_target_to_host32_real (image_target, (x)))
@@ -1626,12 +1645,18 @@
 	core_size = program_size + header_size + footer_size;
       }
       break;
+    case IMAGE_UBOOT:
+      /* Raw image, no header, added below */
+      break;
     }
 
   grub_util_write_image (core_img, core_size, out, outname);
   free (core_img);
   free (kernel_path);
 
+  fflush (out);
+  fsync (fileno (out));
+
   while (path_list)
     {
       next = path_list->next;
@@ -1639,6 +1664,41 @@
       free (path_list);
       path_list = next;
     }
+
+  /* Add U-Boot header using mkimage command */
+  if (image_target->id == IMAGE_UBOOT)
+    {
+      char cmdstr[1024];
+      const char *arch;
+      int retval;
+      
+      if (image_target->elf_target == EM_ARM)
+	{
+	  arch = "ARM";
+	}
+      else
+	{
+	  fprintf(stderr, "%s\n", _("Unsupported U-Boot architecture."));
+	  return;
+	}
+
+      retval = snprintf(cmdstr, sizeof(cmdstr),
+			"mkimage -T kernel -A %s -O Linux -a 0x%08x " \
+			"-e 0x%08x -C none -d %s %s.ubt",
+			arch, (grub_uint32_t)GRUB_KERNEL_ARM_UBOOT_LINK_ADDR,
+			(grub_uint32_t)GRUB_KERNEL_ARM_UBOOT_LINK_ADDR,
+			outname, outname);
+
+      if (retval >= sizeof(cmdstr))
+	{
+	  fprintf(stderr, "%s\n", _("mkimage command line truncated."));
+	  return;
+	}
+
+      retval = system(cmdstr);
+      if (retval != 0)
+	fprintf(stderr, "%s\n", _("mkimage command failed."));
+    }
 }
 
 \f
@@ -1862,7 +1922,6 @@
       if (! fp)
 	grub_util_error (_("cannot open `%s': %s"), arguments.output,
 			 strerror (errno));
-      free (arguments.output);
     }
 
   if (!arguments.dir)
@@ -1882,12 +1941,13 @@
 		  arguments.modules, arguments.memdisk, arguments.config,
 		  arguments.image_target, arguments.note, arguments.comp);
 
-  fflush (fp);
-  fsync (fileno (fp));
   fclose (fp);
 
   if (arguments.dir)
     free (arguments.dir);
 
+  if (arguments.output)
+    free (arguments.output);
+
   return 0;
 }

                 reply	other threads:[~2012-10-22 18:51 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

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

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

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

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

  git send-email \
    --in-reply-to=5085959D.4040407@arm.com \
    --to=leif.lindholm@arm.com \
    --cc=grub-devel@gnu.org \
    /path/to/YOUR_REPLY

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

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