New ports to arm-uboot and arm-efi.

Mostly by Leif Lindholm with some additions from
	Francesco Lavra and cleanup by Vladimir Serbinenko.

	Also-By: Francesco Lavra <francescolavra.fl@gmail.com>

	Also-By: Vladimir Serbinenko <phcoder@gmail.com>
This commit is contained in:
Leif Lindholm 2013-07-18 17:59:14 +02:00 committed by Vladimir 'phcoder' Serbinenko
commit 43d53b72c9
60 changed files with 4653 additions and 12 deletions

View file

@ -206,6 +206,8 @@ po/*.gmo
po/LINGUAS
include/grub/gcrypt/gcrypt.h
include/grub/gcrypt/g10lib.h
grub-core/lib/dtc-grub
grub-core/Makefile.libfdt.def
po/POTFILES.in
po/POTFILES-shell.in
grub-glue-efi

View file

@ -1,3 +1,11 @@
2013-07-18 Leif Lindholm <leif.lindholm@arm.com>
2013-07-18 Francesco Lavra <francescolavra.fl@gmail.com>
2013-07-18 Vladimir Serbinenko <phcoder@gmail.com>
New ports to arm-uboot and arm-efi.
Mostly by Leif Lindholm with some additions from
Francesco Lavra and cleanup by Vladimir Serbinenko.
2013-07-16 Vladimir Serbinenko <phcoder@gmail.com>
* grub-core/loader/multiboot_elfxx.c: Check eip after v2p translation

View file

@ -167,6 +167,8 @@ program = {
common = util/resolve.c;
common = grub-core/kern/emu/argp_common.c;
common = grub-core/kern/arm/dl_helper.c;
extra_dist = util/grub-mkimagexx.c;
ldadd = libgrubmods.a;

View file

@ -432,3 +432,23 @@ dnl program.
AC_DEFUN([grub_TRANSFORM],[dnl
AC_SUBST(AS_TR_SH([$1]), [`AS_ECHO([$1]) | sed "$program_transform_name"`])dnl
])
dnl Check if the C compiler supports `-mno-unaligned-access'.
AC_DEFUN([grub_CHECK_NO_UNALIGNED_ACCESS],[
[# foobar
nua_possible=yes]
AC_MSG_CHECKING([whether `$CC' supports `-mno-unaligned-access'])
AC_LANG_CONFTEST([AC_LANG_SOURCE([[
int main() {
return 0;
}
]])])
[if eval "$ac_compile -S -mno-unaligned-access -o conftest.s" 2> /dev/null; then]
AC_MSG_RESULT([yes])
[rm -f conftest.s
else
nua_possible=no]
AC_MSG_RESULT([no])
[fi]
])

View file

@ -37,6 +37,10 @@ if COND_sparc64_ieee1275
CFLAGS_PLATFORM += -mno-app-regs
LDFLAGS_PLATFORM = -Wl,-melf64_sparc -mno-relax
endif
if COND_arm
CFLAGS_PLATFORM += -mthumb-interwork -mlong-calls
LDFLAGS_PLATFORM = -Wl,--wrap=__clear_cache
endif
# Other options
@ -115,6 +119,8 @@ CPPFLAGS_GNULIB = -I$(top_builddir)/grub-core/gnulib -I$(top_srcdir)/grub-core/g
CFLAGS_POSIX = -fno-builtin
CPPFLAGS_POSIX = -I$(top_srcdir)/grub-core/lib/posix_wrap
CPPFLAGS_LIBFDT = -I$(top_srcdir)/grub-core/lib/dtc-grub/libfdt $(CPPFLAGS_POSIX)
CFLAGS_GCRY = -Wno-error -Wno-missing-field-initializers $(CFLAGS_POSIX)
CPPFLAGS_GCRY = -I$(top_srcdir)/grub-core/lib/libgcrypt_wrap $(CPPFLAGS_POSIX) -D_GCRYPT_IN_LIBGCRYPT=1 -I$(top_srcdir)/include/grub/gcrypt

View file

@ -18,6 +18,7 @@ EXTRA_DIST += conf/i386-pc-cygwin-img-ld.sc
EXTRA_DIST += grub-core/Makefile.core.def
EXTRA_DIST += grub-core/Makefile.gcry.def
EXTRA_DIST += grub-core/Makefile.libfdt.def
EXTRA_DIST += grub-core/genmoddep.awk
EXTRA_DIST += grub-core/genmod.sh.in

View file

@ -96,6 +96,9 @@ case "$target_cpu" in
target_cpu=mips;
machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_CPU_MIPS=1";
;;
arm*)
target_cpu=arm;
;;
esac
# Specify the platform (such as firmware).
@ -116,6 +119,7 @@ if test "x$with_platform" = x; then
mipsel-*) platform=loongson ;;
mips-*) platform=arc ;;
ia64-*) platform=efi ;;
arm-*) platform=uboot ;;
*) AC_MSG_ERROR([unsupported CPU: "$target_cpu"]) ;;
esac
else
@ -151,6 +155,8 @@ case "$target_cpu"-"$platform" in
mipsel-yeeloong) platform=loongson ;;
mipsel-fuloong) platform=loongson ;;
mipsel-loongson) ;;
arm-uboot) ;;
arm-efi) ;;
*-emu) ;;
*) AC_MSG_ERROR([platform "$platform" is not supported for target CPU "$target_cpu"]) ;;
esac
@ -182,6 +188,7 @@ case "$platform" in
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" ;;
@ -190,6 +197,7 @@ case "$platform" in
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
@ -675,6 +683,14 @@ if test x"$sap_possible" = xyes; then
TARGET_CFLAGS="$TARGET_CFLAGS -mno-stack-arg-probe"
fi
# -mno-unaligned-access
if test "$target_cpu" = arm; then
grub_CHECK_NO_UNALIGNED_ACCESS
if test x"$nua_possible" = xyes; then
TARGET_CFLAGS="$TARGET_CFLAGS -mno-unaligned-access"
fi
fi
AC_ARG_ENABLE([werror],
[AS_HELP_STRING([--disable-werror],
[do not use -Werror when building GRUB])])
@ -1160,6 +1176,9 @@ AM_CONDITIONAL([COND_powerpc_ieee1275], [test x$target_cpu = xpowerpc -a x$platf
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_arm_efi], [test x$target_cpu = xarm -a x$platform = xefi])
AM_CONDITIONAL([COND_HOST_HURD], [test x$host_kernel = xhurd])
AM_CONDITIONAL([COND_HOST_LINUX], [test x$host_kernel = xlinux])

View file

@ -3436,6 +3436,7 @@ you forget a command, you can run the command @command{help}
* crc:: Compute or check CRC32 checksums
* cryptomount:: Mount a crypto device
* date:: Display or set current date and time
* devicetree:: Load a device tree blob
* drivemap:: Map a drive to another
* echo:: Display a line of text
* eval:: Evaluate agruments as GRUB commands
@ -3747,6 +3748,17 @@ hour, minute, and second unchanged.
@end deffn
@node devicetree
@subsection linux
@deffn Command devicetree file
Load a device tree blob (.dtb) from a filesystem, for later use by a Linux
kernel. Does not perform merging with any device tree supplied by firmware,
but rather replaces it completely.
@ref{GNU/Linux}.
@end deffn
@node drivemap
@subsection drivemap

View file

@ -23,7 +23,7 @@ GRUB_PLATFORMS = [ "emu", "i386_pc", "i386_efi", "i386_qemu", "i386_coreboot",
"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", "arm_efi" ]
GROUPS = {}
@ -36,10 +36,12 @@ GROUPS["x86"] = GROUPS["i386"] + GROUPS["x86_64"]
GROUPS["mips"] = [ "mips_loongson", "mips_qemu_mips", "mips_arc" ]
GROUPS["sparc64"] = [ "sparc64_ieee1275" ]
GROUPS["powerpc"] = [ "powerpc_ieee1275" ]
GROUPS["arm"] = [ "arm_uboot", "arm_efi" ]
# Groups based on firmware
GROUPS["efi"] = [ "i386_efi", "x86_64_efi", "ia64_efi" ]
GROUPS["efi"] = [ "i386_efi", "x86_64_efi", "ia64_efi", "arm_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 @@ GROUPS["videomodules"] = GRUB_PLATFORMS[:];
for i in GROUPS["videoinkernel"]: GROUPS["videomodules"].remove(i)
# Similar for terminfo
GROUPS["terminfoinkernel"] = [ "emu", "mips_loongson", "mips_arc", "mips_qemu_mips" ] + GROUPS["ieee1275"];
GROUPS["terminfoinkernel"] = [ "emu", "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", "arm_efi" ]
# 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")

View file

@ -203,6 +203,19 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/extcmd.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/lib/arg.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
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/extcmd.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/lib/arg.h
endif
if COND_arm_efi
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/arm/efi/loader.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/efi.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/disk.h
endif
if COND_emu
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/datetime.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/emu/misc.h

View file

@ -59,6 +59,9 @@ kernel = {
ia64_efi_ldflags = '-Wl,-r,-d';
ia64_efi_stripflags = '--strip-unneeded -K start -R .note -R .comment -R .note.gnu.gold-version';
arm_efi_ldflags = '-Wl,-r,-d';
arm_efi_stripflags = '--strip-unneeded -K start -R .note -R .comment -R .note.gnu.gold-version';
i386_pc_ldflags = '$(TARGET_IMG_LDFLAGS)';
i386_pc_ldflags = '$(TARGET_IMG_BASE_LDOPT),0x9000';
@ -81,6 +84,8 @@ kernel = {
i386_qemu_cppflags = '-DGRUB_BOOT_MACHINE_LINK_ADDR=$(GRUB_BOOT_MACHINE_LINK_ADDR)';
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;
@ -92,6 +97,8 @@ kernel = {
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;
arm_efi_startup = kern/arm/efi/startup.S;
common = kern/command.c;
common = kern/corecmd.c;
@ -127,6 +134,12 @@ kernel = {
ieee1275 = term/ieee1275/console.c;
ieee1275 = kern/ieee1275/init.c;
uboot = disk/uboot/ubootdisk.c;
uboot = kern/uboot/uboot.c;
uboot = kern/uboot/init.c;
uboot = kern/uboot/hw.c;
uboot = term/uboot/console.c;
terminfoinkernel = term/terminfo.c;
terminfoinkernel = term/tparm.c;
terminfoinkernel = commands/extcmd.c;
@ -161,6 +174,9 @@ kernel = {
ia64_efi = kern/ia64/dl.c;
ia64_efi = kern/ia64/dl_helper.c;
arm_efi = kern/arm/efi/init.c;
arm_efi = kern/arm/efi/misc.c;
i386_pc = kern/i386/pc/init.c;
i386_pc = kern/i386/pc/mmap.c;
i386_pc = term/i386/pc/console.c;
@ -213,6 +229,13 @@ kernel = {
sparc64_ieee1275 = kern/sparc64/dl.c;
sparc64_ieee1275 = kern/sparc64/ieee1275/ieee1275.c;
arm = kern/arm/dl.c;
arm = kern/arm/dl_helper.c;
arm = kern/arm/cache_armv6.S;
arm = kern/arm/cache_armv7.S;
arm = kern/arm/cache.c;
arm = kern/arm/misc.S;
emu = disk/host.c;
emu = gnulib/progname.c;
emu = kern/emu/error.c;
@ -673,6 +696,8 @@ module = {
enable = powerpc_ieee1275;
enable = mips_arc;
enable = ia64_efi;
enable = arm_efi;
enable = arm_uboot;
};
module = {
@ -753,6 +778,7 @@ module = {
efi = lib/efi/halt.c;
ieee1275 = lib/ieee1275/halt.c;
emu = lib/emu/halt.c;
uboot = lib/uboot/halt.c;
};
module = {
@ -761,11 +787,13 @@ module = {
i386 = lib/i386/reboot_trampoline.S;
ia64_efi = lib/efi/reboot.c;
x86_64_efi = lib/efi/reboot.c;
arm_efi = lib/efi/reboot.c;
powerpc_ieee1275 = lib/ieee1275/reboot.c;
sparc64_ieee1275 = lib/ieee1275/reboot.c;
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;
};
@ -1441,6 +1469,7 @@ module = {
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;
@ -1460,6 +1489,7 @@ module = {
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 = {
@ -1539,6 +1569,8 @@ module = {
powerpc_ieee1275 = loader/powerpc/ieee1275/linux.c;
sparc64_ieee1275 = loader/sparc64/ieee1275/linux.c;
ia64_efi = loader/ia64/efi/linux.c;
arm = loader/arm/linux.c;
arm = lib/fdt.c;
common = loader/linux.c;
common = lib/cmdline.c;
enable = noemu;
@ -1590,6 +1622,7 @@ module = {
enable = x86;
enable = ia64_efi;
enable = arm_efi;
enable = mips;
};
@ -1922,6 +1955,12 @@ module = {
enable = ieee1275;
};
module = {
name = ubootnet;
common = net/drivers/uboot/ubootnet.c;
enable = uboot;
};
module = {
name = efinet;
common = net/drivers/efi/efinet.c;

View file

@ -0,0 +1,299 @@
/* ubootdisk.c - disk subsystem support for U-Boot platforms */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2013 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#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>
#include <grub/uboot/api_public.h>
static struct ubootdisk_data *hd_devices;
static int hd_num;
static int hd_max;
/*
* 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)
{
struct ubootdisk_data *d;
#define STOR_TYPE(x) ((x) & 0x0ff0)
switch (STOR_TYPE (newdev->type))
{
case DT_STOR_IDE:
case DT_STOR_SATA:
case DT_STOR_MMC:
case DT_STOR_USB:
/* hd */
if (hd_num == hd_max)
{
int new_num;
new_num = (hd_max ? hd_max * 2 : 1);
d = grub_realloc(hd_devices,
sizeof (struct ubootdisk_data) * new_num);
if (!d)
return grub_errno;
hd_devices = d;
hd_max = new_num;
}
d = &hd_devices[hd_num];
hd_num++;
break;
default:
return GRUB_ERR_BAD_DEVICE;
break;
}
d->dev = newdev;
d->cookie = newdev->cookie;
d->opencount = 0;
return 0;
}
/*
* uboot_disk_iterate():
* Iterator over enumerated disk devices.
*/
static int
uboot_disk_iterate (grub_disk_dev_iterate_hook_t hook, void *hook_data,
grub_disk_pull_t pull)
{
char buf[16];
int count;
switch (pull)
{
case GRUB_DISK_PULL_NONE:
/* "hd" - built-in mass-storage */
for (count = 0 ; count < hd_num; count++)
{
grub_snprintf (buf, sizeof (buf) - 1, "hd%d", count);
grub_dprintf ("ubootdisk", "iterating %s\n", buf);
if (hook (buf, hook_data))
return 1;
}
break;
default:
return 0;
}
return 0;
}
/* Helper function for uboot_disk_open. */
static struct ubootdisk_data *
get_hd_device (int num)
{
if (num < hd_num)
return &hd_devices[num];
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 'h':
d = get_hd_device (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 = grub_uboot_dev_open (d->dev);
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;
devinfo = d->dev;
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);
if (devinfo->di_stor.block_count)
disk->total_sectors = devinfo->di_stor.block_count;
else
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 = grub_uboot_dev_close (d->dev);
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;
grub_size_t real_size;
int retval;
d = disk->data;
retval = grub_uboot_dev_read (d->dev, 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)))
{
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
"attempt to write (not supported)");
}
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);
}

130
grub-core/kern/arm/cache.S Normal file
View file

@ -0,0 +1,130 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2013 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#include <grub/symbol.h>
.file "cache.S"
.text
.syntax unified
.arm
#if !defined (ARMV6) && !defined (ARMV7)
# error Unsupported architecture version!
#endif
.align 2
/*
* Simple cache maintenance functions
*/
@ r0 - *beg (inclusive)
@ r1 - *end (exclusive)
clean_dcache_range:
@ Clean data cache for range to point-of-unification
ldr r2, =EXT_C(grub_arch_cache_dlinesz)
sub r3, r2, #1 @ align "beg" to start of line
mvn r3, r3
and r0, r0, r3
1: cmp r0, r1
bge 2f
#ifdef ARMV6
mcr p15, 0, r0, c7, c10, 1 @ Clean data cache line by MVA
#else
mcr p15, 0, r0, c7, c11, 1 @ DCCMVAU
#endif
add r0, r0, r2 @ Next line
b 1b
2: DSB
bx lr
@ r0 - *beg (inclusive)
@ r1 - *end (exclusive)
invalidate_icache_range:
@ Invalidate instruction cache for range to point-of-unification
ldr r2, =EXT_C(grub_arch_cache_ilinesz)
sub r3, r2, #1 @ align "beg" to start of line
mvn r3, r3
and r0, r0, r3
1: cmp r0, r1
bge 2f
mcr p15, 0, r0, c7, c5, 1 @ ICIMVAU
add r0, r0, r2 @ Next line
b 1b
@ Branch predictor invalidate all
2: mcr p15, 0, r0, c7, c5, 6 @ BPIALL
DSB
ISB
bx lr
@void grub_arch_sync_caches (void *address, grub_size_t len)
#ifdef ARMV6
FUNCTION(grub_arch_sync_caches_armv6)
#else
FUNCTION(grub_arch_sync_caches_armv7)
#endif
add r1, r0, r1
DSB
push {r0-r1, r4-r6, lr}
ldrdeq r0, r1, [sp]
bl clean_dcache_range
pop {r0, r1}
bl invalidate_icache_range
pop {r4-r6, pc}
#ifdef ARMV6
FUNCTION(grub_arm_disable_caches_mmu_armv6)
#else
FUNCTION(grub_arm_disable_caches_mmu_armv7)
#endif
push {r4, lr}
@ disable D-cache
mrc p15, 0, r0, c1, c0, 0
bic r0, r0, #(1 << 2)
mcr p15, 0, r0, c1, c0, 0
DSB
ISB
@ clean/invalidate D-cache
bl clean_invalidate_dcache
@ disable I-cache
mrc p15, 0, r0, c1, c0, 0
bic r0, r0, #(1 << 12)
mcr p15, 0, r0, c1, c0, 0
DSB
ISB
@ invalidate I-cache (also invalidates branch predictors)
mcr p15, 0, r0, c7, c5, 0
DSB
ISB
@ clear SCTLR M bit
mrc p15, 0, r0, c1, c0, 0
bic r0, r0, #(1 << 0)
mcr p15, 0, r0, c1, c0, 0
mcr p15, 0, r0, c8, c7, 0 @ invalidate TLB
mcr p15, 0, r0, c7, c5, 6 @ invalidate branch predictor
DSB
ISB
pop {r4, pc}

108
grub-core/kern/arm/cache.c Normal file
View file

@ -0,0 +1,108 @@
#include <grub/dl.h>
#include <grub/cache.h>
#include <grub/arm/system.h>
/* This is only about cache architecture. It doesn't imply
the CPU architecture. */
static enum
{
ARCH_UNKNOWN,
ARCH_ARMV6,
ARCH_ARMV6_UNIFIED,
ARCH_ARMV7
} type = ARCH_UNKNOWN;
grub_uint32_t grub_arch_cache_dlinesz;
grub_uint32_t grub_arch_cache_ilinesz;
/* Prototypes for asm functions. */
void grub_arch_sync_caches_armv6 (void *address, grub_size_t len);
void grub_arch_sync_caches_armv7 (void *address, grub_size_t len);
void grub_arm_disable_caches_mmu_armv6 (void);
void grub_arm_disable_caches_mmu_armv7 (void);
static void
probe_caches (void)
{
grub_uint32_t main_id, cache_type;
/* Read main ID Register */
asm volatile ("mrc p15, 0, %0, c0, c0, 0": "=r"(main_id));
if (((main_id >> 16) & 0x7) != 0x7)
grub_fatal ("Unsupported ARM ID 0x%x", main_id);
/* Read Cache Type Register */
asm volatile ("mrc p15, 0, %0, c0, c0, 1": "=r"(cache_type));
switch (cache_type >> 24)
{
case 0x04:
case 0x0a:
case 0x0c:
case 0x0e:
case 0x1c:
grub_arch_cache_dlinesz = 8 << ((cache_type >> 12) & 3);
grub_arch_cache_ilinesz = 8 << (cache_type & 3);
type = ARCH_ARMV6_UNIFIED;
break;
case 0x05:
case 0x0b:
case 0x0d:
case 0x0f:
case 0x1d:
grub_arch_cache_dlinesz = 8 << ((cache_type >> 12) & 3);
grub_arch_cache_ilinesz = 8 << (cache_type & 3);
type = ARCH_ARMV6;
break;
case 0x80 ... 0x8f:
grub_arch_cache_dlinesz = 4 << ((cache_type >> 16) & 0xf);
grub_arch_cache_ilinesz = 4 << (cache_type & 0xf);
type = ARCH_ARMV7;
break;
default:
grub_fatal ("Unsupported cache type 0x%x", cache_type);
}
}
void
grub_arch_sync_caches (void *address, grub_size_t len)
{
if (type == ARCH_UNKNOWN)
probe_caches ();
switch (type)
{
case ARCH_ARMV6:
grub_arch_sync_caches_armv6 (address, len);
break;
case ARCH_ARMV7:
grub_arch_sync_caches_armv7 (address, len);
break;
/* Nothing to do. */
case ARCH_ARMV6_UNIFIED:
break;
/* Pacify GCC. */
case ARCH_UNKNOWN:
break;
}
}
void
grub_arm_disable_caches_mmu (void)
{
if (type == ARCH_UNKNOWN)
probe_caches ();
switch (type)
{
case ARCH_ARMV6_UNIFIED:
case ARCH_ARMV6:
grub_arm_disable_caches_mmu_armv6 ();
break;
case ARCH_ARMV7:
grub_arm_disable_caches_mmu_armv7 ();
break;
/* Pacify GCC. */
case ARCH_UNKNOWN:
break;
}
}

View file

@ -0,0 +1,35 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2013 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#include <grub/symbol.h>
.file "cache_armv6.S"
.text
.syntax unified
.arm
.arch armv6
# define DMB mcr p15, 0, r0, c7, c10, 5
# define DSB mcr p15, 0, r0, c7, c10, 4
# define ISB mcr p15, 0, r0, c7, c5, 4
#define ARMV6 1
clean_invalidate_dcache:
mcr p15, 0, r0, c7, c14, 0 @ Clean/Invalidate D-cache
bx lr
#include "cache.S"

View file

@ -0,0 +1,114 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2013 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#include <grub/symbol.h>
.file "cache_armv7.S"
.text
.syntax unified
.arm
.arch armv7a
# define DMB dmb
# define DSB dsb
# define ISB isb
#define ARMV7 1
@ r0 - CLIDR
@ r1 - LoC
@ r2 - current level
@ r3 - num sets
@ r4 - num ways
@ r5 - current set
@ r6 - current way
@ r7 - line size
@ r8 - scratch
@ r9 - scratch
@ r10 - scratch
@ r11 - scratch
clean_invalidate_dcache:
push {r4-r12, lr}
mrc p15, 1, r0, c0, c0, 1 @ Read CLIDR
lsr r1, r0, #24 @ Extract LoC
and r1, r1, #0x7
mov r2, #0 @ First level, L1
2: and r8, r0, #7 @ cache type at current level
cmp r8, #2
blt 5f @ instruction only, or none, skip level
@ set current cache level/type (for CCSIDR read)
lsl r8, r2, #1
mcr p15, 2, r8, c0, c0, 0 @ Write CSSELR (level, type: data/uni)
@ read current cache information
mrc p15, 1, r8, c0, c0, 0 @ Read CCSIDR
lsr r3, r8, #13 @ Number of sets -1
ldr r9, =0x3fff
and r3, r3, r9
lsr r4, r8, #3 @ Number of ways -1
ldr r9, =0x1ff
and r4, r4, r9
and r7, r8, #7 @ log2(line size in words) - 2
add r7, r7, #2 @ adjust
mov r8, #1
lsl r7, r8, r7 @ -> line size in words
lsl r7, r7, #2 @ -> bytes
@ set loop
mov r5, #0 @ current set = 0
3: lsl r8, r2, #1 @ insert level
clz r9, r7 @ calculate set field offset
mov r10, #31
sub r9, r10, r9
lsl r10, r5, r9
orr r8, r8, r10 @ insert set field
@ way loop
@ calculate way field offset
mov r6, #0 @ current way = 0
add r10, r4, #1
clz r9, r10 @ r9 = way field offset
add r9, r9, #1
4: lsl r10, r6, r9
orr r11, r8, r10 @ insert way field
@ clean and invalidate line by set/way
mcr p15, 0, r11, c7, c14, 2 @ DCCISW
@ next way
add r6, r6, #1
cmp r6, r4
ble 4b
@ next set
add r5, r5, #1
cmp r5, r3
ble 3b
@ next level
5: lsr r0, r0, #3 @ align next level CLIDR 'type' field
add r2, r2, #1 @ increment cache level counter
cmp r2, r1
blt 2b @ outer loop
@ return
6: DSB
ISB
pop {r4-r12, pc}
#include "cache.S"

201
grub-core/kern/arm/dl.c Normal file
View file

@ -0,0 +1,201 @@
/* dl.c - arch-dependent part of loadable module support */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2013 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#include <grub/dl.h>
#include <grub/elf.h>
#include <grub/misc.h>
#include <grub/err.h>
#include <grub/mm.h>
#include <grub/i18n.h>
#include <grub/arm/reloc.h>
/*************************************************
* Runtime dynamic linker with helper functions. *
*************************************************/
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. */
for (seg = mod->segment ; seg ; seg = seg->next)
if (seg->section == relhdr->sh_info)
break;
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_Addr *target, sym_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);
target = (void *) ((grub_addr_t) seg->addr + rel[i].r_offset);
sym_addr = sym[relsym].st_value;
switch (reltype)
{
case R_ARM_ABS32:
{
/* Data will be naturally aligned */
retval = grub_arm_reloc_abs32 (target, sym_addr);
if (retval != GRUB_ERR_NONE)
return retval;
}
break;
case R_ARM_CALL:
case R_ARM_JUMP24:
{
retval = grub_arm_reloc_jump24 (target, sym_addr);
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 = grub_arm_reloc_thm_call ((grub_uint16_t *) target, sym_addr);
if (retval != GRUB_ERR_NONE)
return retval;
}
break;
case R_ARM_THM_JUMP19:
{
/* Thumb instructions can be 16-bit aligned */
retval = grub_arm_reloc_thm_jump19 ((grub_uint16_t *) target, sym_addr);
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"));
#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_dprintf ("dl", "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;
}

View file

@ -0,0 +1,222 @@
/* dl.c - arch-dependent part of loadable module support */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2013 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#include <grub/dl.h>
#include <grub/elf.h>
#include <grub/misc.h>
#include <grub/err.h>
#include <grub/mm.h>
#include <grub/i18n.h>
#include <grub/arm/reloc.h>
/*
* R_ARM_ABS32
*
* Simple relocation of 32-bit value (in literal pool)
*/
grub_err_t
grub_arm_reloc_abs32 (Elf32_Word *target, Elf32_Addr sym_addr)
{
Elf32_Addr tmp;
tmp = grub_le_to_cpu32 (*target);
tmp += sym_addr;
*target = grub_cpu_to_le32 (tmp);
grub_dprintf ("dl", " %s: reloc_abs32 0x%08x => 0x%08x", __FUNCTION__,
(unsigned int) sym_addr, (unsigned int) tmp);
return GRUB_ERR_NONE;
}
/********************************************************************
* Thumb (T32) relocations: *
* *
* 32-bit Thumb instructions can be 16-bit aligned, and are fetched *
* little-endian, requiring some additional fiddling. *
********************************************************************/
/*
* R_ARM_THM_CALL/THM_JUMP24
*
* Relocate Thumb (T32) instruction set relative branches:
* B.W, BL and BLX
*/
grub_err_t
grub_arm_reloc_thm_call (grub_uint16_t *target, Elf32_Addr sym_addr)
{
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 = (grub_le_to_cpu16 (*target) << 16)
| (grub_le_to_cpu16(*(target + 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;
/* If BLX, target symbol must be ARM (target address LSB == 0) */
if (is_blx && (sym_addr & 1))
return grub_error (GRUB_ERR_BAD_MODULE,
N_("Relocation targeting wrong execution state"));
offset_low = -16777216;
offset_high = is_blx ? 16777212 : 16777214;
/* 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 & (1 << 24))
offset -= (1 << 25);
grub_dprintf ("dl", " sym_addr = 0x%08x", sym_addr);
offset += sym_addr;
#ifndef GRUB_UTIL
offset -= (grub_uint32_t) target;
#endif
grub_dprintf("dl", " %s: target=%p, sym_addr=0x%08x, offset=%d\n",
is_blx ? "BLX" : "BL", target, sym_addr, offset);
if ((offset < offset_low) || (offset > offset_high))
return grub_error (GRUB_ERR_BAD_MODULE,
N_("THM_CALL Relocation out of range."));
grub_dprintf ("dl", " relative destination = 0x%08lx",
(unsigned long)target + offset);
/* 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 */
*target = grub_cpu_to_le16 ((insword >> 16) & 0xffff);
*(target + 1) = grub_cpu_to_le16 (insword & 0xffff);
grub_dprintf ("dl", " *insword = 0x%08x", insword);
return GRUB_ERR_NONE;
}
/*
* R_ARM_THM_JUMP19
*
* Relocate conditional Thumb (T32) B<c>.W
*/
grub_err_t
grub_arm_reloc_thm_jump19 (grub_uint16_t *target, Elf32_Addr sym_addr)
{
grub_int32_t offset;
grub_uint32_t insword, insmask;
/* Extract instruction word in alignment-safe manner */
insword = grub_le_to_cpu16 ((*target)) << 16
| grub_le_to_cpu16 (*(target + 1));
insmask = 0xfbc0d000;
/* Extract and sign extend offset */
offset = ((insword >> 26) & 1) << 19
| ((insword >> 11) & 1) << 18
| ((insword >> 13) & 1) << 17
| ((insword >> 16) & 0x3f) << 11
| (insword & 0x7ff);
offset <<= 1;
if (offset & (1 << 20))
offset -= (1 << 21);
/* Adjust and re-truncate offset */
offset += sym_addr;
#ifndef GRUB_UTIL
offset -= (grub_uint32_t) target;
#endif
if ((offset > 1048574) || (offset < -1048576))
return grub_error (GRUB_ERR_BAD_MODULE,
N_("THM_JUMP19 Relocation out of range."));
offset >>= 1;
offset &= 0xfffff;
/* Reassemble instruction word and write back */
insword &= insmask;
insword |= ((offset >> 19) & 1) << 26
| ((offset >> 18) & 1) << 11
| ((offset >> 17) & 1) << 13
| ((offset >> 11) & 0x3f) << 16
| (offset & 0x7ff);
*target = grub_cpu_to_le16 (insword >> 16);
*(target + 1) = grub_cpu_to_le16 (insword & 0xffff);
return GRUB_ERR_NONE;
}
/***********************************************************
* ARM (A32) relocations: *
* *
* ARM instructions are 32-bit in size and 32-bit aligned. *
***********************************************************/
/*
* R_ARM_JUMP24
*
* Relocate ARM (A32) B
*/
grub_err_t
grub_arm_reloc_jump24 (grub_uint32_t *target, Elf32_Addr sym_addr)
{
grub_uint32_t insword;
grub_int32_t offset;
if (sym_addr & 1)
return grub_error (GRUB_ERR_BAD_MODULE,
N_("Relocation targeting wrong execution state"));
insword = grub_le_to_cpu32 (*target);
offset = (insword & 0x00ffffff) << 2;
if (offset & 0x02000000)
offset -= 0x04000000;
offset += sym_addr;
#ifndef GRUB_UTIL
offset -= (grub_uint32_t) target;
#endif
insword &= 0xff000000;
insword |= (offset >> 2) & 0x00ffffff;
*target = grub_cpu_to_le32 (insword);
return GRUB_ERR_NONE;
}

View file

@ -0,0 +1,68 @@
/* init.c - initialize an arm-based EFI system */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2013 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#include <grub/env.h>
#include <grub/kernel.h>
#include <grub/misc.h>
#include <grub/mm.h>
#include <grub/time.h>
#include <grub/efi/efi.h>
/*
* A bit ugly, but functional - and should be completely portable.
*/
static grub_uint64_t
grub_efi_get_time_ms(void)
{
grub_efi_time_t now;
grub_uint64_t retval;
grub_efi_status_t status;
status = efi_call_2 (grub_efi_system_table->runtime_services->get_time,
&now, NULL);
if (status != GRUB_EFI_SUCCESS)
{
grub_printf("No time!\n");
return 0;
}
retval = now.year * 365 * 24 * 60 * 60 * 1000;
retval += now.month * 30 * 24 * 60 * 60 * 1000;
retval += now.day * 24 * 60 * 60 * 1000;
retval += now.hour * 60 * 60 * 1000;
retval += now.minute * 60 * 1000;
retval += now.second * 1000;
retval += now.nanosecond / 1000;
grub_dprintf("timer", "timestamp: 0x%llx\n", retval);
return retval;
}
void
grub_machine_init (void)
{
grub_efi_init ();
grub_install_get_time_ms (grub_efi_get_time_ms);
}
void
grub_machine_fini (void)
{
grub_efi_fini ();
}

View file

@ -0,0 +1,203 @@
/* misc.c - various system functions for an arm-based EFI system */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2013 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#include <grub/misc.h>
#include <grub/mm.h>
#include <grub/cpu/linux.h>
#include <grub/cpu/system.h>
#include <grub/efi/efi.h>
#include <grub/machine/loader.h>
static inline grub_size_t
page_align (grub_size_t size)
{
return (size + (1 << 12) - 1) & (~((1 << 12) - 1));
}
/* Find the optimal number of pages for the memory map. Is it better to
move this code to efi/mm.c? */
static grub_efi_uintn_t
find_mmap_size (void)
{
static grub_efi_uintn_t mmap_size = 0;
if (mmap_size != 0)
return mmap_size;
mmap_size = (1 << 12);
while (1)
{
int ret;
grub_efi_memory_descriptor_t *mmap;
grub_efi_uintn_t desc_size;
mmap = grub_malloc (mmap_size);
if (! mmap)
return 0;
ret = grub_efi_get_memory_map (&mmap_size, mmap, 0, &desc_size, 0);
grub_free (mmap);
if (ret < 0)
{
grub_error (GRUB_ERR_IO, "cannot get memory map");
return 0;
}
else if (ret > 0)
break;
mmap_size += (1 << 12);
}
/* Increase the size a bit for safety, because GRUB allocates more on
later, and EFI itself may allocate more. */
mmap_size += (1 << 12);
return page_align (mmap_size);
}
#define NEXT_MEMORY_DESCRIPTOR(desc, size) \
((grub_efi_memory_descriptor_t *) ((char *) (desc) + (size)))
#define PAGE_SHIFT 12
void *
grub_efi_allocate_loader_memory (grub_uint32_t min_offset, grub_uint32_t size)
{
grub_efi_uintn_t desc_size;
grub_efi_memory_descriptor_t *mmap, *mmap_end;
grub_efi_uintn_t mmap_size, tmp_mmap_size;
grub_efi_memory_descriptor_t *desc;
void *mem = NULL;
grub_addr_t min_start = 0;
mmap_size = find_mmap_size();
if (!mmap_size)
return NULL;
mmap = grub_malloc(mmap_size);
if (!mmap)
return NULL;
tmp_mmap_size = mmap_size;
if (grub_efi_get_memory_map (&tmp_mmap_size, mmap, 0, &desc_size, 0) <= 0)
{
grub_error (GRUB_ERR_IO, "cannot get memory map");
goto fail;
}
mmap_end = NEXT_MEMORY_DESCRIPTOR (mmap, tmp_mmap_size);
/* Find lowest accessible RAM location */
{
int found = 0;
for (desc = mmap ; !found && (desc < mmap_end) ;
desc = NEXT_MEMORY_DESCRIPTOR(desc, desc_size))
{
switch (desc->type)
{
case GRUB_EFI_CONVENTIONAL_MEMORY:
case GRUB_EFI_LOADER_CODE:
case GRUB_EFI_LOADER_DATA:
min_start = desc->physical_start + min_offset;
found = 1;
break;
default:
break;
}
}
}
/* First, find free pages for the real mode code
and the memory map buffer. */
for (desc = mmap ; desc < mmap_end ;
desc = NEXT_MEMORY_DESCRIPTOR(desc, desc_size))
{
grub_uint64_t start, end;
grub_dprintf("mm", "%s: 0x%08x bytes @ 0x%08x\n",
__FUNCTION__,
(grub_uint32_t) (desc->num_pages << PAGE_SHIFT),
(grub_uint32_t) (desc->physical_start));
if (desc->type != GRUB_EFI_CONVENTIONAL_MEMORY)
continue;
start = desc->physical_start;
end = start + (desc->num_pages << PAGE_SHIFT);
grub_dprintf("mm", "%s: start=0x%016llx, end=0x%016llx\n",
__FUNCTION__, start, end);
start = start < min_start ? min_start : start;
if (start + size > end)
continue;
grub_dprintf("mm", "%s: let's allocate some (0x%x) pages @ 0x%08x...\n",
__FUNCTION__, (size >> PAGE_SHIFT), (grub_addr_t) start);
mem = grub_efi_allocate_pages (start, (size >> PAGE_SHIFT) + 1);
grub_dprintf("mm", "%s: retval=0x%08x\n",
__FUNCTION__, (grub_addr_t) mem);
if (! mem)
{
grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate memory");
goto fail;
}
break;
}
if (! mem)
{
grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate memory");
goto fail;
}
grub_free (mmap);
return mem;
fail:
grub_free (mmap);
return NULL;
}
grub_err_t
grub_efi_prepare_platform (void)
{
grub_efi_uintn_t mmap_size;
grub_efi_uintn_t map_key;
grub_efi_uintn_t desc_size;
grub_efi_uint32_t desc_version;
grub_efi_memory_descriptor_t *mmap_buf;
grub_err_t err;
/*
* Cloned from IA64
* Must be done after grub_machine_fini because map_key is used by
*exit_boot_services.
*/
mmap_size = find_mmap_size ();
if (! mmap_size)
return GRUB_ERR_OUT_OF_MEMORY;
mmap_buf = grub_efi_allocate_pages (0, page_align (mmap_size) >> 12);
if (! mmap_buf)
return GRUB_ERR_OUT_OF_MEMORY;
err = grub_efi_finish_boot_services (&mmap_size, mmap_buf, &map_key,
&desc_size, &desc_version);
if (err != GRUB_ERR_NONE)
return err;
grub_arm_disable_caches_mmu();
return GRUB_ERR_NONE;
}

View file

@ -0,0 +1,38 @@
/*
* (C) Copyright 2013 Free Software Foundation
*
* 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/symbol.h>
.file "startup.S"
.text
.arm
FUNCTION(_start)
/*
* EFI_SYSTEM_TABLE and EFI_HANDLE are passed in r1/r0.
*/
ldr ip, =EXT_C(grub_efi_image_handle)
str r0, [ip]
ldr ip, =EXT_C(grub_efi_system_table)
str r1, [ip]
ldr ip, =EXT_C(grub_main)
bx ip
.thumb @ For relocation debugging
blx _start
.end

44
grub-core/kern/arm/misc.S Normal file
View file

@ -0,0 +1,44 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2013 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#include <grub/symbol.h>
#include <grub/dl.h>
.file "misc.S"
.text
.syntax unified
#if !defined (__thumb2__)
.arm
#define ARM(x...) x
#define THUMB(x...)
#else
.thumb
#define THUMB(x...) x
#define ARM(x...)
#endif
.align 2
/*
* Null divide-by-zero handler
*/
FUNCTION(raise)
mov r0, #0
bx lr
.end

View file

@ -0,0 +1,169 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2013 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#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).
* <stack>:
* <modules>:
* Loadable modules, post relocation.
* <heap>:
*/
.text
.arm
FUNCTION(_start)
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)
ldr r12, =EXT_C(grub_uboot_machine_type)
str r1, [r12]
ldr r12, =EXT_C(grub_uboot_boot_data)
str r2, [r12]
@ Modules have been stored as a blob in BSS,
@ they need to be manually relocated to _end
ldr r0, =EXT_C(__bss_start) @ src
add r0, r0, #(GRUB_KERNEL_MACHINE_MOD_ALIGN - 1)
mvn r1, #(GRUB_KERNEL_MACHINE_MOD_ALIGN - 1)
and r0, r0, r1
ldr r1, =EXT_C(_end) @ dst = End of BSS
ldr r2, grub_total_module_size @ blob size
add r1, r1, #GRUB_KERNEL_MACHINE_STACK_SIZE
and r1, r1, #~0x7 @ Ensure 8-byte alignment
sub sp, r1, #8
add r1, r1, #1024
ldr r12, =EXT_C(grub_modbase)
str r1, [r12]
add r1, r1, r2
add r0, r0, r2
sub r1, r1, #4
sub r0, r0, #4
1: ldr r3, [r0], #-4 @ r3 = *src--
str r3, [r1], #-4 @ *dst-- = r3
subs r2, #4 @ remaining -= 4
bne 1b @ while remaining != 0
@ Since we _are_ the C run-time, we need to manually zero the BSS
@ region before continuing
ldr r0, =EXT_C(__bss_start) @ zero from here
@ If unaligned, bytewise zero until base address aligned.
mov r2, #0
1: tst r0, #3
beq 2f
strb r2, [r0], #1
b 1b
2: ldr r1, =EXT_C(_end) @ to here
1: str r2, [r0], #4
cmp r0, r1
bne 1b
b EXT_C(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(grub_uboot_syscall)
ldr ip, =transition_space
stm ip, {r8, lr}
ldr ip, =gd_backup
ldr r8, [ip]
ldr ip, =grub_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(grub_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(grub_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(grub_uboot_syscall_ptr)
.long 0 @
.end

112
grub-core/kern/uboot/hw.c Normal file
View file

@ -0,0 +1,112 @@
/* hw.c - U-Boot hardware discovery */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2013 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#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>
#include <grub/uboot/api_public.h>
grub_addr_t start_of_ram;
/*
* 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 = grub_uboot_get_sys_info ();
grub_mm_init_region ((void *) grub_modules_get_end (),
GRUB_KERNEL_MACHINE_HEAP_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 = grub_uboot_dev_enum ();
grub_dprintf ("init", "%d devices found\n", devcount);
for (i = 0; i < devcount; i++)
{
struct device_info *devinfo = grub_uboot_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);
}
else if (devinfo->type & DEV_TYP_NET)
{
/* Dealt with in ubootnet module. */
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, void *hook_data)
{
int i;
struct sys_info *si = grub_uboot_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,
hook_data);
return GRUB_ERR_NONE;
}

157
grub-core/kern/uboot/init.c Normal file
View file

@ -0,0 +1,157 @@
/* init.c - generic U-Boot initialization and finalization */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2013 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#include <grub/env.h>
#include <grub/kernel.h>
#include <grub/misc.h>
#include <grub/mm.h>
#include <grub/offsets.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>
#include <grub/uboot/api_public.h>
extern char __bss_start[];
extern char _end[];
extern grub_size_t grub_total_module_size;
extern int (*grub_uboot_syscall_ptr) (int, int *, ...);
/* Set to anything other than zero so it lands in .data and not .bss. */
grub_addr_t grub_modbase = 0x55aa55aa;
grub_uint32_t grub_uboot_machine_type = 0x55aa55aa;
grub_addr_t grub_uboot_boot_data = 0x55aa55aa;
static unsigned long timer_start;
void
grub_exit (void)
{
grub_uboot_return (0);
}
grub_uint32_t
grub_uboot_get_machine_type (void)
{
return grub_uboot_machine_type;
}
grub_addr_t
grub_uboot_get_boot_data (void)
{
return grub_uboot_boot_data;
}
static grub_uint64_t
uboot_timer_ms (void)
{
return (grub_uint64_t) grub_uboot_get_timer (timer_start) / 1000;
}
void
grub_machine_init (void)
{
int ver;
/* First of all - establish connection with U-Boot */
ver = grub_uboot_api_init ();
if (!ver)
{
/* Don't even have a console to log errors to... */
grub_exit ();
}
else if (ver > API_SIG_VERSION)
{
/* Try to print an error message */
grub_uboot_puts ("invalid U-Boot API version\n");
}
/* Initialize the console so that GRUB can display messages. */
grub_console_init_early ();
/* Enumerate memory and initialize the memory management system. */
grub_uboot_mm_init ();
grub_dprintf ("init", "__bss_start: %p\n", __bss_start);
grub_dprintf ("init", "_end: %p\n", _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 ());
/* Initialise full terminfo support */
grub_console_init_lately ();
/* Enumerate uboot devices */
grub_uboot_probe_hardware ();
/* Initialise timer */
timer_start = grub_uboot_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 = grub_uboot_env_get ("grub_bootdev");
if (tmp)
{
*device = grub_strdup (tmp);
if (*device == NULL)
return;
}
else
*device = NULL;
tmp = grub_uboot_env_get ("grub_bootpath");
if (tmp)
{
*path = grub_strdup (tmp);
if (*path == NULL)
return;
}
else
*path = NULL;
}
void
grub_uboot_fini (void)
{
grub_ubootdisk_fini ();
grub_console_fini ();
}

View file

@ -0,0 +1,326 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2013 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#include <grub/misc.h>
#include <grub/mm.h>
#include <grub/uboot/api_public.h>
#include <grub/uboot/uboot.h>
/*
* The main syscall entry point is not reentrant, only one call is
* serviced until finished.
*
* int syscall(int call, int *retval, ...)
* e.g. syscall(1, int *, u_int32_t, u_int32_t, u_int32_t, u_int32_t);
*
* call: syscall number
*
* retval: points to the return value placeholder, this is the place the
* syscall puts its return value, if NULL the caller does not
* expect a return value
*
* ... syscall arguments (variable number)
*
* returns: 0 if the call not found, 1 if serviced
*/
extern int (*grub_uboot_syscall_ptr) (int, int *, ...);
extern int grub_uboot_syscall (int, int *, ...);
extern grub_addr_t grub_uboot_search_hint;
static struct sys_info uboot_sys_info;
static struct mem_region uboot_mem_info[5];
static struct device_info * devices;
static int num_devices;
int
grub_uboot_api_init (void)
{
struct api_signature *start, *end;
struct api_signature *p;
if (grub_uboot_search_hint)
{
/* Extended search range to work around Trim Slice U-Boot issue */
start = (struct api_signature *) ((grub_uboot_search_hint & ~0x000fffff)
- 0x00500000);
end =
(struct api_signature *) ((grub_addr_t) start + UBOOT_API_SEARCH_LEN -
API_SIG_MAGLEN + 0x00500000);
}
else
{
start = 0;
end = (struct api_signature *) (256 * 1024 * 1024);
}
/* Structure alignment is (at least) 8 bytes */
for (p = start; p < end; p = (void *) ((grub_addr_t) p + 8))
{
if (grub_memcmp (&(p->magic), API_SIG_MAGIC, API_SIG_MAGLEN) == 0)
{
grub_uboot_syscall_ptr = p->syscall;
return p->version;
}
}
return 0;
}
/*
* All functions below are wrappers around the grub_uboot_syscall() function
*/
int
grub_uboot_getc (void)
{
int c;
if (!grub_uboot_syscall (API_GETC, NULL, &c))
return -1;
return c;
}
int
grub_uboot_tstc (void)
{
int c;
if (!grub_uboot_syscall (API_TSTC, NULL, &c))
return -1;
return c;
}
void
grub_uboot_putc (int c)
{
grub_uboot_syscall (API_PUTC, NULL, &c);
}
void
grub_uboot_puts (const char *s)
{
grub_uboot_syscall (API_PUTS, NULL, s);
}
void
grub_uboot_reset (void)
{
grub_uboot_syscall (API_RESET, NULL, 0);
}
struct sys_info *
grub_uboot_get_sys_info (void)
{
int retval;
grub_memset (&uboot_sys_info, 0, sizeof (uboot_sys_info));
grub_memset (&uboot_mem_info, 0, sizeof (uboot_mem_info));
uboot_sys_info.mr = uboot_mem_info;
uboot_sys_info.mr_no = sizeof (uboot_mem_info) / sizeof (struct mem_region);
if (grub_uboot_syscall (API_GET_SYS_INFO, &retval, &uboot_sys_info))
if (retval == 0)
return &uboot_sys_info;
return NULL;
}
void
grub_uboot_udelay (grub_uint32_t usec)
{
grub_uboot_syscall (API_UDELAY, NULL, &usec);
}
grub_uint32_t
grub_uboot_get_timer (grub_uint32_t base)
{
grub_uint32_t current;
if (!grub_uboot_syscall (API_GET_TIMER, NULL, &current, &base))
return 0;
return current;
}
int
grub_uboot_dev_enum (void)
{
struct device_info * enum_devices;
int num_enum_devices, max_devices;
if (num_devices)
return num_devices;
max_devices = 2;
enum_devices = grub_malloc (sizeof(struct device_info) * max_devices);
if (!enum_devices)
return 0;
/*
* The API_DEV_ENUM call starts a fresh enumeration when passed a
* struct device_info with a NULL cookie, and then depends on having
* the previously enumerated device cookie "seeded" into the target
* structure.
*/
enum_devices[0].cookie = NULL;
num_enum_devices = 0;
if (grub_uboot_syscall (API_DEV_ENUM, NULL,
&enum_devices[num_enum_devices]) == 0)
goto error;
num_enum_devices++;
while (enum_devices[num_enum_devices - 1].cookie != NULL)
{
if (num_enum_devices == max_devices)
{
struct device_info *tmp;
int new_max;
new_max = max_devices * 2;
tmp = grub_realloc (enum_devices,
sizeof (struct device_info) * new_max);
if (!tmp)
{
/* Failed to realloc, so return what we have */
break;
}
enum_devices = tmp;
max_devices = new_max;
}
enum_devices[num_enum_devices].cookie =
enum_devices[num_enum_devices - 1].cookie;
if (grub_uboot_syscall (API_DEV_ENUM, NULL,
&enum_devices[num_enum_devices]) == 0)
goto error;
if (enum_devices[num_enum_devices].cookie == NULL)
break;
num_enum_devices++;
}
devices = enum_devices;
return num_devices = num_enum_devices;
error:
grub_free (enum_devices);
return 0;
}
#define VALID_DEV(x) (((x) < num_devices) && ((x) >= 0))
#define OPEN_DEV(x) ((x->state == DEV_STA_OPEN))
struct device_info *
grub_uboot_dev_get (int index)
{
if (VALID_DEV (index))
return &devices[index];
return NULL;
}
int
grub_uboot_dev_open (struct device_info *dev)
{
int retval;
if (!grub_uboot_syscall (API_DEV_OPEN, &retval, dev))
return -1;
return retval;
}
int
grub_uboot_dev_close (struct device_info *dev)
{
int retval;
if (!grub_uboot_syscall (API_DEV_CLOSE, &retval, dev))
return -1;
return retval;
}
int
grub_uboot_dev_read (struct device_info *dev, void *buf, grub_size_t blocks,
grub_uint32_t start, grub_size_t * real_blocks)
{
int retval;
if (!OPEN_DEV (dev))
return -1;
if (!grub_uboot_syscall (API_DEV_READ, &retval, dev, buf,
&blocks, &start, real_blocks))
return -1;
return retval;
}
int
grub_uboot_dev_recv (struct device_info *dev, void *buf,
int size, int *real_size)
{
int retval;
if (!OPEN_DEV (dev))
return -1;
if (!grub_uboot_syscall (API_DEV_READ, &retval, dev, buf, &size, real_size))
return -1;
return retval;
}
int
grub_uboot_dev_send (struct device_info *dev, void *buf, int size)
{
int retval;
if (!OPEN_DEV (dev))
return -1;
if (!grub_uboot_syscall (API_DEV_WRITE, &retval, dev, buf, &size))
return -1;
return retval;
}
char *
grub_uboot_env_get (const char *name)
{
char *value;
if (!grub_uboot_syscall (API_ENV_GET, NULL, name, &value))
return NULL;
return value;
}
void
grub_uboot_env_set (const char *name, const char *value)
{
grub_uboot_syscall (API_ENV_SET, NULL, name, value);
}

View file

@ -0,0 +1,42 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2013 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#include <grub/symbol.h>
.file "setjmp.S"
.syntax unified
.arm
.text
/*
* int grub_setjmp (grub_jmp_buf env)
*/
FUNCTION(grub_setjmp)
stm r0, { r4-r11, sp, lr }
mov r0, #0
bx lr
/*
* int grub_longjmp (grub_jmp_buf env, int val)
*/
FUNCTION(grub_longjmp)
ldm r0, { r4-r11, sp, lr }
movs r0, r1
moveq r0, #1
bx lr

View file

@ -28,7 +28,7 @@ void
grub_halt (void)
{
grub_machine_fini ();
#ifndef __ia64__
#if !defined(__ia64__) && !defined(__arm__)
grub_acpi_halt ();
#endif
efi_call_4 (grub_efi_system_table->runtime_services->reset_system,

389
grub-core/lib/fdt.c Normal file
View file

@ -0,0 +1,389 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2013 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#include <grub/fdt.h>
#include <grub/misc.h>
#include <grub/mm.h>
#define FDT_SUPPORTED_VERSION 17
#define FDT_BEGIN_NODE 0x00000001
#define FDT_END_NODE 0x00000002
#define FDT_PROP 0x00000003
#define FDT_NOP 0x00000004
#define FDT_END 0x00000009
#define struct_end(fdt) \
((grub_addr_t) fdt + grub_fdt_get_off_dt_struct(fdt) \
+ grub_fdt_get_size_dt_struct(fdt))
/* Size needed by a node entry: 2 tokens (FDT_BEGIN_NODE and FDT_END_NODE), plus
the NULL-terminated string containing the name, plus padding if needed. */
#define node_entry_size(node_name) \
(2 * sizeof(grub_uint32_t) \
+ ALIGN_UP (grub_strlen (name) + 1, sizeof(grub_uint32_t)))
/* Size needed by a property entry: 1 token (FDT_PROPERTY), plus len and nameoff
fields, plus the property value, plus padding if needed. */
#define prop_entry_size(prop_len) \
(3 * sizeof(grub_uint32_t) + ALIGN_UP(prop_len, sizeof(grub_uint32_t)))
static grub_uint32_t *get_next_node (const void *fdt, char *node_name)
{
grub_uint32_t *end = (void *) struct_end (fdt);
grub_uint32_t *token;
if (node_name >= (char *) end)
return NULL;
while (*node_name)
{
if (++node_name >= (char *) end)
return NULL;
}
token = (grub_uint32_t *) ALIGN_UP ((grub_addr_t) node_name, 4);
while (token < end)
{
switch (grub_be_to_cpu32(*token))
{
case FDT_BEGIN_NODE:
token = get_next_node (fdt, (char *) (token + 1));
if (!token)
return NULL;
break;
case FDT_END_NODE:
token++;
if (token >= end)
return NULL;
return token;
case FDT_PROP:
/* Skip property token and following data (len, nameoff and property
value). */
token += 3 + grub_be_to_cpu32 (*(token + 1));
break;
case FDT_NOP:
token++;
break;
default:
return NULL;
}
}
return NULL;
}
static int get_mem_rsvmap_size (const void *fdt)
{
int size = 0;
grub_uint64_t *ptr = (void *) ((grub_addr_t) fdt
+ grub_fdt_get_off_mem_rsvmap (fdt));
do
{
size += 2 * sizeof(*ptr);
if (!*ptr && !*(ptr + 1))
return size;
ptr += 2;
} while ((grub_addr_t) ptr <= (grub_addr_t) fdt + grub_fdt_get_totalsize (fdt)
- 2 * sizeof(grub_uint64_t));
return -1;
}
static grub_uint32_t get_free_space (void *fdt)
{
int mem_rsvmap_size = get_mem_rsvmap_size (fdt);
if (mem_rsvmap_size < 0)
/* invalid memory reservation block */
return 0;
return (grub_fdt_get_totalsize (fdt) - sizeof(grub_fdt_header_t)
- mem_rsvmap_size - grub_fdt_get_size_dt_strings (fdt)
- grub_fdt_get_size_dt_struct (fdt));
}
static int add_subnode (void *fdt, int parentoffset, const char *name)
{
grub_uint32_t *begin = (void *) ((grub_addr_t) fdt
+ grub_fdt_get_off_dt_struct(fdt)
+ parentoffset);
grub_uint32_t *end = (void *) struct_end (fdt);
unsigned int entry_size = node_entry_size (name);
grub_uint32_t *token = begin;
/* Insert the new subnode just after the properties of the parent node (if
any).*/
while (1)
{
if (token >= end)
return -1;
switch (grub_be_to_cpu32(*token))
{
case FDT_PROP:
/* Skip len and nameoff. */
token += 2;
break;
case FDT_BEGIN_NODE:
case FDT_END_NODE:
goto insert;
case FDT_NOP:
break;
default:
/* invalid token */
return -1;
}
token++;
}
insert:
grub_memmove (token + entry_size, token,
(grub_addr_t) end - (grub_addr_t) token);
*token = grub_cpu_to_be32(FDT_BEGIN_NODE);
token[entry_size / sizeof(*token) - 2] = 0; /* padding bytes */
grub_strcpy((char *) (token + 1), name);
token += entry_size / sizeof(*token) - 1;
*token = grub_cpu_to_be32(FDT_END_NODE);
return ((grub_addr_t) token - (grub_addr_t) fdt
- grub_fdt_get_off_dt_struct(fdt));
}
/* Rearrange FDT blocks in the canonical order: first the memory reservation
block (just after the FDT header), then the structure block and finally the
strings block. No free space is left between the first and the second block,
while the space between the second and the third block is given by the
clearance argument. */
static int rearrange_blocks (void *fdt, unsigned int clearance)
{
grub_uint32_t off_mem_rsvmap = ALIGN_UP(sizeof(grub_fdt_header_t), 8);
grub_uint32_t off_dt_struct = off_mem_rsvmap + get_mem_rsvmap_size (fdt);
grub_uint32_t off_dt_strings = off_dt_struct
+ grub_fdt_get_size_dt_struct (fdt)
+ clearance;
grub_uint8_t *fdt_ptr = fdt;
grub_uint8_t *tmp_fdt;
if ((grub_fdt_get_off_mem_rsvmap (fdt) == off_mem_rsvmap)
&& (grub_fdt_get_off_dt_struct (fdt) == off_dt_struct))
{
/* No need to allocate memory for a temporary FDT, just move the strings
block if needed. */
if (grub_fdt_get_off_dt_strings (fdt) != off_dt_strings)
grub_memmove(fdt_ptr + off_dt_strings,
fdt_ptr + grub_fdt_get_off_dt_strings (fdt),
grub_fdt_get_size_dt_strings (fdt));
return 0;
}
tmp_fdt = grub_malloc (grub_fdt_get_totalsize (fdt));
if (!tmp_fdt)
return -1;
grub_memcpy (tmp_fdt + off_mem_rsvmap,
fdt_ptr + grub_fdt_get_off_mem_rsvmap (fdt),
get_mem_rsvmap_size (fdt));
grub_fdt_set_off_mem_rsvmap (fdt, off_mem_rsvmap);
grub_memcpy (tmp_fdt + off_dt_struct,
fdt_ptr + grub_fdt_get_off_dt_struct (fdt),
grub_fdt_get_size_dt_struct (fdt));
grub_fdt_set_off_dt_struct (fdt, off_dt_struct);
grub_memcpy (tmp_fdt + off_dt_strings,
fdt_ptr + grub_fdt_get_off_dt_strings (fdt),
grub_fdt_get_size_dt_strings (fdt));
grub_fdt_set_off_dt_strings (fdt, off_dt_strings);
/* Copy reordered blocks back to fdt. */
memcpy (fdt_ptr + off_mem_rsvmap, tmp_fdt + off_mem_rsvmap,
grub_fdt_get_totalsize (fdt) - off_mem_rsvmap);
grub_free(tmp_fdt);
return 0;
}
static grub_uint32_t *find_prop (void *fdt, unsigned int nodeoffset,
const char *name)
{
grub_uint32_t *prop = (void *) ((grub_addr_t) fdt
+ grub_fdt_get_off_dt_struct (fdt)
+ nodeoffset);
grub_uint32_t nameoff;
do
{
if (grub_be_to_cpu32(*prop) == FDT_PROP)
{
nameoff = grub_be_to_cpu32(*(prop + 2));
if ((nameoff + grub_strlen (name) < grub_fdt_get_size_dt_strings (fdt))
&& !grub_strcmp (name, (char *) fdt +
grub_fdt_get_off_dt_strings (fdt) + nameoff))
return prop;
prop += prop_entry_size(grub_be_to_cpu32(*prop + 1)) / sizeof (*prop);
}
else if (grub_be_to_cpu32(*prop) != FDT_NOP)
return NULL;
prop++;
} while ((grub_addr_t) prop < ((grub_addr_t) fdt
+ grub_fdt_get_off_dt_struct (fdt)
+ grub_fdt_get_size_dt_struct (fdt)));
return NULL;
}
/* Check the FDT header for consistency and adjust the totalsize field to match
the size allocated for the FDT; if this function is called before the other
functions in this file and returns success, the other functions are
guaranteed not to access memory locations outside the allocated memory. */
int grub_fdt_check_header (void *fdt, unsigned int size)
{
if (((grub_addr_t) fdt & 0x7) || (grub_fdt_get_magic (fdt) != FDT_MAGIC)
|| (grub_fdt_get_totalsize (fdt) > size)
|| (grub_fdt_get_version (fdt) < FDT_SUPPORTED_VERSION)
|| (grub_fdt_get_last_comp_version (fdt) > FDT_SUPPORTED_VERSION)
|| (grub_fdt_get_off_dt_struct (fdt) & 0x00000003)
|| (grub_fdt_get_size_dt_struct (fdt) & 0x00000003)
|| (grub_fdt_get_off_dt_struct (fdt) + grub_fdt_get_size_dt_struct (fdt)
> grub_fdt_get_totalsize (fdt))
|| (grub_fdt_get_off_dt_strings (fdt) + grub_fdt_get_size_dt_strings (fdt)
> grub_fdt_get_totalsize (fdt))
|| (grub_fdt_get_off_mem_rsvmap (fdt) & 0x00000007)
|| (grub_fdt_get_off_mem_rsvmap (fdt)
> grub_fdt_get_totalsize (fdt) - 2 * sizeof(grub_uint64_t)))
return -1;
return 0;
}
/* Find a direct sub-node of a given parent node. */
int grub_fdt_find_subnode (const void *fdt, unsigned int parentoffset,
const char *name)
{
grub_uint32_t *token, *end;
char *node_name;
if (parentoffset & 0x3)
return -1;
token = (void *) ((grub_addr_t) fdt + grub_fdt_get_off_dt_struct(fdt)
+ parentoffset);
end = (void *) struct_end (fdt);
while (token < end)
{
switch (grub_be_to_cpu32(*token))
{
case FDT_BEGIN_NODE:
node_name = (char *) (token + 1);
if (node_name + grub_strlen (name) >= (char *) end)
return -1;
if (!grub_strcmp (node_name, name))
return (int) ((grub_addr_t) token
+ ALIGN_UP(grub_strlen (name) + 1, 4)
- grub_fdt_get_off_dt_struct (fdt));
token = get_next_node (fdt, node_name);
if (!token)
return -1;
break;
case FDT_END_NODE:
return -1;
case FDT_PROP:
/* Skip property token and following data (len, nameoff and property
value). */
token += 3 + grub_be_to_cpu32 (*(token + 1));
break;
case FDT_NOP:
token++;
break;
default:
return -1;
}
}
return -1;
}
int grub_fdt_add_subnode (void *fdt, unsigned int parentoffset,
const char *name)
{
unsigned int entry_size = node_entry_size(name);
if ((parentoffset & 0x3) || (get_free_space (fdt) < entry_size))
return -1;
/* The new node entry will increase the size of the structure block: rearrange
blocks such that there is sufficient free space between the structure and
the strings block, then add the new node entry. */
if (rearrange_blocks (fdt, entry_size) < 0)
return -1;
return add_subnode (fdt, parentoffset, name);
}
int grub_fdt_set_prop (void *fdt, unsigned int nodeoffset, const char *name,
const void *val, grub_uint32_t len)
{
grub_uint32_t *prop;
int prop_name_present = 0;
grub_uint32_t nameoff = 0;
if ((nodeoffset >= grub_fdt_get_size_dt_struct (fdt)) || (nodeoffset & 0x3))
return -1;
prop = find_prop (fdt, nodeoffset, name);
if (prop)
{
grub_uint32_t prop_len = ALIGN_UP(grub_be_to_cpu32 (*(prop + 1)),
sizeof(grub_uint32_t));
grub_uint32_t i;
prop_name_present = 1;
for (i = 0; i < prop_len / sizeof(grub_uint32_t); i++)
*(prop + 3 + i) = grub_cpu_to_be32 (FDT_NOP);
if (len > prop_len)
{
/* Length of new property value is greater than the space allocated
for the current value: a new entry needs to be created, so save the
nameoff field of the current entry and replace the current entry
with NOP tokens. */
nameoff = grub_be_to_cpu32 (*(prop + 2));
*prop = *(prop + 1) = *(prop + 2) = grub_cpu_to_be32 (FDT_NOP);
prop = NULL;
}
}
if (!prop || !prop_name_present) {
unsigned int needed_space = 0;
if (!prop)
needed_space = prop_entry_size(len);
if (!prop_name_present)
needed_space += grub_strlen (name) + 1;
if (needed_space > get_free_space (fdt))
return -1;
if (rearrange_blocks (fdt, !prop ? prop_entry_size(len) : 0) < 0)
return -1;
}
if (!prop_name_present) {
/* Append the property name at the end of the strings block. */
nameoff = grub_fdt_get_size_dt_strings (fdt);
grub_strcpy ((char *) fdt + grub_fdt_get_off_dt_strings (fdt) + nameoff,
name);
grub_fdt_set_size_dt_strings (fdt, grub_fdt_get_size_dt_strings (fdt)
+ grub_strlen (name) + 1);
}
if (!prop) {
prop = (void *) ((grub_addr_t) fdt + grub_fdt_get_off_dt_struct (fdt)
+ nodeoffset);
grub_memmove (prop + prop_entry_size(len), prop,
grub_fdt_get_size_dt_struct (fdt) - nodeoffset);
*prop = grub_cpu_to_be32 (FDT_PROP);
*(prop + 1) = grub_cpu_to_be32 (len);
*(prop + 2) = grub_cpu_to_be32 (nameoff);
/* Insert padding bytes at the end of the value; if they are not needed,
they will be overwritten by the follozing memcpy. */
*(prop + prop_entry_size(len) / sizeof(grub_uint32_t) - 1) = 0;
grub_memcpy (prop + 3, val, len);
}
return 0;
}

View file

@ -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

View file

@ -0,0 +1,41 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2013 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#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");
}

View file

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

View file

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

View file

@ -0,0 +1,401 @@
/* linux.c - boot Linux */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2013 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#include <grub/dl.h>
#include <grub/fdt.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>
GRUB_MOD_LICENSE ("GPLv3+");
static grub_dl_t my_mod;
static grub_addr_t initrd_start;
static grub_addr_t initrd_end;
static grub_addr_t linux_addr;
static grub_size_t linux_size;
static char *linux_args;
static grub_uint32_t machine_type;
static void *fdt_addr;
#define LINUX_ZIMAGE_OFFSET 0x24
#define LINUX_ZIMAGE_MAGIC 0x016f2818
#define ARM_FDT_MACHINE_TYPE 0xFFFFFFFF
#define LINUX_PHYS_OFFSET (0x00008000)
#define LINUX_INITRD_PHYS_OFFSET (LINUX_PHYS_OFFSET + 0x02000000)
#define LINUX_FDT_PHYS_OFFSET (LINUX_INITRD_PHYS_OFFSET - 0x10000)
/*
* 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 = grub_fdt_get_totalsize (fdt_addr) + 0x100 + grub_strlen (linux_args);
tmp_fdt = grub_malloc (tmp_size);
if (!tmp_fdt)
return grub_errno;
grub_memcpy (tmp_fdt, fdt_addr, grub_fdt_get_totalsize (fdt_addr));
grub_fdt_set_totalsize (tmp_fdt, tmp_size);
/* Find or create '/chosen' node */
node = grub_fdt_find_subnode (tmp_fdt, 0, "chosen");
if (node < 0)
{
grub_printf ("No 'chosen' node in FDT - creating.\n");
node = grub_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 = grub_fdt_set_prop (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_dprintf ("loader", "Initrd @ 0x%08x-0x%08x\n",
initrd_start, initrd_end);
retval = grub_fdt_set_prop32 (tmp_fdt, node, "linux,initrd-start",
initrd_start);
if (retval)
goto failure;
retval = grub_fdt_set_prop32 (tmp_fdt, node, "linux,initrd-end",
initrd_end);
if (retval)
goto failure;
}
/* Copy updated FDT to its launch location */
grub_memcpy (fdt_addr, tmp_fdt, tmp_size);
grub_free (tmp_fdt);
grub_dprintf ("loader", "FDT updated for Linux boot\n");
return GRUB_ERR_NONE;
failure:
grub_free (tmp_fdt);
return grub_error (GRUB_ERR_BAD_ARGUMENT, "unable to prepare FDT");
}
static grub_err_t
linux_boot (void)
{
kernel_entry_t linuxmain;
grub_err_t err;
if (!fdt_addr && machine_type == ARM_FDT_MACHINE_TYPE)
return grub_error (GRUB_ERR_FILE_NOT_FOUND,
N_("device tree must be supplied"));
grub_arch_sync_caches ((void *) linux_addr, linux_size);
grub_dprintf ("loader", "Kernel at: 0x%x\n", linux_addr);
err = linux_prepare_fdt ();
if (err)
return err;
grub_dprintf ("loader", "FDT @ 0x%p\n", fdt_addr);
grub_dprintf ("loader", "Jumping to Linux...\n");
/* Boot the kernel.
* Arguments to kernel:
* r0 - 0
* r1 - machine type
* r2 - address of DTB
*/
linuxmain = (kernel_entry_t) linux_addr;
#ifdef GRUB_MACHINE_EFI
err = grub_efi_prepare_platform();
if (err != GRUB_ERR_NONE)
return err;
#endif
linuxmain (0, machine_type, fdt_addr);
return err;
}
/*
* Only support zImage, so no relocations necessary
*/
static grub_err_t
linux_load (const char *filename, grub_file_t file)
{
int size;
size = grub_file_size (file);
if (size == 0)
return grub_error (GRUB_ERR_BAD_OS, "empty kernel");
#ifdef GRUB_MACHINE_EFI
linux_addr = (grub_addr_t) grub_efi_allocate_loader_memory (LINUX_PHYS_OFFSET, size);
if (!linux_addr)
return grub_errno;
#else
linux_addr = LINUX_ADDRESS;
#endif
grub_dprintf ("loader", "Loading Linux to 0x%08x\n",
(grub_addr_t) linux_addr);
if (grub_file_read (file, (void *) linux_addr, size) != size)
{
if (!grub_errno)
grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
filename);
return grub_errno;
}
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;
grub_err_t err;
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;
err = linux_load (argv[0], file);
grub_file_close (file);
if (err)
goto fail;
grub_loader_set (linux_boot, linux_unload, 0);
size = grub_loader_cmdline_size (argc, argv);
linux_args = grub_malloc (size + sizeof (LINUX_IMAGE));
if (!linux_args)
{
grub_loader_unset();
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;
if (initrd_start)
grub_free ((void *) initrd_start);
#ifdef GRUB_MACHINE_EFI
initrd_start = (grub_addr_t) grub_efi_allocate_loader_memory (LINUX_INITRD_PHYS_OFFSET, size);
if (!initrd_start)
{
grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("memory allocation failed"));
goto fail;
}
#else
initrd_start = LINUX_INITRD_ADDRESS;
#endif
grub_dprintf ("loader", "Loading initrd to 0x%08x\n",
(grub_addr_t) initrd_start);
if (grub_file_read (file, (void *) initrd_start, size) != size)
{
initrd_start = 0;
if (!grub_errno)
grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
argv[0]);
goto fail;
}
initrd_end = initrd_start + size;
return GRUB_ERR_NONE;
fail:
grub_file_close (file);
return grub_errno;
}
static grub_err_t
load_dtb (grub_file_t dtb, int size)
{
if ((grub_file_read (dtb, fdt_addr, size) != size)
|| (grub_fdt_check_header (fdt_addr, size) != 0))
return grub_error (GRUB_ERR_BAD_OS, N_("invalid device tree"));
grub_fdt_set_totalsize (fdt_addr, size);
return GRUB_ERR_NONE;
}
static grub_err_t
grub_cmd_devicetree (grub_command_t cmd __attribute__ ((unused)),
int argc, char *argv[])
{
grub_file_t dtb;
int size;
if (argc != 1)
return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
dtb = grub_file_open (argv[0]);
if (!dtb)
goto out;
size = grub_file_size (dtb);
if (size == 0)
{
grub_error (GRUB_ERR_BAD_OS, "empty file");
goto out;
}
#ifdef GRUB_MACHINE_EFI
fdt_addr = grub_efi_allocate_loader_memory (LINUX_FDT_PHYS_OFFSET, size);
if (!fdt_addr)
{
grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("memory allocation failed"));
goto out;
}
#else
fdt_addr = (void *) LINUX_FDT_ADDRESS;
#endif
grub_dprintf ("loader", "Loading device tree to 0x%08x\n",
(grub_addr_t) fdt_addr);
load_dtb (dtb, size);
if (grub_errno != GRUB_ERR_NONE)
{
fdt_addr = NULL;
goto out;
}
/*
* We've successfully loaded an FDT, so any machine type passed
* from firmware is now obsolete.
*/
machine_type = ARM_FDT_MACHINE_TYPE;
out:
grub_file_close (dtb);
return grub_errno;
}
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;
fdt_addr = (void *) firmware_get_boot_data ();
machine_type = firmware_get_machine_type ();
}
GRUB_MOD_FINI (linux)
{
grub_unregister_command (cmd_linux);
grub_unregister_command (cmd_initrd);
grub_unregister_command (cmd_devicetree);
}

View file

@ -0,0 +1,161 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2013 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#include <grub/net/netbuff.h>
#include <grub/uboot/disk.h>
#include <grub/uboot/uboot.h>
#include <grub/uboot/api_public.h>
#include <grub/dl.h>
#include <grub/net.h>
#include <grub/time.h>
#include <grub/i18n.h>
GRUB_MOD_LICENSE ("GPLv3+");
static grub_err_t
card_open (struct grub_net_card *dev)
{
int status;
status = grub_uboot_dev_open (dev->data);
if (status)
return grub_error (GRUB_ERR_IO, "Couldn't open network card.");
return GRUB_ERR_NONE;
}
static void
card_close (struct grub_net_card *dev)
{
grub_uboot_dev_close (dev->data);
}
static grub_err_t
send_card_buffer (struct grub_net_card *dev, struct grub_net_buff *pack)
{
int status;
grub_size_t len;
len = (pack->tail - pack->data);
if (len > dev->mtu)
len = dev->mtu;
grub_memcpy (dev->txbuf, pack->data, len);
status = grub_uboot_dev_send (dev->data, dev->txbuf, len);
if (status)
return grub_error (GRUB_ERR_IO, N_("couldn't send network packet"));
return GRUB_ERR_NONE;
}
static struct grub_net_buff *
get_card_packet (struct grub_net_card *dev)
{
int rc;
grub_uint64_t start_time;
struct grub_net_buff *nb;
int actual;
nb = grub_netbuff_alloc (dev->mtu + 64 + 2);
if (!nb)
return NULL;
/* Reserve 2 bytes so that 2 + 14/18 bytes of ethernet header is divisible
by 4. So that IP header is aligned on 4 bytes. */
grub_netbuff_reserve (nb, 2);
start_time = grub_get_time_ms ();
do
{
rc = grub_uboot_dev_recv (dev->data, nb->data, dev->mtu + 64, &actual);
grub_dprintf ("net", "rc=%d, actual=%d, time=%lld\n", rc, actual,
grub_get_time_ms () - start_time);
}
while ((actual <= 0 || rc < 0) && (grub_get_time_ms () - start_time < 200));
if (actual > 0)
{
grub_netbuff_put (nb, actual);
return nb;
}
grub_netbuff_free (nb);
return NULL;
}
static struct grub_net_card_driver ubootnet =
{
.name = "ubnet",
.open = card_open,
.close = card_close,
.send = send_card_buffer,
.recv = get_card_packet
};
GRUB_MOD_INIT (ubootnet)
{
int devcount, i;
int nfound = 0;
devcount = grub_uboot_dev_enum ();
for (i = 0; i < devcount; i++)
{
struct device_info *devinfo = grub_uboot_dev_get (i);
struct grub_net_card *card;
if (!(devinfo->type & DEV_TYP_NET))
continue;
card = grub_zalloc (sizeof (struct grub_net_card));
if (!card)
{
grub_print_error ();
return;
}
/* FIXME: Any way to check this? */
card->mtu = 1500;
grub_memcpy (&(card->default_address.mac), &devinfo->di_net.hwaddr, 6);
card->default_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
card->txbufsize = ALIGN_UP (card->mtu, 64) + 256;
card->txbuf = grub_zalloc (card->txbufsize);
if (!card->txbuf)
{
grub_free (card);
grub_print_error ();
continue;
}
card->data = devinfo;
card->flags = 0;
card->name = grub_xasprintf ("ubnet_%d", ++nfound);
card->idle_poll_delay_ms = 10;
card->driver = &ubootnet;
grub_net_card_register (card);
}
}
GRUB_MOD_FINI (ubootnet)
{
struct grub_net_card *card, *next;
FOR_NET_CARDS_SAFE (card, next)
if (card->driver && grub_strcmp (card->driver->name, "ubnet") == 0)
grub_net_card_unregister (card);
}

View file

@ -745,7 +745,9 @@ grub_cmd_terminfo (grub_extcmd_context_t ctxt, int argc, char **args)
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)

View file

@ -0,0 +1,141 @@
/* console.c - console interface layer for U-Boot platforms */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2013 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#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)
{
grub_uboot_putc (c);
}
static int
readkey (struct grub_term_input *term __attribute__ ((unused)))
{
if (grub_uboot_tstc () > 0)
return grub_uboot_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,
};
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 = grub_uboot_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)
{
}

View file

@ -0,0 +1,26 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2013 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GRUB_LOADER_MACHINE_HEADER
#define GRUB_LOADER_MACHINE_HEADER 1
grub_err_t EXPORT_FUNC (grub_efi_prepare_platform) (void);
void * EXPORT_FUNC (grub_efi_allocate_loader_memory) (grub_uint32_t min_offset,
grub_uint32_t size);
#endif /* ! GRUB_LOADER_MACHINE_HEADER */

View file

@ -0,0 +1 @@
#include <grub/efi/memory.h>

59
include/grub/arm/linux.h Normal file
View file

@ -0,0 +1,59 @@
/* linux.h - ARM linux specific definitions */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2013 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GRUB_LINUX_CPU_HEADER
#define GRUB_LINUX_CPU_HEADER 1
#define LINUX_ZIMAGE_OFFSET 0x24
#define LINUX_ZIMAGE_MAGIC 0x016f2818
#define ARM_FDT_MACHINE_TYPE 0xFFFFFFFF
#if defined GRUB_MACHINE_UBOOT
# include <grub/uboot/uboot.h>
# define LINUX_ADDRESS (start_of_ram + 0x8000)
# define LINUX_INITRD_ADDRESS (start_of_ram + 0x02000000)
# define LINUX_FDT_ADDRESS (LINUX_INITRD_ADDRESS - 0x10000)
# define firmware_get_boot_data grub_uboot_get_boot_data
# define firmware_get_machine_type grub_uboot_get_machine_type
#elif defined GRUB_MACHINE_EFI
# include <grub/efi/efi.h>
# include <grub/machine/loader.h>
/* On UEFI platforms - load the images at the lowest available address not
less than *_PHYS_OFFSET from the first available memory location. */
# define LINUX_PHYS_OFFSET (0x00008000)
# define LINUX_INITRD_PHYS_OFFSET (LINUX_PHYS_OFFSET + 0x02000000)
# define LINUX_FDT_PHYS_OFFSET (LINUX_INITRD_PHYS_OFFSET - 0x10000)
static inline grub_addr_t
firmware_get_boot_data (void)
{
return 0;
}
static inline grub_uint32_t
firmware_get_machine_type (void)
{
return ARM_FDT_MACHINE_TYPE;
}
#endif
#define FDT_ADDITIONAL_ENTRIES_SIZE 0x300
typedef void (*kernel_entry_t) (int, unsigned long, void *);
#endif /* ! GRUB_LINUX_CPU_HEADER */

27
include/grub/arm/reloc.h Normal file
View file

@ -0,0 +1,27 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2013 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GRUB_ARM_RELOC_H
#define GRUB_ARM_RELOC_H 1
grub_err_t grub_arm_reloc_abs32 (grub_uint32_t *addr, Elf32_Addr sym_addr);
grub_err_t grub_arm_reloc_jump24 (grub_uint32_t *addr, Elf32_Addr sym_addr);
grub_err_t grub_arm_reloc_thm_call (grub_uint16_t *addr, Elf32_Addr sym_addr);
grub_err_t grub_arm_reloc_thm_jump19 (grub_uint16_t *addr, Elf32_Addr sym_addr);
#endif

27
include/grub/arm/setjmp.h Normal file
View file

@ -0,0 +1,27 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2002,2004,2006,2007,2009 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GRUB_SETJMP_CPU_HEADER
#define GRUB_SETJMP_CPU_HEADER 1
typedef unsigned long grub_jmp_buf[10];
int grub_setjmp (grub_jmp_buf env) __attribute__ ((returns_twice));
void grub_longjmp (grub_jmp_buf env, int val) __attribute__ ((noreturn));
#endif /* ! GRUB_SETJMP_CPU_HEADER */

View file

@ -0,0 +1,7 @@
#ifndef GRUB_SYSTEM_CPU_HEADER
#define GRUB_SYSTEM_CPU_HEADER
void grub_arm_disable_caches_mmu (void);
#endif /* ! GRUB_SYSTEM_CPU_HEADER */

29
include/grub/arm/time.h Normal file
View file

@ -0,0 +1,29 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2013 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef 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 */

34
include/grub/arm/types.h Normal file
View file

@ -0,0 +1,34 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2013 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GRUB_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 */

View file

@ -0,0 +1,32 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2013 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GRUB_KERNEL_MACHINE_HEADER
#define GRUB_KERNEL_MACHINE_HEADER 1
#ifndef ASM_FILE
#include <grub/symbol.h>
#include <grub/types.h>
#endif /* ! ASM_FILE */
#define GRUB_KERNEL_MACHINE_STACK_SIZE 0x40000
#define GRUB_KERNEL_MACHINE_HEAP_SIZE (grub_size_t) (2 * 1024 * 1024)
#endif /* ! GRUB_KERNEL_MACHINE_HEADER */

View file

@ -46,7 +46,8 @@ enum grub_disk_dev_id
GRUB_DISK_DEVICE_ARCDISK_ID,
GRUB_DISK_DEVICE_HOSTDISK_ID,
GRUB_DISK_DEVICE_PROCFS_ID,
GRUB_DISK_DEVICE_CBFSDISK_ID
GRUB_DISK_DEVICE_CBFSDISK_ID,
GRUB_DISK_DEVICE_UBOOTDISK_ID,
};
struct grub_disk;

View file

@ -63,9 +63,10 @@ struct grub_pe32_coff_header
grub_uint16_t characteristics;
};
#define GRUB_PE32_MACHINE_I386 0x14c
#define GRUB_PE32_MACHINE_IA64 0x200
#define GRUB_PE32_MACHINE_X86_64 0x8664
#define GRUB_PE32_MACHINE_I386 0x14c
#define GRUB_PE32_MACHINE_IA64 0x200
#define GRUB_PE32_MACHINE_X86_64 0x8664
#define GRUB_PE32_MACHINE_ARMTHUMB_MIXED 0x01c2
#define GRUB_PE32_RELOCS_STRIPPED 0x0001
#define GRUB_PE32_EXECUTABLE_IMAGE 0x0002
@ -276,8 +277,10 @@ struct grub_pe32_fixup_block
#define GRUB_PE32_REL_BASED_HIGHLOW 3
#define GRUB_PE32_REL_BASED_HIGHADJ 4
#define GRUB_PE32_REL_BASED_MIPS_JMPADDR 5
#define GRUB_PE32_REL_BASED_ARM_MOV32A 5
#define GRUB_PE32_REL_BASED_SECTION 6
#define GRUB_PE32_REL_BASED_REL 7
#define GRUB_PE32_REL_BASED_ARM_MOV32T 7
#define GRUB_PE32_REL_BASED_IA64_IMM64 9
#define GRUB_PE32_REL_BASED_DIR64 10
#define GRUB_PE32_REL_BASED_HIGH3ADJ 11

99
include/grub/fdt.h Normal file
View file

@ -0,0 +1,99 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2013 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GRUB_FDT_HEADER
#define GRUB_FDT_HEADER 1
#include <grub/types.h>
#define FDT_MAGIC 0xD00DFEED
typedef struct {
grub_uint32_t magic;
grub_uint32_t totalsize;
grub_uint32_t off_dt_struct;
grub_uint32_t off_dt_strings;
grub_uint32_t off_mem_rsvmap;
grub_uint32_t version;
grub_uint32_t last_comp_version;
grub_uint32_t boot_cpuid_phys;
grub_uint32_t size_dt_strings;
grub_uint32_t size_dt_struct;
} grub_fdt_header_t;
#define grub_fdt_get_header(fdt, field) \
grub_be_to_cpu32(((const grub_fdt_header_t *)(fdt))->field)
#define grub_fdt_set_header(fdt, field, value) \
((grub_fdt_header_t *)(fdt))->field = grub_cpu_to_be32(value)
#define grub_fdt_get_magic(fdt) \
grub_fdt_get_header(fdt, magic)
#define grub_fdt_set_magic(fdt, value) \
grub_fdt_set_header(fdt, magic, value)
#define grub_fdt_get_totalsize(fdt) \
grub_fdt_get_header(fdt, totalsize)
#define grub_fdt_set_totalsize(fdt, value) \
grub_fdt_set_header(fdt, totalsize, value)
#define grub_fdt_get_off_dt_struct(fdt) \
grub_fdt_get_header(fdt, off_dt_struct)
#define grub_fdt_set_off_dt_struct(fdt, value) \
grub_fdt_set_header(fdt, off_dt_struct, value)
#define grub_fdt_get_off_dt_strings(fdt) \
grub_fdt_get_header(fdt, off_dt_strings)
#define grub_fdt_set_off_dt_strings(fdt, value) \
grub_fdt_set_header(fdt, off_dt_strings, value)
#define grub_fdt_get_off_mem_rsvmap(fdt) \
grub_fdt_get_header(fdt, off_mem_rsvmap)
#define grub_fdt_set_off_mem_rsvmap(fdt, value) \
grub_fdt_set_header(fdt, off_mem_rsvmap, value)
#define grub_fdt_get_version(fdt) \
grub_fdt_get_header(fdt, version)
#define grub_fdt_set_version(fdt, value) \
grub_fdt_set_header(fdt, version, value)
#define grub_fdt_get_last_comp_version(fdt) \
grub_fdt_get_header(fdt, last_comp_version)
#define grub_fdt_set_last_comp_version(fdt, value) \
grub_fdt_set_header(fdt, last_comp_version, value)
#define grub_fdt_get_boot_cpuid_phys(fdt) \
grub_fdt_get_header(fdt, boot_cpuid_phys)
#define grub_fdt_set_boot_cpuid_phys(fdt, value) \
grub_fdt_set_header(fdt, boot_cpuid_phys, value)
#define grub_fdt_get_size_dt_strings(fdt) \
grub_fdt_get_header(fdt, size_dt_strings)
#define grub_fdt_set_size_dt_strings(fdt, value) \
grub_fdt_set_header(fdt, size_dt_strings, value)
#define grub_fdt_get_size_dt_struct(fdt) \
grub_fdt_get_header(fdt, size_dt_struct)
#define grub_fdt_set_size_dt_struct(fdt, value) \
grub_fdt_set_header(fdt, size_dt_struct, value)
int grub_fdt_check_header (void *fdt, unsigned int size);
int grub_fdt_find_subnode (const void *fdt, unsigned int parentoffset,
const char *name);
int grub_fdt_add_subnode (void *fdt, unsigned int parentoffset,
const char *name);
int grub_fdt_set_prop (void *fdt, unsigned int nodeoffset, const char *name,
const void *val, grub_uint32_t len);
#define grub_fdt_set_prop32(fdt, nodeoffset, name, val) \
({ \
grub_uint32_t _val = grub_cpu_to_be32(val); \
grub_fdt_set_prop ((fdt), (nodeoffset), (name), &_val, 4); \
})
#endif /* ! GRUB_FDT_HEADER */

View file

@ -78,7 +78,7 @@ struct grub_module_info64
#if defined (GRUB_MACHINE_PCBIOS) || defined (GRUB_MACHINE_COREBOOT) \
|| defined (GRUB_MACHINE_MULTIBOOT) || defined (GRUB_MACHINE_MIPS_QEMU_MIPS) \
|| defined (GRUB_MACHINE_MIPS_LOONGSON) || defined (GRUB_MACHINE_ARC) \
|| defined (__sparc__)
|| defined (__sparc__) || defined (GRUB_MACHINE_UBOOT)
/* FIXME: stack is between 2 heap regions. Move it. */
#define GRUB_KERNEL_PRELOAD_SPACE_REUSABLE 1
#endif

View file

@ -112,3 +112,14 @@ void EXPORT_FUNC (_savegpr_29) (void);
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 (__aeabi_ulcmp) (void);
#endif

View file

@ -103,6 +103,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
@ -111,6 +112,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 0x8
#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. */

View file

@ -0,0 +1,181 @@
/*
* (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 *, ...);
#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 */
grub_uint16_t version; /* API version */
grub_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_ */

View file

@ -0,0 +1,29 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2013 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GRUB_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 */

43
include/grub/uboot/disk.h Normal file
View file

@ -0,0 +1,43 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2013 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GRUB_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
{
void *cookie;
struct device_info *dev;
int opencount;
enum disktype type;
grub_uint32_t block_size;
};
grub_err_t grub_ubootdisk_register (struct device_info *newdev);
#endif /* ! GRUB_UBOOT_DISK_HEADER */

175
include/grub/uboot/image.h Normal file
View file

@ -0,0 +1,175 @@
/*
* (C) Copyright 2008 Semihalf
*
* (C) Copyright 2000-2005
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*
* 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
*
********************************************************************
* NOTE: This header file defines an interface to U-Boot. Including
* this (unmodified) header file in another file is considered normal
* use of U-Boot, and does *not* fall under the heading of "derived
* work".
********************************************************************
*/
#ifndef __GRUB_UBOOT_IMAGE_H__
#define __GRUB_UBOOT_IMAGE_H__
/*
* Operating System Codes
*/
#define GRUB_UBOOT_IH_OS_INVALID 0 /* Invalid OS */
#define GRUB_UBOOT_IH_OS_OPENBSD 1 /* OpenBSD */
#define GRUB_UBOOT_IH_OS_NETBSD 2 /* NetBSD */
#define GRUB_UBOOT_IH_OS_FREEBSD 3 /* FreeBSD */
#define GRUB_UBOOT_IH_OS_4_4BSD 4 /* 4.4BSD */
#define GRUB_UBOOT_IH_OS_LINUX 5 /* Linux */
#define GRUB_UBOOT_IH_OS_SVR4 6 /* SVR4 */
#define GRUB_UBOOT_IH_OS_ESIX 7 /* Esix */
#define GRUB_UBOOT_IH_OS_SOLARIS 8 /* Solaris */
#define GRUB_UBOOT_IH_OS_IRIX 9 /* Irix */
#define GRUB_UBOOT_IH_OS_SCO 10 /* SCO */
#define GRUB_UBOOT_IH_OS_DELL 11 /* Dell */
#define GRUB_UBOOT_IH_OS_NCR 12 /* NCR */
#define GRUB_UBOOT_IH_OS_LYNXOS 13 /* LynxOS */
#define GRUB_UBOOT_IH_OS_VXWORKS 14 /* VxWorks */
#define GRUB_UBOOT_IH_OS_PSOS 15 /* pSOS */
#define GRUB_UBOOT_IH_OS_QNX 16 /* QNX */
#define GRUB_UBOOT_IH_OS_U_BOOT 17 /* Firmware */
#define GRUB_UBOOT_IH_OS_RTEMS 18 /* RTEMS */
#define GRUB_UBOOT_IH_OS_ARTOS 19 /* ARTOS */
#define GRUB_UBOOT_IH_OS_UNITY 20 /* Unity OS */
#define GRUB_UBOOT_IH_OS_INTEGRITY 21 /* INTEGRITY */
#define GRUB_UBOOT_IH_OS_OSE 22 /* OSE */
/*
* CPU Architecture Codes (supported by Linux)
*/
#define GRUB_UBOOT_IH_ARCH_INVALID 0 /* Invalid CPU */
#define GRUB_UBOOT_IH_ARCH_ALPHA 1 /* Alpha */
#define GRUB_UBOOT_IH_ARCH_ARM 2 /* ARM */
#define GRUB_UBOOT_IH_ARCH_I386 3 /* Intel x86 */
#define GRUB_UBOOT_IH_ARCH_IA64 4 /* IA64 */
#define GRUB_UBOOT_IH_ARCH_MIPS 5 /* MIPS */
#define GRUB_UBOOT_IH_ARCH_MIPS64 6 /* MIPS 64 Bit */
#define GRUB_UBOOT_IH_ARCH_PPC 7 /* PowerPC */
#define GRUB_UBOOT_IH_ARCH_S390 8 /* IBM S390 */
#define GRUB_UBOOT_IH_ARCH_SH 9 /* SuperH */
#define GRUB_UBOOT_IH_ARCH_SPARC 10 /* Sparc */
#define GRUB_UBOOT_IH_ARCH_SPARC64 11 /* Sparc 64 Bit */
#define GRUB_UBOOT_IH_ARCH_M68K 12 /* M68K */
#define GRUB_UBOOT_IH_ARCH_MICROBLAZE 14 /* MicroBlaze */
#define GRUB_UBOOT_IH_ARCH_NIOS2 15 /* Nios-II */
#define GRUB_UBOOT_IH_ARCH_BLACKFIN 16 /* Blackfin */
#define GRUB_UBOOT_IH_ARCH_AVR32 17 /* AVR32 */
#define GRUB_UBOOT_IH_ARCH_ST200 18 /* STMicroelectronics ST200 */
#define GRUB_UBOOT_IH_ARCH_SANDBOX 19 /* Sandbox architecture (test only) */
#define GRUB_UBOOT_IH_ARCH_NDS32 20 /* ANDES Technology - NDS32 */
#define GRUB_UBOOT_IH_ARCH_OPENRISC 21 /* OpenRISC 1000 */
/*
* Image Types
*
* "Standalone Programs" are directly runnable in the environment
* provided by U-Boot; it is expected that (if they behave
* well) you can continue to work in U-Boot after return from
* the Standalone Program.
* "OS Kernel Images" are usually images of some Embedded OS which
* will take over control completely. Usually these programs
* will install their own set of exception handlers, device
* drivers, set up the MMU, etc. - this means, that you cannot
* expect to re-enter U-Boot except by resetting the CPU.
* "RAMDisk Images" are more or less just data blocks, and their
* parameters (address, size) are passed to an OS kernel that is
* being started.
* "Multi-File Images" contain several images, typically an OS
* (Linux) kernel image and one or more data images like
* RAMDisks. This construct is useful for instance when you want
* to boot over the network using BOOTP etc., where the boot
* server provides just a single image file, but you want to get
* for instance an OS kernel and a RAMDisk image.
*
* "Multi-File Images" start with a list of image sizes, each
* image size (in bytes) specified by an "uint32_t" in network
* byte order. This list is terminated by an "(uint32_t)0".
* Immediately after the terminating 0 follow the images, one by
* one, all aligned on "uint32_t" boundaries (size rounded up to
* a multiple of 4 bytes - except for the last file).
*
* "Firmware Images" are binary images containing firmware (like
* U-Boot or FPGA images) which usually will be programmed to
* flash memory.
*
* "Script files" are command sequences that will be executed by
* U-Boot's command interpreter; this feature is especially
* useful when you configure U-Boot to use a real shell (hush)
* as command interpreter (=> Shell Scripts).
*/
#define GRUB_UBOOT_IH_TYPE_INVALID 0 /* Invalid Image */
#define GRUB_UBOOT_IH_TYPE_STANDALONE 1 /* Standalone Program */
#define GRUB_UBOOT_IH_TYPE_KERNEL 2 /* OS Kernel Image */
#define GRUB_UBOOT_IH_TYPE_RAMDISK 3 /* RAMDisk Image */
#define GRUB_UBOOT_IH_TYPE_MULTI 4 /* Multi-File Image */
#define GRUB_UBOOT_IH_TYPE_FIRMWARE 5 /* Firmware Image */
#define GRUB_UBOOT_IH_TYPE_SCRIPT 6 /* Script file */
#define GRUB_UBOOT_IH_TYPE_FILESYSTEM 7 /* Filesystem Image (any type) */
#define GRUB_UBOOT_IH_TYPE_FLATDT 8 /* Binary Flat Device Tree Blob */
#define GRUB_UBOOT_IH_TYPE_KWBIMAGE 9 /* Kirkwood Boot Image */
#define GRUB_UBOOT_IH_TYPE_IMXIMAGE 10 /* Freescale IMXBoot Image */
#define GRUB_UBOOT_IH_TYPE_UBLIMAGE 11 /* Davinci UBL Image */
#define GRUB_UBOOT_IH_TYPE_OMAPIMAGE 12 /* TI OMAP Config Header Image */
#define GRUB_UBOOT_IH_TYPE_AISIMAGE 13 /* TI Davinci AIS Image */
#define GRUB_UBOOT_IH_TYPE_KERNEL_NOLOAD 14 /* OS Kernel Image, can run from any load address */
#define GRUB_UBOOT_IH_TYPE_PBLIMAGE 15 /* Freescale PBL Boot Image */
/*
* Compression Types
*/
#define GRUB_UBOOT_IH_COMP_NONE 0 /* No Compression Used */
#define GRUB_UBOOT_IH_COMP_GZIP 1 /* gzip Compression Used */
#define GRUB_UBOOT_IH_COMP_BZIP2 2 /* bzip2 Compression Used */
#define GRUB_UBOOT_IH_COMP_LZMA 3 /* lzma Compression Used */
#define GRUB_UBOOT_IH_COMP_LZO 4 /* lzo Compression Used */
#define GRUB_UBOOT_IH_MAGIC 0x27051956 /* Image Magic Number */
#define GRUB_UBOOT_IH_NMLEN 32 /* Image Name Length */
/*
* Legacy format image header,
* all data in network byte order (aka natural aka bigendian).
*/
struct grub_uboot_image_header {
grub_uint32_t ih_magic; /* Image Header Magic Number */
grub_uint32_t ih_hcrc; /* Image Header CRC Checksum */
grub_uint32_t ih_time; /* Image Creation Timestamp */
grub_uint32_t ih_size; /* Image Data Size */
grub_uint32_t ih_load; /* Data Load Address */
grub_uint32_t ih_ep; /* Entry Point Address */
grub_uint32_t ih_dcrc; /* Image Data CRC Checksum */
grub_uint8_t ih_os; /* Operating System */
grub_uint8_t ih_arch; /* CPU architecture */
grub_uint8_t ih_type; /* Image Type */
grub_uint8_t ih_comp; /* Compression Type */
grub_uint8_t ih_name[GRUB_UBOOT_IH_NMLEN]; /* Image Name */
};
#endif /* __IMAGE_H__ */

View file

@ -0,0 +1,86 @@
/* uboot.h - declare variables and functions for U-Boot support */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2013 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GRUB_UBOOT_UBOOT_HEADER
#define GRUB_UBOOT_UBOOT_HEADER 1
#include <grub/types.h>
#include <grub/dl.h>
/* Functions. */
void grub_uboot_mm_init (void);
void grub_uboot_init (void);
void grub_uboot_fini (void);
void grub_uboot_return (int) __attribute__ ((noreturn));
grub_addr_t grub_uboot_get_real_bss_start (void);
grub_err_t grub_uboot_probe_hardware (void);
extern grub_addr_t EXPORT_VAR (start_of_ram);
grub_uint32_t EXPORT_FUNC (grub_uboot_get_machine_type) (void);
grub_addr_t EXPORT_FUNC (grub_uboot_get_boot_data) (void);
/*
* The U-Boot API operates through a "syscall" interface, consisting of an
* entry point address and a set of syscall numbers. The location of this
* entry point is described in a structure allocated on the U-Boot heap.
* We scan through a defined region around the hint address passed to us
* from U-Boot.
*/
#define UBOOT_API_SEARCH_LEN (3 * 1024 * 1024)
int grub_uboot_api_init (void);
/*
* All functions below are wrappers around the uboot_syscall() function,
* implemented in grub-core/kern/uboot/uboot.c
*/
int grub_uboot_getc (void);
int grub_uboot_tstc (void);
void grub_uboot_putc (int c);
void grub_uboot_puts (const char *s);
void EXPORT_FUNC (grub_uboot_reset) (void);
struct sys_info *grub_uboot_get_sys_info (void);
void grub_uboot_udelay (grub_uint32_t usec);
grub_uint32_t grub_uboot_get_timer (grub_uint32_t base);
int EXPORT_FUNC (grub_uboot_dev_enum) (void);
struct device_info * EXPORT_FUNC (grub_uboot_dev_get) (int index);
int EXPORT_FUNC (grub_uboot_dev_open) (struct device_info *dev);
int EXPORT_FUNC (grub_uboot_dev_close) (struct device_info *dev);
int grub_uboot_dev_write (struct device_info *dev, void *buf, int *len);
int grub_uboot_dev_read (struct device_info *dev, void *buf, grub_size_t blocks,
grub_uint32_t start, grub_size_t * real_blocks);
int EXPORT_FUNC (grub_uboot_dev_recv) (struct device_info *dev, void *buf,
int size, int *real_size);
int EXPORT_FUNC (grub_uboot_dev_send) (struct device_info *dev, void *buf,
int size);
char *grub_uboot_env_get (const char *name);
void grub_uboot_env_set (const char *name, const char *value);
#endif /* ! GRUB_UBOOT_UBOOT_HEADER */

View file

@ -272,6 +272,8 @@ if [ x$source_directory = x ]; then
target=i386-pc
fi
;;
x"arm"*)
target="arm-uboot";;
*)
gettext "Unable to determine your platform. Use --target." ;
echo ;;
@ -291,7 +293,7 @@ if [ "${grub_modinfo_target_cpu}-${grub_modinfo_platform}" = "i386-pc" ] ; then
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
@ -424,6 +426,8 @@ if [ x"$grub_modinfo_platform" = xefi ]; then
# expansion.
ia64)
efi_file=BOOTIA64.EFI ;;
arm)
efi_file=BOOTARM.EFI ;;
esac
else
# It is convenient for each architecture to have a different
@ -438,6 +442,8 @@ if [ x"$grub_modinfo_platform" = xefi ]; then
# expansion.
ia64)
efi_file=grubia64.efi ;;
arm)
efi_file=grubarm.efi ;;
*)
efi_file=grub.efi ;;
esac

View file

@ -40,6 +40,8 @@
#include <stdlib.h>
#include <assert.h>
#include <grub/efi/pe32.h>
#include <grub/uboot/image.h>
#include <grub/arm/reloc.h>
#include <grub/ia64/reloc.h>
#define _GNU_SOURCE 1
@ -71,7 +73,7 @@ struct image_target_desc
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
{
@ -489,6 +491,46 @@ struct image_target_desc image_targets[] =
.link_align = GRUB_KERNEL_MIPS_QEMU_MIPS_LINK_ALIGN,
.default_compression = COMPRESSION_NONE
},
{
.dirname = "arm-uboot",
.names = { "arm-uboot", NULL },
.voidp_sizeof = 4,
.bigendian = 0,
.id = IMAGE_UBOOT,
.flags = PLATFORM_FLAGS_NONE,
.total_module_size = GRUB_KERNEL_ARM_UBOOT_TOTAL_MODULE_SIZE,
.decompressor_compressed_size = TARGET_NO_FIELD,
.decompressor_uncompressed_size = TARGET_NO_FIELD,
.decompressor_uncompressed_addr = TARGET_NO_FIELD,
.section_align = GRUB_KERNEL_ARM_UBOOT_MOD_ALIGN,
.vaddr_offset = 0,
.link_addr = GRUB_KERNEL_ARM_UBOOT_LINK_ADDR,
.elf_target = EM_ARM,
.mod_gap = GRUB_KERNEL_ARM_UBOOT_MOD_GAP,
.mod_align = GRUB_KERNEL_ARM_UBOOT_MOD_ALIGN,
.link_align = 4
},
{
.dirname = "arm-efi",
.names = { "arm-efi", NULL },
.voidp_sizeof = 4,
.bigendian = 0,
.id = IMAGE_EFI,
.flags = PLATFORM_FLAGS_NONE,
.total_module_size = TARGET_NO_FIELD,
.decompressor_compressed_size = TARGET_NO_FIELD,
.decompressor_uncompressed_size = TARGET_NO_FIELD,
.decompressor_uncompressed_addr = TARGET_NO_FIELD,
.section_align = GRUB_PE32_SECTION_ALIGNMENT,
.vaddr_offset = ALIGN_UP (GRUB_PE32_MSDOS_STUB_SIZE
+ GRUB_PE32_SIGNATURE_SIZE
+ sizeof (struct grub_pe32_coff_header)
+ sizeof (struct grub_pe32_optional_header)
+ 4 * sizeof (struct grub_pe32_section_table),
GRUB_PE32_SECTION_ALIGNMENT),
.pe_target = GRUB_PE32_MACHINE_ARMTHUMB_MIXED,
.elf_target = EM_ARM,
},
};
#define grub_target_to_host32(x) (grub_target_to_host32_real (image_target, (x)))
@ -1057,6 +1099,7 @@ generate_image (const char *dir, const char *prefix,
case IMAGE_SPARC64_CDCORE:
case IMAGE_I386_IEEE1275:
case IMAGE_PPC:
case IMAGE_UBOOT:
break;
}
@ -1496,6 +1539,42 @@ generate_image (const char *dir, const char *prefix,
core_size = rom_size;
}
break;
case IMAGE_UBOOT:
{
struct grub_uboot_image_header *hdr;
GRUB_PROPERLY_ALIGNED_ARRAY (crc32_context, GRUB_MD_CRC32->contextsize);
hdr = xmalloc (core_size + sizeof (struct grub_uboot_image_header));
memcpy (hdr + 1, core_img, core_size);
memset (hdr, 0, sizeof (*hdr));
hdr->ih_magic = grub_cpu_to_be32_compile_time (GRUB_UBOOT_IH_MAGIC);
hdr->ih_time = grub_cpu_to_be32 (time (0));
hdr->ih_size = grub_cpu_to_be32 (core_size);
hdr->ih_load = grub_cpu_to_be32 (image_target->link_addr);
hdr->ih_ep = grub_cpu_to_be32 (image_target->link_addr);
hdr->ih_type = GRUB_UBOOT_IH_TYPE_KERNEL;
hdr->ih_os = GRUB_UBOOT_IH_OS_LINUX;
hdr->ih_arch = GRUB_UBOOT_IH_ARCH_ARM;
hdr->ih_comp = GRUB_UBOOT_IH_COMP_NONE;
GRUB_MD_CRC32->init(crc32_context);
GRUB_MD_CRC32->write(crc32_context, hdr + 1, core_size);
GRUB_MD_CRC32->final(crc32_context);
hdr->ih_dcrc = grub_get_unaligned32 (GRUB_MD_CRC32->read (crc32_context));
GRUB_MD_CRC32->init(crc32_context);
GRUB_MD_CRC32->write(crc32_context, hdr, sizeof (*hdr));
GRUB_MD_CRC32->final(crc32_context);
hdr->ih_hcrc = grub_get_unaligned32 (GRUB_MD_CRC32->read (crc32_context));
free (core_img);
core_img = (char *) hdr;
core_size += sizeof (struct grub_uboot_image_header);
}
break;
case IMAGE_MIPS_ARC:
{
char *ecoff_img;

View file

@ -58,6 +58,8 @@
#error "I'm confused"
#endif
static Elf_Addr SUFFIX (entry_point);
/* Relocate symbols; note that this function overwrites the symbol table.
Return the address of a start symbol. */
static Elf_Addr
@ -408,6 +410,55 @@ SUFFIX (relocate_addresses) (Elf_Ehdr *e, Elf_Shdr *sections,
}
break;
#endif
#if defined(MKIMAGE_ELF32)
case EM_ARM:
{
sym_addr += addend;
sym_addr -= SUFFIX (entry_point);
switch (ELF_R_TYPE (info))
{
case R_ARM_ABS32:
{
grub_util_info (" ABS32:\toffset=%d\t(0x%08x)",
(int) sym_addr, (int) sym_addr);
/* Data will be naturally aligned */
sym_addr += 0x400;
*target = grub_host_to_target32 (grub_target_to_host32 (*target) + sym_addr);
}
break;
case R_ARM_THM_CALL:
case R_ARM_THM_JUMP24:
{
grub_err_t err;
grub_util_info (" THM_JUMP24:\ttarget=0x%08lx\toffset=(0x%08x)", (unsigned long) target, sym_addr);
sym_addr -= offset;
/* Thumb instructions can be 16-bit aligned */
err = grub_arm_reloc_thm_call ((grub_uint16_t *) target,
sym_addr);
if (err)
grub_util_error ("%s", grub_errmsg);
}
break;
case R_ARM_THM_JUMP19:
{
grub_err_t err;
grub_util_info (" THM_JUMP19:\toffset=%d\t(0x%08x)",
sym_addr, sym_addr);
sym_addr -= offset;
/* Thumb instructions can be 16-bit aligned */
err = grub_arm_reloc_thm_jump19 ((grub_uint16_t *) target, sym_addr);
if (err)
grub_util_error ("%s", grub_errmsg);
}
break;
default:
grub_util_error (_("relocation 0x%x is not implemented yet!"), ELF_R_TYPE (info));
break;
}
break;
}
#endif /* MKIMAGE_ELF32 */
default:
grub_util_error ("unknown architecture type %d",
image_target->elf_target);
@ -635,6 +686,41 @@ SUFFIX (make_reloc_section) (Elf_Ehdr *e, void **out,
break;
}
break;
#if defined(MKIMAGE_ELF32)
case EM_ARM:
switch (ELF_R_TYPE (info))
{
/* Relative relocations do not require fixup entries. */
case R_ARM_JUMP24:
case R_ARM_THM_CALL:
case R_ARM_THM_JUMP19:
case R_ARM_THM_JUMP24:
{
Elf_Addr addr;
addr = section_address + offset;
grub_util_info (" %s: not adding fixup: 0x%08x : 0x%08x", __FUNCTION__, (unsigned int) addr, (unsigned int) current_address);
}
break;
/* Create fixup entry for PE/COFF loader */
case R_ARM_ABS32:
{
Elf_Addr addr;
addr = section_address + offset;
current_address
= SUFFIX (add_fixup_entry) (&lst,
GRUB_PE32_REL_BASED_HIGHLOW,
addr, 0, current_address,
image_target);
}
break;
default:
grub_util_error (_("fixup for relocation 0x%x not implemented"), ELF_R_TYPE (info));
break;
}
break;
#endif /* defined(MKIMAGE_ELF32) */
default:
grub_util_error ("unknown machine type 0x%x", image_target->elf_target);
}
@ -945,6 +1031,8 @@ SUFFIX (load_image) (const char *kernel_path, grub_size_t *exec_size,
if (*start == 0)
grub_util_error ("start symbol is not defined");
SUFFIX (entry_point) = (Elf_Addr) *start;
/* Resolve addresses in the virtual address space. */
SUFFIX (relocate_addresses) (e, sections, section_addresses,
section_entsize,