From 389b31cd71bca8217a9c6e7f196f13d6ee76f4e3 Mon Sep 17 00:00:00 2001 From: Leif Lindholm Date: Sun, 7 Apr 2013 02:41:07 +0200 Subject: [PATCH 01/25] Initial import of Leif's work --- .bzrignore | 2 + Makefile.util.def | 3 + autogen.sh | 5 +- conf/Makefile.common | 9 + conf/Makefile.extra-dist | 2 + configure.ac | 11 + docs/grub.texi | 12 + gentpl.py | 11 +- grub-core/Makefile.am | 13 + grub-core/Makefile.core.def | 29 + grub-core/disk/uboot/ubootdisk.c | 346 ++++++ grub-core/kern/arm/cache.S | 251 ++++ grub-core/kern/arm/dl.c | 490 ++++++++ grub-core/kern/arm/efi/init.c | 68 ++ grub-core/kern/arm/efi/misc.c | 203 ++++ grub-core/kern/arm/efi/startup.S | 38 + grub-core/kern/arm/misc.S | 44 + grub-core/kern/arm/uboot/startup.S | 176 +++ grub-core/kern/uboot/hw.c | 112 ++ grub-core/kern/uboot/init.c | 171 +++ grub-core/kern/uboot/uboot.c | 363 ++++++ grub-core/lib/arm/setjmp.S | 55 + grub-core/lib/dtc/libfdt-grub.diff | 45 + grub-core/lib/dtc/libfdt/Makefile.libfdt | 10 + grub-core/lib/dtc/libfdt/TODO | 3 + grub-core/lib/dtc/libfdt/fdt.c | 241 ++++ grub-core/lib/dtc/libfdt/fdt.h | 64 + grub-core/lib/dtc/libfdt/fdt_ro.c | 608 ++++++++++ grub-core/lib/dtc/libfdt/fdt_rw.c | 490 ++++++++ grub-core/lib/dtc/libfdt/fdt_strerror.c | 100 ++ grub-core/lib/dtc/libfdt/fdt_sw.c | 267 +++++ grub-core/lib/dtc/libfdt/fdt_wip.c | 123 ++ grub-core/lib/dtc/libfdt/libfdt.h | 1239 ++++++++++++++++++++ grub-core/lib/dtc/libfdt/libfdt_env.h | 27 + grub-core/lib/dtc/libfdt/libfdt_internal.h | 100 ++ grub-core/lib/dtc/libfdt/version.lds | 54 + grub-core/lib/efi/halt.c | 2 +- grub-core/lib/setjmp.S | 2 + grub-core/lib/uboot/datetime.c | 41 + grub-core/lib/uboot/halt.c | 31 + grub-core/lib/uboot/reboot.c | 30 + grub-core/loader/arm/linux.c | 405 +++++++ grub-core/term/terminfo.c | 4 +- grub-core/term/uboot/console.c | 141 +++ include/grub/arm/efi/loader.h | 26 + include/grub/arm/efi/memory.h | 1 + include/grub/arm/linux.h | 59 + include/grub/arm/system.h | 7 + include/grub/arm/time.h | 29 + include/grub/arm/types.h | 34 + include/grub/arm/uboot/kernel.h | 32 + include/grub/disk.h | 1 + include/grub/efi/pe32.h | 9 +- include/grub/kernel.h | 2 +- include/grub/libgcc.h | 11 + include/grub/offsets.h | 5 + include/grub/symbol.h | 6 +- include/grub/uboot/api_public.h | 184 +++ include/grub/uboot/console.h | 29 + include/grub/uboot/disk.h | 44 + include/grub/uboot/uboot.h | 150 +++ util/grub-install.in | 16 +- util/grub-mkimage.c | 46 +- util/grub-mkimagexx.c | 89 ++ util/import_libfdt.py | 103 ++ 65 files changed, 7311 insertions(+), 13 deletions(-) create mode 100644 grub-core/disk/uboot/ubootdisk.c create mode 100644 grub-core/kern/arm/cache.S create mode 100644 grub-core/kern/arm/dl.c create mode 100644 grub-core/kern/arm/efi/init.c create mode 100644 grub-core/kern/arm/efi/misc.c create mode 100644 grub-core/kern/arm/efi/startup.S create mode 100644 grub-core/kern/arm/misc.S create mode 100644 grub-core/kern/arm/uboot/startup.S create mode 100644 grub-core/kern/uboot/hw.c create mode 100644 grub-core/kern/uboot/init.c create mode 100644 grub-core/kern/uboot/uboot.c create mode 100644 grub-core/lib/arm/setjmp.S create mode 100644 grub-core/lib/dtc/libfdt-grub.diff create mode 100644 grub-core/lib/dtc/libfdt/Makefile.libfdt create mode 100644 grub-core/lib/dtc/libfdt/TODO create mode 100644 grub-core/lib/dtc/libfdt/fdt.c create mode 100644 grub-core/lib/dtc/libfdt/fdt.h create mode 100644 grub-core/lib/dtc/libfdt/fdt_ro.c create mode 100644 grub-core/lib/dtc/libfdt/fdt_rw.c create mode 100644 grub-core/lib/dtc/libfdt/fdt_strerror.c create mode 100644 grub-core/lib/dtc/libfdt/fdt_sw.c create mode 100644 grub-core/lib/dtc/libfdt/fdt_wip.c create mode 100644 grub-core/lib/dtc/libfdt/libfdt.h create mode 100644 grub-core/lib/dtc/libfdt/libfdt_env.h create mode 100644 grub-core/lib/dtc/libfdt/libfdt_internal.h create mode 100644 grub-core/lib/dtc/libfdt/version.lds create mode 100644 grub-core/lib/uboot/datetime.c create mode 100644 grub-core/lib/uboot/halt.c create mode 100644 grub-core/lib/uboot/reboot.c create mode 100644 grub-core/loader/arm/linux.c create mode 100644 grub-core/term/uboot/console.c create mode 100644 include/grub/arm/efi/loader.h create mode 100644 include/grub/arm/efi/memory.h create mode 100644 include/grub/arm/linux.h create mode 100644 include/grub/arm/system.h create mode 100644 include/grub/arm/time.h create mode 100644 include/grub/arm/types.h create mode 100644 include/grub/arm/uboot/kernel.h create mode 100644 include/grub/uboot/api_public.h create mode 100644 include/grub/uboot/console.h create mode 100644 include/grub/uboot/disk.h create mode 100644 include/grub/uboot/uboot.h create mode 100644 util/import_libfdt.py diff --git a/.bzrignore b/.bzrignore index c6797ad8f..a0cd25dd4 100644 --- a/.bzrignore +++ b/.bzrignore @@ -174,3 +174,5 @@ po/*.gmo po/LINGUAS include/grub/gcrypt/gcrypt.h include/grub/gcrypt/g10lib.h +grub-core/lib/dtc-grub +grub-core/Makefile.libfdt.def diff --git a/Makefile.util.def b/Makefile.util.def index 513dc3858..3c74e853b 100644 --- a/Makefile.util.def +++ b/Makefile.util.def @@ -150,6 +150,8 @@ program = { common = util/resolve.c; common = grub-core/kern/emu/argp_common.c; + arm = grub-core/kern/arm/dl.c; + extra_dist = util/grub-mkimagexx.c; ldadd = libgrubmods.a; @@ -470,6 +472,7 @@ script = { enable = mips_loongson; enable = ia64_efi; enable = powerpc_ieee1275; + enable = arm_uboot; }; script = { diff --git a/autogen.sh b/autogen.sh index 7a4b5c8be..6df462e0a 100755 --- a/autogen.sh +++ b/autogen.sh @@ -30,6 +30,9 @@ for x in mpi-asm-defs.h mpih-add1.c mpih-sub1.c mpih-mul1.c mpih-mul2.c mpih-mul ln -s generic/"$x" grub-core/lib/libgcrypt-grub/mpi/"$x" done +echo "Importing libfdt..." +python util/import_libfdt.py grub-core/lib/dtc/ grub-core + echo "Creating Makefile.tpl..." python gentpl.py | sed -e '/^$/{N;/^\n$/D;}' > Makefile.tpl @@ -43,7 +46,7 @@ if [ "x${GRUB_CONTRIB}" != x ]; then fi UTIL_DEFS='Makefile.util.def Makefile.utilgcry.def' -CORE_DEFS='grub-core/Makefile.core.def grub-core/Makefile.gcry.def' +CORE_DEFS='grub-core/Makefile.core.def grub-core/Makefile.gcry.def grub-core/Makefile.libfdt.def' for extra in contrib/*/Makefile.util.def; do if test -e "$extra"; then diff --git a/conf/Makefile.common b/conf/Makefile.common index c185a553d..d9b34714a 100644 --- a/conf/Makefile.common +++ b/conf/Makefile.common @@ -37,6 +37,13 @@ if COND_sparc64_ieee1275 CFLAGS_PLATFORM += -mno-app-regs LDFLAGS_PLATFORM = -Wl,-melf64_sparc -mno-relax endif +if COND_arm +# Image entry point always in ARM (A32) state - ensure proper functionality if +# the rest is built for the Thumb (T32) state. + CFLAGS_PLATFORM += -mthumb-interwork -mno-unaligned-access -mlong-calls + CCASFLAGS_PLATFORM = -Wa,-mimplicit-it=thumb + LDFLAGS_PLATFORM = -Wl,--wrap=__clear_cache +endif # Other options @@ -110,6 +117,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 diff --git a/conf/Makefile.extra-dist b/conf/Makefile.extra-dist index 2e365008f..0a7a8befe 100644 --- a/conf/Makefile.extra-dist +++ b/conf/Makefile.extra-dist @@ -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 @@ -27,6 +28,7 @@ EXTRA_DIST += grub-core/genemuinit.sh EXTRA_DIST += grub-core/genemuinitheader.sh EXTRA_DIST += grub-core/lib/libgcrypt/cipher +EXTRA_DIST += grub-core/lib/dtc EXTRA_DIST += $(shell find $(top_srcdir)/include -name '*.h') EXTRA_DIST += $(shell find $(top_srcdir)/grub-core/lib -name '*.h') EXTRA_DIST += $(shell find $(top_srcdir)/grub-core/gnulib -name '*.h') diff --git a/configure.ac b/configure.ac index a39a025fe..ed8de8ab4 100644 --- a/configure.ac +++ b/configure.ac @@ -94,6 +94,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). @@ -114,6 +117,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 @@ -148,6 +152,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 @@ -179,6 +185,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" ;; @@ -187,6 +194,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 @@ -1150,6 +1158,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]) diff --git a/docs/grub.texi b/docs/grub.texi index bd366a67d..31a0420f9 100644 --- a/docs/grub.texi +++ b/docs/grub.texi @@ -3389,6 +3389,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 * export:: Export an environment variable @@ -3698,6 +3699,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 diff --git a/gentpl.py b/gentpl.py index b159795a1..93089bfd9 100644 --- a/gentpl.py +++ b/gentpl.py @@ -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"] = ["mips_loongson", "mips_arc", "mips_qemu_mips" ] + GROUPS["ieee1275"]; +GROUPS["terminfoinkernel"] = ["mips_loongson", "mips_arc", "mips_qemu_mips" ] + GROUPS["ieee1275"] + GROUPS["uboot"]; GROUPS["terminfomodule"] = GRUB_PLATFORMS[:]; for i in GROUPS["terminfoinkernel"]: GROUPS["terminfomodule"].remove(i) +# Flattened Device Trees (FDT) +GROUPS["fdt"] = [ "arm_uboot", "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") diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am index 6f156e75d..f1190a6c5 100644 --- a/grub-core/Makefile.am +++ b/grub-core/Makefile.am @@ -211,6 +211,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 diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index 4b4c02473..f58888a6f 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -45,6 +45,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'; @@ -66,6 +69,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; @@ -77,6 +82,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; @@ -112,6 +119,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; @@ -143,6 +156,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; @@ -192,6 +208,10 @@ kernel = { sparc64_ieee1275 = kern/sparc64/dl.c; sparc64_ieee1275 = kern/sparc64/ieee1275/ieee1275.c; + arm = kern/arm/dl.c; + arm = kern/arm/cache.S; + arm = kern/arm/misc.S; + emu = disk/host.c; emu = gnulib/progname.c; emu = gnulib/error.c; @@ -688,6 +708,7 @@ module = { efi = lib/efi/halt.c; ieee1275 = lib/ieee1275/halt.c; emu = lib/emu/halt.c; + uboot = lib/uboot/halt.c; }; module = { @@ -696,11 +717,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; }; @@ -1358,6 +1381,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; @@ -1377,6 +1401,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 = { @@ -1456,9 +1481,12 @@ 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; common = loader/linux.c; common = lib/cmdline.c; enable = noemu; + + fdt_cppflags = '$(CPPFLAGS_LIBFDT)'; }; module = { @@ -1507,6 +1535,7 @@ module = { enable = x86; enable = ia64_efi; + enable = arm_efi; enable = mips; }; diff --git a/grub-core/disk/uboot/ubootdisk.c b/grub-core/disk/uboot/ubootdisk.c new file mode 100644 index 000000000..92ce1e780 --- /dev/null +++ b/grub-core/disk/uboot/ubootdisk.c @@ -0,0 +1,346 @@ +/* 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 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static struct ubootdisk_data *fd_devices; +static struct ubootdisk_data *hd_devices; +static struct ubootdisk_data *cd_devices; + +/* + * grub_ubootdisk_register(): + * Called for each disk device enumerated as part of U-Boot initialization + * code. + */ +grub_err_t +grub_ubootdisk_register (struct device_info *newdev, int handle) +{ + struct ubootdisk_data *d; + enum disktype type; + +#define STOR_TYPE(x) ((x) & 0x0ff0) + switch (STOR_TYPE (newdev->type)) + { + case DT_STOR_IDE: + case DT_STOR_SATA: + /* hd */ + type = hd; + break; + case DT_STOR_MMC: + case DT_STOR_USB: + /* fd */ + type = fd; + break; + default: + return GRUB_ERR_BAD_DEVICE; + break; + } + + d = (struct ubootdisk_data *) grub_malloc (sizeof (struct ubootdisk_data)); + if (!d) + return GRUB_ERR_OUT_OF_MEMORY; + d->handle = handle; + d->cookie = newdev->cookie; + d->opencount = 0; + + switch (type) + { + case cd: + grub_dprintf ("ubootdisk", "registering cd device\n"); + d->next = cd_devices; + cd_devices = d; + + break; + case fd: + grub_dprintf ("ubootdisk", "registering fd device\n"); + d->next = fd_devices; + fd_devices = d; + + break; + case hd: + grub_dprintf ("ubootdisk", "registering hd device\n"); + d->next = hd_devices; + hd_devices = d; + + break; + default: + grub_free (d); + return GRUB_ERR_BAD_DEVICE; + } + + return 0; +} + +/* + * uboot_disk_iterate(): + * Itarator over enumerated disk devices. + */ +static int +uboot_disk_iterate (grub_disk_dev_iterate_hook_t hook, void *hook_data, + grub_disk_pull_t pull) +{ + struct ubootdisk_data *d; + char buf[16]; + int count; + + switch (pull) + { + case GRUB_DISK_PULL_NONE: + /* "hd" - built-in mass-storage */ + for (d = hd_devices, count = 0; d; d = d->next, count++) + { + grub_snprintf (buf, sizeof (buf) - 1, "hd%d", count); + grub_dprintf ("ubootdisk", "iterating %s\n", buf); + if (hook (buf, hook_data)) + return 1; + } + break; + case GRUB_DISK_PULL_REMOVABLE: + /* "floppy" - removable mass storage */ + for (d = fd_devices, count = 0; d; d = d->next, count++) + { + grub_snprintf (buf, sizeof (buf) - 1, "fd%d", count); + grub_dprintf ("ubootdisk", "iterating %s\n", buf); + if (hook (buf, hook_data)) + return 1; + } + + /* "cdrom" - removeable read-only storage */ + for (d = cd_devices, count = 0; d; d = d->next, count++) + { + grub_snprintf (buf, sizeof (buf) - 1, "cd%d", count); + grub_dprintf ("ubootdisk", "iterating %s\n", buf); + if (hook (buf, hook_data)) + return 1; + } + break; + default: + return 0; + } + + return 0; +} + +/* Helper function for uboot_disk_open. */ +static struct ubootdisk_data * +get_device (struct ubootdisk_data *devices, int num) +{ + struct ubootdisk_data *d; + + for (d = devices; d && num; d = d->next, num--) + ; + + if (num == 0) + return d; + + return NULL; +} + +/* + * uboot_disk_open(): + * Opens a disk device already enumerated. + */ +static grub_err_t +uboot_disk_open (const char *name, struct grub_disk *disk) +{ + struct ubootdisk_data *d; + struct device_info *devinfo; + int num; + int retval; + + grub_dprintf ("ubootdisk", "Opening '%s'\n", name); + + num = grub_strtoul (name + 2, 0, 10); + if (grub_errno != GRUB_ERR_NONE) + { + grub_dprintf ("ubootdisk", "Opening '%s' failed, invalid number\n", + name); + goto fail; + } + + if (name[1] != 'd') + { + grub_dprintf ("ubootdisk", "Opening '%s' failed, invalid name\n", name); + goto fail; + } + + switch (name[0]) + { + case 'f': + d = get_device (fd_devices, num); + break; + case 'c': + d = get_device (cd_devices, num); + break; + case 'h': + d = get_device (hd_devices, num); + break; + default: + goto fail; + } + + if (!d) + goto fail; + + /* + * Subsystems may call open on the same device recursively - but U-Boot + * does not deal with this. So simply keep track of number of calls and + * return success if already open. + */ + if (d->opencount > 0) + { + grub_dprintf ("ubootdisk", "(%s) already open\n", disk->name); + d->opencount++; + retval = 0; + } + else + { + retval = uboot_dev_open (d->handle); + if (retval != 0) + goto fail; + d->opencount = 1; + } + + grub_dprintf ("ubootdisk", "cookie: 0x%08x\n", (grub_addr_t) d->cookie); + disk->id = (grub_addr_t) d->cookie; + + /* Device has previously been enumerated, so this should never fail */ + if ((devinfo = uboot_dev_get (d->handle)) == NULL) + goto fail; + + d->block_size = devinfo->di_stor.block_size; + if (d->block_size == 0) + { + grub_printf ("%s: no block size!\n", __FUNCTION__); + return GRUB_ERR_IO; + } + + for (disk->log_sector_size = 0; + (1U << disk->log_sector_size) < d->block_size; + disk->log_sector_size++); + + grub_dprintf ("ubootdisk", "(%s) blocksize=%d, log_sector_size=%d\n", + disk->name, d->block_size, disk->log_sector_size); + + disk->total_sectors = GRUB_DISK_SIZE_UNKNOWN; + disk->data = d; + + return GRUB_ERR_NONE; + +fail: + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no such device"); +} + +static void +uboot_disk_close (struct grub_disk *disk) +{ + struct ubootdisk_data *d; + int retval; + + d = disk->data; + + /* + * In mirror of open function, keep track of number of calls to close and + * send on to U-Boot only when opencount would decrease to 0. + */ + if (d->opencount > 1) + { + grub_dprintf ("ubootdisk", "Closed (%s)\n", disk->name); + + d->opencount--; + } + else if (d->opencount == 1) + { + retval = uboot_dev_close (d->handle); + d->opencount--; + grub_dprintf ("ubootdisk", "closed %s (%d)\n", disk->name, retval); + } + else + { + grub_dprintf ("ubootdisk", "device %s not open!\n", disk->name); + } +} + +/* + * uboot_disk_read(): + * Called from within disk subsystem to read a sequence of blocks into the + * disk cache. Maps directly on top of U-Boot API, only wrap in some error + * handling. + */ +static grub_err_t +uboot_disk_read (struct grub_disk *disk, + grub_disk_addr_t offset, grub_size_t numblocks, char *buf) +{ + struct ubootdisk_data *d; + lbasize_t real_size; + int retval; + + d = disk->data; + + retval = uboot_dev_read (d->handle, buf, numblocks, offset, &real_size); + grub_dprintf ("ubootdisk", + "retval=%d, numblocks=%d, real_size=%llu, sector=%llu\n", + retval, numblocks, (grub_uint64_t) real_size, + (grub_uint64_t) offset); + if (retval != 0) + return grub_error (GRUB_ERR_IO, "U-Boot disk read error"); + + return GRUB_ERR_NONE; +} + +static grub_err_t +uboot_disk_write (struct grub_disk *disk __attribute__ ((unused)), + grub_disk_addr_t sector __attribute__ ((unused)), + grub_size_t size __attribute__ ((unused)), + const char *buf __attribute__ ((unused))) +{ + grub_dprintf ("ubootdisk", "attempt to write\n"); + return GRUB_ERR_NOT_IMPLEMENTED_YET; +} + +static struct grub_disk_dev grub_ubootdisk_dev = { + .name = "ubootdisk", + .id = GRUB_DISK_DEVICE_UBOOTDISK_ID, + .iterate = uboot_disk_iterate, + .open = uboot_disk_open, + .close = uboot_disk_close, + .read = uboot_disk_read, + .write = uboot_disk_write, + .next = 0 +}; + +void +grub_ubootdisk_init (void) +{ + grub_disk_dev_register (&grub_ubootdisk_dev); +} + +void +grub_ubootdisk_fini (void) +{ + grub_disk_dev_unregister (&grub_ubootdisk_dev); +} diff --git a/grub-core/kern/arm/cache.S b/grub-core/kern/arm/cache.S new file mode 100644 index 000000000..6d7ed8537 --- /dev/null +++ b/grub-core/kern/arm/cache.S @@ -0,0 +1,251 @@ +/* + * 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 . + */ + +#include +#include + + .file "cache.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 + +/* + * Simple cache maintenance functions + */ + +@ r0 - *beg (inclusive) +@ r1 - *end (exclusive) +clean_dcache_range: + @ Clean data cache range for range to point-of-unification + ldr r2, dlinesz +1: cmp r0, r1 + bge 2f +#ifdef DEBUG + push {r0-r2, lr} + mov r1, r2 + mov r2, r0 + ldr r0, =dcstr + bl EXT_C(grub_printf) + pop {r0-r2, lr} +#endif + mcr p15, 0, r0, c7, c11, 1 @ DCCMVAU + 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, ilinesz +1: cmp r0, r1 + bge 2f +#ifdef DEBUG + push {r0-r2, lr} + mov r1, r2 + mov r2, r0 + ldr r0, =icstr + bl EXT_C(grub_printf) + pop {r0-r2, lr} +#endif + 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 __wrap___clear_cache(char *beg, char *end); +FUNCTION(__wrap___clear_cache) + dmb + dsb + push {r4-r6, lr} + ldr r2, probed @ If first call, probe cache sizes + cmp r2, #0 + bleq probe_caches @ This call corrupts r3 + mov r4, r0 + mov r5, r1 + bl clean_dcache_range + mov r0, r4 + mov r1, r5 + bl invalidate_icache_range + pop {r4-r6, pc} + +probe_caches: + push {r4-r6, lr} + mrc p15, 0, r4, c0, c0, 1 @ Read Cache Type Register + mov r5, #1 + ubfx r6, r4, #16, #4 @ Extract min D-cache num word log2 + add r6, r6, #2 @ words->bytes + lsl r6, r5, r6 @ Convert to num bytes + ldr r3, =dlinesz + str r6, [r3] + and r6, r4, #0xf @ Extract min I-cache num word log2 + add r6, r6, #2 @ words->bytes + lsl r6, r5, r6 @ Convert to num bytes + ldr r3, =ilinesz + str r6, [r3] + ldr r3, =probed @ Flag cache probing done + str r5, [r3] + pop {r4-r6, pc} + +#ifdef DEBUG +dcstr: .asciz "cleaning %d bytes of D cache @ 0x%08x\n" +icstr: .asciz "invalidating %d bytes of I cache @ 0x%08x\n" +#endif + + .align 3 +probed: .long 0 +dlinesz: + .long 0 +ilinesz: + .long 0 + +@void grub_arch_sync_caches (void *address, grub_size_t len) +FUNCTION(grub_arch_sync_caches) + add r1, r0, r1 + b __wrap___clear_cache + + @ 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 + ubfx r1, r0, #24, #3 @ Extract LoC + + 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 CSSIDR 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 CSSIDR + ubfx r3, r8, #13, #14 @ Number of sets -1 + ubfx r4, r8, #3, #9 @ Number of ways -1 + 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 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} + +FUNCTION(grub_arm_disable_caches_mmu) + 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} + diff --git a/grub-core/kern/arm/dl.c b/grub-core/kern/arm/dl.c new file mode 100644 index 000000000..39a34ca5b --- /dev/null +++ b/grub-core/kern/arm/dl.c @@ -0,0 +1,490 @@ +/* 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 . + */ + +#include +#include +#include +#include +#include +#include + +#ifdef GRUB_UTIL +# include +#else +# if !defined(__thumb2__) +# error "Relocations not implemented for A32 ("ARM") instruction set yet!" +# endif + +grub_err_t reloc_jump24 (grub_uint32_t *addr, Elf32_Addr sym_addr); +grub_err_t reloc_thm_call (grub_uint16_t *addr, Elf32_Addr sym_addr); +grub_err_t reloc_thm_jump19 (grub_uint16_t *addr, Elf32_Addr sym_addr); + +#ifdef DL_DEBUG +static const char *symstrtab; + +/* + * This is a bit of a hack, setting the symstrtab pointer to the last STRTAB + * section in the module (which is where symbol names are in the objects I've + * inspected manually). + */ +static void +set_symstrtab (Elf_Ehdr * e) +{ + int i; + Elf_Shdr *s; + + symstrtab = NULL; + + for (i = 0, s = (Elf_Shdr *) ((grub_uint32_t) e + e->e_shoff); + i < e->e_shnum; + i++, s = (Elf_Shdr *) ((grub_uint32_t) s + e->e_shentsize)) + if (s->sh_type == SHT_STRTAB) + symstrtab = (void *) ((grub_addr_t) e + s->sh_offset); +} + +static const char * +get_symbolname (Elf_Sym * sym) +{ + const char *symbolname = symstrtab + sym->st_name; + + return (*symbolname ? symbolname : NULL); +} +#endif /* DL_DEBUG */ + +/* + * R_ARM_ABS32 + * + * Simple relocation of 32-bit value (in literal pool) + */ +static grub_err_t +reloc_abs32 (Elf_Word *target, Elf_Addr sym_addr) +{ + Elf_Addr tmp; + + tmp = *target; + tmp += sym_addr; + *target = tmp; +#if 0 //def GRUB_UTIL + grub_util_info (" %s: reloc_abs32 0x%08x => 0x%08x", __FUNCTION__, + (unsigned int) sym_addr, (unsigned int) tmp); +#endif + + return GRUB_ERR_NONE; +} +#endif /* ndef GRUB_UTIL */ + + +/******************************************************************** + * 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 +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 = (*target << 16) | (*(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)) + { +#ifndef GRUB_UTIL + return grub_error + (GRUB_ERR_BUG, N_("Relocation targeting wrong execution state")); +#else + grub_util_error ("Relocation targeting wrong execution state"); +#endif + } + + 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); +#ifdef GRUB_UTIL + grub_util_info (" sym_addr = 0x%08x", sym_addr); +#endif +#ifdef GRUB_UTIL + offset += sym_addr; +#else + offset += sym_addr - (grub_uint32_t) target; +#endif +#ifdef DEBUG + grub_printf(" %s: target=0x%08x, sym_addr=0x%08x, offset=%d\n", + is_blx ? "BLX" : "BL", (unsigned int) target, sym_addr, offset); +#endif + + if ((offset < offset_low) || (offset > offset_high)) + { +#ifdef GRUB_UTIL + grub_util_error ("Relocation out of range"); +#else + return grub_error + (GRUB_ERR_OUT_OF_RANGE, N_("THM_CALL Relocation out of range.")); +#endif + } + +#ifdef GRUB_UTIL + grub_util_info (" relative destination = 0x%08x", + (unsigned int)target + offset); +#endif + + /* 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 = (insword >> 16) & 0xffff; + *(target + 1) = insword & 0xffff; + +#ifdef GRUB_UTIL +#pragma GCC diagnostic ignored "-Wcast-align" + grub_util_info (" *target = 0x%08x", *((unsigned int *)target)); +#endif + + return GRUB_ERR_NONE; +} + +/* + * R_ARM_THM_JUMP19 + * + * Relocate conditional Thumb (T32) B.W + */ +grub_err_t +reloc_thm_jump19 (grub_uint16_t *addr, Elf32_Addr sym_addr) +{ + grub_int32_t offset; + grub_uint32_t insword, insmask; + + /* Extract instruction word in alignment-safe manner */ + insword = (*addr) << 16 | *(addr + 1); + insmask = 0xfbc0d800; + + /* Extract and sign extend offset */ + offset = ((insword >> 26) & 1) << 18 + | ((insword >> 11) & 1) << 17 + | ((insword >> 13) & 1) << 16 + | ((insword >> 16) & 0x3f) << 11 + | (insword & 0x7ff); + offset <<= 1; + if (offset & (1 << 19)) + offset -= (1 << 20); + + /* Adjust and re-truncate offset */ +#ifdef GRUB_UTIL + offset += sym_addr; +#else + offset += sym_addr - (grub_uint32_t) addr; +#endif + if ((offset > 1048574) || (offset < -1048576)) + { + return grub_error + (GRUB_ERR_OUT_OF_RANGE, N_("THM_JUMP19 Relocation out of range.")); + } + + offset >>= 1; + offset &= 0x7ffff; + + /* Reassemble instruction word and write back */ + insword &= insmask; + insword |= ((offset >> 18) & 1) << 26 + | ((offset >> 17) & 1) << 11 + | ((offset >> 16) & 1) << 13 + | ((offset >> 11) & 0x3f) << 16 + | (offset & 0x7ff); + *addr = insword >> 16; + *(addr + 1) = 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 +reloc_jump24 (grub_uint32_t *addr, Elf32_Addr sym_addr) +{ + grub_uint32_t insword; + grub_int32_t offset; + + insword = *addr; + + offset = (insword & 0x00ffffff) << 2; + if (offset & 0x02000000) + offset -= 0x04000000; +#ifdef GRUB_UTIL + offset += sym_addr; +#else + offset += sym_addr - (grub_uint32_t) addr; +#endif + + insword &= 0xff000000; + insword |= (offset >> 2) & 0x00ffffff; + + *addr = insword; + + return GRUB_ERR_NONE; +} + + + +/************************************************* + * Runtime dynamic linker with helper functions. * + *************************************************/ +#ifndef GRUB_UTIL +/* + * find_segment(): finds a module segment matching sh_info + */ +static grub_dl_segment_t +find_segment (grub_dl_segment_t seg, Elf32_Word sh_info) +{ + for (; seg; seg = seg->next) + if (seg->section == sh_info) + return seg; + + return NULL; +} + + +/* + * do_relocations(): + * Iterate over all relocations in section, calling appropriate functions + * for patching. + */ +static grub_err_t +do_relocations (Elf_Shdr * relhdr, Elf_Ehdr * e, grub_dl_t mod) +{ + grub_dl_segment_t seg; + Elf_Rel *rel; + Elf_Sym *sym; + int i, entnum; + + entnum = relhdr->sh_size / sizeof (Elf_Rel); + + /* Find the target segment for this relocation section. */ + seg = find_segment (mod->segment, relhdr->sh_info); + if (!seg) + return grub_error (GRUB_ERR_EOF, N_("relocation segment not found")); + + rel = (Elf_Rel *) ((grub_addr_t) e + relhdr->sh_offset); + + /* Step through all relocations */ + for (i = 0, sym = mod->symtab; i < entnum; i++) + { + Elf_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 = (Elf_Word *) ((grub_addr_t) seg->addr + rel[i].r_offset); + + sym_addr = sym[relsym].st_value; + +#ifdef DL_DEBUG + + grub_printf ("%s: 0x%08x -> %s @ 0x%08x\n", __FUNCTION__, + (grub_addr_t) sym_addr, get_symbolname (sym), sym->st_value); +#endif + + switch (reltype) + { + case R_ARM_ABS32: + { + /* Data will be naturally aligned */ + retval = reloc_abs32 (target, sym_addr); + if (retval != GRUB_ERR_NONE) + return retval; + } + break; + case R_ARM_JUMP24: + { + retval = 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 = 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 = 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")); + +#ifdef DL_DEBUG + set_symstrtab (e); +#endif + +#define FIRST_SHDR(x) ((Elf_Shdr *) ((grub_addr_t)(x) + (x)->e_shoff)) +#define NEXT_SHDR(x, y) ((Elf_Shdr *) ((grub_addr_t)(y) + (x)->e_shentsize)) + + for (i = 0, s = FIRST_SHDR (e); i < e->e_shnum; i++, s = NEXT_SHDR (e, s)) + { + grub_err_t ret; + + switch (s->sh_type) + { + case SHT_REL: + { + /* Relocations, no addends */ + ret = do_relocations (s, e, mod); + if (ret != GRUB_ERR_NONE) + return ret; + } + break; + case SHT_NULL: + case SHT_PROGBITS: + case SHT_SYMTAB: + case SHT_STRTAB: + case SHT_NOBITS: + case SHT_ARM_ATTRIBUTES: + break; + case SHT_RELA: + default: + { + grub_printf ("unhandled section_type: %d (0x%08x)\n", + s->sh_type, s->sh_type); + return GRUB_ERR_NOT_IMPLEMENTED_YET; + }; + } + } + +#undef FIRST_SHDR +#undef NEXT_SHDR + + return GRUB_ERR_NONE; +} +#endif /* ndef GRUB_UTIL */ diff --git a/grub-core/kern/arm/efi/init.c b/grub-core/kern/arm/efi/init.c new file mode 100644 index 000000000..3a2b74dcc --- /dev/null +++ b/grub-core/kern/arm/efi/init.c @@ -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 . + */ + +#include +#include +#include +#include +#include +#include + +/* + * 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 (); +} diff --git a/grub-core/kern/arm/efi/misc.c b/grub-core/kern/arm/efi/misc.c new file mode 100644 index 000000000..efec98061 --- /dev/null +++ b/grub-core/kern/arm/efi/misc.c @@ -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 . + */ + +#include +#include +#include +#include +#include +#include + +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; +} diff --git a/grub-core/kern/arm/efi/startup.S b/grub-core/kern/arm/efi/startup.S new file mode 100644 index 000000000..557ec6c3d --- /dev/null +++ b/grub-core/kern/arm/efi/startup.S @@ -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 + + .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 diff --git a/grub-core/kern/arm/misc.S b/grub-core/kern/arm/misc.S new file mode 100644 index 000000000..c2170f669 --- /dev/null +++ b/grub-core/kern/arm/misc.S @@ -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 . + */ + +#include +#include + + .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 diff --git a/grub-core/kern/arm/uboot/startup.S b/grub-core/kern/arm/uboot/startup.S new file mode 100644 index 000000000..0ed33cc42 --- /dev/null +++ b/grub-core/kern/arm/uboot/startup.S @@ -0,0 +1,176 @@ +/* + * 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 . + */ + +#include +#include +#include + +/* + * 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). + * : + * Any part of the module blob that extends beyond _end. + * : + * Loadable modules, post relocation. + * : + * : + */ + + .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) + + @ Put kernel parameters aside until we can store them (further down) + mov r4, r1 @ machine type + mov r5, r2 @ boot data + + @ Modules have been stored as a blob in BSS, + @ they need to be manually relocated to _end or + @ (__bss_start + grub_total_module_size), whichever greater. + bl uboot_get_real_bss_start @ r0 = src + ldr r1, =EXT_C(_end) @ dst = End of BSS + ldr r2, grub_total_module_size @ blob size + add r3, r0, r2 @ blob end + cmp r1, r3 @ _end < blob end? + movlt r1, r3 @ dst = blob end + blob size + +1: ldr r3, [r0], #4 @ r3 = *src++ + str r3, [r1], #4 @ *dst++ = r3 + subs r2, #4 @ remaining -= 4 + bne 1b @ while remaining != 0 + + @ Set up a new stack, beyond the end of copied modules. + ldr r3, =GRUB_KERNEL_MACHINE_STACK_SIZE + add r3, r1, r3 @ Place stack beyond end of modules + and sp, r3, #~0x7 @ Ensure 8-byte alignment + + @ Since we _are_ the C run-time, we need to manually zero the BSS + @ region before continuing + bl uboot_get_real_bss_start @ zero from here + ldr r1, =EXT_C(_end) @ to here + mov r2, #0 +1: str r2, [r0], #4 + cmp r0, r1 + bne 1b + + @ Global variables now accessible - store kernel parameters in memory + ldr r12, =EXT_C(uboot_machine_type) + str r4, [r12] + ldr r12, =EXT_C(uboot_boot_data) + str r5, [r12] + + b EXT_C(grub_main) + + /* + * __bss_start does not actually point to the start of the runtime + * BSS, but rather to the next byte following the preceding data. + */ +FUNCTION (uboot_get_real_bss_start) + ldr r0, =EXT_C(__bss_start) @ src + tst r0, #(GRUB_KERNEL_MACHINE_MOD_ALIGN - 1) + beq 1f + mvn r1, #(GRUB_KERNEL_MACHINE_MOD_ALIGN - 1) + and r0, r0, r1 + add r0, r0, #(GRUB_KERNEL_MACHINE_MOD_ALIGN) +1: bx lr + + /* + * uboot_syscall(): + * This function is effectively a veneer, so it cannot + * modify the stack or corrupt any registers other than + * r12 (ip). Furthermore it needs to restore r8 for + * U-Boot (Global Data Pointer) and preserve it for Grub. + */ +FUNCTION(uboot_syscall) + ldr ip, =transition_space + stm ip, {r8, lr} + ldr ip, =gd_backup + ldr r8, [ip] + ldr ip, =uboot_syscall_ptr + mov lr, pc + ldr pc, [ip] + ldr ip, =gd_backup + str r8, [ip] + ldr ip, =transition_space + ldm ip, {r8, lr} + bx lr + +FUNCTION(uboot_return) + ldr sp, =entry_state_end + pop {r4-r12, lr} + mov sp, r12 + bx lr + + + .data + .align 3 @ 8-byte alignment for stack +@ U-boot context stack space +entry_state_end: + .long 0 @ r4 + .long 0 @ r5 + .long 0 @ r6 + .long 0 @ r7 +gd_backup: + .long 0 @ r8 - U-Boot global data pointer + .long 0 @ r9 + .long 0 @ r10 + .long 0 @ r11 +VARIABLE(uboot_search_hint)@ U-Boot stack pointer - + .long 0 @ also API signature address hint. + .long 0 @ lr +entry_state: @ backup for U-Boot context + +@ GRUB context stack space +transition_space: + .long 0 @ r8 + .long 0 @ lr + +VARIABLE(uboot_syscall_ptr) + .long 0 @ + + .end diff --git a/grub-core/kern/uboot/hw.c b/grub-core/kern/uboot/hw.c new file mode 100644 index 000000000..afa1e1069 --- /dev/null +++ b/grub-core/kern/uboot/hw.c @@ -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 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +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 = uboot_get_sys_info (); + + grub_mm_init_region ((void *) (grub_modules_get_end () + + GRUB_KERNEL_MACHINE_STACK_SIZE), + 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 = uboot_dev_enum (); + grub_dprintf ("init", "%d devices found\n", devcount); + + for (i = 0; i < devcount; i++) + { + struct device_info *devinfo = 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, i); + } + else if (devinfo->type & DEV_TYP_NET) + { + grub_dprintf ("init", " type\t\t= NET (not supported yet)\n"); + } + else + { + grub_dprintf ("init", "%s: unknown device type", __FUNCTION__); + } + } + + return GRUB_ERR_NONE; +} + +grub_err_t +grub_machine_mmap_iterate (grub_memory_hook_t hook, void *hook_data) +{ + int i; + struct sys_info *si = 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; +} diff --git a/grub-core/kern/uboot/init.c b/grub-core/kern/uboot/init.c new file mode 100644 index 000000000..b9944a452 --- /dev/null +++ b/grub-core/kern/uboot/init.c @@ -0,0 +1,171 @@ +/* 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 . + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern char __bss_start[]; +extern char _end[]; +extern grub_size_t grub_total_module_size; +extern int (*uboot_syscall_ptr) (int, int *, ...); + +grub_addr_t grub_modbase; + +grub_uint32_t uboot_machine_type; +grub_addr_t uboot_boot_data; + +static unsigned long timer_start; + +void +grub_exit (void) +{ + uboot_return (0); +} + +grub_uint32_t +uboot_get_machine_type (void) +{ + return uboot_machine_type; +} + +grub_addr_t +uboot_get_boot_data (void) +{ + return uboot_boot_data; +} + +static grub_uint64_t +uboot_timer_ms (void) +{ + return (grub_uint64_t) uboot_get_timer (timer_start); +} + +void +grub_machine_init (void) +{ + grub_addr_t end, real_bss_start; + int ver; + + /* First of all - establish connection with U-Boot */ + ver = 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 */ + uboot_puts ("invalid U-Boot API version\n"); + } + + /* + * Modules were relocated to _end, or __bss_start + grub_total_module_size, + * whichever greater. (And __bss_start may not point to actual BSS start...) + */ + real_bss_start = uboot_get_real_bss_start (); + end = real_bss_start + grub_total_module_size; + if (end < (grub_addr_t) _end) + end = (grub_addr_t) _end; + grub_modbase = end; + + /* Initialize the console so that GRUB can display messages. */ + grub_console_init_early (); + + /* Enumerate memory and initialize the memory management system. */ + grub_uboot_mm_init (); + + grub_dprintf ("init", "__bss_start: 0x%08x, real_bss_start: 0x%08x\n", + (grub_addr_t) __bss_start, real_bss_start); + grub_dprintf ("init", "end: 0x%08x, _end: 0x%08x\n", + (grub_addr_t) end, (grub_addr_t) _end); + grub_dprintf ("init", "grub_modbase: %p\n", (void *) grub_modbase); + grub_dprintf ("init", "grub_modules_get_end(): %p\n", + (void *) grub_modules_get_end ()); + + /* Initialise full terminfo support */ + grub_console_init_lately (); + + /* Enumerate uboot devices */ + grub_uboot_probe_hardware (); + + /* Initialise timer */ + timer_start = 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 = uboot_env_get ("grub_bootdev"); + if (tmp) + { + *device = grub_malloc (grub_strlen (tmp) + 1); + if (*device == NULL) + return; + grub_strncpy (*device, tmp, grub_strlen (tmp) + 1); + } + else + *device = NULL; + + tmp = uboot_env_get ("grub_bootpath"); + if (tmp) + { + *path = grub_malloc (grub_strlen (tmp) + 1); + if (*path == NULL) + return; + grub_strncpy (*path, tmp, grub_strlen (tmp) + 1); + } + else + *path = NULL; +} + +void +grub_uboot_fini (void) +{ + grub_ubootdisk_fini (); + grub_console_fini (); +} diff --git a/grub-core/kern/uboot/uboot.c b/grub-core/kern/uboot/uboot.c new file mode 100644 index 000000000..1e78d8ad9 --- /dev/null +++ b/grub-core/kern/uboot/uboot.c @@ -0,0 +1,363 @@ +/* + * 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 . + */ + +#include +#include +#include + +/* + * 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 (*uboot_syscall_ptr) (int, int *, ...); +extern int uboot_syscall (int, int *, ...); +extern grub_addr_t uboot_search_hint; + +static struct sys_info uboot_sys_info; +static struct mem_region uboot_mem_info[5]; +static struct device_info uboot_devices[6]; +static int num_devices; + +int +uboot_api_init (void) +{ + struct api_signature *start, *end; + struct api_signature *p; + + if (uboot_search_hint) + { + /* Extended search range to work around Trim Slice U-Boot issue */ + start = (struct api_signature *) ((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) + { + uboot_syscall_ptr = p->syscall; + return p->version; + } + } + + return 0; +} + +/* All functions below are wrappers around the uboot_syscall() function */ + +/* + * int API_getc(int *c) + */ +int +uboot_getc (void) +{ + int c; + if (!uboot_syscall (API_GETC, NULL, &c)) + return -1; + + return c; +} + +/* + * int API_tstc(int *c) + */ +int +uboot_tstc (void) +{ + int c; + if (!uboot_syscall (API_TSTC, NULL, &c)) + return -1; + + return c; +} + +/* + * int API_putc(char *ch) + */ +void +uboot_putc (int c) +{ + uboot_syscall (API_PUTC, NULL, &c); +} + +/* + * int API_puts(const char *s) + */ +void +uboot_puts (const char *s) +{ + uboot_syscall (API_PUTS, NULL, s); +} + +/* + * int API_reset(void) + */ +void +uboot_reset (void) +{ + uboot_syscall (API_RESET, NULL, 0); +} + +/* + * int API_get_sys_info(struct sys_info *si) + * + * fill out the sys_info struct containing selected parameters about the + * machine + */ +struct sys_info * +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 (uboot_syscall (API_GET_SYS_INFO, &retval, &uboot_sys_info)) + if (retval == 0) + return &uboot_sys_info; + + return NULL; +} + +/* + * int API_udelay(unsigned long *udelay) + */ +void +uboot_udelay (grub_uint32_t usec) +{ + uboot_syscall (API_UDELAY, NULL, &usec); +} + +/* + * int API_get_timer(unsigned long *current, unsigned long *base) + */ +grub_uint32_t +uboot_get_timer (grub_uint32_t base) +{ + grub_uint32_t current; + + if (!uboot_syscall (API_GET_TIMER, NULL, ¤t, &base)) + return 0; + + return current; +} + +/* + * int API_dev_enum(struct device_info *) + * + */ +int +uboot_dev_enum (void) +{ + int max; + + grub_memset (&uboot_devices, 0, sizeof (uboot_devices)); + max = sizeof (uboot_devices) / sizeof (struct device_info); + + /* + * 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 prevoiusly enumerated device cookie "seeded" into the target + * structure. + */ + if (!uboot_syscall (API_DEV_ENUM, NULL, &uboot_devices) + || uboot_devices[0].cookie == NULL) + return 0; + + for (num_devices = 1; num_devices < max; num_devices++) + { + uboot_devices[num_devices].cookie = + uboot_devices[num_devices - 1].cookie; + if (!uboot_syscall (API_DEV_ENUM, NULL, &uboot_devices[num_devices])) + return 0; + + /* When no more devices to enumerate, target cookie set to NULL */ + if (uboot_devices[num_devices].cookie == NULL) + break; + } + + return num_devices; +} + +#define VALID_DEV(x) (((x) < num_devices) && ((x) >= 0)) +#define OPEN_DEV(x) (VALID_DEV(x) && (uboot_devices[(x)].state == DEV_STA_OPEN)) + +struct device_info * +uboot_dev_get (int handle) +{ + if (VALID_DEV (handle)) + return &uboot_devices[handle]; + + return NULL; +} + + +/* + * int API_dev_open(struct device_info *) + */ +int +uboot_dev_open (int handle) +{ + struct device_info *dev; + int retval; + + if (!VALID_DEV (handle)) + return -1; + + dev = &uboot_devices[handle]; + + if (!uboot_syscall (API_DEV_OPEN, &retval, dev)) + return -1; + + return retval; +} + +/* + * int API_dev_close(struct device_info *) + */ +int +uboot_dev_close (int handle) +{ + struct device_info *dev; + int retval; + + if (!VALID_DEV (handle)) + return -1; + + dev = &uboot_devices[handle]; + + if (!uboot_syscall (API_DEV_CLOSE, &retval, dev)) + return -1; + + return retval; +} + + +/* + * int API_dev_read(struct device_info *di, void *buf, size_t *len, + * unsigned long *start, size_t *act_len) + */ +int +uboot_dev_read (int handle, void *buf, lbasize_t blocks, + lbastart_t start, lbasize_t * real_blocks) +{ + struct device_info *dev; + int retval; + + if (!OPEN_DEV (handle)) + return -1; + + dev = &uboot_devices[handle]; + + if (!uboot_syscall (API_DEV_READ, &retval, dev, buf, + &blocks, &start, real_blocks)) + return -1; + + return retval; +} + +/* + * int API_dev_read(struct device_info *di, void *buf, + * size_t *len, size_t *act_len) + */ +int +uboot_dev_recv (int handle, void *buf, int size, int *real_size) +{ + struct device_info *dev; + int retval; + + if (!OPEN_DEV (handle)) + return -1; + + dev = &uboot_devices[handle]; + if (!uboot_syscall (API_DEV_READ, &retval, dev, buf, &size, real_size)) + return -1; + + return retval; + +} + +/* + * Notice: this is for sending network packets only, as U-Boot does not + * support writing to storage at the moment (12.2007) + * + * int API_dev_write(struct device_info *di, void *buf, int *len) + */ +int +uboot_dev_send (int handle, void *buf, int size) +{ + struct device_info *dev; + int retval; + + if (!OPEN_DEV (handle)) + return -1; + + dev = &uboot_devices[handle]; + if (!uboot_syscall (API_DEV_WRITE, &retval, dev, buf, &size)) + return -1; + + return retval; +} + +/* + * int API_env_get(const char *name, char **value) + */ +char * +uboot_env_get (const char *name) +{ + char *value; + + if (!uboot_syscall (API_ENV_GET, NULL, name, &value)) + return NULL; + + return value; +} + +/* + * int API_env_set(const char *name, const char *value) + */ +void +uboot_env_set (const char *name, const char *value) +{ + uboot_syscall (API_ENV_SET, NULL, name, value); +} diff --git a/grub-core/lib/arm/setjmp.S b/grub-core/lib/arm/setjmp.S new file mode 100644 index 000000000..7038a229c --- /dev/null +++ b/grub-core/lib/arm/setjmp.S @@ -0,0 +1,55 @@ +/* + * 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 . + */ + +#include +#include + + .file "setjmp.S" + .syntax unified +#if !defined (__thumb2__) + .arm +#define ARM(x...) x +#define THUMB(x...) +#else + .thumb +#define THUMB(x...) x +#define ARM(x...) +#endif + + .text + +/* + * int grub_setjmp (grub_jmp_buf env) + */ +FUNCTION(grub_setjmp) + THUMB( mov ip, sp ) + THUMB( stm r0, { r4-r11, ip, lr } ) + ARM( stm r0, { r4-r11, sp, lr } ) + mov r0, #0 + bx lr + +/* + * int grub_longjmp (grub_jmp_buf env, int val) + */ +FUNCTION(grub_longjmp) + THUMB( ldm r0, { r4-r11, ip, lr } ) + THUMB( mov sp, ip ) + ARM( ldm r0, { r4-r11, sp, lr } ) + movs r0, r1 + moveq r0, #1 + bx lr diff --git a/grub-core/lib/dtc/libfdt-grub.diff b/grub-core/lib/dtc/libfdt-grub.diff new file mode 100644 index 000000000..173619d0d --- /dev/null +++ b/grub-core/lib/dtc/libfdt-grub.diff @@ -0,0 +1,45 @@ +diff -purN libfdt.orig/fdt_rw.c libfdt/fdt_rw.c +--- libfdt.orig/fdt_rw.c 2011-05-08 20:45:39.000000000 +0100 ++++ libfdt/fdt_rw.c 2012-10-19 15:33:11.085523185 +0100 +@@ -88,9 +88,9 @@ static int _fdt_rw_check_header(void *fd + + #define FDT_RW_CHECK_HEADER(fdt) \ + { \ +- int err; \ +- if ((err = _fdt_rw_check_header(fdt)) != 0) \ +- return err; \ ++ int macro_err; \ ++ if ((macro_err = _fdt_rw_check_header(fdt)) != 0) \ ++ return macro_err; \ + } + + static inline int +diff -purN libfdt.orig/libfdt_env.h libfdt/libfdt_env.h +--- libfdt.orig/libfdt_env.h 2011-05-08 20:45:39.000000000 +0100 ++++ libfdt/libfdt_env.h 2012-10-19 16:13:19.051344173 +0100 +@@ -7,6 +7,9 @@ + #include + #include + #include ++#pragma GCC diagnostic ignored "-Wcast-align" ++#pragma GCC diagnostic ignored "-Wsign-compare" ++typedef grub_addr_t uintptr_t; + + #define _B(n) ((unsigned long long)((uint8_t *)&x)[n]) + static inline uint32_t +diff -purN libfdt.orig/libfdt_internal.h libfdt/libfdt_internal.h +--- libfdt.orig/libfdt_internal.h 2011-05-08 20:45:39.000000000 +0100 ++++ libfdt/libfdt_internal.h 2012-10-19 15:33:11.105524731 +0100 +@@ -60,9 +60,9 @@ + + #define FDT_CHECK_HEADER(fdt) \ + { \ +- int err; \ +- if ((err = fdt_check_header(fdt)) != 0) \ +- return err; \ ++ int macro_err; \ ++ if ((macro_err = fdt_check_header(fdt)) != 0) \ ++ return macro_err; \ + } + + int _fdt_check_node_offset (const void *fdt, int offset); diff --git a/grub-core/lib/dtc/libfdt/Makefile.libfdt b/grub-core/lib/dtc/libfdt/Makefile.libfdt new file mode 100644 index 000000000..d55a6f852 --- /dev/null +++ b/grub-core/lib/dtc/libfdt/Makefile.libfdt @@ -0,0 +1,10 @@ +# Makefile.libfdt +# +# This is not a complete Makefile of itself. Instead, it is designed to +# be easily embeddable into other systems of Makefiles. +# +LIBFDT_soname = libfdt.$(SHAREDLIB_EXT).1 +LIBFDT_INCLUDES = fdt.h libfdt.h +LIBFDT_VERSION = version.lds +LIBFDT_SRCS = fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c +LIBFDT_OBJS = $(LIBFDT_SRCS:%.c=%.o) diff --git a/grub-core/lib/dtc/libfdt/TODO b/grub-core/lib/dtc/libfdt/TODO new file mode 100644 index 000000000..288437e39 --- /dev/null +++ b/grub-core/lib/dtc/libfdt/TODO @@ -0,0 +1,3 @@ +- Tree traversal functions +- Graft function +- Complete libfdt.h documenting comments diff --git a/grub-core/lib/dtc/libfdt/fdt.c b/grub-core/lib/dtc/libfdt/fdt.c new file mode 100644 index 000000000..e8627349e --- /dev/null +++ b/grub-core/lib/dtc/libfdt/fdt.c @@ -0,0 +1,241 @@ +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + * + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * + * a) This library 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 library 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 library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * Alternatively, + * + * b) 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + */ +#include "libfdt_env.h" + +#include +#include + +#include "libfdt_internal.h" + +int +fdt_check_header (const void *fdt) +{ + if (fdt_magic (fdt) == FDT_MAGIC) + { + /* Complete tree */ + if (fdt_version (fdt) < FDT_FIRST_SUPPORTED_VERSION) + return -FDT_ERR_BADVERSION; + if (fdt_last_comp_version (fdt) > FDT_LAST_SUPPORTED_VERSION) + return -FDT_ERR_BADVERSION; + } + else if (fdt_magic (fdt) == FDT_SW_MAGIC) + { + /* Unfinished sequential-write blob */ + if (fdt_size_dt_struct (fdt) == 0) + return -FDT_ERR_BADSTATE; + } + else + { + return -FDT_ERR_BADMAGIC; + } + + return 0; +} + +const void * +fdt_offset_ptr (const void *fdt, int offset, unsigned int len) +{ + const char *p; + + if (fdt_version (fdt) >= 0x11) + if (((offset + len) < offset) + || ((offset + len) > fdt_size_dt_struct (fdt))) + return NULL; + + p = _fdt_offset_ptr (fdt, offset); + + if (p + len < p) + return NULL; + return p; +} + +uint32_t +fdt_next_tag (const void *fdt, int startoffset, int *nextoffset) +{ + const uint32_t *tagp, *lenp; + uint32_t tag; + int offset = startoffset; + const char *p; + + *nextoffset = -FDT_ERR_TRUNCATED; + tagp = fdt_offset_ptr (fdt, offset, FDT_TAGSIZE); + if (!tagp) + return FDT_END; /* premature end */ + tag = fdt32_to_cpu (*tagp); + offset += FDT_TAGSIZE; + + *nextoffset = -FDT_ERR_BADSTRUCTURE; + switch (tag) + { + case FDT_BEGIN_NODE: + /* skip name */ + do + { + p = fdt_offset_ptr (fdt, offset++, 1); + } + while (p && (*p != '\0')); + if (!p) + return FDT_END; /* premature end */ + break; + + case FDT_PROP: + lenp = fdt_offset_ptr (fdt, offset, sizeof (*lenp)); + if (!lenp) + return FDT_END; /* premature end */ + /* skip-name offset, length and value */ + offset += sizeof (struct fdt_property) - FDT_TAGSIZE + + fdt32_to_cpu (*lenp); + break; + + case FDT_END: + case FDT_END_NODE: + case FDT_NOP: + break; + + default: + return FDT_END; + } + + if (!fdt_offset_ptr (fdt, startoffset, offset - startoffset)) + return FDT_END; /* premature end */ + + *nextoffset = FDT_TAGALIGN (offset); + return tag; +} + +int +_fdt_check_node_offset (const void *fdt, int offset) +{ + if ((offset < 0) || (offset % FDT_TAGSIZE) + || (fdt_next_tag (fdt, offset, &offset) != FDT_BEGIN_NODE)) + return -FDT_ERR_BADOFFSET; + + return offset; +} + +int +_fdt_check_prop_offset (const void *fdt, int offset) +{ + if ((offset < 0) || (offset % FDT_TAGSIZE) + || (fdt_next_tag (fdt, offset, &offset) != FDT_PROP)) + return -FDT_ERR_BADOFFSET; + + return offset; +} + +int +fdt_next_node (const void *fdt, int offset, int *depth) +{ + int nextoffset = 0; + uint32_t tag; + + if (offset >= 0) + if ((nextoffset = _fdt_check_node_offset (fdt, offset)) < 0) + return nextoffset; + + do + { + offset = nextoffset; + tag = fdt_next_tag (fdt, offset, &nextoffset); + + switch (tag) + { + case FDT_PROP: + case FDT_NOP: + break; + + case FDT_BEGIN_NODE: + if (depth) + (*depth)++; + break; + + case FDT_END_NODE: + if (depth && ((--(*depth)) < 0)) + return nextoffset; + break; + + case FDT_END: + if ((nextoffset >= 0) + || ((nextoffset == -FDT_ERR_TRUNCATED) && !depth)) + return -FDT_ERR_NOTFOUND; + else + return nextoffset; + } + } + while (tag != FDT_BEGIN_NODE); + + return offset; +} + +const char * +_fdt_find_string (const char *strtab, int tabsize, const char *s) +{ + int len = strlen (s) + 1; + const char *last = strtab + tabsize - len; + const char *p; + + for (p = strtab; p <= last; p++) + if (memcmp (p, s, len) == 0) + return p; + return NULL; +} + +int +fdt_move (const void *fdt, void *buf, int bufsize) +{ + FDT_CHECK_HEADER (fdt); + + if (fdt_totalsize (fdt) > bufsize) + return -FDT_ERR_NOSPACE; + + memmove (buf, fdt, fdt_totalsize (fdt)); + return 0; +} diff --git a/grub-core/lib/dtc/libfdt/fdt.h b/grub-core/lib/dtc/libfdt/fdt.h new file mode 100644 index 000000000..25bd3082a --- /dev/null +++ b/grub-core/lib/dtc/libfdt/fdt.h @@ -0,0 +1,64 @@ +#ifndef _FDT_H +#define _FDT_H + +#ifndef __ASSEMBLY__ + +struct fdt_header +{ + uint32_t magic; /* magic word FDT_MAGIC */ + uint32_t totalsize; /* total size of DT block */ + uint32_t off_dt_struct; /* offset to structure */ + uint32_t off_dt_strings; /* offset to strings */ + uint32_t off_mem_rsvmap; /* offset to memory reserve map */ + uint32_t version; /* format version */ + uint32_t last_comp_version; /* last compatible version */ + + /* version 2 fields below */ + uint32_t boot_cpuid_phys; /* Which physical CPU id we're + booting on */ + /* version 3 fields below */ + uint32_t size_dt_strings; /* size of the strings block */ + + /* version 17 fields below */ + uint32_t size_dt_struct; /* size of the structure block */ +}; + +struct fdt_reserve_entry +{ + uint64_t address; + uint64_t size; +}; + +struct fdt_node_header +{ + uint32_t tag; + char name[0]; +}; + +struct fdt_property +{ + uint32_t tag; + uint32_t len; + uint32_t nameoff; + char data[0]; +}; + +#endif /* !__ASSEMBLY */ + +#define FDT_MAGIC 0xd00dfeed /* 4: version, 4: total size */ +#define FDT_TAGSIZE sizeof(uint32_t) + +#define FDT_BEGIN_NODE 0x1 /* Start node: full name */ +#define FDT_END_NODE 0x2 /* End node */ +#define FDT_PROP 0x3 /* Property: name off, + size, content */ +#define FDT_NOP 0x4 /* nop */ +#define FDT_END 0x9 + +#define FDT_V1_SIZE (7*sizeof(uint32_t)) +#define FDT_V2_SIZE (FDT_V1_SIZE + sizeof(uint32_t)) +#define FDT_V3_SIZE (FDT_V2_SIZE + sizeof(uint32_t)) +#define FDT_V16_SIZE FDT_V3_SIZE +#define FDT_V17_SIZE (FDT_V16_SIZE + sizeof(uint32_t)) + +#endif /* _FDT_H */ diff --git a/grub-core/lib/dtc/libfdt/fdt_ro.c b/grub-core/lib/dtc/libfdt/fdt_ro.c new file mode 100644 index 000000000..7014e302d --- /dev/null +++ b/grub-core/lib/dtc/libfdt/fdt_ro.c @@ -0,0 +1,608 @@ +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + * + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * + * a) This library 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 library 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 library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * Alternatively, + * + * b) 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + */ +#include "libfdt_env.h" + +#include +#include + +#include "libfdt_internal.h" + +static int +_fdt_nodename_eq (const void *fdt, int offset, const char *s, int len) +{ + const char *p = fdt_offset_ptr (fdt, offset + FDT_TAGSIZE, len + 1); + + if (!p) + /* short match */ + return 0; + + if (memcmp (p, s, len) != 0) + return 0; + + if (p[len] == '\0') + return 1; + else if (!memchr (s, '@', len) && (p[len] == '@')) + return 1; + else + return 0; +} + +const char * +fdt_string (const void *fdt, int stroffset) +{ + return (const char *) fdt + fdt_off_dt_strings (fdt) + stroffset; +} + +static int +_fdt_string_eq (const void *fdt, int stroffset, const char *s, int len) +{ + const char *p = fdt_string (fdt, stroffset); + + return (strlen (p) == len) && (memcmp (p, s, len) == 0); +} + +int +fdt_get_mem_rsv (const void *fdt, int n, uint64_t * address, uint64_t * size) +{ + FDT_CHECK_HEADER (fdt); + *address = fdt64_to_cpu (_fdt_mem_rsv (fdt, n)->address); + *size = fdt64_to_cpu (_fdt_mem_rsv (fdt, n)->size); + return 0; +} + +int +fdt_num_mem_rsv (const void *fdt) +{ + int i = 0; + + while (fdt64_to_cpu (_fdt_mem_rsv (fdt, i)->size) != 0) + i++; + return i; +} + +static int +_nextprop (const void *fdt, int offset) +{ + uint32_t tag; + int nextoffset; + + do + { + tag = fdt_next_tag (fdt, offset, &nextoffset); + + switch (tag) + { + case FDT_END: + if (nextoffset >= 0) + return -FDT_ERR_BADSTRUCTURE; + else + return nextoffset; + + case FDT_PROP: + return offset; + } + offset = nextoffset; + } + while (tag == FDT_NOP); + + return -FDT_ERR_NOTFOUND; +} + +int +fdt_subnode_offset_namelen (const void *fdt, int offset, + const char *name, int namelen) +{ + int depth; + + FDT_CHECK_HEADER (fdt); + + for (depth = 0; + (offset >= 0) && (depth >= 0); + offset = fdt_next_node (fdt, offset, &depth)) + if ((depth == 1) && _fdt_nodename_eq (fdt, offset, name, namelen)) + return offset; + + if (depth < 0) + return -FDT_ERR_NOTFOUND; + return offset; /* error */ +} + +int +fdt_subnode_offset (const void *fdt, int parentoffset, const char *name) +{ + return fdt_subnode_offset_namelen (fdt, parentoffset, name, strlen (name)); +} + +int +fdt_path_offset (const void *fdt, const char *path) +{ + const char *end = path + strlen (path); + const char *p = path; + int offset = 0; + + FDT_CHECK_HEADER (fdt); + + /* see if we have an alias */ + if (*path != '/') + { + const char *q = strchr (path, '/'); + + if (!q) + q = end; + + p = fdt_get_alias_namelen (fdt, p, q - p); + if (!p) + return -FDT_ERR_BADPATH; + offset = fdt_path_offset (fdt, p); + + p = q; + } + + while (*p) + { + const char *q; + + while (*p == '/') + p++; + if (!*p) + return offset; + q = strchr (p, '/'); + if (!q) + q = end; + + offset = fdt_subnode_offset_namelen (fdt, offset, p, q - p); + if (offset < 0) + return offset; + + p = q; + } + + return offset; +} + +const char * +fdt_get_name (const void *fdt, int nodeoffset, int *len) +{ + const struct fdt_node_header *nh = _fdt_offset_ptr (fdt, nodeoffset); + int err; + + if (((err = fdt_check_header (fdt)) != 0) + || ((err = _fdt_check_node_offset (fdt, nodeoffset)) < 0)) + goto fail; + + if (len) + *len = strlen (nh->name); + + return nh->name; + +fail: + if (len) + *len = err; + return NULL; +} + +int +fdt_first_property_offset (const void *fdt, int nodeoffset) +{ + int offset; + + if ((offset = _fdt_check_node_offset (fdt, nodeoffset)) < 0) + return offset; + + return _nextprop (fdt, offset); +} + +int +fdt_next_property_offset (const void *fdt, int offset) +{ + if ((offset = _fdt_check_prop_offset (fdt, offset)) < 0) + return offset; + + return _nextprop (fdt, offset); +} + +const struct fdt_property * +fdt_get_property_by_offset (const void *fdt, int offset, int *lenp) +{ + int err; + const struct fdt_property *prop; + + if ((err = _fdt_check_prop_offset (fdt, offset)) < 0) + { + if (lenp) + *lenp = err; + return NULL; + } + + prop = _fdt_offset_ptr (fdt, offset); + + if (lenp) + *lenp = fdt32_to_cpu (prop->len); + + return prop; +} + +const struct fdt_property * +fdt_get_property_namelen (const void *fdt, + int offset, + const char *name, int namelen, int *lenp) +{ + for (offset = fdt_first_property_offset (fdt, offset); + (offset >= 0); (offset = fdt_next_property_offset (fdt, offset))) + { + const struct fdt_property *prop; + + if (!(prop = fdt_get_property_by_offset (fdt, offset, lenp))) + { + offset = -FDT_ERR_INTERNAL; + break; + } + if (_fdt_string_eq (fdt, fdt32_to_cpu (prop->nameoff), name, namelen)) + return prop; + } + + if (lenp) + *lenp = offset; + return NULL; +} + +const struct fdt_property * +fdt_get_property (const void *fdt, + int nodeoffset, const char *name, int *lenp) +{ + return fdt_get_property_namelen (fdt, nodeoffset, name, + strlen (name), lenp); +} + +const void * +fdt_getprop_namelen (const void *fdt, int nodeoffset, + const char *name, int namelen, int *lenp) +{ + const struct fdt_property *prop; + + prop = fdt_get_property_namelen (fdt, nodeoffset, name, namelen, lenp); + if (!prop) + return NULL; + + return prop->data; +} + +const void * +fdt_getprop_by_offset (const void *fdt, int offset, + const char **namep, int *lenp) +{ + const struct fdt_property *prop; + + prop = fdt_get_property_by_offset (fdt, offset, lenp); + if (!prop) + return NULL; + if (namep) + *namep = fdt_string (fdt, fdt32_to_cpu (prop->nameoff)); + return prop->data; +} + +const void * +fdt_getprop (const void *fdt, int nodeoffset, const char *name, int *lenp) +{ + return fdt_getprop_namelen (fdt, nodeoffset, name, strlen (name), lenp); +} + +uint32_t +fdt_get_phandle (const void *fdt, int nodeoffset) +{ + const uint32_t *php; + int len; + + /* FIXME: This is a bit sub-optimal, since we potentially scan + * over all the properties twice. */ + php = fdt_getprop (fdt, nodeoffset, "phandle", &len); + if (!php || (len != sizeof (*php))) + { + php = fdt_getprop (fdt, nodeoffset, "linux,phandle", &len); + if (!php || (len != sizeof (*php))) + return 0; + } + + return fdt32_to_cpu (*php); +} + +const char * +fdt_get_alias_namelen (const void *fdt, const char *name, int namelen) +{ + int aliasoffset; + + aliasoffset = fdt_path_offset (fdt, "/aliases"); + if (aliasoffset < 0) + return NULL; + + return fdt_getprop_namelen (fdt, aliasoffset, name, namelen, NULL); +} + +const char * +fdt_get_alias (const void *fdt, const char *name) +{ + return fdt_get_alias_namelen (fdt, name, strlen (name)); +} + +int +fdt_get_path (const void *fdt, int nodeoffset, char *buf, int buflen) +{ + int pdepth = 0, p = 0; + int offset, depth, namelen; + const char *name; + + FDT_CHECK_HEADER (fdt); + + if (buflen < 2) + return -FDT_ERR_NOSPACE; + + for (offset = 0, depth = 0; + (offset >= 0) && (offset <= nodeoffset); + offset = fdt_next_node (fdt, offset, &depth)) + { + while (pdepth > depth) + { + do + { + p--; + } + while (buf[p - 1] != '/'); + pdepth--; + } + + if (pdepth >= depth) + { + name = fdt_get_name (fdt, offset, &namelen); + if (!name) + return namelen; + if ((p + namelen + 1) <= buflen) + { + memcpy (buf + p, name, namelen); + p += namelen; + buf[p++] = '/'; + pdepth++; + } + } + + if (offset == nodeoffset) + { + if (pdepth < (depth + 1)) + return -FDT_ERR_NOSPACE; + + if (p > 1) /* special case so that root path is "/", not "" */ + p--; + buf[p] = '\0'; + return 0; + } + } + + if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0)) + return -FDT_ERR_BADOFFSET; + else if (offset == -FDT_ERR_BADOFFSET) + return -FDT_ERR_BADSTRUCTURE; + + return offset; /* error from fdt_next_node() */ +} + +int +fdt_supernode_atdepth_offset (const void *fdt, int nodeoffset, + int supernodedepth, int *nodedepth) +{ + int offset, depth; + int supernodeoffset = -FDT_ERR_INTERNAL; + + FDT_CHECK_HEADER (fdt); + + if (supernodedepth < 0) + return -FDT_ERR_NOTFOUND; + + for (offset = 0, depth = 0; + (offset >= 0) && (offset <= nodeoffset); + offset = fdt_next_node (fdt, offset, &depth)) + { + if (depth == supernodedepth) + supernodeoffset = offset; + + if (offset == nodeoffset) + { + if (nodedepth) + *nodedepth = depth; + + if (supernodedepth > depth) + return -FDT_ERR_NOTFOUND; + else + return supernodeoffset; + } + } + + if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0)) + return -FDT_ERR_BADOFFSET; + else if (offset == -FDT_ERR_BADOFFSET) + return -FDT_ERR_BADSTRUCTURE; + + return offset; /* error from fdt_next_node() */ +} + +int +fdt_node_depth (const void *fdt, int nodeoffset) +{ + int nodedepth; + int err; + + err = fdt_supernode_atdepth_offset (fdt, nodeoffset, 0, &nodedepth); + if (err) + return (err < 0) ? err : -FDT_ERR_INTERNAL; + return nodedepth; +} + +int +fdt_parent_offset (const void *fdt, int nodeoffset) +{ + int nodedepth = fdt_node_depth (fdt, nodeoffset); + + if (nodedepth < 0) + return nodedepth; + return fdt_supernode_atdepth_offset (fdt, nodeoffset, nodedepth - 1, NULL); +} + +int +fdt_node_offset_by_prop_value (const void *fdt, int startoffset, + const char *propname, + const void *propval, int proplen) +{ + int offset; + const void *val; + int len; + + FDT_CHECK_HEADER (fdt); + + /* FIXME: The algorithm here is pretty horrible: we scan each + * property of a node in fdt_getprop(), then if that didn't + * find what we want, we scan over them again making our way + * to the next node. Still it's the easiest to implement + * approach; performance can come later. */ + for (offset = fdt_next_node (fdt, startoffset, NULL); + offset >= 0; offset = fdt_next_node (fdt, offset, NULL)) + { + val = fdt_getprop (fdt, offset, propname, &len); + if (val && (len == proplen) && (memcmp (val, propval, len) == 0)) + return offset; + } + + return offset; /* error from fdt_next_node() */ +} + +int +fdt_node_offset_by_phandle (const void *fdt, uint32_t phandle) +{ + int offset; + + if ((phandle == 0) || (phandle == -1)) + return -FDT_ERR_BADPHANDLE; + + FDT_CHECK_HEADER (fdt); + + /* FIXME: The algorithm here is pretty horrible: we + * potentially scan each property of a node in + * fdt_get_phandle(), then if that didn't find what + * we want, we scan over them again making our way to the next + * node. Still it's the easiest to implement approach; + * performance can come later. */ + for (offset = fdt_next_node (fdt, -1, NULL); + offset >= 0; offset = fdt_next_node (fdt, offset, NULL)) + { + if (fdt_get_phandle (fdt, offset) == phandle) + return offset; + } + + return offset; /* error from fdt_next_node() */ +} + +static int +_fdt_stringlist_contains (const char *strlist, int listlen, const char *str) +{ + int len = strlen (str); + const char *p; + + while (listlen >= len) + { + if (memcmp (str, strlist, len + 1) == 0) + return 1; + p = memchr (strlist, '\0', listlen); + if (!p) + return 0; /* malformed strlist.. */ + listlen -= (p - strlist) + 1; + strlist = p + 1; + } + return 0; +} + +int +fdt_node_check_compatible (const void *fdt, int nodeoffset, + const char *compatible) +{ + const void *prop; + int len; + + prop = fdt_getprop (fdt, nodeoffset, "compatible", &len); + if (!prop) + return len; + if (_fdt_stringlist_contains (prop, len, compatible)) + return 0; + else + return 1; +} + +int +fdt_node_offset_by_compatible (const void *fdt, int startoffset, + const char *compatible) +{ + int offset, err; + + FDT_CHECK_HEADER (fdt); + + /* FIXME: The algorithm here is pretty horrible: we scan each + * property of a node in fdt_node_check_compatible(), then if + * that didn't find what we want, we scan over them again + * making our way to the next node. Still it's the easiest to + * implement approach; performance can come later. */ + for (offset = fdt_next_node (fdt, startoffset, NULL); + offset >= 0; offset = fdt_next_node (fdt, offset, NULL)) + { + err = fdt_node_check_compatible (fdt, offset, compatible); + if ((err < 0) && (err != -FDT_ERR_NOTFOUND)) + return err; + else if (err == 0) + return offset; + } + + return offset; /* error from fdt_next_node() */ +} diff --git a/grub-core/lib/dtc/libfdt/fdt_rw.c b/grub-core/lib/dtc/libfdt/fdt_rw.c new file mode 100644 index 000000000..58bc4adf0 --- /dev/null +++ b/grub-core/lib/dtc/libfdt/fdt_rw.c @@ -0,0 +1,490 @@ +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + * + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * + * a) This library 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 library 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 library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * Alternatively, + * + * b) 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + */ +#include "libfdt_env.h" + +#include +#include + +#include "libfdt_internal.h" + +static int +_fdt_blocks_misordered (const void *fdt, int mem_rsv_size, int struct_size) +{ + return (fdt_off_mem_rsvmap (fdt) < + FDT_ALIGN (sizeof (struct fdt_header), 8)) + || (fdt_off_dt_struct (fdt) < (fdt_off_mem_rsvmap (fdt) + mem_rsv_size)) + || (fdt_off_dt_strings (fdt) < (fdt_off_dt_struct (fdt) + struct_size)) + || (fdt_totalsize (fdt) < + (fdt_off_dt_strings (fdt) + fdt_size_dt_strings (fdt))); +} + +static int +_fdt_rw_check_header (void *fdt) +{ + FDT_CHECK_HEADER (fdt); + + if (fdt_version (fdt) < 17) + return -FDT_ERR_BADVERSION; + if (_fdt_blocks_misordered (fdt, sizeof (struct fdt_reserve_entry), + fdt_size_dt_struct (fdt))) + return -FDT_ERR_BADLAYOUT; + if (fdt_version (fdt) > 17) + fdt_set_version (fdt, 17); + + return 0; +} + +#define FDT_RW_CHECK_HEADER(fdt) \ + { \ + int err; \ + if ((err = _fdt_rw_check_header(fdt)) != 0) \ + return err; \ + } + +static inline int +_fdt_data_size (void *fdt) +{ + return fdt_off_dt_strings (fdt) + fdt_size_dt_strings (fdt); +} + +static int +_fdt_splice (void *fdt, void *splicepoint, int oldlen, int newlen) +{ + char *p = splicepoint; + char *end = (char *) fdt + _fdt_data_size (fdt); + + if (((p + oldlen) < p) || ((p + oldlen) > end)) + return -FDT_ERR_BADOFFSET; + if ((end - oldlen + newlen) > ((char *) fdt + fdt_totalsize (fdt))) + return -FDT_ERR_NOSPACE; + memmove (p + newlen, p + oldlen, end - p - oldlen); + return 0; +} + +static int +_fdt_splice_mem_rsv (void *fdt, struct fdt_reserve_entry *p, + int oldn, int newn) +{ + int delta = (newn - oldn) * sizeof (*p); + int err; + err = _fdt_splice (fdt, p, oldn * sizeof (*p), newn * sizeof (*p)); + if (err) + return err; + fdt_set_off_dt_struct (fdt, fdt_off_dt_struct (fdt) + delta); + fdt_set_off_dt_strings (fdt, fdt_off_dt_strings (fdt) + delta); + return 0; +} + +static int +_fdt_splice_struct (void *fdt, void *p, int oldlen, int newlen) +{ + int delta = newlen - oldlen; + int err; + + if ((err = _fdt_splice (fdt, p, oldlen, newlen))) + return err; + + fdt_set_size_dt_struct (fdt, fdt_size_dt_struct (fdt) + delta); + fdt_set_off_dt_strings (fdt, fdt_off_dt_strings (fdt) + delta); + return 0; +} + +static int +_fdt_splice_string (void *fdt, int newlen) +{ + void *p = (char *) fdt + + fdt_off_dt_strings (fdt) + fdt_size_dt_strings (fdt); + int err; + + if ((err = _fdt_splice (fdt, p, 0, newlen))) + return err; + + fdt_set_size_dt_strings (fdt, fdt_size_dt_strings (fdt) + newlen); + return 0; +} + +static int +_fdt_find_add_string (void *fdt, const char *s) +{ + char *strtab = (char *) fdt + fdt_off_dt_strings (fdt); + const char *p; + char *new; + int len = strlen (s) + 1; + int err; + + p = _fdt_find_string (strtab, fdt_size_dt_strings (fdt), s); + if (p) + /* found it */ + return (p - strtab); + + new = strtab + fdt_size_dt_strings (fdt); + err = _fdt_splice_string (fdt, len); + if (err) + return err; + + memcpy (new, s, len); + return (new - strtab); +} + +int +fdt_add_mem_rsv (void *fdt, uint64_t address, uint64_t size) +{ + struct fdt_reserve_entry *re; + int err; + + FDT_RW_CHECK_HEADER (fdt); + + re = _fdt_mem_rsv_w (fdt, fdt_num_mem_rsv (fdt)); + err = _fdt_splice_mem_rsv (fdt, re, 0, 1); + if (err) + return err; + + re->address = cpu_to_fdt64 (address); + re->size = cpu_to_fdt64 (size); + return 0; +} + +int +fdt_del_mem_rsv (void *fdt, int n) +{ + struct fdt_reserve_entry *re = _fdt_mem_rsv_w (fdt, n); + int err; + + FDT_RW_CHECK_HEADER (fdt); + + if (n >= fdt_num_mem_rsv (fdt)) + return -FDT_ERR_NOTFOUND; + + err = _fdt_splice_mem_rsv (fdt, re, 1, 0); + if (err) + return err; + return 0; +} + +static int +_fdt_resize_property (void *fdt, int nodeoffset, const char *name, + int len, struct fdt_property **prop) +{ + int oldlen; + int err; + + *prop = fdt_get_property_w (fdt, nodeoffset, name, &oldlen); + if (!(*prop)) + return oldlen; + + if ((err = _fdt_splice_struct (fdt, (*prop)->data, FDT_TAGALIGN (oldlen), + FDT_TAGALIGN (len)))) + return err; + + (*prop)->len = cpu_to_fdt32 (len); + return 0; +} + +static int +_fdt_add_property (void *fdt, int nodeoffset, const char *name, + int len, struct fdt_property **prop) +{ + int proplen; + int nextoffset; + int namestroff; + int err; + + if ((nextoffset = _fdt_check_node_offset (fdt, nodeoffset)) < 0) + return nextoffset; + + namestroff = _fdt_find_add_string (fdt, name); + if (namestroff < 0) + return namestroff; + + *prop = _fdt_offset_ptr_w (fdt, nextoffset); + proplen = sizeof (**prop) + FDT_TAGALIGN (len); + + err = _fdt_splice_struct (fdt, *prop, 0, proplen); + if (err) + return err; + + (*prop)->tag = cpu_to_fdt32 (FDT_PROP); + (*prop)->nameoff = cpu_to_fdt32 (namestroff); + (*prop)->len = cpu_to_fdt32 (len); + return 0; +} + +int +fdt_set_name (void *fdt, int nodeoffset, const char *name) +{ + char *namep; + int oldlen, newlen; + int err; + + FDT_RW_CHECK_HEADER (fdt); + + namep = (char *) (uintptr_t) fdt_get_name (fdt, nodeoffset, &oldlen); + if (!namep) + return oldlen; + + newlen = strlen (name); + + err = _fdt_splice_struct (fdt, namep, FDT_TAGALIGN (oldlen + 1), + FDT_TAGALIGN (newlen + 1)); + if (err) + return err; + + memcpy (namep, name, newlen + 1); + return 0; +} + +int +fdt_setprop (void *fdt, int nodeoffset, const char *name, + const void *val, int len) +{ + struct fdt_property *prop; + int err; + + FDT_RW_CHECK_HEADER (fdt); + + err = _fdt_resize_property (fdt, nodeoffset, name, len, &prop); + if (err == -FDT_ERR_NOTFOUND) + err = _fdt_add_property (fdt, nodeoffset, name, len, &prop); + if (err) + return err; + + memcpy (prop->data, val, len); + return 0; +} + +int +fdt_delprop (void *fdt, int nodeoffset, const char *name) +{ + struct fdt_property *prop; + int len, proplen; + + FDT_RW_CHECK_HEADER (fdt); + + prop = fdt_get_property_w (fdt, nodeoffset, name, &len); + if (!prop) + return len; + + proplen = sizeof (*prop) + FDT_TAGALIGN (len); + return _fdt_splice_struct (fdt, prop, proplen, 0); +} + +int +fdt_add_subnode_namelen (void *fdt, int parentoffset, + const char *name, int namelen) +{ + struct fdt_node_header *nh; + int offset, nextoffset; + int nodelen; + int err; + uint32_t tag; + uint32_t *endtag; + + FDT_RW_CHECK_HEADER (fdt); + + offset = fdt_subnode_offset_namelen (fdt, parentoffset, name, namelen); + if (offset >= 0) + return -FDT_ERR_EXISTS; + else if (offset != -FDT_ERR_NOTFOUND) + return offset; + + /* Try to place the new node after the parent's properties */ + fdt_next_tag (fdt, parentoffset, &nextoffset); /* skip the BEGIN_NODE */ + do + { + offset = nextoffset; + tag = fdt_next_tag (fdt, offset, &nextoffset); + } + while ((tag == FDT_PROP) || (tag == FDT_NOP)); + + nh = _fdt_offset_ptr_w (fdt, offset); + nodelen = sizeof (*nh) + FDT_TAGALIGN (namelen + 1) + FDT_TAGSIZE; + + err = _fdt_splice_struct (fdt, nh, 0, nodelen); + if (err) + return err; + + nh->tag = cpu_to_fdt32 (FDT_BEGIN_NODE); + memset (nh->name, 0, FDT_TAGALIGN (namelen + 1)); + memcpy (nh->name, name, namelen); + endtag = (uint32_t *) ((char *) nh + nodelen - FDT_TAGSIZE); + *endtag = cpu_to_fdt32 (FDT_END_NODE); + + return offset; +} + +int +fdt_add_subnode (void *fdt, int parentoffset, const char *name) +{ + return fdt_add_subnode_namelen (fdt, parentoffset, name, strlen (name)); +} + +int +fdt_del_node (void *fdt, int nodeoffset) +{ + int endoffset; + + FDT_RW_CHECK_HEADER (fdt); + + endoffset = _fdt_node_end_offset (fdt, nodeoffset); + if (endoffset < 0) + return endoffset; + + return _fdt_splice_struct (fdt, _fdt_offset_ptr_w (fdt, nodeoffset), + endoffset - nodeoffset, 0); +} + +static void +_fdt_packblocks (const char *old, char *new, + int mem_rsv_size, int struct_size) +{ + int mem_rsv_off, struct_off, strings_off; + + mem_rsv_off = FDT_ALIGN (sizeof (struct fdt_header), 8); + struct_off = mem_rsv_off + mem_rsv_size; + strings_off = struct_off + struct_size; + + memmove (new + mem_rsv_off, old + fdt_off_mem_rsvmap (old), mem_rsv_size); + fdt_set_off_mem_rsvmap (new, mem_rsv_off); + + memmove (new + struct_off, old + fdt_off_dt_struct (old), struct_size); + fdt_set_off_dt_struct (new, struct_off); + fdt_set_size_dt_struct (new, struct_size); + + memmove (new + strings_off, old + fdt_off_dt_strings (old), + fdt_size_dt_strings (old)); + fdt_set_off_dt_strings (new, strings_off); + fdt_set_size_dt_strings (new, fdt_size_dt_strings (old)); +} + +int +fdt_open_into (const void *fdt, void *buf, int bufsize) +{ + int err; + int mem_rsv_size, struct_size; + int newsize; + const char *fdtstart = fdt; + const char *fdtend = fdtstart + fdt_totalsize (fdt); + char *tmp; + + FDT_CHECK_HEADER (fdt); + + mem_rsv_size = (fdt_num_mem_rsv (fdt) + 1) + * sizeof (struct fdt_reserve_entry); + + if (fdt_version (fdt) >= 17) + { + struct_size = fdt_size_dt_struct (fdt); + } + else + { + struct_size = 0; + while (fdt_next_tag (fdt, struct_size, &struct_size) != FDT_END) + ; + if (struct_size < 0) + return struct_size; + } + + if (!_fdt_blocks_misordered (fdt, mem_rsv_size, struct_size)) + { + /* no further work necessary */ + err = fdt_move (fdt, buf, bufsize); + if (err) + return err; + fdt_set_version (buf, 17); + fdt_set_size_dt_struct (buf, struct_size); + fdt_set_totalsize (buf, bufsize); + return 0; + } + + /* Need to reorder */ + newsize = FDT_ALIGN (sizeof (struct fdt_header), 8) + mem_rsv_size + + struct_size + fdt_size_dt_strings (fdt); + + if (bufsize < newsize) + return -FDT_ERR_NOSPACE; + + /* First attempt to build converted tree at beginning of buffer */ + tmp = buf; + /* But if that overlaps with the old tree... */ + if (((tmp + newsize) > fdtstart) && (tmp < fdtend)) + { + /* Try right after the old tree instead */ + tmp = (char *) (uintptr_t) fdtend; + if ((tmp + newsize) > ((char *) buf + bufsize)) + return -FDT_ERR_NOSPACE; + } + + _fdt_packblocks (fdt, tmp, mem_rsv_size, struct_size); + memmove (buf, tmp, newsize); + + fdt_set_magic (buf, FDT_MAGIC); + fdt_set_totalsize (buf, bufsize); + fdt_set_version (buf, 17); + fdt_set_last_comp_version (buf, 16); + fdt_set_boot_cpuid_phys (buf, fdt_boot_cpuid_phys (fdt)); + + return 0; +} + +int +fdt_pack (void *fdt) +{ + int mem_rsv_size; + + FDT_RW_CHECK_HEADER (fdt); + + mem_rsv_size = (fdt_num_mem_rsv (fdt) + 1) + * sizeof (struct fdt_reserve_entry); + _fdt_packblocks (fdt, fdt, mem_rsv_size, fdt_size_dt_struct (fdt)); + fdt_set_totalsize (fdt, _fdt_data_size (fdt)); + + return 0; +} diff --git a/grub-core/lib/dtc/libfdt/fdt_strerror.c b/grub-core/lib/dtc/libfdt/fdt_strerror.c new file mode 100644 index 000000000..2d8606bec --- /dev/null +++ b/grub-core/lib/dtc/libfdt/fdt_strerror.c @@ -0,0 +1,100 @@ +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + * + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * + * a) This library 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 library 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 library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * Alternatively, + * + * b) 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + */ +#include "libfdt_env.h" + +#include +#include + +#include "libfdt_internal.h" + +struct fdt_errtabent +{ + const char *str; +}; + +#define FDT_ERRTABENT(val) \ + [(val)] = { .str = #val, } + +static struct fdt_errtabent fdt_errtable[] = { + FDT_ERRTABENT (FDT_ERR_NOTFOUND), + FDT_ERRTABENT (FDT_ERR_EXISTS), + FDT_ERRTABENT (FDT_ERR_NOSPACE), + + FDT_ERRTABENT (FDT_ERR_BADOFFSET), + FDT_ERRTABENT (FDT_ERR_BADPATH), + FDT_ERRTABENT (FDT_ERR_BADSTATE), + + FDT_ERRTABENT (FDT_ERR_TRUNCATED), + FDT_ERRTABENT (FDT_ERR_BADMAGIC), + FDT_ERRTABENT (FDT_ERR_BADVERSION), + FDT_ERRTABENT (FDT_ERR_BADSTRUCTURE), + FDT_ERRTABENT (FDT_ERR_BADLAYOUT), +}; + +#define FDT_ERRTABSIZE (sizeof(fdt_errtable) / sizeof(fdt_errtable[0])) + +const char * +fdt_strerror (int errval) +{ + if (errval > 0) + return ""; + else if (errval == 0) + return ""; + else if (errval > -FDT_ERRTABSIZE) + { + const char *s = fdt_errtable[-errval].str; + + if (s) + return s; + } + + return ""; +} diff --git a/grub-core/lib/dtc/libfdt/fdt_sw.c b/grub-core/lib/dtc/libfdt/fdt_sw.c new file mode 100644 index 000000000..86d1d7353 --- /dev/null +++ b/grub-core/lib/dtc/libfdt/fdt_sw.c @@ -0,0 +1,267 @@ +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + * + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * + * a) This library 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 library 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 library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * Alternatively, + * + * b) 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + */ +#include "libfdt_env.h" + +#include +#include + +#include "libfdt_internal.h" + +static int +_fdt_sw_check_header (void *fdt) +{ + if (fdt_magic (fdt) != FDT_SW_MAGIC) + return -FDT_ERR_BADMAGIC; + /* FIXME: should check more details about the header state */ + return 0; +} + +#define FDT_SW_CHECK_HEADER(fdt) \ + { \ + int err; \ + if ((err = _fdt_sw_check_header(fdt)) != 0) \ + return err; \ + } + +static void * +_fdt_grab_space (void *fdt, size_t len) +{ + int offset = fdt_size_dt_struct (fdt); + int spaceleft; + + spaceleft = fdt_totalsize (fdt) - fdt_off_dt_struct (fdt) + - fdt_size_dt_strings (fdt); + + if ((offset + len < offset) || (offset + len > spaceleft)) + return NULL; + + fdt_set_size_dt_struct (fdt, offset + len); + return _fdt_offset_ptr_w (fdt, offset); +} + +int +fdt_create (void *buf, int bufsize) +{ + void *fdt = buf; + + if (bufsize < sizeof (struct fdt_header)) + return -FDT_ERR_NOSPACE; + + memset (buf, 0, bufsize); + + fdt_set_magic (fdt, FDT_SW_MAGIC); + fdt_set_version (fdt, FDT_LAST_SUPPORTED_VERSION); + fdt_set_last_comp_version (fdt, FDT_FIRST_SUPPORTED_VERSION); + fdt_set_totalsize (fdt, bufsize); + + fdt_set_off_mem_rsvmap (fdt, FDT_ALIGN (sizeof (struct fdt_header), + sizeof (struct fdt_reserve_entry))); + fdt_set_off_dt_struct (fdt, fdt_off_mem_rsvmap (fdt)); + fdt_set_off_dt_strings (fdt, bufsize); + + return 0; +} + +int +fdt_add_reservemap_entry (void *fdt, uint64_t addr, uint64_t size) +{ + struct fdt_reserve_entry *re; + int offset; + + FDT_SW_CHECK_HEADER (fdt); + + if (fdt_size_dt_struct (fdt)) + return -FDT_ERR_BADSTATE; + + offset = fdt_off_dt_struct (fdt); + if ((offset + sizeof (*re)) > fdt_totalsize (fdt)) + return -FDT_ERR_NOSPACE; + + re = (struct fdt_reserve_entry *) ((char *) fdt + offset); + re->address = cpu_to_fdt64 (addr); + re->size = cpu_to_fdt64 (size); + + fdt_set_off_dt_struct (fdt, offset + sizeof (*re)); + + return 0; +} + +int +fdt_finish_reservemap (void *fdt) +{ + return fdt_add_reservemap_entry (fdt, 0, 0); +} + +int +fdt_begin_node (void *fdt, const char *name) +{ + struct fdt_node_header *nh; + int namelen = strlen (name) + 1; + + FDT_SW_CHECK_HEADER (fdt); + + nh = _fdt_grab_space (fdt, sizeof (*nh) + FDT_TAGALIGN (namelen)); + if (!nh) + return -FDT_ERR_NOSPACE; + + nh->tag = cpu_to_fdt32 (FDT_BEGIN_NODE); + memcpy (nh->name, name, namelen); + return 0; +} + +int +fdt_end_node (void *fdt) +{ + uint32_t *en; + + FDT_SW_CHECK_HEADER (fdt); + + en = _fdt_grab_space (fdt, FDT_TAGSIZE); + if (!en) + return -FDT_ERR_NOSPACE; + + *en = cpu_to_fdt32 (FDT_END_NODE); + return 0; +} + +static int +_fdt_find_add_string (void *fdt, const char *s) +{ + char *strtab = (char *) fdt + fdt_totalsize (fdt); + const char *p; + int strtabsize = fdt_size_dt_strings (fdt); + int len = strlen (s) + 1; + int struct_top, offset; + + p = _fdt_find_string (strtab - strtabsize, strtabsize, s); + if (p) + return p - strtab; + + /* Add it */ + offset = -strtabsize - len; + struct_top = fdt_off_dt_struct (fdt) + fdt_size_dt_struct (fdt); + if (fdt_totalsize (fdt) + offset < struct_top) + return 0; /* no more room */ + + memcpy (strtab + offset, s, len); + fdt_set_size_dt_strings (fdt, strtabsize + len); + return offset; +} + +int +fdt_property (void *fdt, const char *name, const void *val, int len) +{ + struct fdt_property *prop; + int nameoff; + + FDT_SW_CHECK_HEADER (fdt); + + nameoff = _fdt_find_add_string (fdt, name); + if (nameoff == 0) + return -FDT_ERR_NOSPACE; + + prop = _fdt_grab_space (fdt, sizeof (*prop) + FDT_TAGALIGN (len)); + if (!prop) + return -FDT_ERR_NOSPACE; + + prop->tag = cpu_to_fdt32 (FDT_PROP); + prop->nameoff = cpu_to_fdt32 (nameoff); + prop->len = cpu_to_fdt32 (len); + memcpy (prop->data, val, len); + return 0; +} + +int +fdt_finish (void *fdt) +{ + char *p = (char *) fdt; + uint32_t *end; + int oldstroffset, newstroffset; + uint32_t tag; + int offset, nextoffset; + + FDT_SW_CHECK_HEADER (fdt); + + /* Add terminator */ + end = _fdt_grab_space (fdt, sizeof (*end)); + if (!end) + return -FDT_ERR_NOSPACE; + *end = cpu_to_fdt32 (FDT_END); + + /* Relocate the string table */ + oldstroffset = fdt_totalsize (fdt) - fdt_size_dt_strings (fdt); + newstroffset = fdt_off_dt_struct (fdt) + fdt_size_dt_struct (fdt); + memmove (p + newstroffset, p + oldstroffset, fdt_size_dt_strings (fdt)); + fdt_set_off_dt_strings (fdt, newstroffset); + + /* Walk the structure, correcting string offsets */ + offset = 0; + while ((tag = fdt_next_tag (fdt, offset, &nextoffset)) != FDT_END) + { + if (tag == FDT_PROP) + { + struct fdt_property *prop = _fdt_offset_ptr_w (fdt, offset); + int nameoff; + + nameoff = fdt32_to_cpu (prop->nameoff); + nameoff += fdt_size_dt_strings (fdt); + prop->nameoff = cpu_to_fdt32 (nameoff); + } + offset = nextoffset; + } + if (nextoffset < 0) + return nextoffset; + + /* Finally, adjust the header */ + fdt_set_totalsize (fdt, newstroffset + fdt_size_dt_strings (fdt)); + fdt_set_magic (fdt, FDT_MAGIC); + return 0; +} diff --git a/grub-core/lib/dtc/libfdt/fdt_wip.c b/grub-core/lib/dtc/libfdt/fdt_wip.c new file mode 100644 index 000000000..09297d9a6 --- /dev/null +++ b/grub-core/lib/dtc/libfdt/fdt_wip.c @@ -0,0 +1,123 @@ +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + * + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * + * a) This library 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 library 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 library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * Alternatively, + * + * b) 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + */ +#include "libfdt_env.h" + +#include +#include + +#include "libfdt_internal.h" + +int +fdt_setprop_inplace (void *fdt, int nodeoffset, const char *name, + const void *val, int len) +{ + void *propval; + int proplen; + + propval = fdt_getprop_w (fdt, nodeoffset, name, &proplen); + if (!propval) + return proplen; + + if (proplen != len) + return -FDT_ERR_NOSPACE; + + memcpy (propval, val, len); + return 0; +} + +static void +_fdt_nop_region (void *start, int len) +{ + uint32_t *p; + + for (p = start; (char *) p < ((char *) start + len); p++) + *p = cpu_to_fdt32 (FDT_NOP); +} + +int +fdt_nop_property (void *fdt, int nodeoffset, const char *name) +{ + struct fdt_property *prop; + int len; + + prop = fdt_get_property_w (fdt, nodeoffset, name, &len); + if (!prop) + return len; + + _fdt_nop_region (prop, len + sizeof (*prop)); + + return 0; +} + +int +_fdt_node_end_offset (void *fdt, int offset) +{ + int depth = 0; + + while ((offset >= 0) && (depth >= 0)) + offset = fdt_next_node (fdt, offset, &depth); + + return offset; +} + +int +fdt_nop_node (void *fdt, int nodeoffset) +{ + int endoffset; + + endoffset = _fdt_node_end_offset (fdt, nodeoffset); + if (endoffset < 0) + return endoffset; + + _fdt_nop_region (fdt_offset_ptr_w (fdt, nodeoffset, 0), + endoffset - nodeoffset); + return 0; +} diff --git a/grub-core/lib/dtc/libfdt/libfdt.h b/grub-core/lib/dtc/libfdt/libfdt.h new file mode 100644 index 000000000..6b9bfb5dc --- /dev/null +++ b/grub-core/lib/dtc/libfdt/libfdt.h @@ -0,0 +1,1239 @@ +#ifndef _LIBFDT_H +#define _LIBFDT_H +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + * + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * + * a) This library 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 library 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 library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * Alternatively, + * + * b) 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + */ + +#include +#include + +#define FDT_FIRST_SUPPORTED_VERSION 0x10 +#define FDT_LAST_SUPPORTED_VERSION 0x11 + +/* Error codes: informative error codes */ +#define FDT_ERR_NOTFOUND 1 + /* FDT_ERR_NOTFOUND: The requested node or property does not exist */ +#define FDT_ERR_EXISTS 2 + /* FDT_ERR_EXISTS: Attemped to create a node or property which + * already exists */ +#define FDT_ERR_NOSPACE 3 + /* FDT_ERR_NOSPACE: Operation needed to expand the device + * tree, but its buffer did not have sufficient space to + * contain the expanded tree. Use fdt_open_into() to move the + * device tree to a buffer with more space. */ + +/* Error codes: codes for bad parameters */ +#define FDT_ERR_BADOFFSET 4 + /* FDT_ERR_BADOFFSET: Function was passed a structure block + * offset which is out-of-bounds, or which points to an + * unsuitable part of the structure for the operation. */ +#define FDT_ERR_BADPATH 5 + /* FDT_ERR_BADPATH: Function was passed a badly formatted path + * (e.g. missing a leading / for a function which requires an + * absolute path) */ +#define FDT_ERR_BADPHANDLE 6 + /* FDT_ERR_BADPHANDLE: Function was passed an invalid phandle + * value. phandle values of 0 and -1 are not permitted. */ +#define FDT_ERR_BADSTATE 7 + /* FDT_ERR_BADSTATE: Function was passed an incomplete device + * tree created by the sequential-write functions, which is + * not sufficiently complete for the requested operation. */ + +/* Error codes: codes for bad device tree blobs */ +#define FDT_ERR_TRUNCATED 8 + /* FDT_ERR_TRUNCATED: Structure block of the given device tree + * ends without an FDT_END tag. */ +#define FDT_ERR_BADMAGIC 9 + /* FDT_ERR_BADMAGIC: Given "device tree" appears not to be a + * device tree at all - it is missing the flattened device + * tree magic number. */ +#define FDT_ERR_BADVERSION 10 + /* FDT_ERR_BADVERSION: Given device tree has a version which + * can't be handled by the requested operation. For + * read-write functions, this may mean that fdt_open_into() is + * required to convert the tree to the expected version. */ +#define FDT_ERR_BADSTRUCTURE 11 + /* FDT_ERR_BADSTRUCTURE: Given device tree has a corrupt + * structure block or other serious error (e.g. misnested + * nodes, or subnodes preceding properties). */ +#define FDT_ERR_BADLAYOUT 12 + /* FDT_ERR_BADLAYOUT: For read-write functions, the given + * device tree has it's sub-blocks in an order that the + * function can't handle (memory reserve map, then structure, + * then strings). Use fdt_open_into() to reorganize the tree + * into a form suitable for the read-write operations. */ + +/* "Can't happen" error indicating a bug in libfdt */ +#define FDT_ERR_INTERNAL 13 + /* FDT_ERR_INTERNAL: libfdt has failed an internal assertion. + * Should never be returned, if it is, it indicates a bug in + * libfdt itself. */ + +#define FDT_ERR_MAX 13 + +/**********************************************************************/ +/* Low-level functions (you probably don't need these) */ +/**********************************************************************/ + +const void *fdt_offset_ptr (const void *fdt, int offset, + unsigned int checklen); +static inline void * +fdt_offset_ptr_w (void *fdt, int offset, int checklen) +{ + return (void *) (uintptr_t) fdt_offset_ptr (fdt, offset, checklen); +} + +uint32_t fdt_next_tag (const void *fdt, int offset, int *nextoffset); + +/**********************************************************************/ +/* Traversal functions */ +/**********************************************************************/ + +int fdt_next_node (const void *fdt, int offset, int *depth); + +/**********************************************************************/ +/* General functions */ +/**********************************************************************/ + +#define fdt_get_header(fdt, field) \ + (fdt32_to_cpu(((const struct fdt_header *)(fdt))->field)) +#define fdt_magic(fdt) (fdt_get_header(fdt, magic)) +#define fdt_totalsize(fdt) (fdt_get_header(fdt, totalsize)) +#define fdt_off_dt_struct(fdt) (fdt_get_header(fdt, off_dt_struct)) +#define fdt_off_dt_strings(fdt) (fdt_get_header(fdt, off_dt_strings)) +#define fdt_off_mem_rsvmap(fdt) (fdt_get_header(fdt, off_mem_rsvmap)) +#define fdt_version(fdt) (fdt_get_header(fdt, version)) +#define fdt_last_comp_version(fdt) (fdt_get_header(fdt, last_comp_version)) +#define fdt_boot_cpuid_phys(fdt) (fdt_get_header(fdt, boot_cpuid_phys)) +#define fdt_size_dt_strings(fdt) (fdt_get_header(fdt, size_dt_strings)) +#define fdt_size_dt_struct(fdt) (fdt_get_header(fdt, size_dt_struct)) + +#define __fdt_set_hdr(name) \ + static inline void fdt_set_##name(void *fdt, uint32_t val) \ + { \ + struct fdt_header *fdth = (struct fdt_header*)fdt; \ + fdth->name = cpu_to_fdt32(val); \ + } +__fdt_set_hdr (magic); +__fdt_set_hdr (totalsize); +__fdt_set_hdr (off_dt_struct); +__fdt_set_hdr (off_dt_strings); +__fdt_set_hdr (off_mem_rsvmap); +__fdt_set_hdr (version); +__fdt_set_hdr (last_comp_version); +__fdt_set_hdr (boot_cpuid_phys); +__fdt_set_hdr (size_dt_strings); +__fdt_set_hdr (size_dt_struct); +#undef __fdt_set_hdr + +/** + * fdt_check_header - sanity check a device tree or possible device tree + * @fdt: pointer to data which might be a flattened device tree + * + * fdt_check_header() checks that the given buffer contains what + * appears to be a flattened device tree with sane information in its + * header. + * + * returns: + * 0, if the buffer appears to contain a valid device tree + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, standard meanings, as above + */ +int fdt_check_header (const void *fdt); + +/** + * fdt_move - move a device tree around in memory + * @fdt: pointer to the device tree to move + * @buf: pointer to memory where the device is to be moved + * @bufsize: size of the memory space at buf + * + * fdt_move() relocates, if possible, the device tree blob located at + * fdt to the buffer at buf of size bufsize. The buffer may overlap + * with the existing device tree blob at fdt. Therefore, + * fdt_move(fdt, fdt, fdt_totalsize(fdt)) + * should always succeed. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, bufsize is insufficient to contain the device tree + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, standard meanings + */ +int fdt_move (const void *fdt, void *buf, int bufsize); + +/**********************************************************************/ +/* Read-only functions */ +/**********************************************************************/ + +/** + * fdt_string - retrieve a string from the strings block of a device tree + * @fdt: pointer to the device tree blob + * @stroffset: offset of the string within the strings block (native endian) + * + * fdt_string() retrieves a pointer to a single string from the + * strings block of the device tree blob at fdt. + * + * returns: + * a pointer to the string, on success + * NULL, if stroffset is out of bounds + */ +const char *fdt_string (const void *fdt, int stroffset); + +/** + * fdt_num_mem_rsv - retrieve the number of memory reserve map entries + * @fdt: pointer to the device tree blob + * + * Returns the number of entries in the device tree blob's memory + * reservation map. This does not include the terminating 0,0 entry + * or any other (0,0) entries reserved for expansion. + * + * returns: + * the number of entries + */ +int fdt_num_mem_rsv (const void *fdt); + +/** + * fdt_get_mem_rsv - retrieve one memory reserve map entry + * @fdt: pointer to the device tree blob + * @address, @size: pointers to 64-bit variables + * + * On success, *address and *size will contain the address and size of + * the n-th reserve map entry from the device tree blob, in + * native-endian format. + * + * returns: + * 0, on success + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, standard meanings + */ +int fdt_get_mem_rsv (const void *fdt, int n, uint64_t * address, + uint64_t * size); + +/** + * fdt_subnode_offset_namelen - find a subnode based on substring + * @fdt: pointer to the device tree blob + * @parentoffset: structure block offset of a node + * @name: name of the subnode to locate + * @namelen: number of characters of name to consider + * + * Identical to fdt_subnode_offset(), but only examine the first + * namelen characters of name for matching the subnode name. This is + * useful for finding subnodes based on a portion of a larger string, + * such as a full path. + */ +int fdt_subnode_offset_namelen (const void *fdt, int parentoffset, + const char *name, int namelen); +/** + * fdt_subnode_offset - find a subnode of a given node + * @fdt: pointer to the device tree blob + * @parentoffset: structure block offset of a node + * @name: name of the subnode to locate + * + * fdt_subnode_offset() finds a subnode of the node at structure block + * offset parentoffset with the given name. name may include a unit + * address, in which case fdt_subnode_offset() will find the subnode + * with that unit address, or the unit address may be omitted, in + * which case fdt_subnode_offset() will find an arbitrary subnode + * whose name excluding unit address matches the given name. + * + * returns: + * structure block offset of the requested subnode (>=0), on success + * -FDT_ERR_NOTFOUND, if the requested subnode does not exist + * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings. + */ +int fdt_subnode_offset (const void *fdt, int parentoffset, const char *name); + +/** + * fdt_path_offset - find a tree node by its full path + * @fdt: pointer to the device tree blob + * @path: full path of the node to locate + * + * fdt_path_offset() finds a node of a given path in the device tree. + * Each path component may omit the unit address portion, but the + * results of this are undefined if any such path component is + * ambiguous (that is if there are multiple nodes at the relevant + * level matching the given component, differentiated only by unit + * address). + * + * returns: + * structure block offset of the node with the requested path (>=0), on success + * -FDT_ERR_BADPATH, given path does not begin with '/' or is invalid + * -FDT_ERR_NOTFOUND, if the requested node does not exist + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings. + */ +int fdt_path_offset (const void *fdt, const char *path); + +/** + * fdt_get_name - retrieve the name of a given node + * @fdt: pointer to the device tree blob + * @nodeoffset: structure block offset of the starting node + * @lenp: pointer to an integer variable (will be overwritten) or NULL + * + * fdt_get_name() retrieves the name (including unit address) of the + * device tree node at structure block offset nodeoffset. If lenp is + * non-NULL, the length of this name is also returned, in the integer + * pointed to by lenp. + * + * returns: + * pointer to the node's name, on success + * If lenp is non-NULL, *lenp contains the length of that name (>=0) + * NULL, on error + * if lenp is non-NULL *lenp contains an error code (<0): + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, standard meanings + */ +const char *fdt_get_name (const void *fdt, int nodeoffset, int *lenp); + +/** + * fdt_first_property_offset - find the offset of a node's first property + * @fdt: pointer to the device tree blob + * @nodeoffset: structure block offset of a node + * + * fdt_first_property_offset() finds the first property of the node at + * the given structure block offset. + * + * returns: + * structure block offset of the property (>=0), on success + * -FDT_ERR_NOTFOUND, if the requested node has no properties + * -FDT_ERR_BADOFFSET, if nodeoffset did not point to an FDT_BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings. + */ +int fdt_first_property_offset (const void *fdt, int nodeoffset); + +/** + * fdt_next_property_offset - step through a node's properties + * @fdt: pointer to the device tree blob + * @offset: structure block offset of a property + * + * fdt_next_property_offset() finds the property immediately after the + * one at the given structure block offset. This will be a property + * of the same node as the given property. + * + * returns: + * structure block offset of the next property (>=0), on success + * -FDT_ERR_NOTFOUND, if the given property is the last in its node + * -FDT_ERR_BADOFFSET, if nodeoffset did not point to an FDT_PROP tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings. + */ +int fdt_next_property_offset (const void *fdt, int offset); + +/** + * fdt_get_property_by_offset - retrieve the property at a given offset + * @fdt: pointer to the device tree blob + * @offset: offset of the property to retrieve + * @lenp: pointer to an integer variable (will be overwritten) or NULL + * + * fdt_get_property_by_offset() retrieves a pointer to the + * fdt_property structure within the device tree blob at the given + * offset. If lenp is non-NULL, the length of the property value is + * also returned, in the integer pointed to by lenp. + * + * returns: + * pointer to the structure representing the property + * if lenp is non-NULL, *lenp contains the length of the property + * value (>=0) + * NULL, on error + * if lenp is non-NULL, *lenp contains an error code (<0): + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_PROP tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ +const struct fdt_property *fdt_get_property_by_offset (const void *fdt, + int offset, int *lenp); + +/** + * fdt_get_property_namelen - find a property based on substring + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to find + * @name: name of the property to find + * @namelen: number of characters of name to consider + * @lenp: pointer to an integer variable (will be overwritten) or NULL + * + * Identical to fdt_get_property_namelen(), but only examine the first + * namelen characters of name for matching the property name. + */ +const struct fdt_property *fdt_get_property_namelen (const void *fdt, + int nodeoffset, + const char *name, + int namelen, int *lenp); + +/** + * fdt_get_property - find a given property in a given node + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to find + * @name: name of the property to find + * @lenp: pointer to an integer variable (will be overwritten) or NULL + * + * fdt_get_property() retrieves a pointer to the fdt_property + * structure within the device tree blob corresponding to the property + * named 'name' of the node at offset nodeoffset. If lenp is + * non-NULL, the length of the property value is also returned, in the + * integer pointed to by lenp. + * + * returns: + * pointer to the structure representing the property + * if lenp is non-NULL, *lenp contains the length of the property + * value (>=0) + * NULL, on error + * if lenp is non-NULL, *lenp contains an error code (<0): + * -FDT_ERR_NOTFOUND, node does not have named property + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ +const struct fdt_property *fdt_get_property (const void *fdt, int nodeoffset, + const char *name, int *lenp); +static inline struct fdt_property * +fdt_get_property_w (void *fdt, int nodeoffset, const char *name, int *lenp) +{ + return (struct fdt_property *) (uintptr_t) + fdt_get_property (fdt, nodeoffset, name, lenp); +} + +/** + * fdt_getprop_by_offset - retrieve the value of a property at a given offset + * @fdt: pointer to the device tree blob + * @ffset: offset of the property to read + * @namep: pointer to a string variable (will be overwritten) or NULL + * @lenp: pointer to an integer variable (will be overwritten) or NULL + * + * fdt_getprop_by_offset() retrieves a pointer to the value of the + * property at structure block offset 'offset' (this will be a pointer + * to within the device blob itself, not a copy of the value). If + * lenp is non-NULL, the length of the property value is also + * returned, in the integer pointed to by lenp. If namep is non-NULL, + * the property's namne will also be returned in the char * pointed to + * by namep (this will be a pointer to within the device tree's string + * block, not a new copy of the name). + * + * returns: + * pointer to the property's value + * if lenp is non-NULL, *lenp contains the length of the property + * value (>=0) + * if namep is non-NULL *namep contiains a pointer to the property + * name. + * NULL, on error + * if lenp is non-NULL, *lenp contains an error code (<0): + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_PROP tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ +const void *fdt_getprop_by_offset (const void *fdt, int offset, + const char **namep, int *lenp); + +/** + * fdt_getprop_namelen - get property value based on substring + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to find + * @name: name of the property to find + * @namelen: number of characters of name to consider + * @lenp: pointer to an integer variable (will be overwritten) or NULL + * + * Identical to fdt_getprop(), but only examine the first namelen + * characters of name for matching the property name. + */ +const void *fdt_getprop_namelen (const void *fdt, int nodeoffset, + const char *name, int namelen, int *lenp); + +/** + * fdt_getprop - retrieve the value of a given property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to find + * @name: name of the property to find + * @lenp: pointer to an integer variable (will be overwritten) or NULL + * + * fdt_getprop() retrieves a pointer to the value of the property + * named 'name' of the node at offset nodeoffset (this will be a + * pointer to within the device blob itself, not a copy of the value). + * If lenp is non-NULL, the length of the property value is also + * returned, in the integer pointed to by lenp. + * + * returns: + * pointer to the property's value + * if lenp is non-NULL, *lenp contains the length of the property + * value (>=0) + * NULL, on error + * if lenp is non-NULL, *lenp contains an error code (<0): + * -FDT_ERR_NOTFOUND, node does not have named property + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ +const void *fdt_getprop (const void *fdt, int nodeoffset, + const char *name, int *lenp); +static inline void * +fdt_getprop_w (void *fdt, int nodeoffset, const char *name, int *lenp) +{ + return (void *) (uintptr_t) fdt_getprop (fdt, nodeoffset, name, lenp); +} + +/** + * fdt_get_phandle - retrieve the phandle of a given node + * @fdt: pointer to the device tree blob + * @nodeoffset: structure block offset of the node + * + * fdt_get_phandle() retrieves the phandle of the device tree node at + * structure block offset nodeoffset. + * + * returns: + * the phandle of the node at nodeoffset, on success (!= 0, != -1) + * 0, if the node has no phandle, or another error occurs + */ +uint32_t fdt_get_phandle (const void *fdt, int nodeoffset); + +/** + * fdt_get_alias_namelen - get alias based on substring + * @fdt: pointer to the device tree blob + * @name: name of the alias th look up + * @namelen: number of characters of name to consider + * + * Identical to fdt_get_alias(), but only examine the first namelen + * characters of name for matching the alias name. + */ +const char *fdt_get_alias_namelen (const void *fdt, + const char *name, int namelen); + +/** + * fdt_get_alias - retreive the path referenced by a given alias + * @fdt: pointer to the device tree blob + * @name: name of the alias th look up + * + * fdt_get_alias() retrieves the value of a given alias. That is, the + * value of the property named 'name' in the node /aliases. + * + * returns: + * a pointer to the expansion of the alias named 'name', of it exists + * NULL, if the given alias or the /aliases node does not exist + */ +const char *fdt_get_alias (const void *fdt, const char *name); + +/** + * fdt_get_path - determine the full path of a node + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose path to find + * @buf: character buffer to contain the returned path (will be overwritten) + * @buflen: size of the character buffer at buf + * + * fdt_get_path() computes the full path of the node at offset + * nodeoffset, and records that path in the buffer at buf. + * + * NOTE: This function is expensive, as it must scan the device tree + * structure from the start to nodeoffset. + * + * returns: + * 0, on success + * buf contains the absolute path of the node at + * nodeoffset, as a NUL-terminated string. + * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_NOSPACE, the path of the given node is longer than (bufsize-1) + * characters and will not fit in the given buffer. + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, standard meanings + */ +int fdt_get_path (const void *fdt, int nodeoffset, char *buf, int buflen); + +/** + * fdt_supernode_atdepth_offset - find a specific ancestor of a node + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose parent to find + * @supernodedepth: depth of the ancestor to find + * @nodedepth: pointer to an integer variable (will be overwritten) or NULL + * + * fdt_supernode_atdepth_offset() finds an ancestor of the given node + * at a specific depth from the root (where the root itself has depth + * 0, its immediate subnodes depth 1 and so forth). So + * fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, NULL); + * will always return 0, the offset of the root node. If the node at + * nodeoffset has depth D, then: + * fdt_supernode_atdepth_offset(fdt, nodeoffset, D, NULL); + * will return nodeoffset itself. + * + * NOTE: This function is expensive, as it must scan the device tree + * structure from the start to nodeoffset. + * + * returns: + + * structure block offset of the node at node offset's ancestor + * of depth supernodedepth (>=0), on success + * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag +* -FDT_ERR_NOTFOUND, supernodedepth was greater than the depth of nodeoffset + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, standard meanings + */ +int fdt_supernode_atdepth_offset (const void *fdt, int nodeoffset, + int supernodedepth, int *nodedepth); + +/** + * fdt_node_depth - find the depth of a given node + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose parent to find + * + * fdt_node_depth() finds the depth of a given node. The root node + * has depth 0, its immediate subnodes depth 1 and so forth. + * + * NOTE: This function is expensive, as it must scan the device tree + * structure from the start to nodeoffset. + * + * returns: + * depth of the node at nodeoffset (>=0), on success + * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, standard meanings + */ +int fdt_node_depth (const void *fdt, int nodeoffset); + +/** + * fdt_parent_offset - find the parent of a given node + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose parent to find + * + * fdt_parent_offset() locates the parent node of a given node (that + * is, it finds the offset of the node which contains the node at + * nodeoffset as a subnode). + * + * NOTE: This function is expensive, as it must scan the device tree + * structure from the start to nodeoffset, *twice*. + * + * returns: + * structure block offset of the parent of the node at nodeoffset + * (>=0), on success + * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, standard meanings + */ +int fdt_parent_offset (const void *fdt, int nodeoffset); + +/** + * fdt_node_offset_by_prop_value - find nodes with a given property value + * @fdt: pointer to the device tree blob + * @startoffset: only find nodes after this offset + * @propname: property name to check + * @propval: property value to search for + * @proplen: length of the value in propval + * + * fdt_node_offset_by_prop_value() returns the offset of the first + * node after startoffset, which has a property named propname whose + * value is of length proplen and has value equal to propval; or if + * startoffset is -1, the very first such node in the tree. + * + * To iterate through all nodes matching the criterion, the following + * idiom can be used: + * offset = fdt_node_offset_by_prop_value(fdt, -1, propname, + * propval, proplen); + * while (offset != -FDT_ERR_NOTFOUND) { + * // other code here + * offset = fdt_node_offset_by_prop_value(fdt, offset, propname, + * propval, proplen); + * } + * + * Note the -1 in the first call to the function, if 0 is used here + * instead, the function will never locate the root node, even if it + * matches the criterion. + * + * returns: + * structure block offset of the located node (>= 0, >startoffset), + * on success + * -FDT_ERR_NOTFOUND, no node matching the criterion exists in the + * tree after startoffset + * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, standard meanings + */ +int fdt_node_offset_by_prop_value (const void *fdt, int startoffset, + const char *propname, + const void *propval, int proplen); + +/** + * fdt_node_offset_by_phandle - find the node with a given phandle + * @fdt: pointer to the device tree blob + * @phandle: phandle value + * + * fdt_node_offset_by_phandle() returns the offset of the node + * which has the given phandle value. If there is more than one node + * in the tree with the given phandle (an invalid tree), results are + * undefined. + * + * returns: + * structure block offset of the located node (>= 0), on success + * -FDT_ERR_NOTFOUND, no node with that phandle exists + * -FDT_ERR_BADPHANDLE, given phandle value was invalid (0 or -1) + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, standard meanings + */ +int fdt_node_offset_by_phandle (const void *fdt, uint32_t phandle); + +/** + * fdt_node_check_compatible: check a node's compatible property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of a tree node + * @compatible: string to match against + * + * + * fdt_node_check_compatible() returns 0 if the given node contains a + * 'compatible' property with the given string as one of its elements, + * it returns non-zero otherwise, or on error. + * + * returns: + * 0, if the node has a 'compatible' property listing the given string + * 1, if the node has a 'compatible' property, but it does not list + * the given string + * -FDT_ERR_NOTFOUND, if the given node has no 'compatible' property + * -FDT_ERR_BADOFFSET, if nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, standard meanings + */ +int fdt_node_check_compatible (const void *fdt, int nodeoffset, + const char *compatible); + +/** + * fdt_node_offset_by_compatible - find nodes with a given 'compatible' value + * @fdt: pointer to the device tree blob + * @startoffset: only find nodes after this offset + * @compatible: 'compatible' string to match against + * + * fdt_node_offset_by_compatible() returns the offset of the first + * node after startoffset, which has a 'compatible' property which + * lists the given compatible string; or if startoffset is -1, the + * very first such node in the tree. + * + * To iterate through all nodes matching the criterion, the following + * idiom can be used: + * offset = fdt_node_offset_by_compatible(fdt, -1, compatible); + * while (offset != -FDT_ERR_NOTFOUND) { + * // other code here + * offset = fdt_node_offset_by_compatible(fdt, offset, compatible); + * } + * + * Note the -1 in the first call to the function, if 0 is used here + * instead, the function will never locate the root node, even if it + * matches the criterion. + * + * returns: + * structure block offset of the located node (>= 0, >startoffset), + * on success + * -FDT_ERR_NOTFOUND, no node matching the criterion exists in the + * tree after startoffset + * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, standard meanings + */ +int fdt_node_offset_by_compatible (const void *fdt, int startoffset, + const char *compatible); + +/**********************************************************************/ +/* Write-in-place functions */ +/**********************************************************************/ + +/** + * fdt_setprop_inplace - change a property's value, but not its size + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @val: pointer to data to replace the property value with + * @len: length of the property value + * + * fdt_setprop_inplace() replaces the value of a given property with + * the data in val, of length len. This function cannot change the + * size of a property, and so will only work if len is equal to the + * current length of the property. + * + * This function will alter only the bytes in the blob which contain + * the given property value, and will not alter or move any other part + * of the tree. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, if len is not equal to the property's current length + * -FDT_ERR_NOTFOUND, node does not have the named property + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ +int fdt_setprop_inplace (void *fdt, int nodeoffset, const char *name, + const void *val, int len); + +/** + * fdt_setprop_inplace_cell - change the value of a single-cell property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @val: cell (32-bit integer) value to replace the property with + * + * fdt_setprop_inplace_cell() replaces the value of a given property + * with the 32-bit integer cell value in val, converting val to + * big-endian if necessary. This function cannot change the size of a + * property, and so will only work if the property already exists and + * has length 4. + * + * This function will alter only the bytes in the blob which contain + * the given property value, and will not alter or move any other part + * of the tree. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, if the property's length is not equal to 4 + * -FDT_ERR_NOTFOUND, node does not have the named property + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ +static inline int +fdt_setprop_inplace_cell (void *fdt, int nodeoffset, + const char *name, uint32_t val) +{ + val = cpu_to_fdt32 (val); + return fdt_setprop_inplace (fdt, nodeoffset, name, &val, sizeof (val)); +} + +/** + * fdt_nop_property - replace a property with nop tags + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to nop + * @name: name of the property to nop + * + * fdt_nop_property() will replace a given property's representation + * in the blob with FDT_NOP tags, effectively removing it from the + * tree. + * + * This function will alter only the bytes in the blob which contain + * the property, and will not alter or move any other part of the + * tree. + * + * returns: + * 0, on success + * -FDT_ERR_NOTFOUND, node does not have the named property + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ +int fdt_nop_property (void *fdt, int nodeoffset, const char *name); + +/** + * fdt_nop_node - replace a node (subtree) with nop tags + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node to nop + * + * fdt_nop_node() will replace a given node's representation in the + * blob, including all its subnodes, if any, with FDT_NOP tags, + * effectively removing it from the tree. + * + * This function will alter only the bytes in the blob which contain + * the node and its properties and subnodes, and will not alter or + * move any other part of the tree. + * + * returns: + * 0, on success + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ +int fdt_nop_node (void *fdt, int nodeoffset); + +/**********************************************************************/ +/* Sequential write functions */ +/**********************************************************************/ + +int fdt_create (void *buf, int bufsize); +int fdt_add_reservemap_entry (void *fdt, uint64_t addr, uint64_t size); +int fdt_finish_reservemap (void *fdt); +int fdt_begin_node (void *fdt, const char *name); +int fdt_property (void *fdt, const char *name, const void *val, int len); +static inline int +fdt_property_cell (void *fdt, const char *name, uint32_t val) +{ + val = cpu_to_fdt32 (val); + return fdt_property (fdt, name, &val, sizeof (val)); +} + +#define fdt_property_string(fdt, name, str) \ + fdt_property(fdt, name, str, strlen(str)+1) +int fdt_end_node (void *fdt); +int fdt_finish (void *fdt); + +/**********************************************************************/ +/* Read-write functions */ +/**********************************************************************/ + +int fdt_open_into (const void *fdt, void *buf, int bufsize); +int fdt_pack (void *fdt); + +/** + * fdt_add_mem_rsv - add one memory reserve map entry + * @fdt: pointer to the device tree blob + * @address, @size: 64-bit values (native endian) + * + * Adds a reserve map entry to the given blob reserving a region at + * address address of length size. + * + * This function will insert data into the reserve map and will + * therefore change the indexes of some entries in the table. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to + * contain the new reservation entry + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings + */ +int fdt_add_mem_rsv (void *fdt, uint64_t address, uint64_t size); + +/** + * fdt_del_mem_rsv - remove a memory reserve map entry + * @fdt: pointer to the device tree blob + * @n: entry to remove + * + * fdt_del_mem_rsv() removes the n-th memory reserve map entry from + * the blob. + * + * This function will delete data from the reservation table and will + * therefore change the indexes of some entries in the table. + * + * returns: + * 0, on success + * -FDT_ERR_NOTFOUND, there is no entry of the given index (i.e. there + * are less than n+1 reserve map entries) + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings + */ +int fdt_del_mem_rsv (void *fdt, int n); + +/** + * fdt_set_name - change the name of a given node + * @fdt: pointer to the device tree blob + * @nodeoffset: structure block offset of a node + * @name: name to give the node + * + * fdt_set_name() replaces the name (including unit address, if any) + * of the given node with the given string. NOTE: this function can't + * efficiently check if the new name is unique amongst the given + * node's siblings; results are undefined if this function is invoked + * with a name equal to one of the given node's siblings. + * + * This function may insert or delete data from the blob, and will + * therefore change the offsets of some existing nodes. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob + * to contain the new name + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, standard meanings + */ +int fdt_set_name (void *fdt, int nodeoffset, const char *name); + +/** + * fdt_setprop - create or change a property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @val: pointer to data to set the property value to + * @len: length of the property value + * + * fdt_setprop() sets the value of the named property in the given + * node to the given value and length, creating the property if it + * does not already exist. + * + * This function may insert or delete data from the blob, and will + * therefore change the offsets of some existing nodes. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to + * contain the new property value + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings + */ +int fdt_setprop (void *fdt, int nodeoffset, const char *name, + const void *val, int len); + +/** + * fdt_setprop_cell - set a property to a single cell value + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @val: 32-bit integer value for the property (native endian) + * + * fdt_setprop_cell() sets the value of the named property in the + * given node to the given cell value (converting to big-endian if + * necessary), or creates a new property with that value if it does + * not already exist. + * + * This function may insert or delete data from the blob, and will + * therefore change the offsets of some existing nodes. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to + * contain the new property value + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings + */ +static inline int +fdt_setprop_cell (void *fdt, int nodeoffset, const char *name, uint32_t val) +{ + val = cpu_to_fdt32 (val); + return fdt_setprop (fdt, nodeoffset, name, &val, sizeof (val)); +} + +/** + * fdt_setprop_string - set a property to a string value + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @str: string value for the property + * + * fdt_setprop_string() sets the value of the named property in the + * given node to the given string value (using the length of the + * string to determine the new length of the property), or creates a + * new property with that value if it does not already exist. + * + * This function may insert or delete data from the blob, and will + * therefore change the offsets of some existing nodes. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to + * contain the new property value + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings + */ +#define fdt_setprop_string(fdt, nodeoffset, name, str) \ + fdt_setprop((fdt), (nodeoffset), (name), (str), strlen(str)+1) + +/** + * fdt_delprop - delete a property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to nop + * @name: name of the property to nop + * + * fdt_del_property() will delete the given property. + * + * This function will delete data from the blob, and will therefore + * change the offsets of some existing nodes. + * + * returns: + * 0, on success + * -FDT_ERR_NOTFOUND, node does not have the named property + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ +int fdt_delprop (void *fdt, int nodeoffset, const char *name); + +/** + * fdt_add_subnode_namelen - creates a new node based on substring + * @fdt: pointer to the device tree blob + * @parentoffset: structure block offset of a node + * @name: name of the subnode to locate + * @namelen: number of characters of name to consider + * + * Identical to fdt_add_subnode(), but use only the first namelen + * characters of name as the name of the new node. This is useful for + * creating subnodes based on a portion of a larger string, such as a + * full path. + */ +int fdt_add_subnode_namelen (void *fdt, int parentoffset, + const char *name, int namelen); + +/** + * fdt_add_subnode - creates a new node + * @fdt: pointer to the device tree blob + * @parentoffset: structure block offset of a node + * @name: name of the subnode to locate + * + * fdt_add_subnode() creates a new node as a subnode of the node at + * structure block offset parentoffset, with the given name (which + * should include the unit address, if any). + * + * This function will insert data into the blob, and will therefore + * change the offsets of some existing nodes. + + * returns: + * structure block offset of the created nodeequested subnode (>=0), on success + * -FDT_ERR_NOTFOUND, if the requested subnode does not exist + * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE tag + * -FDT_ERR_EXISTS, if the node at parentoffset already has a subnode of + * the given name + * -FDT_ERR_NOSPACE, if there is insufficient free space in the + * blob to contain the new node + * -FDT_ERR_NOSPACE + * -FDT_ERR_BADLAYOUT + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings. + */ +int fdt_add_subnode (void *fdt, int parentoffset, const char *name); + +/** + * fdt_del_node - delete a node (subtree) + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node to nop + * + * fdt_del_node() will remove the given node, including all its + * subnodes if any, from the blob. + * + * This function will delete data from the blob, and will therefore + * change the offsets of some existing nodes. + * + * returns: + * 0, on success + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ +int fdt_del_node (void *fdt, int nodeoffset); + +/**********************************************************************/ +/* Debugging / informational functions */ +/**********************************************************************/ + +const char *fdt_strerror (int errval); + +#endif /* _LIBFDT_H */ diff --git a/grub-core/lib/dtc/libfdt/libfdt_env.h b/grub-core/lib/dtc/libfdt/libfdt_env.h new file mode 100644 index 000000000..bf66ffd49 --- /dev/null +++ b/grub-core/lib/dtc/libfdt/libfdt_env.h @@ -0,0 +1,27 @@ +#ifndef _LIBFDT_ENV_H +#define _LIBFDT_ENV_H + +#include +#include +#include + +#define _B(n) ((unsigned long long)((uint8_t *)&x)[n]) +static inline uint32_t +fdt32_to_cpu (uint32_t x) +{ + return (_B (0) << 24) | (_B (1) << 16) | (_B (2) << 8) | _B (3); +} + +#define cpu_to_fdt32(x) fdt32_to_cpu(x) + +static inline uint64_t +fdt64_to_cpu (uint64_t x) +{ + return (_B (0) << 56) | (_B (1) << 48) | (_B (2) << 40) | (_B (3) << 32) + | (_B (4) << 24) | (_B (5) << 16) | (_B (6) << 8) | _B (7); +} + +#define cpu_to_fdt64(x) fdt64_to_cpu(x) +#undef _B + +#endif /* _LIBFDT_ENV_H */ diff --git a/grub-core/lib/dtc/libfdt/libfdt_internal.h b/grub-core/lib/dtc/libfdt/libfdt_internal.h new file mode 100644 index 000000000..b197032c8 --- /dev/null +++ b/grub-core/lib/dtc/libfdt/libfdt_internal.h @@ -0,0 +1,100 @@ +#ifndef _LIBFDT_INTERNAL_H +#define _LIBFDT_INTERNAL_H +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + * + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * + * a) This library 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 library 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 library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * Alternatively, + * + * b) 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + */ +#include + +#define FDT_ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) +#define FDT_TAGALIGN(x) (FDT_ALIGN((x), FDT_TAGSIZE)) + +#define FDT_CHECK_HEADER(fdt) \ + { \ + int err; \ + if ((err = fdt_check_header(fdt)) != 0) \ + return err; \ + } + +int _fdt_check_node_offset (const void *fdt, int offset); +int _fdt_check_prop_offset (const void *fdt, int offset); +const char *_fdt_find_string (const char *strtab, int tabsize, const char *s); +int _fdt_node_end_offset (void *fdt, int nodeoffset); + +static inline const void * +_fdt_offset_ptr (const void *fdt, int offset) +{ + return (const char *) fdt + fdt_off_dt_struct (fdt) + offset; +} + +static inline void * +_fdt_offset_ptr_w (void *fdt, int offset) +{ + return (void *) (uintptr_t) _fdt_offset_ptr (fdt, offset); +} + +static inline const struct fdt_reserve_entry * +_fdt_mem_rsv (const void *fdt, int n) +{ + const struct fdt_reserve_entry *rsv_table = + (const struct fdt_reserve_entry *) + ((const char *) fdt + fdt_off_mem_rsvmap (fdt)); + + return rsv_table + n; +} + +static inline struct fdt_reserve_entry * +_fdt_mem_rsv_w (void *fdt, int n) +{ + return (void *) (uintptr_t) _fdt_mem_rsv (fdt, n); +} + +#define FDT_SW_MAGIC (~FDT_MAGIC) + +#endif /* _LIBFDT_INTERNAL_H */ diff --git a/grub-core/lib/dtc/libfdt/version.lds b/grub-core/lib/dtc/libfdt/version.lds new file mode 100644 index 000000000..3c3994e27 --- /dev/null +++ b/grub-core/lib/dtc/libfdt/version.lds @@ -0,0 +1,54 @@ +LIBFDT_1.2 { + global: + fdt_next_node; + fdt_check_header; + fdt_move; + fdt_string; + fdt_num_mem_rsv; + fdt_get_mem_rsv; + fdt_subnode_offset_namelen; + fdt_subnode_offset; + fdt_path_offset; + fdt_get_name; + fdt_get_property_namelen; + fdt_get_property; + fdt_getprop_namelen; + fdt_getprop; + fdt_get_phandle; + fdt_get_alias_namelen; + fdt_get_alias; + fdt_get_path; + fdt_supernode_atdepth_offset; + fdt_node_depth; + fdt_parent_offset; + fdt_node_offset_by_prop_value; + fdt_node_offset_by_phandle; + fdt_node_check_compatible; + fdt_node_offset_by_compatible; + fdt_setprop_inplace; + fdt_nop_property; + fdt_nop_node; + fdt_create; + fdt_add_reservemap_entry; + fdt_finish_reservemap; + fdt_begin_node; + fdt_property; + fdt_end_node; + fdt_finish; + fdt_open_into; + fdt_pack; + fdt_add_mem_rsv; + fdt_del_mem_rsv; + fdt_set_name; + fdt_setprop; + fdt_delprop; + fdt_add_subnode_namelen; + fdt_add_subnode; + fdt_del_node; + fdt_strerror; + fdt_offset_ptr; + fdt_next_tag; + + local: + *; +}; diff --git a/grub-core/lib/efi/halt.c b/grub-core/lib/efi/halt.c index 5ebf2cd1d..3e1ea47f4 100644 --- a/grub-core/lib/efi/halt.c +++ b/grub-core/lib/efi/halt.c @@ -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, diff --git a/grub-core/lib/setjmp.S b/grub-core/lib/setjmp.S index 2e4974297..feb7b431c 100644 --- a/grub-core/lib/setjmp.S +++ b/grub-core/lib/setjmp.S @@ -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 diff --git a/grub-core/lib/uboot/datetime.c b/grub-core/lib/uboot/datetime.c new file mode 100644 index 000000000..4be716928 --- /dev/null +++ b/grub-core/lib/uboot/datetime.c @@ -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 . + */ + +#include +#include +#include +#include +#include + +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"); +} diff --git a/grub-core/lib/uboot/halt.c b/grub-core/lib/uboot/halt.c new file mode 100644 index 000000000..9d5a1386d --- /dev/null +++ b/grub-core/lib/uboot/halt.c @@ -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 . + */ + +#include +#include +#include + +void +grub_halt (void) +{ + grub_machine_fini (); + + /* Just stop here */ + + while (1); +} diff --git a/grub-core/lib/uboot/reboot.c b/grub-core/lib/uboot/reboot.c new file mode 100644 index 000000000..3a9004418 --- /dev/null +++ b/grub-core/lib/uboot/reboot.c @@ -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 . + */ + +#include +#include +#include + +void +grub_reboot (void) +{ + grub_machine_fini (); + + uboot_reset (); + while (1); +} diff --git a/grub-core/loader/arm/linux.c b/grub-core/loader/arm/linux.c new file mode 100644 index 000000000..40b5b5e01 --- /dev/null +++ b/grub-core/loader/arm/linux.c @@ -0,0 +1,405 @@ +/* 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 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +GRUB_MOD_LICENSE ("GPLv3+"); + +static grub_dl_t my_mod; + +static grub_addr_t initrd_start; +static grub_size_t initrd_end; + +static grub_addr_t linux_addr; +static grub_size_t linux_size; + +static char *linux_args; + +static grub_addr_t firmware_boot_data; +static grub_addr_t boot_data; +static grub_uint32_t machine_type; + +/* + * linux_prepare_fdt(): + * Prepares a loaded FDT for being passed to Linux. + * Merges in command line parameters and sets up initrd addresses. + */ +static grub_err_t +linux_prepare_fdt (void) +{ + int node; + int retval; + int tmp_size; + void *tmp_fdt; + + tmp_size = fdt_totalsize ((void *) boot_data) + FDT_ADDITIONAL_ENTRIES_SIZE; + tmp_fdt = grub_malloc (tmp_size); + if (!tmp_fdt) + return GRUB_ERR_OUT_OF_MEMORY; + + fdt_open_into ((void *) boot_data, tmp_fdt, tmp_size); + + /* Find or create '/chosen' node */ + node = fdt_subnode_offset (tmp_fdt, 0, "chosen"); + if (node < 0) + { + grub_printf ("No 'chosen' node in FDT - creating.\n"); + node = fdt_add_subnode (tmp_fdt, 0, "chosen"); + if (node < 0) + goto failure; + } + + grub_printf ("linux_args: '%s'\n", linux_args); + + /* Generate and set command line */ + retval = fdt_setprop (tmp_fdt, node, "bootargs", linux_args, + grub_strlen (linux_args) + 1); + if (retval) + goto failure; + + if (initrd_start && initrd_end) + { + /* + * We're using physical addresses, so even if we have LPAE, we're + * restricted to a 32-bit address space. + */ + grub_uint32_t fdt_initrd_start = cpu_to_fdt32 (initrd_start); + grub_uint32_t fdt_initrd_end = cpu_to_fdt32 (initrd_end); + + grub_dprintf ("loader", "Initrd @ 0x%08x-0x%08x\n", + initrd_start, initrd_end); + + retval = fdt_setprop (tmp_fdt, node, "linux,initrd-start", + &fdt_initrd_start, sizeof (fdt_initrd_start)); + if (retval) + goto failure; + retval = fdt_setprop (tmp_fdt, node, "linux,initrd-end", + &fdt_initrd_end, sizeof (fdt_initrd_end)); + if (retval) + goto failure; + } + + /* Copy updated FDT to its launch location */ + fdt_move (tmp_fdt, (void *) boot_data, fdt_totalsize (tmp_fdt)); + grub_free (tmp_fdt); + fdt_pack ((void *) boot_data); + + grub_dprintf ("loader", "FDT updated for Linux boot\n"); + + return GRUB_ERR_NONE; + +failure: + grub_free (tmp_fdt); + return GRUB_ERR_BAD_ARGUMENT; +} + +static grub_err_t +linux_boot (void) +{ + kernel_entry_t linuxmain; + grub_err_t err = GRUB_ERR_NONE; + + grub_arch_sync_caches ((void *) linux_addr, linux_size); + + grub_dprintf ("loader", "Kernel at: 0x%x\n", linux_addr); + + if (!boot_data) + { + if (firmware_boot_data) + { + grub_printf ("Using firmware-supplied boot data @ 0x%08x\n", + firmware_boot_data); + boot_data = firmware_boot_data; + } + else + { + return GRUB_ERR_FILE_NOT_FOUND; + } + } + + grub_dprintf ("loader", "Boot data at: 0x%x\n", boot_data); + + if (fdt32_to_cpu (*(grub_uint32_t *) (boot_data)) == FDT_MAGIC) + { + grub_dprintf ("loader", "FDT @ 0x%08x\n", (grub_addr_t) boot_data); + if (linux_prepare_fdt () != GRUB_ERR_NONE) + { + grub_dprintf ("loader", "linux_prepare_fdt() failed\n"); + return GRUB_ERR_FILE_NOT_FOUND; + } + } + + grub_dprintf ("loader", "Jumping to Linux...\n"); + + /* Boot the kernel. + * Arguments to kernel: + * r0 - 0 + * r1 - machine type (possibly passed from firmware) + * r2 - address of DTB or ATAG list + */ + 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, (void *) boot_data); + + return err; +} + +/* + * Only support zImage, so no relocations necessary + */ +static grub_err_t +linux_load (const char *filename) +{ + grub_file_t file; + int size; + + file = grub_file_open (filename); + if (!file) + return GRUB_ERR_FILE_NOT_FOUND; + + size = grub_file_size (file); + if (size == 0) + return GRUB_ERR_FILE_READ_ERROR; + +#ifdef GRUB_MACHINE_EFI + linux_addr = (grub_addr_t) grub_efi_allocate_loader_memory (LINUX_PHYS_OFFSET, size); +#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) + { + grub_printf ("Kernel read failed!\n"); + return GRUB_ERR_FILE_READ_ERROR; + } + + if (*(grub_uint32_t *) (linux_addr + LINUX_ZIMAGE_OFFSET) + != LINUX_ZIMAGE_MAGIC) + { + return grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("invalid zImage")); + } + + linux_size = size; + + return GRUB_ERR_NONE; +} + +static grub_err_t +linux_unload (void) +{ + grub_dl_unref (my_mod); + + grub_free (linux_args); + linux_args = NULL; + + initrd_start = initrd_end = 0; + + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) +{ + int size, retval; + grub_file_t file; + grub_dl_ref (my_mod); + + if (argc == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); + + file = grub_file_open (argv[0]); + if (!file) + goto fail; + + retval = linux_load (argv[0]); + grub_file_close (file); + if (retval != GRUB_ERR_NONE) + goto fail; + + grub_loader_set (linux_boot, linux_unload, 1); + + size = grub_loader_cmdline_size (argc, argv); + linux_args = grub_malloc (size + sizeof (LINUX_IMAGE)); + if (!linux_args) + goto fail; + + /* Create kernel command line. */ + grub_memcpy (linux_args, LINUX_IMAGE, sizeof (LINUX_IMAGE)); + grub_create_loader_cmdline (argc, argv, + linux_args + sizeof (LINUX_IMAGE) - 1, size); + + return GRUB_ERR_NONE; + +fail: + grub_dl_unref (my_mod); + return grub_errno; +} + +static grub_err_t +grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) +{ + grub_file_t file; + int size; + + if (argc == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); + + file = grub_file_open (argv[0]); + if (!file) + return grub_errno; + + size = grub_file_size (file); + if (size == 0) + goto fail; + +#ifdef GRUB_MACHINE_EFI + initrd_start = (grub_addr_t) grub_efi_allocate_loader_memory (LINUX_INITRD_PHYS_OFFSET, size); +#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) + goto fail; + + initrd_end = initrd_start + size; + + return GRUB_ERR_NONE; + +fail: + grub_file_close (file); + + return grub_errno; +} + +static void * +load_dtb (grub_file_t dtb, int size) +{ + void *fdt; + + fdt = grub_malloc (size); + if (!fdt) + return NULL; + + if (grub_file_read (dtb, fdt, size) != size) + { + grub_free (fdt); + return NULL; + } + + if (fdt_check_header (fdt) != 0) + { + grub_free (fdt); + return NULL; + } + + return fdt; +} + +static grub_err_t +grub_cmd_devicetree (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) +{ + grub_file_t dtb; + void *blob; + int size; + + if (argc != 1) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); + + dtb = grub_file_open (argv[0]); + if (!dtb) + return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("failed to open file")); + + size = grub_file_size (dtb); + if (size == 0) + goto out; + + blob = load_dtb (dtb, size); + if (!blob) + return GRUB_ERR_FILE_NOT_FOUND; + +#ifdef GRUB_MACHINE_EFI + boot_data = (grub_addr_t) grub_efi_allocate_loader_memory (LINUX_FDT_PHYS_OFFSET, size); +#else + boot_data = LINUX_FDT_ADDRESS; +#endif + grub_dprintf ("loader", "Loading device tree to 0x%08x\n", + (grub_addr_t) boot_data); + fdt_move (blob, (void *) boot_data, fdt_totalsize (blob)); + grub_free (blob); + + /* + * We've successfully loaded an FDT, so any machine type passed + * from firmware is now obsolete. + */ + machine_type = ARM_FDT_MACHINE_TYPE; + + return GRUB_ERR_NONE; + + 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; + firmware_boot_data = firmware_get_boot_data (); + + boot_data = (grub_addr_t) NULL; + 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); +} diff --git a/grub-core/term/terminfo.c b/grub-core/term/terminfo.c index a46bb4b27..efb17e210 100644 --- a/grub-core/term/terminfo.c +++ b/grub-core/term/terminfo.c @@ -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) diff --git a/grub-core/term/uboot/console.c b/grub-core/term/uboot/console.c new file mode 100644 index 000000000..e351e6193 --- /dev/null +++ b/grub-core/term/uboot/console.c @@ -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 . + */ + +#include +#include +#include +#include +#include +#include +#include + +static void +put (struct grub_term_output *term __attribute__ ((unused)), const int c) +{ + uboot_putc (c); +} + +static int +readkey (struct grub_term_input *term __attribute__ ((unused))) +{ + if (uboot_tstc () > 0) + return 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 = 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) +{ +} diff --git a/include/grub/arm/efi/loader.h b/include/grub/arm/efi/loader.h new file mode 100644 index 000000000..4bab18e83 --- /dev/null +++ b/include/grub/arm/efi/loader.h @@ -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 . + */ + +#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 */ diff --git a/include/grub/arm/efi/memory.h b/include/grub/arm/efi/memory.h new file mode 100644 index 000000000..c9a61bb77 --- /dev/null +++ b/include/grub/arm/efi/memory.h @@ -0,0 +1 @@ +#include diff --git a/include/grub/arm/linux.h b/include/grub/arm/linux.h new file mode 100644 index 000000000..33e6c4b84 --- /dev/null +++ b/include/grub/arm/linux.h @@ -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 . + */ + +#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 +# 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 uboot_get_boot_data +# define firmware_get_machine_type uboot_get_machine_type +#elif defined GRUB_MACHINE_EFI +# include +# include +/* 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 */ diff --git a/include/grub/arm/system.h b/include/grub/arm/system.h new file mode 100644 index 000000000..e22060003 --- /dev/null +++ b/include/grub/arm/system.h @@ -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 */ + diff --git a/include/grub/arm/time.h b/include/grub/arm/time.h new file mode 100644 index 000000000..4128506cb --- /dev/null +++ b/include/grub/arm/time.h @@ -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 . + */ + +#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 */ diff --git a/include/grub/arm/types.h b/include/grub/arm/types.h new file mode 100644 index 000000000..4a806d05e --- /dev/null +++ b/include/grub/arm/types.h @@ -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 . + */ + +#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 */ diff --git a/include/grub/arm/uboot/kernel.h b/include/grub/arm/uboot/kernel.h new file mode 100644 index 000000000..c37a18d06 --- /dev/null +++ b/include/grub/arm/uboot/kernel.h @@ -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 . + */ + +#ifndef GRUB_KERNEL_MACHINE_HEADER +#define GRUB_KERNEL_MACHINE_HEADER 1 + +#ifndef ASM_FILE + +#include +#include + +#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 */ diff --git a/include/grub/disk.h b/include/grub/disk.h index d19b1ac96..70ff60997 100644 --- a/include/grub/disk.h +++ b/include/grub/disk.h @@ -44,6 +44,7 @@ enum grub_disk_dev_id GRUB_DISK_DEVICE_ARCDISK_ID, GRUB_DISK_DEVICE_HOSTDISK_ID, GRUB_DISK_DEVICE_PROCFS_ID, + GRUB_DISK_DEVICE_UBOOTDISK_ID, }; struct grub_disk; diff --git a/include/grub/efi/pe32.h b/include/grub/efi/pe32.h index c3efa9b3d..7cacabd45 100644 --- a/include/grub/efi/pe32.h +++ b/include/grub/efi/pe32.h @@ -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 diff --git a/include/grub/kernel.h b/include/grub/kernel.h index 73ea41656..52105fcce 100644 --- a/include/grub/kernel.h +++ b/include/grub/kernel.h @@ -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 diff --git a/include/grub/libgcc.h b/include/grub/libgcc.h index ca0d5774e..71674a940 100644 --- a/include/grub/libgcc.h +++ b/include/grub/libgcc.h @@ -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 (__wrap___clear_cache) (void *, void *); +#endif diff --git a/include/grub/offsets.h b/include/grub/offsets.h index bce755d98..1d5152ce9 100644 --- a/include/grub/offsets.h +++ b/include/grub/offsets.h @@ -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. */ diff --git a/include/grub/symbol.h b/include/grub/symbol.h index 390eb62f2..e2119bf35 100644 --- a/include/grub/symbol.h +++ b/include/grub/symbol.h @@ -29,7 +29,11 @@ #if HAVE_ASM_USCORE #ifdef ASM_FILE -# define EXT_C(sym) _ ## sym +# ifndef (__arm__) +# define EXT_C(sym) _ ## sym +# else +# define EXT_C(sym) % ## sym +# endif #else # define EXT_C(sym) "_" sym #endif diff --git a/include/grub/uboot/api_public.h b/include/grub/uboot/api_public.h new file mode 100644 index 000000000..35910ece6 --- /dev/null +++ b/include/grub/uboot/api_public.h @@ -0,0 +1,184 @@ +/* + * (C) Copyright 2007-2008 Semihalf + * + * Written by: Rafal Jaworowski + * + * This file is dual licensed; you can use it under the terms of + * either the GPL, or the BSD license, at your option. + * + * I. GPL: + * + * This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Alternatively, + * + * II. BSD license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _API_PUBLIC_H_ +#define _API_PUBLIC_H_ + +#define API_EINVAL 1 /* invalid argument(s) */ +#define API_ENODEV 2 /* no device */ +#define API_ENOMEM 3 /* no memory */ +#define API_EBUSY 4 /* busy, occupied etc. */ +#define API_EIO 5 /* I/O error */ +#define API_ESYSC 6 /* syscall error */ + +typedef int (*scp_t) (int, int *, ...); + +typedef grub_uint16_t uint16_t; +typedef grub_uint32_t uint32_t; + +#define API_SIG_VERSION 1 +#define API_SIG_MAGIC "UBootAPI" +#define API_SIG_MAGLEN 8 + +struct api_signature +{ + char magic[API_SIG_MAGLEN]; /* magic string */ + uint16_t version; /* API version */ + uint32_t checksum; /* checksum of this sig struct */ + scp_t syscall; /* entry point to the API */ +}; + +enum +{ + API_RSVD = 0, + API_GETC, + API_PUTC, + API_TSTC, + API_PUTS, + API_RESET, + API_GET_SYS_INFO, + API_UDELAY, + API_GET_TIMER, + API_DEV_ENUM, + API_DEV_OPEN, + API_DEV_CLOSE, + API_DEV_READ, + API_DEV_WRITE, + API_ENV_ENUM, + API_ENV_GET, + API_ENV_SET, + API_DISPLAY_GET_INFO, + API_DISPLAY_DRAW_BITMAP, + API_DISPLAY_CLEAR, + API_MAXCALL +}; + +#define MR_ATTR_FLASH 0x0001 +#define MR_ATTR_DRAM 0x0002 +#define MR_ATTR_SRAM 0x0003 +#define MR_ATTR_MASK 0x000f + +struct mem_region +{ + unsigned long start; + unsigned long size; + int flags; +}; + +struct sys_info +{ + unsigned long clk_bus; + unsigned long clk_cpu; + unsigned long bar; + struct mem_region *mr; + int mr_no; /* number of memory regions */ +}; + +#undef CONFIG_SYS_64BIT_LBA +#ifdef CONFIG_SYS_64BIT_LBA +typedef u_int64_t lbasize_t; +#else +typedef unsigned long lbasize_t; +#endif +typedef unsigned long lbastart_t; + +#define DEV_TYP_NONE 0x0000 +#define DEV_TYP_NET 0x0001 + +#define DEV_TYP_STOR 0x0002 +#define DT_STOR_IDE 0x0010 +#define DT_STOR_SCSI 0x0020 +#define DT_STOR_USB 0x0040 +#define DT_STOR_MMC 0x0080 +#define DT_STOR_SATA 0x0100 + +#define DEV_STA_CLOSED 0x0000 /* invalid, closed */ +#define DEV_STA_OPEN 0x0001 /* open i.e. active */ + +struct device_info +{ + int type; + void *cookie; + + union + { + struct + { + lbasize_t block_count; /* no of blocks */ + unsigned long block_size; /* size of one block */ + } storage; + + struct + { + unsigned char hwaddr[6]; + } net; + } info; +#define di_stor info.storage +#define di_net info.net + + int state; +}; + +#define DISPLAY_TYPE_LCD 0x0001 +#define DISPLAY_TYPE_VIDEO 0x0002 + +struct display_info +{ + int type; + /* screen size in pixels */ + int pixel_width; + int pixel_height; + /* screen size in rows and columns of text */ + int screen_rows; + int screen_cols; +}; + +#endif /* _API_PUBLIC_H_ */ diff --git a/include/grub/uboot/console.h b/include/grub/uboot/console.h new file mode 100644 index 000000000..993a53845 --- /dev/null +++ b/include/grub/uboot/console.h @@ -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 . + */ + +#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 */ diff --git a/include/grub/uboot/disk.h b/include/grub/uboot/disk.h new file mode 100644 index 000000000..b93665fea --- /dev/null +++ b/include/grub/uboot/disk.h @@ -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 . + */ + +#ifndef GRUB_UBOOT_DISK_HEADER +#define GRUB_UBOOT_DISK_HEADER 1 + +#include +#include +#include + +void grub_ubootdisk_init (void); +void grub_ubootdisk_fini (void); + +enum disktype +{ cd, fd, hd }; + +struct ubootdisk_data +{ + struct ubootdisk_data *next; + void *cookie; + int handle; + int opencount; + enum disktype type; + grub_uint32_t block_size; +}; + +grub_err_t grub_ubootdisk_register (struct device_info *newdev, int handle); + +#endif /* ! GRUB_UBOOT_DISK_HEADER */ diff --git a/include/grub/uboot/uboot.h b/include/grub/uboot/uboot.h new file mode 100644 index 000000000..642bbb6fa --- /dev/null +++ b/include/grub/uboot/uboot.h @@ -0,0 +1,150 @@ +/* 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 . + */ + +#ifndef GRUB_UBOOT_UBOOT_HEADER +#define GRUB_UBOOT_UBOOT_HEADER 1 + +#include +#include + +/* Functions. */ +void grub_uboot_mm_init (void); +void grub_uboot_init (void); +void grub_uboot_fini (void); + +void uboot_return (int) __attribute__ ((noreturn)); + +grub_addr_t 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 (uboot_get_machine_type) (void); +grub_addr_t EXPORT_FUNC (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. + */ +#include + +#define UBOOT_API_SEARCH_LEN (3 * 1024 * 1024) +int uboot_api_init (void); + +/* All functions below are wrappers around the uboot_syscall() function */ + +/* + * int API_getc(int *c) + */ +int uboot_getc (void); + +/* + * int API_tstc(int *c) + */ +int uboot_tstc (void); + +/* + * int API_putc(char *ch) + */ +void uboot_putc (int c); + +/* + * int API_puts(const char *s) + */ +void uboot_puts (const char *s); + +/* + * int API_reset(void) + */ +void EXPORT_FUNC (uboot_reset) (void); + +/* + * int API_get_sys_info(struct sys_info *si) + * + * fill out the sys_info struct containing selected parameters about the + * machine + */ +struct sys_info *uboot_get_sys_info (void); + +/* + * int API_udelay(unsigned long *udelay) + */ +void uboot_udelay (grub_uint32_t usec); + +/* + * int API_get_timer(unsigned long *current, unsigned long *base) + */ +grub_uint32_t uboot_get_timer (grub_uint32_t base); + +/* + * int API_dev_enum(struct device_info *) + */ +int uboot_dev_enum (void); + +struct device_info *uboot_dev_get (int handle); + +/* + * int API_dev_open(struct device_info *) + */ +int uboot_dev_open (int handle); + +/* + * int API_dev_close(struct device_info *) + */ +int uboot_dev_close (int handle); + +/* + * Notice: this is for sending network packets only, as U-Boot does not + * support writing to storage at the moment (12.2007) + * + * int API_dev_write(struct device_info *di, void *buf, int *len) + */ +int uboot_dev_write (int handle, void *buf, int *len); + +/* + * int API_dev_read( + * struct device_info *di, + * void *buf, + * size_t *len, + * unsigned long *start + * size_t *act_len + * ) + */ +int uboot_dev_read (int handle, void *buf, lbasize_t blocks, + lbastart_t start, lbasize_t * real_blocks); + +int uboot_dev_recv (int handle, void *buf, int size, int *real_size); +int uboot_dev_send (int handle, void *buf, int size); + +/* + * int API_env_get(const char *name, char **value) + */ +char *uboot_env_get (const char *name); + +/* + * int API_env_set(const char *name, const char *value) + */ +void uboot_env_set (const char *name, const char *value); + +#endif /* ! GRUB_UBOOT_UBOOT_HEADER */ diff --git a/util/grub-install.in b/util/grub-install.in index 016b16147..65f1e9013 100644 --- a/util/grub-install.in +++ b/util/grub-install.in @@ -316,6 +316,8 @@ if [ x$source_dir = x ]; then target=i386-pc fi ;; + x"arm"*) + target="arm-uboot";; *) gettext "Unable to determine your platform. Use --target." ; echo ;; @@ -335,7 +337,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 @@ -464,6 +466,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 @@ -478,6 +482,8 @@ if [ x"$grub_modinfo_platform" = xefi ]; then # expansion. ia64) efi_file=grubia64.efi ;; + arm) + efi_file=grubarm.efi ;; *) efi_file=grub.efi ;; esac @@ -827,6 +833,14 @@ elif [ x"$grub_modinfo_platform" = xefi ]; then -L "$bootloader_id" -l "\\EFI\\$efi_distributor\\$efi_file" fi fi +elif [ x"${grub_modinfo_target_cpu}-${grub_modinfo_platform}" = xarm-uboot ]; then + grub_imgname="${grubdir}/${grub_modinfo_target_cpu}-$grub_modinfo_platform/core.${imgext}" + raw_imgname="${uboot_imgname}.raw" + mv "$grub_imgname" "$raw_imgname" + mkimage -T kernel -A ARM -O Linux -a 0x08000000 -e 0x08000000 -C none -d "$raw_imgname" "$grub_imgname" + if [ $? -eq 0 ]; then + rm -f "$raw_imgname" + fi else gettext "WARNING: no platform-specific install was performed" 1>&2 echo 1>&2 diff --git a/util/grub-mkimage.c b/util/grub-mkimage.c index ecea5d4f1..682e27e8f 100644 --- a/util/grub-mkimage.c +++ b/util/grub-mkimage.c @@ -69,7 +69,7 @@ struct image_target_desc IMAGE_SPARC64_AOUT, IMAGE_SPARC64_RAW, IMAGE_I386_IEEE1275, IMAGE_LOONGSON_ELF, IMAGE_QEMU, IMAGE_PPC, IMAGE_YEELOONG_FLASH, IMAGE_FULOONG2F_FLASH, IMAGE_I386_PC_PXE, IMAGE_MIPS_ARC, - IMAGE_QEMU_MIPS_FLASH + IMAGE_QEMU_MIPS_FLASH, IMAGE_UBOOT } id; enum { @@ -455,6 +455,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))) @@ -1022,6 +1062,7 @@ generate_image (const char *dir, const char *prefix, case IMAGE_SPARC64_RAW: case IMAGE_I386_IEEE1275: case IMAGE_PPC: + case IMAGE_UBOOT: break; } @@ -1684,6 +1725,9 @@ generate_image (const char *dir, const char *prefix, core_size = program_size + header_size + footer_size; } break; + case IMAGE_UBOOT: + /* Raw image, header added by grub-install */ + break; } grub_util_write_image (core_img, core_size, out, outname); diff --git a/util/grub-mkimagexx.c b/util/grub-mkimagexx.c index 476d05eeb..812db900a 100644 --- a/util/grub-mkimagexx.c +++ b/util/grub-mkimagexx.c @@ -58,6 +58,11 @@ #error "I'm confused" #endif +static Elf_Addr SUFFIX (entry_point); + +grub_err_t reloc_thm_call (grub_uint16_t *addr, Elf32_Addr sym_addr); +grub_err_t reloc_thm_jump19 (grub_uint16_t *addr, Elf32_Addr sym_addr); + /* Relocate symbols; note that this function overwrites the symbol table. Return the address of a start symbol. */ static Elf_Addr @@ -528,6 +533,48 @@ 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 -= offset; + 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_util_info (" THM_JUMP24:\ttarget=0x%08x\toffset=(0x%08x)", (unsigned int) target, sym_addr); + sym_addr -= offset; + /* Thumb instructions can be 16-bit aligned */ + reloc_thm_call ((grub_uint16_t *) target, sym_addr); + } + break; + case R_ARM_THM_JUMP19: + { + grub_util_info (" THM_JUMP19:\toffset=%d\t(0x%08x)", + sym_addr, sym_addr); + sym_addr -= offset; + /* Thumb instructions can be 16-bit aligned */ + reloc_thm_jump19 ((grub_uint16_t *) target, sym_addr); + } + 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); @@ -755,6 +802,46 @@ 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; +#if 0 + grub_util_info (" %s: add_fixup: 0x%08x : 0x%08x", + __FUNCTION__, (unsigned int) addr, + (unsigned int) current_address); +#endif + current_address + = SUFFIX (add_fixup_entry) (&lst, + GRUB_PE32_REL_BASED_HIGHLOW, + addr, 0, current_address, + image_target); + } + break; + default: + grub_util_error (_("relocation 0x%x is not implemented yet2"), ELF_R_TYPE (info)); + break; + } + break; +#endif /* defined(MKIMAGE_ELF32) */ default: grub_util_error ("unknown machine type 0x%x", image_target->elf_target); } @@ -1065,6 +1152,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, diff --git a/util/import_libfdt.py b/util/import_libfdt.py new file mode 100644 index 000000000..752a42363 --- /dev/null +++ b/util/import_libfdt.py @@ -0,0 +1,103 @@ +#* +#* 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 . +#* + +import re +import sys +import os +import codecs +import datetime + +if len (sys.argv) < 3: + print ("Usage: %s SOURCE DESTINATION" % sys.argv[0]) + exit (0) +dtcdir = sys.argv[1] +indir = os.path.join (dtcdir, "libfdt/") +outdir = os.path.join (sys.argv[2], "lib/dtc-grub/libfdt/") +try: + os.makedirs (outdir) +except: + print ("WARNING: %s already exists" % outdir) + +conf = codecs.open (os.path.join ("grub-core/", "Makefile.libfdt.def"), "w", "utf-8") +conf.write ("AutoGen definitions Makefile.tpl;\n\n") +conf.write ("module = {\n") +conf.write (" name = fdt;\n") +conf.write (" common = lib/dtc-grub/libfdt/fdt.c;\n") +conf.write (" common = lib/dtc-grub/libfdt/fdt_ro.c;\n") +conf.write (" common = lib/dtc-grub/libfdt/fdt_rw.c;\n") +conf.write (" common = lib/dtc-grub/libfdt/fdt_strerror.c;\n") +conf.write (" common = lib/dtc-grub/libfdt/fdt_sw.c;\n") +conf.write (" common = lib/dtc-grub/libfdt/fdt_wip.c;\n") +conf.write (" cppflags = '$(CPPFLAGS_POSIX) $(CPPFLAGS_LIBFDT)';\n") +conf.write ("\n") +conf.write (" enable = fdt;\n") +conf.write ("};\n") + +conf.close (); + + +libfdt_files = sorted (os.listdir (indir)) +chlog = "" + +for libfdt_file in libfdt_files: + infile = os.path.join (indir, (libfdt_file)) + outfile = os.path.join (outdir, (libfdt_file)) + + if not re.match (".*\.[ch]$", libfdt_file): + chlog = "%s * %s: Removed\n" % (chlog, libfdt_file) + continue + +# print ("file: %s, infile: %s, outfile: %s" % (libfdt_file, infile, outfile)) + + f = codecs.open (infile, "r", "utf-8") + fw = codecs.open (outfile, "w", "utf-8") + + lineno = 1 + + fw.write ("/* This file was automatically imported with \n") + fw.write (" import_libfdt.py. Please don't modify it */\n") + fw.write ("#include \n") + + # libfdt is dual-licensed: BSD or GPLv2+ + if re.match (".*\.c$", libfdt_file): + fw.write ("GRUB_MOD_LICENSE (\"GPLv2+\");\n") + + lines = f.readlines() + + for line in lines: + fw.write (line) + + f.close () + fw.close () + +patchfile = os.path.join (dtcdir, "libfdt-grub.diff") +#print "Patchfile: %s\n" % patchfile +ret = os.system("patch -d %s -p1 < %s" % (outdir, patchfile)) +if ret: + chlog = "%s * Applied Grub build patch\n" % chlog + + +dt = datetime.date.today () +fw = codecs.open (os.path.join (outdir, "ImportLog"), "w", "utf-8") +fw.write ("%04d-%02d-%02d Automatic import tool\n" % \ + (dt.year,dt.month, dt.day)) +fw.write ("\n") +fw.write (" Imported libfdt to GRUB\n") +fw.write ("\n") +fw.write (chlog) +fw.close () From bc1cf01cf283a0fe56bcbdae57bf0babf854cb0d Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Fri, 12 Apr 2013 16:46:51 +0200 Subject: [PATCH 02/25] Add uboot header ourselves --- include/grub/uboot/image.h | 175 +++++++++++++++++++++++++++++++++++++ util/grub-install.in | 8 -- util/grub-mkimage.c | 41 ++++++++- 3 files changed, 213 insertions(+), 11 deletions(-) create mode 100644 include/grub/uboot/image.h diff --git a/include/grub/uboot/image.h b/include/grub/uboot/image.h new file mode 100644 index 000000000..3e3f0346e --- /dev/null +++ b/include/grub/uboot/image.h @@ -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__ */ diff --git a/util/grub-install.in b/util/grub-install.in index 65f1e9013..cb428d4cd 100644 --- a/util/grub-install.in +++ b/util/grub-install.in @@ -833,14 +833,6 @@ elif [ x"$grub_modinfo_platform" = xefi ]; then -L "$bootloader_id" -l "\\EFI\\$efi_distributor\\$efi_file" fi fi -elif [ x"${grub_modinfo_target_cpu}-${grub_modinfo_platform}" = xarm-uboot ]; then - grub_imgname="${grubdir}/${grub_modinfo_target_cpu}-$grub_modinfo_platform/core.${imgext}" - raw_imgname="${uboot_imgname}.raw" - mv "$grub_imgname" "$raw_imgname" - mkimage -T kernel -A ARM -O Linux -a 0x08000000 -e 0x08000000 -C none -d "$raw_imgname" "$grub_imgname" - if [ $? -eq 0 ]; then - rm -f "$raw_imgname" - fi else gettext "WARNING: no platform-specific install was performed" 1>&2 echo 1>&2 diff --git a/util/grub-mkimage.c b/util/grub-mkimage.c index 682e27e8f..913861008 100644 --- a/util/grub-mkimage.c +++ b/util/grub-mkimage.c @@ -40,6 +40,8 @@ #include #include #include +#include +#include #define _GNU_SOURCE 1 #include @@ -1499,6 +1501,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; @@ -1725,9 +1763,6 @@ generate_image (const char *dir, const char *prefix, core_size = program_size + header_size + footer_size; } break; - case IMAGE_UBOOT: - /* Raw image, header added by grub-install */ - break; } grub_util_write_image (core_img, core_size, out, outname); From b2e2e9b07da6d8c3107e0202f32f118848ce4b48 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Fri, 12 Apr 2013 16:47:15 +0200 Subject: [PATCH 03/25] Add missing arm function --- include/grub/libgcc.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/grub/libgcc.h b/include/grub/libgcc.h index 71674a940..3038d5016 100644 --- a/include/grub/libgcc.h +++ b/include/grub/libgcc.h @@ -122,4 +122,5 @@ void EXPORT_FUNC (__aeabi_llsr) (void); void EXPORT_FUNC (__aeabi_uidiv) (void); void EXPORT_FUNC (__aeabi_uidivmod) (void); void EXPORT_FUNC (__wrap___clear_cache) (void *, void *); +void EXPORT_FUNC (__aeabi_ulcmp) (void); #endif From 04e80baa3291bf98031f9ef9bb9d329e0cd93483 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Fri, 12 Apr 2013 16:50:21 +0200 Subject: [PATCH 04/25] Report disk size --- grub-core/disk/uboot/ubootdisk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/grub-core/disk/uboot/ubootdisk.c b/grub-core/disk/uboot/ubootdisk.c index 92ce1e780..fed649439 100644 --- a/grub-core/disk/uboot/ubootdisk.c +++ b/grub-core/disk/uboot/ubootdisk.c @@ -246,7 +246,7 @@ uboot_disk_open (const char *name, struct grub_disk *disk) grub_dprintf ("ubootdisk", "(%s) blocksize=%d, log_sector_size=%d\n", disk->name, d->block_size, disk->log_sector_size); - disk->total_sectors = GRUB_DISK_SIZE_UNKNOWN; + disk->total_sectors = devinfo->di_stor.block_count ? : GRUB_DISK_SIZE_UNKNOWN; disk->data = d; return GRUB_ERR_NONE; From b624c948569baadf66381eb292d3b56b7ff2a991 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Fri, 12 Apr 2013 16:50:58 +0200 Subject: [PATCH 05/25] Simplify init assembly --- grub-core/kern/arm/uboot/startup.S | 39 +++++++++++------------------- grub-core/kern/uboot/init.c | 25 +++++-------------- 2 files changed, 20 insertions(+), 44 deletions(-) diff --git a/grub-core/kern/arm/uboot/startup.S b/grub-core/kern/arm/uboot/startup.S index 0ed33cc42..9585bf959 100644 --- a/grub-core/kern/arm/uboot/startup.S +++ b/grub-core/kern/arm/uboot/startup.S @@ -65,20 +65,28 @@ FUNCTION(codestart) ldr sp, =entry_state push {r4-r12,lr} @ store U-Boot context (sp in r12) - @ Put kernel parameters aside until we can store them (further down) - mov r4, r1 @ machine type - mov r5, r2 @ boot data + ldr r12, =EXT_C(uboot_machine_type) + str r1, [r12] + ldr r12, =EXT_C(uboot_boot_data) + str r2, [r12] @ Modules have been stored as a blob in BSS, @ they need to be manually relocated to _end or @ (__bss_start + grub_total_module_size), whichever greater. - bl uboot_get_real_bss_start @ r0 = src + 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 r3, r0, r2 @ blob end cmp r1, r3 @ _end < blob end? movlt r1, r3 @ dst = blob end + blob size - + + ldr r12, =EXT_C(grub_modbase) + str r1, [r12] + 1: ldr r3, [r0], #4 @ r3 = *src++ str r3, [r1], #4 @ *dst++ = r3 subs r2, #4 @ remaining -= 4 @@ -91,34 +99,15 @@ FUNCTION(codestart) @ Since we _are_ the C run-time, we need to manually zero the BSS @ region before continuing - bl uboot_get_real_bss_start @ zero from here + ldr r0, =EXT_C(__bss_start) @ zero from here ldr r1, =EXT_C(_end) @ to here mov r2, #0 1: str r2, [r0], #4 cmp r0, r1 bne 1b - - @ Global variables now accessible - store kernel parameters in memory - ldr r12, =EXT_C(uboot_machine_type) - str r4, [r12] - ldr r12, =EXT_C(uboot_boot_data) - str r5, [r12] b EXT_C(grub_main) - /* - * __bss_start does not actually point to the start of the runtime - * BSS, but rather to the next byte following the preceding data. - */ -FUNCTION (uboot_get_real_bss_start) - ldr r0, =EXT_C(__bss_start) @ src - tst r0, #(GRUB_KERNEL_MACHINE_MOD_ALIGN - 1) - beq 1f - mvn r1, #(GRUB_KERNEL_MACHINE_MOD_ALIGN - 1) - and r0, r0, r1 - add r0, r0, #(GRUB_KERNEL_MACHINE_MOD_ALIGN) -1: bx lr - /* * uboot_syscall(): * This function is effectively a veneer, so it cannot diff --git a/grub-core/kern/uboot/init.c b/grub-core/kern/uboot/init.c index b9944a452..431bd7b36 100644 --- a/grub-core/kern/uboot/init.c +++ b/grub-core/kern/uboot/init.c @@ -35,10 +35,10 @@ extern char _end[]; extern grub_size_t grub_total_module_size; extern int (*uboot_syscall_ptr) (int, int *, ...); -grub_addr_t grub_modbase; - -grub_uint32_t uboot_machine_type; -grub_addr_t uboot_boot_data; +/* Set to anything other than zero so it lands in .data and not .bss. */ +grub_addr_t grub_modbase = 0x55aa55aa; +grub_uint32_t uboot_machine_type = 0x55aa55aa; +grub_addr_t uboot_boot_data = 0x55aa55aa; static unsigned long timer_start; @@ -69,7 +69,6 @@ uboot_timer_ms (void) void grub_machine_init (void) { - grub_addr_t end, real_bss_start; int ver; /* First of all - establish connection with U-Boot */ @@ -85,26 +84,14 @@ grub_machine_init (void) uboot_puts ("invalid U-Boot API version\n"); } - /* - * Modules were relocated to _end, or __bss_start + grub_total_module_size, - * whichever greater. (And __bss_start may not point to actual BSS start...) - */ - real_bss_start = uboot_get_real_bss_start (); - end = real_bss_start + grub_total_module_size; - if (end < (grub_addr_t) _end) - end = (grub_addr_t) _end; - grub_modbase = end; - /* Initialize the console so that GRUB can display messages. */ grub_console_init_early (); /* Enumerate memory and initialize the memory management system. */ grub_uboot_mm_init (); - grub_dprintf ("init", "__bss_start: 0x%08x, real_bss_start: 0x%08x\n", - (grub_addr_t) __bss_start, real_bss_start); - grub_dprintf ("init", "end: 0x%08x, _end: 0x%08x\n", - (grub_addr_t) end, (grub_addr_t) _end); + 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 ()); From 4e13e84e56f7ed59145ea2fcb57e60bb967e9ff1 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Fri, 12 Apr 2013 16:51:33 +0200 Subject: [PATCH 06/25] Fix timer units --- grub-core/kern/uboot/init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/grub-core/kern/uboot/init.c b/grub-core/kern/uboot/init.c index 431bd7b36..1da37384a 100644 --- a/grub-core/kern/uboot/init.c +++ b/grub-core/kern/uboot/init.c @@ -63,7 +63,7 @@ uboot_get_boot_data (void) static grub_uint64_t uboot_timer_ms (void) { - return (grub_uint64_t) uboot_get_timer (timer_start); + return (grub_uint64_t) uboot_get_timer (timer_start) / 1000; } void From 28af3d867c5212f9459c8c1a3a458bbbc847b532 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Fri, 12 Apr 2013 16:53:58 +0200 Subject: [PATCH 07/25] Relocations cleanup --- grub-core/kern/arm/dl.c | 45 +++++++++++++--------------------------- include/grub/arm/reloc.h | 26 +++++++++++++++++++++++ util/grub-mkimagexx.c | 17 +++++++++------ 3 files changed, 51 insertions(+), 37 deletions(-) create mode 100644 include/grub/arm/reloc.h diff --git a/grub-core/kern/arm/dl.c b/grub-core/kern/arm/dl.c index 39a34ca5b..74e6b96b5 100644 --- a/grub-core/kern/arm/dl.c +++ b/grub-core/kern/arm/dl.c @@ -23,17 +23,11 @@ #include #include #include +#include #ifdef GRUB_UTIL # include #else -# if !defined(__thumb2__) -# error "Relocations not implemented for A32 ("ARM") instruction set yet!" -# endif - -grub_err_t reloc_jump24 (grub_uint32_t *addr, Elf32_Addr sym_addr); -grub_err_t reloc_thm_call (grub_uint16_t *addr, Elf32_Addr sym_addr); -grub_err_t reloc_thm_jump19 (grub_uint16_t *addr, Elf32_Addr sym_addr); #ifdef DL_DEBUG static const char *symstrtab; @@ -104,7 +98,7 @@ reloc_abs32 (Elf_Word *target, Elf_Addr sym_addr) * B.W, BL and BLX */ grub_err_t -reloc_thm_call (grub_uint16_t *target, Elf32_Addr sym_addr) +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; @@ -122,14 +116,8 @@ reloc_thm_call (grub_uint16_t *target, Elf32_Addr sym_addr) /* If BLX, target symbol must be ARM (target address LSB == 0) */ if (is_blx && (sym_addr & 1)) - { -#ifndef GRUB_UTIL - return grub_error - (GRUB_ERR_BUG, N_("Relocation targeting wrong execution state")); -#else - grub_util_error ("Relocation targeting wrong execution state"); -#endif - } + return grub_error (GRUB_ERR_BUG, + N_("Relocation targeting wrong execution state")); offset_low = -16777216; offset_high = is_blx ? 16777212 : 16777214; @@ -159,18 +147,12 @@ reloc_thm_call (grub_uint16_t *target, Elf32_Addr sym_addr) #endif if ((offset < offset_low) || (offset > offset_high)) - { -#ifdef GRUB_UTIL - grub_util_error ("Relocation out of range"); -#else - return grub_error - (GRUB_ERR_OUT_OF_RANGE, N_("THM_CALL Relocation out of range.")); -#endif - } + return grub_error (GRUB_ERR_OUT_OF_RANGE, + N_("THM_CALL Relocation out of range.")); #ifdef GRUB_UTIL - grub_util_info (" relative destination = 0x%08x", - (unsigned int)target + offset); + grub_util_info (" relative destination = 0x%08lx", + (unsigned long)target + offset); #endif /* Reassemble instruction word */ @@ -200,7 +182,7 @@ reloc_thm_call (grub_uint16_t *target, Elf32_Addr sym_addr) * Relocate conditional Thumb (T32) B.W */ grub_err_t -reloc_thm_jump19 (grub_uint16_t *addr, Elf32_Addr sym_addr) +grub_arm_reloc_thm_jump19 (grub_uint16_t *addr, Elf32_Addr sym_addr) { grub_int32_t offset; grub_uint32_t insword, insmask; @@ -260,7 +242,7 @@ reloc_thm_jump19 (grub_uint16_t *addr, Elf32_Addr sym_addr) * Relocate ARM (A32) B */ grub_err_t -reloc_jump24 (grub_uint32_t *addr, Elf32_Addr sym_addr) +grub_arm_reloc_jump24 (grub_uint32_t *addr, Elf32_Addr sym_addr) { grub_uint32_t insword; grub_int32_t offset; @@ -358,9 +340,10 @@ do_relocations (Elf_Shdr * relhdr, Elf_Ehdr * e, grub_dl_t mod) return retval; } break; + case R_ARM_CALL: case R_ARM_JUMP24: { - retval = reloc_jump24 (target, sym_addr); + retval = grub_arm_reloc_jump24 (target, sym_addr); if (retval != GRUB_ERR_NONE) return retval; } @@ -369,7 +352,7 @@ do_relocations (Elf_Shdr * relhdr, Elf_Ehdr * e, grub_dl_t mod) case R_ARM_THM_JUMP24: { /* Thumb instructions can be 16-bit aligned */ - retval = reloc_thm_call ((grub_uint16_t *) target, sym_addr); + retval = grub_arm_reloc_thm_call ((grub_uint16_t *) target, sym_addr); if (retval != GRUB_ERR_NONE) return retval; } @@ -377,7 +360,7 @@ do_relocations (Elf_Shdr * relhdr, Elf_Ehdr * e, grub_dl_t mod) case R_ARM_THM_JUMP19: { /* Thumb instructions can be 16-bit aligned */ - retval = reloc_thm_jump19 ((grub_uint16_t *) target, sym_addr); + retval = grub_arm_reloc_thm_jump19 ((grub_uint16_t *) target, sym_addr); if (retval != GRUB_ERR_NONE) return retval; } diff --git a/include/grub/arm/reloc.h b/include/grub/arm/reloc.h new file mode 100644 index 000000000..b47792d95 --- /dev/null +++ b/include/grub/arm/reloc.h @@ -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 . + */ + +#ifndef GRUB_ARM_RELOC_H +#define GRUB_ARM_RELOC_H 1 + +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 diff --git a/util/grub-mkimagexx.c b/util/grub-mkimagexx.c index 812db900a..b6a7dcbee 100644 --- a/util/grub-mkimagexx.c +++ b/util/grub-mkimagexx.c @@ -60,9 +60,6 @@ static Elf_Addr SUFFIX (entry_point); -grub_err_t reloc_thm_call (grub_uint16_t *addr, Elf32_Addr sym_addr); -grub_err_t reloc_thm_jump19 (grub_uint16_t *addr, Elf32_Addr sym_addr); - /* Relocate symbols; note that this function overwrites the symbol table. Return the address of a start symbol. */ static Elf_Addr @@ -553,19 +550,27 @@ SUFFIX (relocate_addresses) (Elf_Ehdr *e, Elf_Shdr *sections, case R_ARM_THM_CALL: case R_ARM_THM_JUMP24: { - grub_util_info (" THM_JUMP24:\ttarget=0x%08x\toffset=(0x%08x)", (unsigned int) target, sym_addr); + 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 */ - reloc_thm_call ((grub_uint16_t *) target, sym_addr); + 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 */ - reloc_thm_jump19 ((grub_uint16_t *) target, sym_addr); + err = grub_arm_reloc_thm_jump19 ((grub_uint16_t *) target, + sym_addr); + if (err) + grub_util_error ("%s", grub_errmsg); } break; default: From 66eae7974d815b1c58d146e023effebb6a4a5d58 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Fri, 12 Apr 2013 16:54:28 +0200 Subject: [PATCH 08/25] Amall cleanup in api_public.h --- include/grub/uboot/api_public.h | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/include/grub/uboot/api_public.h b/include/grub/uboot/api_public.h index 35910ece6..0707f5cff 100644 --- a/include/grub/uboot/api_public.h +++ b/include/grub/uboot/api_public.h @@ -61,9 +61,6 @@ typedef int (*scp_t) (int, int *, ...); -typedef grub_uint16_t uint16_t; -typedef grub_uint32_t uint32_t; - #define API_SIG_VERSION 1 #define API_SIG_MAGIC "UBootAPI" #define API_SIG_MAGLEN 8 @@ -71,8 +68,8 @@ typedef grub_uint32_t uint32_t; struct api_signature { char magic[API_SIG_MAGLEN]; /* magic string */ - uint16_t version; /* API version */ - uint32_t checksum; /* checksum of this sig struct */ + grub_uint16_t version; /* API version */ + grub_uint32_t checksum; /* checksum of this sig struct */ scp_t syscall; /* entry point to the API */ }; From 2081f503071db2f0f148272ea04811996a214b74 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Fri, 12 Apr 2013 16:54:54 +0200 Subject: [PATCH 09/25] Makefile fix --- Makefile.util.def | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Makefile.util.def b/Makefile.util.def index 3c74e853b..aba7499e2 100644 --- a/Makefile.util.def +++ b/Makefile.util.def @@ -150,7 +150,7 @@ program = { common = util/resolve.c; common = grub-core/kern/emu/argp_common.c; - arm = grub-core/kern/arm/dl.c; + common = grub-core/kern/arm/dl.c; extra_dist = util/grub-mkimagexx.c; @@ -472,7 +472,6 @@ script = { enable = mips_loongson; enable = ia64_efi; enable = powerpc_ieee1275; - enable = arm_uboot; }; script = { From c86c39abef7637365b5e09a5ff620564b66d537d Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Fri, 12 Apr 2013 16:55:38 +0200 Subject: [PATCH 10/25] Add uboot net --- grub-core/Makefile.core.def | 6 + grub-core/kern/uboot/hw.c | 2 +- grub-core/net/drivers/uboot/ubootnet.c | 185 +++++++++++++++++++++++++ include/grub/uboot/uboot.h | 12 +- 4 files changed, 198 insertions(+), 7 deletions(-) create mode 100644 grub-core/net/drivers/uboot/ubootnet.c diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index f58888a6f..607d21795 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -1830,6 +1830,12 @@ module = { enable = ieee1275; }; +module = { + name = ubootnet; + common = net/drivers/uboot/ubootnet.c; + enable = uboot; +}; + module = { name = efinet; common = net/drivers/efi/efinet.c; diff --git a/grub-core/kern/uboot/hw.c b/grub-core/kern/uboot/hw.c index afa1e1069..08f8fb312 100644 --- a/grub-core/kern/uboot/hw.c +++ b/grub-core/kern/uboot/hw.c @@ -82,7 +82,7 @@ grub_uboot_probe_hardware (void) } else if (devinfo->type & DEV_TYP_NET) { - grub_dprintf ("init", " type\t\t= NET (not supported yet)\n"); + grub_dprintf ("init", " type\t\t= NET\n"); } else { diff --git a/grub-core/net/drivers/uboot/ubootnet.c b/grub-core/net/drivers/uboot/ubootnet.c new file mode 100644 index 000000000..c0454f429 --- /dev/null +++ b/grub-core/net/drivers/uboot/ubootnet.c @@ -0,0 +1,185 @@ +/* + * 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 . + */ + +#include +#include +#include +#include +#include +#include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); + +struct ubootnet_data +{ + void *cookie; + int handle; +}; + +static grub_err_t +card_open (struct grub_net_card *dev) +{ + int status; + struct ubootnet_data *data = dev->data; + + status = uboot_dev_open (data->handle); + 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) +{ + struct ubootnet_data *data = dev->data; + + uboot_dev_close (data->handle); +} + +static grub_err_t +send_card_buffer (struct grub_net_card *dev, struct grub_net_buff *pack) +{ + int status; + struct ubootnet_data *data = dev->data; + grub_size_t len; + + len = (pack->tail - pack->data); + if (len > dev->mtu) + len = dev->mtu; + + grub_memcpy (dev->txbuf, pack->data, len); + status = uboot_dev_send (data->handle, 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; + struct ubootnet_data *data = dev->data; + grub_uint64_t start_time; + struct grub_net_buff *nb; + int actual; + + nb = grub_netbuff_alloc (dev->mtu + 64 + 2); + if (!nb) + { + grub_netbuff_free (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 = uboot_dev_recv (data->handle, 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 = uboot_dev_enum (); + + for (i = 0; i < devcount; i++) + { + struct device_info *devinfo = uboot_dev_get (i); + struct ubootnet_data *ubdata; + struct grub_net_card *card; + + if (!(devinfo->type & DEV_TYP_NET)) + continue; + + ubdata = grub_malloc (sizeof (struct ubootnet_data)); + if (!ubdata) + { + grub_print_error (); + return; + } + card = grub_zalloc (sizeof (struct grub_net_card)); + if (!card) + { + grub_free (ubdata); + grub_print_error (); + return; + } + + ubdata->handle = i; + ubdata->cookie = devinfo->cookie; + + /* 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_print_error (); + continue; + } + + card->data = ubdata; + 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); +} diff --git a/include/grub/uboot/uboot.h b/include/grub/uboot/uboot.h index 642bbb6fa..c9fb86771 100644 --- a/include/grub/uboot/uboot.h +++ b/include/grub/uboot/uboot.h @@ -100,19 +100,19 @@ grub_uint32_t uboot_get_timer (grub_uint32_t base); /* * int API_dev_enum(struct device_info *) */ -int uboot_dev_enum (void); +int EXPORT_FUNC(uboot_dev_enum) (void); -struct device_info *uboot_dev_get (int handle); +struct device_info *EXPORT_FUNC(uboot_dev_get) (int handle); /* * int API_dev_open(struct device_info *) */ -int uboot_dev_open (int handle); +int EXPORT_FUNC(uboot_dev_open) (int handle); /* * int API_dev_close(struct device_info *) */ -int uboot_dev_close (int handle); +int EXPORT_FUNC(uboot_dev_close) (int handle); /* * Notice: this is for sending network packets only, as U-Boot does not @@ -134,8 +134,8 @@ int uboot_dev_write (int handle, void *buf, int *len); int uboot_dev_read (int handle, void *buf, lbasize_t blocks, lbastart_t start, lbasize_t * real_blocks); -int uboot_dev_recv (int handle, void *buf, int size, int *real_size); -int uboot_dev_send (int handle, void *buf, int size); +int EXPORT_FUNC(uboot_dev_recv) (int handle, void *buf, int size, int *real_size); +int EXPORT_FUNC(uboot_dev_send) (int handle, void *buf, int size); /* * int API_env_get(const char *name, char **value) From fa8058da9ee190cbf683b5a7329bd983429d168e Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sat, 13 Apr 2013 20:07:37 +0200 Subject: [PATCH 11/25] Fix few memory leaks. Reported by Francesco Lavra --- grub-core/net/drivers/uboot/ubootnet.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/grub-core/net/drivers/uboot/ubootnet.c b/grub-core/net/drivers/uboot/ubootnet.c index c0454f429..2b743f445 100644 --- a/grub-core/net/drivers/uboot/ubootnet.c +++ b/grub-core/net/drivers/uboot/ubootnet.c @@ -84,10 +84,7 @@ get_card_packet (struct grub_net_card *dev) nb = grub_netbuff_alloc (dev->mtu + 64 + 2); if (!nb) - { - grub_netbuff_free (nb); - return NULL; - } + 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); @@ -161,6 +158,8 @@ GRUB_MOD_INIT (ubootnet) card->txbuf = grub_zalloc (card->txbufsize); if (!card->txbuf) { + grub_free (ubdata); + grub_free (card); grub_print_error (); continue; } From bb9f92b9b1b00cefbfbe63ab53077049bd15e517 Mon Sep 17 00:00:00 2001 From: Leif Lindholm Date: Fri, 3 May 2013 14:41:08 +0200 Subject: [PATCH 12/25] Leif's build fixes --- acinclude.m4 | 20 ++++++ conf/Makefile.common | 5 +- configure.ac | 8 +++ grub-core/kern/arm/cache.S | 119 +++++++++++++++++------------------- grub-core/kern/uboot/init.c | 6 +- grub-core/lib/arm/setjmp.S | 17 +----- include/grub/libgcc.h | 1 - include/grub/symbol.h | 6 +- 8 files changed, 90 insertions(+), 92 deletions(-) diff --git a/acinclude.m4 b/acinclude.m4 index 49a1a75d1..faf90fb18 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -458,3 +458,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] +]) diff --git a/conf/Makefile.common b/conf/Makefile.common index d9b34714a..08fd2b0d6 100644 --- a/conf/Makefile.common +++ b/conf/Makefile.common @@ -38,10 +38,7 @@ if COND_sparc64_ieee1275 LDFLAGS_PLATFORM = -Wl,-melf64_sparc -mno-relax endif if COND_arm -# Image entry point always in ARM (A32) state - ensure proper functionality if -# the rest is built for the Thumb (T32) state. - CFLAGS_PLATFORM += -mthumb-interwork -mno-unaligned-access -mlong-calls - CCASFLAGS_PLATFORM = -Wa,-mimplicit-it=thumb + CFLAGS_PLATFORM += -mthumb-interwork -mlong-calls LDFLAGS_PLATFORM = -Wl,--wrap=__clear_cache endif diff --git a/configure.ac b/configure.ac index ed8de8ab4..7ad6231d7 100644 --- a/configure.ac +++ b/configure.ac @@ -656,6 +656,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])]) diff --git a/grub-core/kern/arm/cache.S b/grub-core/kern/arm/cache.S index 6d7ed8537..dc1b63aea 100644 --- a/grub-core/kern/arm/cache.S +++ b/grub-core/kern/arm/cache.S @@ -17,19 +17,22 @@ */ #include -#include .file "cache.S" .text .syntax unified -#if !defined (__thumb2__) .arm -#define ARM(x...) x -#define THUMB(x...) +#if (__ARM_ARCH_6__ == 1) + .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 +#elif (__ARM_ARCH_7A__ == 1) +# define DMB dmb +# define DSB dsb +# define ISB isb #else - .thumb -#define THUMB(x...) x -#define ARM(x...) +# error Unsupported architecture version! #endif .align 2 @@ -39,54 +42,43 @@ */ @ r0 - *beg (inclusive) -@ r1 - *end (exclusive) +@ r1 - *end (exclusive) clean_dcache_range: - @ Clean data cache range for range to point-of-unification + @ Clean data cache for range to point-of-unification ldr r2, 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 DEBUG - push {r0-r2, lr} - mov r1, r2 - mov r2, r0 - ldr r0, =dcstr - bl EXT_C(grub_printf) - pop {r0-r2, lr} -#endif mcr p15, 0, r0, c7, c11, 1 @ DCCMVAU add r0, r0, r2 @ Next line b 1b -2: dsb +2: DSB bx lr @ r0 - *beg (inclusive) -@ r1 - *end (exclusive) +@ r1 - *end (exclusive) invalidate_icache_range: @ Invalidate instruction cache for range to point-of-unification ldr r2, ilinesz + sub r3, r2, #1 @ align "beg" to start of line + mvn r3, r3 + and r0, r0, r3 1: cmp r0, r1 bge 2f -#ifdef DEBUG - push {r0-r2, lr} - mov r1, r2 - mov r2, r0 - ldr r0, =icstr - bl EXT_C(grub_printf) - pop {r0-r2, lr} -#endif 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 + DSB + ISB bx lr - -@void __wrap___clear_cache(char *beg, char *end); -FUNCTION(__wrap___clear_cache) - dmb - dsb + +sync_caches: + DMB + DSB push {r4-r6, lr} ldr r2, probed @ If first call, probe cache sizes cmp r2, #0 @@ -103,7 +95,8 @@ probe_caches: push {r4-r6, lr} mrc p15, 0, r4, c0, c0, 1 @ Read Cache Type Register mov r5, #1 - ubfx r6, r4, #16, #4 @ Extract min D-cache num word log2 + lsr r6, r4, #16 @ Extract min D-cache num word log2 + and r6, r6, #0xf add r6, r6, #2 @ words->bytes lsl r6, r5, r6 @ Convert to num bytes ldr r3, =dlinesz @@ -117,11 +110,6 @@ probe_caches: str r5, [r3] pop {r4-r6, pc} -#ifdef DEBUG -dcstr: .asciz "cleaning %d bytes of D cache @ 0x%08x\n" -icstr: .asciz "invalidating %d bytes of I cache @ 0x%08x\n" -#endif - .align 3 probed: .long 0 dlinesz: @@ -132,7 +120,7 @@ ilinesz: @void grub_arch_sync_caches (void *address, grub_size_t len) FUNCTION(grub_arch_sync_caches) add r1, r0, r1 - b __wrap___clear_cache + b sync_caches @ r0 - CLIDR @ r1 - LoC @@ -149,21 +137,26 @@ FUNCTION(grub_arch_sync_caches) clean_invalidate_dcache: push {r4-r12, lr} mrc p15, 1, r0, c0, c0, 1 @ Read CLIDR - ubfx r1, r0, #24, #3 @ Extract LoC - + 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 CSSIDR read) + @ 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 CSSIDR - ubfx r3, r8, #13, #14 @ Number of sets -1 - ubfx r4, r8, #3, #9 @ Number of ways -1 + 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 @@ -186,11 +179,11 @@ clean_invalidate_dcache: clz r9, r10 @ r9 = way field offset add r9, r9, #1 4: lsl r10, r6, r9 - orr r11, r8, r10 @ insert way field - - @ clean line by set/way + 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 @@ -200,7 +193,7 @@ clean_invalidate_dcache: 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 @@ -208,8 +201,8 @@ clean_invalidate_dcache: blt 2b @ outer loop @ return -6: dsb - isb +6: DSB + ISB pop {r4-r12, pc} FUNCTION(grub_arm_disable_caches_mmu) @@ -219,8 +212,8 @@ FUNCTION(grub_arm_disable_caches_mmu) mrc p15, 0, r0, c1, c0, 0 bic r0, r0, #(1 << 2) mcr p15, 0, r0, c1, c0, 0 - dsb - isb + DSB + ISB @ clean/invalidate D-cache bl clean_invalidate_dcache @@ -229,14 +222,14 @@ FUNCTION(grub_arm_disable_caches_mmu) mrc p15, 0, r0, c1, c0, 0 bic r0, r0, #(1 << 12) mcr p15, 0, r0, c1, c0, 0 - dsb - isb + DSB + ISB @ invalidate I-cache (also invalidates branch predictors) mcr p15, 0, r0, c7, c5, 0 - dsb - isb - + DSB + ISB + @ clear SCTLR M bit mrc p15, 0, r0, c1, c0, 0 bic r0, r0, #(1 << 0) @@ -244,8 +237,8 @@ FUNCTION(grub_arm_disable_caches_mmu) mcr p15, 0, r0, c8, c7, 0 @ invalidate TLB mcr p15, 0, r0, c7, c5, 6 @ invalidate branch predictor - dsb - isb + DSB + ISB pop {r4, pc} diff --git a/grub-core/kern/uboot/init.c b/grub-core/kern/uboot/init.c index 1da37384a..ab4eec682 100644 --- a/grub-core/kern/uboot/init.c +++ b/grub-core/kern/uboot/init.c @@ -130,10 +130,9 @@ grub_machine_get_bootlocation (char **device, char **path) tmp = uboot_env_get ("grub_bootdev"); if (tmp) { - *device = grub_malloc (grub_strlen (tmp) + 1); + *device = grub_strdup (tmp); if (*device == NULL) return; - grub_strncpy (*device, tmp, grub_strlen (tmp) + 1); } else *device = NULL; @@ -141,10 +140,9 @@ grub_machine_get_bootlocation (char **device, char **path) tmp = uboot_env_get ("grub_bootpath"); if (tmp) { - *path = grub_malloc (grub_strlen (tmp) + 1); + *path = grub_strdup (tmp); if (*path == NULL) return; - grub_strncpy (*path, tmp, grub_strlen (tmp) + 1); } else *path = NULL; diff --git a/grub-core/lib/arm/setjmp.S b/grub-core/lib/arm/setjmp.S index 7038a229c..9054e073e 100644 --- a/grub-core/lib/arm/setjmp.S +++ b/grub-core/lib/arm/setjmp.S @@ -17,19 +17,10 @@ */ #include -#include .file "setjmp.S" .syntax unified -#if !defined (__thumb2__) .arm -#define ARM(x...) x -#define THUMB(x...) -#else - .thumb -#define THUMB(x...) x -#define ARM(x...) -#endif .text @@ -37,9 +28,7 @@ * int grub_setjmp (grub_jmp_buf env) */ FUNCTION(grub_setjmp) - THUMB( mov ip, sp ) - THUMB( stm r0, { r4-r11, ip, lr } ) - ARM( stm r0, { r4-r11, sp, lr } ) + stm r0, { r4-r11, sp, lr } mov r0, #0 bx lr @@ -47,9 +36,7 @@ FUNCTION(grub_setjmp) * int grub_longjmp (grub_jmp_buf env, int val) */ FUNCTION(grub_longjmp) - THUMB( ldm r0, { r4-r11, ip, lr } ) - THUMB( mov sp, ip ) - ARM( ldm r0, { r4-r11, sp, lr } ) + ldm r0, { r4-r11, sp, lr } movs r0, r1 moveq r0, #1 bx lr diff --git a/include/grub/libgcc.h b/include/grub/libgcc.h index 3038d5016..d101db473 100644 --- a/include/grub/libgcc.h +++ b/include/grub/libgcc.h @@ -121,6 +121,5 @@ 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 (__wrap___clear_cache) (void *, void *); void EXPORT_FUNC (__aeabi_ulcmp) (void); #endif diff --git a/include/grub/symbol.h b/include/grub/symbol.h index e2119bf35..390eb62f2 100644 --- a/include/grub/symbol.h +++ b/include/grub/symbol.h @@ -29,11 +29,7 @@ #if HAVE_ASM_USCORE #ifdef ASM_FILE -# ifndef (__arm__) -# define EXT_C(sym) _ ## sym -# else -# define EXT_C(sym) % ## sym -# endif +# define EXT_C(sym) _ ## sym #else # define EXT_C(sym) "_" sym #endif From b385e0723b1613792956bf4efd70e44b46953e6a Mon Sep 17 00:00:00 2001 From: Leif Lindholm Date: Fri, 3 May 2013 15:07:39 +0200 Subject: [PATCH 13/25] Leif's API fixes --- grub-core/disk/uboot/ubootdisk.c | 123 ++++--------- grub-core/kern/arm/uboot/startup.S | 14 +- grub-core/kern/uboot/hw.c | 15 +- grub-core/kern/uboot/init.c | 29 +-- grub-core/kern/uboot/uboot.c | 241 +++++++++++-------------- grub-core/lib/uboot/reboot.c | 2 +- grub-core/net/drivers/uboot/ubootnet.c | 41 +---- grub-core/term/uboot/console.c | 8 +- include/grub/arm/linux.h | 4 +- include/grub/uboot/disk.h | 5 +- include/grub/uboot/uboot.h | 122 +++---------- 11 files changed, 217 insertions(+), 387 deletions(-) diff --git a/grub-core/disk/uboot/ubootdisk.c b/grub-core/disk/uboot/ubootdisk.c index fed649439..9b9fc6b4a 100644 --- a/grub-core/disk/uboot/ubootdisk.c +++ b/grub-core/disk/uboot/ubootdisk.c @@ -26,10 +26,11 @@ #include #include #include +#include -static struct ubootdisk_data *fd_devices; static struct ubootdisk_data *hd_devices; -static struct ubootdisk_data *cd_devices; +static int hd_num; +static int hd_max; /* * grub_ubootdisk_register(): @@ -37,73 +38,53 @@ static struct ubootdisk_data *cd_devices; * code. */ grub_err_t -grub_ubootdisk_register (struct device_info *newdev, int handle) +grub_ubootdisk_register (struct device_info *newdev) { struct ubootdisk_data *d; - enum disktype type; #define STOR_TYPE(x) ((x) & 0x0ff0) switch (STOR_TYPE (newdev->type)) { case DT_STOR_IDE: case DT_STOR_SATA: - /* hd */ - type = hd; - break; case DT_STOR_MMC: case DT_STOR_USB: - /* fd */ - type = fd; + /* 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 = (struct ubootdisk_data *) grub_malloc (sizeof (struct ubootdisk_data)); - if (!d) - return GRUB_ERR_OUT_OF_MEMORY; - d->handle = handle; + d->dev = newdev; d->cookie = newdev->cookie; d->opencount = 0; - switch (type) - { - case cd: - grub_dprintf ("ubootdisk", "registering cd device\n"); - d->next = cd_devices; - cd_devices = d; - - break; - case fd: - grub_dprintf ("ubootdisk", "registering fd device\n"); - d->next = fd_devices; - fd_devices = d; - - break; - case hd: - grub_dprintf ("ubootdisk", "registering hd device\n"); - d->next = hd_devices; - hd_devices = d; - - break; - default: - grub_free (d); - return GRUB_ERR_BAD_DEVICE; - } - return 0; } /* * uboot_disk_iterate(): - * Itarator over enumerated disk devices. + * 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) { - struct ubootdisk_data *d; char buf[16]; int count; @@ -111,7 +92,7 @@ uboot_disk_iterate (grub_disk_dev_iterate_hook_t hook, void *hook_data, { case GRUB_DISK_PULL_NONE: /* "hd" - built-in mass-storage */ - for (d = hd_devices, count = 0; d; d = d->next, count++) + for (count = 0 ; count < hd_num; count++) { grub_snprintf (buf, sizeof (buf) - 1, "hd%d", count); grub_dprintf ("ubootdisk", "iterating %s\n", buf); @@ -119,25 +100,6 @@ uboot_disk_iterate (grub_disk_dev_iterate_hook_t hook, void *hook_data, return 1; } break; - case GRUB_DISK_PULL_REMOVABLE: - /* "floppy" - removable mass storage */ - for (d = fd_devices, count = 0; d; d = d->next, count++) - { - grub_snprintf (buf, sizeof (buf) - 1, "fd%d", count); - grub_dprintf ("ubootdisk", "iterating %s\n", buf); - if (hook (buf, hook_data)) - return 1; - } - - /* "cdrom" - removeable read-only storage */ - for (d = cd_devices, count = 0; d; d = d->next, count++) - { - grub_snprintf (buf, sizeof (buf) - 1, "cd%d", count); - grub_dprintf ("ubootdisk", "iterating %s\n", buf); - if (hook (buf, hook_data)) - return 1; - } - break; default: return 0; } @@ -147,15 +109,10 @@ uboot_disk_iterate (grub_disk_dev_iterate_hook_t hook, void *hook_data, /* Helper function for uboot_disk_open. */ static struct ubootdisk_data * -get_device (struct ubootdisk_data *devices, int num) +get_hd_device (int num) { - struct ubootdisk_data *d; - - for (d = devices; d && num; d = d->next, num--) - ; - - if (num == 0) - return d; + if (num < hd_num) + return &hd_devices[num]; return NULL; } @@ -190,14 +147,8 @@ uboot_disk_open (const char *name, struct grub_disk *disk) switch (name[0]) { - case 'f': - d = get_device (fd_devices, num); - break; - case 'c': - d = get_device (cd_devices, num); - break; case 'h': - d = get_device (hd_devices, num); + d = get_hd_device (num); break; default: goto fail; @@ -219,7 +170,7 @@ uboot_disk_open (const char *name, struct grub_disk *disk) } else { - retval = uboot_dev_open (d->handle); + retval = grub_uboot_dev_open (d->dev); if (retval != 0) goto fail; d->opencount = 1; @@ -228,9 +179,7 @@ uboot_disk_open (const char *name, struct grub_disk *disk) grub_dprintf ("ubootdisk", "cookie: 0x%08x\n", (grub_addr_t) d->cookie); disk->id = (grub_addr_t) d->cookie; - /* Device has previously been enumerated, so this should never fail */ - if ((devinfo = uboot_dev_get (d->handle)) == NULL) - goto fail; + devinfo = d->dev; d->block_size = devinfo->di_stor.block_size; if (d->block_size == 0) @@ -246,7 +195,11 @@ uboot_disk_open (const char *name, struct grub_disk *disk) grub_dprintf ("ubootdisk", "(%s) blocksize=%d, log_sector_size=%d\n", disk->name, d->block_size, disk->log_sector_size); - disk->total_sectors = devinfo->di_stor.block_count ? : GRUB_DISK_SIZE_UNKNOWN; + 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; @@ -275,7 +228,7 @@ uboot_disk_close (struct grub_disk *disk) } else if (d->opencount == 1) { - retval = uboot_dev_close (d->handle); + retval = grub_uboot_dev_close (d->dev); d->opencount--; grub_dprintf ("ubootdisk", "closed %s (%d)\n", disk->name, retval); } @@ -296,12 +249,12 @@ uboot_disk_read (struct grub_disk *disk, grub_disk_addr_t offset, grub_size_t numblocks, char *buf) { struct ubootdisk_data *d; - lbasize_t real_size; + grub_size_t real_size; int retval; d = disk->data; - retval = uboot_dev_read (d->handle, buf, numblocks, offset, &real_size); + 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, @@ -318,8 +271,8 @@ uboot_disk_write (struct grub_disk *disk __attribute__ ((unused)), grub_size_t size __attribute__ ((unused)), const char *buf __attribute__ ((unused))) { - grub_dprintf ("ubootdisk", "attempt to write\n"); - return GRUB_ERR_NOT_IMPLEMENTED_YET; + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "attempt to write (not supported)"); } static struct grub_disk_dev grub_ubootdisk_dev = { diff --git a/grub-core/kern/arm/uboot/startup.S b/grub-core/kern/arm/uboot/startup.S index 9585bf959..80dd15361 100644 --- a/grub-core/kern/arm/uboot/startup.S +++ b/grub-core/kern/arm/uboot/startup.S @@ -65,9 +65,9 @@ FUNCTION(codestart) ldr sp, =entry_state push {r4-r12,lr} @ store U-Boot context (sp in r12) - ldr r12, =EXT_C(uboot_machine_type) + ldr r12, =EXT_C(grub_uboot_machine_type) str r1, [r12] - ldr r12, =EXT_C(uboot_boot_data) + ldr r12, =EXT_C(grub_uboot_boot_data) str r2, [r12] @ Modules have been stored as a blob in BSS, @@ -115,12 +115,12 @@ FUNCTION(codestart) * r12 (ip). Furthermore it needs to restore r8 for * U-Boot (Global Data Pointer) and preserve it for Grub. */ -FUNCTION(uboot_syscall) +FUNCTION(grub_uboot_syscall) ldr ip, =transition_space stm ip, {r8, lr} ldr ip, =gd_backup ldr r8, [ip] - ldr ip, =uboot_syscall_ptr + ldr ip, =grub_uboot_syscall_ptr mov lr, pc ldr pc, [ip] ldr ip, =gd_backup @@ -129,7 +129,7 @@ FUNCTION(uboot_syscall) ldm ip, {r8, lr} bx lr -FUNCTION(uboot_return) +FUNCTION(grub_uboot_return) ldr sp, =entry_state_end pop {r4-r12, lr} mov sp, r12 @@ -149,7 +149,7 @@ gd_backup: .long 0 @ r9 .long 0 @ r10 .long 0 @ r11 -VARIABLE(uboot_search_hint)@ U-Boot stack pointer - +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 @@ -159,7 +159,7 @@ transition_space: .long 0 @ r8 .long 0 @ lr -VARIABLE(uboot_syscall_ptr) +VARIABLE(grub_uboot_syscall_ptr) .long 0 @ .end diff --git a/grub-core/kern/uboot/hw.c b/grub-core/kern/uboot/hw.c index 08f8fb312..9cacb4ad2 100644 --- a/grub-core/kern/uboot/hw.c +++ b/grub-core/kern/uboot/hw.c @@ -25,6 +25,7 @@ #include #include #include +#include grub_addr_t start_of_ram; @@ -37,7 +38,7 @@ grub_addr_t start_of_ram; void grub_uboot_mm_init (void) { - struct sys_info *si = uboot_get_sys_info (); + struct sys_info *si = grub_uboot_get_sys_info (); grub_mm_init_region ((void *) (grub_modules_get_end () + GRUB_KERNEL_MACHINE_STACK_SIZE), @@ -57,19 +58,18 @@ grub_uboot_mm_init (void) /* * grub_uboot_probe_hardware(): - * */ grub_err_t grub_uboot_probe_hardware (void) { int devcount, i; - devcount = uboot_dev_enum (); + devcount = grub_uboot_dev_enum (); grub_dprintf ("init", "%d devices found\n", devcount); for (i = 0; i < devcount; i++) { - struct device_info *devinfo = uboot_dev_get (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", @@ -78,11 +78,12 @@ grub_uboot_probe_hardware (void) if (devinfo->type & DEV_TYP_STOR) { grub_dprintf ("init", " type\t\t= DISK\n"); - grub_ubootdisk_register (devinfo, i); + grub_ubootdisk_register (devinfo); } else if (devinfo->type & DEV_TYP_NET) { - grub_dprintf ("init", " type\t\t= NET\n"); + /* Dealt with in ubootnet module. */ + grub_dprintf ("init", " type\t\t= NET (not supported yet)\n"); } else { @@ -97,7 +98,7 @@ grub_err_t grub_machine_mmap_iterate (grub_memory_hook_t hook, void *hook_data) { int i; - struct sys_info *si = uboot_get_sys_info (); + struct sys_info *si = grub_uboot_get_sys_info (); if (!si || (si->mr_no < 1)) return GRUB_ERR_BUG; diff --git a/grub-core/kern/uboot/init.c b/grub-core/kern/uboot/init.c index ab4eec682..4b8c2e2ac 100644 --- a/grub-core/kern/uboot/init.c +++ b/grub-core/kern/uboot/init.c @@ -29,41 +29,42 @@ #include #include #include +#include extern char __bss_start[]; extern char _end[]; extern grub_size_t grub_total_module_size; -extern int (*uboot_syscall_ptr) (int, int *, ...); +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 uboot_machine_type = 0x55aa55aa; -grub_addr_t uboot_boot_data = 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) { - uboot_return (0); + grub_uboot_return (0); } grub_uint32_t -uboot_get_machine_type (void) +grub_uboot_get_machine_type (void) { - return uboot_machine_type; + return grub_uboot_machine_type; } grub_addr_t -uboot_get_boot_data (void) +grub_uboot_get_boot_data (void) { - return uboot_boot_data; + return grub_uboot_boot_data; } static grub_uint64_t uboot_timer_ms (void) { - return (grub_uint64_t) uboot_get_timer (timer_start) / 1000; + return (grub_uint64_t) grub_uboot_get_timer (timer_start) / 1000; } void @@ -72,7 +73,7 @@ grub_machine_init (void) int ver; /* First of all - establish connection with U-Boot */ - ver = uboot_api_init (); + ver = grub_uboot_api_init (); if (!ver) { /* Don't even have a console to log errors to... */ @@ -81,7 +82,7 @@ grub_machine_init (void) else if (ver > API_SIG_VERSION) { /* Try to print an error message */ - uboot_puts ("invalid U-Boot API version\n"); + grub_uboot_puts ("invalid U-Boot API version\n"); } /* Initialize the console so that GRUB can display messages. */ @@ -103,7 +104,7 @@ grub_machine_init (void) grub_uboot_probe_hardware (); /* Initialise timer */ - timer_start = uboot_get_timer (0); + timer_start = grub_uboot_get_timer (0); grub_install_get_time_ms (uboot_timer_ms); /* Initialize */ @@ -127,7 +128,7 @@ grub_machine_get_bootlocation (char **device, char **path) { char *tmp; - tmp = uboot_env_get ("grub_bootdev"); + tmp = grub_uboot_env_get ("grub_bootdev"); if (tmp) { *device = grub_strdup (tmp); @@ -137,7 +138,7 @@ grub_machine_get_bootlocation (char **device, char **path) else *device = NULL; - tmp = uboot_env_get ("grub_bootpath"); + tmp = grub_uboot_env_get ("grub_bootpath"); if (tmp) { *path = grub_strdup (tmp); diff --git a/grub-core/kern/uboot/uboot.c b/grub-core/kern/uboot/uboot.c index 1e78d8ad9..6800a4beb 100644 --- a/grub-core/kern/uboot/uboot.c +++ b/grub-core/kern/uboot/uboot.c @@ -18,6 +18,7 @@ #include #include +#include #include /* @@ -38,25 +39,25 @@ * returns: 0 if the call not found, 1 if serviced */ -extern int (*uboot_syscall_ptr) (int, int *, ...); -extern int uboot_syscall (int, int *, ...); -extern grub_addr_t uboot_search_hint; +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 uboot_devices[6]; +static struct device_info * devices; static int num_devices; int -uboot_api_init (void) +grub_uboot_api_init (void) { struct api_signature *start, *end; struct api_signature *p; - if (uboot_search_hint) + if (grub_uboot_search_hint) { /* Extended search range to work around Trim Slice U-Boot issue */ - start = (struct api_signature *) ((uboot_search_hint & ~0x000fffff) + start = (struct api_signature *) ((grub_uboot_search_hint & ~0x000fffff) - 0x00500000); end = (struct api_signature *) ((grub_addr_t) start + UBOOT_API_SEARCH_LEN - @@ -73,7 +74,7 @@ uboot_api_init (void) { if (grub_memcmp (&(p->magic), API_SIG_MAGIC, API_SIG_MAGLEN) == 0) { - uboot_syscall_ptr = p->syscall; + grub_uboot_syscall_ptr = p->syscall; return p->version; } } @@ -81,69 +82,50 @@ uboot_api_init (void) return 0; } -/* All functions below are wrappers around the uboot_syscall() function */ - /* - * int API_getc(int *c) + * All functions below are wrappers around the grub_uboot_syscall() function */ + int -uboot_getc (void) +grub_uboot_getc (void) { int c; - if (!uboot_syscall (API_GETC, NULL, &c)) + if (!grub_uboot_syscall (API_GETC, NULL, &c)) return -1; return c; } -/* - * int API_tstc(int *c) - */ int -uboot_tstc (void) +grub_uboot_tstc (void) { int c; - if (!uboot_syscall (API_TSTC, NULL, &c)) + if (!grub_uboot_syscall (API_TSTC, NULL, &c)) return -1; return c; } -/* - * int API_putc(char *ch) - */ void -uboot_putc (int c) +grub_uboot_putc (int c) { - uboot_syscall (API_PUTC, NULL, &c); + grub_uboot_syscall (API_PUTC, NULL, &c); } -/* - * int API_puts(const char *s) - */ void -uboot_puts (const char *s) +grub_uboot_puts (const char *s) { - uboot_syscall (API_PUTS, NULL, s); + grub_uboot_syscall (API_PUTS, NULL, s); } -/* - * int API_reset(void) - */ void -uboot_reset (void) +grub_uboot_reset (void) { - uboot_syscall (API_RESET, NULL, 0); + grub_uboot_syscall (API_RESET, NULL, 0); } -/* - * int API_get_sys_info(struct sys_info *si) - * - * fill out the sys_info struct containing selected parameters about the - * machine - */ struct sys_info * -uboot_get_sys_info (void) +grub_uboot_get_sys_info (void) { int retval; @@ -152,212 +134,193 @@ uboot_get_sys_info (void) uboot_sys_info.mr = uboot_mem_info; uboot_sys_info.mr_no = sizeof (uboot_mem_info) / sizeof (struct mem_region); - if (uboot_syscall (API_GET_SYS_INFO, &retval, &uboot_sys_info)) + if (grub_uboot_syscall (API_GET_SYS_INFO, &retval, &uboot_sys_info)) if (retval == 0) return &uboot_sys_info; return NULL; } -/* - * int API_udelay(unsigned long *udelay) - */ void -uboot_udelay (grub_uint32_t usec) +grub_uboot_udelay (grub_uint32_t usec) { - uboot_syscall (API_UDELAY, NULL, &usec); + grub_uboot_syscall (API_UDELAY, NULL, &usec); } -/* - * int API_get_timer(unsigned long *current, unsigned long *base) - */ grub_uint32_t -uboot_get_timer (grub_uint32_t base) +grub_uboot_get_timer (grub_uint32_t base) { grub_uint32_t current; - if (!uboot_syscall (API_GET_TIMER, NULL, ¤t, &base)) + if (!grub_uboot_syscall (API_GET_TIMER, NULL, ¤t, &base)) return 0; return current; } -/* - * int API_dev_enum(struct device_info *) - * - */ int -uboot_dev_enum (void) +grub_uboot_dev_enum (void) { - int max; + struct device_info * enum_devices; + int num_enum_devices, max_devices; - grub_memset (&uboot_devices, 0, sizeof (uboot_devices)); - max = sizeof (uboot_devices) / sizeof (struct device_info); + 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 prevoiusly enumerated device cookie "seeded" into the target + * the previously enumerated device cookie "seeded" into the target * structure. */ - if (!uboot_syscall (API_DEV_ENUM, NULL, &uboot_devices) - || uboot_devices[0].cookie == NULL) - return 0; - for (num_devices = 1; num_devices < max; num_devices++) + 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) { - uboot_devices[num_devices].cookie = - uboot_devices[num_devices - 1].cookie; - if (!uboot_syscall (API_DEV_ENUM, NULL, &uboot_devices[num_devices])) - return 0; + 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; + } - /* When no more devices to enumerate, target cookie set to NULL */ - if (uboot_devices[num_devices].cookie == NULL) + 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++; } - return num_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) (VALID_DEV(x) && (uboot_devices[(x)].state == DEV_STA_OPEN)) +#define OPEN_DEV(x) ((x->state == DEV_STA_OPEN)) struct device_info * -uboot_dev_get (int handle) +grub_uboot_dev_get (int index) { - if (VALID_DEV (handle)) - return &uboot_devices[handle]; + if (VALID_DEV (index)) + return &devices[index]; return NULL; } -/* - * int API_dev_open(struct device_info *) - */ int -uboot_dev_open (int handle) +grub_uboot_dev_open (struct device_info *dev) { - struct device_info *dev; int retval; - if (!VALID_DEV (handle)) - return -1; - - dev = &uboot_devices[handle]; - - if (!uboot_syscall (API_DEV_OPEN, &retval, dev)) + if (!grub_uboot_syscall (API_DEV_OPEN, &retval, dev)) return -1; return retval; } -/* - * int API_dev_close(struct device_info *) - */ int -uboot_dev_close (int handle) +grub_uboot_dev_close (struct device_info *dev) { - struct device_info *dev; int retval; - if (!VALID_DEV (handle)) - return -1; - - dev = &uboot_devices[handle]; - - if (!uboot_syscall (API_DEV_CLOSE, &retval, dev)) + if (!grub_uboot_syscall (API_DEV_CLOSE, &retval, dev)) return -1; return retval; } -/* - * int API_dev_read(struct device_info *di, void *buf, size_t *len, - * unsigned long *start, size_t *act_len) - */ int -uboot_dev_read (int handle, void *buf, lbasize_t blocks, - lbastart_t start, lbasize_t * real_blocks) +grub_uboot_dev_read (struct device_info *dev, void *buf, grub_size_t blocks, + grub_uint32_t start, grub_size_t * real_blocks) { - struct device_info *dev; int retval; - if (!OPEN_DEV (handle)) + if (!OPEN_DEV (dev)) return -1; - dev = &uboot_devices[handle]; - - if (!uboot_syscall (API_DEV_READ, &retval, dev, buf, - &blocks, &start, real_blocks)) + if (!grub_uboot_syscall (API_DEV_READ, &retval, dev, buf, + &blocks, &start, real_blocks)) return -1; return retval; } -/* - * int API_dev_read(struct device_info *di, void *buf, - * size_t *len, size_t *act_len) - */ int -uboot_dev_recv (int handle, void *buf, int size, int *real_size) +grub_uboot_dev_recv (struct device_info *dev, void *buf, + int size, int *real_size) { - struct device_info *dev; int retval; - if (!OPEN_DEV (handle)) + if (!OPEN_DEV (dev)) return -1; - dev = &uboot_devices[handle]; - if (!uboot_syscall (API_DEV_READ, &retval, dev, buf, &size, real_size)) + if (!grub_uboot_syscall (API_DEV_READ, &retval, dev, buf, &size, real_size)) return -1; return retval; } -/* - * Notice: this is for sending network packets only, as U-Boot does not - * support writing to storage at the moment (12.2007) - * - * int API_dev_write(struct device_info *di, void *buf, int *len) - */ int -uboot_dev_send (int handle, void *buf, int size) +grub_uboot_dev_send (struct device_info *dev, void *buf, int size) { - struct device_info *dev; int retval; - if (!OPEN_DEV (handle)) + if (!OPEN_DEV (dev)) return -1; - dev = &uboot_devices[handle]; - if (!uboot_syscall (API_DEV_WRITE, &retval, dev, buf, &size)) + if (!grub_uboot_syscall (API_DEV_WRITE, &retval, dev, buf, &size)) return -1; return retval; } -/* - * int API_env_get(const char *name, char **value) - */ char * -uboot_env_get (const char *name) +grub_uboot_env_get (const char *name) { char *value; - if (!uboot_syscall (API_ENV_GET, NULL, name, &value)) + if (!grub_uboot_syscall (API_ENV_GET, NULL, name, &value)) return NULL; return value; } -/* - * int API_env_set(const char *name, const char *value) - */ void -uboot_env_set (const char *name, const char *value) +grub_uboot_env_set (const char *name, const char *value) { - uboot_syscall (API_ENV_SET, NULL, name, value); + grub_uboot_syscall (API_ENV_SET, NULL, name, value); } diff --git a/grub-core/lib/uboot/reboot.c b/grub-core/lib/uboot/reboot.c index 3a9004418..e5c54d467 100644 --- a/grub-core/lib/uboot/reboot.c +++ b/grub-core/lib/uboot/reboot.c @@ -25,6 +25,6 @@ grub_reboot (void) { grub_machine_fini (); - uboot_reset (); + grub_uboot_reset (); while (1); } diff --git a/grub-core/net/drivers/uboot/ubootnet.c b/grub-core/net/drivers/uboot/ubootnet.c index 2b743f445..056052e40 100644 --- a/grub-core/net/drivers/uboot/ubootnet.c +++ b/grub-core/net/drivers/uboot/ubootnet.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -26,19 +27,12 @@ GRUB_MOD_LICENSE ("GPLv3+"); -struct ubootnet_data -{ - void *cookie; - int handle; -}; - static grub_err_t card_open (struct grub_net_card *dev) { int status; - struct ubootnet_data *data = dev->data; - status = uboot_dev_open (data->handle); + status = grub_uboot_dev_open (dev->data); if (status) return grub_error (GRUB_ERR_IO, "Couldn't open network card."); @@ -48,16 +42,13 @@ card_open (struct grub_net_card *dev) static void card_close (struct grub_net_card *dev) { - struct ubootnet_data *data = dev->data; - - uboot_dev_close (data->handle); + 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; - struct ubootnet_data *data = dev->data; grub_size_t len; len = (pack->tail - pack->data); @@ -65,8 +56,7 @@ send_card_buffer (struct grub_net_card *dev, struct grub_net_buff *pack) len = dev->mtu; grub_memcpy (dev->txbuf, pack->data, len); - status = uboot_dev_send (data->handle, dev->txbuf, - 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")); @@ -77,7 +67,6 @@ static struct grub_net_buff * get_card_packet (struct grub_net_card *dev) { int rc; - struct ubootnet_data *data = dev->data; grub_uint64_t start_time; struct grub_net_buff *nb; int actual; @@ -92,7 +81,7 @@ get_card_packet (struct grub_net_card *dev) start_time = grub_get_time_ms (); do { - rc = uboot_dev_recv (data->handle, nb->data, dev->mtu + 64, &actual); + 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); } @@ -120,34 +109,23 @@ GRUB_MOD_INIT (ubootnet) int devcount, i; int nfound = 0; - devcount = uboot_dev_enum (); + devcount = grub_uboot_dev_enum (); for (i = 0; i < devcount; i++) { - struct device_info *devinfo = uboot_dev_get (i); - struct ubootnet_data *ubdata; + struct device_info *devinfo = grub_uboot_dev_get (i); struct grub_net_card *card; if (!(devinfo->type & DEV_TYP_NET)) continue; - - ubdata = grub_malloc (sizeof (struct ubootnet_data)); - if (!ubdata) - { - grub_print_error (); - return; - } + card = grub_zalloc (sizeof (struct grub_net_card)); if (!card) { - grub_free (ubdata); grub_print_error (); return; } - ubdata->handle = i; - ubdata->cookie = devinfo->cookie; - /* FIXME: Any way to check this? */ card->mtu = 1500; @@ -158,13 +136,12 @@ GRUB_MOD_INIT (ubootnet) card->txbuf = grub_zalloc (card->txbufsize); if (!card->txbuf) { - grub_free (ubdata); grub_free (card); grub_print_error (); continue; } - card->data = ubdata; + card->data = devinfo; card->flags = 0; card->name = grub_xasprintf ("ubnet_%d", ++nfound); card->idle_poll_delay_ms = 10; diff --git a/grub-core/term/uboot/console.c b/grub-core/term/uboot/console.c index e351e6193..51defee6e 100644 --- a/grub-core/term/uboot/console.c +++ b/grub-core/term/uboot/console.c @@ -28,14 +28,14 @@ static void put (struct grub_term_output *term __attribute__ ((unused)), const int c) { - uboot_putc (c); + grub_uboot_putc (c); } static int readkey (struct grub_term_input *term __attribute__ ((unused))) { - if (uboot_tstc () > 0) - return uboot_getc (); + if (grub_uboot_tstc () > 0) + return grub_uboot_getc (); return -1; } @@ -127,7 +127,7 @@ grub_console_init_lately (void) const char *type; /* See if explicitly set by U-Boot environment */ - type = uboot_env_get ("grub_term"); + type = grub_uboot_env_get ("grub_term"); if (!type) type = "vt100"; diff --git a/include/grub/arm/linux.h b/include/grub/arm/linux.h index 33e6c4b84..1f62d76ac 100644 --- a/include/grub/arm/linux.h +++ b/include/grub/arm/linux.h @@ -30,8 +30,8 @@ # 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 uboot_get_boot_data -# define firmware_get_machine_type uboot_get_machine_type +# 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 # include diff --git a/include/grub/uboot/disk.h b/include/grub/uboot/disk.h index b93665fea..e380b4c89 100644 --- a/include/grub/uboot/disk.h +++ b/include/grub/uboot/disk.h @@ -31,14 +31,13 @@ enum disktype struct ubootdisk_data { - struct ubootdisk_data *next; void *cookie; - int handle; + struct device_info *dev; int opencount; enum disktype type; grub_uint32_t block_size; }; -grub_err_t grub_ubootdisk_register (struct device_info *newdev, int handle); +grub_err_t grub_ubootdisk_register (struct device_info *newdev); #endif /* ! GRUB_UBOOT_DISK_HEADER */ diff --git a/include/grub/uboot/uboot.h b/include/grub/uboot/uboot.h index c9fb86771..c122de6ab 100644 --- a/include/grub/uboot/uboot.h +++ b/include/grub/uboot/uboot.h @@ -28,16 +28,16 @@ void grub_uboot_mm_init (void); void grub_uboot_init (void); void grub_uboot_fini (void); -void uboot_return (int) __attribute__ ((noreturn)); +void grub_uboot_return (int) __attribute__ ((noreturn)); -grub_addr_t uboot_get_real_bss_start (void); +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 (uboot_get_machine_type) (void); -grub_addr_t EXPORT_FUNC (uboot_get_boot_data) (void); +grub_uint32_t EXPORT_FUNC (grub_uboot_get_machine_type) (void); +grub_addr_t EXPORT_FUNC (grub_uboot_get_boot_data) (void); /* @@ -47,104 +47,40 @@ grub_addr_t EXPORT_FUNC (uboot_get_boot_data) (void); * We scan through a defined region around the hint address passed to us * from U-Boot. */ -#include #define UBOOT_API_SEARCH_LEN (3 * 1024 * 1024) -int uboot_api_init (void); - -/* All functions below are wrappers around the uboot_syscall() function */ +int grub_uboot_api_init (void); /* - * int API_getc(int *c) - */ -int uboot_getc (void); + * All functions below are wrappers around the uboot_syscall() function, + * implemented in grub-core/kern/uboot/uboot.c +*/ -/* - * int API_tstc(int *c) - */ -int uboot_tstc (void); +int grub_uboot_getc (void); +int grub_uboot_tstc (void); +void grub_uboot_putc (int c); +void grub_uboot_puts (const char *s); -/* - * int API_putc(char *ch) - */ -void uboot_putc (int c); +void EXPORT_FUNC (grub_uboot_reset) (void); -/* - * int API_puts(const char *s) - */ -void uboot_puts (const char *s); +struct sys_info *grub_uboot_get_sys_info (void); -/* - * int API_reset(void) - */ -void EXPORT_FUNC (uboot_reset) (void); +void grub_uboot_udelay (grub_uint32_t usec); +grub_uint32_t grub_uboot_get_timer (grub_uint32_t base); -/* - * int API_get_sys_info(struct sys_info *si) - * - * fill out the sys_info struct containing selected parameters about the - * machine - */ -struct sys_info *uboot_get_sys_info (void); +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); -/* - * int API_udelay(unsigned long *udelay) - */ -void uboot_udelay (grub_uint32_t usec); - -/* - * int API_get_timer(unsigned long *current, unsigned long *base) - */ -grub_uint32_t uboot_get_timer (grub_uint32_t base); - -/* - * int API_dev_enum(struct device_info *) - */ -int EXPORT_FUNC(uboot_dev_enum) (void); - -struct device_info *EXPORT_FUNC(uboot_dev_get) (int handle); - -/* - * int API_dev_open(struct device_info *) - */ -int EXPORT_FUNC(uboot_dev_open) (int handle); - -/* - * int API_dev_close(struct device_info *) - */ -int EXPORT_FUNC(uboot_dev_close) (int handle); - -/* - * Notice: this is for sending network packets only, as U-Boot does not - * support writing to storage at the moment (12.2007) - * - * int API_dev_write(struct device_info *di, void *buf, int *len) - */ -int uboot_dev_write (int handle, void *buf, int *len); - -/* - * int API_dev_read( - * struct device_info *di, - * void *buf, - * size_t *len, - * unsigned long *start - * size_t *act_len - * ) - */ -int uboot_dev_read (int handle, void *buf, lbasize_t blocks, - lbastart_t start, lbasize_t * real_blocks); - -int EXPORT_FUNC(uboot_dev_recv) (int handle, void *buf, int size, int *real_size); -int EXPORT_FUNC(uboot_dev_send) (int handle, void *buf, int size); - -/* - * int API_env_get(const char *name, char **value) - */ -char *uboot_env_get (const char *name); - -/* - * int API_env_set(const char *name, const char *value) - */ -void uboot_env_set (const char *name, const char *value); +char *grub_uboot_env_get (const char *name); +void grub_uboot_env_set (const char *name, const char *value); #endif /* ! GRUB_UBOOT_UBOOT_HEADER */ From 854f383c288358be4c3f587ffdb136bf63027644 Mon Sep 17 00:00:00 2001 From: Leif Lindholm Date: Sat, 11 May 2013 10:42:11 +0200 Subject: [PATCH 14/25] Move common function to dl_helper.c --- Makefile.util.def | 2 +- grub-core/Makefile.core.def | 1 + grub-core/kern/arm/dl.c | 284 +-------------------------------- grub-core/kern/arm/dl_helper.c | 222 ++++++++++++++++++++++++++ include/grub/arm/reloc.h | 1 + util/grub-mkimagexx.c | 14 +- 6 files changed, 235 insertions(+), 289 deletions(-) create mode 100644 grub-core/kern/arm/dl_helper.c diff --git a/Makefile.util.def b/Makefile.util.def index 2194f0df4..a88aaeaa5 100644 --- a/Makefile.util.def +++ b/Makefile.util.def @@ -163,7 +163,7 @@ program = { common = util/resolve.c; common = grub-core/kern/emu/argp_common.c; - common = grub-core/kern/arm/dl.c; + common = grub-core/kern/arm/dl_helper.c; extra_dist = util/grub-mkimagexx.c; diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index a7a0b9f36..b444042b3 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -226,6 +226,7 @@ kernel = { sparc64_ieee1275 = kern/sparc64/ieee1275/ieee1275.c; arm = kern/arm/dl.c; + arm = kern/arm/dl_helper.c; arm = kern/arm/cache.S; arm = kern/arm/misc.S; diff --git a/grub-core/kern/arm/dl.c b/grub-core/kern/arm/dl.c index 74e6b96b5..4d7f34b2b 100644 --- a/grub-core/kern/arm/dl.c +++ b/grub-core/kern/arm/dl.c @@ -25,272 +25,9 @@ #include #include -#ifdef GRUB_UTIL -# include -#else - -#ifdef DL_DEBUG -static const char *symstrtab; - -/* - * This is a bit of a hack, setting the symstrtab pointer to the last STRTAB - * section in the module (which is where symbol names are in the objects I've - * inspected manually). - */ -static void -set_symstrtab (Elf_Ehdr * e) -{ - int i; - Elf_Shdr *s; - - symstrtab = NULL; - - for (i = 0, s = (Elf_Shdr *) ((grub_uint32_t) e + e->e_shoff); - i < e->e_shnum; - i++, s = (Elf_Shdr *) ((grub_uint32_t) s + e->e_shentsize)) - if (s->sh_type == SHT_STRTAB) - symstrtab = (void *) ((grub_addr_t) e + s->sh_offset); -} - -static const char * -get_symbolname (Elf_Sym * sym) -{ - const char *symbolname = symstrtab + sym->st_name; - - return (*symbolname ? symbolname : NULL); -} -#endif /* DL_DEBUG */ - -/* - * R_ARM_ABS32 - * - * Simple relocation of 32-bit value (in literal pool) - */ -static grub_err_t -reloc_abs32 (Elf_Word *target, Elf_Addr sym_addr) -{ - Elf_Addr tmp; - - tmp = *target; - tmp += sym_addr; - *target = tmp; -#if 0 //def GRUB_UTIL - grub_util_info (" %s: reloc_abs32 0x%08x => 0x%08x", __FUNCTION__, - (unsigned int) sym_addr, (unsigned int) tmp); -#endif - - return GRUB_ERR_NONE; -} -#endif /* ndef GRUB_UTIL */ - - -/******************************************************************** - * 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 = (*target << 16) | (*(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_BUG, - 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); -#ifdef GRUB_UTIL - grub_util_info (" sym_addr = 0x%08x", sym_addr); -#endif -#ifdef GRUB_UTIL - offset += sym_addr; -#else - offset += sym_addr - (grub_uint32_t) target; -#endif -#ifdef DEBUG - grub_printf(" %s: target=0x%08x, sym_addr=0x%08x, offset=%d\n", - is_blx ? "BLX" : "BL", (unsigned int) target, sym_addr, offset); -#endif - - if ((offset < offset_low) || (offset > offset_high)) - return grub_error (GRUB_ERR_OUT_OF_RANGE, - N_("THM_CALL Relocation out of range.")); - -#ifdef GRUB_UTIL - grub_util_info (" relative destination = 0x%08lx", - (unsigned long)target + offset); -#endif - - /* 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 = (insword >> 16) & 0xffff; - *(target + 1) = insword & 0xffff; - -#ifdef GRUB_UTIL -#pragma GCC diagnostic ignored "-Wcast-align" - grub_util_info (" *target = 0x%08x", *((unsigned int *)target)); -#endif - - return GRUB_ERR_NONE; -} - -/* - * R_ARM_THM_JUMP19 - * - * Relocate conditional Thumb (T32) B.W - */ -grub_err_t -grub_arm_reloc_thm_jump19 (grub_uint16_t *addr, Elf32_Addr sym_addr) -{ - grub_int32_t offset; - grub_uint32_t insword, insmask; - - /* Extract instruction word in alignment-safe manner */ - insword = (*addr) << 16 | *(addr + 1); - insmask = 0xfbc0d800; - - /* Extract and sign extend offset */ - offset = ((insword >> 26) & 1) << 18 - | ((insword >> 11) & 1) << 17 - | ((insword >> 13) & 1) << 16 - | ((insword >> 16) & 0x3f) << 11 - | (insword & 0x7ff); - offset <<= 1; - if (offset & (1 << 19)) - offset -= (1 << 20); - - /* Adjust and re-truncate offset */ -#ifdef GRUB_UTIL - offset += sym_addr; -#else - offset += sym_addr - (grub_uint32_t) addr; -#endif - if ((offset > 1048574) || (offset < -1048576)) - { - return grub_error - (GRUB_ERR_OUT_OF_RANGE, N_("THM_JUMP19 Relocation out of range.")); - } - - offset >>= 1; - offset &= 0x7ffff; - - /* Reassemble instruction word and write back */ - insword &= insmask; - insword |= ((offset >> 18) & 1) << 26 - | ((offset >> 17) & 1) << 11 - | ((offset >> 16) & 1) << 13 - | ((offset >> 11) & 0x3f) << 16 - | (offset & 0x7ff); - *addr = insword >> 16; - *(addr + 1) = 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 *addr, Elf32_Addr sym_addr) -{ - grub_uint32_t insword; - grub_int32_t offset; - - insword = *addr; - - offset = (insword & 0x00ffffff) << 2; - if (offset & 0x02000000) - offset -= 0x04000000; -#ifdef GRUB_UTIL - offset += sym_addr; -#else - offset += sym_addr - (grub_uint32_t) addr; -#endif - - insword &= 0xff000000; - insword |= (offset >> 2) & 0x00ffffff; - - *addr = insword; - - return GRUB_ERR_NONE; -} - - - /************************************************* * Runtime dynamic linker with helper functions. * *************************************************/ -#ifndef GRUB_UTIL -/* - * find_segment(): finds a module segment matching sh_info - */ -static grub_dl_segment_t -find_segment (grub_dl_segment_t seg, Elf32_Word sh_info) -{ - for (; seg; seg = seg->next) - if (seg->section == sh_info) - return seg; - - return NULL; -} - - -/* - * do_relocations(): - * Iterate over all relocations in section, calling appropriate functions - * for patching. - */ static grub_err_t do_relocations (Elf_Shdr * relhdr, Elf_Ehdr * e, grub_dl_t mod) { @@ -302,7 +39,9 @@ do_relocations (Elf_Shdr * relhdr, Elf_Ehdr * e, grub_dl_t mod) entnum = relhdr->sh_size / sizeof (Elf_Rel); /* Find the target segment for this relocation section. */ - seg = find_segment (mod->segment, relhdr->sh_info); + 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")); @@ -320,22 +59,16 @@ do_relocations (Elf_Shdr * relhdr, Elf_Ehdr * e, grub_dl_t mod) "reloc offset is out of the segment"); relsym = ELF_R_SYM (rel[i].r_info); reltype = ELF_R_TYPE (rel[i].r_info); - target = (Elf_Word *) ((grub_addr_t) seg->addr + rel[i].r_offset); + target = (void *) ((grub_addr_t) seg->addr + rel[i].r_offset); sym_addr = sym[relsym].st_value; -#ifdef DL_DEBUG - - grub_printf ("%s: 0x%08x -> %s @ 0x%08x\n", __FUNCTION__, - (grub_addr_t) sym_addr, get_symbolname (sym), sym->st_value); -#endif - switch (reltype) { case R_ARM_ABS32: { /* Data will be naturally aligned */ - retval = reloc_abs32 (target, sym_addr); + retval = grub_arm_reloc_abs32 (target, sym_addr); if (retval != GRUB_ERR_NONE) return retval; } @@ -427,10 +160,6 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr) if (!has_symtab (e)) return grub_error (GRUB_ERR_BAD_MODULE, N_("no symbol table")); -#ifdef DL_DEBUG - set_symstrtab (e); -#endif - #define FIRST_SHDR(x) ((Elf_Shdr *) ((grub_addr_t)(x) + (x)->e_shoff)) #define NEXT_SHDR(x, y) ((Elf_Shdr *) ((grub_addr_t)(y) + (x)->e_shentsize)) @@ -458,7 +187,7 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr) case SHT_RELA: default: { - grub_printf ("unhandled section_type: %d (0x%08x)\n", + grub_dprintf ("dl", "unhandled section_type: %d (0x%08x)\n", s->sh_type, s->sh_type); return GRUB_ERR_NOT_IMPLEMENTED_YET; }; @@ -470,4 +199,3 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr) return GRUB_ERR_NONE; } -#endif /* ndef GRUB_UTIL */ diff --git a/grub-core/kern/arm/dl_helper.c b/grub-core/kern/arm/dl_helper.c new file mode 100644 index 000000000..951019b58 --- /dev/null +++ b/grub-core/kern/arm/dl_helper.c @@ -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 . + */ + +#include +#include +#include +#include +#include +#include +#include + +/* + * 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.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; +} diff --git a/include/grub/arm/reloc.h b/include/grub/arm/reloc.h index b47792d95..50d070f01 100644 --- a/include/grub/arm/reloc.h +++ b/include/grub/arm/reloc.h @@ -19,6 +19,7 @@ #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); diff --git a/util/grub-mkimagexx.c b/util/grub-mkimagexx.c index f72c8972a..0f4464084 100644 --- a/util/grub-mkimagexx.c +++ b/util/grub-mkimagexx.c @@ -422,7 +422,6 @@ SUFFIX (relocate_addresses) (Elf_Ehdr *e, Elf_Shdr *sections, grub_util_info (" ABS32:\toffset=%d\t(0x%08x)", (int) sym_addr, (int) sym_addr); /* Data will be naturally aligned */ - // sym_addr -= offset; sym_addr += 0x400; *target = grub_host_to_target32 (grub_target_to_host32 (*target) + sym_addr); } @@ -446,9 +445,9 @@ SUFFIX (relocate_addresses) (Elf_Ehdr *e, Elf_Shdr *sections, 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); + err = grub_arm_reloc_thm_jump19 ((grub_uint16_t *) target, sym_addr); if (err) grub_util_error ("%s", grub_errmsg); } @@ -705,15 +704,10 @@ SUFFIX (make_reloc_section) (Elf_Ehdr *e, void **out, break; /* Create fixup entry for PE/COFF loader */ case R_ARM_ABS32: - { + { Elf_Addr addr; addr = section_address + offset; -#if 0 - grub_util_info (" %s: add_fixup: 0x%08x : 0x%08x", - __FUNCTION__, (unsigned int) addr, - (unsigned int) current_address); -#endif current_address = SUFFIX (add_fixup_entry) (&lst, GRUB_PE32_REL_BASED_HIGHLOW, @@ -722,7 +716,7 @@ SUFFIX (make_reloc_section) (Elf_Ehdr *e, void **out, } break; default: - grub_util_error (_("relocation 0x%x is not implemented yet2"), ELF_R_TYPE (info)); + grub_util_error (_("fixup for relocation 0x%x not implemented"), ELF_R_TYPE (info)); break; } break; From 1a53e1dd5c3d233f3ec0c05710ec086c23ed48f3 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sat, 11 May 2013 10:43:22 +0200 Subject: [PATCH 15/25] Add missing setjmp.h --- include/grub/arm/setjmp.h | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 include/grub/arm/setjmp.h diff --git a/include/grub/arm/setjmp.h b/include/grub/arm/setjmp.h new file mode 100644 index 000000000..1c1d0b54e --- /dev/null +++ b/include/grub/arm/setjmp.h @@ -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 . + */ + +#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 */ From 141430a295cf93d4c5d7e3839f1a0a38986c61a5 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Thu, 16 May 2013 16:17:05 +0200 Subject: [PATCH 16/25] * grub-core/lib/dtc/libfdt-grub.diff: Remove extraneous uintptr_t declaration. --- ChangeLog | 5 +++++ grub-core/lib/dtc/libfdt-grub.diff | 3 +-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 0dedc844b..489088db0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2013-05-16 Vladimir Serbinenko + + * grub-core/lib/dtc/libfdt-grub.diff: Remove extraneous uintptr_t + declaration. + 2013-05-11 Vladimir Serbinenko * grub-core/tests/setjmp_test.c: Ignore missing noreturn. diff --git a/grub-core/lib/dtc/libfdt-grub.diff b/grub-core/lib/dtc/libfdt-grub.diff index 173619d0d..e5164a2c8 100644 --- a/grub-core/lib/dtc/libfdt-grub.diff +++ b/grub-core/lib/dtc/libfdt-grub.diff @@ -17,13 +17,12 @@ diff -purN libfdt.orig/fdt_rw.c libfdt/fdt_rw.c diff -purN libfdt.orig/libfdt_env.h libfdt/libfdt_env.h --- libfdt.orig/libfdt_env.h 2011-05-08 20:45:39.000000000 +0100 +++ libfdt/libfdt_env.h 2012-10-19 16:13:19.051344173 +0100 -@@ -7,6 +7,9 @@ +@@ -7,6 +7,8 @@ #include #include #include +#pragma GCC diagnostic ignored "-Wcast-align" +#pragma GCC diagnostic ignored "-Wsign-compare" -+typedef grub_addr_t uintptr_t; #define _B(n) ((unsigned long long)((uint8_t *)&x)[n]) static inline uint32_t From 5bac5d9ad6002ff1d19660280f70dc0f1757ae4e Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Thu, 16 May 2013 16:18:37 +0200 Subject: [PATCH 17/25] * grub-core/partmap/dfly.c: New partition map. --- ChangeLog | 4 ++++ grub-core/kern/arm/uboot/startup.S | 29 ++++++++++++++--------------- grub-core/kern/uboot/hw.c | 3 +-- 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/ChangeLog b/ChangeLog index 489088db0..bb06a93f5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2013-05-16 Vladimir Serbinenko + + * grub-core/kern/arm/uboot/startup.S: Move stack before modules. + 2013-05-16 Vladimir Serbinenko * grub-core/lib/dtc/libfdt-grub.diff: Remove extraneous uintptr_t diff --git a/grub-core/kern/arm/uboot/startup.S b/grub-core/kern/arm/uboot/startup.S index 80dd15361..3e3869867 100644 --- a/grub-core/kern/arm/uboot/startup.S +++ b/grub-core/kern/arm/uboot/startup.S @@ -39,11 +39,9 @@ * Also where global/static variables are located. * _end: * End of bss region (but not necessarily module blob). - * : - * Any part of the module blob that extends beyond _end. + * : * : * Loadable modules, post relocation. - * : * : */ @@ -71,8 +69,7 @@ FUNCTION(codestart) str r2, [r12] @ Modules have been stored as a blob in BSS, - @ they need to be manually relocated to _end or - @ (__bss_start + grub_total_module_size), whichever greater. + @ 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) @@ -80,22 +77,24 @@ FUNCTION(codestart) ldr r1, =EXT_C(_end) @ dst = End of BSS ldr r2, grub_total_module_size @ blob size - add r3, r0, r2 @ blob end - cmp r1, r3 @ _end < blob end? - movlt r1, r3 @ dst = blob end + blob size + + 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] -1: ldr r3, [r0], #4 @ r3 = *src++ - str r3, [r1], #4 @ *dst++ = r3 + 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 - - @ Set up a new stack, beyond the end of copied modules. - ldr r3, =GRUB_KERNEL_MACHINE_STACK_SIZE - add r3, r1, r3 @ Place stack beyond end of modules - and sp, r3, #~0x7 @ Ensure 8-byte alignment @ Since we _are_ the C run-time, we need to manually zero the BSS @ region before continuing diff --git a/grub-core/kern/uboot/hw.c b/grub-core/kern/uboot/hw.c index 9cacb4ad2..272b83bd7 100644 --- a/grub-core/kern/uboot/hw.c +++ b/grub-core/kern/uboot/hw.c @@ -40,8 +40,7 @@ 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_STACK_SIZE), + grub_mm_init_region ((void *) grub_modules_get_end (), GRUB_KERNEL_MACHINE_HEAP_SIZE); if (si && (si->mr_no != 0)) From 72a21cf09b07f26fdeb82b55ecf199bfbb545f26 Mon Sep 17 00:00:00 2001 From: Leif Lindholm Date: Thu, 16 May 2013 16:23:31 +0200 Subject: [PATCH 18/25] Leif's ARMv6 cache support --- grub-core/kern/arm/cache.S | 55 +++++++++++++++++++++++++------------- 1 file changed, 37 insertions(+), 18 deletions(-) diff --git a/grub-core/kern/arm/cache.S b/grub-core/kern/arm/cache.S index dc1b63aea..15d7b14e6 100644 --- a/grub-core/kern/arm/cache.S +++ b/grub-core/kern/arm/cache.S @@ -51,7 +51,11 @@ clean_dcache_range: and r0, r0, r3 1: cmp r0, r1 bge 2f +#if (__ARM_ARCH_6__ == 1) + 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 @@ -77,37 +81,47 @@ invalidate_icache_range: bx lr sync_caches: - DMB DSB - push {r4-r6, lr} + push {r0-r1, r4-r6, lr} ldr r2, probed @ If first call, probe cache sizes cmp r2, #0 - bleq probe_caches @ This call corrupts r3 - mov r4, r0 - mov r5, r1 + bleq probe_caches + ldrdeq r0, r1, [sp] bl clean_dcache_range - mov r0, r4 - mov r1, r5 + pop {r0, r1} bl invalidate_icache_range pop {r4-r6, pc} probe_caches: push {r4-r6, lr} - mrc p15, 0, r4, c0, c0, 1 @ Read Cache Type Register - mov r5, #1 - lsr r6, r4, #16 @ Extract min D-cache num word log2 - and r6, r6, #0xf - add r6, r6, #2 @ words->bytes - lsl r6, r5, r6 @ Convert to num bytes + mrc p15, 0, r0, c0, c0, 1 @ Read Cache Type Register + mov r1, #1 +@ Cache Type Register format changed in ARMv7 +@ r5 - dlinesz +@ r6 - ilinesz +#if (__ARM_ARCH_6__ == 1) + lsl r2, r0, #12 + and r2, r2, #3 @ Dsize 'len' + lsl r2, r1, r2 @ Convert to num 8-byte blocks + lsl r5, r2, #3 @ Convert to num bytes + and r2, r0, #3 @ Isize 'len' + lsl r2, r1, r2 @ Convert to num 8-byte blocks + lsl r6, r2, #3 @ Convert to num bytes +#else + lsr r2, r0, #16 @ Extract min D-cache num word log2 + and r2, r2, #0xf + add r2, r2, #2 @ words->bytes + lsl r5, r1, r2 @ Convert to num bytes + and r2, r0, #0xf @ Extract min I-cache num word log2 + add r2, r2, #2 @ words->bytes + lsl r6, r1, r2 @ Convert to num bytes +#endif ldr r3, =dlinesz - str r6, [r3] - and r6, r4, #0xf @ Extract min I-cache num word log2 - add r6, r6, #2 @ words->bytes - lsl r6, r5, r6 @ Convert to num bytes + str r5, [r3] ldr r3, =ilinesz str r6, [r3] ldr r3, =probed @ Flag cache probing done - str r5, [r3] + str r1, [r3] pop {r4-r6, pc} .align 3 @@ -135,6 +149,10 @@ FUNCTION(grub_arch_sync_caches) @ r10 - scratch @ r11 - scratch clean_invalidate_dcache: +#if (__ARM_ARCH_6__ == 1) + mcr p15, 0, r0, c7, c14, 0 @ Clean/Invalidate D-cache + bx lr +#elif (__ARM_ARCH_7A__ == 1) push {r4-r12, lr} mrc p15, 1, r0, c0, c0, 1 @ Read CLIDR lsr r1, r0, #24 @ Extract LoC @@ -204,6 +222,7 @@ clean_invalidate_dcache: 6: DSB ISB pop {r4-r12, pc} +#endif FUNCTION(grub_arm_disable_caches_mmu) push {r4, lr} From c59fe1d776ccf21c3ad9936378b750b4959bbb73 Mon Sep 17 00:00:00 2001 From: Leif Lindholm Date: Thu, 16 May 2013 16:30:41 +0200 Subject: [PATCH 19/25] Leif's BSS fix --- grub-core/kern/arm/uboot/startup.S | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/grub-core/kern/arm/uboot/startup.S b/grub-core/kern/arm/uboot/startup.S index 3e3869867..256613674 100644 --- a/grub-core/kern/arm/uboot/startup.S +++ b/grub-core/kern/arm/uboot/startup.S @@ -99,8 +99,13 @@ FUNCTION(codestart) @ 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 - ldr r1, =EXT_C(_end) @ to 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 From 390df92f0b4bc356323c276562d7e4cc1735a8bc Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Fri, 17 May 2013 01:33:22 +0200 Subject: [PATCH 20/25] Detect cache type on runtime rather than compile time --- grub-core/Makefile.core.def | 4 +- grub-core/kern/arm/cache.S | 161 +++---------------------------- grub-core/kern/arm/cache.c | 72 ++++++++++++++ grub-core/kern/arm/cache_armv6.S | 35 +++++++ grub-core/kern/arm/cache_armv7.S | 114 ++++++++++++++++++++++ 5 files changed, 238 insertions(+), 148 deletions(-) create mode 100644 grub-core/kern/arm/cache.c create mode 100644 grub-core/kern/arm/cache_armv6.S create mode 100644 grub-core/kern/arm/cache_armv7.S diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index b444042b3..d01667d8b 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -227,7 +227,9 @@ kernel = { arm = kern/arm/dl.c; arm = kern/arm/dl_helper.c; - arm = kern/arm/cache.S; + 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; diff --git a/grub-core/kern/arm/cache.S b/grub-core/kern/arm/cache.S index 15d7b14e6..cd28dd908 100644 --- a/grub-core/kern/arm/cache.S +++ b/grub-core/kern/arm/cache.S @@ -22,16 +22,7 @@ .text .syntax unified .arm -#if (__ARM_ARCH_6__ == 1) - .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 -#elif (__ARM_ARCH_7A__ == 1) -# define DMB dmb -# define DSB dsb -# define ISB isb -#else +#if !defined (ARMV6) && !defined (ARMV7) # error Unsupported architecture version! #endif @@ -45,13 +36,13 @@ @ r1 - *end (exclusive) clean_dcache_range: @ Clean data cache for range to point-of-unification - ldr r2, dlinesz + 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 -#if (__ARM_ARCH_6__ == 1) +#ifdef ARMV6 mcr p15, 0, r0, c7, c10, 1 @ Clean data cache line by MVA #else mcr p15, 0, r0, c7, c11, 1 @ DCCMVAU @@ -65,7 +56,7 @@ clean_dcache_range: @ r1 - *end (exclusive) invalidate_icache_range: @ Invalidate instruction cache for range to point-of-unification - ldr r2, ilinesz + 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 @@ -80,151 +71,27 @@ invalidate_icache_range: ISB bx lr -sync_caches: +@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} - ldr r2, probed @ If first call, probe cache sizes - cmp r2, #0 - bleq probe_caches ldrdeq r0, r1, [sp] bl clean_dcache_range pop {r0, r1} bl invalidate_icache_range pop {r4-r6, pc} -probe_caches: - push {r4-r6, lr} - mrc p15, 0, r0, c0, c0, 1 @ Read Cache Type Register - mov r1, #1 -@ Cache Type Register format changed in ARMv7 -@ r5 - dlinesz -@ r6 - ilinesz -#if (__ARM_ARCH_6__ == 1) - lsl r2, r0, #12 - and r2, r2, #3 @ Dsize 'len' - lsl r2, r1, r2 @ Convert to num 8-byte blocks - lsl r5, r2, #3 @ Convert to num bytes - and r2, r0, #3 @ Isize 'len' - lsl r2, r1, r2 @ Convert to num 8-byte blocks - lsl r6, r2, #3 @ Convert to num bytes +#ifdef ARMV6 +FUNCTION(grub_arm_disable_caches_mmu_armv6) #else - lsr r2, r0, #16 @ Extract min D-cache num word log2 - and r2, r2, #0xf - add r2, r2, #2 @ words->bytes - lsl r5, r1, r2 @ Convert to num bytes - and r2, r0, #0xf @ Extract min I-cache num word log2 - add r2, r2, #2 @ words->bytes - lsl r6, r1, r2 @ Convert to num bytes -#endif - ldr r3, =dlinesz - str r5, [r3] - ldr r3, =ilinesz - str r6, [r3] - ldr r3, =probed @ Flag cache probing done - str r1, [r3] - pop {r4-r6, pc} - - .align 3 -probed: .long 0 -dlinesz: - .long 0 -ilinesz: - .long 0 - -@void grub_arch_sync_caches (void *address, grub_size_t len) -FUNCTION(grub_arch_sync_caches) - add r1, r0, r1 - b sync_caches - - @ 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: -#if (__ARM_ARCH_6__ == 1) - mcr p15, 0, r0, c7, c14, 0 @ Clean/Invalidate D-cache - bx lr -#elif (__ARM_ARCH_7A__ == 1) - 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} +FUNCTION(grub_arm_disable_caches_mmu_armv7) #endif -FUNCTION(grub_arm_disable_caches_mmu) push {r4, lr} @ disable D-cache diff --git a/grub-core/kern/arm/cache.c b/grub-core/kern/arm/cache.c new file mode 100644 index 000000000..4849d2400 --- /dev/null +++ b/grub-core/kern/arm/cache.c @@ -0,0 +1,72 @@ +#include +#include +#include + +static enum + { + ARCH_UNKNOWN, + ARCH_ARMV6, + 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 Cache Type Register */ + asm volatile ("mrc p15, 0, %0, c0, c0, 0": "=r"(main_id)); + + if (((main_id >> 12) & 0xf) == 0x0 || ((main_id >> 12) & 0xf) == 0x7 + || (((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 >> 29) + { + case 0: + grub_arch_cache_dlinesz = 8 << ((cache_type >> 12) & 3); + grub_arch_cache_ilinesz = 8 << (cache_type & 3); + type = ARCH_ARMV6; + break; + case 4: + grub_arch_cache_dlinesz = 4 << ((cache_type >> 16) & 0xf); + grub_arch_cache_ilinesz = 4 << (cache_type & 0xf); + type = ARCH_ARMV7; + 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 (); + if (type == ARCH_ARMV6) + grub_arch_sync_caches_armv6 (address, len); + if (type == ARCH_ARMV7) + grub_arch_sync_caches_armv7 (address, len); +} + +void +grub_arm_disable_caches_mmu (void) +{ + if (type == ARCH_UNKNOWN) + probe_caches (); + if (type == ARCH_ARMV6) + grub_arm_disable_caches_mmu_armv6 (); + if (type == ARCH_ARMV7) + grub_arm_disable_caches_mmu_armv7 (); +} diff --git a/grub-core/kern/arm/cache_armv6.S b/grub-core/kern/arm/cache_armv6.S new file mode 100644 index 000000000..e9da423dd --- /dev/null +++ b/grub-core/kern/arm/cache_armv6.S @@ -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 . + */ + +#include + + .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" \ No newline at end of file diff --git a/grub-core/kern/arm/cache_armv7.S b/grub-core/kern/arm/cache_armv7.S new file mode 100644 index 000000000..0c16b1047 --- /dev/null +++ b/grub-core/kern/arm/cache_armv7.S @@ -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 . + */ + +#include + + .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" \ No newline at end of file From 470038745c7b70c65103686e6a5b7b2ae839bb35 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Fri, 17 May 2013 13:05:28 +0200 Subject: [PATCH 21/25] Fix a bug and stick nearer to the specification, introduce armv6_unified. --- grub-core/kern/arm/cache.c | 61 ++++++++++++++++++++++++++++++-------- 1 file changed, 49 insertions(+), 12 deletions(-) diff --git a/grub-core/kern/arm/cache.c b/grub-core/kern/arm/cache.c index 4849d2400..c1fa62ed4 100644 --- a/grub-core/kern/arm/cache.c +++ b/grub-core/kern/arm/cache.c @@ -2,10 +2,13 @@ #include #include +/* 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; @@ -23,7 +26,7 @@ probe_caches (void) { grub_uint32_t main_id, cache_type; - /* Read Cache Type Register */ + /* Read main ID Register */ asm volatile ("mrc p15, 0, %0, c0, c0, 0": "=r"(main_id)); if (((main_id >> 12) & 0xf) == 0x0 || ((main_id >> 12) & 0xf) == 0x7 @@ -33,17 +36,31 @@ probe_caches (void) /* Read Cache Type Register */ asm volatile ("mrc p15, 0, %0, c0, c0, 1": "=r"(cache_type)); - switch (cache_type >> 29) + switch (cache_type >> 24) { - case 0: + 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 4: + case 0x80 ... 0x9f: 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); } @@ -54,10 +71,21 @@ grub_arch_sync_caches (void *address, grub_size_t len) { if (type == ARCH_UNKNOWN) probe_caches (); - if (type == ARCH_ARMV6) - grub_arch_sync_caches_armv6 (address, len); - if (type == ARCH_ARMV7) - grub_arch_sync_caches_armv7 (address, len); + 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 @@ -65,8 +93,17 @@ grub_arm_disable_caches_mmu (void) { if (type == ARCH_UNKNOWN) probe_caches (); - if (type == ARCH_ARMV6) - grub_arm_disable_caches_mmu_armv6 (); - if (type == ARCH_ARMV7) - grub_arm_disable_caches_mmu_armv7 (); + 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; + } } From c6a8472baf067d8f89b043de69c790d0af3eb68f Mon Sep 17 00:00:00 2001 From: Francesco Lavra Date: Fri, 17 May 2013 13:45:22 +0200 Subject: [PATCH 22/25] Own fdt parsing implementation --- grub-core/Makefile.core.def | 3 +- grub-core/lib/fdt.c | 389 +++++++++++++++++++++++++++++++++++ grub-core/loader/arm/linux.c | 200 +++++++++--------- include/grub/fdt.h | 99 +++++++++ 4 files changed, 587 insertions(+), 104 deletions(-) create mode 100644 grub-core/lib/fdt.c create mode 100644 include/grub/fdt.h diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index d01667d8b..990352d61 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -1536,11 +1536,10 @@ module = { 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; - - fdt_cppflags = '$(CPPFLAGS_LIBFDT)'; }; module = { diff --git a/grub-core/lib/fdt.c b/grub-core/lib/fdt.c new file mode 100644 index 000000000..57528c58f --- /dev/null +++ b/grub-core/lib/fdt.c @@ -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 . + */ + +#include +#include +#include + +#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; +} diff --git a/grub-core/loader/arm/linux.c b/grub-core/loader/arm/linux.c index 40b5b5e01..22450a09f 100644 --- a/grub-core/loader/arm/linux.c +++ b/grub-core/loader/arm/linux.c @@ -18,6 +18,7 @@ */ #include +#include #include #include #include @@ -27,23 +28,29 @@ #include #include -#include - GRUB_MOD_LICENSE ("GPLv3+"); static grub_dl_t my_mod; static grub_addr_t initrd_start; -static grub_size_t initrd_end; +static grub_addr_t initrd_end; static grub_addr_t linux_addr; static grub_size_t linux_size; static char *linux_args; -static grub_addr_t firmware_boot_data; -static grub_addr_t boot_data; static grub_uint32_t machine_type; +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(): @@ -58,19 +65,20 @@ linux_prepare_fdt (void) int tmp_size; void *tmp_fdt; - tmp_size = fdt_totalsize ((void *) boot_data) + FDT_ADDITIONAL_ENTRIES_SIZE; + tmp_size = grub_fdt_get_totalsize (fdt_addr) + 0x100 + grub_strlen (linux_args); tmp_fdt = grub_malloc (tmp_size); if (!tmp_fdt) - return GRUB_ERR_OUT_OF_MEMORY; + return grub_errno; - fdt_open_into ((void *) boot_data, tmp_fdt, tmp_size); + 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 = fdt_subnode_offset (tmp_fdt, 0, "chosen"); + node = grub_fdt_find_subnode (tmp_fdt, 0, "chosen"); if (node < 0) { grub_printf ("No 'chosen' node in FDT - creating.\n"); - node = fdt_add_subnode (tmp_fdt, 0, "chosen"); + node = grub_fdt_add_subnode (tmp_fdt, 0, "chosen"); if (node < 0) goto failure; } @@ -78,8 +86,8 @@ linux_prepare_fdt (void) grub_printf ("linux_args: '%s'\n", linux_args); /* Generate and set command line */ - retval = fdt_setprop (tmp_fdt, node, "bootargs", linux_args, - grub_strlen (linux_args) + 1); + retval = grub_fdt_set_prop (tmp_fdt, node, "bootargs", linux_args, + grub_strlen (linux_args) + 1); if (retval) goto failure; @@ -89,26 +97,22 @@ linux_prepare_fdt (void) * We're using physical addresses, so even if we have LPAE, we're * restricted to a 32-bit address space. */ - grub_uint32_t fdt_initrd_start = cpu_to_fdt32 (initrd_start); - grub_uint32_t fdt_initrd_end = cpu_to_fdt32 (initrd_end); - grub_dprintf ("loader", "Initrd @ 0x%08x-0x%08x\n", initrd_start, initrd_end); - retval = fdt_setprop (tmp_fdt, node, "linux,initrd-start", - &fdt_initrd_start, sizeof (fdt_initrd_start)); + retval = grub_fdt_set_prop32 (tmp_fdt, node, "linux,initrd-start", + initrd_start); if (retval) goto failure; - retval = fdt_setprop (tmp_fdt, node, "linux,initrd-end", - &fdt_initrd_end, sizeof (fdt_initrd_end)); + retval = grub_fdt_set_prop32 (tmp_fdt, node, "linux,initrd-end", + initrd_end); if (retval) goto failure; } /* Copy updated FDT to its launch location */ - fdt_move (tmp_fdt, (void *) boot_data, fdt_totalsize (tmp_fdt)); + grub_memcpy (fdt_addr, tmp_fdt, tmp_size); grub_free (tmp_fdt); - fdt_pack ((void *) boot_data); grub_dprintf ("loader", "FDT updated for Linux boot\n"); @@ -116,52 +120,35 @@ linux_prepare_fdt (void) failure: grub_free (tmp_fdt); - return GRUB_ERR_BAD_ARGUMENT; + 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 = GRUB_ERR_NONE; + 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); - if (!boot_data) - { - if (firmware_boot_data) - { - grub_printf ("Using firmware-supplied boot data @ 0x%08x\n", - firmware_boot_data); - boot_data = firmware_boot_data; - } - else - { - return GRUB_ERR_FILE_NOT_FOUND; - } - } - - grub_dprintf ("loader", "Boot data at: 0x%x\n", boot_data); - - if (fdt32_to_cpu (*(grub_uint32_t *) (boot_data)) == FDT_MAGIC) - { - grub_dprintf ("loader", "FDT @ 0x%08x\n", (grub_addr_t) boot_data); - if (linux_prepare_fdt () != GRUB_ERR_NONE) - { - grub_dprintf ("loader", "linux_prepare_fdt() failed\n"); - return GRUB_ERR_FILE_NOT_FOUND; - } - } + 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 (possibly passed from firmware) - * r2 - address of DTB or ATAG list + * r1 - machine type + * r2 - address of DTB */ linuxmain = (kernel_entry_t) linux_addr; @@ -171,7 +158,7 @@ linux_boot (void) return err; #endif - linuxmain (0, machine_type, (void *) boot_data); + linuxmain (0, machine_type, fdt_addr); return err; } @@ -180,21 +167,18 @@ linux_boot (void) * Only support zImage, so no relocations necessary */ static grub_err_t -linux_load (const char *filename) +linux_load (const char *filename, grub_file_t file) { - grub_file_t file; int size; - file = grub_file_open (filename); - if (!file) - return GRUB_ERR_FILE_NOT_FOUND; - size = grub_file_size (file); if (size == 0) - return GRUB_ERR_FILE_READ_ERROR; + 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 @@ -203,8 +187,10 @@ linux_load (const char *filename) if (grub_file_read (file, (void *) linux_addr, size) != size) { - grub_printf ("Kernel read failed!\n"); - return GRUB_ERR_FILE_READ_ERROR; + 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) @@ -235,7 +221,8 @@ static grub_err_t grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), int argc, char *argv[]) { - int size, retval; + int size; + grub_err_t err; grub_file_t file; grub_dl_ref (my_mod); @@ -246,17 +233,20 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), if (!file) goto fail; - retval = linux_load (argv[0]); + err = linux_load (argv[0], file); grub_file_close (file); - if (retval != GRUB_ERR_NONE) + if (err) goto fail; - grub_loader_set (linux_boot, linux_unload, 1); + 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) - goto fail; + { + grub_loader_unset(); + goto fail; + } /* Create kernel command line. */ grub_memcpy (linux_args, LINUX_IMAGE, sizeof (LINUX_IMAGE)); @@ -288,16 +278,31 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), 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) - goto fail; + { + 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; @@ -309,28 +314,15 @@ fail: return grub_errno; } -static void * +static grub_err_t load_dtb (grub_file_t dtb, int size) { - void *fdt; + 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")); - fdt = grub_malloc (size); - if (!fdt) - return NULL; - - if (grub_file_read (dtb, fdt, size) != size) - { - grub_free (fdt); - return NULL; - } - - if (fdt_check_header (fdt) != 0) - { - grub_free (fdt); - return NULL; - } - - return fdt; + grub_fdt_set_totalsize (fdt_addr, size); + return GRUB_ERR_NONE; } static grub_err_t @@ -338,7 +330,6 @@ grub_cmd_devicetree (grub_command_t cmd __attribute__ ((unused)), int argc, char *argv[]) { grub_file_t dtb; - void *blob; int size; if (argc != 1) @@ -346,25 +337,34 @@ grub_cmd_devicetree (grub_command_t cmd __attribute__ ((unused)), dtb = grub_file_open (argv[0]); if (!dtb) - return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("failed to open file")); + goto out; size = grub_file_size (dtb); if (size == 0) - goto out; - - blob = load_dtb (dtb, size); - if (!blob) - return GRUB_ERR_FILE_NOT_FOUND; + { + grub_error (GRUB_ERR_BAD_OS, "empty file"); + goto out; + } #ifdef GRUB_MACHINE_EFI - boot_data = (grub_addr_t) grub_efi_allocate_loader_memory (LINUX_FDT_PHYS_OFFSET, size); + 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 - boot_data = LINUX_FDT_ADDRESS; + fdt_addr = (void *) LINUX_FDT_ADDRESS; #endif + grub_dprintf ("loader", "Loading device tree to 0x%08x\n", - (grub_addr_t) boot_data); - fdt_move (blob, (void *) boot_data, fdt_totalsize (blob)); - grub_free (blob); + (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 @@ -372,8 +372,6 @@ grub_cmd_devicetree (grub_command_t cmd __attribute__ ((unused)), */ machine_type = ARM_FDT_MACHINE_TYPE; - return GRUB_ERR_NONE; - out: grub_file_close (dtb); @@ -391,9 +389,7 @@ GRUB_MOD_INIT (linux) cmd_devicetree = grub_register_command ("devicetree", grub_cmd_devicetree, 0, N_("Load DTB file.")); my_mod = mod; - firmware_boot_data = firmware_get_boot_data (); - - boot_data = (grub_addr_t) NULL; + fdt_addr = (void *) firmware_get_boot_data (); machine_type = firmware_get_machine_type (); } diff --git a/include/grub/fdt.h b/include/grub/fdt.h new file mode 100644 index 000000000..2ad0536b6 --- /dev/null +++ b/include/grub/fdt.h @@ -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 . + */ + +#ifndef GRUB_FDT_HEADER +#define GRUB_FDT_HEADER 1 + +#include + +#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 */ From 2a800dc3f31c78d4ee078c013bbcaf30360e18dd Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Fri, 17 May 2013 13:58:47 +0200 Subject: [PATCH 23/25] Remove libfdt --- autogen.sh | 5 +- grub-core/lib/dtc/libfdt-grub.diff | 44 - grub-core/lib/dtc/libfdt/Makefile.libfdt | 10 - grub-core/lib/dtc/libfdt/TODO | 3 - grub-core/lib/dtc/libfdt/fdt.c | 241 ---- grub-core/lib/dtc/libfdt/fdt.h | 64 - grub-core/lib/dtc/libfdt/fdt_ro.c | 608 ---------- grub-core/lib/dtc/libfdt/fdt_rw.c | 490 -------- grub-core/lib/dtc/libfdt/fdt_strerror.c | 100 -- grub-core/lib/dtc/libfdt/fdt_sw.c | 267 ----- grub-core/lib/dtc/libfdt/fdt_wip.c | 123 -- grub-core/lib/dtc/libfdt/libfdt.h | 1239 -------------------- grub-core/lib/dtc/libfdt/libfdt_env.h | 27 - grub-core/lib/dtc/libfdt/libfdt_internal.h | 100 -- grub-core/lib/dtc/libfdt/version.lds | 54 - util/import_libfdt.py | 103 -- 16 files changed, 1 insertion(+), 3477 deletions(-) delete mode 100644 grub-core/lib/dtc/libfdt-grub.diff delete mode 100644 grub-core/lib/dtc/libfdt/Makefile.libfdt delete mode 100644 grub-core/lib/dtc/libfdt/TODO delete mode 100644 grub-core/lib/dtc/libfdt/fdt.c delete mode 100644 grub-core/lib/dtc/libfdt/fdt.h delete mode 100644 grub-core/lib/dtc/libfdt/fdt_ro.c delete mode 100644 grub-core/lib/dtc/libfdt/fdt_rw.c delete mode 100644 grub-core/lib/dtc/libfdt/fdt_strerror.c delete mode 100644 grub-core/lib/dtc/libfdt/fdt_sw.c delete mode 100644 grub-core/lib/dtc/libfdt/fdt_wip.c delete mode 100644 grub-core/lib/dtc/libfdt/libfdt.h delete mode 100644 grub-core/lib/dtc/libfdt/libfdt_env.h delete mode 100644 grub-core/lib/dtc/libfdt/libfdt_internal.h delete mode 100644 grub-core/lib/dtc/libfdt/version.lds delete mode 100644 util/import_libfdt.py diff --git a/autogen.sh b/autogen.sh index d97b273ac..d63a79a22 100755 --- a/autogen.sh +++ b/autogen.sh @@ -33,9 +33,6 @@ for x in mpi-asm-defs.h mpih-add1.c mpih-sub1.c mpih-mul1.c mpih-mul2.c mpih-mul ln -s generic/"$x" grub-core/lib/libgcrypt-grub/mpi/"$x" done -echo "Importing libfdt..." -python util/import_libfdt.py grub-core/lib/dtc/ grub-core - echo "Creating Makefile.tpl..." python gentpl.py | sed -e '/^$/{N;/^\n$/D;}' > Makefile.tpl @@ -49,7 +46,7 @@ if [ "x${GRUB_CONTRIB}" != x ]; then fi UTIL_DEFS='Makefile.util.def Makefile.utilgcry.def' -CORE_DEFS='grub-core/Makefile.core.def grub-core/Makefile.gcry.def grub-core/Makefile.libfdt.def' +CORE_DEFS='grub-core/Makefile.core.def grub-core/Makefile.gcry.def' for extra in contrib/*/Makefile.util.def; do if test -e "$extra"; then diff --git a/grub-core/lib/dtc/libfdt-grub.diff b/grub-core/lib/dtc/libfdt-grub.diff deleted file mode 100644 index e5164a2c8..000000000 --- a/grub-core/lib/dtc/libfdt-grub.diff +++ /dev/null @@ -1,44 +0,0 @@ -diff -purN libfdt.orig/fdt_rw.c libfdt/fdt_rw.c ---- libfdt.orig/fdt_rw.c 2011-05-08 20:45:39.000000000 +0100 -+++ libfdt/fdt_rw.c 2012-10-19 15:33:11.085523185 +0100 -@@ -88,9 +88,9 @@ static int _fdt_rw_check_header(void *fd - - #define FDT_RW_CHECK_HEADER(fdt) \ - { \ -- int err; \ -- if ((err = _fdt_rw_check_header(fdt)) != 0) \ -- return err; \ -+ int macro_err; \ -+ if ((macro_err = _fdt_rw_check_header(fdt)) != 0) \ -+ return macro_err; \ - } - - static inline int -diff -purN libfdt.orig/libfdt_env.h libfdt/libfdt_env.h ---- libfdt.orig/libfdt_env.h 2011-05-08 20:45:39.000000000 +0100 -+++ libfdt/libfdt_env.h 2012-10-19 16:13:19.051344173 +0100 -@@ -7,6 +7,8 @@ - #include - #include - #include -+#pragma GCC diagnostic ignored "-Wcast-align" -+#pragma GCC diagnostic ignored "-Wsign-compare" - - #define _B(n) ((unsigned long long)((uint8_t *)&x)[n]) - static inline uint32_t -diff -purN libfdt.orig/libfdt_internal.h libfdt/libfdt_internal.h ---- libfdt.orig/libfdt_internal.h 2011-05-08 20:45:39.000000000 +0100 -+++ libfdt/libfdt_internal.h 2012-10-19 15:33:11.105524731 +0100 -@@ -60,9 +60,9 @@ - - #define FDT_CHECK_HEADER(fdt) \ - { \ -- int err; \ -- if ((err = fdt_check_header(fdt)) != 0) \ -- return err; \ -+ int macro_err; \ -+ if ((macro_err = fdt_check_header(fdt)) != 0) \ -+ return macro_err; \ - } - - int _fdt_check_node_offset (const void *fdt, int offset); diff --git a/grub-core/lib/dtc/libfdt/Makefile.libfdt b/grub-core/lib/dtc/libfdt/Makefile.libfdt deleted file mode 100644 index d55a6f852..000000000 --- a/grub-core/lib/dtc/libfdt/Makefile.libfdt +++ /dev/null @@ -1,10 +0,0 @@ -# Makefile.libfdt -# -# This is not a complete Makefile of itself. Instead, it is designed to -# be easily embeddable into other systems of Makefiles. -# -LIBFDT_soname = libfdt.$(SHAREDLIB_EXT).1 -LIBFDT_INCLUDES = fdt.h libfdt.h -LIBFDT_VERSION = version.lds -LIBFDT_SRCS = fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c -LIBFDT_OBJS = $(LIBFDT_SRCS:%.c=%.o) diff --git a/grub-core/lib/dtc/libfdt/TODO b/grub-core/lib/dtc/libfdt/TODO deleted file mode 100644 index 288437e39..000000000 --- a/grub-core/lib/dtc/libfdt/TODO +++ /dev/null @@ -1,3 +0,0 @@ -- Tree traversal functions -- Graft function -- Complete libfdt.h documenting comments diff --git a/grub-core/lib/dtc/libfdt/fdt.c b/grub-core/lib/dtc/libfdt/fdt.c deleted file mode 100644 index e8627349e..000000000 --- a/grub-core/lib/dtc/libfdt/fdt.c +++ /dev/null @@ -1,241 +0,0 @@ -/* - * libfdt - Flat Device Tree manipulation - * Copyright (C) 2006 David Gibson, IBM Corporation. - * - * libfdt is dual licensed: you can use it either under the terms of - * the GPL, or the BSD license, at your option. - * - * a) This library 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 library 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 library; if not, write to the Free - * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, - * MA 02110-1301 USA - * - * Alternatively, - * - * b) 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. - */ -#include "libfdt_env.h" - -#include -#include - -#include "libfdt_internal.h" - -int -fdt_check_header (const void *fdt) -{ - if (fdt_magic (fdt) == FDT_MAGIC) - { - /* Complete tree */ - if (fdt_version (fdt) < FDT_FIRST_SUPPORTED_VERSION) - return -FDT_ERR_BADVERSION; - if (fdt_last_comp_version (fdt) > FDT_LAST_SUPPORTED_VERSION) - return -FDT_ERR_BADVERSION; - } - else if (fdt_magic (fdt) == FDT_SW_MAGIC) - { - /* Unfinished sequential-write blob */ - if (fdt_size_dt_struct (fdt) == 0) - return -FDT_ERR_BADSTATE; - } - else - { - return -FDT_ERR_BADMAGIC; - } - - return 0; -} - -const void * -fdt_offset_ptr (const void *fdt, int offset, unsigned int len) -{ - const char *p; - - if (fdt_version (fdt) >= 0x11) - if (((offset + len) < offset) - || ((offset + len) > fdt_size_dt_struct (fdt))) - return NULL; - - p = _fdt_offset_ptr (fdt, offset); - - if (p + len < p) - return NULL; - return p; -} - -uint32_t -fdt_next_tag (const void *fdt, int startoffset, int *nextoffset) -{ - const uint32_t *tagp, *lenp; - uint32_t tag; - int offset = startoffset; - const char *p; - - *nextoffset = -FDT_ERR_TRUNCATED; - tagp = fdt_offset_ptr (fdt, offset, FDT_TAGSIZE); - if (!tagp) - return FDT_END; /* premature end */ - tag = fdt32_to_cpu (*tagp); - offset += FDT_TAGSIZE; - - *nextoffset = -FDT_ERR_BADSTRUCTURE; - switch (tag) - { - case FDT_BEGIN_NODE: - /* skip name */ - do - { - p = fdt_offset_ptr (fdt, offset++, 1); - } - while (p && (*p != '\0')); - if (!p) - return FDT_END; /* premature end */ - break; - - case FDT_PROP: - lenp = fdt_offset_ptr (fdt, offset, sizeof (*lenp)); - if (!lenp) - return FDT_END; /* premature end */ - /* skip-name offset, length and value */ - offset += sizeof (struct fdt_property) - FDT_TAGSIZE - + fdt32_to_cpu (*lenp); - break; - - case FDT_END: - case FDT_END_NODE: - case FDT_NOP: - break; - - default: - return FDT_END; - } - - if (!fdt_offset_ptr (fdt, startoffset, offset - startoffset)) - return FDT_END; /* premature end */ - - *nextoffset = FDT_TAGALIGN (offset); - return tag; -} - -int -_fdt_check_node_offset (const void *fdt, int offset) -{ - if ((offset < 0) || (offset % FDT_TAGSIZE) - || (fdt_next_tag (fdt, offset, &offset) != FDT_BEGIN_NODE)) - return -FDT_ERR_BADOFFSET; - - return offset; -} - -int -_fdt_check_prop_offset (const void *fdt, int offset) -{ - if ((offset < 0) || (offset % FDT_TAGSIZE) - || (fdt_next_tag (fdt, offset, &offset) != FDT_PROP)) - return -FDT_ERR_BADOFFSET; - - return offset; -} - -int -fdt_next_node (const void *fdt, int offset, int *depth) -{ - int nextoffset = 0; - uint32_t tag; - - if (offset >= 0) - if ((nextoffset = _fdt_check_node_offset (fdt, offset)) < 0) - return nextoffset; - - do - { - offset = nextoffset; - tag = fdt_next_tag (fdt, offset, &nextoffset); - - switch (tag) - { - case FDT_PROP: - case FDT_NOP: - break; - - case FDT_BEGIN_NODE: - if (depth) - (*depth)++; - break; - - case FDT_END_NODE: - if (depth && ((--(*depth)) < 0)) - return nextoffset; - break; - - case FDT_END: - if ((nextoffset >= 0) - || ((nextoffset == -FDT_ERR_TRUNCATED) && !depth)) - return -FDT_ERR_NOTFOUND; - else - return nextoffset; - } - } - while (tag != FDT_BEGIN_NODE); - - return offset; -} - -const char * -_fdt_find_string (const char *strtab, int tabsize, const char *s) -{ - int len = strlen (s) + 1; - const char *last = strtab + tabsize - len; - const char *p; - - for (p = strtab; p <= last; p++) - if (memcmp (p, s, len) == 0) - return p; - return NULL; -} - -int -fdt_move (const void *fdt, void *buf, int bufsize) -{ - FDT_CHECK_HEADER (fdt); - - if (fdt_totalsize (fdt) > bufsize) - return -FDT_ERR_NOSPACE; - - memmove (buf, fdt, fdt_totalsize (fdt)); - return 0; -} diff --git a/grub-core/lib/dtc/libfdt/fdt.h b/grub-core/lib/dtc/libfdt/fdt.h deleted file mode 100644 index 25bd3082a..000000000 --- a/grub-core/lib/dtc/libfdt/fdt.h +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef _FDT_H -#define _FDT_H - -#ifndef __ASSEMBLY__ - -struct fdt_header -{ - uint32_t magic; /* magic word FDT_MAGIC */ - uint32_t totalsize; /* total size of DT block */ - uint32_t off_dt_struct; /* offset to structure */ - uint32_t off_dt_strings; /* offset to strings */ - uint32_t off_mem_rsvmap; /* offset to memory reserve map */ - uint32_t version; /* format version */ - uint32_t last_comp_version; /* last compatible version */ - - /* version 2 fields below */ - uint32_t boot_cpuid_phys; /* Which physical CPU id we're - booting on */ - /* version 3 fields below */ - uint32_t size_dt_strings; /* size of the strings block */ - - /* version 17 fields below */ - uint32_t size_dt_struct; /* size of the structure block */ -}; - -struct fdt_reserve_entry -{ - uint64_t address; - uint64_t size; -}; - -struct fdt_node_header -{ - uint32_t tag; - char name[0]; -}; - -struct fdt_property -{ - uint32_t tag; - uint32_t len; - uint32_t nameoff; - char data[0]; -}; - -#endif /* !__ASSEMBLY */ - -#define FDT_MAGIC 0xd00dfeed /* 4: version, 4: total size */ -#define FDT_TAGSIZE sizeof(uint32_t) - -#define FDT_BEGIN_NODE 0x1 /* Start node: full name */ -#define FDT_END_NODE 0x2 /* End node */ -#define FDT_PROP 0x3 /* Property: name off, - size, content */ -#define FDT_NOP 0x4 /* nop */ -#define FDT_END 0x9 - -#define FDT_V1_SIZE (7*sizeof(uint32_t)) -#define FDT_V2_SIZE (FDT_V1_SIZE + sizeof(uint32_t)) -#define FDT_V3_SIZE (FDT_V2_SIZE + sizeof(uint32_t)) -#define FDT_V16_SIZE FDT_V3_SIZE -#define FDT_V17_SIZE (FDT_V16_SIZE + sizeof(uint32_t)) - -#endif /* _FDT_H */ diff --git a/grub-core/lib/dtc/libfdt/fdt_ro.c b/grub-core/lib/dtc/libfdt/fdt_ro.c deleted file mode 100644 index 7014e302d..000000000 --- a/grub-core/lib/dtc/libfdt/fdt_ro.c +++ /dev/null @@ -1,608 +0,0 @@ -/* - * libfdt - Flat Device Tree manipulation - * Copyright (C) 2006 David Gibson, IBM Corporation. - * - * libfdt is dual licensed: you can use it either under the terms of - * the GPL, or the BSD license, at your option. - * - * a) This library 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 library 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 library; if not, write to the Free - * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, - * MA 02110-1301 USA - * - * Alternatively, - * - * b) 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. - */ -#include "libfdt_env.h" - -#include -#include - -#include "libfdt_internal.h" - -static int -_fdt_nodename_eq (const void *fdt, int offset, const char *s, int len) -{ - const char *p = fdt_offset_ptr (fdt, offset + FDT_TAGSIZE, len + 1); - - if (!p) - /* short match */ - return 0; - - if (memcmp (p, s, len) != 0) - return 0; - - if (p[len] == '\0') - return 1; - else if (!memchr (s, '@', len) && (p[len] == '@')) - return 1; - else - return 0; -} - -const char * -fdt_string (const void *fdt, int stroffset) -{ - return (const char *) fdt + fdt_off_dt_strings (fdt) + stroffset; -} - -static int -_fdt_string_eq (const void *fdt, int stroffset, const char *s, int len) -{ - const char *p = fdt_string (fdt, stroffset); - - return (strlen (p) == len) && (memcmp (p, s, len) == 0); -} - -int -fdt_get_mem_rsv (const void *fdt, int n, uint64_t * address, uint64_t * size) -{ - FDT_CHECK_HEADER (fdt); - *address = fdt64_to_cpu (_fdt_mem_rsv (fdt, n)->address); - *size = fdt64_to_cpu (_fdt_mem_rsv (fdt, n)->size); - return 0; -} - -int -fdt_num_mem_rsv (const void *fdt) -{ - int i = 0; - - while (fdt64_to_cpu (_fdt_mem_rsv (fdt, i)->size) != 0) - i++; - return i; -} - -static int -_nextprop (const void *fdt, int offset) -{ - uint32_t tag; - int nextoffset; - - do - { - tag = fdt_next_tag (fdt, offset, &nextoffset); - - switch (tag) - { - case FDT_END: - if (nextoffset >= 0) - return -FDT_ERR_BADSTRUCTURE; - else - return nextoffset; - - case FDT_PROP: - return offset; - } - offset = nextoffset; - } - while (tag == FDT_NOP); - - return -FDT_ERR_NOTFOUND; -} - -int -fdt_subnode_offset_namelen (const void *fdt, int offset, - const char *name, int namelen) -{ - int depth; - - FDT_CHECK_HEADER (fdt); - - for (depth = 0; - (offset >= 0) && (depth >= 0); - offset = fdt_next_node (fdt, offset, &depth)) - if ((depth == 1) && _fdt_nodename_eq (fdt, offset, name, namelen)) - return offset; - - if (depth < 0) - return -FDT_ERR_NOTFOUND; - return offset; /* error */ -} - -int -fdt_subnode_offset (const void *fdt, int parentoffset, const char *name) -{ - return fdt_subnode_offset_namelen (fdt, parentoffset, name, strlen (name)); -} - -int -fdt_path_offset (const void *fdt, const char *path) -{ - const char *end = path + strlen (path); - const char *p = path; - int offset = 0; - - FDT_CHECK_HEADER (fdt); - - /* see if we have an alias */ - if (*path != '/') - { - const char *q = strchr (path, '/'); - - if (!q) - q = end; - - p = fdt_get_alias_namelen (fdt, p, q - p); - if (!p) - return -FDT_ERR_BADPATH; - offset = fdt_path_offset (fdt, p); - - p = q; - } - - while (*p) - { - const char *q; - - while (*p == '/') - p++; - if (!*p) - return offset; - q = strchr (p, '/'); - if (!q) - q = end; - - offset = fdt_subnode_offset_namelen (fdt, offset, p, q - p); - if (offset < 0) - return offset; - - p = q; - } - - return offset; -} - -const char * -fdt_get_name (const void *fdt, int nodeoffset, int *len) -{ - const struct fdt_node_header *nh = _fdt_offset_ptr (fdt, nodeoffset); - int err; - - if (((err = fdt_check_header (fdt)) != 0) - || ((err = _fdt_check_node_offset (fdt, nodeoffset)) < 0)) - goto fail; - - if (len) - *len = strlen (nh->name); - - return nh->name; - -fail: - if (len) - *len = err; - return NULL; -} - -int -fdt_first_property_offset (const void *fdt, int nodeoffset) -{ - int offset; - - if ((offset = _fdt_check_node_offset (fdt, nodeoffset)) < 0) - return offset; - - return _nextprop (fdt, offset); -} - -int -fdt_next_property_offset (const void *fdt, int offset) -{ - if ((offset = _fdt_check_prop_offset (fdt, offset)) < 0) - return offset; - - return _nextprop (fdt, offset); -} - -const struct fdt_property * -fdt_get_property_by_offset (const void *fdt, int offset, int *lenp) -{ - int err; - const struct fdt_property *prop; - - if ((err = _fdt_check_prop_offset (fdt, offset)) < 0) - { - if (lenp) - *lenp = err; - return NULL; - } - - prop = _fdt_offset_ptr (fdt, offset); - - if (lenp) - *lenp = fdt32_to_cpu (prop->len); - - return prop; -} - -const struct fdt_property * -fdt_get_property_namelen (const void *fdt, - int offset, - const char *name, int namelen, int *lenp) -{ - for (offset = fdt_first_property_offset (fdt, offset); - (offset >= 0); (offset = fdt_next_property_offset (fdt, offset))) - { - const struct fdt_property *prop; - - if (!(prop = fdt_get_property_by_offset (fdt, offset, lenp))) - { - offset = -FDT_ERR_INTERNAL; - break; - } - if (_fdt_string_eq (fdt, fdt32_to_cpu (prop->nameoff), name, namelen)) - return prop; - } - - if (lenp) - *lenp = offset; - return NULL; -} - -const struct fdt_property * -fdt_get_property (const void *fdt, - int nodeoffset, const char *name, int *lenp) -{ - return fdt_get_property_namelen (fdt, nodeoffset, name, - strlen (name), lenp); -} - -const void * -fdt_getprop_namelen (const void *fdt, int nodeoffset, - const char *name, int namelen, int *lenp) -{ - const struct fdt_property *prop; - - prop = fdt_get_property_namelen (fdt, nodeoffset, name, namelen, lenp); - if (!prop) - return NULL; - - return prop->data; -} - -const void * -fdt_getprop_by_offset (const void *fdt, int offset, - const char **namep, int *lenp) -{ - const struct fdt_property *prop; - - prop = fdt_get_property_by_offset (fdt, offset, lenp); - if (!prop) - return NULL; - if (namep) - *namep = fdt_string (fdt, fdt32_to_cpu (prop->nameoff)); - return prop->data; -} - -const void * -fdt_getprop (const void *fdt, int nodeoffset, const char *name, int *lenp) -{ - return fdt_getprop_namelen (fdt, nodeoffset, name, strlen (name), lenp); -} - -uint32_t -fdt_get_phandle (const void *fdt, int nodeoffset) -{ - const uint32_t *php; - int len; - - /* FIXME: This is a bit sub-optimal, since we potentially scan - * over all the properties twice. */ - php = fdt_getprop (fdt, nodeoffset, "phandle", &len); - if (!php || (len != sizeof (*php))) - { - php = fdt_getprop (fdt, nodeoffset, "linux,phandle", &len); - if (!php || (len != sizeof (*php))) - return 0; - } - - return fdt32_to_cpu (*php); -} - -const char * -fdt_get_alias_namelen (const void *fdt, const char *name, int namelen) -{ - int aliasoffset; - - aliasoffset = fdt_path_offset (fdt, "/aliases"); - if (aliasoffset < 0) - return NULL; - - return fdt_getprop_namelen (fdt, aliasoffset, name, namelen, NULL); -} - -const char * -fdt_get_alias (const void *fdt, const char *name) -{ - return fdt_get_alias_namelen (fdt, name, strlen (name)); -} - -int -fdt_get_path (const void *fdt, int nodeoffset, char *buf, int buflen) -{ - int pdepth = 0, p = 0; - int offset, depth, namelen; - const char *name; - - FDT_CHECK_HEADER (fdt); - - if (buflen < 2) - return -FDT_ERR_NOSPACE; - - for (offset = 0, depth = 0; - (offset >= 0) && (offset <= nodeoffset); - offset = fdt_next_node (fdt, offset, &depth)) - { - while (pdepth > depth) - { - do - { - p--; - } - while (buf[p - 1] != '/'); - pdepth--; - } - - if (pdepth >= depth) - { - name = fdt_get_name (fdt, offset, &namelen); - if (!name) - return namelen; - if ((p + namelen + 1) <= buflen) - { - memcpy (buf + p, name, namelen); - p += namelen; - buf[p++] = '/'; - pdepth++; - } - } - - if (offset == nodeoffset) - { - if (pdepth < (depth + 1)) - return -FDT_ERR_NOSPACE; - - if (p > 1) /* special case so that root path is "/", not "" */ - p--; - buf[p] = '\0'; - return 0; - } - } - - if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0)) - return -FDT_ERR_BADOFFSET; - else if (offset == -FDT_ERR_BADOFFSET) - return -FDT_ERR_BADSTRUCTURE; - - return offset; /* error from fdt_next_node() */ -} - -int -fdt_supernode_atdepth_offset (const void *fdt, int nodeoffset, - int supernodedepth, int *nodedepth) -{ - int offset, depth; - int supernodeoffset = -FDT_ERR_INTERNAL; - - FDT_CHECK_HEADER (fdt); - - if (supernodedepth < 0) - return -FDT_ERR_NOTFOUND; - - for (offset = 0, depth = 0; - (offset >= 0) && (offset <= nodeoffset); - offset = fdt_next_node (fdt, offset, &depth)) - { - if (depth == supernodedepth) - supernodeoffset = offset; - - if (offset == nodeoffset) - { - if (nodedepth) - *nodedepth = depth; - - if (supernodedepth > depth) - return -FDT_ERR_NOTFOUND; - else - return supernodeoffset; - } - } - - if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0)) - return -FDT_ERR_BADOFFSET; - else if (offset == -FDT_ERR_BADOFFSET) - return -FDT_ERR_BADSTRUCTURE; - - return offset; /* error from fdt_next_node() */ -} - -int -fdt_node_depth (const void *fdt, int nodeoffset) -{ - int nodedepth; - int err; - - err = fdt_supernode_atdepth_offset (fdt, nodeoffset, 0, &nodedepth); - if (err) - return (err < 0) ? err : -FDT_ERR_INTERNAL; - return nodedepth; -} - -int -fdt_parent_offset (const void *fdt, int nodeoffset) -{ - int nodedepth = fdt_node_depth (fdt, nodeoffset); - - if (nodedepth < 0) - return nodedepth; - return fdt_supernode_atdepth_offset (fdt, nodeoffset, nodedepth - 1, NULL); -} - -int -fdt_node_offset_by_prop_value (const void *fdt, int startoffset, - const char *propname, - const void *propval, int proplen) -{ - int offset; - const void *val; - int len; - - FDT_CHECK_HEADER (fdt); - - /* FIXME: The algorithm here is pretty horrible: we scan each - * property of a node in fdt_getprop(), then if that didn't - * find what we want, we scan over them again making our way - * to the next node. Still it's the easiest to implement - * approach; performance can come later. */ - for (offset = fdt_next_node (fdt, startoffset, NULL); - offset >= 0; offset = fdt_next_node (fdt, offset, NULL)) - { - val = fdt_getprop (fdt, offset, propname, &len); - if (val && (len == proplen) && (memcmp (val, propval, len) == 0)) - return offset; - } - - return offset; /* error from fdt_next_node() */ -} - -int -fdt_node_offset_by_phandle (const void *fdt, uint32_t phandle) -{ - int offset; - - if ((phandle == 0) || (phandle == -1)) - return -FDT_ERR_BADPHANDLE; - - FDT_CHECK_HEADER (fdt); - - /* FIXME: The algorithm here is pretty horrible: we - * potentially scan each property of a node in - * fdt_get_phandle(), then if that didn't find what - * we want, we scan over them again making our way to the next - * node. Still it's the easiest to implement approach; - * performance can come later. */ - for (offset = fdt_next_node (fdt, -1, NULL); - offset >= 0; offset = fdt_next_node (fdt, offset, NULL)) - { - if (fdt_get_phandle (fdt, offset) == phandle) - return offset; - } - - return offset; /* error from fdt_next_node() */ -} - -static int -_fdt_stringlist_contains (const char *strlist, int listlen, const char *str) -{ - int len = strlen (str); - const char *p; - - while (listlen >= len) - { - if (memcmp (str, strlist, len + 1) == 0) - return 1; - p = memchr (strlist, '\0', listlen); - if (!p) - return 0; /* malformed strlist.. */ - listlen -= (p - strlist) + 1; - strlist = p + 1; - } - return 0; -} - -int -fdt_node_check_compatible (const void *fdt, int nodeoffset, - const char *compatible) -{ - const void *prop; - int len; - - prop = fdt_getprop (fdt, nodeoffset, "compatible", &len); - if (!prop) - return len; - if (_fdt_stringlist_contains (prop, len, compatible)) - return 0; - else - return 1; -} - -int -fdt_node_offset_by_compatible (const void *fdt, int startoffset, - const char *compatible) -{ - int offset, err; - - FDT_CHECK_HEADER (fdt); - - /* FIXME: The algorithm here is pretty horrible: we scan each - * property of a node in fdt_node_check_compatible(), then if - * that didn't find what we want, we scan over them again - * making our way to the next node. Still it's the easiest to - * implement approach; performance can come later. */ - for (offset = fdt_next_node (fdt, startoffset, NULL); - offset >= 0; offset = fdt_next_node (fdt, offset, NULL)) - { - err = fdt_node_check_compatible (fdt, offset, compatible); - if ((err < 0) && (err != -FDT_ERR_NOTFOUND)) - return err; - else if (err == 0) - return offset; - } - - return offset; /* error from fdt_next_node() */ -} diff --git a/grub-core/lib/dtc/libfdt/fdt_rw.c b/grub-core/lib/dtc/libfdt/fdt_rw.c deleted file mode 100644 index 58bc4adf0..000000000 --- a/grub-core/lib/dtc/libfdt/fdt_rw.c +++ /dev/null @@ -1,490 +0,0 @@ -/* - * libfdt - Flat Device Tree manipulation - * Copyright (C) 2006 David Gibson, IBM Corporation. - * - * libfdt is dual licensed: you can use it either under the terms of - * the GPL, or the BSD license, at your option. - * - * a) This library 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 library 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 library; if not, write to the Free - * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, - * MA 02110-1301 USA - * - * Alternatively, - * - * b) 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. - */ -#include "libfdt_env.h" - -#include -#include - -#include "libfdt_internal.h" - -static int -_fdt_blocks_misordered (const void *fdt, int mem_rsv_size, int struct_size) -{ - return (fdt_off_mem_rsvmap (fdt) < - FDT_ALIGN (sizeof (struct fdt_header), 8)) - || (fdt_off_dt_struct (fdt) < (fdt_off_mem_rsvmap (fdt) + mem_rsv_size)) - || (fdt_off_dt_strings (fdt) < (fdt_off_dt_struct (fdt) + struct_size)) - || (fdt_totalsize (fdt) < - (fdt_off_dt_strings (fdt) + fdt_size_dt_strings (fdt))); -} - -static int -_fdt_rw_check_header (void *fdt) -{ - FDT_CHECK_HEADER (fdt); - - if (fdt_version (fdt) < 17) - return -FDT_ERR_BADVERSION; - if (_fdt_blocks_misordered (fdt, sizeof (struct fdt_reserve_entry), - fdt_size_dt_struct (fdt))) - return -FDT_ERR_BADLAYOUT; - if (fdt_version (fdt) > 17) - fdt_set_version (fdt, 17); - - return 0; -} - -#define FDT_RW_CHECK_HEADER(fdt) \ - { \ - int err; \ - if ((err = _fdt_rw_check_header(fdt)) != 0) \ - return err; \ - } - -static inline int -_fdt_data_size (void *fdt) -{ - return fdt_off_dt_strings (fdt) + fdt_size_dt_strings (fdt); -} - -static int -_fdt_splice (void *fdt, void *splicepoint, int oldlen, int newlen) -{ - char *p = splicepoint; - char *end = (char *) fdt + _fdt_data_size (fdt); - - if (((p + oldlen) < p) || ((p + oldlen) > end)) - return -FDT_ERR_BADOFFSET; - if ((end - oldlen + newlen) > ((char *) fdt + fdt_totalsize (fdt))) - return -FDT_ERR_NOSPACE; - memmove (p + newlen, p + oldlen, end - p - oldlen); - return 0; -} - -static int -_fdt_splice_mem_rsv (void *fdt, struct fdt_reserve_entry *p, - int oldn, int newn) -{ - int delta = (newn - oldn) * sizeof (*p); - int err; - err = _fdt_splice (fdt, p, oldn * sizeof (*p), newn * sizeof (*p)); - if (err) - return err; - fdt_set_off_dt_struct (fdt, fdt_off_dt_struct (fdt) + delta); - fdt_set_off_dt_strings (fdt, fdt_off_dt_strings (fdt) + delta); - return 0; -} - -static int -_fdt_splice_struct (void *fdt, void *p, int oldlen, int newlen) -{ - int delta = newlen - oldlen; - int err; - - if ((err = _fdt_splice (fdt, p, oldlen, newlen))) - return err; - - fdt_set_size_dt_struct (fdt, fdt_size_dt_struct (fdt) + delta); - fdt_set_off_dt_strings (fdt, fdt_off_dt_strings (fdt) + delta); - return 0; -} - -static int -_fdt_splice_string (void *fdt, int newlen) -{ - void *p = (char *) fdt - + fdt_off_dt_strings (fdt) + fdt_size_dt_strings (fdt); - int err; - - if ((err = _fdt_splice (fdt, p, 0, newlen))) - return err; - - fdt_set_size_dt_strings (fdt, fdt_size_dt_strings (fdt) + newlen); - return 0; -} - -static int -_fdt_find_add_string (void *fdt, const char *s) -{ - char *strtab = (char *) fdt + fdt_off_dt_strings (fdt); - const char *p; - char *new; - int len = strlen (s) + 1; - int err; - - p = _fdt_find_string (strtab, fdt_size_dt_strings (fdt), s); - if (p) - /* found it */ - return (p - strtab); - - new = strtab + fdt_size_dt_strings (fdt); - err = _fdt_splice_string (fdt, len); - if (err) - return err; - - memcpy (new, s, len); - return (new - strtab); -} - -int -fdt_add_mem_rsv (void *fdt, uint64_t address, uint64_t size) -{ - struct fdt_reserve_entry *re; - int err; - - FDT_RW_CHECK_HEADER (fdt); - - re = _fdt_mem_rsv_w (fdt, fdt_num_mem_rsv (fdt)); - err = _fdt_splice_mem_rsv (fdt, re, 0, 1); - if (err) - return err; - - re->address = cpu_to_fdt64 (address); - re->size = cpu_to_fdt64 (size); - return 0; -} - -int -fdt_del_mem_rsv (void *fdt, int n) -{ - struct fdt_reserve_entry *re = _fdt_mem_rsv_w (fdt, n); - int err; - - FDT_RW_CHECK_HEADER (fdt); - - if (n >= fdt_num_mem_rsv (fdt)) - return -FDT_ERR_NOTFOUND; - - err = _fdt_splice_mem_rsv (fdt, re, 1, 0); - if (err) - return err; - return 0; -} - -static int -_fdt_resize_property (void *fdt, int nodeoffset, const char *name, - int len, struct fdt_property **prop) -{ - int oldlen; - int err; - - *prop = fdt_get_property_w (fdt, nodeoffset, name, &oldlen); - if (!(*prop)) - return oldlen; - - if ((err = _fdt_splice_struct (fdt, (*prop)->data, FDT_TAGALIGN (oldlen), - FDT_TAGALIGN (len)))) - return err; - - (*prop)->len = cpu_to_fdt32 (len); - return 0; -} - -static int -_fdt_add_property (void *fdt, int nodeoffset, const char *name, - int len, struct fdt_property **prop) -{ - int proplen; - int nextoffset; - int namestroff; - int err; - - if ((nextoffset = _fdt_check_node_offset (fdt, nodeoffset)) < 0) - return nextoffset; - - namestroff = _fdt_find_add_string (fdt, name); - if (namestroff < 0) - return namestroff; - - *prop = _fdt_offset_ptr_w (fdt, nextoffset); - proplen = sizeof (**prop) + FDT_TAGALIGN (len); - - err = _fdt_splice_struct (fdt, *prop, 0, proplen); - if (err) - return err; - - (*prop)->tag = cpu_to_fdt32 (FDT_PROP); - (*prop)->nameoff = cpu_to_fdt32 (namestroff); - (*prop)->len = cpu_to_fdt32 (len); - return 0; -} - -int -fdt_set_name (void *fdt, int nodeoffset, const char *name) -{ - char *namep; - int oldlen, newlen; - int err; - - FDT_RW_CHECK_HEADER (fdt); - - namep = (char *) (uintptr_t) fdt_get_name (fdt, nodeoffset, &oldlen); - if (!namep) - return oldlen; - - newlen = strlen (name); - - err = _fdt_splice_struct (fdt, namep, FDT_TAGALIGN (oldlen + 1), - FDT_TAGALIGN (newlen + 1)); - if (err) - return err; - - memcpy (namep, name, newlen + 1); - return 0; -} - -int -fdt_setprop (void *fdt, int nodeoffset, const char *name, - const void *val, int len) -{ - struct fdt_property *prop; - int err; - - FDT_RW_CHECK_HEADER (fdt); - - err = _fdt_resize_property (fdt, nodeoffset, name, len, &prop); - if (err == -FDT_ERR_NOTFOUND) - err = _fdt_add_property (fdt, nodeoffset, name, len, &prop); - if (err) - return err; - - memcpy (prop->data, val, len); - return 0; -} - -int -fdt_delprop (void *fdt, int nodeoffset, const char *name) -{ - struct fdt_property *prop; - int len, proplen; - - FDT_RW_CHECK_HEADER (fdt); - - prop = fdt_get_property_w (fdt, nodeoffset, name, &len); - if (!prop) - return len; - - proplen = sizeof (*prop) + FDT_TAGALIGN (len); - return _fdt_splice_struct (fdt, prop, proplen, 0); -} - -int -fdt_add_subnode_namelen (void *fdt, int parentoffset, - const char *name, int namelen) -{ - struct fdt_node_header *nh; - int offset, nextoffset; - int nodelen; - int err; - uint32_t tag; - uint32_t *endtag; - - FDT_RW_CHECK_HEADER (fdt); - - offset = fdt_subnode_offset_namelen (fdt, parentoffset, name, namelen); - if (offset >= 0) - return -FDT_ERR_EXISTS; - else if (offset != -FDT_ERR_NOTFOUND) - return offset; - - /* Try to place the new node after the parent's properties */ - fdt_next_tag (fdt, parentoffset, &nextoffset); /* skip the BEGIN_NODE */ - do - { - offset = nextoffset; - tag = fdt_next_tag (fdt, offset, &nextoffset); - } - while ((tag == FDT_PROP) || (tag == FDT_NOP)); - - nh = _fdt_offset_ptr_w (fdt, offset); - nodelen = sizeof (*nh) + FDT_TAGALIGN (namelen + 1) + FDT_TAGSIZE; - - err = _fdt_splice_struct (fdt, nh, 0, nodelen); - if (err) - return err; - - nh->tag = cpu_to_fdt32 (FDT_BEGIN_NODE); - memset (nh->name, 0, FDT_TAGALIGN (namelen + 1)); - memcpy (nh->name, name, namelen); - endtag = (uint32_t *) ((char *) nh + nodelen - FDT_TAGSIZE); - *endtag = cpu_to_fdt32 (FDT_END_NODE); - - return offset; -} - -int -fdt_add_subnode (void *fdt, int parentoffset, const char *name) -{ - return fdt_add_subnode_namelen (fdt, parentoffset, name, strlen (name)); -} - -int -fdt_del_node (void *fdt, int nodeoffset) -{ - int endoffset; - - FDT_RW_CHECK_HEADER (fdt); - - endoffset = _fdt_node_end_offset (fdt, nodeoffset); - if (endoffset < 0) - return endoffset; - - return _fdt_splice_struct (fdt, _fdt_offset_ptr_w (fdt, nodeoffset), - endoffset - nodeoffset, 0); -} - -static void -_fdt_packblocks (const char *old, char *new, - int mem_rsv_size, int struct_size) -{ - int mem_rsv_off, struct_off, strings_off; - - mem_rsv_off = FDT_ALIGN (sizeof (struct fdt_header), 8); - struct_off = mem_rsv_off + mem_rsv_size; - strings_off = struct_off + struct_size; - - memmove (new + mem_rsv_off, old + fdt_off_mem_rsvmap (old), mem_rsv_size); - fdt_set_off_mem_rsvmap (new, mem_rsv_off); - - memmove (new + struct_off, old + fdt_off_dt_struct (old), struct_size); - fdt_set_off_dt_struct (new, struct_off); - fdt_set_size_dt_struct (new, struct_size); - - memmove (new + strings_off, old + fdt_off_dt_strings (old), - fdt_size_dt_strings (old)); - fdt_set_off_dt_strings (new, strings_off); - fdt_set_size_dt_strings (new, fdt_size_dt_strings (old)); -} - -int -fdt_open_into (const void *fdt, void *buf, int bufsize) -{ - int err; - int mem_rsv_size, struct_size; - int newsize; - const char *fdtstart = fdt; - const char *fdtend = fdtstart + fdt_totalsize (fdt); - char *tmp; - - FDT_CHECK_HEADER (fdt); - - mem_rsv_size = (fdt_num_mem_rsv (fdt) + 1) - * sizeof (struct fdt_reserve_entry); - - if (fdt_version (fdt) >= 17) - { - struct_size = fdt_size_dt_struct (fdt); - } - else - { - struct_size = 0; - while (fdt_next_tag (fdt, struct_size, &struct_size) != FDT_END) - ; - if (struct_size < 0) - return struct_size; - } - - if (!_fdt_blocks_misordered (fdt, mem_rsv_size, struct_size)) - { - /* no further work necessary */ - err = fdt_move (fdt, buf, bufsize); - if (err) - return err; - fdt_set_version (buf, 17); - fdt_set_size_dt_struct (buf, struct_size); - fdt_set_totalsize (buf, bufsize); - return 0; - } - - /* Need to reorder */ - newsize = FDT_ALIGN (sizeof (struct fdt_header), 8) + mem_rsv_size - + struct_size + fdt_size_dt_strings (fdt); - - if (bufsize < newsize) - return -FDT_ERR_NOSPACE; - - /* First attempt to build converted tree at beginning of buffer */ - tmp = buf; - /* But if that overlaps with the old tree... */ - if (((tmp + newsize) > fdtstart) && (tmp < fdtend)) - { - /* Try right after the old tree instead */ - tmp = (char *) (uintptr_t) fdtend; - if ((tmp + newsize) > ((char *) buf + bufsize)) - return -FDT_ERR_NOSPACE; - } - - _fdt_packblocks (fdt, tmp, mem_rsv_size, struct_size); - memmove (buf, tmp, newsize); - - fdt_set_magic (buf, FDT_MAGIC); - fdt_set_totalsize (buf, bufsize); - fdt_set_version (buf, 17); - fdt_set_last_comp_version (buf, 16); - fdt_set_boot_cpuid_phys (buf, fdt_boot_cpuid_phys (fdt)); - - return 0; -} - -int -fdt_pack (void *fdt) -{ - int mem_rsv_size; - - FDT_RW_CHECK_HEADER (fdt); - - mem_rsv_size = (fdt_num_mem_rsv (fdt) + 1) - * sizeof (struct fdt_reserve_entry); - _fdt_packblocks (fdt, fdt, mem_rsv_size, fdt_size_dt_struct (fdt)); - fdt_set_totalsize (fdt, _fdt_data_size (fdt)); - - return 0; -} diff --git a/grub-core/lib/dtc/libfdt/fdt_strerror.c b/grub-core/lib/dtc/libfdt/fdt_strerror.c deleted file mode 100644 index 2d8606bec..000000000 --- a/grub-core/lib/dtc/libfdt/fdt_strerror.c +++ /dev/null @@ -1,100 +0,0 @@ -/* - * libfdt - Flat Device Tree manipulation - * Copyright (C) 2006 David Gibson, IBM Corporation. - * - * libfdt is dual licensed: you can use it either under the terms of - * the GPL, or the BSD license, at your option. - * - * a) This library 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 library 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 library; if not, write to the Free - * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, - * MA 02110-1301 USA - * - * Alternatively, - * - * b) 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. - */ -#include "libfdt_env.h" - -#include -#include - -#include "libfdt_internal.h" - -struct fdt_errtabent -{ - const char *str; -}; - -#define FDT_ERRTABENT(val) \ - [(val)] = { .str = #val, } - -static struct fdt_errtabent fdt_errtable[] = { - FDT_ERRTABENT (FDT_ERR_NOTFOUND), - FDT_ERRTABENT (FDT_ERR_EXISTS), - FDT_ERRTABENT (FDT_ERR_NOSPACE), - - FDT_ERRTABENT (FDT_ERR_BADOFFSET), - FDT_ERRTABENT (FDT_ERR_BADPATH), - FDT_ERRTABENT (FDT_ERR_BADSTATE), - - FDT_ERRTABENT (FDT_ERR_TRUNCATED), - FDT_ERRTABENT (FDT_ERR_BADMAGIC), - FDT_ERRTABENT (FDT_ERR_BADVERSION), - FDT_ERRTABENT (FDT_ERR_BADSTRUCTURE), - FDT_ERRTABENT (FDT_ERR_BADLAYOUT), -}; - -#define FDT_ERRTABSIZE (sizeof(fdt_errtable) / sizeof(fdt_errtable[0])) - -const char * -fdt_strerror (int errval) -{ - if (errval > 0) - return ""; - else if (errval == 0) - return ""; - else if (errval > -FDT_ERRTABSIZE) - { - const char *s = fdt_errtable[-errval].str; - - if (s) - return s; - } - - return ""; -} diff --git a/grub-core/lib/dtc/libfdt/fdt_sw.c b/grub-core/lib/dtc/libfdt/fdt_sw.c deleted file mode 100644 index 86d1d7353..000000000 --- a/grub-core/lib/dtc/libfdt/fdt_sw.c +++ /dev/null @@ -1,267 +0,0 @@ -/* - * libfdt - Flat Device Tree manipulation - * Copyright (C) 2006 David Gibson, IBM Corporation. - * - * libfdt is dual licensed: you can use it either under the terms of - * the GPL, or the BSD license, at your option. - * - * a) This library 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 library 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 library; if not, write to the Free - * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, - * MA 02110-1301 USA - * - * Alternatively, - * - * b) 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. - */ -#include "libfdt_env.h" - -#include -#include - -#include "libfdt_internal.h" - -static int -_fdt_sw_check_header (void *fdt) -{ - if (fdt_magic (fdt) != FDT_SW_MAGIC) - return -FDT_ERR_BADMAGIC; - /* FIXME: should check more details about the header state */ - return 0; -} - -#define FDT_SW_CHECK_HEADER(fdt) \ - { \ - int err; \ - if ((err = _fdt_sw_check_header(fdt)) != 0) \ - return err; \ - } - -static void * -_fdt_grab_space (void *fdt, size_t len) -{ - int offset = fdt_size_dt_struct (fdt); - int spaceleft; - - spaceleft = fdt_totalsize (fdt) - fdt_off_dt_struct (fdt) - - fdt_size_dt_strings (fdt); - - if ((offset + len < offset) || (offset + len > spaceleft)) - return NULL; - - fdt_set_size_dt_struct (fdt, offset + len); - return _fdt_offset_ptr_w (fdt, offset); -} - -int -fdt_create (void *buf, int bufsize) -{ - void *fdt = buf; - - if (bufsize < sizeof (struct fdt_header)) - return -FDT_ERR_NOSPACE; - - memset (buf, 0, bufsize); - - fdt_set_magic (fdt, FDT_SW_MAGIC); - fdt_set_version (fdt, FDT_LAST_SUPPORTED_VERSION); - fdt_set_last_comp_version (fdt, FDT_FIRST_SUPPORTED_VERSION); - fdt_set_totalsize (fdt, bufsize); - - fdt_set_off_mem_rsvmap (fdt, FDT_ALIGN (sizeof (struct fdt_header), - sizeof (struct fdt_reserve_entry))); - fdt_set_off_dt_struct (fdt, fdt_off_mem_rsvmap (fdt)); - fdt_set_off_dt_strings (fdt, bufsize); - - return 0; -} - -int -fdt_add_reservemap_entry (void *fdt, uint64_t addr, uint64_t size) -{ - struct fdt_reserve_entry *re; - int offset; - - FDT_SW_CHECK_HEADER (fdt); - - if (fdt_size_dt_struct (fdt)) - return -FDT_ERR_BADSTATE; - - offset = fdt_off_dt_struct (fdt); - if ((offset + sizeof (*re)) > fdt_totalsize (fdt)) - return -FDT_ERR_NOSPACE; - - re = (struct fdt_reserve_entry *) ((char *) fdt + offset); - re->address = cpu_to_fdt64 (addr); - re->size = cpu_to_fdt64 (size); - - fdt_set_off_dt_struct (fdt, offset + sizeof (*re)); - - return 0; -} - -int -fdt_finish_reservemap (void *fdt) -{ - return fdt_add_reservemap_entry (fdt, 0, 0); -} - -int -fdt_begin_node (void *fdt, const char *name) -{ - struct fdt_node_header *nh; - int namelen = strlen (name) + 1; - - FDT_SW_CHECK_HEADER (fdt); - - nh = _fdt_grab_space (fdt, sizeof (*nh) + FDT_TAGALIGN (namelen)); - if (!nh) - return -FDT_ERR_NOSPACE; - - nh->tag = cpu_to_fdt32 (FDT_BEGIN_NODE); - memcpy (nh->name, name, namelen); - return 0; -} - -int -fdt_end_node (void *fdt) -{ - uint32_t *en; - - FDT_SW_CHECK_HEADER (fdt); - - en = _fdt_grab_space (fdt, FDT_TAGSIZE); - if (!en) - return -FDT_ERR_NOSPACE; - - *en = cpu_to_fdt32 (FDT_END_NODE); - return 0; -} - -static int -_fdt_find_add_string (void *fdt, const char *s) -{ - char *strtab = (char *) fdt + fdt_totalsize (fdt); - const char *p; - int strtabsize = fdt_size_dt_strings (fdt); - int len = strlen (s) + 1; - int struct_top, offset; - - p = _fdt_find_string (strtab - strtabsize, strtabsize, s); - if (p) - return p - strtab; - - /* Add it */ - offset = -strtabsize - len; - struct_top = fdt_off_dt_struct (fdt) + fdt_size_dt_struct (fdt); - if (fdt_totalsize (fdt) + offset < struct_top) - return 0; /* no more room */ - - memcpy (strtab + offset, s, len); - fdt_set_size_dt_strings (fdt, strtabsize + len); - return offset; -} - -int -fdt_property (void *fdt, const char *name, const void *val, int len) -{ - struct fdt_property *prop; - int nameoff; - - FDT_SW_CHECK_HEADER (fdt); - - nameoff = _fdt_find_add_string (fdt, name); - if (nameoff == 0) - return -FDT_ERR_NOSPACE; - - prop = _fdt_grab_space (fdt, sizeof (*prop) + FDT_TAGALIGN (len)); - if (!prop) - return -FDT_ERR_NOSPACE; - - prop->tag = cpu_to_fdt32 (FDT_PROP); - prop->nameoff = cpu_to_fdt32 (nameoff); - prop->len = cpu_to_fdt32 (len); - memcpy (prop->data, val, len); - return 0; -} - -int -fdt_finish (void *fdt) -{ - char *p = (char *) fdt; - uint32_t *end; - int oldstroffset, newstroffset; - uint32_t tag; - int offset, nextoffset; - - FDT_SW_CHECK_HEADER (fdt); - - /* Add terminator */ - end = _fdt_grab_space (fdt, sizeof (*end)); - if (!end) - return -FDT_ERR_NOSPACE; - *end = cpu_to_fdt32 (FDT_END); - - /* Relocate the string table */ - oldstroffset = fdt_totalsize (fdt) - fdt_size_dt_strings (fdt); - newstroffset = fdt_off_dt_struct (fdt) + fdt_size_dt_struct (fdt); - memmove (p + newstroffset, p + oldstroffset, fdt_size_dt_strings (fdt)); - fdt_set_off_dt_strings (fdt, newstroffset); - - /* Walk the structure, correcting string offsets */ - offset = 0; - while ((tag = fdt_next_tag (fdt, offset, &nextoffset)) != FDT_END) - { - if (tag == FDT_PROP) - { - struct fdt_property *prop = _fdt_offset_ptr_w (fdt, offset); - int nameoff; - - nameoff = fdt32_to_cpu (prop->nameoff); - nameoff += fdt_size_dt_strings (fdt); - prop->nameoff = cpu_to_fdt32 (nameoff); - } - offset = nextoffset; - } - if (nextoffset < 0) - return nextoffset; - - /* Finally, adjust the header */ - fdt_set_totalsize (fdt, newstroffset + fdt_size_dt_strings (fdt)); - fdt_set_magic (fdt, FDT_MAGIC); - return 0; -} diff --git a/grub-core/lib/dtc/libfdt/fdt_wip.c b/grub-core/lib/dtc/libfdt/fdt_wip.c deleted file mode 100644 index 09297d9a6..000000000 --- a/grub-core/lib/dtc/libfdt/fdt_wip.c +++ /dev/null @@ -1,123 +0,0 @@ -/* - * libfdt - Flat Device Tree manipulation - * Copyright (C) 2006 David Gibson, IBM Corporation. - * - * libfdt is dual licensed: you can use it either under the terms of - * the GPL, or the BSD license, at your option. - * - * a) This library 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 library 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 library; if not, write to the Free - * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, - * MA 02110-1301 USA - * - * Alternatively, - * - * b) 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. - */ -#include "libfdt_env.h" - -#include -#include - -#include "libfdt_internal.h" - -int -fdt_setprop_inplace (void *fdt, int nodeoffset, const char *name, - const void *val, int len) -{ - void *propval; - int proplen; - - propval = fdt_getprop_w (fdt, nodeoffset, name, &proplen); - if (!propval) - return proplen; - - if (proplen != len) - return -FDT_ERR_NOSPACE; - - memcpy (propval, val, len); - return 0; -} - -static void -_fdt_nop_region (void *start, int len) -{ - uint32_t *p; - - for (p = start; (char *) p < ((char *) start + len); p++) - *p = cpu_to_fdt32 (FDT_NOP); -} - -int -fdt_nop_property (void *fdt, int nodeoffset, const char *name) -{ - struct fdt_property *prop; - int len; - - prop = fdt_get_property_w (fdt, nodeoffset, name, &len); - if (!prop) - return len; - - _fdt_nop_region (prop, len + sizeof (*prop)); - - return 0; -} - -int -_fdt_node_end_offset (void *fdt, int offset) -{ - int depth = 0; - - while ((offset >= 0) && (depth >= 0)) - offset = fdt_next_node (fdt, offset, &depth); - - return offset; -} - -int -fdt_nop_node (void *fdt, int nodeoffset) -{ - int endoffset; - - endoffset = _fdt_node_end_offset (fdt, nodeoffset); - if (endoffset < 0) - return endoffset; - - _fdt_nop_region (fdt_offset_ptr_w (fdt, nodeoffset, 0), - endoffset - nodeoffset); - return 0; -} diff --git a/grub-core/lib/dtc/libfdt/libfdt.h b/grub-core/lib/dtc/libfdt/libfdt.h deleted file mode 100644 index 6b9bfb5dc..000000000 --- a/grub-core/lib/dtc/libfdt/libfdt.h +++ /dev/null @@ -1,1239 +0,0 @@ -#ifndef _LIBFDT_H -#define _LIBFDT_H -/* - * libfdt - Flat Device Tree manipulation - * Copyright (C) 2006 David Gibson, IBM Corporation. - * - * libfdt is dual licensed: you can use it either under the terms of - * the GPL, or the BSD license, at your option. - * - * a) This library 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 library 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 library; if not, write to the Free - * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, - * MA 02110-1301 USA - * - * Alternatively, - * - * b) 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. - */ - -#include -#include - -#define FDT_FIRST_SUPPORTED_VERSION 0x10 -#define FDT_LAST_SUPPORTED_VERSION 0x11 - -/* Error codes: informative error codes */ -#define FDT_ERR_NOTFOUND 1 - /* FDT_ERR_NOTFOUND: The requested node or property does not exist */ -#define FDT_ERR_EXISTS 2 - /* FDT_ERR_EXISTS: Attemped to create a node or property which - * already exists */ -#define FDT_ERR_NOSPACE 3 - /* FDT_ERR_NOSPACE: Operation needed to expand the device - * tree, but its buffer did not have sufficient space to - * contain the expanded tree. Use fdt_open_into() to move the - * device tree to a buffer with more space. */ - -/* Error codes: codes for bad parameters */ -#define FDT_ERR_BADOFFSET 4 - /* FDT_ERR_BADOFFSET: Function was passed a structure block - * offset which is out-of-bounds, or which points to an - * unsuitable part of the structure for the operation. */ -#define FDT_ERR_BADPATH 5 - /* FDT_ERR_BADPATH: Function was passed a badly formatted path - * (e.g. missing a leading / for a function which requires an - * absolute path) */ -#define FDT_ERR_BADPHANDLE 6 - /* FDT_ERR_BADPHANDLE: Function was passed an invalid phandle - * value. phandle values of 0 and -1 are not permitted. */ -#define FDT_ERR_BADSTATE 7 - /* FDT_ERR_BADSTATE: Function was passed an incomplete device - * tree created by the sequential-write functions, which is - * not sufficiently complete for the requested operation. */ - -/* Error codes: codes for bad device tree blobs */ -#define FDT_ERR_TRUNCATED 8 - /* FDT_ERR_TRUNCATED: Structure block of the given device tree - * ends without an FDT_END tag. */ -#define FDT_ERR_BADMAGIC 9 - /* FDT_ERR_BADMAGIC: Given "device tree" appears not to be a - * device tree at all - it is missing the flattened device - * tree magic number. */ -#define FDT_ERR_BADVERSION 10 - /* FDT_ERR_BADVERSION: Given device tree has a version which - * can't be handled by the requested operation. For - * read-write functions, this may mean that fdt_open_into() is - * required to convert the tree to the expected version. */ -#define FDT_ERR_BADSTRUCTURE 11 - /* FDT_ERR_BADSTRUCTURE: Given device tree has a corrupt - * structure block or other serious error (e.g. misnested - * nodes, or subnodes preceding properties). */ -#define FDT_ERR_BADLAYOUT 12 - /* FDT_ERR_BADLAYOUT: For read-write functions, the given - * device tree has it's sub-blocks in an order that the - * function can't handle (memory reserve map, then structure, - * then strings). Use fdt_open_into() to reorganize the tree - * into a form suitable for the read-write operations. */ - -/* "Can't happen" error indicating a bug in libfdt */ -#define FDT_ERR_INTERNAL 13 - /* FDT_ERR_INTERNAL: libfdt has failed an internal assertion. - * Should never be returned, if it is, it indicates a bug in - * libfdt itself. */ - -#define FDT_ERR_MAX 13 - -/**********************************************************************/ -/* Low-level functions (you probably don't need these) */ -/**********************************************************************/ - -const void *fdt_offset_ptr (const void *fdt, int offset, - unsigned int checklen); -static inline void * -fdt_offset_ptr_w (void *fdt, int offset, int checklen) -{ - return (void *) (uintptr_t) fdt_offset_ptr (fdt, offset, checklen); -} - -uint32_t fdt_next_tag (const void *fdt, int offset, int *nextoffset); - -/**********************************************************************/ -/* Traversal functions */ -/**********************************************************************/ - -int fdt_next_node (const void *fdt, int offset, int *depth); - -/**********************************************************************/ -/* General functions */ -/**********************************************************************/ - -#define fdt_get_header(fdt, field) \ - (fdt32_to_cpu(((const struct fdt_header *)(fdt))->field)) -#define fdt_magic(fdt) (fdt_get_header(fdt, magic)) -#define fdt_totalsize(fdt) (fdt_get_header(fdt, totalsize)) -#define fdt_off_dt_struct(fdt) (fdt_get_header(fdt, off_dt_struct)) -#define fdt_off_dt_strings(fdt) (fdt_get_header(fdt, off_dt_strings)) -#define fdt_off_mem_rsvmap(fdt) (fdt_get_header(fdt, off_mem_rsvmap)) -#define fdt_version(fdt) (fdt_get_header(fdt, version)) -#define fdt_last_comp_version(fdt) (fdt_get_header(fdt, last_comp_version)) -#define fdt_boot_cpuid_phys(fdt) (fdt_get_header(fdt, boot_cpuid_phys)) -#define fdt_size_dt_strings(fdt) (fdt_get_header(fdt, size_dt_strings)) -#define fdt_size_dt_struct(fdt) (fdt_get_header(fdt, size_dt_struct)) - -#define __fdt_set_hdr(name) \ - static inline void fdt_set_##name(void *fdt, uint32_t val) \ - { \ - struct fdt_header *fdth = (struct fdt_header*)fdt; \ - fdth->name = cpu_to_fdt32(val); \ - } -__fdt_set_hdr (magic); -__fdt_set_hdr (totalsize); -__fdt_set_hdr (off_dt_struct); -__fdt_set_hdr (off_dt_strings); -__fdt_set_hdr (off_mem_rsvmap); -__fdt_set_hdr (version); -__fdt_set_hdr (last_comp_version); -__fdt_set_hdr (boot_cpuid_phys); -__fdt_set_hdr (size_dt_strings); -__fdt_set_hdr (size_dt_struct); -#undef __fdt_set_hdr - -/** - * fdt_check_header - sanity check a device tree or possible device tree - * @fdt: pointer to data which might be a flattened device tree - * - * fdt_check_header() checks that the given buffer contains what - * appears to be a flattened device tree with sane information in its - * header. - * - * returns: - * 0, if the buffer appears to contain a valid device tree - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, standard meanings, as above - */ -int fdt_check_header (const void *fdt); - -/** - * fdt_move - move a device tree around in memory - * @fdt: pointer to the device tree to move - * @buf: pointer to memory where the device is to be moved - * @bufsize: size of the memory space at buf - * - * fdt_move() relocates, if possible, the device tree blob located at - * fdt to the buffer at buf of size bufsize. The buffer may overlap - * with the existing device tree blob at fdt. Therefore, - * fdt_move(fdt, fdt, fdt_totalsize(fdt)) - * should always succeed. - * - * returns: - * 0, on success - * -FDT_ERR_NOSPACE, bufsize is insufficient to contain the device tree - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, standard meanings - */ -int fdt_move (const void *fdt, void *buf, int bufsize); - -/**********************************************************************/ -/* Read-only functions */ -/**********************************************************************/ - -/** - * fdt_string - retrieve a string from the strings block of a device tree - * @fdt: pointer to the device tree blob - * @stroffset: offset of the string within the strings block (native endian) - * - * fdt_string() retrieves a pointer to a single string from the - * strings block of the device tree blob at fdt. - * - * returns: - * a pointer to the string, on success - * NULL, if stroffset is out of bounds - */ -const char *fdt_string (const void *fdt, int stroffset); - -/** - * fdt_num_mem_rsv - retrieve the number of memory reserve map entries - * @fdt: pointer to the device tree blob - * - * Returns the number of entries in the device tree blob's memory - * reservation map. This does not include the terminating 0,0 entry - * or any other (0,0) entries reserved for expansion. - * - * returns: - * the number of entries - */ -int fdt_num_mem_rsv (const void *fdt); - -/** - * fdt_get_mem_rsv - retrieve one memory reserve map entry - * @fdt: pointer to the device tree blob - * @address, @size: pointers to 64-bit variables - * - * On success, *address and *size will contain the address and size of - * the n-th reserve map entry from the device tree blob, in - * native-endian format. - * - * returns: - * 0, on success - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, standard meanings - */ -int fdt_get_mem_rsv (const void *fdt, int n, uint64_t * address, - uint64_t * size); - -/** - * fdt_subnode_offset_namelen - find a subnode based on substring - * @fdt: pointer to the device tree blob - * @parentoffset: structure block offset of a node - * @name: name of the subnode to locate - * @namelen: number of characters of name to consider - * - * Identical to fdt_subnode_offset(), but only examine the first - * namelen characters of name for matching the subnode name. This is - * useful for finding subnodes based on a portion of a larger string, - * such as a full path. - */ -int fdt_subnode_offset_namelen (const void *fdt, int parentoffset, - const char *name, int namelen); -/** - * fdt_subnode_offset - find a subnode of a given node - * @fdt: pointer to the device tree blob - * @parentoffset: structure block offset of a node - * @name: name of the subnode to locate - * - * fdt_subnode_offset() finds a subnode of the node at structure block - * offset parentoffset with the given name. name may include a unit - * address, in which case fdt_subnode_offset() will find the subnode - * with that unit address, or the unit address may be omitted, in - * which case fdt_subnode_offset() will find an arbitrary subnode - * whose name excluding unit address matches the given name. - * - * returns: - * structure block offset of the requested subnode (>=0), on success - * -FDT_ERR_NOTFOUND, if the requested subnode does not exist - * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings. - */ -int fdt_subnode_offset (const void *fdt, int parentoffset, const char *name); - -/** - * fdt_path_offset - find a tree node by its full path - * @fdt: pointer to the device tree blob - * @path: full path of the node to locate - * - * fdt_path_offset() finds a node of a given path in the device tree. - * Each path component may omit the unit address portion, but the - * results of this are undefined if any such path component is - * ambiguous (that is if there are multiple nodes at the relevant - * level matching the given component, differentiated only by unit - * address). - * - * returns: - * structure block offset of the node with the requested path (>=0), on success - * -FDT_ERR_BADPATH, given path does not begin with '/' or is invalid - * -FDT_ERR_NOTFOUND, if the requested node does not exist - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings. - */ -int fdt_path_offset (const void *fdt, const char *path); - -/** - * fdt_get_name - retrieve the name of a given node - * @fdt: pointer to the device tree blob - * @nodeoffset: structure block offset of the starting node - * @lenp: pointer to an integer variable (will be overwritten) or NULL - * - * fdt_get_name() retrieves the name (including unit address) of the - * device tree node at structure block offset nodeoffset. If lenp is - * non-NULL, the length of this name is also returned, in the integer - * pointed to by lenp. - * - * returns: - * pointer to the node's name, on success - * If lenp is non-NULL, *lenp contains the length of that name (>=0) - * NULL, on error - * if lenp is non-NULL *lenp contains an error code (<0): - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, standard meanings - */ -const char *fdt_get_name (const void *fdt, int nodeoffset, int *lenp); - -/** - * fdt_first_property_offset - find the offset of a node's first property - * @fdt: pointer to the device tree blob - * @nodeoffset: structure block offset of a node - * - * fdt_first_property_offset() finds the first property of the node at - * the given structure block offset. - * - * returns: - * structure block offset of the property (>=0), on success - * -FDT_ERR_NOTFOUND, if the requested node has no properties - * -FDT_ERR_BADOFFSET, if nodeoffset did not point to an FDT_BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings. - */ -int fdt_first_property_offset (const void *fdt, int nodeoffset); - -/** - * fdt_next_property_offset - step through a node's properties - * @fdt: pointer to the device tree blob - * @offset: structure block offset of a property - * - * fdt_next_property_offset() finds the property immediately after the - * one at the given structure block offset. This will be a property - * of the same node as the given property. - * - * returns: - * structure block offset of the next property (>=0), on success - * -FDT_ERR_NOTFOUND, if the given property is the last in its node - * -FDT_ERR_BADOFFSET, if nodeoffset did not point to an FDT_PROP tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings. - */ -int fdt_next_property_offset (const void *fdt, int offset); - -/** - * fdt_get_property_by_offset - retrieve the property at a given offset - * @fdt: pointer to the device tree blob - * @offset: offset of the property to retrieve - * @lenp: pointer to an integer variable (will be overwritten) or NULL - * - * fdt_get_property_by_offset() retrieves a pointer to the - * fdt_property structure within the device tree blob at the given - * offset. If lenp is non-NULL, the length of the property value is - * also returned, in the integer pointed to by lenp. - * - * returns: - * pointer to the structure representing the property - * if lenp is non-NULL, *lenp contains the length of the property - * value (>=0) - * NULL, on error - * if lenp is non-NULL, *lenp contains an error code (<0): - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_PROP tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings - */ -const struct fdt_property *fdt_get_property_by_offset (const void *fdt, - int offset, int *lenp); - -/** - * fdt_get_property_namelen - find a property based on substring - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose property to find - * @name: name of the property to find - * @namelen: number of characters of name to consider - * @lenp: pointer to an integer variable (will be overwritten) or NULL - * - * Identical to fdt_get_property_namelen(), but only examine the first - * namelen characters of name for matching the property name. - */ -const struct fdt_property *fdt_get_property_namelen (const void *fdt, - int nodeoffset, - const char *name, - int namelen, int *lenp); - -/** - * fdt_get_property - find a given property in a given node - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose property to find - * @name: name of the property to find - * @lenp: pointer to an integer variable (will be overwritten) or NULL - * - * fdt_get_property() retrieves a pointer to the fdt_property - * structure within the device tree blob corresponding to the property - * named 'name' of the node at offset nodeoffset. If lenp is - * non-NULL, the length of the property value is also returned, in the - * integer pointed to by lenp. - * - * returns: - * pointer to the structure representing the property - * if lenp is non-NULL, *lenp contains the length of the property - * value (>=0) - * NULL, on error - * if lenp is non-NULL, *lenp contains an error code (<0): - * -FDT_ERR_NOTFOUND, node does not have named property - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings - */ -const struct fdt_property *fdt_get_property (const void *fdt, int nodeoffset, - const char *name, int *lenp); -static inline struct fdt_property * -fdt_get_property_w (void *fdt, int nodeoffset, const char *name, int *lenp) -{ - return (struct fdt_property *) (uintptr_t) - fdt_get_property (fdt, nodeoffset, name, lenp); -} - -/** - * fdt_getprop_by_offset - retrieve the value of a property at a given offset - * @fdt: pointer to the device tree blob - * @ffset: offset of the property to read - * @namep: pointer to a string variable (will be overwritten) or NULL - * @lenp: pointer to an integer variable (will be overwritten) or NULL - * - * fdt_getprop_by_offset() retrieves a pointer to the value of the - * property at structure block offset 'offset' (this will be a pointer - * to within the device blob itself, not a copy of the value). If - * lenp is non-NULL, the length of the property value is also - * returned, in the integer pointed to by lenp. If namep is non-NULL, - * the property's namne will also be returned in the char * pointed to - * by namep (this will be a pointer to within the device tree's string - * block, not a new copy of the name). - * - * returns: - * pointer to the property's value - * if lenp is non-NULL, *lenp contains the length of the property - * value (>=0) - * if namep is non-NULL *namep contiains a pointer to the property - * name. - * NULL, on error - * if lenp is non-NULL, *lenp contains an error code (<0): - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_PROP tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings - */ -const void *fdt_getprop_by_offset (const void *fdt, int offset, - const char **namep, int *lenp); - -/** - * fdt_getprop_namelen - get property value based on substring - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose property to find - * @name: name of the property to find - * @namelen: number of characters of name to consider - * @lenp: pointer to an integer variable (will be overwritten) or NULL - * - * Identical to fdt_getprop(), but only examine the first namelen - * characters of name for matching the property name. - */ -const void *fdt_getprop_namelen (const void *fdt, int nodeoffset, - const char *name, int namelen, int *lenp); - -/** - * fdt_getprop - retrieve the value of a given property - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose property to find - * @name: name of the property to find - * @lenp: pointer to an integer variable (will be overwritten) or NULL - * - * fdt_getprop() retrieves a pointer to the value of the property - * named 'name' of the node at offset nodeoffset (this will be a - * pointer to within the device blob itself, not a copy of the value). - * If lenp is non-NULL, the length of the property value is also - * returned, in the integer pointed to by lenp. - * - * returns: - * pointer to the property's value - * if lenp is non-NULL, *lenp contains the length of the property - * value (>=0) - * NULL, on error - * if lenp is non-NULL, *lenp contains an error code (<0): - * -FDT_ERR_NOTFOUND, node does not have named property - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings - */ -const void *fdt_getprop (const void *fdt, int nodeoffset, - const char *name, int *lenp); -static inline void * -fdt_getprop_w (void *fdt, int nodeoffset, const char *name, int *lenp) -{ - return (void *) (uintptr_t) fdt_getprop (fdt, nodeoffset, name, lenp); -} - -/** - * fdt_get_phandle - retrieve the phandle of a given node - * @fdt: pointer to the device tree blob - * @nodeoffset: structure block offset of the node - * - * fdt_get_phandle() retrieves the phandle of the device tree node at - * structure block offset nodeoffset. - * - * returns: - * the phandle of the node at nodeoffset, on success (!= 0, != -1) - * 0, if the node has no phandle, or another error occurs - */ -uint32_t fdt_get_phandle (const void *fdt, int nodeoffset); - -/** - * fdt_get_alias_namelen - get alias based on substring - * @fdt: pointer to the device tree blob - * @name: name of the alias th look up - * @namelen: number of characters of name to consider - * - * Identical to fdt_get_alias(), but only examine the first namelen - * characters of name for matching the alias name. - */ -const char *fdt_get_alias_namelen (const void *fdt, - const char *name, int namelen); - -/** - * fdt_get_alias - retreive the path referenced by a given alias - * @fdt: pointer to the device tree blob - * @name: name of the alias th look up - * - * fdt_get_alias() retrieves the value of a given alias. That is, the - * value of the property named 'name' in the node /aliases. - * - * returns: - * a pointer to the expansion of the alias named 'name', of it exists - * NULL, if the given alias or the /aliases node does not exist - */ -const char *fdt_get_alias (const void *fdt, const char *name); - -/** - * fdt_get_path - determine the full path of a node - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose path to find - * @buf: character buffer to contain the returned path (will be overwritten) - * @buflen: size of the character buffer at buf - * - * fdt_get_path() computes the full path of the node at offset - * nodeoffset, and records that path in the buffer at buf. - * - * NOTE: This function is expensive, as it must scan the device tree - * structure from the start to nodeoffset. - * - * returns: - * 0, on success - * buf contains the absolute path of the node at - * nodeoffset, as a NUL-terminated string. - * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag - * -FDT_ERR_NOSPACE, the path of the given node is longer than (bufsize-1) - * characters and will not fit in the given buffer. - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, standard meanings - */ -int fdt_get_path (const void *fdt, int nodeoffset, char *buf, int buflen); - -/** - * fdt_supernode_atdepth_offset - find a specific ancestor of a node - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose parent to find - * @supernodedepth: depth of the ancestor to find - * @nodedepth: pointer to an integer variable (will be overwritten) or NULL - * - * fdt_supernode_atdepth_offset() finds an ancestor of the given node - * at a specific depth from the root (where the root itself has depth - * 0, its immediate subnodes depth 1 and so forth). So - * fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, NULL); - * will always return 0, the offset of the root node. If the node at - * nodeoffset has depth D, then: - * fdt_supernode_atdepth_offset(fdt, nodeoffset, D, NULL); - * will return nodeoffset itself. - * - * NOTE: This function is expensive, as it must scan the device tree - * structure from the start to nodeoffset. - * - * returns: - - * structure block offset of the node at node offset's ancestor - * of depth supernodedepth (>=0), on success - * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag -* -FDT_ERR_NOTFOUND, supernodedepth was greater than the depth of nodeoffset - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, standard meanings - */ -int fdt_supernode_atdepth_offset (const void *fdt, int nodeoffset, - int supernodedepth, int *nodedepth); - -/** - * fdt_node_depth - find the depth of a given node - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose parent to find - * - * fdt_node_depth() finds the depth of a given node. The root node - * has depth 0, its immediate subnodes depth 1 and so forth. - * - * NOTE: This function is expensive, as it must scan the device tree - * structure from the start to nodeoffset. - * - * returns: - * depth of the node at nodeoffset (>=0), on success - * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, standard meanings - */ -int fdt_node_depth (const void *fdt, int nodeoffset); - -/** - * fdt_parent_offset - find the parent of a given node - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose parent to find - * - * fdt_parent_offset() locates the parent node of a given node (that - * is, it finds the offset of the node which contains the node at - * nodeoffset as a subnode). - * - * NOTE: This function is expensive, as it must scan the device tree - * structure from the start to nodeoffset, *twice*. - * - * returns: - * structure block offset of the parent of the node at nodeoffset - * (>=0), on success - * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, standard meanings - */ -int fdt_parent_offset (const void *fdt, int nodeoffset); - -/** - * fdt_node_offset_by_prop_value - find nodes with a given property value - * @fdt: pointer to the device tree blob - * @startoffset: only find nodes after this offset - * @propname: property name to check - * @propval: property value to search for - * @proplen: length of the value in propval - * - * fdt_node_offset_by_prop_value() returns the offset of the first - * node after startoffset, which has a property named propname whose - * value is of length proplen and has value equal to propval; or if - * startoffset is -1, the very first such node in the tree. - * - * To iterate through all nodes matching the criterion, the following - * idiom can be used: - * offset = fdt_node_offset_by_prop_value(fdt, -1, propname, - * propval, proplen); - * while (offset != -FDT_ERR_NOTFOUND) { - * // other code here - * offset = fdt_node_offset_by_prop_value(fdt, offset, propname, - * propval, proplen); - * } - * - * Note the -1 in the first call to the function, if 0 is used here - * instead, the function will never locate the root node, even if it - * matches the criterion. - * - * returns: - * structure block offset of the located node (>= 0, >startoffset), - * on success - * -FDT_ERR_NOTFOUND, no node matching the criterion exists in the - * tree after startoffset - * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, standard meanings - */ -int fdt_node_offset_by_prop_value (const void *fdt, int startoffset, - const char *propname, - const void *propval, int proplen); - -/** - * fdt_node_offset_by_phandle - find the node with a given phandle - * @fdt: pointer to the device tree blob - * @phandle: phandle value - * - * fdt_node_offset_by_phandle() returns the offset of the node - * which has the given phandle value. If there is more than one node - * in the tree with the given phandle (an invalid tree), results are - * undefined. - * - * returns: - * structure block offset of the located node (>= 0), on success - * -FDT_ERR_NOTFOUND, no node with that phandle exists - * -FDT_ERR_BADPHANDLE, given phandle value was invalid (0 or -1) - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, standard meanings - */ -int fdt_node_offset_by_phandle (const void *fdt, uint32_t phandle); - -/** - * fdt_node_check_compatible: check a node's compatible property - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of a tree node - * @compatible: string to match against - * - * - * fdt_node_check_compatible() returns 0 if the given node contains a - * 'compatible' property with the given string as one of its elements, - * it returns non-zero otherwise, or on error. - * - * returns: - * 0, if the node has a 'compatible' property listing the given string - * 1, if the node has a 'compatible' property, but it does not list - * the given string - * -FDT_ERR_NOTFOUND, if the given node has no 'compatible' property - * -FDT_ERR_BADOFFSET, if nodeoffset does not refer to a BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, standard meanings - */ -int fdt_node_check_compatible (const void *fdt, int nodeoffset, - const char *compatible); - -/** - * fdt_node_offset_by_compatible - find nodes with a given 'compatible' value - * @fdt: pointer to the device tree blob - * @startoffset: only find nodes after this offset - * @compatible: 'compatible' string to match against - * - * fdt_node_offset_by_compatible() returns the offset of the first - * node after startoffset, which has a 'compatible' property which - * lists the given compatible string; or if startoffset is -1, the - * very first such node in the tree. - * - * To iterate through all nodes matching the criterion, the following - * idiom can be used: - * offset = fdt_node_offset_by_compatible(fdt, -1, compatible); - * while (offset != -FDT_ERR_NOTFOUND) { - * // other code here - * offset = fdt_node_offset_by_compatible(fdt, offset, compatible); - * } - * - * Note the -1 in the first call to the function, if 0 is used here - * instead, the function will never locate the root node, even if it - * matches the criterion. - * - * returns: - * structure block offset of the located node (>= 0, >startoffset), - * on success - * -FDT_ERR_NOTFOUND, no node matching the criterion exists in the - * tree after startoffset - * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, standard meanings - */ -int fdt_node_offset_by_compatible (const void *fdt, int startoffset, - const char *compatible); - -/**********************************************************************/ -/* Write-in-place functions */ -/**********************************************************************/ - -/** - * fdt_setprop_inplace - change a property's value, but not its size - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose property to change - * @name: name of the property to change - * @val: pointer to data to replace the property value with - * @len: length of the property value - * - * fdt_setprop_inplace() replaces the value of a given property with - * the data in val, of length len. This function cannot change the - * size of a property, and so will only work if len is equal to the - * current length of the property. - * - * This function will alter only the bytes in the blob which contain - * the given property value, and will not alter or move any other part - * of the tree. - * - * returns: - * 0, on success - * -FDT_ERR_NOSPACE, if len is not equal to the property's current length - * -FDT_ERR_NOTFOUND, node does not have the named property - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings - */ -int fdt_setprop_inplace (void *fdt, int nodeoffset, const char *name, - const void *val, int len); - -/** - * fdt_setprop_inplace_cell - change the value of a single-cell property - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose property to change - * @name: name of the property to change - * @val: cell (32-bit integer) value to replace the property with - * - * fdt_setprop_inplace_cell() replaces the value of a given property - * with the 32-bit integer cell value in val, converting val to - * big-endian if necessary. This function cannot change the size of a - * property, and so will only work if the property already exists and - * has length 4. - * - * This function will alter only the bytes in the blob which contain - * the given property value, and will not alter or move any other part - * of the tree. - * - * returns: - * 0, on success - * -FDT_ERR_NOSPACE, if the property's length is not equal to 4 - * -FDT_ERR_NOTFOUND, node does not have the named property - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings - */ -static inline int -fdt_setprop_inplace_cell (void *fdt, int nodeoffset, - const char *name, uint32_t val) -{ - val = cpu_to_fdt32 (val); - return fdt_setprop_inplace (fdt, nodeoffset, name, &val, sizeof (val)); -} - -/** - * fdt_nop_property - replace a property with nop tags - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose property to nop - * @name: name of the property to nop - * - * fdt_nop_property() will replace a given property's representation - * in the blob with FDT_NOP tags, effectively removing it from the - * tree. - * - * This function will alter only the bytes in the blob which contain - * the property, and will not alter or move any other part of the - * tree. - * - * returns: - * 0, on success - * -FDT_ERR_NOTFOUND, node does not have the named property - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings - */ -int fdt_nop_property (void *fdt, int nodeoffset, const char *name); - -/** - * fdt_nop_node - replace a node (subtree) with nop tags - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node to nop - * - * fdt_nop_node() will replace a given node's representation in the - * blob, including all its subnodes, if any, with FDT_NOP tags, - * effectively removing it from the tree. - * - * This function will alter only the bytes in the blob which contain - * the node and its properties and subnodes, and will not alter or - * move any other part of the tree. - * - * returns: - * 0, on success - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings - */ -int fdt_nop_node (void *fdt, int nodeoffset); - -/**********************************************************************/ -/* Sequential write functions */ -/**********************************************************************/ - -int fdt_create (void *buf, int bufsize); -int fdt_add_reservemap_entry (void *fdt, uint64_t addr, uint64_t size); -int fdt_finish_reservemap (void *fdt); -int fdt_begin_node (void *fdt, const char *name); -int fdt_property (void *fdt, const char *name, const void *val, int len); -static inline int -fdt_property_cell (void *fdt, const char *name, uint32_t val) -{ - val = cpu_to_fdt32 (val); - return fdt_property (fdt, name, &val, sizeof (val)); -} - -#define fdt_property_string(fdt, name, str) \ - fdt_property(fdt, name, str, strlen(str)+1) -int fdt_end_node (void *fdt); -int fdt_finish (void *fdt); - -/**********************************************************************/ -/* Read-write functions */ -/**********************************************************************/ - -int fdt_open_into (const void *fdt, void *buf, int bufsize); -int fdt_pack (void *fdt); - -/** - * fdt_add_mem_rsv - add one memory reserve map entry - * @fdt: pointer to the device tree blob - * @address, @size: 64-bit values (native endian) - * - * Adds a reserve map entry to the given blob reserving a region at - * address address of length size. - * - * This function will insert data into the reserve map and will - * therefore change the indexes of some entries in the table. - * - * returns: - * 0, on success - * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to - * contain the new reservation entry - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_TRUNCATED, standard meanings - */ -int fdt_add_mem_rsv (void *fdt, uint64_t address, uint64_t size); - -/** - * fdt_del_mem_rsv - remove a memory reserve map entry - * @fdt: pointer to the device tree blob - * @n: entry to remove - * - * fdt_del_mem_rsv() removes the n-th memory reserve map entry from - * the blob. - * - * This function will delete data from the reservation table and will - * therefore change the indexes of some entries in the table. - * - * returns: - * 0, on success - * -FDT_ERR_NOTFOUND, there is no entry of the given index (i.e. there - * are less than n+1 reserve map entries) - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_TRUNCATED, standard meanings - */ -int fdt_del_mem_rsv (void *fdt, int n); - -/** - * fdt_set_name - change the name of a given node - * @fdt: pointer to the device tree blob - * @nodeoffset: structure block offset of a node - * @name: name to give the node - * - * fdt_set_name() replaces the name (including unit address, if any) - * of the given node with the given string. NOTE: this function can't - * efficiently check if the new name is unique amongst the given - * node's siblings; results are undefined if this function is invoked - * with a name equal to one of the given node's siblings. - * - * This function may insert or delete data from the blob, and will - * therefore change the offsets of some existing nodes. - * - * returns: - * 0, on success - * -FDT_ERR_NOSPACE, there is insufficient free space in the blob - * to contain the new name - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, standard meanings - */ -int fdt_set_name (void *fdt, int nodeoffset, const char *name); - -/** - * fdt_setprop - create or change a property - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose property to change - * @name: name of the property to change - * @val: pointer to data to set the property value to - * @len: length of the property value - * - * fdt_setprop() sets the value of the named property in the given - * node to the given value and length, creating the property if it - * does not already exist. - * - * This function may insert or delete data from the blob, and will - * therefore change the offsets of some existing nodes. - * - * returns: - * 0, on success - * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to - * contain the new property value - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_TRUNCATED, standard meanings - */ -int fdt_setprop (void *fdt, int nodeoffset, const char *name, - const void *val, int len); - -/** - * fdt_setprop_cell - set a property to a single cell value - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose property to change - * @name: name of the property to change - * @val: 32-bit integer value for the property (native endian) - * - * fdt_setprop_cell() sets the value of the named property in the - * given node to the given cell value (converting to big-endian if - * necessary), or creates a new property with that value if it does - * not already exist. - * - * This function may insert or delete data from the blob, and will - * therefore change the offsets of some existing nodes. - * - * returns: - * 0, on success - * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to - * contain the new property value - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_TRUNCATED, standard meanings - */ -static inline int -fdt_setprop_cell (void *fdt, int nodeoffset, const char *name, uint32_t val) -{ - val = cpu_to_fdt32 (val); - return fdt_setprop (fdt, nodeoffset, name, &val, sizeof (val)); -} - -/** - * fdt_setprop_string - set a property to a string value - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose property to change - * @name: name of the property to change - * @str: string value for the property - * - * fdt_setprop_string() sets the value of the named property in the - * given node to the given string value (using the length of the - * string to determine the new length of the property), or creates a - * new property with that value if it does not already exist. - * - * This function may insert or delete data from the blob, and will - * therefore change the offsets of some existing nodes. - * - * returns: - * 0, on success - * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to - * contain the new property value - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_TRUNCATED, standard meanings - */ -#define fdt_setprop_string(fdt, nodeoffset, name, str) \ - fdt_setprop((fdt), (nodeoffset), (name), (str), strlen(str)+1) - -/** - * fdt_delprop - delete a property - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose property to nop - * @name: name of the property to nop - * - * fdt_del_property() will delete the given property. - * - * This function will delete data from the blob, and will therefore - * change the offsets of some existing nodes. - * - * returns: - * 0, on success - * -FDT_ERR_NOTFOUND, node does not have the named property - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings - */ -int fdt_delprop (void *fdt, int nodeoffset, const char *name); - -/** - * fdt_add_subnode_namelen - creates a new node based on substring - * @fdt: pointer to the device tree blob - * @parentoffset: structure block offset of a node - * @name: name of the subnode to locate - * @namelen: number of characters of name to consider - * - * Identical to fdt_add_subnode(), but use only the first namelen - * characters of name as the name of the new node. This is useful for - * creating subnodes based on a portion of a larger string, such as a - * full path. - */ -int fdt_add_subnode_namelen (void *fdt, int parentoffset, - const char *name, int namelen); - -/** - * fdt_add_subnode - creates a new node - * @fdt: pointer to the device tree blob - * @parentoffset: structure block offset of a node - * @name: name of the subnode to locate - * - * fdt_add_subnode() creates a new node as a subnode of the node at - * structure block offset parentoffset, with the given name (which - * should include the unit address, if any). - * - * This function will insert data into the blob, and will therefore - * change the offsets of some existing nodes. - - * returns: - * structure block offset of the created nodeequested subnode (>=0), on success - * -FDT_ERR_NOTFOUND, if the requested subnode does not exist - * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE tag - * -FDT_ERR_EXISTS, if the node at parentoffset already has a subnode of - * the given name - * -FDT_ERR_NOSPACE, if there is insufficient free space in the - * blob to contain the new node - * -FDT_ERR_NOSPACE - * -FDT_ERR_BADLAYOUT - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings. - */ -int fdt_add_subnode (void *fdt, int parentoffset, const char *name); - -/** - * fdt_del_node - delete a node (subtree) - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node to nop - * - * fdt_del_node() will remove the given node, including all its - * subnodes if any, from the blob. - * - * This function will delete data from the blob, and will therefore - * change the offsets of some existing nodes. - * - * returns: - * 0, on success - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings - */ -int fdt_del_node (void *fdt, int nodeoffset); - -/**********************************************************************/ -/* Debugging / informational functions */ -/**********************************************************************/ - -const char *fdt_strerror (int errval); - -#endif /* _LIBFDT_H */ diff --git a/grub-core/lib/dtc/libfdt/libfdt_env.h b/grub-core/lib/dtc/libfdt/libfdt_env.h deleted file mode 100644 index bf66ffd49..000000000 --- a/grub-core/lib/dtc/libfdt/libfdt_env.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef _LIBFDT_ENV_H -#define _LIBFDT_ENV_H - -#include -#include -#include - -#define _B(n) ((unsigned long long)((uint8_t *)&x)[n]) -static inline uint32_t -fdt32_to_cpu (uint32_t x) -{ - return (_B (0) << 24) | (_B (1) << 16) | (_B (2) << 8) | _B (3); -} - -#define cpu_to_fdt32(x) fdt32_to_cpu(x) - -static inline uint64_t -fdt64_to_cpu (uint64_t x) -{ - return (_B (0) << 56) | (_B (1) << 48) | (_B (2) << 40) | (_B (3) << 32) - | (_B (4) << 24) | (_B (5) << 16) | (_B (6) << 8) | _B (7); -} - -#define cpu_to_fdt64(x) fdt64_to_cpu(x) -#undef _B - -#endif /* _LIBFDT_ENV_H */ diff --git a/grub-core/lib/dtc/libfdt/libfdt_internal.h b/grub-core/lib/dtc/libfdt/libfdt_internal.h deleted file mode 100644 index b197032c8..000000000 --- a/grub-core/lib/dtc/libfdt/libfdt_internal.h +++ /dev/null @@ -1,100 +0,0 @@ -#ifndef _LIBFDT_INTERNAL_H -#define _LIBFDT_INTERNAL_H -/* - * libfdt - Flat Device Tree manipulation - * Copyright (C) 2006 David Gibson, IBM Corporation. - * - * libfdt is dual licensed: you can use it either under the terms of - * the GPL, or the BSD license, at your option. - * - * a) This library 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 library 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 library; if not, write to the Free - * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, - * MA 02110-1301 USA - * - * Alternatively, - * - * b) 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. - */ -#include - -#define FDT_ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) -#define FDT_TAGALIGN(x) (FDT_ALIGN((x), FDT_TAGSIZE)) - -#define FDT_CHECK_HEADER(fdt) \ - { \ - int err; \ - if ((err = fdt_check_header(fdt)) != 0) \ - return err; \ - } - -int _fdt_check_node_offset (const void *fdt, int offset); -int _fdt_check_prop_offset (const void *fdt, int offset); -const char *_fdt_find_string (const char *strtab, int tabsize, const char *s); -int _fdt_node_end_offset (void *fdt, int nodeoffset); - -static inline const void * -_fdt_offset_ptr (const void *fdt, int offset) -{ - return (const char *) fdt + fdt_off_dt_struct (fdt) + offset; -} - -static inline void * -_fdt_offset_ptr_w (void *fdt, int offset) -{ - return (void *) (uintptr_t) _fdt_offset_ptr (fdt, offset); -} - -static inline const struct fdt_reserve_entry * -_fdt_mem_rsv (const void *fdt, int n) -{ - const struct fdt_reserve_entry *rsv_table = - (const struct fdt_reserve_entry *) - ((const char *) fdt + fdt_off_mem_rsvmap (fdt)); - - return rsv_table + n; -} - -static inline struct fdt_reserve_entry * -_fdt_mem_rsv_w (void *fdt, int n) -{ - return (void *) (uintptr_t) _fdt_mem_rsv (fdt, n); -} - -#define FDT_SW_MAGIC (~FDT_MAGIC) - -#endif /* _LIBFDT_INTERNAL_H */ diff --git a/grub-core/lib/dtc/libfdt/version.lds b/grub-core/lib/dtc/libfdt/version.lds deleted file mode 100644 index 3c3994e27..000000000 --- a/grub-core/lib/dtc/libfdt/version.lds +++ /dev/null @@ -1,54 +0,0 @@ -LIBFDT_1.2 { - global: - fdt_next_node; - fdt_check_header; - fdt_move; - fdt_string; - fdt_num_mem_rsv; - fdt_get_mem_rsv; - fdt_subnode_offset_namelen; - fdt_subnode_offset; - fdt_path_offset; - fdt_get_name; - fdt_get_property_namelen; - fdt_get_property; - fdt_getprop_namelen; - fdt_getprop; - fdt_get_phandle; - fdt_get_alias_namelen; - fdt_get_alias; - fdt_get_path; - fdt_supernode_atdepth_offset; - fdt_node_depth; - fdt_parent_offset; - fdt_node_offset_by_prop_value; - fdt_node_offset_by_phandle; - fdt_node_check_compatible; - fdt_node_offset_by_compatible; - fdt_setprop_inplace; - fdt_nop_property; - fdt_nop_node; - fdt_create; - fdt_add_reservemap_entry; - fdt_finish_reservemap; - fdt_begin_node; - fdt_property; - fdt_end_node; - fdt_finish; - fdt_open_into; - fdt_pack; - fdt_add_mem_rsv; - fdt_del_mem_rsv; - fdt_set_name; - fdt_setprop; - fdt_delprop; - fdt_add_subnode_namelen; - fdt_add_subnode; - fdt_del_node; - fdt_strerror; - fdt_offset_ptr; - fdt_next_tag; - - local: - *; -}; diff --git a/util/import_libfdt.py b/util/import_libfdt.py deleted file mode 100644 index 752a42363..000000000 --- a/util/import_libfdt.py +++ /dev/null @@ -1,103 +0,0 @@ -#* -#* 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 . -#* - -import re -import sys -import os -import codecs -import datetime - -if len (sys.argv) < 3: - print ("Usage: %s SOURCE DESTINATION" % sys.argv[0]) - exit (0) -dtcdir = sys.argv[1] -indir = os.path.join (dtcdir, "libfdt/") -outdir = os.path.join (sys.argv[2], "lib/dtc-grub/libfdt/") -try: - os.makedirs (outdir) -except: - print ("WARNING: %s already exists" % outdir) - -conf = codecs.open (os.path.join ("grub-core/", "Makefile.libfdt.def"), "w", "utf-8") -conf.write ("AutoGen definitions Makefile.tpl;\n\n") -conf.write ("module = {\n") -conf.write (" name = fdt;\n") -conf.write (" common = lib/dtc-grub/libfdt/fdt.c;\n") -conf.write (" common = lib/dtc-grub/libfdt/fdt_ro.c;\n") -conf.write (" common = lib/dtc-grub/libfdt/fdt_rw.c;\n") -conf.write (" common = lib/dtc-grub/libfdt/fdt_strerror.c;\n") -conf.write (" common = lib/dtc-grub/libfdt/fdt_sw.c;\n") -conf.write (" common = lib/dtc-grub/libfdt/fdt_wip.c;\n") -conf.write (" cppflags = '$(CPPFLAGS_POSIX) $(CPPFLAGS_LIBFDT)';\n") -conf.write ("\n") -conf.write (" enable = fdt;\n") -conf.write ("};\n") - -conf.close (); - - -libfdt_files = sorted (os.listdir (indir)) -chlog = "" - -for libfdt_file in libfdt_files: - infile = os.path.join (indir, (libfdt_file)) - outfile = os.path.join (outdir, (libfdt_file)) - - if not re.match (".*\.[ch]$", libfdt_file): - chlog = "%s * %s: Removed\n" % (chlog, libfdt_file) - continue - -# print ("file: %s, infile: %s, outfile: %s" % (libfdt_file, infile, outfile)) - - f = codecs.open (infile, "r", "utf-8") - fw = codecs.open (outfile, "w", "utf-8") - - lineno = 1 - - fw.write ("/* This file was automatically imported with \n") - fw.write (" import_libfdt.py. Please don't modify it */\n") - fw.write ("#include \n") - - # libfdt is dual-licensed: BSD or GPLv2+ - if re.match (".*\.c$", libfdt_file): - fw.write ("GRUB_MOD_LICENSE (\"GPLv2+\");\n") - - lines = f.readlines() - - for line in lines: - fw.write (line) - - f.close () - fw.close () - -patchfile = os.path.join (dtcdir, "libfdt-grub.diff") -#print "Patchfile: %s\n" % patchfile -ret = os.system("patch -d %s -p1 < %s" % (outdir, patchfile)) -if ret: - chlog = "%s * Applied Grub build patch\n" % chlog - - -dt = datetime.date.today () -fw = codecs.open (os.path.join (outdir, "ImportLog"), "w", "utf-8") -fw.write ("%04d-%02d-%02d Automatic import tool\n" % \ - (dt.year,dt.month, dt.day)) -fw.write ("\n") -fw.write (" Imported libfdt to GRUB\n") -fw.write ("\n") -fw.write (chlog) -fw.close () From d60c9a81acb27a859ccfe7aebf83be42b30d4321 Mon Sep 17 00:00:00 2001 From: Francesco Lavra Date: Fri, 7 Jun 2013 16:56:24 +0200 Subject: [PATCH 24/25] Fix ARM cpuid probing --- grub-core/kern/arm/cache.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/grub-core/kern/arm/cache.c b/grub-core/kern/arm/cache.c index c1fa62ed4..88054f3fc 100644 --- a/grub-core/kern/arm/cache.c +++ b/grub-core/kern/arm/cache.c @@ -29,8 +29,7 @@ probe_caches (void) /* Read main ID Register */ asm volatile ("mrc p15, 0, %0, c0, c0, 0": "=r"(main_id)); - if (((main_id >> 12) & 0xf) == 0x0 || ((main_id >> 12) & 0xf) == 0x7 - || (((main_id >> 16) & 0x7) != 0x7)) + if (((main_id >> 16) & 0x7) != 0x7) grub_fatal ("Unsupported ARM ID 0x%x", main_id); /* Read Cache Type Register */ @@ -56,7 +55,7 @@ probe_caches (void) grub_arch_cache_ilinesz = 8 << (cache_type & 3); type = ARCH_ARMV6; break; - case 0x80 ... 0x9f: + case 0x80 ... 0x8f: grub_arch_cache_dlinesz = 4 << ((cache_type >> 16) & 0xf); grub_arch_cache_ilinesz = 4 << (cache_type & 0xf); type = ARCH_ARMV7; From bd744218c0a5beca37c02da99f3dae49f19c87a9 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Wed, 17 Jul 2013 19:03:11 +0200 Subject: [PATCH 25/25] Fix arm-uboot compilation problem --- grub-core/Makefile.core.def | 2 ++ 1 file changed, 2 insertions(+) diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index 56447b30e..06617d79a 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -696,6 +696,8 @@ module = { enable = powerpc_ieee1275; enable = mips_arc; enable = ia64_efi; + enable = arm_efi; + enable = arm_uboot; }; module = {