[RFC] arch: add minimal aarch64 support
Antony Pavlov
antonynpavlov at gmail.com
Fri Apr 15 08:03:18 PDT 2016
On Fri, 15 Apr 2016 10:05:25 +0200
Raphael Poggi <poggi.raph at gmail.com> wrote:
> This commit add minimal support for aarch64/arm64 architecture.
>
> The main current limitations are:
> - MMU not implemented
> - barebox running at EL1
> - barebox env not working
> - only test on qemu
Your patch is suffering from whitespace errors.
Also please check pbl paths in your pbl code, e.g.:
$ grep arch/arm/ YOUR_PATCH | grep incbin
+ .incbin "arch/arm/pbl/piggy.gzip"
+ .incbin "arch/arm/pbl/piggy.lz4"
+ .incbin "arch/arm/pbl/piggy.lzo"
+ .incbin "arch/arm/pbl/piggy.shipped"
+ .incbin "arch/arm/pbl/piggy.xzkern"
> Signed-off-by: Raphael Poggi <poggi.raph at gmail.com>
> ---
> arch/arm64/Kconfig | 140 +++++++
> arch/arm64/Makefile | 109 +++++
> arch/arm64/boards/Makefile | 2 +
> arch/arm64/boards/virt/Kconfig | 8 +
> arch/arm64/boards/virt/Makefile | 3 +
> arch/arm64/boards/virt/env/config | 38 ++
> arch/arm64/boards/virt/init.c | 52 +++
> arch/arm64/boards/virt/lowlevel.c | 18 +
> arch/arm64/configs/virt_defconfig | 53 +++
> arch/arm64/cpu/Kconfig | 54 +++
> arch/arm64/cpu/Makefile | 30 ++
> arch/arm64/cpu/cache-armv8.S | 168 ++++++++
> arch/arm64/cpu/cache.c | 110 ++++++
> arch/arm64/cpu/cpu.c | 106 +++++
> arch/arm64/cpu/cpuinfo.c | 211 ++++++++++
> arch/arm64/cpu/entry.c | 38 ++
> arch/arm64/cpu/entry.h | 18 +
> arch/arm64/cpu/exceptions.S | 127 ++++++
> arch/arm64/cpu/interrupts.c | 162 ++++++++
> arch/arm64/cpu/lowlevel.S | 49 +++
> arch/arm64/cpu/mmu-early.c | 53 +++
> arch/arm64/cpu/mmu-early.h | 6 +
> arch/arm64/cpu/mmu.c | 492 +++++++++++++++++++++++
> arch/arm64/cpu/mmu.h | 14 +
> arch/arm64/cpu/mmuinfo.c | 104 +++++
> arch/arm64/cpu/no-mmu.c | 61 +++
> arch/arm64/cpu/start-pbl.c | 102 +++++
> arch/arm64/cpu/start.c | 247 ++++++++++++
> arch/arm64/cpu/uncompress.c | 111 ++++++
> arch/arm64/include/asm/armlinux.h | 43 ++
> arch/arm64/include/asm/assembler.h | 116 ++++++
> arch/arm64/include/asm/barebox-arm-head.h | 65 +++
> arch/arm64/include/asm/barebox-arm.h | 165 ++++++++
> arch/arm64/include/asm/barebox.h | 12 +
> arch/arm64/include/asm/bitops.h | 48 +++
> arch/arm64/include/asm/bitsperlong.h | 1 +
> arch/arm64/include/asm/byteorder.h | 32 ++
> arch/arm64/include/asm/cache-l2x0.h | 101 +++++
> arch/arm64/include/asm/cache.h | 16 +
> arch/arm64/include/asm/common.h | 48 +++
> arch/arm64/include/asm/cputype.h | 100 +++++
> arch/arm64/include/asm/debug_ll_pl011.h | 25 ++
> arch/arm64/include/asm/dma.h | 46 +++
> arch/arm64/include/asm/elf.h | 119 ++++++
> arch/arm64/include/asm/errata.h | 79 ++++
> arch/arm64/include/asm/gic.h | 128 ++++++
> arch/arm64/include/asm/hardware/arm_timer.h | 38 ++
> arch/arm64/include/asm/hardware/sp810.h | 68 ++++
> arch/arm64/include/asm/io.h | 87 ++++
> arch/arm64/include/asm/linkage.h | 11 +
> arch/arm64/include/asm/memory.h | 19 +
> arch/arm64/include/asm/mmu.h | 65 +++
> arch/arm64/include/asm/module.h | 13 +
> arch/arm64/include/asm/pgtable.h | 90 +++++
> arch/arm64/include/asm/posix_types.h | 1 +
> arch/arm64/include/asm/processor.h | 131 ++++++
> arch/arm64/include/asm/ptrace.h | 34 ++
> arch/arm64/include/asm/sections.h | 34 ++
> arch/arm64/include/asm/semihosting.h | 19 +
> arch/arm64/include/asm/setup.h | 216 ++++++++++
> arch/arm64/include/asm/stacktrace.h | 16 +
> arch/arm64/include/asm/string.h | 13 +
> arch/arm64/include/asm/swab.h | 69 ++++
> arch/arm64/include/asm/system.h | 125 ++++++
> arch/arm64/include/asm/system_info.h | 194 +++++++++
> arch/arm64/include/asm/types.h | 54 +++
> arch/arm64/include/asm/unaligned.h | 19 +
> arch/arm64/include/asm/unified.h | 127 ++++++
> arch/arm64/include/asm/unwind.h | 51 +++
> arch/arm64/lib/Makefile | 16 +
> arch/arm64/lib/armlinux.c | 275 +++++++++++++
> arch/arm64/lib/asm-offsets.c | 16 +
> arch/arm64/lib/barebox.lds | 125 ++++++
> arch/arm64/lib/barebox.lds.S | 125 ++++++
> arch/arm64/lib/bootm.c | 572 +++++++++++++++++++++++++++
> arch/arm64/lib/bootu.c | 44 +++
> arch/arm64/lib/bootz.c | 136 +++++++
> arch/arm64/lib/copy_template.S | 192 +++++++++
> arch/arm64/lib/div0.c | 27 ++
> arch/arm64/lib/memcpy.S | 74 ++++
> arch/arm64/lib/memset.S | 215 ++++++++++
> arch/arm64/lib/module.c | 98 +++++
> arch/arm64/lib/pbl.lds.S | 96 +++++
> arch/arm64/lib/runtime-offset.S | 52 +++
> arch/arm64/lib/unwind.c | 349 ++++++++++++++++
> arch/arm64/mach-virt/Kconfig | 15 +
> arch/arm64/mach-virt/Makefile | 1 +
> arch/arm64/mach-virt/devices.c | 30 ++
> arch/arm64/mach-virt/include/mach/debug_ll.h | 24 ++
> arch/arm64/mach-virt/include/mach/devices.h | 13 +
> arch/arm64/mach-virt/reset.c | 24 ++
> arch/arm64/pbl/Makefile | 58 +++
> arch/arm64/pbl/piggy.gzip.S | 6 +
> arch/arm64/pbl/piggy.lz4.S | 6 +
> arch/arm64/pbl/piggy.lzo.S | 6 +
> arch/arm64/pbl/piggy.shipped.S | 6 +
> arch/arm64/pbl/piggy.xzkern.S | 6 +
> 97 files changed, 7931 insertions(+)
> create mode 100644 arch/arm64/Kconfig
> create mode 100644 arch/arm64/Makefile
> create mode 100644 arch/arm64/boards/Makefile
> create mode 100644 arch/arm64/boards/virt/Kconfig
> create mode 100644 arch/arm64/boards/virt/Makefile
> create mode 100644 arch/arm64/boards/virt/env/config
> create mode 100644 arch/arm64/boards/virt/init.c
> create mode 100644 arch/arm64/boards/virt/lowlevel.c
> create mode 100644 arch/arm64/configs/virt_defconfig
> create mode 100644 arch/arm64/cpu/Kconfig
> create mode 100644 arch/arm64/cpu/Makefile
> create mode 100644 arch/arm64/cpu/cache-armv8.S
> create mode 100644 arch/arm64/cpu/cache.c
> create mode 100644 arch/arm64/cpu/cpu.c
> create mode 100644 arch/arm64/cpu/cpuinfo.c
> create mode 100644 arch/arm64/cpu/entry.c
> create mode 100644 arch/arm64/cpu/entry.h
> create mode 100644 arch/arm64/cpu/exceptions.S
> create mode 100644 arch/arm64/cpu/interrupts.c
> create mode 100644 arch/arm64/cpu/lowlevel.S
> create mode 100644 arch/arm64/cpu/mmu-early.c
> create mode 100644 arch/arm64/cpu/mmu-early.h
> create mode 100644 arch/arm64/cpu/mmu.c
> create mode 100644 arch/arm64/cpu/mmu.h
> create mode 100644 arch/arm64/cpu/mmuinfo.c
> create mode 100644 arch/arm64/cpu/no-mmu.c
> create mode 100644 arch/arm64/cpu/start-pbl.c
> create mode 100644 arch/arm64/cpu/start.c
> create mode 100644 arch/arm64/cpu/uncompress.c
> create mode 100644 arch/arm64/include/asm/armlinux.h
> create mode 100644 arch/arm64/include/asm/assembler.h
> create mode 100644 arch/arm64/include/asm/barebox-arm-head.h
> create mode 100644 arch/arm64/include/asm/barebox-arm.h
> create mode 100644 arch/arm64/include/asm/barebox.h
> create mode 100644 arch/arm64/include/asm/bitops.h
> create mode 100644 arch/arm64/include/asm/bitsperlong.h
> create mode 100644 arch/arm64/include/asm/byteorder.h
> create mode 100644 arch/arm64/include/asm/cache-l2x0.h
> create mode 100644 arch/arm64/include/asm/cache.h
> create mode 100644 arch/arm64/include/asm/common.h
> create mode 100644 arch/arm64/include/asm/cputype.h
> create mode 100644 arch/arm64/include/asm/debug_ll_pl011.h
> create mode 100644 arch/arm64/include/asm/dma.h
> create mode 100644 arch/arm64/include/asm/elf.h
> create mode 100644 arch/arm64/include/asm/errata.h
> create mode 100644 arch/arm64/include/asm/gic.h
> create mode 100644 arch/arm64/include/asm/hardware/arm_timer.h
> create mode 100644 arch/arm64/include/asm/hardware/sp810.h
> create mode 100644 arch/arm64/include/asm/io.h
> create mode 100644 arch/arm64/include/asm/linkage.h
> create mode 100644 arch/arm64/include/asm/memory.h
> create mode 100644 arch/arm64/include/asm/mmu.h
> create mode 100644 arch/arm64/include/asm/module.h
> create mode 100644 arch/arm64/include/asm/pgtable.h
> create mode 100644 arch/arm64/include/asm/posix_types.h
> create mode 100644 arch/arm64/include/asm/processor.h
> create mode 100644 arch/arm64/include/asm/ptrace.h
> create mode 100644 arch/arm64/include/asm/sections.h
> create mode 100644 arch/arm64/include/asm/semihosting.h
> create mode 100644 arch/arm64/include/asm/setup.h
> create mode 100644 arch/arm64/include/asm/stacktrace.h
> create mode 100644 arch/arm64/include/asm/string.h
> create mode 100644 arch/arm64/include/asm/swab.h
> create mode 100644 arch/arm64/include/asm/system.h
> create mode 100644 arch/arm64/include/asm/system_info.h
> create mode 100644 arch/arm64/include/asm/types.h
> create mode 100644 arch/arm64/include/asm/unaligned.h
> create mode 100644 arch/arm64/include/asm/unified.h
> create mode 100644 arch/arm64/include/asm/unwind.h
> create mode 100644 arch/arm64/lib/Makefile
> create mode 100644 arch/arm64/lib/armlinux.c
> create mode 100644 arch/arm64/lib/asm-offsets.c
> create mode 100644 arch/arm64/lib/barebox.lds
> create mode 100644 arch/arm64/lib/barebox.lds.S
> create mode 100644 arch/arm64/lib/bootm.c
> create mode 100644 arch/arm64/lib/bootu.c
> create mode 100644 arch/arm64/lib/bootz.c
> create mode 100644 arch/arm64/lib/copy_template.S
> create mode 100644 arch/arm64/lib/div0.c
> create mode 100644 arch/arm64/lib/memcpy.S
> create mode 100644 arch/arm64/lib/memset.S
> create mode 100644 arch/arm64/lib/module.c
> create mode 100644 arch/arm64/lib/pbl.lds.S
> create mode 100644 arch/arm64/lib/runtime-offset.S
> create mode 100644 arch/arm64/lib/unwind.c
> create mode 100644 arch/arm64/mach-virt/Kconfig
> create mode 100644 arch/arm64/mach-virt/Makefile
> create mode 100644 arch/arm64/mach-virt/devices.c
> create mode 100644 arch/arm64/mach-virt/include/mach/debug_ll.h
> create mode 100644 arch/arm64/mach-virt/include/mach/devices.h
> create mode 100644 arch/arm64/mach-virt/reset.c
> create mode 100644 arch/arm64/pbl/Makefile
> create mode 100644 arch/arm64/pbl/piggy.gzip.S
> create mode 100644 arch/arm64/pbl/piggy.lz4.S
> create mode 100644 arch/arm64/pbl/piggy.lzo.S
> create mode 100644 arch/arm64/pbl/piggy.shipped.S
> create mode 100644 arch/arm64/pbl/piggy.xzkern.S
>
> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
> new file mode 100644
> index 0000000..7d10404
> --- /dev/null
> +++ b/arch/arm64/Kconfig
> @@ -0,0 +1,140 @@
> +config ARM
> + bool
> + select HAS_KALLSYMS
> + select HAS_MODULES
> + select HAS_DMA
> + select HAS_CACHE
> + select HAVE_CONFIGURABLE_TEXT_BASE
> + select HAVE_PBL_IMAGE
> + select HAVE_IMAGE_COMPRESSION
> + default y
> +
> +config ARM_LINUX
> + bool
> + default y
> + depends on CMD_BOOTZ || CMD_BOOTU || BOOTM
> +
> +config HAVE_MACH_ARM_HEAD
> + bool
> +
> +config ARM_USE_COMPRESSED_DTB
> + bool
> + select UNCOMPRESS
> + select LZO_DECOMPRESS
> +
> +menu "System Type"
> +
> +config BUILTIN_DTB
> + bool "link a DTB into the barebox image"
> + depends on OFTREE
> + depends on !HAVE_PBL_MULTI_IMAGES
> +
> +config BUILTIN_DTB_NAME
> + string "DTB to build into the barebox image"
> + depends on BUILTIN_DTB
> + default "canon-a1100" if MACH_CANON_A1100
> + default "imx51-genesi-efika-sb" if MACH_EFIKA_MX_SMARTBOOK
> + default "versatile-pb" if ARCH_VERSATILE_PB
> + default "virt2real" if MACH_VIRT2REAL
> + default "module-mb7707" if MACH_MB7707
> +
> +choice
> + prompt "ARM system type"
> +
> +config ARCH_VIRT
> + bool "ARM QEMU virt boards"
> + select HAS_DEBUG_LL
> + select CPU_V8
> + select SYS_SUPPORTS_64BIT_KERNEL
> + select ARM_AMBA
> + select HAVE_CONFIGURABLE_MEMORY_LAYOUT
> +
> +endchoice
> +
> +source arch/arm64/cpu/Kconfig
> +source arch/arm64/mach-virt/Kconfig
> +
> +config ARM_ASM_UNIFIED
> + bool
> +
> +config AEABI
> + bool "Use the ARM EABI to compile barebox"
> + help
> + This option allows for barebox to be compiled using the latest
> + ARM ABI (aka EABI).
> +
> + To use this you need GCC version 4.0.0 or later.
> +
> +config ARM_BOARD_APPEND_ATAG
> + bool "Let board specific code to add ATAGs to be passed to the kernel"
> + depends on ARM_LINUX
> + help
> + This option is purely to start some vendor provided kernels.
> + ** DO NOT USE FOR YOUR OWN DESIGNS! **
> +
> +endmenu
> +
> +choice
> + prompt "Barebox code model"
> + help
> + You should only select this option if you have a workload that
> + actually benefits from 64-bit processing or if your machine has
> + large memory. You will only be presented a single option in this
> + menu if your system does not support both 32-bit and 64-bit modes.
> +
> +config 32BIT
> + bool "32-bit barebox"
> + depends on CPU_SUPPORTS_32BIT_KERNEL && SYS_SUPPORTS_32BIT_KERNEL
> + help
> + Select this option if you want to build a 32-bit barebox.
> +
> +config 64BIT
> + bool "64-bit barebox"
> + depends on CPU_SUPPORTS_64BIT_KERNEL && SYS_SUPPORTS_64BIT_KERNEL
> + select ARCH_DMA_ADDR_T_64BIT
> + help
> + Select this option if you want to build a 64-bit barebox.
> +
> +endchoice
> +
> +menu "ARM specific settings"
> +
> +config ARM_OPTIMZED_STRING_FUNCTIONS
> + bool "use assembler optimized string functions"
> + help
> + Say yes here to use assembler optimized memcpy / memset functions.
> + These functions work much faster than the normal versions but
> + increase your binary size.
> +
> +config ARM_EXCEPTIONS
> + bool "enable arm exception handling support"
> + default y
> +
> +config ARM_UNWIND
> + bool "enable stack unwinding support"
> + depends on AEABI
> + help
> + This option enables stack unwinding support in barebox
> + using the information automatically generated by the
> + compiler. The resulting kernel image is slightly bigger but
> + the performance is not affected. Currently, this feature
> + only works with EABI compilers. If unsure say Y.
> +
> +config ARM_SEMIHOSTING
> + bool "enable ARM semihosting support"
> + help
> + This option enables ARM semihosting support in barebox. ARM
> + semihosting is a communication discipline that allows code
> + running on target ARM cpu perform system calls and access
> + the data on the host computer connected to the target via
> + debugging channel (JTAG, SWD). If unsure say N
> +
> +endmenu
> +
> +source common/Kconfig
> +source commands/Kconfig
> +source net/Kconfig
> +source drivers/Kconfig
> +source fs/Kconfig
> +source lib/Kconfig
> +source crypto/Kconfig
> diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile
> new file mode 100644
> index 0000000..b5a90c4
> --- /dev/null
> +++ b/arch/arm64/Makefile
> @@ -0,0 +1,109 @@
> +
> +CPPFLAGS += -D__ARM__ -fno-strict-aliasing
> +CPPFLAGS +=$(call cc-option,-maarch64,)
> +
> +ifeq ($(CONFIG_CPU_BIG_ENDIAN),y)
> +CPPFLAGS += -mbig-endian
> +AS += -EB
> +LD += -EB
> +else
> +CPPFLAGS += -mlittle-endian
> +AS += -EL
> +LD += -EL
> +endif
> +
> +# This selects which instruction set is used.
> +# Note that GCC does not numerically define an architecture version
> +# macro, but instead defines a whole series of macros which makes
> +# testing for a specific architecture or later rather impossible.
> +arch-$(CONFIG_CPU_64v8) := -D__LINUX_ARM_ARCH__=8 $(call cc-option,-march=armv8-a)
> +
> +CFLAGS_ABI :=-mabi=lp64
> +
> +ifeq ($(CONFIG_ARM_UNWIND),y)
> +CFLAGS_ABI +=-funwind-tables
> +endif
> +
> +CPPFLAGS += $(CFLAGS_ABI) $(arch-y) $(tune-y)
> +
> +AFLAGS += -include asm/unified.h
> +
> +# Machine directory name. This list is sorted alphanumerically
> +# by CONFIG_* macro name.
> +machine-$(CONFIG_ARCH_VIRT) := virt
> +
> +
> +machdirs := $(patsubst %,arch/arm64/mach-%/,$(machine-y))
> +
> +ifeq ($(KBUILD_SRC),)
> +CPPFLAGS += $(patsubst %,-I%include,$(machdirs))
> +else
> +CPPFLAGS += $(patsubst %,-I$(srctree)/%include,$(machdirs))
> +endif
> +
> +TEXT_BASE = $(CONFIG_TEXT_BASE)
> +
> +CPPFLAGS += -DTEXT_BASE=$(TEXT_BASE)
> +
> +# Add cleanup flags
> +CPPFLAGS += -fdata-sections -ffunction-sections
> +LDFLAGS_barebox += --gc-sections
> +
> +ifdef CONFIG_RELOCATABLE
> +LDFLAGS_barebox += -pie
> +else
> +LDFLAGS_barebox += -static
> +endif
> +
> +ifdef CONFIG_IMAGE_COMPRESSION
> +KBUILD_BINARY := arch/arm64/pbl/zbarebox.bin
> +else
> +KBUILD_BINARY := barebox.bin
> +endif
> +
> +barebox.netx: $(KBUILD_BINARY)
> + $(Q)scripts/gen_netx_image -i $< -o barebox.netx \
> + --sdramctrl=$(CONFIG_NETX_SDRAM_CTRL) \
> + --sdramtimctrl=$(CONFIG_NETX_SDRAM_TIMING_CTRL) \
> + --memctrl=$(CONFIG_NETX_MEM_CTRL) \
> + --entrypoint=$(CONFIG_TEXT_BASE) \
> + --cookie=$(CONFIG_NETX_COOKIE);
> +
> +ifeq ($(machine-y),netx)
> +KBUILD_IMAGE := barebox.netx
> +endif
> +
> +barebox.s5p: $(KBUILD_BINARY)
> + $(Q)scripts/s5p_cksum $< barebox.s5p
> +
> +boarddir = $(srctree)/arch/arm64/boards
> +
> +pbl := arch/arm64/pbl
> +$(pbl)/zbarebox.S $(pbl)/zbarebox.bin $(pbl)/zbarebox: barebox.bin FORCE
> + $(Q)$(MAKE) $(build)=$(pbl) $@
> +
> +archclean:
> + $(MAKE) $(clean)=$(pbl)
> +
> +KBUILD_IMAGE ?= $(KBUILD_BINARY)
> +
> +ifneq ($(board-y),)
> +BOARD := arch/arm64/boards/$(board-y)/
> +else
> +BOARD :=
> +endif
> +
> +ifneq ($(machine-y),)
> +MACH := arch/arm64/mach-$(machine-y)/
> +else
> +MACH :=
> +endif
> +
> +common-y += $(BOARD) arch/arm64/boards/ $(MACH)
> +common-y += arch/arm64/lib/ arch/arm64/cpu/
> +
> +lds-y := arch/arm64/lib/barebox.lds
> +
> +common- += $(patsubst %,arch/arm64/boards/%/,$(board-))
> +
> +CLEAN_FILES += include/generated/mach-types.h arch/arm64/lib/barebox.lds barebox-flash-image
> diff --git a/arch/arm64/boards/Makefile b/arch/arm64/boards/Makefile
> new file mode 100644
> index 0000000..2207c05
> --- /dev/null
> +++ b/arch/arm64/boards/Makefile
> @@ -0,0 +1,2 @@
> +# keep sorted by CONFIG_* macro name.
> +obj-$(CONFIG_MACH_VIRT) += virt/
> diff --git a/arch/arm64/boards/virt/Kconfig b/arch/arm64/boards/virt/Kconfig
> new file mode 100644
> index 0000000..b239127
> --- /dev/null
> +++ b/arch/arm64/boards/virt/Kconfig
> @@ -0,0 +1,8 @@
> +
> +if MACH_VIRT
> +
> +config ARCH_TEXT_BASE
> + hex
> + default 0x40000000
> +
> +endif
> diff --git a/arch/arm64/boards/virt/Makefile b/arch/arm64/boards/virt/Makefile
> new file mode 100644
> index 0000000..e11fd5b
> --- /dev/null
> +++ b/arch/arm64/boards/virt/Makefile
> @@ -0,0 +1,3 @@
> +obj-y += init.o
> +
> +lwl-y += lowlevel.o
> diff --git a/arch/arm64/boards/virt/env/config b/arch/arm64/boards/virt/env/config
> new file mode 100644
> index 0000000..6c0abda
> --- /dev/null
> +++ b/arch/arm64/boards/virt/env/config
> @@ -0,0 +1,38 @@
> +#!/bin/sh
> +
> +# use 'dhcp' to do dhcp in barebox and in kernel
> +# use 'none' if you want to skip kernel ip autoconfiguration
> +ip=dhcp
> +global.dhcp.vendor_id=barebox-${global.hostname}
> +
> +# or set your networking parameters here
> +#eth0.ipaddr=a.b.c.d
> +#eth0.netmask=a.b.c.d
> +#eth0.gateway=a.b.c.d
> +#eth0.serverip=a.b.c.d
> +
> +# can be either 'nfs', 'tftp' or 'nor'
> +kernel_loc=tftp
> +# can be either 'net', 'nor' or 'initrd'
> +rootfs_loc=initrd
> +
> +# can be either 'jffs2' or 'ubifs'
> +rootfs_type=ubifs
> +rootfsimage=root.$rootfs_type
> +
> +kernelimage=zImage
> +#kernelimage=uImage
> +#kernelimage=Image
> +#kernelimage=Image.lzo
> +
> +nfsroot="$eth0.serverip:/opt/work/busybox/arm9/rootfs_arm"
> +
> +nor_parts="256k(barebox)ro,64k(bareboxenv),1536k(kernel),-(root)"
> +rootfs_mtdblock_nor=3
> +
> +autoboot_timeout=3
> +
> +bootargs="console=ttyAMA0,115200n8 CONSOLE=/dev/ttyAMA0"
> +
> +# set a fancy prompt (if support is compiled in)
> +PS1="\e[1;31m[barebox@\h]:\w\e[0m\n# "
> diff --git a/arch/arm64/boards/virt/init.c b/arch/arm64/boards/virt/init.c
> new file mode 100644
> index 0000000..0ba41b7
> --- /dev/null
> +++ b/arch/arm64/boards/virt/init.c
> @@ -0,0 +1,52 @@
> +/*
> + * Copyright (C) 2016 Raphaël Poggi <poggi.raph at gmail.com>
> + *
> + * GPLv2 only
> + */
> +
> +#include <common.h>
> +#include <init.h>
> +#include <asm/armlinux.h>
> +#include <asm/system_info.h>
> +#include <mach/devices.h>
> +#include <environment.h>
> +#include <linux/sizes.h>
> +#include <io.h>
> +#include <globalvar.h>
> +
> +static int virt_mem_init(void)
> +{
> + virt_add_ddram(SZ_256M);
> +
> + add_cfi_flash_device(0, 0x00000000, SZ_4M, 0);
> +
> + devfs_add_partition("nor0", 0x00000, 0x40000, DEVFS_PARTITION_FIXED, "self0");
> + devfs_add_partition("nor0", 0x40000, 0x20000, DEVFS_PARTITION_FIXED, "env0");
> +
> + return 0;
> +}
> +mem_initcall(virt_mem_init);
> +
> +static int virt_console_init(void)
> +{
> + virt_register_uart(0);
> +
> + return 0;
> +}
> +console_initcall(virt_console_init);
> +
> +static int virt_core_init(void)
> +{
> + char *hostname = "virt";
> +
> + if (cpu_is_cortex_a53())
> + hostname = "virt-a53";
> + else if (cpu_is_cortex_a57())
> + hostname = "virt-a57";
> +
> + barebox_set_model("ARM QEMU virt");
> + barebox_set_hostname(hostname);
> +
> + return 0;
> +}
> +postcore_initcall(virt_core_init);
> diff --git a/arch/arm64/boards/virt/lowlevel.c b/arch/arm64/boards/virt/lowlevel.c
> new file mode 100644
> index 0000000..ab62121
> --- /dev/null
> +++ b/arch/arm64/boards/virt/lowlevel.c
> @@ -0,0 +1,18 @@
> +/*
> + * Copyright (C) 2013 Jean-Christophe PLAGNIOL-VILLARD <plagnio at jcrosoft.com>
> + *
> + * GPLv2 only
> + */
> +
> +#include <common.h>
> +#include <linux/sizes.h>
> +#include <asm/barebox-arm-head.h>
> +#include <asm/barebox-arm.h>
> +#include <asm/system_info.h>
> +
> +void barebox_arm_reset_vector(void)
> +{
> + arm_cpu_lowlevel_init();
> +
> + barebox_arm_entry(0x40000000, SZ_512M, NULL);
> +}
> diff --git a/arch/arm64/configs/virt_defconfig b/arch/arm64/configs/virt_defconfig
> new file mode 100644
> index 0000000..e0d78bf
> --- /dev/null
> +++ b/arch/arm64/configs/virt_defconfig
> @@ -0,0 +1,53 @@
> +CONFIG_AEABI=y
> +CONFIG_ARM_OPTIMZED_STRING_FUNCTIONS=y
> +CONFIG_BAREBOX_MAX_IMAGE_SIZE=0x05000000
> +CONFIG_BAREBOX_MAX_BARE_INIT_SIZE=0x01000000
> +CONFIG_MEMORY_LAYOUT_FIXED=y
> +CONFIG_STACK_BASE=0x60000000
> +CONFIG_MALLOC_BASE=0x50000000
> +CONFIG_PROMPT="virt: "
> +CONFIG_HUSH_FANCY_PROMPT=y
> +CONFIG_CMDLINE_EDITING=y
> +CONFIG_AUTO_COMPLETE=y
> +CONFIG_MENU=y
> +CONFIG_PASSWORD=y
> +CONFIG_PARTITION=y
> +CONFIG_DEFAULT_ENVIRONMENT_GENERIC_NEW=y
> +CONFIG_DEFAULT_ENVIRONMENT_PATH="arch/arm64/boards/virt/env"
> +CONFIG_DEBUG_INFO=y
> +# CONFIG_CMD_ARM_CPUINFO is not set
> +CONFIG_LONGHELP=y
> +# CONFIG_CMD_BOOTM is not set
> +# CONFIG_CMD_BOOTU is not set
> +# CONFIG_CMD_MOUNT is not set
> +# CONFIG_CMD_UMOUNT is not set
> +# CONFIG_CMD_CAT is not set
> +# CONFIG_CMD_CD is not set
> +# CONFIG_CMD_CP is not set
> +# CONFIG_CMD_LS is not set
> +# CONFIG_CMD_MKDIR is not set
> +# CONFIG_CMD_PWD is not set
> +# CONFIG_CMD_RM is not set
> +# CONFIG_CMD_RMDIR is not set
> +# CONFIG_CMD_FALSE is not set
> +# CONFIG_CMD_TEST is not set
> +# CONFIG_CMD_TRUE is not set
> +# CONFIG_CMD_CLEAR is not set
> +# CONFIG_CMD_ECHO is not set
> +CONFIG_CMD_CRC=y
> +CONFIG_CMD_CRC_CMP=y
> +# CONFIG_CMD_MD is not set
> +# CONFIG_CMD_MEMCMP is not set
> +# CONFIG_CMD_MEMCPY is not set
> +# CONFIG_CMD_MEMSET is not set
> +# CONFIG_CMD_MW is not set
> +CONFIG_SERIAL_AMBA_PL011=y
> +# CONFIG_SPI is not set
> +CONFIG_MTD=y
> +CONFIG_DRIVER_CFI=y
> +CONFIG_DRIVER_CFI_BANK_WIDTH_8=y
> +CONFIG_CFI_BUFFER_WRITE=y
> +CONFIG_NAND=y
> +# CONFIG_FS_RAMFS is not set
> +CONFIG_DIGEST_SHA1_GENERIC=y
> +CONFIG_DIGEST_SHA256_GENERIC=y
> diff --git a/arch/arm64/cpu/Kconfig b/arch/arm64/cpu/Kconfig
> new file mode 100644
> index 0000000..86d64a4
> --- /dev/null
> +++ b/arch/arm64/cpu/Kconfig
> @@ -0,0 +1,54 @@
> +comment "Processor Type"
> +
> +config CPU_64
> + bool
> + default y
> +
> +# Select CPU types depending on the architecture selected. This selects
> +# which CPUs we support in the kernel image, and the compiler instruction
> +# optimiser behaviour.
> +
> +# ARMv8
> +config CPU_V8
> + bool
> + select CPU_64v8
> + select CPU_SUPPORTS_64BIT_KERNEL
> +
> +config CPU_64v8
> + bool
> +
> +comment "processor features"
> +
> +config ARCH_SUPPORTS_BIG_ENDIAN
> + bool
> +
> +config CPU_BIG_ENDIAN
> + bool "Build big-endian kernel"
> + depends on ARCH_SUPPORTS_BIG_ENDIAN
> + help
> + Say Y if you plan on running a kernel in big-endian mode.
> + Note that your board must be properly built and your board
> + port must properly enable any big-endian related features
> + of your chipset/board/processor.
> +
> +config BOOT_ENDIANNESS_SWITCH
> + bool "Support switching of Linux kernel endianness"
> + help
> + Say Y here if you need to switch CPU endianness before running
> + Linux kernel, e.g. if you want big-endian Barebox to run
> + little-endian Linux.
> +
> + Currently implemented only by "bootz" command.
> +
> +config SYS_SUPPORTS_32BIT_KERNEL
> + bool
> +
> +config SYS_SUPPORTS_64BIT_KERNEL
> + bool
> +
> +config CPU_SUPPORTS_32BIT_KERNEL
> + bool
> +
> +config CPU_SUPPORTS_64BIT_KERNEL
> + bool
> +
> diff --git a/arch/arm64/cpu/Makefile b/arch/arm64/cpu/Makefile
> new file mode 100644
> index 0000000..9b0009d
> --- /dev/null
> +++ b/arch/arm64/cpu/Makefile
> @@ -0,0 +1,30 @@
> +obj-y += cpu.o
> +obj-$(CONFIG_ARM_EXCEPTIONS) += exceptions.o
> +obj-$(CONFIG_ARM_EXCEPTIONS) += interrupts.o
> +obj-y += start.o entry.o
> +
> +#
> +# Any variants can be called as start-armxyz.S
> +#
> +obj-$(CONFIG_CMD_ARM_CPUINFO) += cpuinfo.o
> +obj-$(CONFIG_CMD_ARM_MMUINFO) += mmuinfo.o
> +obj-$(CONFIG_MMU) += mmu.o cache.o mmu-early.o
> +pbl-$(CONFIG_MMU) += mmu-early.o
> +
> +ifeq ($(CONFIG_MMU),)
> +#obj-y += no-mmu.o
> +endif
> +
> +AFLAGS_cache-armv8.o :=-Wa,-march=armv8-a
> +obj-$(CONFIG_CPU_64v8) += cache-armv8.o
> +AFLAGS_pbl-cache-armv8.o :=-Wa,-march=armv8-a
> +pbl-$(CONFIG_CPU_64v8) += cache-armv8.o
> +
> +pbl-y += setupc.o entry.o
> +pbl-$(CONFIG_PBL_SINGLE_IMAGE) += start-pbl.o
> +pbl-$(CONFIG_PBL_MULTI_IMAGES) += uncompress.o
> +
> +obj-y += cache.o
> +pbl-y += cache.o
> +
> +lwl-y += lowlevel.o
> diff --git a/arch/arm64/cpu/cache-armv8.S b/arch/arm64/cpu/cache-armv8.S
> new file mode 100644
> index 0000000..82b2f81
> --- /dev/null
> +++ b/arch/arm64/cpu/cache-armv8.S
> @@ -0,0 +1,168 @@
> +/*
> + * (C) Copyright 2013
> + * David Feng <fenghua at phytium.com.cn>
> + *
> + * This file is based on sample code from ARMv8 ARM.
> + *
> + * SPDX-License-Identifier: GPL-2.0+
> + */
> +
> +#include <config.h>
> +#include <linux/linkage.h>
> +#include <init.h>
> +
> +/*
> + * void v8_flush_dcache_level(level)
> + *
> + * clean and invalidate one level cache.
> + *
> + * x0: cache level
> + * x1: 0 flush & invalidate, 1 invalidate only
> + * x2~x9: clobbered
> + */
> +.section .text.v8_flush_dcache_level
> +ENTRY(v8_flush_dcache_level)
> + lsl x12, x0, #1
> + msr csselr_el1, x12 /* select cache level */
> + isb /* sync change of cssidr_el1 */
> + mrs x6, ccsidr_el1 /* read the new cssidr_el1 */
> + and x2, x6, #7 /* x2 <- log2(cache line size)-4 */
> + add x2, x2, #4 /* x2 <- log2(cache line size) */
> + mov x3, #0x3ff
> + and x3, x3, x6, lsr #3 /* x3 <- max number of #ways */
> + clz w5, w3 /* bit position of #ways */
> + mov x4, #0x7fff
> + and x4, x4, x6, lsr #13 /* x4 <- max number of #sets */
> + /* x12 <- cache level << 1 */
> + /* x2 <- line length offset */
> + /* x3 <- number of cache ways - 1 */
> + /* x4 <- number of cache sets - 1 */
> + /* x5 <- bit position of #ways */
> +
> +loop_set:
> + mov x6, x3 /* x6 <- working copy of #ways */
> +loop_way:
> + lsl x7, x6, x5
> + orr x9, x12, x7 /* map way and level to cisw value */
> + lsl x7, x4, x2
> + orr x9, x9, x7 /* map set number to cisw value */
> + tbz w1, #0, 1f
> + dc isw, x9
> + b 2f
> +1: dc cisw, x9 /* clean & invalidate by set/way */
> +2: subs x6, x6, #1 /* decrement the way */
> + b.ge loop_way
> + subs x4, x4, #1 /* decrement the set */
> + b.ge loop_set
> +
> + ret
> +ENDPROC(v8_flush_dcache_level)
> +
> +/*
> + * void v8_flush_dcache_all(int invalidate_only)
> + *
> + * x0: 0 flush & invalidate, 1 invalidate only
> + *
> + * clean and invalidate all data cache by SET/WAY.
> + */
> +.section .text.v8_dcache_all
> +ENTRY(v8_dcache_all)
> + mov x1, x0
> + dsb sy
> + mrs x10, clidr_el1 /* read clidr_el1 */
> + lsr x11, x10, #24
> + and x11, x11, #0x7 /* x11 <- loc */
> + cbz x11, finished /* if loc is 0, exit */
> + mov x15, x30
> + mov x0, #0 /* start flush at cache level 0 */
> + /* x0 <- cache level */
> + /* x10 <- clidr_el1 */
> + /* x11 <- loc */
> + /* x15 <- return address */
> +
> +loop_level:
> + lsl x12, x0, #1
> + add x12, x12, x0 /* x0 <- tripled cache level */
> + lsr x12, x10, x12
> + and x12, x12, #7 /* x12 <- cache type */
> + cmp x12, #2
> + b.lt skip /* skip if no cache or icache */
> + bl v8_flush_dcache_level /* x1 = 0 flush, 1 invalidate */
> +skip:
> + add x0, x0, #1 /* increment cache level */
> + cmp x11, x0
> + b.gt loop_level
> +
> + mov x0, #0
> + msr csselr_el1, x0 /* restore csselr_el1 */
> + dsb sy
> + isb
> + mov x30, x15
> +
> +finished:
> + ret
> +ENDPROC(v8_dcache_all)
> +
> +.section .text.v8_flush_dcache_all
> +ENTRY(v8_flush_dcache_all)
> + mov x16, x30
> + mov x0, #0
> + bl v8_dcache_all
> + mov x30, x16
> + ret
> +ENDPROC(v8_flush_dcache_all)
> +
> +.section .text.v8_invalidate_dcache_all
> +ENTRY(v8_invalidate_dcache_all)
> + mov x16, x30
> + mov x0, #0x1
> + bl v8_dcache_all
> + mov x30, x16
> + ret
> +ENDPROC(v8_invalidate_dcache_all)
> +
> +/*
> + * void v8_flush_dcache_range(start, end)
> + *
> + * clean & invalidate data cache in the range
> + *
> + * x0: start address
> + * x1: end address
> + */
> +.section .text.v8_flush_dcache_range
> +ENTRY(v8_flush_dcache_range)
> + mrs x3, ctr_el0
> + lsr x3, x3, #16
> + and x3, x3, #0xf
> + mov x2, #4
> + lsl x2, x2, x3 /* cache line size */
> +
> + /* x2 <- minimal cache line size in cache system */
> + sub x3, x2, #1
> + bic x0, x0, x3
> +1: dc civac, x0 /* clean & invalidate data or unified cache */
> + add x0, x0, x2
> + cmp x0, x1
> + b.lo 1b
> + dsb sy
> + ret
> +ENDPROC(v8_flush_dcache_range)
> +
> +/*
> + * void v8_invalidate_icache_all(void)
> + *
> + * invalidate all tlb entries.
> + */
> +.section .text.v8_invalidate_icache_all
> +ENTRY(v8_invalidate_icache_all)
> + ic ialluis
> + isb sy
> + ret
> +ENDPROC(v8_invalidate_icache_all)
> +
> +.section .text.v8_flush_l3_cache
> +ENTRY(v8_flush_l3_cache)
> + mov x0, #0 /* return status as success */
> + ret
> +ENDPROC(v8_flush_l3_cache)
> + .weak v8_flush_l3_cache
> diff --git a/arch/arm64/cpu/cache.c b/arch/arm64/cpu/cache.c
> new file mode 100644
> index 0000000..8465cf9
> --- /dev/null
> +++ b/arch/arm64/cpu/cache.c
> @@ -0,0 +1,110 @@
> +#include <common.h>
> +#include <init.h>
> +#include <asm/mmu.h>
> +#include <asm/cache.h>
> +#include <asm/system_info.h>
> +
> +struct cache_fns {
> + void (*dma_clean_range)(unsigned long start, unsigned long end);
> + void (*dma_flush_range)(unsigned long start, unsigned long end);
> + void (*dma_inv_range)(unsigned long start, unsigned long end);
> + void (*mmu_cache_on)(void);
> + void (*mmu_cache_off)(void);
> + void (*mmu_cache_flush)(void);
> +};
> +
> +struct cache_fns *cache_fns;
> +
> +#define DEFINE_CPU_FNS(arch) \
> + void arch##_dma_clean_range(unsigned long start, unsigned long end); \
> + void arch##_dma_flush_range(unsigned long start, unsigned long end); \
> + void arch##_dma_inv_range(unsigned long start, unsigned long end); \
> + void arch##_mmu_cache_on(void); \
> + void arch##_mmu_cache_off(void); \
> + void arch##_mmu_cache_flush(void); \
> + \
> + static struct cache_fns __maybe_unused cache_fns_arm##arch = { \
> + .dma_clean_range = arch##_dma_clean_range, \
> + .dma_flush_range = arch##_dma_flush_range, \
> + .dma_inv_range = arch##_dma_inv_range, \
> + .mmu_cache_on = arch##_mmu_cache_on, \
> + .mmu_cache_off = arch##_mmu_cache_off, \
> + .mmu_cache_flush = arch##_mmu_cache_flush, \
> + };
> +
> +DEFINE_CPU_FNS(v8)
> +
> +void __dma_clean_range(unsigned long start, unsigned long end)
> +{
> + if (cache_fns)
> + cache_fns->dma_clean_range(start, end);
> +}
> +
> +void __dma_flush_range(unsigned long start, unsigned long end)
> +{
> + if (cache_fns)
> + cache_fns->dma_flush_range(start, end);
> +}
> +
> +void __dma_inv_range(unsigned long start, unsigned long end)
> +{
> + if (cache_fns)
> + cache_fns->dma_inv_range(start, end);
> +}
> +
> +void __mmu_cache_on(void)
> +{
> + if (cache_fns)
> + cache_fns->mmu_cache_on();
> +}
> +
> +void __mmu_cache_off(void)
> +{
> + if (cache_fns)
> + cache_fns->mmu_cache_off();
> +}
> +
> +void __mmu_cache_flush(void)
> +{
> + if (cache_fns)
> + cache_fns->mmu_cache_flush();
> + if (outer_cache.flush_all)
> + outer_cache.flush_all();
> +}
> +
> +int arm_set_cache_functions(void)
> +{
> + switch (cpu_architecture()) {
> + case CPU_ARCH_ARMv8:
> + cache_fns = &cache_fns_armv8;
> + break;
> + default:
> + while(1);
> + }
> +
> + return 0;
> +}
> +
> +/*
> + * Early function to flush the caches. This is for use when the
> + * C environment is not yet fully initialized.
> + */
> +void arm_early_mmu_cache_flush(void)
> +{
> + switch (arm_early_get_cpu_architecture()) {
> + case CPU_ARCH_ARMv8:
> +// v7_mmu_cache_flush();
> + return;
> + }
> +}
> +
> +//void v7_mmu_cache_invalidate(void);
> +
> +void arm_early_mmu_cache_invalidate(void)
> +{
> + switch (arm_early_get_cpu_architecture()) {
> + case CPU_ARCH_ARMv8:
> +// v7_mmu_cache_invalidate();
> + return;
> + }
> +}
> diff --git a/arch/arm64/cpu/cpu.c b/arch/arm64/cpu/cpu.c
> new file mode 100644
> index 0000000..2a27e72
> --- /dev/null
> +++ b/arch/arm64/cpu/cpu.c
> @@ -0,0 +1,106 @@
> +/*
> + * cpu.c - A few helper functions for ARM
> + *
> + * Copyright (c) 2007 Sascha Hauer <s.hauer at pengutronix.de>, Pengutronix
> + *
> + * 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 version 2
> + * as published by the Free Software Foundation.
> + *
> + * 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.
> + */
> +
> +/**
> + * @file
> + * @brief A few helper functions for ARM
> + */
> +
> +#include <common.h>
> +#include <init.h>
> +#include <command.h>
> +#include <cache.h>
> +#include <asm/mmu.h>
> +#include <asm/system.h>
> +#include <asm/memory.h>
> +#include <asm-generic/memory_layout.h>
> +#include <asm/cputype.h>
> +#include <asm/cache.h>
> +#include <asm/ptrace.h>
> +
> +#include "mmu.h"
> +
> +/**
> + * Enable processor's instruction cache
> + */
> +void icache_enable(void)
> +{
> + v8_invalidate_icache_all();
> + set_sctlr(get_sctlr() | CR_I);
> +}
> +
> +/**
> + * Disable processor's instruction cache
> + */
> +void icache_disable(void)
> +{
> + set_sctlr(get_sctlr() & ~CR_I);
> +}
> +
> +/**
> + * Detect processor's current instruction cache status
> + * @return 0=disabled, 1=enabled
> + */
> +int icache_status(void)
> +{
> + return (get_sctlr() & CR_I) != 0;
> +}
> +
> +/*
> + * SoC like the ux500 have the l2x0 always enable
> + * with or without MMU enable
> + */
> +struct outer_cache_fns outer_cache;
> +
> +/*
> + * Clean and invalide caches, disable MMU
> + */
> +void mmu_disable(void)
> +{
> + __mmu_cache_flush();
> + if (outer_cache.disable) {
> + outer_cache.flush_all();
> + outer_cache.disable();
> + }
> + __mmu_cache_off();
> +}
> +
> +/**
> + * Disable MMU and D-cache, flush caches
> + * @return 0 (always)
> + *
> + * This function is called by shutdown_barebox to get a clean
> + * memory/cache state.
> + */
> +static void arch_shutdown(void)
> +{
> + mmu_disable();
> + flush_icache();
> +}
> +archshutdown_exitcall(arch_shutdown);
> +
> +extern unsigned long arm_stack_top;
> +
> +static int arm_request_stack(void)
> +{
> + if (!request_sdram_region("stack", arm_stack_top - STACK_SIZE, STACK_SIZE))
> + pr_err("Error: Cannot request SDRAM region for stack\n");
> +
> + return 0;
> +}
> +coredevice_initcall(arm_request_stack);
> diff --git a/arch/arm64/cpu/cpuinfo.c b/arch/arm64/cpu/cpuinfo.c
> new file mode 100644
> index 0000000..2306101
> --- /dev/null
> +++ b/arch/arm64/cpu/cpuinfo.c
> @@ -0,0 +1,211 @@
> +/*
> + * cpuinfo.c - Show information about cp15 registers
> + *
> + * Copyright (c) 2009 Sascha Hauer <s.hauer at pengutronix.de>, Pengutronix
> + *
> + * 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 version 2
> + * as published by the Free Software Foundation.
> + *
> + * 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.
> + */
> +
> +#include <common.h>
> +#include <command.h>
> +#include <complete.h>
> +
> +#define CPU_ARCH_UNKNOWN 0
> +#define CPU_ARCH_ARMv8 10
> +
> +#define ARM_CPU_PART_CORTEX_A53 0xD034
> +#define ARM_CPU_PART_CORTEX_A57 0xD070
> +
> +static void decode_cache(unsigned long size)
> +{
> + int linelen = 1 << ((size & 0x3) + 3);
> + int mult = 2 + ((size >> 2) & 1);
> + int cache_size = mult << (((size >> 6) & 0x7) + 8);
> +
> + if (((size >> 2) & 0xf) == 1)
> + printf("no cache\n");
> + else
> + printf("%d bytes (linelen = %d)\n", cache_size, linelen);
> +}
> +
> +static char *crbits[] = {"M", "A", "C", "W", "P", "D", "L", "B", "S", "R",
> + "F", "Z", "I", "V", "RR", "L4", "DT", "", "IT", "ST", "", "FI", "U", "XP",
> + "VE", "EE", "L2", "", "TRE", "AFE", "TE"};
> +
> +static int do_cpuinfo(int argc, char *argv[])
> +{
> + unsigned long mainid, cache, cr;
> + char *architecture, *implementer;
> + int i;
> + int cpu_arch;
> +
> + __asm__ __volatile__(
> + "mrs %0, midr_el1\n"
> + : "=r" (mainid)
> + :
> + : "memory");
> +
> +// __asm__ __volatile__(
> +// "mrc p15, 0, %0, c0, c0, 1 @ read control reg\n"
> +// : "=r" (cache)
> +// :
> +// : "memory");
> +//
> +// __asm__ __volatile__(
> +// "mrc p15, 0, %0, c1, c0, 0 @ read control reg\n"
> +// : "=r" (cr)
> +// :
> +// : "memory");
> +
> + switch (mainid >> 24) {
> + case 0x41:
> + implementer = "ARM";
> + break;
> + case 0x44:
> + implementer = "Digital Equipment Corp.";
> + break;
> + case 0x40:
> + implementer = "Motorola - Freescale Semiconductor Inc.";
> + break;
> + case 0x56:
> + implementer = "Marvell Semiconductor Inc.";
> + break;
> + case 0x69:
> + implementer = "Intel Corp.";
> + break;
> + default:
> + implementer = "Unknown";
> + }
> +
> + if ((mainid & 0x0008f000) == 0) {
> + cpu_arch = CPU_ARCH_UNKNOWN;
> + } else if ((mainid & 0x0008f000) == 0x00007000) {
> + cpu_arch = (mainid & (1 << 23)) ? CPU_ARCH_ARMv4T : CPU_ARCH_ARMv3;
> + } else if ((mainid & 0x00080000) == 0x00000000) {
> + cpu_arch = (mainid >> 16) & 7;
> + if (cpu_arch)
> + cpu_arch += CPU_ARCH_ARMv3;
> + } else if ((mainid & 0x000f0000) == 0x000f0000) {
> + unsigned int mmfr0;
> +
> + /* Revised CPUID format. Read the Memory Model Feature
> + * Register 0 and check for VMSAv7 or PMSAv7 */
> +// asm("mrc p15, 0, %0, c0, c1, 4"
> +// : "=r" (mmfr0));
> + if ((mmfr0 & 0x0000000f) >= 0x00000003 ||
> + (mmfr0 & 0x000000f0) >= 0x00000030)
> + cpu_arch = CPU_ARCH_ARMv7;
> + else if ((mmfr0 & 0x0000000f) == 0x00000002 ||
> + (mmfr0 & 0x000000f0) == 0x00000020)
> + cpu_arch = CPU_ARCH_ARMv6;
> + else
> + cpu_arch = CPU_ARCH_UNKNOWN;
> + } else
> + cpu_arch = CPU_ARCH_UNKNOWN;
> +
> + switch (cpu_arch) {
> + case CPU_ARCH_ARMv3:
> + architecture = "v3";
> + break;
> + case CPU_ARCH_ARMv4:
> + architecture = "v4";
> + break;
> + case CPU_ARCH_ARMv4T:
> + architecture = "v4T";
> + break;
> + case CPU_ARCH_ARMv5:
> + architecture = "v5";
> + break;
> + case CPU_ARCH_ARMv5T:
> + architecture = "v5T";
> + break;
> + case CPU_ARCH_ARMv5TE:
> + architecture = "v5TE";
> + break;
> + case CPU_ARCH_ARMv5TEJ:
> + architecture = "v5TEJ";
> + break;
> + case CPU_ARCH_ARMv6:
> + architecture = "v6";
> + break;
> + case CPU_ARCH_ARMv7:
> + architecture = "v7";
> + break;
> + case CPU_ARCH_ARMv8:
> + architecture = "v8";
> + break;
> + case CPU_ARCH_UNKNOWN:
> + default:
> + architecture = "Unknown";
> + }
> +
> + printf("implementer: %s\narchitecture: %s\n",
> + implementer, architecture);
> +
> + if (cpu_arch == CPU_ARCH_ARMv7) {
> + unsigned int major, minor;
> + char *part;
> + major = (mainid >> 20) & 0xf;
> + minor = mainid & 0xf;
> + switch (mainid & 0xfff0) {
> + case ARM_CPU_PART_CORTEX_A5:
> + part = "Cortex-A5";
> + break;
> + case ARM_CPU_PART_CORTEX_A7:
> + part = "Cortex-A7";
> + break;
> + case ARM_CPU_PART_CORTEX_A8:
> + part = "Cortex-A8";
> + break;
> + case ARM_CPU_PART_CORTEX_A9:
> + part = "Cortex-A9";
> + break;
> + case ARM_CPU_PART_CORTEX_A15:
> + part = "Cortex-A15";
> + break;
> + case ARM_CPU_PART_CORTEX_A53:
> + part = "Cortex-A53";
> + default:
> + part = "unknown";
> + }
> + printf("core: %s r%up%u\n", part, major, minor);
> + }
> +
> +// if (cache & (1 << 24)) {
> +// /* separate I/D cache */
> +// printf("I-cache: ");
> +// decode_cache(cache & 0xfff);
> +// printf("D-cache: ");
> +// decode_cache((cache >> 12) & 0xfff);
> +// } else {
> +// /* unified I/D cache */
> +// printf("cache: ");
> +// decode_cache(cache & 0xfff);
> +// }
> +
> +// printf("Control register: ");
> +// for (i = 0; i < ARRAY_SIZE(crbits); i++)
> +// if (cr & (1 << i))
> +// printf("%s ", crbits[i]);
> +// printf("\n");
> +
> + return 0;
> +}
> +
> +BAREBOX_CMD_START(cpuinfo)
> + .cmd = do_cpuinfo,
> + BAREBOX_CMD_DESC("show info about CPU")
> + BAREBOX_CMD_GROUP(CMD_GRP_INFO)
> + BAREBOX_CMD_COMPLETE(empty_complete)
> +BAREBOX_CMD_END
> +
> diff --git a/arch/arm64/cpu/entry.c b/arch/arm64/cpu/entry.c
> new file mode 100644
> index 0000000..a029f09
> --- /dev/null
> +++ b/arch/arm64/cpu/entry.c
> @@ -0,0 +1,38 @@
> +#include <types.h>
> +
> +#include <asm/cache.h>
> +
> +#include "entry.h"
> +
> +/*
> + * Main ARM entry point. Call this with the memory region you can
> + * spare for barebox. This doesn't necessarily have to be the full
> + * SDRAM. The currently running binary can be inside or outside of
> + * this region. TEXT_BASE can be inside or outside of this
> + * region. boarddata will be preserved and can be accessed later with
> + * barebox_arm_boarddata().
> + *
> + * -> membase + memsize
> + * STACK_SIZE - stack
> + * 16KiB, aligned to 16KiB - First level page table if early MMU support
> + * is enabled
> + * 128KiB - early memory space
> + * -> maximum end of barebox binary
> + *
> + * Usually a TEXT_BASE of 1MiB below your lowest possible end of memory should
> + * be fine.
> + */
> +
> +void __noreturn barebox_arm_entry(unsigned long membase,
> + unsigned long memsize, void *boarddata)
> +{
> + arm_setup_stack(membase + memsize - 16);
> + arm_early_mmu_cache_invalidate();
> +
> + if (IS_ENABLED(CONFIG_PBL_MULTI_IMAGES))
> + barebox_multi_pbl_start(membase, memsize, boarddata);
> + else if (IS_ENABLED(CONFIG_PBL_SINGLE_IMAGE))
> + barebox_single_pbl_start(membase, memsize, boarddata);
> + else
> + barebox_non_pbl_start(membase, memsize, boarddata);
> +}
> diff --git a/arch/arm64/cpu/entry.h b/arch/arm64/cpu/entry.h
> new file mode 100644
> index 0000000..f0163a3
> --- /dev/null
> +++ b/arch/arm64/cpu/entry.h
> @@ -0,0 +1,18 @@
> +#ifndef __ENTRY_H__
> +#define __ENTRY_H__
> +
> +#include <common.h>
> +
> +void __noreturn barebox_non_pbl_start(unsigned long membase,
> + unsigned long memsize,
> + void *boarddata);
> +
> +void __noreturn barebox_multi_pbl_start(unsigned long membase,
> + unsigned long memsize,
> + void *boarddata);
> +
> +void __noreturn barebox_single_pbl_start(unsigned long membase,
> + unsigned long memsize,
> + void *boarddata);
> +
> +#endif
> diff --git a/arch/arm64/cpu/exceptions.S b/arch/arm64/cpu/exceptions.S
> new file mode 100644
> index 0000000..5812025
> --- /dev/null
> +++ b/arch/arm64/cpu/exceptions.S
> @@ -0,0 +1,127 @@
> +/*
> + * (C) Copyright 2013
> + * David Feng <fenghua at phytium.com.cn>
> + *
> + * SPDX-License-Identifier: GPL-2.0+
> + */
> +
> +#include <config.h>
> +#include <asm/ptrace.h>
> +#include <linux/linkage.h>
> +
> +/*
> + * Enter Exception.
> + * This will save the processor state that is ELR/X0~X30
> + * to the stack frame.
> + */
> +.macro exception_entry
> + stp x29, x30, [sp, #-16]!
> + stp x27, x28, [sp, #-16]!
> + stp x25, x26, [sp, #-16]!
> + stp x23, x24, [sp, #-16]!
> + stp x21, x22, [sp, #-16]!
> + stp x19, x20, [sp, #-16]!
> + stp x17, x18, [sp, #-16]!
> + stp x15, x16, [sp, #-16]!
> + stp x13, x14, [sp, #-16]!
> + stp x11, x12, [sp, #-16]!
> + stp x9, x10, [sp, #-16]!
> + stp x7, x8, [sp, #-16]!
> + stp x5, x6, [sp, #-16]!
> + stp x3, x4, [sp, #-16]!
> + stp x1, x2, [sp, #-16]!
> +
> + /* Could be running at EL3/EL2/EL1 */
> + mrs x11, CurrentEL
> + cmp x11, #0xC /* Check EL3 state */
> + b.eq 1f
> + cmp x11, #0x8 /* Check EL2 state */
> + b.eq 2f
> + cmp x11, #0x4 /* Check EL1 state */
> + b.eq 3f
> +3: mrs x1, esr_el3
> + mrs x2, elr_el3
> + b 0f
> +2: mrs x1, esr_el2
> + mrs x2, elr_el2
> + b 0f
> +1: mrs x1, esr_el1
> + mrs x2, elr_el1
> +0:
> + stp x2, x0, [sp, #-16]!
> + mov x0, sp
> +.endm
> +
> +/*
> + * Exception vectors.
> + */
> + .align 11
> + .globl vectors
> +vectors:
> + .align 7
> + b _do_bad_sync /* Current EL Synchronous Thread */
> +
> + .align 7
> + b _do_bad_irq /* Current EL IRQ Thread */
> +
> + .align 7
> + b _do_bad_fiq /* Current EL FIQ Thread */
> +
> + .align 7
> + b _do_bad_error /* Current EL Error Thread */
> +
> + .align 7
> + b _do_sync /* Current EL Synchronous Handler */
> +
> + .align 7
> + b _do_irq /* Current EL IRQ Handler */
> +
> + .align 7
> + b _do_fiq /* Current EL FIQ Handler */
> +
> + .align 7
> + b _do_error /* Current EL Error Handler */
> +
> +
> +_do_bad_sync:
> + exception_entry
> + bl do_bad_sync
> +
> +_do_bad_irq:
> + exception_entry
> + bl do_bad_irq
> +
> +_do_bad_fiq:
> + exception_entry
> + bl do_bad_fiq
> +
> +_do_bad_error:
> + exception_entry
> + bl do_bad_error
> +
> +_do_sync:
> + exception_entry
> + bl do_sync
> +
> +_do_irq:
> + exception_entry
> + bl do_irq
> +
> +_do_fiq:
> + exception_entry
> + bl do_fiq
> +
> +_do_error:
> + exception_entry
> + bl do_error
> +
> +.section .data
> +.align 4
> +.global arm_ignore_data_abort
> +arm_ignore_data_abort:
> +.word 0 /* When != 0 data aborts are ignored */
> +.global arm_data_abort_occurred
> +arm_data_abort_occurred:
> +.word 0 /* set != 0 by the data abort handler */
> +abort_stack:
> +.space 8
> diff --git a/arch/arm64/cpu/interrupts.c b/arch/arm64/cpu/interrupts.c
> new file mode 100644
> index 0000000..32f5b4b
> --- /dev/null
> +++ b/arch/arm64/cpu/interrupts.c
> @@ -0,0 +1,162 @@
> +/*
> + * interrupts.c - Interrupt Support Routines
> + *
> + * Copyright (c) 2007 Sascha Hauer <s.hauer at pengutronix.de>, Pengutronix
> + *
> + * 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 version 2
> + * as published by the Free Software Foundation.
> + *
> + * 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.
> + *
> + */
> +
> +/**
> + * @file
> + * @brief Interrupt Support Routines
> + */
> +
> +#include <common.h>
> +#include <abort.h>
> +#include <asm/ptrace.h>
> +#include <asm/unwind.h>
> +
> +static void __noreturn do_exception(struct pt_regs *pt_regs)
> +{
> + panic("");
> +}
> +
> +/**
> + * The CPU runs into an undefined instruction. That really should not happen!
> + * @param[in] pt_regs Register set content when the accident happens
> + */
> +void do_undefined_instruction (struct pt_regs *pt_regs)
> +{
> + printf ("undefined instruction\n");
> + do_exception(pt_regs);
> +}
> +
> +/**
> + * The CPU catches a software interrupt
> + * @param[in] pt_regs Register set content when the interrupt happens
> + *
> + * There is no function behind this feature. So what to do else than
> + * a reset?
> + */
> +void do_software_interrupt (struct pt_regs *pt_regs)
> +{
> + printf ("software interrupt\n");
> + do_exception(pt_regs);
> +}
> +
> +/**
> + * The CPU catches a prefetch abort. That really should not happen!
> + * @param[in] pt_regs Register set content when the accident happens
> + *
> + * instruction fetch from an unmapped area
> + */
> +void do_prefetch_abort (struct pt_regs *pt_regs)
> +{
> + printf ("prefetch abort\n");
> + do_exception(pt_regs);
> +}
> +
> +/**
> + * The CPU catches a data abort. That really should not happen!
> + * @param[in] pt_regs Register set content when the accident happens
> + *
> + * data fetch from an unmapped area
> + */
> +void do_data_abort (struct pt_regs *pt_regs)
> +{
> + u32 far;
> +
> + printf("unable to handle %s at address 0x%08x\n",
> + far < PAGE_SIZE ? "NULL pointer dereference" :
> + "paging request", far);
> +
> + do_exception(pt_regs);
> +}
> +
> +/**
> + * The CPU catches a fast interrupt request.
> + * @param[in] pt_regs Register set content when the interrupt happens
> + *
> + * We never enable FIQs, so this should not happen
> + */
> +void do_fiq (struct pt_regs *pt_regs)
> +{
> + printf ("fast interrupt request\n");
> + do_exception(pt_regs);
> +}
> +
> +/**
> + * The CPU catches a regular interrupt.
> + * @param[in] pt_regs Register set content when the interrupt happens
> + *
> + * We never enable interrupts, so this should not happen
> + */
> +void do_irq (struct pt_regs *pt_regs)
> +{
> + printf ("interrupt request\n");
> + do_exception(pt_regs);
> +}
> +
> +void do_bad_sync(struct pt_regs *pt_regs)
> +{
> + printf("bad sync\n");
> + do_exception(pt_regs);
> +}
> +
> +void do_bad_irq(struct pt_regs *pt_regs)
> +{
> + printf("bad irq\n");
> + do_exception(pt_regs);
> +}
> +
> +void do_bad_fiq(struct pt_regs *pt_regs)
> +{
> + printf("bad fiq\n");
> + do_exception(pt_regs);
> +}
> +
> +void do_bad_error(struct pt_regs *pt_regs)
> +{
> + printf("bad error\n");
> + do_exception(pt_regs);
> +}
> +
> +void do_sync(struct pt_regs *pt_regs)
> +{
> + printf("sync exception\n");
> + do_exception(pt_regs);
> +}
> +
> +
> +void do_error(struct pt_regs *pt_regs)
> +{
> + printf("error exception\n");
> + do_exception(pt_regs);
> +}
> +
> +extern volatile int arm_ignore_data_abort;
> +extern volatile int arm_data_abort_occurred;
> +
> +void data_abort_mask(void)
> +{
> + arm_data_abort_occurred = 0;
> + arm_ignore_data_abort = 1;
> +}
> +
> +int data_abort_unmask(void)
> +{
> + arm_ignore_data_abort = 0;
> +
> + return arm_data_abort_occurred != 0;
> +}
> diff --git a/arch/arm64/cpu/lowlevel.S b/arch/arm64/cpu/lowlevel.S
> new file mode 100644
> index 0000000..87d6ecf
> --- /dev/null
> +++ b/arch/arm64/cpu/lowlevel.S
> @@ -0,0 +1,49 @@
> +#include <linux/linkage.h>
> +#include <init.h>
> +#include <asm/system.h>
> +#include <asm/gic.h>
> +#include <asm-generic/memory_layout.h>
> +
> +.section ".text_bare_init_","ax"
> +
> +ENTRY(arm_cpu_lowlevel_init)
> + adr x0, vectors
> + mrs x1, CurrentEL
> + cmp x1, #0xC /* Check EL3 state */
> + b.eq 1f
> + cmp x1, #0x8 /* Check EL2 state */
> + b.eq 2f
> + cmp x1, #0x4 /* Check EL1 state */
> + b.eq 3f
> +
> +1:
> + msr vbar_el3, x0
> + mov x0, #1 /* Non-Secure EL0/1 */
> + orr x0, x0, #(1 << 10) /* 64-bit EL2 */
> + msr scr_el3, x0
> + msr cptr_el3, xzr
> + b done
> +
> +2:
> + msr vbar_el2, x0
> + mov x0, #0x33ff /* Enable FP/SIMD */
> + msr cptr_el2, x0
> + b done
> +
> +
> +3:
> + msr vbar_el1, x0
> + mov x0, #(3 << 20) /* Enable FP/SIMD */
> + msr cpacr_el1, x0
> + b done
> +
> +done:
> + ldr x1, =STACK_BASE
> + mov sp, x1
> + mov x29, #0
> + stp x29, x29, [sp, #-16]!
> + mov x29, sp
> +
> + ret
> +
> +ENDPROC(arm_cpu_lowlevel_init)
> diff --git a/arch/arm64/cpu/mmu-early.c b/arch/arm64/cpu/mmu-early.c
> new file mode 100644
> index 0000000..2e4d316
> --- /dev/null
> +++ b/arch/arm64/cpu/mmu-early.c
> @@ -0,0 +1,53 @@
> +#include <common.h>
> +#include <asm/mmu.h>
> +#include <errno.h>
> +#include <linux/sizes.h>
> +#include <asm/memory.h>
> +#include <asm/system.h>
> +#include <asm/cache.h>
> +
> +#include "mmu.h"
> +
> +static uint32_t *ttb;
> +
> +static void create_sections(unsigned long addr, int size_m, unsigned int flags)
> +{
> + int i;
> +
> + addr >>= 20;
> +
> + for (i = size_m; i > 0; i--, addr++)
> + ttb[addr] = (addr << 20) | flags;
> +}
> +
> +static void map_cachable(unsigned long start, unsigned long size)
> +{
> + start &= ~(SZ_1M - 1);
> + size = (size + (SZ_1M - 1)) & ~(SZ_1M - 1);
> +
> + create_sections(start, size >> 20, PMD_SECT_AP_WRITE |
> + PMD_SECT_AP_READ | PMD_TYPE_SECT | PMD_SECT_WB);
> +}
> +
> +void mmu_early_enable(uint32_t membase, uint32_t memsize, uint32_t _ttb)
> +{
> + int i;
> +
> + ttb = (uint32_t *)_ttb;
> +
> + arm_set_cache_functions();
> +
> + /* Set the ttb register */
> + asm volatile ("mcr p15,0,%0,c2,c0,0" : : "r"(ttb) /*:*/);
> +
> + /* Set the Domain Access Control Register */
> + i = 0x3;
> + asm volatile ("mcr p15,0,%0,c3,c0,0" : : "r"(i) /*:*/);
> +
> + create_sections(0, 4096, PMD_SECT_AP_WRITE |
> + PMD_SECT_AP_READ | PMD_TYPE_SECT);
> +
> + map_cachable(membase, memsize);
> +
> + __mmu_cache_on();
> +}
> diff --git a/arch/arm64/cpu/mmu-early.h b/arch/arm64/cpu/mmu-early.h
> new file mode 100644
> index 0000000..af21f52
> --- /dev/null
> +++ b/arch/arm64/cpu/mmu-early.h
> @@ -0,0 +1,6 @@
> +#ifndef __ARM_CPU_MMU_EARLY_H
> +#define __ARM_CPU_MMU_EARLY_H
> +
> +void mmu_early_enable(uint32_t membase, uint32_t memsize, uint32_t ttb);
> +
> +#endif /* __ARM_CPU_MMU_EARLY_H */
> diff --git a/arch/arm64/cpu/mmu.c b/arch/arm64/cpu/mmu.c
> new file mode 100644
> index 0000000..bc5325f
> --- /dev/null
> +++ b/arch/arm64/cpu/mmu.c
> @@ -0,0 +1,492 @@
> +/*
> + * Copyright (c) 2009-2013 Sascha Hauer <s.hauer at pengutronix.de>, Pengutronix
> + *
> + * 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 version 2
> + * as published by the Free Software Foundation.
> + *
> + * 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.
> + *
> + */
> +
> +#define pr_fmt(fmt) "mmu: " fmt
> +
> +#include <common.h>
> +#include <dma-dir.h>
> +#include <init.h>
> +#include <mmu.h>
> +#include <errno.h>
> +#include <linux/sizes.h>
> +#include <asm/memory.h>
> +#include <asm/barebox-arm.h>
> +#include <asm/system.h>
> +#include <asm/cache.h>
> +#include <memory.h>
> +#include <asm/system_info.h>
> +
> +#include "mmu.h"
> +
> +static unsigned long *ttb;
> +
> +static void create_sections(unsigned long virt, unsigned long phys, int size_m,
> + unsigned int flags)
> +{
> + int i;
> +
> + phys >>= 20;
> + virt >>= 20;
> +
> + for (i = size_m; i > 0; i--, virt++, phys++)
> + ttb[virt] = (phys << 20) | flags;
> +
> + __mmu_cache_flush();
> +}
> +
> +/*
> + * Do it the simple way for now and invalidate the entire
> + * tlb
> + */
> +static inline void tlb_invalidate(void)
> +{
> + asm volatile (
> + "mov r0, #0\n"
> + "mcr p15, 0, r0, c7, c10, 4; @ drain write buffer\n"
> + "mcr p15, 0, r0, c8, c6, 0; @ invalidate D TLBs\n"
> + "mcr p15, 0, r0, c8, c5, 0; @ invalidate I TLBs\n"
> + :
> + :
> + : "r0"
> + );
> +}
> +
> +#define PTE_FLAGS_CACHED_V7 (PTE_EXT_TEX(1) | PTE_BUFFERABLE | PTE_CACHEABLE)
> +#define PTE_FLAGS_WC_V7 PTE_EXT_TEX(1)
> +#define PTE_FLAGS_UNCACHED_V7 (0)
> +#define PTE_FLAGS_CACHED_V4 (PTE_SMALL_AP_UNO_SRW | PTE_BUFFERABLE | PTE_CACHEABLE)
> +#define PTE_FLAGS_UNCACHED_V4 PTE_SMALL_AP_UNO_SRW
> +
> +/*
> + * PTE flags to set cached and uncached areas.
> + * This will be determined at runtime.
> + */
> +static uint32_t pte_flags_cached;
> +static uint32_t pte_flags_wc;
> +static uint32_t pte_flags_uncached;
> +
> +#define PTE_MASK ((1 << 12) - 1)
> +
> +static void arm_mmu_not_initialized_error(void)
> +{
> + /*
> + * This means:
> + * - one of the MMU functions like dma_alloc_coherent
> + * or remap_range is called too early, before the MMU is initialized
> + * - Or the MMU initialization has failed earlier
> + */
> + panic("MMU not initialized\n");
> +}
> +
> +/*
> + * Create a second level translation table for the given virtual address.
> + * We initially create a flat uncached mapping on it.
> + * Not yet exported, but may be later if someone finds use for it.
> + */
> +static u32 *arm_create_pte(unsigned long virt)
> +{
> + u32 *table;
> + int i;
> +
> + table = memalign(0x400, 0x400);
> +
> + if (!ttb)
> + arm_mmu_not_initialized_error();
> +
> + ttb[virt >> 20] = (unsigned long)table | PMD_TYPE_TABLE;
> +
> + for (i = 0; i < 256; i++) {
> + table[i] = virt | PTE_TYPE_SMALL | pte_flags_uncached;
> + virt += PAGE_SIZE;
> + }
> +
> + return table;
> +}
> +
> +static u32 *find_pte(unsigned long adr)
> +{
> + u32 *table;
> +
> + if (!ttb)
> + arm_mmu_not_initialized_error();
> +
> + if ((ttb[adr >> 20] & PMD_TYPE_MASK) != PMD_TYPE_TABLE) {
> + struct memory_bank *bank;
> + int i = 0;
> +
> + /*
> + * This should only be called for page mapped memory inside our
> + * memory banks. It's a bug to call it with section mapped memory
> + * locations.
> + */
> + pr_crit("%s: TTB for address 0x%08lx is not of type table\n",
> + __func__, adr);
> + pr_crit("Memory banks:\n");
> + for_each_memory_bank(bank)
> + pr_crit("#%d 0x%08lx - 0x%08lx\n", i, bank->start,
> + bank->start + bank->size - 1);
> + BUG();
> + }
> +
> + /* find the coarse page table base address */
> + table = (u32 *)(ttb[adr >> 20] & ~0x3ff);
> +
> + /* find second level descriptor */
> + return &table[(adr >> PAGE_SHIFT) & 0xff];
> +}
> +
> +static void dma_flush_range(unsigned long start, unsigned long end)
> +{
> + __dma_flush_range(start, end);
> + if (outer_cache.flush_range)
> + outer_cache.flush_range(start, end);
> +}
> +
> +static void dma_inv_range(unsigned long start, unsigned long end)
> +{
> + if (outer_cache.inv_range)
> + outer_cache.inv_range(start, end);
> + __dma_inv_range(start, end);
> +}
> +
> +static int __remap_range(void *_start, size_t size, u32 pte_flags)
> +{
> + unsigned long start = (unsigned long)_start;
> + u32 *p;
> + int numentries, i;
> +
> + numentries = size >> PAGE_SHIFT;
> + p = find_pte(start);
> +
> + for (i = 0; i < numentries; i++) {
> + p[i] &= ~PTE_MASK;
> + p[i] |= pte_flags | PTE_TYPE_SMALL;
> + }
> +
> + dma_flush_range((unsigned long)p,
> + (unsigned long)p + numentries * sizeof(u32));
> +
> + tlb_invalidate();
> +
> + return 0;
> +}
> +
> +int arch_remap_range(void *start, size_t size, unsigned flags)
> +{
> + u32 pte_flags;
> +
> + switch (flags) {
> + case MAP_CACHED:
> + pte_flags = pte_flags_cached;
> + break;
> + case MAP_UNCACHED:
> + pte_flags = pte_flags_uncached;
> + break;
> + default:
> + return -EINVAL;
> + }
> +
> + return __remap_range(start, size, pte_flags);
> +}
> +
> +void *map_io_sections(unsigned long phys, void *_start, size_t size)
> +{
> + unsigned long start = (unsigned long)_start, sec;
> +
> + phys >>= 20;
> + for (sec = start; sec < start + size; sec += (1 << 20))
> + ttb[sec >> 20] = (phys++ << 20) | PMD_SECT_DEF_UNCACHED;
> +
> + dma_flush_range((unsigned long)ttb, (unsigned long)ttb + 0x4000);
> + tlb_invalidate();
> + return _start;
> +}
> +
> +/*
> + * remap the memory bank described by mem cachable and
> + * bufferable
> + */
> +static int arm_mmu_remap_sdram(struct memory_bank *bank)
> +{
> + unsigned long phys = (unsigned long)bank->start;
> + unsigned long ttb_start = phys >> 20;
> + unsigned long ttb_end = (phys >> 20) + (bank->size >> 20);
> + unsigned long num_ptes = bank->size >> 12;
> + int i, pte;
> + u32 *ptes;
> +
> + pr_debug("remapping SDRAM from 0x%08lx (size 0x%08lx)\n",
> + phys, bank->size);
> +
> + /*
> + * We replace each 1MiB section in this range with second level page
> + * tables, therefore we must have 1Mib aligment here.
> + */
> + if ((phys & (SZ_1M - 1)) || (bank->size & (SZ_1M - 1)))
> + return -EINVAL;
> +
> + ptes = xmemalign(PAGE_SIZE, num_ptes * sizeof(u32));
> +
> + pr_debug("ptes: 0x%p ttb_start: 0x%08lx ttb_end: 0x%08lx\n",
> + ptes, ttb_start, ttb_end);
> +
> + for (i = 0; i < num_ptes; i++) {
> + ptes[i] = (phys + i * PAGE_SIZE) | PTE_TYPE_SMALL |
> + pte_flags_cached;
> + }
> +
> + pte = 0;
> +
> + for (i = ttb_start; i < ttb_end; i++) {
> + ttb[i] = (unsigned long)(&ptes[pte]) | PMD_TYPE_TABLE |
> + (0 << 4);
> + pte += 256;
> + }
> +
> + dma_flush_range((unsigned long)ttb, (unsigned long)ttb + 0x4000);
> + dma_flush_range((unsigned long)ptes,
> + (unsigned long)ptes + num_ptes * sizeof(u32));
> +
> + tlb_invalidate();
> +
> + return 0;
> +}
> +/*
> + * We have 8 exception vectors and the table consists of absolute
> + * jumps, so we need 8 * 4 bytes for the instructions and another
> + * 8 * 4 bytes for the addresses.
> + */
> +#define ARM_VECTORS_SIZE (sizeof(u32) * 8 * 2)
> +
> +/*
> + * Map vectors and zero page
> + */
> +static void vectors_init(void)
> +{
> + u32 *exc, *zero = NULL;
> + void *vectors;
> + u32 cr;
> +
> + cr = get_cr();
> + cr |= CR_V;
> + set_cr(cr);
> + cr = get_cr();
> +
> + if (cr & CR_V) {
> + /*
> + * If we can use high vectors, create the second level
> + * page table for the high vectors and zero page
> + */
> + exc = arm_create_pte(0xfff00000);
> + zero = arm_create_pte(0x0);
> +
> + /* Set the zero page to faulting */
> + zero[0] = 0;
> + } else {
> + /*
> + * Otherwise map the vectors to the zero page. We have to
> + * live without being able to catch NULL pointer dereferences
> + */
> + exc = arm_create_pte(0x0);
> +
> + if (cpu_architecture() >= CPU_ARCH_ARMv7) {
> + /*
> + * ARMv7 CPUs allow to remap low vectors from
> + * 0x0 to an arbitrary address using VBAR
> + * register, so let's make sure we have it
> + * pointing to the correct address
> + */
> + set_vbar(0x0);
> + }
> + }
> +
> + arm_fixup_vectors();
> +
> + vectors = xmemalign(PAGE_SIZE, PAGE_SIZE);
> + memset(vectors, 0, PAGE_SIZE);
> + memcpy(vectors, __exceptions_start, __exceptions_stop - __exceptions_start);
> +
> + if (cr & CR_V)
> + exc[256 - 16] = (u32)vectors | PTE_TYPE_SMALL |
> + pte_flags_cached;
> + else
> + exc[0] = (u32)vectors | PTE_TYPE_SMALL | pte_flags_cached;
> +}
> +
> +/*
> + * Prepare MMU for usage enable it.
> + */
> +static int mmu_init(void)
> +{
> + struct memory_bank *bank;
> + int i;
> +
> + if (list_empty(&memory_banks))
> + /*
> + * If you see this it means you have no memory registered.
> + * This can be done either with arm_add_mem_device() in an
> + * initcall prior to mmu_initcall or via devicetree in the
> + * memory node.
> + */
> + panic("MMU: No memory bank found! Cannot continue\n");
> +
> + arm_set_cache_functions();
> +
> + if (cpu_architecture() >= CPU_ARCH_ARMv7) {
> + pte_flags_cached = PTE_FLAGS_CACHED_V7;
> + pte_flags_wc = PTE_FLAGS_WC_V7;
> + pte_flags_uncached = PTE_FLAGS_UNCACHED_V7;
> + } else {
> + pte_flags_cached = PTE_FLAGS_CACHED_V4;
> + pte_flags_wc = PTE_FLAGS_UNCACHED_V4;
> + pte_flags_uncached = PTE_FLAGS_UNCACHED_V4;
> + }
> +
> + if (get_cr() & CR_M) {
> + /*
> + * Early MMU code has already enabled the MMU. We assume a
> + * flat 1:1 section mapping in this case.
> + */
> + asm volatile ("mrc p15,0,%0,c2,c0,0" : "=r"(ttb));
> +
> + /* Clear unpredictable bits [13:0] */
> + ttb = (unsigned long *)((unsigned long)ttb & ~0x3fff);
> +
> + if (!request_sdram_region("ttb", (unsigned long)ttb, SZ_16K))
> + /*
> + * This can mean that:
> + * - the early MMU code has put the ttb into a place
> + * which we don't have inside our available memory
> + * - Somebody else has occupied the ttb region which means
> + * the ttb will get corrupted.
> + */
> + pr_crit("Critical Error: Can't request SDRAM region for ttb at %p\n",
> + ttb);
> + } else {
> + ttb = memalign(0x10000, 0x4000);
> + }
> +
> + pr_debug("ttb: 0x%p\n", ttb);
> +
> + /* Set the ttb register */
> + asm volatile ("mcr p15,0,%0,c2,c0,0" : : "r"(ttb) /*:*/);
> +
> + /* Set the Domain Access Control Register */
> + i = 0x3;
> + asm volatile ("mcr p15,0,%0,c3,c0,0" : : "r"(i) /*:*/);
> +
> + /* create a flat mapping using 1MiB sections */
> + create_sections(0, 0, PAGE_SIZE, PMD_SECT_AP_WRITE | PMD_SECT_AP_READ |
> + PMD_TYPE_SECT);
> +
> + vectors_init();
> +
> + /*
> + * First remap sdram cached using sections.
> + * This is to speed up the generation of 2nd level page tables
> + * below
> + */
> + for_each_memory_bank(bank)
> + create_sections(bank->start, bank->start, bank->size >> 20,
> + PMD_SECT_DEF_CACHED);
> +
> + __mmu_cache_on();
> +
> + /*
> + * Now that we have the MMU and caches on remap sdram again using
> + * page tables
> + */
> + for_each_memory_bank(bank)
> + arm_mmu_remap_sdram(bank);
> +
> + return 0;
> +}
> +mmu_initcall(mmu_init);
> +
> +void *dma_alloc_coherent(size_t size, dma_addr_t *dma_handle)
> +{
> + void *ret;
> +
> + size = PAGE_ALIGN(size);
> + ret = xmemalign(PAGE_SIZE, size);
> + if (dma_handle)
> + *dma_handle = (dma_addr_t)ret;
> +
> + dma_inv_range((unsigned long)ret, (unsigned long)ret + size);
> +
> + __remap_range(ret, size, pte_flags_uncached);
> +
> + return ret;
> +}
> +
> +void *dma_alloc_writecombine(size_t size, dma_addr_t *dma_handle)
> +{
> + void *ret;
> +
> + size = PAGE_ALIGN(size);
> + ret = xmemalign(PAGE_SIZE, size);
> + if (dma_handle)
> + *dma_handle = (dma_addr_t)ret;
> +
> + dma_inv_range((unsigned long)ret, (unsigned long)ret + size);
> +
> + __remap_range(ret, size, pte_flags_wc);
> +
> + return ret;
> +}
> +
> +unsigned long virt_to_phys(volatile void *virt)
> +{
> + return (unsigned long)virt;
> +}
> +
> +void *phys_to_virt(unsigned long phys)
> +{
> + return (void *)phys;
> +}
> +
> +void dma_free_coherent(void *mem, dma_addr_t dma_handle, size_t size)
> +{
> + size = PAGE_ALIGN(size);
> + __remap_range(mem, size, pte_flags_cached);
> +
> + free(mem);
> +}
> +
> +void dma_sync_single_for_cpu(unsigned long address, size_t size,
> + enum dma_data_direction dir)
> +{
> + if (dir != DMA_TO_DEVICE) {
> + if (outer_cache.inv_range)
> + outer_cache.inv_range(address, address + size);
> + __dma_inv_range(address, address + size);
> + }
> +}
> +
> +void dma_sync_single_for_device(unsigned long address, size_t size,
> + enum dma_data_direction dir)
> +{
> + if (dir == DMA_FROM_DEVICE) {
> + __dma_inv_range(address, address + size);
> + if (outer_cache.inv_range)
> + outer_cache.inv_range(address, address + size);
> + } else {
> + __dma_clean_range(address, address + size);
> + if (outer_cache.clean_range)
> + outer_cache.clean_range(address, address + size);
> + }
> +}
> diff --git a/arch/arm64/cpu/mmu.h b/arch/arm64/cpu/mmu.h
> new file mode 100644
> index 0000000..79ebc80
> --- /dev/null
> +++ b/arch/arm64/cpu/mmu.h
> @@ -0,0 +1,14 @@
> +#ifndef __ARM_MMU_H
> +#define __ARM_MMU_H
> +
> +#ifdef CONFIG_MMU
> +void __mmu_cache_on(void);
> +void __mmu_cache_off(void);
> +void __mmu_cache_flush(void);
> +#else
> +static inline void __mmu_cache_on(void) {}
> +static inline void __mmu_cache_off(void) {}
> +static inline void __mmu_cache_flush(void) {}
> +#endif
> +
> +#endif /* __ARM_MMU_H */
> diff --git a/arch/arm64/cpu/mmuinfo.c b/arch/arm64/cpu/mmuinfo.c
> new file mode 100644
> index 0000000..c7ec76c
> --- /dev/null
> +++ b/arch/arm64/cpu/mmuinfo.c
> @@ -0,0 +1,104 @@
> +/*
> + * mmuinfo.c - Show MMU/cache information from cp15 registers
> + *
> + * Copyright (c) Jan Luebbe <j.luebbe at pengutronix.de>, Pengutronix
> + *
> + * 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 version 2
> + * as published by the Free Software Foundation.
> + *
> + * 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.
> + *
> + */
> +
> +#include <common.h>
> +#include <command.h>
> +
> +static char *inner_attr[] = {
> + "0b000 Non-cacheable",
> + "0b001 Strongly-ordered",
> + "0b010 (reserved)",
> + "0b011 Device",
> + "0b100 (reserved)",
> + "0b101 Write-Back, Write-Allocate",
> + "0b110 Write-Through",
> + "0b111 Write-Back, no Write-Allocate",
> +};
> +
> +static char *outer_attr[] = {
> + "0b00 Non-cacheable",
> + "0b01 Write-Back, Write-Allocate",
> + "0b10 Write-Through, no Write-Allocate",
> + "0b11 Write-Back, no Write-Allocate",
> +};
> +
> +static void decode_par(unsigned long par)
> +{
> + printf(" Physical Address [31:12]: 0x%08lx\n", par & 0xFFFFF000);
> + printf(" Reserved [11]: 0x%lx\n", (par >> 11) & 0x1);
> + printf(" Not Outer Shareable [10]: 0x%lx\n", (par >> 10) & 0x1);
> + printf(" Non-Secure [9]: 0x%lx\n", (par >> 9) & 0x1);
> + printf(" Impl. def. [8]: 0x%lx\n", (par >> 8) & 0x1);
> + printf(" Shareable [7]: 0x%lx\n", (par >> 7) & 0x1);
> + printf(" Inner mem. attr. [6:4]: 0x%lx (%s)\n", (par >> 4) & 0x7,
> + inner_attr[(par >> 4) & 0x7]);
> + printf(" Outer mem. attr. [3:2]: 0x%lx (%s)\n", (par >> 2) & 0x3,
> + outer_attr[(par >> 2) & 0x3]);
> + printf(" SuperSection [1]: 0x%lx\n", (par >> 1) & 0x1);
> + printf(" Failure [0]: 0x%lx\n", (par >> 0) & 0x1);
> +}
> +
> +static int do_mmuinfo(int argc, char *argv[])
> +{
> + unsigned long addr = 0, priv_read, priv_write;
> +
> + if (argc < 2)
> + return COMMAND_ERROR_USAGE;
> +
> + addr = strtoul_suffix(argv[1], NULL, 0);
> +
> + __asm__ __volatile__(
> + "mcr p15, 0, %0, c7, c8, 0 @ write VA to PA translation (priv read)\n"
> + :
> + : "r" (addr)
> + : "memory");
> +
> + __asm__ __volatile__(
> + "mrc p15, 0, %0, c7, c4, 0 @ read PAR\n"
> + : "=r" (priv_read)
> + :
> + : "memory");
> +
> + __asm__ __volatile__(
> + "mcr p15, 0, %0, c7, c8, 1 @ write VA to PA translation (priv write)\n"
> + :
> + : "r" (addr)
> + : "memory");
> +
> + __asm__ __volatile__(
> + "mrc p15, 0, %0, c7, c4, 0 @ read PAR\n"
> + : "=r" (priv_write)
> + :
> + : "memory");
> +
> + printf("PAR result for 0x%08lx: \n", addr);
> + printf(" privileged read: 0x%08lx\n", priv_read);
> + decode_par(priv_read);
> + printf(" privileged write: 0x%08lx\n", priv_write);
> + decode_par(priv_write);
> +
> + return 0;
> +}
> +
> +BAREBOX_CMD_START(mmuinfo)
> + .cmd = do_mmuinfo,
> + BAREBOX_CMD_DESC("show MMU/cache information of an address")
> + BAREBOX_CMD_OPTS("ADDRESS")
> + BAREBOX_CMD_GROUP(CMD_GRP_INFO)
> +BAREBOX_CMD_END
> diff --git a/arch/arm64/cpu/no-mmu.c b/arch/arm64/cpu/no-mmu.c
> new file mode 100644
> index 0000000..4559509
> --- /dev/null
> +++ b/arch/arm64/cpu/no-mmu.c
> @@ -0,0 +1,61 @@
> +/*
> + * Copyright (c) 2015 Zodiac Inflight Innovation
> + * Author: Andrey Smirnov <andrew.smirnov at gmail.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2
> + * as published by the Free Software Foundation.
> + *
> + * 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.
> + *
> + */
> +
> +#define pr_fmt(fmt) "nommu: " fmt
> +
> +#include <common.h>
> +#include <dma-dir.h>
> +#include <init.h>
> +#include <mmu.h>
> +#include <errno.h>
> +#include <linux/sizes.h>
> +#include <asm/memory.h>
> +#include <asm/barebox-arm.h>
> +#include <asm/system.h>
> +#include <asm/cache.h>
> +#include <memory.h>
> +#include <asm/system_info.h>
> +#include <debug_ll.h>
> +
> +
> +#define __exceptions_size (__exceptions_stop - __exceptions_start)
> +
> +static int nommu_v8_vectors_init(void)
> +{
> + void *vectors;
> + u32 cr;
> +
> + if (cpu_architecture() < CPU_ARCH_ARMv8)
> + return 0;
> +
> +// /*
> +// * High vectors cannot be re-mapped, so we have to use normal
> +// * vectors
> +// */
> +// cr = get_cr();
> +// cr &= ~CR_V;
> +// set_cr(cr);
> +//
> +// arm_fixup_vectors();
> +//
> +// vectors = xmemalign(PAGE_SIZE, PAGE_SIZE);
> +// memset(vectors, 0, PAGE_SIZE);
> +// memcpy(vectors, __exceptions_start, __exceptions_size);
> +//
> +// set_vbar((unsigned int)vectors);
> +
> + return 0;
> +}
> +mmu_initcall(nommu_v8_vectors_init);
> diff --git a/arch/arm64/cpu/start-pbl.c b/arch/arm64/cpu/start-pbl.c
> new file mode 100644
> index 0000000..f723edc
> --- /dev/null
> +++ b/arch/arm64/cpu/start-pbl.c
> @@ -0,0 +1,102 @@
> +/*
> + * start-pbl.c
> + *
> + * Copyright (c) 2010-2012 Sascha Hauer <s.hauer at pengutronix.de>, Pengutronix
> + * Copyright (c) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj at jcrosoft.com>
> + *
> + * See file CREDITS for list of people who contributed to this
> + * project.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2
> + * as published by the Free Software Foundation.
> + *
> + * 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.
> + *
> + */
> +
> +#include <common.h>
> +#include <init.h>
> +#include <linux/sizes.h>
> +#include <pbl.h>
> +#include <asm/barebox-arm.h>
> +#include <asm/barebox-arm-head.h>
> +#include <asm-generic/memory_layout.h>
> +#include <asm/sections.h>
> +#include <asm/pgtable.h>
> +#include <asm/cache.h>
> +
> +#include "mmu-early.h"
> +
> +unsigned long free_mem_ptr;
> +unsigned long free_mem_end_ptr;
> +
> +/*
> + * First instructions in the pbl image
> + */
> +void __naked __section(.text_head_entry) pbl_start(void)
> +{
> + barebox_arm_head();
> +}
> +
> +extern void *input_data;
> +extern void *input_data_end;
> +
> +__noreturn void barebox_single_pbl_start(unsigned long membase,
> + unsigned long memsize, void *boarddata)
> +{
> + uint32_t offset;
> + uint32_t pg_start, pg_end, pg_len;
> + void __noreturn (*barebox)(unsigned long, unsigned long, void *);
> + uint32_t endmem = membase + memsize;
> + unsigned long barebox_base;
> +
> + if (IS_ENABLED(CONFIG_PBL_RELOCATABLE))
> + relocate_to_current_adr();
> +
> + /* Get offset between linked address and runtime address */
> + offset = get_runtime_offset();
> +
> + pg_start = (uint32_t)&input_data - offset;
> + pg_end = (uint32_t)&input_data_end - offset;
> + pg_len = pg_end - pg_start;
> +
> + if (IS_ENABLED(CONFIG_RELOCATABLE))
> + barebox_base = arm_mem_barebox_image(membase, endmem, pg_len);
> + else
> + barebox_base = TEXT_BASE;
> +
> + if (offset && (IS_ENABLED(CONFIG_PBL_FORCE_PIGGYDATA_COPY) ||
> + region_overlap(pg_start, pg_len, barebox_base, pg_len * 4))) {
> + /*
> + * copy piggydata binary to its link address
> + */
> + memcpy(&input_data, (void *)pg_start, pg_len);
> + pg_start = (uint32_t)&input_data;
> + }
> +
> + setup_c();
> +
> + if (IS_ENABLED(CONFIG_MMU_EARLY)) {
> + unsigned long ttb = arm_mem_ttb(membase, endmem);
> + mmu_early_enable(membase, memsize, ttb);
> + }
> +
> + free_mem_ptr = arm_mem_early_malloc(membase, endmem);
> + free_mem_end_ptr = arm_mem_early_malloc_end(membase, endmem);
> +
> + pbl_barebox_uncompress((void*)barebox_base, (void *)pg_start, pg_len);
> +
> + arm_early_mmu_cache_flush();
> + flush_icache();
> +
> + if (IS_ENABLED(CONFIG_THUMB2_BAREBOX))
> + barebox = (void *)(barebox_base + 1);
> + else
> + barebox = (void *)barebox_base;
> +
> + barebox(membase, memsize, boarddata);
> +}
> diff --git a/arch/arm64/cpu/start.c b/arch/arm64/cpu/start.c
> new file mode 100644
> index 0000000..e4a48e3
> --- /dev/null
> +++ b/arch/arm64/cpu/start.c
> @@ -0,0 +1,247 @@
> +/*
> + * Copyright (c) 2010 Sascha Hauer <s.hauer at pengutronix.de>, Pengutronix
> + *
> + * 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 version 2
> + * as published by the Free Software Foundation.
> + *
> + * 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.
> + *
> + */
> +#define pr_fmt(fmt) "start.c: " fmt
> +
> +#include <common.h>
> +#include <init.h>
> +#include <linux/sizes.h>
> +#include <of.h>
> +#include <asm/barebox-arm.h>
> +#include <asm/barebox-arm-head.h>
> +#include <asm-generic/memory_layout.h>
> +#include <asm/sections.h>
> +#include <asm/unaligned.h>
> +#include <asm/cache.h>
> +#include <memory.h>
> +#include <uncompress.h>
> +#include <malloc.h>
> +
> +#include <debug_ll.h>
> +#include "mmu-early.h"
> +
> +unsigned long arm_stack_top;
> +static unsigned long arm_head_bottom;
> +static unsigned long arm_barebox_size;
> +static void *barebox_boarddata;
> +
> +static bool blob_is_fdt(const void *blob)
> +{
> + return get_unaligned_be32(blob) == FDT_MAGIC;
> +}
> +
> +static bool blob_is_compressed_fdt(const void *blob)
> +{
> + const struct barebox_arm_boarddata_compressed_dtb *dtb = blob;
> +
> + return dtb->magic == BAREBOX_ARM_BOARDDATA_COMPRESSED_DTB_MAGIC;
> +}
> +
> +static bool blob_is_arm_boarddata(const void *blob)
> +{
> + const struct barebox_arm_boarddata *bd = blob;
> +
> + return bd->magic == BAREBOX_ARM_BOARDDATA_MAGIC;
> +}
> +
> +u32 barebox_arm_machine(void)
> +{
> + if (barebox_boarddata && blob_is_arm_boarddata(barebox_boarddata)) {
> + const struct barebox_arm_boarddata *bd = barebox_boarddata;
> + return bd->machine;
> + } else {
> + return 0;
> + }
> +}
> +
> +void *barebox_arm_boot_dtb(void)
> +{
> + void *dtb;
> + void *data;
> + int ret;
> + struct barebox_arm_boarddata_compressed_dtb *compressed_dtb;
> +
> + if (barebox_boarddata && blob_is_fdt(barebox_boarddata)) {
> + pr_debug("%s: using barebox_boarddata\n", __func__);
> + return barebox_boarddata;
> + }
> +
> + if (!IS_ENABLED(CONFIG_ARM_USE_COMPRESSED_DTB) || !barebox_boarddata
> + || !blob_is_compressed_fdt(barebox_boarddata))
> + return NULL;
> +
> + compressed_dtb = barebox_boarddata;
> +
> + pr_debug("%s: using compressed_dtb\n", __func__);
> +
> + dtb = malloc(compressed_dtb->datalen_uncompressed);
> + if (!dtb)
> + return NULL;
> +
> + data = compressed_dtb + 1;
> +
> + ret = uncompress(data, compressed_dtb->datalen, NULL, NULL,
> + dtb, NULL, NULL);
> + if (ret) {
> + pr_err("uncompressing dtb failed\n");
> + free(dtb);
> + return NULL;
> + }
> +
> + barebox_boarddata = dtb;
> +
> + return barebox_boarddata;
> +}
> +
> +static inline unsigned long arm_mem_boarddata(unsigned long membase,
> + unsigned long endmem,
> + unsigned long size)
> +{
> + unsigned long mem;
> +
> + mem = arm_mem_barebox_image(membase, endmem, barebox_image_size);
> + mem -= ALIGN(size, 64);
> +
> + return mem;
> +}
> +
> +unsigned long arm_mem_ramoops_get(void)
> +{
> + return arm_mem_ramoops(0, arm_stack_top);
> +}
> +EXPORT_SYMBOL_GPL(arm_mem_ramoops_get);
> +
> +static int barebox_memory_areas_init(void)
> +{
> + unsigned long start = arm_head_bottom;
> + unsigned long size = arm_mem_barebox_image(0, arm_stack_top,
> + arm_barebox_size) -
> + arm_head_bottom;
> + request_sdram_region("board data", start, size);
> +
> + return 0;
> +}
> +device_initcall(barebox_memory_areas_init);
> +
> +__noreturn void barebox_non_pbl_start(unsigned long membase,
> + unsigned long memsize, void *boarddata)
> +{
> + unsigned long endmem = membase + memsize;
> + unsigned long malloc_start, malloc_end;
> + unsigned long barebox_size = barebox_image_size +
> + ((unsigned long)&__bss_stop - (unsigned long)&__bss_start);
> +
> + if (IS_ENABLED(CONFIG_RELOCATABLE)) {
> + unsigned long barebox_base = arm_mem_barebox_image(membase,
> + endmem,
> + barebox_size);
> + relocate_to_adr(barebox_base);
> + }
> +
> +// setup_c();
> +
> + barrier();
> +
> + pr_debug("memory at 0x%08lx, size 0x%08lx\n", membase, memsize);
> +
> + arm_stack_top = endmem;
> + arm_barebox_size = barebox_size;
> + arm_head_bottom = arm_mem_barebox_image(membase, endmem,
> + arm_barebox_size);
> +
> + if (IS_ENABLED(CONFIG_MMU_EARLY)) {
> + unsigned long ttb = arm_mem_ttb(membase, endmem);
> +
> + if (IS_ENABLED(CONFIG_PBL_IMAGE)) {
> + arm_set_cache_functions();
> + } else {
> + pr_debug("enabling MMU, ttb @ 0x%08lx\n", ttb);
> + arm_early_mmu_cache_invalidate();
> + mmu_early_enable(membase, memsize, ttb);
> + }
> + }
> +
> + if (boarddata) {
> + uint32_t totalsize = 0;
> + const char *name;
> +
> + if (blob_is_fdt(boarddata)) {
> + totalsize = get_unaligned_be32(boarddata + 4);
> + name = "DTB";
> + } else if (blob_is_compressed_fdt(boarddata)) {
> + struct barebox_arm_boarddata_compressed_dtb *bd = boarddata;
> + totalsize = bd->datalen + sizeof(*bd);
> + name = "Compressed DTB";
> + } else if (blob_is_arm_boarddata(boarddata)) {
> + totalsize = sizeof(struct barebox_arm_boarddata);
> + name = "machine type";
> + }
> +
> + if (totalsize) {
> + unsigned long mem = arm_mem_boarddata(membase, endmem,
> + totalsize);
> + pr_debug("found %s in boarddata, copying to 0x%lu\n",
> + name, mem);
> + barebox_boarddata = memcpy((void *)mem, boarddata,
> + totalsize);
> + arm_head_bottom = mem;
> + }
> + }
> +
> + malloc_end = arm_head_bottom;
> +
> + /*
> + * Maximum malloc space is the Kconfig value if given
> + * or 1GB.
> + */
> + if (MALLOC_SIZE > 0) {
> + malloc_start = malloc_end - MALLOC_SIZE;
> + if (malloc_start < membase)
> + malloc_start = membase;
> + } else {
> + malloc_start = malloc_end - (malloc_end - membase) / 2;
> + if (malloc_end - malloc_start > SZ_1G)
> + malloc_start = malloc_end - SZ_1G;
> + }
> +
> + pr_debug("initializing malloc pool at 0x%08lx (size 0x%08lx)\n",
> + malloc_start, malloc_end - malloc_start);
> +
> + mem_malloc_init((void *)malloc_start, (void *)malloc_end - 1);
> +
> + pr_debug("starting barebox...\n");
> +
> + start_barebox();
> +}
> +
> +#ifndef CONFIG_PBL_IMAGE
> +
> +void __section(.text_entry) start(void)
> +{
> + barebox_arm_head();
> +}
> +
> +#else
> +/*
> + * First function in the uncompressed image. We get here from
> + * the pbl. The stack already has been set up by the pbl.
> + */
> +void __section(.text_entry) start(unsigned long membase,
> + unsigned long memsize, void *boarddata)
> +{
> + barebox_non_pbl_start(membase, memsize, boarddata);
> +}
> +#endif
> diff --git a/arch/arm64/cpu/uncompress.c b/arch/arm64/cpu/uncompress.c
> new file mode 100644
> index 0000000..5bcce6b
> --- /dev/null
> +++ b/arch/arm64/cpu/uncompress.c
> @@ -0,0 +1,111 @@
> +/*
> + * uncompress.c - uncompressor code for self extracing pbl image
> + *
> + * Copyright (c) 2010-2013 Sascha Hauer <s.hauer at pengutronix.de>, Pengutronix
> + * Copyright (c) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj at jcrosoft.com>
> + *
> + * See file CREDITS for list of people who contributed to this
> + * project.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2
> + * as published by the Free Software Foundation.
> + *
> + * 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.
> + *
> + */
> +#define pr_fmt(fmt) "uncompress.c: " fmt
> +
> +#include <common.h>
> +#include <init.h>
> +#include <linux/sizes.h>
> +#include <pbl.h>
> +#include <asm/barebox-arm.h>
> +#include <asm/barebox-arm-head.h>
> +#include <asm-generic/memory_layout.h>
> +#include <asm/sections.h>
> +#include <asm/pgtable.h>
> +#include <asm/cache.h>
> +
> +#include <debug_ll.h>
> +
> +#include "mmu-early.h"
> +
> +unsigned long free_mem_ptr;
> +unsigned long free_mem_end_ptr;
> +
> +static int __attribute__((__used__))
> + __attribute__((__section__(".image_end")))
> + __image_end_dummy = 0xdeadbeef;
> +
> +void __noreturn barebox_multi_pbl_start(unsigned long membase,
> + unsigned long memsize, void *boarddata)
> +{
> + uint32_t pg_len;
> + void __noreturn (*barebox)(unsigned long, unsigned long, void *);
> + uint32_t endmem = membase + memsize;
> + unsigned long barebox_base;
> + uint32_t *image_end;
> + void *pg_start;
> + unsigned long pc = get_pc();
> +
> + image_end = (void *)ld_var(__image_end) - get_runtime_offset();
> +
> + if (IS_ENABLED(CONFIG_PBL_RELOCATABLE)) {
> + /*
> + * If we run from inside the memory just relocate the binary
> + * to the current address. Otherwise it may be a readonly location.
> + * Copy and relocate to the start of the memory in this case.
> + */
> + if (pc > membase && pc < membase + memsize)
> + relocate_to_current_adr();
> + else
> + relocate_to_adr(membase);
> + }
> +
> + /*
> + * image_end is the first location after the executable. It contains
> + * the size of the appended compressed binary followed by the binary.
> + */
> + pg_start = image_end + 1;
> + pg_len = *(image_end);
> +
> + if (IS_ENABLED(CONFIG_RELOCATABLE))
> + barebox_base = arm_mem_barebox_image(membase, endmem,
> + pg_len);
> + else
> + barebox_base = TEXT_BASE;
> +
> + setup_c();
> +
> + pr_debug("memory at 0x%08lx, size 0x%08lx\n", membase, memsize);
> +
> + if (IS_ENABLED(CONFIG_MMU_EARLY)) {
> + unsigned long ttb = arm_mem_ttb(membase, endmem);
> + pr_debug("enabling MMU, ttb @ 0x%08lx\n", ttb);
> + mmu_early_enable(membase, memsize, ttb);
> + }
> +
> + free_mem_ptr = arm_mem_early_malloc(membase, endmem);
> + free_mem_end_ptr = arm_mem_early_malloc_end(membase, endmem);
> +
> + pr_debug("uncompressing barebox binary at 0x%p (size 0x%08x) to 0x%08lx\n",
> + pg_start, pg_len, barebox_base);
> +
> + pbl_barebox_uncompress((void*)barebox_base, pg_start, pg_len);
> +
> + arm_early_mmu_cache_flush();
> + flush_icache();
> +
> + if (IS_ENABLED(CONFIG_THUMB2_BAREBOX))
> + barebox = (void *)(barebox_base + 1);
> + else
> + barebox = (void *)barebox_base;
> +
> + pr_debug("jumping to uncompressed image at 0x%p\n", barebox);
> +
> + barebox(membase, memsize, boarddata);
> +}
> diff --git a/arch/arm64/include/asm/armlinux.h b/arch/arm64/include/asm/armlinux.h
> new file mode 100644
> index 0000000..07479fb
> --- /dev/null
> +++ b/arch/arm64/include/asm/armlinux.h
> @@ -0,0 +1,43 @@
> +#ifndef __ARCH_ARMLINUX_H
> +#define __ARCH_ARMLINUX_H
> +
> +#include <asm/memory.h>
> +#include <asm/setup.h>
> +
> +#if defined CONFIG_ARM_LINUX
> +void armlinux_set_bootparams(void *params);
> +void armlinux_set_architecture(int architecture);
> +void armlinux_set_revision(unsigned int);
> +void armlinux_set_serial(u64);
> +#else
> +static inline void armlinux_set_bootparams(void *params)
> +{
> +}
> +
> +static inline void armlinux_set_architecture(int architecture)
> +{
> +}
> +
> +static inline void armlinux_set_revision(unsigned int rev)
> +{
> +}
> +
> +static inline void armlinux_set_serial(u64 serial)
> +{
> +}
> +#endif
> +
> +#if defined CONFIG_ARM_BOARD_APPEND_ATAG
> +void armlinux_set_atag_appender(struct tag *(*)(struct tag *));
> +#else
> +static inline void armlinux_set_atag_appender(struct tag *(*func)(struct tag *))
> +{
> +}
> +#endif
> +
> +struct image_data;
> +
> +void start_linux(void *adr, int swap, unsigned long initrd_address,
> + unsigned long initrd_size, void *oftree);
> +
> +#endif /* __ARCH_ARMLINUX_H */
> diff --git a/arch/arm64/include/asm/assembler.h b/arch/arm64/include/asm/assembler.h
> new file mode 100644
> index 0000000..6116e48
> --- /dev/null
> +++ b/arch/arm64/include/asm/assembler.h
> @@ -0,0 +1,116 @@
> +/*
> + * arch/arm/include/asm/assembler.h
> + *
> + * Copyright (C) 1996-2000 Russell King
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This file contains arm architecture specific defines
> + * for the different processors.
> + *
> + * Do not include any C declarations in this file - it is included by
> + * assembler source.
> + */
> +#ifndef __ASSEMBLY__
> +#error "Only include this from assembly code"
> +#endif
> +
> +#include <asm/ptrace.h>
> +
> +/*
> + * Endian independent macros for shifting bytes within registers.
> + */
> +#ifndef __ARMEB__
> +#define pull lsr
> +#define push lsl
> +#define get_byte_0 lsl #0
> +#define get_byte_1 lsr #8
> +#define get_byte_2 lsr #16
> +#define get_byte_3 lsr #24
> +#define put_byte_0 lsl #0
> +#define put_byte_1 lsl #8
> +#define put_byte_2 lsl #16
> +#define put_byte_3 lsl #24
> +#else
> +#define pull lsl
> +#define push lsr
> +#define get_byte_0 lsr #24
> +#define get_byte_1 lsr #16
> +#define get_byte_2 lsr #8
> +#define get_byte_3 lsl #0
> +#define put_byte_0 lsl #24
> +#define put_byte_1 lsl #16
> +#define put_byte_2 lsl #8
> +#define put_byte_3 lsl #0
> +#endif
> +
> +/*
> + * Data preload for architectures that support it
> + */
> +#if __LINUX_ARM_ARCH__ >= 5
> +#define PLD(code...) code
> +#else
> +#define PLD(code...)
> +#endif
> +
> +/*
> + * This can be used to enable code to cacheline align the destination
> + * pointer when bulk writing to memory. Experiments on StrongARM and
> + * XScale didn't show this a worthwhile thing to do when the cache is not
> + * set to write-allocate (this would need further testing on XScale when WA
> + * is used).
> + *
> + * On Feroceon there is much to gain however, regardless of cache mode.
> + */
> +#ifdef CONFIG_CPU_FEROCEON
> +#define CALGN(code...) code
> +#else
> +#define CALGN(code...)
> +#endif
> +
> +/*
> + * Enable and disable interrupts
> + */
> +#if __LINUX_ARM_ARCH__ >= 6
> + .macro disable_irq
> + cpsid i
> + .endm
> +
> + .macro enable_irq
> + cpsie i
> + .endm
> +#else
> + .macro disable_irq
> + msr cpsr_c, #PSR_I_BIT | SVC_MODE
> + .endm
> +
> + .macro enable_irq
> + msr cpsr_c, #SVC_MODE
> + .endm
> +#endif
> +
> +/*
> + * Save the current IRQ state and disable IRQs. Note that this macro
> + * assumes FIQs are enabled, and that the processor is in SVC mode.
> + */
> + .macro save_and_disable_irqs, oldcpsr
> + mrs \oldcpsr, cpsr
> + disable_irq
> + .endm
> +
> +/*
> + * Restore interrupt state previously stored in a register. We don't
> + * guarantee that this will preserve the flags.
> + */
> + .macro restore_irqs, oldcpsr
> + msr cpsr_c, \oldcpsr
> + .endm
> +
> +#define USER(x...) \
> +9999: x; \
> + .section __ex_table,"a"; \
> + .align 3; \
> + .long 9999b,9001f; \
> + .previous
> diff --git a/arch/arm64/include/asm/barebox-arm-head.h b/arch/arm64/include/asm/barebox-arm-head.h
> new file mode 100644
> index 0000000..0a2eb6b
> --- /dev/null
> +++ b/arch/arm64/include/asm/barebox-arm-head.h
> @@ -0,0 +1,65 @@
> +#ifndef __ASM_ARM_HEAD_H
> +#define __ASM_ARM_HEAD_H
> +
> +#include <asm/system.h>
> +
> +#ifndef __ASSEMBLY__
> +
> +void arm_cpu_lowlevel_init(void);
> +
> +/*
> + * 32 bytes at this offset is reserved in the barebox head for board/SoC
> + * usage
> + */
> +#define ARM_HEAD_SPARE_OFS 0x30
> +#define ARM_HEAD_SPARE_MARKER 0x55555555
> +
> +#ifdef CONFIG_HAVE_MACH_ARM_HEAD
> +#include <mach/barebox-arm-head.h>
> +#else
> +static inline void __barebox_arm_head(void)
> +{
> + __asm__ __volatile__ (
> +#ifdef CONFIG_THUMB2_BAREBOX
> + ".arm\n"
> + "adr r9, 1f + 1\n"
> + "bx r9\n"
> + ".thumb\n"
> + "1:\n"
> + "bl 2f\n"
> + ".rept 10\n"
> + "1: b 1b\n"
> + ".endr\n"
> +#else
> + "b 2f\n"
> + "1: b 1b\n"
> + "1: b 1b\n"
> + "1: b 1b\n"
> + "1: b 1b\n"
> + "1: b 1b\n"
> + "1: b 1b\n"
> + "1: b 1b\n"
> +#endif
> + ".asciz \"barebox\"\n"
> + ".word _text\n" /* text base. If copied there,
> + * barebox can skip relocation
> + */
> + ".word _barebox_image_size\n" /* image size to copy */
> + ".rept 8\n"
> + ".word 0x55555555\n"
> + ".endr\n"
> + "2:\n"
> + );
> +}
> +static inline void barebox_arm_head(void)
> +{
> + __barebox_arm_head();
> + __asm__ __volatile__ (
> + "b barebox_arm_reset_vector\n"
> + );
> +}
> +#endif
> +
> +#endif /* __ASSEMBLY__ */
> +
> +#endif /* __ASM_ARM_HEAD_H */
> diff --git a/arch/arm64/include/asm/barebox-arm.h b/arch/arm64/include/asm/barebox-arm.h
> new file mode 100644
> index 0000000..6713326
> --- /dev/null
> +++ b/arch/arm64/include/asm/barebox-arm.h
> @@ -0,0 +1,165 @@
> +/*
> + * (C) Copyright 2002
> + * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
> + * Marius Groeger <mgroeger at sysgo.de>
> + *
> + * (C) Copyright 2002
> + * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
> + * Alex Zuepke <azu at sysgo.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.
> + *
> + */
> +
> +#ifndef _BAREBOX_ARM_H_
> +#define _BAREBOX_ARM_H_
> +
> +#include <linux/sizes.h>
> +#include <asm-generic/memory_layout.h>
> +#include <linux/kernel.h>
> +#include <linux/types.h>
> +#include <linux/compiler.h>
> +#include <asm/barebox-arm-head.h>
> +
> +/* cpu/.../cpu.c */
> +int cleanup_before_linux(void);
> +
> +/* arch/<arch>board(s)/.../... */
> +int board_init(void);
> +int dram_init (void);
> +
> +extern char __exceptions_start[], __exceptions_stop[];
> +
> +void board_init_lowlevel(void);
> +uint32_t get_runtime_offset(void);
> +
> +void setup_c(void);
> +void relocate_to_current_adr(void);
> +void relocate_to_adr(unsigned long target);
> +void __noreturn barebox_arm_entry(unsigned long membase, unsigned long memsize, void *boarddata);
> +
> +struct barebox_arm_boarddata {
> +#define BAREBOX_ARM_BOARDDATA_MAGIC 0xabe742c3
> + u32 magic;
> + u32 machine; /* machine number to pass to barebox. This may or may
> + * not be a ARM machine number registered on arm.linux.org.uk.
> + * It must only be unique across barebox. Please use a number
> + * that do not potientially clashes with registered machines,
> + * i.e. use a number > 0x10000.
> + */
> +};
> +
> +/*
> + * Create a boarddata struct at given address. Suitable to be passed
> + * as boarddata to barebox_arm_entry(). The machine can be retrieved
> + * later with barebox_arm_machine().
> + */
> +static inline void boarddata_create(void *adr, u32 machine)
> +{
> + struct barebox_arm_boarddata *bd = adr;
> +
> + bd->magic = BAREBOX_ARM_BOARDDATA_MAGIC;
> + bd->machine = machine;
> +}
> +
> +u32 barebox_arm_machine(void);
> +
> +struct barebox_arm_boarddata_compressed_dtb {
> +#define BAREBOX_ARM_BOARDDATA_COMPRESSED_DTB_MAGIC 0x7b66bcbd
> + u32 magic;
> + u32 datalen;
> + u32 datalen_uncompressed;
> +};
> +
> +struct barebox_arm_boarddata *barebox_arm_get_boarddata(void);
> +
> +#if defined(CONFIG_RELOCATABLE) && defined(CONFIG_ARM_EXCEPTIONS)
> +void arm_fixup_vectors(void);
> +#else
> +static inline void arm_fixup_vectors(void)
> +{
> +}
> +#endif
> +
> +void *barebox_arm_boot_dtb(void);
> +
> +static inline unsigned long arm_mem_stack(unsigned long membase,
> + unsigned long endmem)
> +{
> + return endmem - STACK_SIZE;
> +}
> +
> +static inline unsigned long arm_mem_ttb(unsigned long membase,
> + unsigned long endmem)
> +{
> + endmem = arm_mem_stack(membase, endmem);
> + endmem &= ~(SZ_16K - 1);
> + endmem -= SZ_16K;
> +
> + return endmem;
> +}
> +
> +static inline unsigned long arm_mem_early_malloc(unsigned long membase,
> + unsigned long endmem)
> +{
> + return arm_mem_ttb(membase, endmem) - SZ_128K;
> +}
> +
> +static inline unsigned long arm_mem_early_malloc_end(unsigned long membase,
> + unsigned long endmem)
> +{
> + return arm_mem_ttb(membase, endmem);
> +}
> +
> +static inline unsigned long arm_mem_ramoops(unsigned long membase,
> + unsigned long endmem)
> +{
> + endmem = arm_mem_ttb(membase, endmem);
> +#ifdef CONFIG_FS_PSTORE_RAMOOPS
> + endmem -= CONFIG_FS_PSTORE_RAMOOPS_SIZE;
> + endmem &= ~(SZ_4K - 1); /* Align to 4K */
> +#endif
> +
> + return endmem;
> +}
> +
> +static inline unsigned long arm_mem_barebox_image(unsigned long membase,
> + unsigned long endmem,
> + unsigned long size)
> +{
> + endmem = arm_mem_ramoops(membase, endmem);
> +
> + if (IS_ENABLED(CONFIG_RELOCATABLE)) {
> + endmem -= size;
> + endmem &= ~(SZ_1M - 1);
> + }
> +
> + return endmem;
> +}
> +
> +#define ENTRY_FUNCTION(name, arg0, arg1, arg2) \
> + static void __##name(uint32_t, uint32_t, uint32_t); \
> + \
> + void __naked __section(.text_head_entry_##name) name \
> + (uint32_t r0, uint32_t r1, uint32_t r2) \
> + { \
> + __barebox_arm_head(); \
> + __##name(r0, r1, r2); \
> + } \
> + static void __naked noinline __##name \
> + (uint32_t arg0, uint32_t arg1, uint32_t arg2)
> +
> +
> +
> +#endif /* _BAREBOX_ARM_H_ */
> diff --git a/arch/arm64/include/asm/barebox.h b/arch/arm64/include/asm/barebox.h
> new file mode 100644
> index 0000000..31a8e15
> --- /dev/null
> +++ b/arch/arm64/include/asm/barebox.h
> @@ -0,0 +1,12 @@
> +#ifndef _BAREBOX_H_
> +#define _BAREBOX_H_ 1
> +
> +#ifdef CONFIG_ARM_UNWIND
> +#define ARCH_HAS_STACK_DUMP
> +#endif
> +
> +#ifdef CONFIG_ARM_EXCEPTIONS
> +#define ARCH_HAS_DATA_ABORT_MASK
> +#endif
> +
> +#endif /* _BAREBOX_H_ */
> diff --git a/arch/arm64/include/asm/bitops.h b/arch/arm64/include/asm/bitops.h
> new file mode 100644
> index 0000000..ac85a0a
> --- /dev/null
> +++ b/arch/arm64/include/asm/bitops.h
> @@ -0,0 +1,48 @@
> +/*
> + * Copyright (C) 2012 ARM Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * 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, see <http://www.gnu.org/licenses/>.
> + */
> +#ifndef __ASM_BITOPS_H
> +#define __ASM_BITOPS_H
> +
> +#include <linux/compiler.h>
> +
> +#ifndef _LINUX_BITOPS_H
> +#error only <linux/bitops.h> can be included directly
> +#endif
> +
> +/*
> + * Little endian assembly atomic bitops.
> + */
> +extern void set_bit(int nr, volatile unsigned long *p);
> +extern void clear_bit(int nr, volatile unsigned long *p);
> +extern void change_bit(int nr, volatile unsigned long *p);
> +extern int test_and_set_bit(int nr, volatile unsigned long *p);
> +extern int test_and_clear_bit(int nr, volatile unsigned long *p);
> +extern int test_and_change_bit(int nr, volatile unsigned long *p);
> +
> +#include <asm-generic/bitops/__ffs.h>
> +#include <asm-generic/bitops/ffs.h>
> +#include <asm-generic/bitops/__fls.h>
> +#include <asm-generic/bitops/fls.h>
> +
> +#include <asm-generic/bitops/ffz.h>
> +#include <asm-generic/bitops/fls64.h>
> +#include <asm-generic/bitops/find.h>
> +
> +#include <asm-generic/bitops/hweight.h>
> +
> +#include <asm-generic/bitops/ops.h>
> +
> +#endif /* __ASM_BITOPS_H */
> diff --git a/arch/arm64/include/asm/bitsperlong.h b/arch/arm64/include/asm/bitsperlong.h
> new file mode 100644
> index 0000000..6dc0bb0
> --- /dev/null
> +++ b/arch/arm64/include/asm/bitsperlong.h
> @@ -0,0 +1 @@
> +#include <asm-generic/bitsperlong.h>
> diff --git a/arch/arm64/include/asm/byteorder.h b/arch/arm64/include/asm/byteorder.h
> new file mode 100644
> index 0000000..c3489f1
> --- /dev/null
> +++ b/arch/arm64/include/asm/byteorder.h
> @@ -0,0 +1,32 @@
> +/*
> + * linux/include/asm-arm/byteorder.h
> + *
> + * ARM Endian-ness. In little endian mode, the data bus is connected such
> + * that byte accesses appear as:
> + * 0 = d0...d7, 1 = d8...d15, 2 = d16...d23, 3 = d24...d31
> + * and word accesses (data or instruction) appear as:
> + * d0...d31
> + *
> + * When in big endian mode, byte accesses appear as:
> + * 0 = d24...d31, 1 = d16...d23, 2 = d8...d15, 3 = d0...d7
> + * and word accesses (data or instruction) appear as:
> + * d0...d31
> + */
> +#ifndef __ASM_ARM_BYTEORDER_H
> +#define __ASM_ARM_BYTEORDER_H
> +
> +
> +#include <asm/types.h>
> +
> +#if !defined(__STRICT_ANSI__) || defined(__KERNEL__)
> +# define __BYTEORDER_HAS_U64__
> +# define __SWAB_64_THRU_32__
> +#endif
> +
> +#ifdef __ARMEB__
> +#include <linux/byteorder/big_endian.h>
> +#else
> +#include <linux/byteorder/little_endian.h>
> +#endif
> +
> +#endif
> diff --git a/arch/arm64/include/asm/cache-l2x0.h b/arch/arm64/include/asm/cache-l2x0.h
> new file mode 100644
> index 0000000..963dd99
> --- /dev/null
> +++ b/arch/arm64/include/asm/cache-l2x0.h
> @@ -0,0 +1,101 @@
> +/*
> + * arch/arm/include/asm/hardware/cache-l2x0.h
> + *
> + * Copyright (C) 2007 ARM Limited
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * 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.
> + *
> + */
> +
> +#ifndef __ASM_ARM_HARDWARE_L2X0_H
> +#define __ASM_ARM_HARDWARE_L2X0_H
> +
> +#define L2X0_CACHE_ID 0x000
> +#define L2X0_CACHE_TYPE 0x004
> +#define L2X0_CTRL 0x100
> +#define L2X0_AUX_CTRL 0x104
> +#define L2X0_TAG_LATENCY_CTRL 0x108
> +#define L2X0_DATA_LATENCY_CTRL 0x10C
> +#define L2X0_EVENT_CNT_CTRL 0x200
> +#define L2X0_EVENT_CNT1_CFG 0x204
> +#define L2X0_EVENT_CNT0_CFG 0x208
> +#define L2X0_EVENT_CNT1_VAL 0x20C
> +#define L2X0_EVENT_CNT0_VAL 0x210
> +#define L2X0_INTR_MASK 0x214
> +#define L2X0_MASKED_INTR_STAT 0x218
> +#define L2X0_RAW_INTR_STAT 0x21C
> +#define L2X0_INTR_CLEAR 0x220
> +#define L2X0_CACHE_SYNC 0x730
> +#define L2X0_DUMMY_REG 0x740
> +#define L2X0_INV_LINE_PA 0x770
> +#define L2X0_INV_WAY 0x77C
> +#define L2X0_CLEAN_LINE_PA 0x7B0
> +#define L2X0_CLEAN_LINE_IDX 0x7B8
> +#define L2X0_CLEAN_WAY 0x7BC
> +#define L2X0_CLEAN_INV_LINE_PA 0x7F0
> +#define L2X0_CLEAN_INV_LINE_IDX 0x7F8
> +#define L2X0_CLEAN_INV_WAY 0x7FC
> +/*
> + * The lockdown registers repeat 8 times for L310, the L210 has only one
> + * D and one I lockdown register at 0x0900 and 0x0904.
> + */
> +#define L2X0_LOCKDOWN_WAY_D_BASE 0x900
> +#define L2X0_LOCKDOWN_WAY_I_BASE 0x904
> +#define L2X0_LOCKDOWN_STRIDE 0x08
> +#define L2X0_ADDR_FILTER_START 0xC00
> +#define L2X0_ADDR_FILTER_END 0xC04
> +#define L2X0_TEST_OPERATION 0xF00
> +#define L2X0_LINE_DATA 0xF10
> +#define L2X0_LINE_TAG 0xF30
> +#define L2X0_DEBUG_CTRL 0xF40
> +#define L2X0_PREFETCH_CTRL 0xF60
> +#define L2X0_POWER_CTRL 0xF80
> +#define L2X0_DYNAMIC_CLK_GATING_EN (1 << 1)
> +#define L2X0_STNDBY_MODE_EN (1 << 0)
> +
> +/* Registers shifts and masks */
> +#define L2X0_CACHE_ID_PART_MASK (0xf << 6)
> +#define L2X0_CACHE_ID_PART_L210 (1 << 6)
> +#define L2X0_CACHE_ID_PART_L310 (3 << 6)
> +#define L2X0_CACHE_ID_RTL_MASK 0x3f
> +#define L2X0_CACHE_ID_RTL_R0P0 0x0
> +#define L2X0_CACHE_ID_RTL_R1P0 0x2
> +#define L2X0_CACHE_ID_RTL_R2P0 0x4
> +#define L2X0_CACHE_ID_RTL_R3P0 0x5
> +#define L2X0_CACHE_ID_RTL_R3P1 0x6
> +#define L2X0_CACHE_ID_RTL_R3P2 0x8
> +
> +#define L2X0_AUX_CTRL_MASK 0xc0000fff
> +#define L2X0_AUX_CTRL_DATA_RD_LATENCY_SHIFT 0
> +#define L2X0_AUX_CTRL_DATA_RD_LATENCY_MASK 0x7
> +#define L2X0_AUX_CTRL_DATA_WR_LATENCY_SHIFT 3
> +#define L2X0_AUX_CTRL_DATA_WR_LATENCY_MASK (0x7 << 3)
> +#define L2X0_AUX_CTRL_TAG_LATENCY_SHIFT 6
> +#define L2X0_AUX_CTRL_TAG_LATENCY_MASK (0x7 << 6)
> +#define L2X0_AUX_CTRL_DIRTY_LATENCY_SHIFT 9
> +#define L2X0_AUX_CTRL_DIRTY_LATENCY_MASK (0x7 << 9)
> +#define L2X0_AUX_CTRL_ASSOCIATIVITY_SHIFT 16
> +#define L2X0_AUX_CTRL_WAY_SIZE_SHIFT 17
> +#define L2X0_AUX_CTRL_WAY_SIZE_MASK (0x7 << 17)
> +#define L2X0_AUX_CTRL_SHARE_OVERRIDE_SHIFT 22
> +#define L2X0_AUX_CTRL_NS_LOCKDOWN_SHIFT 26
> +#define L2X0_AUX_CTRL_NS_INT_CTRL_SHIFT 27
> +#define L2X0_AUX_CTRL_DATA_PREFETCH_SHIFT 28
> +#define L2X0_AUX_CTRL_INSTR_PREFETCH_SHIFT 29
> +#define L2X0_AUX_CTRL_EARLY_BRESP_SHIFT 30
> +
> +#define L2X0_LATENCY_CTRL_SETUP_SHIFT 0
> +#define L2X0_LATENCY_CTRL_RD_SHIFT 4
> +#define L2X0_LATENCY_CTRL_WR_SHIFT 8
> +
> +#define L2X0_ADDR_FILTER_EN 1
> +
> +
> +#endif
> diff --git a/arch/arm64/include/asm/cache.h b/arch/arm64/include/asm/cache.h
> new file mode 100644
> index 0000000..5a524f3
> --- /dev/null
> +++ b/arch/arm64/include/asm/cache.h
> @@ -0,0 +1,16 @@
> +#ifndef __ASM_CACHE_H
> +#define __ASM_CACHE_H
> +
> +extern void v8_invalidate_icache_all(void);
> +
> +static inline void flush_icache(void)
> +{
> + v8_invalidate_icache_all();
> +}
> +
> +int arm_set_cache_functions(void);
> +
> +void arm_early_mmu_cache_flush(void);
> +void arm_early_mmu_cache_invalidate(void);
> +
> +#endif
> diff --git a/arch/arm64/include/asm/common.h b/arch/arm64/include/asm/common.h
> new file mode 100644
> index 0000000..07ae619
> --- /dev/null
> +++ b/arch/arm64/include/asm/common.h
> @@ -0,0 +1,48 @@
> +#ifndef __ASM_ARM_COMMON_H
> +#define __ASM_ARM_COMMON_H
> +
> +static inline unsigned long get_pc(void)
> +{
> + unsigned long pc;
> +
> + __asm__ __volatile__(
> + "mov %0, pc\n"
> + : "=r" (pc)
> + :
> + : "memory");
> +
> + return pc;
> +}
> +
> +static inline unsigned long get_lr(void)
> +{
> + unsigned long lr;
> +
> + __asm__ __volatile__(
> + "mov %0, lr\n"
> + : "=r" (lr)
> + :
> + : "memory");
> +
> + return lr;
> +}
> +
> +static inline unsigned long get_sp(void)
> +{
> + unsigned long sp;
> +
> + __asm__ __volatile__(
> + "mov %0, sp\n"
> + : "=r" (sp)
> + :
> + : "memory");
> +
> + return sp;
> +}
> +
> +static inline void arm_setup_stack(unsigned long top)
> +{
> + __asm__ __volatile__("mov sp, %0" : : "r"(top));
> +}
> +
> +#endif /* __ASM_ARM_COMMON_H */
> diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h
> new file mode 100644
> index 0000000..f39939b
> --- /dev/null
> +++ b/arch/arm64/include/asm/cputype.h
> @@ -0,0 +1,100 @@
> +#ifndef __ASM_ARM_CPUTYPE_H
> +#define __ASM_ARM_CPUTYPE_H
> +
> +#include <linux/stringify.h>
> +#include <linux/kernel.h>
> +
> +#define CPUID_ID 0
> +#define CPUID_CACHETYPE 1
> +#define CPUID_TCM 2
> +#define CPUID_TLBTYPE 3
> +#define CPUID_MPIDR 5
> +
> +#define CPUID_EXT_PFR0 "c1, 0"
> +#define CPUID_EXT_PFR1 "c1, 1"
> +#define CPUID_EXT_DFR0 "c1, 2"
> +#define CPUID_EXT_AFR0 "c1, 3"
> +#define CPUID_EXT_MMFR0 "c1, 4"
> +#define CPUID_EXT_MMFR1 "c1, 5"
> +#define CPUID_EXT_MMFR2 "c1, 6"
> +#define CPUID_EXT_MMFR3 "c1, 7"
> +#define CPUID_EXT_ISAR0 "c2, 0"
> +#define CPUID_EXT_ISAR1 "c2, 1"
> +#define CPUID_EXT_ISAR2 "c2, 2"
> +#define CPUID_EXT_ISAR3 "c2, 3"
> +#define CPUID_EXT_ISAR4 "c2, 4"
> +#define CPUID_EXT_ISAR5 "c2, 5"
> +
> +extern unsigned int processor_id;
> +
> +#define read_cpuid(reg) \
> + ({ \
> + unsigned int __val; \
> + asm("mrc p15, 0, %0, c0, c0, " __stringify(reg) \
> + : "=r" (__val) \
> + : \
> + : "cc"); \
> + __val; \
> + })
> +#define read_cpuid_ext(ext_reg) \
> + ({ \
> + unsigned int __val; \
> + asm("mrc p15, 0, %0, c0, " ext_reg \
> + : "=r" (__val) \
> + : \
> + : "cc"); \
> + __val; \
> + })
> +
> +/*
> + * The CPU ID never changes at run time, so we might as well tell the
> + * compiler that it's constant. Use this function to read the CPU ID
> + * rather than directly reading processor_id or read_cpuid() directly.
> + */
> +static inline unsigned int __attribute_const__ read_cpuid_id(void)
> +{
> + return read_cpuid(CPUID_ID);
> +}
> +
> +static inline unsigned int __attribute_const__ read_cpuid_cachetype(void)
> +{
> + return read_cpuid(CPUID_CACHETYPE);
> +}
> +
> +static inline unsigned int __attribute_const__ read_cpuid_tcmstatus(void)
> +{
> + return read_cpuid(CPUID_TCM);
> +}
> +
> +static inline unsigned int __attribute_const__ read_cpuid_mpidr(void)
> +{
> + return read_cpuid(CPUID_MPIDR);
> +}
> +
> +/*
> + * Intel's XScale3 core supports some v6 features (supersections, L2)
> + * but advertises itself as v5 as it does not support the v6 ISA. For
> + * this reason, we need a way to explicitly test for this type of CPU.
> + */
> +#ifndef CONFIG_CPU_XSC3
> +#define cpu_is_xsc3() 0
> +#else
> +static inline int cpu_is_xsc3(void)
> +{
> + unsigned int id;
> + id = read_cpuid_id() & 0xffffe000;
> + /* It covers both Intel ID and Marvell ID */
> + if ((id == 0x69056000) || (id == 0x56056000))
> + return 1;
> +
> + return 0;
> +}
> +#endif
> +
> +#if !defined(CONFIG_CPU_XSCALE) && !defined(CONFIG_CPU_XSC3)
> +#define cpu_is_xscale() 0
> +#else
> +#define cpu_is_xscale() 1
> +#endif
> +
> +#endif
> diff --git a/arch/arm64/include/asm/debug_ll_pl011.h b/arch/arm64/include/asm/debug_ll_pl011.h
> new file mode 100644
> index 0000000..db015a3
> --- /dev/null
> +++ b/arch/arm64/include/asm/debug_ll_pl011.h
> @@ -0,0 +1,25 @@
> +#ifndef __INCLUDE_ARM_ASM_DEBUG_LL_PL011_H__
> +#define __INCLUDE_ARM_ASM_DEBUG_LL_PL011_H__
> +
> +#ifndef DEBUG_LL_UART_ADDR
> +#error DEBUG_LL_UART_ADDR is undefined!
> +#endif
> +
> +#include <io.h>
> +#include <linux/amba/serial.h>
> +
> +static inline void PUTC_LL(char c)
> +{
> + /* Wait until there is space in the FIFO */
> + while (readl(DEBUG_LL_UART_ADDR + UART01x_FR) & UART01x_FR_TXFF)
> + ;
> +
> + /* Send the character */
> + writel(c, DEBUG_LL_UART_ADDR + UART01x_DR);
> +
> + /* Wait to make sure it hits the line, in case we die too soon. */
> + while (readl(DEBUG_LL_UART_ADDR + UART01x_FR) & UART01x_FR_TXFF)
> + ;
> +}
> +
> +#endif /* __INCLUDE_ARM_ASM_DEBUG_LL_PL011_H__ */
> diff --git a/arch/arm64/include/asm/dma.h b/arch/arm64/include/asm/dma.h
> new file mode 100644
> index 0000000..1ba2edf
> --- /dev/null
> +++ b/arch/arm64/include/asm/dma.h
> @@ -0,0 +1,46 @@
> +/*
> + * Copyright (C) 2012 by Marc Kleine-Budde <mkl at pengutronix.de>
> + *
> + * This file is released under the GPLv2
> + *
> + */
> +
> +#include <common.h>
> +
> +#define dma_alloc dma_alloc
> +static inline void *dma_alloc(size_t size)
> +{
> + return xmemalign(64, ALIGN(size, 64));
> +}
> +
> +#ifndef CONFIG_MMU
> +static inline void *dma_alloc_coherent(size_t size, dma_addr_t *dma_handle)
> +{
> + void *ret = xmemalign(4096, size);
> + if (dma_handle)
> + *dma_handle = (dma_addr_t)ret;
> +
> + return ret;
> +}
> +
> +static inline void *dma_alloc_writecombine(size_t size, dma_addr_t *dma_handle)
> +{
> + return dma_alloc_coherent(size, dma_handle);
> +}
> +
> +static inline void dma_free_coherent(void *mem, dma_addr_t dma_handle,
> + size_t size)
> +{
> + free(mem);
> +}
> +
> +static inline void dma_sync_single_for_cpu(unsigned long address, size_t size,
> + enum dma_data_direction dir)
> +{
> +}
> +
> +static inline void dma_sync_single_for_device(unsigned long address, size_t size,
> + enum dma_data_direction dir)
> +{
> +}
> +#endif
> diff --git a/arch/arm64/include/asm/elf.h b/arch/arm64/include/asm/elf.h
> new file mode 100644
> index 0000000..724ebb0
> --- /dev/null
> +++ b/arch/arm64/include/asm/elf.h
> @@ -0,0 +1,119 @@
> +#ifndef __ASMARM_ELF_H
> +#define __ASMARM_ELF_H
> +
> +//#include <asm/hwcap.h>
> +
> +#ifndef __ASSEMBLY__
> +/*
> + * ELF register definitions..
> + */
> +#include <asm/ptrace.h>
> +//#include <asm/user.h>
> +
> +typedef unsigned long elf_greg_t;
> +typedef unsigned long elf_freg_t[3];
> +
> +#define ELF_NGREG (sizeof (struct pt_regs) / sizeof(elf_greg_t))
> +typedef elf_greg_t elf_gregset_t[ELF_NGREG];
> +
> +typedef struct user_fp elf_fpregset_t;
> +#endif
> +
> +#define EM_ARM 40
> +#define EF_ARM_APCS26 0x08
> +#define EF_ARM_SOFT_FLOAT 0x200
> +#define EF_ARM_EABI_MASK 0xFF000000
> +
> +#define R_ARM_NONE 0
> +#define R_ARM_PC24 1
> +#define R_ARM_ABS32 2
> +#define R_ARM_CALL 28
> +#define R_ARM_JUMP24 29
> +
> +/*
> + * These are used to set parameters in the core dumps.
> + */
> +#define ELF_CLASS ELFCLASS32
> +#ifdef __ARMEB__
> +#define ELF_DATA ELFDATA2MSB
> +#else
> +#define ELF_DATA ELFDATA2LSB
> +#endif
> +#define ELF_ARCH EM_ARM
> +
> +#ifdef __KERNEL__
> +#ifndef __ASSEMBLY__
> +/*
> + * This yields a string that ld.so will use to load implementation
> + * specific libraries for optimization. This is more specific in
> + * intent than poking at uname or /proc/cpuinfo.
> + *
> + * For now we just provide a fairly general string that describes the
> + * processor family. This could be made more specific later if someone
> + * implemented optimisations that require it. 26-bit CPUs give you
> + * "v1l" for ARM2 (no SWP) and "v2l" for anything else (ARM1 isn't
> + * supported). 32-bit CPUs give you "v3[lb]" for anything based on an
> + * ARM6 or ARM7 core and "armv4[lb]" for anything based on a StrongARM-1
> + * core.
> + */
> +#define ELF_PLATFORM_SIZE 8
> +#define ELF_PLATFORM (elf_platform)
> +
> +extern char elf_platform[];
> +#endif
> +
> +/*
> + * This is used to ensure we don't load something for the wrong architecture.
> + */
> +#define elf_check_arch(x) ((x)->e_machine == EM_ARM && ELF_PROC_OK(x))
> +
> +/*
> + * 32-bit code is always OK. Some cpus can do 26-bit, some can't.
> + */
> +#define ELF_PROC_OK(x) (ELF_THUMB_OK(x) && ELF_26BIT_OK(x))
> +
> +#define ELF_THUMB_OK(x) \
> + ((elf_hwcap & HWCAP_THUMB && ((x)->e_entry & 1) == 1) || \
> + ((x)->e_entry & 3) == 0)
> +
> +#define ELF_26BIT_OK(x) \
> + ((elf_hwcap & HWCAP_26BIT && (x)->e_flags & EF_ARM_APCS26) || \
> + ((x)->e_flags & EF_ARM_APCS26) == 0)
> +
> +#define USE_ELF_CORE_DUMP
> +#define ELF_EXEC_PAGESIZE 4096
> +
> +/* This is the location that an ET_DYN program is loaded if exec'ed. Typical
> + use of this is to invoke "./ld.so someprog" to test out a new version of
> + the loader. We need to make sure that it is out of the way of the program
> + that it will "exec", and that there is sufficient room for the brk. */
> +
> +#define ELF_ET_DYN_BASE (2 * TASK_SIZE / 3)
> +
> +/* When the program starts, a1 contains a pointer to a function to be
> + registered with atexit, as per the SVR4 ABI. A value of 0 means we
> + have no such handler. */
> +#define ELF_PLAT_INIT(_r, load_addr) (_r)->ARM_r0 = 0
> +
> +/*
> + * Since the FPA coprocessor uses CP1 and CP2, and iWMMXt uses CP0
> + * and CP1, we only enable access to the iWMMXt coprocessor if the
> + * binary is EABI or softfloat (and thus, guaranteed not to use
> + * FPA instructions.)
> + */
> +#define SET_PERSONALITY(ex, ibcs2) \
> + do { \
> + if ((ex).e_flags & EF_ARM_APCS26) { \
> + set_personality(PER_LINUX); \
> + } else { \
> + set_personality(PER_LINUX_32BIT); \
> + if (elf_hwcap & HWCAP_IWMMXT && (ex).e_flags & (EF_ARM_EABI_MASK | EF_ARM_SOFT_FLOAT)) \
> + set_thread_flag(TIF_USING_IWMMXT); \
> + else \
> + clear_thread_flag(TIF_USING_IWMMXT); \
> + } \
> + } while (0)
> +
> +#endif
> +
> +#endif
> diff --git a/arch/arm64/include/asm/errata.h b/arch/arm64/include/asm/errata.h
> new file mode 100644
> index 0000000..9525823
> --- /dev/null
> +++ b/arch/arm64/include/asm/errata.h
> @@ -0,0 +1,79 @@
> +/*
> + * Copyright (C) 2014 Lucas Stach, Pengutronix
> + *
> + * 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.
> + */
> +
> +static inline void enable_arm_errata_709718_war(void)
> +{
> + __asm__ __volatile__ (
> + "mrc p15, 0, r0, c10, c2, 0\n"
> + "bic r0, #3 << 16\n"
> + "mcr p15, 0, r0, c10, c2, 0\n"
> + "mrc p15, 0, r0, c1, c0, 0\n"
> + "orr r0, r0, #1 << 28\n"
> + "mcr p15, 0, r0, c1, c0, 0\n"
> + );
> +}
> +
> +static inline void enable_arm_errata_716044_war(void)
> +{
> + __asm__ __volatile__ (
> + "mrc p15, 0, r0, c1, c0, 0\n"
> + "orr r0, r0, #1 << 11\n"
> + "mcr p15, 0, r0, c1, c0, 0\n"
> + );
> +}
> +
> +static inline void enable_arm_errata_742230_war(void)
> +{
> + __asm__ __volatile__ (
> + "mrc p15, 0, r0, c15, c0, 1\n"
> + "orr r0, r0, #1 << 4\n"
> + "mcr p15, 0, r0, c15, c0, 1\n"
> + );
> +}
> +
> +static inline void enable_arm_errata_743622_war(void)
> +{
> + __asm__ __volatile__ (
> + "mrc p15, 0, r0, c15, c0, 1\n"
> + "orr r0, r0, #1 << 6\n"
> + "mcr p15, 0, r0, c15, c0, 1\n"
> + );
> +}
> +
> +static inline void enable_arm_errata_751472_war(void)
> +{
> + __asm__ __volatile__ (
> + "mrc p15, 0, r0, c15, c0, 1\n"
> + "orr r0, r0, #1 << 11\n"
> + "mcr p15, 0, r0, c15, c0, 1\n"
> + );
> +}
> +
> +static inline void enable_arm_errata_761320_war(void)
> +{
> + __asm__ __volatile__ (
> + "mrc p15, 0, r0, c15, c0, 1\n"
> + "orr r0, r0, #1 << 21\n"
> + "mcr p15, 0, r0, c15, c0, 1\n"
> + );
> +}
> +
> +static inline void enable_arm_errata_794072_war(void)
> +{
> + __asm__ __volatile__ (
> + "mrc p15, 0, r0, c15, c0, 1\n"
> + "orr r0, r0, #1 << 4\n"
> + "mcr p15, 0, r0, c15, c0, 1\n"
> + );
> +}
> diff --git a/arch/arm64/include/asm/gic.h b/arch/arm64/include/asm/gic.h
> new file mode 100644
> index 0000000..c7c17e3
> --- /dev/null
> +++ b/arch/arm64/include/asm/gic.h
> @@ -0,0 +1,128 @@
> +#ifndef __GIC_H__
> +#define __GIC_H__
> +
> +/* Generic Interrupt Controller Definitions */
> +//#ifdef CONFIG_GICV3
> +//#define GICD_BASE (0x2f000000)
> +//#define GICR_BASE (0x2f100000)
> +//#else
> +
> +//#if defined(CONFIG_TARGET_VEXPRESS64_BASE_FVP) || \
> + defined(CONFIG_TARGET_VEXPRESS64_BASE_FVP_DRAM)
> +//#define GICD_BASE (0x2f000000)
> +//#define GICC_BASE (0x2c000000)
> +//#elif CONFIG_TARGET_VEXPRESS64_JUNO
> +#define GIC_DIST_BASE (0x2C010000)
> +#define GIC_CPU_BASE (0x2C02f000)
> +//#else
> +//#error "Unknown board variant"
> +//#endif
> +//#endif /* !CONFIG_GICV3 */
> +
> +/* Register offsets for the ARM generic interrupt controller (GIC) */
> +
> +#define GIC_DIST_OFFSET 0x1000
> +#define GIC_CPU_OFFSET_A9 0x0100
> +#define GIC_CPU_OFFSET_A15 0x2000
> +
> +/* Distributor Registers */
> +#define GICD_CTLR 0x0000
> +#define GICD_TYPER 0x0004
> +#define GICD_IIDR 0x0008
> +#define GICD_STATUSR 0x0010
> +#define GICD_SETSPI_NSR 0x0040
> +#define GICD_CLRSPI_NSR 0x0048
> +#define GICD_SETSPI_SR 0x0050
> +#define GICD_CLRSPI_SR 0x0058
> +#define GICD_SEIR 0x0068
> +#define GICD_IGROUPRn 0x0080
> +#define GICD_ISENABLERn 0x0100
> +#define GICD_ICENABLERn 0x0180
> +#define GICD_ISPENDRn 0x0200
> +#define GICD_ICPENDRn 0x0280
> +#define GICD_ISACTIVERn 0x0300
> +#define GICD_ICACTIVERn 0x0380
> +#define GICD_IPRIORITYRn 0x0400
> +#define GICD_ITARGETSRn 0x0800
> +#define GICD_ICFGR 0x0c00
> +#define GICD_IGROUPMODRn 0x0d00
> +#define GICD_NSACRn 0x0e00
> +#define GICD_SGIR 0x0f00
> +#define GICD_CPENDSGIRn 0x0f10
> +#define GICD_SPENDSGIRn 0x0f20
> +#define GICD_IROUTERn 0x6000
> +
> +/* Cpu Interface Memory Mapped Registers */
> +#define GICC_CTLR 0x0000
> +#define GICC_PMR 0x0004
> +#define GICC_BPR 0x0008
> +#define GICC_IAR 0x000C
> +#define GICC_EOIR 0x0010
> +#define GICC_RPR 0x0014
> +#define GICC_HPPIR 0x0018
> +#define GICC_ABPR 0x001c
> +#define GICC_AIAR 0x0020
> +#define GICC_AEOIR 0x0024
> +#define GICC_AHPPIR 0x0028
> +#define GICC_APRn 0x00d0
> +#define GICC_NSAPRn 0x00e0
> +#define GICC_IIDR 0x00fc
> +#define GICC_DIR 0x1000
> +
> +/* ReDistributor Registers for Control and Physical LPIs */
> +#define GICR_CTLR 0x0000
> +#define GICR_IIDR 0x0004
> +#define GICR_TYPER 0x0008
> +#define GICR_STATUSR 0x0010
> +#define GICR_WAKER 0x0014
> +#define GICR_SETLPIR 0x0040
> +#define GICR_CLRLPIR 0x0048
> +#define GICR_SEIR 0x0068
> +#define GICR_PROPBASER 0x0070
> +#define GICR_PENDBASER 0x0078
> +#define GICR_INVLPIR 0x00a0
> +#define GICR_INVALLR 0x00b0
> +#define GICR_SYNCR 0x00c0
> +#define GICR_MOVLPIR 0x0100
> +#define GICR_MOVALLR 0x0110
> +
> +/* ReDistributor Registers for SGIs and PPIs */
> +#define GICR_IGROUPRn 0x0080
> +#define GICR_ISENABLERn 0x0100
> +#define GICR_ICENABLERn 0x0180
> +#define GICR_ISPENDRn 0x0200
> +#define GICR_ICPENDRn 0x0280
> +#define GICR_ISACTIVERn 0x0300
> +#define GICR_ICACTIVERn 0x0380
> +#define GICR_IPRIORITYRn 0x0400
> +#define GICR_ICFGR0 0x0c00
> +#define GICR_ICFGR1 0x0c04
> +#define GICR_IGROUPMODRn 0x0d00
> +#define GICR_NSACRn 0x0e00
> +
> +/* Cpu Interface System Registers */
> +#define ICC_IAR0_EL1 S3_0_C12_C8_0
> +#define ICC_IAR1_EL1 S3_0_C12_C12_0
> +#define ICC_EOIR0_EL1 S3_0_C12_C8_1
> +#define ICC_EOIR1_EL1 S3_0_C12_C12_1
> +#define ICC_HPPIR0_EL1 S3_0_C12_C8_2
> +#define ICC_HPPIR1_EL1 S3_0_C12_C12_2
> +#define ICC_BPR0_EL1 S3_0_C12_C8_3
> +#define ICC_BPR1_EL1 S3_0_C12_C12_3
> +#define ICC_DIR_EL1 S3_0_C12_C11_1
> +#define ICC_PMR_EL1 S3_0_C4_C6_0
> +#define ICC_RPR_EL1 S3_0_C12_C11_3
> +#define ICC_CTLR_EL1 S3_0_C12_C12_4
> +#define ICC_CTLR_EL3 S3_6_C12_C12_4
> +#define ICC_SRE_EL1 S3_0_C12_C12_5
> +#define ICC_SRE_EL2 S3_4_C12_C9_5
> +#define ICC_SRE_EL3 S3_6_C12_C12_5
> +#define ICC_IGRPEN0_EL1 S3_0_C12_C12_6
> +#define ICC_IGRPEN1_EL1 S3_0_C12_C12_7
> +#define ICC_IGRPEN1_EL3 S3_6_C12_C12_7
> +#define ICC_SEIEN_EL1 S3_0_C12_C13_0
> +#define ICC_SGI0R_EL1 S3_0_C12_C11_7
> +#define ICC_SGI1R_EL1 S3_0_C12_C11_5
> +#define ICC_ASGI1R_EL1 S3_0_C12_C11_6
> +
> +#endif /* __GIC_H__ */
> diff --git a/arch/arm64/include/asm/hardware/arm_timer.h b/arch/arm64/include/asm/hardware/arm_timer.h
> new file mode 100644
> index 0000000..8a58390
> --- /dev/null
> +++ b/arch/arm64/include/asm/hardware/arm_timer.h
> @@ -0,0 +1,38 @@
> +#ifndef __ASM_ARM_HARDWARE_ARM_TIMER_H
> +#define __ASM_ARM_HARDWARE_ARM_TIMER_H
> +
> +/*
> + * From Linux v2.6.35
> + * arch/arm/include/asm/hardware/arm_timer.h
> + *
> + * ARM timer implementation, found in Integrator, Versatile and Realview
> + * platforms. Not all platforms support all registers and bits in these
> + * registers, so we mark them with A for Integrator AP, C for Integrator
> + * CP, V for Versatile and R for Realview.
> + *
> + * Integrator AP has 16-bit timers, Integrator CP, Versatile and Realview
> + * can have 16-bit or 32-bit selectable via a bit in the control register.
> + *
> + * Every SP804 contains two identical timers.
> + */
> +#define TIMER_1_BASE 0x00
> +#define TIMER_2_BASE 0x20
> +
> +#define TIMER_LOAD 0x00 /* ACVR rw */
> +#define TIMER_VALUE 0x04 /* ACVR ro */
> +#define TIMER_CTRL 0x08 /* ACVR rw */
> +#define TIMER_CTRL_ONESHOT (1 << 0) /* CVR */
> +#define TIMER_CTRL_32BIT (1 << 1) /* CVR */
> +#define TIMER_CTRL_DIV1 (0 << 2) /* ACVR */
> +#define TIMER_CTRL_DIV16 (1 << 2) /* ACVR */
> +#define TIMER_CTRL_DIV256 (2 << 2) /* ACVR */
> +#define TIMER_CTRL_IE (1 << 5) /* VR */
> +#define TIMER_CTRL_PERIODIC (1 << 6) /* ACVR */
> +#define TIMER_CTRL_ENABLE (1 << 7) /* ACVR */
> +
> +#define TIMER_INTCLR 0x0c /* ACVR wo */
> +#define TIMER_RIS 0x10 /* CVR ro */
> +#define TIMER_MIS 0x14 /* CVR ro */
> +#define TIMER_BGLOAD 0x18 /* CVR rw */
> +
> +#endif
> diff --git a/arch/arm64/include/asm/hardware/sp810.h b/arch/arm64/include/asm/hardware/sp810.h
> new file mode 100644
> index 0000000..3e3996a
> --- /dev/null
> +++ b/arch/arm64/include/asm/hardware/sp810.h
> @@ -0,0 +1,68 @@
> +/*
> + * arch/arm/include/asm/hardware/sp810.h
> + *
> + * ARM PrimeXsys System Controller SP810 header file
> + *
> + * Copyright (C) 2009 ST Microelectronics
> + * Viresh Kumar <viresh.linux at gmail.com>
> + *
> + * This file is licensed under the terms of the GNU General Public
> + * License version 2. This program is licensed "as is" without any
> + * warranty of any kind, whether express or implied.
> + */
> +
> +#ifndef __ASM_ARM_SP810_H
> +#define __ASM_ARM_SP810_H
> +
> +#include <io.h>
> +
> +/* sysctl registers offset */
> +#define SCCTRL 0x000
> +#define SCSYSSTAT 0x004
> +#define SCIMCTRL 0x008
> +#define SCIMSTAT 0x00C
> +#define SCXTALCTRL 0x010
> +#define SCPLLCTRL 0x014
> +#define SCPLLFCTRL 0x018
> +#define SCPERCTRL0 0x01C
> +#define SCPERCTRL1 0x020
> +#define SCPEREN 0x024
> +#define SCPERDIS 0x028
> +#define SCPERCLKEN 0x02C
> +#define SCPERSTAT 0x030
> +#define SCSYSID0 0xEE0
> +#define SCSYSID1 0xEE4
> +#define SCSYSID2 0xEE8
> +#define SCSYSID3 0xEEC
> +#define SCITCR 0xF00
> +#define SCITIR0 0xF04
> +#define SCITIR1 0xF08
> +#define SCITOR 0xF0C
> +#define SCCNTCTRL 0xF10
> +#define SCCNTDATA 0xF14
> +#define SCCNTSTEP 0xF18
> +#define SCPERIPHID0 0xFE0
> +#define SCPERIPHID1 0xFE4
> +#define SCPERIPHID2 0xFE8
> +#define SCPERIPHID3 0xFEC
> +#define SCPCELLID0 0xFF0
> +#define SCPCELLID1 0xFF4
> +#define SCPCELLID2 0xFF8
> +#define SCPCELLID3 0xFFC
> +
> +#define SCCTRL_TIMEREN0SEL_REFCLK (0 << 15)
> +#define SCCTRL_TIMEREN0SEL_TIMCLK (1 << 15)
> +
> +#define SCCTRL_TIMEREN1SEL_REFCLK (0 << 17)
> +#define SCCTRL_TIMEREN1SEL_TIMCLK (1 << 17)
> +
> +static inline void sysctl_soft_reset(void __iomem *base)
> +{
> + /* switch to slow mode */
> + writel(0x2, base + SCCTRL);
> +
> + /* writing any value to SCSYSSTAT reg will reset system */
> + writel(0, base + SCSYSSTAT);
> +}
> +
> +#endif /* __ASM_ARM_SP810_H */
> diff --git a/arch/arm64/include/asm/io.h b/arch/arm64/include/asm/io.h
> new file mode 100644
> index 0000000..eebf093
> --- /dev/null
> +++ b/arch/arm64/include/asm/io.h
> @@ -0,0 +1,87 @@
> +#ifndef __ASM_ARM_IO_H
> +#define __ASM_ARM_IO_H
> +
> +#include <asm-generic/io.h>
> +
> +#define IO_SPACE_LIMIT 0
> +
> +/*
> + * String version of IO memory access ops:
> + */
> +extern void memcpy_fromio(void *, const volatile void __iomem *, size_t);
> +extern void memcpy_toio(volatile void __iomem *, const void *, size_t);
> +extern void memset_io(volatile void __iomem *, int, size_t);
> +
> +/*
> + * Clear and set bits in one shot. These macros can be used to clear and
> + * set multiple bits in a register using a single call. These macros can
> + * also be used to set a multiple-bit bit pattern using a mask, by
> + * specifying the mask in the 'clear' parameter and the new bit pattern
> + * in the 'set' parameter.
> + */
> +
> +#define out_arch(type,endian,a,v) __raw_write##type(cpu_to_##endian(v),a)
> +#define in_arch(type,endian,a) endian##_to_cpu(__raw_read##type(a))
> +
> +#define out_le64(a,v) out_arch(q,le64,a,v)
> +#define out_le32(a,v) out_arch(l,le32,a,v)
> +#define out_le16(a,v) out_arch(w,le16,a,v)
> +
> +#define in_le64(a) in_arch(q,le64,a)
> +#define in_le32(a) in_arch(l,le32,a)
> +#define in_le16(a) in_arch(w,le16,a)
> +
> +#define out_be32(a,v) out_arch(l,be32,a,v)
> +#define out_be16(a,v) out_arch(w,be16,a,v)
> +
> +#define in_be32(a) in_arch(l,be32,a)
> +#define in_be16(a) in_arch(w,be16,a)
> +
> +#define out_8(a,v) __raw_writeb(v,a)
> +#define in_8(a) __raw_readb(a)
> +
> +#define clrbits(type, addr, clear) \
> + out_##type((addr), in_##type(addr) & ~(clear))
> +
> +#define setbits(type, addr, set) \
> + out_##type((addr), in_##type(addr) | (set))
> +
> +#define clrsetbits(type, addr, clear, set) \
> + out_##type((addr), (in_##type(addr) & ~(clear)) | (set))
> +
> +#define clrbits_be32(addr, clear) clrbits(be32, addr, clear)
> +#define setbits_be32(addr, set) setbits(be32, addr, set)
> +#define clrsetbits_be32(addr, clear, set) clrsetbits(be32, addr, clear, set)
> +
> +#define clrbits_le32(addr, clear) clrbits(le32, addr, clear)
> +#define setbits_le32(addr, set) setbits(le32, addr, set)
> +#define clrsetbits_le32(addr, clear, set) clrsetbits(le32, addr, clear, set)
> +
> +#define clrbits_be16(addr, clear) clrbits(be16, addr, clear)
> +#define setbits_be16(addr, set) setbits(be16, addr, set)
> +#define clrsetbits_be16(addr, clear, set) clrsetbits(be16, addr, clear, set)
> +
> +#define clrbits_le16(addr, clear) clrbits(le16, addr, clear)
> +#define setbits_le16(addr, set) setbits(le16, addr, set)
> +#define clrsetbits_le16(addr, clear, set) clrsetbits(le16, addr, clear, set)
> +
> +#define clrbits_8(addr, clear) clrbits(8, addr, clear)
> +#define setbits_8(addr, set) setbits(8, addr, set)
> +#define clrsetbits_8(addr, clear, set) clrsetbits(8, addr, clear, set)
> +
> +#ifdef CONFIG_MMU
> +void *phys_to_virt(unsigned long phys);
> +unsigned long virt_to_phys(volatile void *virt);
> +#else
> +static inline void *phys_to_virt(unsigned long phys)
> +{
> + return (void *)phys;
> +}
> +
> +static inline unsigned long virt_to_phys(volatile void *mem)
> +{
> + return (unsigned long)mem;
> +}
> +#endif
> +
> +#endif /* __ASM_ARM_IO_H */
> diff --git a/arch/arm64/include/asm/linkage.h b/arch/arm64/include/asm/linkage.h
> new file mode 100644
> index 0000000..5a25632
> --- /dev/null
> +++ b/arch/arm64/include/asm/linkage.h
> @@ -0,0 +1,11 @@
> +#ifndef __ASM_LINKAGE_H
> +#define __ASM_LINKAGE_H
> +
> +#define __ALIGN .align 0
> +#define __ALIGN_STR ".align 0"
> +
> +#define ENDPROC(name) \
> + .type name, %function; \
> + END(name)
> +
> +#endif
> diff --git a/arch/arm64/include/asm/memory.h b/arch/arm64/include/asm/memory.h
> new file mode 100644
> index 0000000..52114d0
> --- /dev/null
> +++ b/arch/arm64/include/asm/memory.h
> @@ -0,0 +1,19 @@
> +#ifndef __ASM_ARM_MEMORY_H
> +#define __ASM_ARM_MEMORY_H
> +
> +#include <memory.h>
> +
> +#include <linux/const.h>
> +/*
> + * Allow for constants defined here to be used from assembly code
> + * by prepending the UL suffix only with actual C code compilation.
> + */
> +#define UL(x) _AC(x, UL)
> +
> +static inline void arm_add_mem_device(const char* name, resource_size_t start,
> + resource_size_t size)
> +{
> + barebox_add_memory_bank(name, start, size);
> +}
> +
> +#endif /* __ASM_ARM_MEMORY_H */
> diff --git a/arch/arm64/include/asm/mmu.h b/arch/arm64/include/asm/mmu.h
> new file mode 100644
> index 0000000..8de6544
> --- /dev/null
> +++ b/arch/arm64/include/asm/mmu.h
> @@ -0,0 +1,65 @@
> +#ifndef __ASM_MMU_H
> +#define __ASM_MMU_H
> +
> +#include <common.h>
> +#include <errno.h>
> +#include <malloc.h>
> +#include <xfuncs.h>
> +
> +#include <asm/pgtable.h>
> +
> +#define PMD_SECT_DEF_UNCACHED (PMD_SECT_AP_WRITE | PMD_SECT_AP_READ | PMD_TYPE_SECT)
> +#define PMD_SECT_DEF_CACHED (PMD_SECT_WB | PMD_SECT_DEF_UNCACHED)
> +
> +struct arm_memory;
> +
> +static inline void mmu_enable(void)
> +{
> +}
> +void mmu_disable(void);
> +static inline void arm_create_section(unsigned long virt, unsigned long phys, int size_m,
> + unsigned int flags)
> +{
> +}
> +
> +static inline void setup_dma_coherent(unsigned long offset)
> +{
> +}
> +
> +#ifdef CONFIG_MMU
> +#define ARCH_HAS_REMAP
> +#define MAP_ARCH_DEFAULT MAP_CACHED
> +int arch_remap_range(void *_start, size_t size, unsigned flags);
> +void *map_io_sections(unsigned long physaddr, void *start, size_t size);
> +#else
> +#define MAP_ARCH_DEFAULT MAP_UNCACHED
> +static inline void *map_io_sections(unsigned long phys, void *start, size_t size)
> +{
> + return (void *)phys;
> +}
> +
> +#endif
> +
> +#ifdef CONFIG_CACHE_L2X0
> +void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask);
> +#else
> +static inline void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask)
> +{
> +}
> +#endif
> +
> +struct outer_cache_fns {
> + void (*inv_range)(unsigned long, unsigned long);
> + void (*clean_range)(unsigned long, unsigned long);
> + void (*flush_range)(unsigned long, unsigned long);
> + void (*flush_all)(void);
> + void (*disable)(void);
> +};
> +
> +extern struct outer_cache_fns outer_cache;
> +
> +void __dma_clean_range(unsigned long, unsigned long);
> +void __dma_flush_range(unsigned long, unsigned long);
> +void __dma_inv_range(unsigned long, unsigned long);
> +
> +#endif /* __ASM_MMU_H */
> diff --git a/arch/arm64/include/asm/module.h b/arch/arm64/include/asm/module.h
> new file mode 100644
> index 0000000..5b4d1a3
> --- /dev/null
> +++ b/arch/arm64/include/asm/module.h
> @@ -0,0 +1,13 @@
> +#ifndef _ASM_ARM_MODULE_H
> +#define _ASM_ARM_MODULE_H
> +
> +struct mod_arch_specific
> +{
> + int foo;
> +};
> +
> +#define Elf_Shdr Elf32_Shdr
> +#define Elf_Sym Elf32_Sym
> +#define Elf_Ehdr Elf32_Ehdr
> +
> +#endif /* _ASM_ARM_MODULE_H */
> diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
> new file mode 100644
> index 0000000..fd1521d
> --- /dev/null
> +++ b/arch/arm64/include/asm/pgtable.h
> @@ -0,0 +1,90 @@
> +/*
> + * arch/arm/include/asm/pgtable-hwdef.h
> + *
> + * Copyright (C) 1995-2002 Russell King
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +#ifndef _ASMARM_PGTABLE_HWDEF_H
> +#define _ASMARM_PGTABLE_HWDEF_H
> +
> +/*
> + * Hardware page table definitions.
> + *
> + * + Level 1 descriptor (PMD)
> + * - common
> + */
> +#define PMD_TYPE_MASK (3 << 0)
> +#define PMD_TYPE_FAULT (0 << 0)
> +#define PMD_TYPE_TABLE (1 << 0)
> +#define PMD_TYPE_SECT (2 << 0)
> +#define PMD_BIT4 (1 << 4)
> +#define PMD_DOMAIN(x) ((x) << 5)
> +#define PMD_PROTECTION (1 << 9) /* v5 */
> +/*
> + * - section
> + */
> +#define PMD_SECT_BUFFERABLE (1 << 2)
> +#define PMD_SECT_CACHEABLE (1 << 3)
> +#define PMD_SECT_XN (1 << 4) /* v6 */
> +#define PMD_SECT_AP_WRITE (1 << 10)
> +#define PMD_SECT_AP_READ (1 << 11)
> +#define PMD_SECT_TEX(x) ((x) << 12) /* v5 */
> +#define PMD_SECT_APX (1 << 15) /* v6 */
> +#define PMD_SECT_S (1 << 16) /* v6 */
> +#define PMD_SECT_nG (1 << 17) /* v6 */
> +#define PMD_SECT_SUPER (1 << 18) /* v6 */
> +
> +#define PMD_SECT_UNCACHED (0)
> +#define PMD_SECT_BUFFERED (PMD_SECT_BUFFERABLE)
> +#define PMD_SECT_WT (PMD_SECT_CACHEABLE)
> +#define PMD_SECT_WB (PMD_SECT_CACHEABLE | PMD_SECT_BUFFERABLE)
> +#define PMD_SECT_MINICACHE (PMD_SECT_TEX(1) | PMD_SECT_CACHEABLE)
> +#define PMD_SECT_WBWA (PMD_SECT_TEX(1) | PMD_SECT_CACHEABLE | PMD_SECT_BUFFERABLE)
> +#define PMD_SECT_NONSHARED_DEV (PMD_SECT_TEX(2))
> +
> +/*
> + * - coarse table (not used)
> + */
> +
> +/*
> + * + Level 2 descriptor (PTE)
> + * - common
> + */
> +#define PTE_TYPE_MASK (3 << 0)
> +#define PTE_TYPE_FAULT (0 << 0)
> +#define PTE_TYPE_LARGE (1 << 0)
> +#define PTE_TYPE_SMALL (2 << 0)
> +#define PTE_TYPE_EXT (3 << 0) /* v5 */
> +#define PTE_BUFFERABLE (1 << 2)
> +#define PTE_CACHEABLE (1 << 3)
> +
> +/*
> + * - extended small page/tiny page
> + */
> +#define PTE_EXT_XN (1 << 0) /* v6 */
> +#define PTE_EXT_AP_MASK (3 << 4)
> +#define PTE_EXT_AP0 (1 << 4)
> +#define PTE_EXT_AP1 (2 << 4)
> +#define PTE_EXT_AP_UNO_SRO (0 << 4)
> +#define PTE_EXT_AP_UNO_SRW (PTE_EXT_AP0)
> +#define PTE_EXT_AP_URO_SRW (PTE_EXT_AP1)
> +#define PTE_EXT_AP_URW_SRW (PTE_EXT_AP1|PTE_EXT_AP0)
> +#define PTE_EXT_TEX(x) ((x) << 6) /* v5 */
> +#define PTE_EXT_APX (1 << 9) /* v6 */
> +#define PTE_EXT_COHERENT (1 << 9) /* XScale3 */
> +#define PTE_EXT_SHARED (1 << 10) /* v6 */
> +#define PTE_EXT_NG (1 << 11) /* v6 */
> +
> +/*
> + * - small page
> + */
> +#define PTE_SMALL_AP_MASK (0xff << 4)
> +#define PTE_SMALL_AP_UNO_SRO (0x00 << 4)
> +#define PTE_SMALL_AP_UNO_SRW (0x55 << 4)
> +#define PTE_SMALL_AP_URO_SRW (0xaa << 4)
> +#define PTE_SMALL_AP_URW_SRW (0xff << 4)
> +
> +#endif
> diff --git a/arch/arm64/include/asm/posix_types.h b/arch/arm64/include/asm/posix_types.h
> new file mode 100644
> index 0000000..22cae62
> --- /dev/null
> +++ b/arch/arm64/include/asm/posix_types.h
> @@ -0,0 +1 @@
> +#include <asm-generic/posix_types.h>
> diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h
> new file mode 100644
> index 0000000..d5dbab0
> --- /dev/null
> +++ b/arch/arm64/include/asm/processor.h
> @@ -0,0 +1,131 @@
> +/*
> + * linux/include/asm-arm/processor.h
> + *
> + * Copyright (C) 1995-2002 Russell King
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#ifndef __ASM_ARM_PROCESSOR_H
> +#define __ASM_ARM_PROCESSOR_H
> +
> +/*
> + * Default implementation of macro that returns current
> + * instruction pointer ("program counter").
> + */
> +#define current_text_addr() ({ __label__ _l; _l: &&_l;})
> +
> +#define FP_SIZE 35
> +
> +struct fp_hard_struct {
> + unsigned int save[FP_SIZE]; /* as yet undefined */
> +};
> +
> +struct fp_soft_struct {
> + unsigned int save[FP_SIZE]; /* undefined information */
> +};
> +
> +union fp_state {
> + struct fp_hard_struct hard;
> + struct fp_soft_struct soft;
> +};
> +
> +typedef unsigned long mm_segment_t; /* domain register */
> +
> +#ifdef __KERNEL__
> +
> +#define EISA_bus 0
> +#define MCA_bus 0
> +#define MCA_bus__is_a_macro
> +
> +#include <asm/atomic.h>
> +#include <asm/ptrace.h>
> +#include <asm/proc/processor.h>
> +#include <asm/types.h>
> +
> +union debug_insn {
> + u32 arm;
> + u16 thumb;
> +};
> +
> +struct debug_entry {
> + u32 address;
> + union debug_insn insn;
> +};
> +
> +struct debug_info {
> + int nsaved;
> + struct debug_entry bp[2];
> +};
> +
> +struct thread_struct {
> + atomic_t refcount;
> + /* fault info */
> + unsigned long address;
> + unsigned long trap_no;
> + unsigned long error_code;
> + /* floating point */
> + union fp_state fpstate;
> + /* debugging */
> + struct debug_info debug;
> + /* context info */
> + struct context_save_struct *save;
> + EXTRA_THREAD_STRUCT
> +};
> +
> +#define INIT_THREAD { \
> + refcount: ATOMIC_INIT(1), \
> + EXTRA_THREAD_STRUCT_INIT \
> +}
> +
> +/*
> + * Return saved PC of a blocked thread.
> + */
> +static inline unsigned long thread_saved_pc(struct thread_struct *t)
> +{
> + return t->save ? pc_pointer(t->save->pc) : 0;
> +}
> +
> +static inline unsigned long thread_saved_fp(struct thread_struct *t)
> +{
> + return t->save ? t->save->fp : 0;
> +}
> +
> +/* Forward declaration, a strange C thing */
> +struct task_struct;
> +
> +/* Free all resources held by a thread. */
> +extern void release_thread(struct task_struct *);
> +
> +/* Copy and release all segment info associated with a VM */
> +#define copy_segments(tsk, mm) do { } while (0)
> +#define release_segments(mm) do { } while (0)
> +
> +unsigned long get_wchan(struct task_struct *p);
> +
> +#define THREAD_SIZE (8192)
> +
> +extern struct task_struct *alloc_task_struct(void);
> +extern void __free_task_struct(struct task_struct *);
> +#define get_task_struct(p) atomic_inc(&(p)->thread.refcount)
> +#define free_task_struct(p) \
> + do { \
> + if (atomic_dec_and_test(&(p)->thread.refcount)) \
> + __free_task_struct((p)); \
> + } while (0)
> +
> +#define init_task (init_task_union.task)
> +#define init_stack (init_task_union.stack)
> +
> +#define cpu_relax() barrier()
> +
> +/*
> + * Create a new kernel thread
> + */
> +extern int arch_kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
> +
> +#endif
> +
> +#endif /* __ASM_ARM_PROCESSOR_H */
> diff --git a/arch/arm64/include/asm/ptrace.h b/arch/arm64/include/asm/ptrace.h
> new file mode 100644
> index 0000000..450b63a
> --- /dev/null
> +++ b/arch/arm64/include/asm/ptrace.h
> @@ -0,0 +1,34 @@
> +/*
> + * arch/arm/include/asm/ptrace.h
> + *
> + * Copyright (C) 1996-2003 Russell King
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +#ifndef __ASM_ARM_PTRACE_H
> +#define __ASM_ARM_PTRACE_H
> +
> +#define PTRACE_GETREGS 12
> +#define PTRACE_SETREGS 13
> +#define PTRACE_GETFPREGS 14
> +#define PTRACE_SETFPREGS 15
> +
> +#define PTRACE_SETOPTIONS 21
> +
> +/* options set using PTRACE_SETOPTIONS */
> +#define PTRACE_O_TRACESYSGOOD 0x00000001
> +
> +#ifndef __ASSEMBLY__
> +
> +/* this struct defines the way the registers are stored on the
> + stack during a system call. */
> +
> +struct pt_regs {
> + long uregs[31];
> +};
> +
> +#endif /* __ASSEMBLY__ */
> +
> +#endif
> diff --git a/arch/arm64/include/asm/sections.h b/arch/arm64/include/asm/sections.h
> new file mode 100644
> index 0000000..8c7bc8c
> --- /dev/null
> +++ b/arch/arm64/include/asm/sections.h
> @@ -0,0 +1,34 @@
> +#ifndef __ASM_SECTIONS_H
> +#define __ASM_SECTIONS_H
> +
> +#ifndef __ASSEMBLY__
> +#include <asm-generic/sections.h>
> +
> +/*
> + * Access a linker supplied variable. Use this if your code might not be running
> + * at the address it is linked at.
> + */
> +#define ld_var(name) ({ \
> + unsigned long __ld_var_##name(void); \
> + __ld_var_##name(); \
> +})
> +
> +#else
> +
> +/*
> + * Access a linker supplied variable, assembler macro version
> + */
> +.macro ld_var name, reg, scratch
> + 1000:
> + ldr \reg, 1001f
> + ldr \scratch, =1000b
> + add \reg, \reg, \scratch
> + b 1002f
> + 1001:
> + .word \name - 1000b
> + 1002:
> +.endm
> +
> +#endif
> +
> +#endif /* __ASM_SECTIONS_H */
> diff --git a/arch/arm64/include/asm/semihosting.h b/arch/arm64/include/asm/semihosting.h
> new file mode 100644
> index 0000000..b478dad
> --- /dev/null
> +++ b/arch/arm64/include/asm/semihosting.h
> @@ -0,0 +1,19 @@
> +#ifndef __ASM_ARM_SEMIHOSTING_H
> +#define __ASM_ARM_SEMIHOSTING_H
> +
> +int semihosting_open(const char *fname, int flags);
> +int semihosting_close(int fd);
> +int semihosting_writec(char c);
> +int semihosting_write0(const char *str);
> +ssize_t semihosting_write(int fd, const void *buf, size_t count);
> +ssize_t semihosting_read(int fd, void *buf, size_t count);
> +int semihosting_readc(void);
> +int semihosting_isatty(int fd);
> +int semihosting_seek(int fd, loff_t pos);
> +int semihosting_flen(int fd);
> +int semihosting_remove(const char *fname);
> +int semihosting_rename(const char *fname1, const char *fname2);
> +int semihosting_errno(void);
> +int semihosting_system(const char *command);
> +
> +#endif
> diff --git a/arch/arm64/include/asm/setup.h b/arch/arm64/include/asm/setup.h
> new file mode 100644
> index 0000000..6ce35fb
> --- /dev/null
> +++ b/arch/arm64/include/asm/setup.h
> @@ -0,0 +1,216 @@
> +/*
> + * Copyright (C) 1997-1999 Russell King
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * Structure passed to kernel to tell it about the
> + * hardware it's running on. See linux/Documentation/arm/Setup
> + * for more info.
> + */
> +#ifndef __ASMARM_SETUP_H
> +#define __ASMARM_SETUP_H
> +
> +/*
> + * Usage:
> + * - do not go blindly adding fields, add them at the end
> + * - when adding fields, don't rely on the address until
> + * a patch from me has been released
> + * - unused fields should be zero (for future expansion)
> + * - this structure is relatively short-lived - only
> + * guaranteed to contain useful data in setup_arch()
> + */
> +#define COMMAND_LINE_SIZE 1024
> +
> +/*
> + * The new way of passing information: a list of tagged entries
> + */
> +
> +/* The list ends with an ATAG_NONE node. */
> +#define ATAG_NONE 0x00000000
> +
> +struct tag_header {
> + u32 size;
> + u32 tag;
> +};
> +
> +/* The list must start with an ATAG_CORE node */
> +#define ATAG_CORE 0x54410001
> +
> +struct tag_core {
> + u32 flags; /* bit 0 = read-only */
> + u32 pagesize;
> + u32 rootdev;
> +};
> +
> +/* it is allowed to have multiple ATAG_MEM nodes */
> +#define ATAG_MEM 0x54410002
> +
> +struct tag_mem32 {
> + u32 size;
> + u32 start; /* physical start address */
> +};
> +
> +/* VGA text type displays */
> +#define ATAG_VIDEOTEXT 0x54410003
> +
> +struct tag_videotext {
> + u8 x;
> + u8 y;
> + u16 video_page;
> + u8 video_mode;
> + u8 video_cols;
> + u16 video_ega_bx;
> + u8 video_lines;
> + u8 video_isvga;
> + u16 video_points;
> +};
> +
> +/* describes how the ramdisk will be used in kernel */
> +#define ATAG_RAMDISK 0x54410004
> +
> +struct tag_ramdisk {
> + u32 flags; /* bit 0 = load, bit 1 = prompt */
> + u32 size; /* decompressed ramdisk size in _kilo_ bytes */
> + u32 start; /* starting block of floppy-based RAM disk image */
> +};
> +
> +/* describes where the compressed ramdisk image lives (virtual address) */
> +/*
> + * this one accidentally used virtual addresses - as such,
> + * its depreciated.
> + */
> +#define ATAG_INITRD 0x54410005
> +
> +/* describes where the compressed ramdisk image lives (physical address) */
> +#define ATAG_INITRD2 0x54420005
> +
> +struct tag_initrd {
> + u32 start; /* physical start address */
> + u32 size; /* size of compressed ramdisk image in bytes */
> +};
> +
> +/* board serial number. "64 bits should be enough for everybody" */
> +#define ATAG_SERIAL 0x54410006
> +
> +struct tag_serialnr {
> + u32 low;
> + u32 high;
> +};
> +
> +/* board revision */
> +#define ATAG_REVISION 0x54410007
> +
> +struct tag_revision {
> + u32 rev;
> +};
> +
> +/* initial values for vesafb-type framebuffers. see struct screen_info
> + * in include/linux/tty.h
> + */
> +#define ATAG_VIDEOLFB 0x54410008
> +
> +struct tag_videolfb {
> + u16 lfb_width;
> + u16 lfb_height;
> + u16 lfb_depth;
> + u16 lfb_linelength;
> + u32 lfb_base;
> + u32 lfb_size;
> + u8 red_size;
> + u8 red_pos;
> + u8 green_size;
> + u8 green_pos;
> + u8 blue_size;
> + u8 blue_pos;
> + u8 rsvd_size;
> + u8 rsvd_pos;
> +};
> +
> +/* command line: \0 terminated string */
> +#define ATAG_CMDLINE 0x54410009
> +
> +struct tag_cmdline {
> + char cmdline[1]; /* this is the minimum size */
> +};
> +
> +/* acorn RiscPC specific information */
> +#define ATAG_ACORN 0x41000101
> +
> +struct tag_acorn {
> + u32 memc_control_reg;
> + u32 vram_pages;
> + u8 sounddefault;
> + u8 adfsdrives;
> +};
> +
> +/* footbridge memory clock, see arch/arm/mach-footbridge/arch.c */
> +#define ATAG_MEMCLK 0x41000402
> +
> +struct tag_memclk {
> + u32 fmemclk;
> +};
> +
> +struct tag {
> + struct tag_header hdr;
> + union {
> + struct tag_core core;
> + struct tag_mem32 mem;
> + struct tag_videotext videotext;
> + struct tag_ramdisk ramdisk;
> + struct tag_initrd initrd;
> + struct tag_serialnr serialnr;
> + struct tag_revision revision;
> + struct tag_videolfb videolfb;
> + struct tag_cmdline cmdline;
> +
> + /*
> + * Acorn specific
> + */
> + struct tag_acorn acorn;
> +
> + /*
> + * DC21285 specific
> + */
> + struct tag_memclk memclk;
> + } u;
> +};
> +
> +struct tagtable {
> + u32 tag;
> + int (*parse)(const struct tag *);
> +};
> +
> +#define __tag __attribute__((unused, __section__(".taglist")))
> +#define __tagtable(tag, fn) \
> +static struct tagtable __tagtable_##fn __tag = { tag, fn }
> +
> +#define tag_member_present(tag,member) \
> + ((unsigned long)(&((struct tag *)0L)->member + 1) \
> + <= (tag)->hdr.size * 4)
> +
> +#define tag_next(t) ((struct tag *)((u32 *)(t) + (t)->hdr.size))
> +#define tag_size(type) ((sizeof(struct tag_header) + sizeof(struct type)) >> 2)
> +
> +#define for_each_tag(t,base) \
> + for (t = base; t->hdr.size; t = tag_next(t))
> +
> +/*
> + * Memory map description
> + */
> +#define NR_BANKS 8
> +
> +struct meminfo {
> + int nr_banks;
> + unsigned long end;
> + struct {
> + unsigned long start;
> + unsigned long size;
> + int node;
> + } bank[NR_BANKS];
> +};
> +
> +extern struct meminfo meminfo;
> +
> +#endif
> diff --git a/arch/arm64/include/asm/stacktrace.h b/arch/arm64/include/asm/stacktrace.h
> new file mode 100644
> index 0000000..10f70e1
> --- /dev/null
> +++ b/arch/arm64/include/asm/stacktrace.h
> @@ -0,0 +1,16 @@
> +#ifndef __ASM_STACKTRACE_H
> +#define __ASM_STACKTRACE_H
> +
> +struct stackframe {
> + unsigned long fp;
> + unsigned long sp;
> + unsigned long lr;
> + unsigned long pc;
> +};
> +
> +extern int unwind_frame(struct stackframe *frame);
> +extern void walk_stackframe(struct stackframe *frame,
> + int (*fn)(struct stackframe *, void *), void *data);
> +
> +#endif /* __ASM_STACKTRACE_H */
> +
> diff --git a/arch/arm64/include/asm/string.h b/arch/arm64/include/asm/string.h
> new file mode 100644
> index 0000000..435647a
> --- /dev/null
> +++ b/arch/arm64/include/asm/string.h
> @@ -0,0 +1,13 @@
> +#ifndef __ASM_ARM_STRING_H
> +#define __ASM_ARM_STRING_H
> +
> +#ifdef CONFIG_ARM_OPTIMZED_STRING_FUNCTIONS
> +
> +#define __HAVE_ARCH_MEMCPY
> +extern void *memcpy(void *, const void *, __kernel_size_t);
> +#define __HAVE_ARCH_MEMSET
> +extern void *memset(void *, int, __kernel_size_t);
> +
> +#endif
> +
> +#endif
> diff --git a/arch/arm64/include/asm/swab.h b/arch/arm64/include/asm/swab.h
> new file mode 100644
> index 0000000..9997ad2
> --- /dev/null
> +++ b/arch/arm64/include/asm/swab.h
> @@ -0,0 +1,69 @@
> +/*
> + * arch/arm/include/asm/byteorder.h
> + *
> + * ARM Endian-ness. In little endian mode, the data bus is connected such
> + * that byte accesses appear as:
> + * 0 = d0...d7, 1 = d8...d15, 2 = d16...d23, 3 = d24...d31
> + * and word accesses (data or instruction) appear as:
> + * d0...d31
> + *
> + * When in big endian mode, byte accesses appear as:
> + * 0 = d24...d31, 1 = d16...d23, 2 = d8...d15, 3 = d0...d7
> + * and word accesses (data or instruction) appear as:
> + * d0...d31
> + */
> +#ifndef __ASM_ARM_SWAB_H
> +#define __ASM_ARM_SWAB_H
> +
> +#include <linux/compiler.h>
> +#include <linux/types.h>
> +
> +#if !defined(__STRICT_ANSI__) || defined(__KERNEL__)
> +# define __SWAB_64_THRU_32__
> +#endif
> +
> +#if defined(__KERNEL__) && __LINUX_ARM_ARCH__ >= 6
> +
> +static inline __attribute_const__ __u16 __arch_swab16(__u16 x)
> +{
> + __asm__ ("rev16 %0, %1" : "=r" (x) : "r" (x));
> + return x;
> +}
> +#define __arch_swab16 __arch_swab16
> +
> +static inline __attribute_const__ __u32 __arch_swab32(__u32 x)
> +{
> + __asm__ ("rev %0, %1" : "=r" (x) : "r" (x));
> + return x;
> +}
> +#define __arch_swab32 __arch_swab32
> +
> +#else
> +
> +static inline __attribute_const__ __u32 __arch_swab32(__u32 x)
> +{
> + __u32 t;
> +
> +#ifndef __thumb__
> + if (!__builtin_constant_p(x)) {
> + /*
> + * The compiler needs a bit of a hint here to always do the
> + * right thing and not screw it up to different degrees
> + * depending on the gcc version.
> + */
> + asm ("eor\t%0, %1, %1, ror #16" : "=r" (t) : "r" (x));
> + } else
> +#endif
> + t = x ^ ((x << 16) | (x >> 16)); /* eor r1,r0,r0,ror #16 */
> +
> + x = (x << 24) | (x >> 8); /* mov r0,r0,ror #8 */
> + t &= ~0x00FF0000; /* bic r1,r1,#0x00FF0000 */
> + x ^= (t >> 8); /* eor r0,r0,r1,lsr #8 */
> +
> + return x;
> +}
> +#define __arch_swab32 __arch_swab32
> +
> +#endif
> +
> +#endif
> diff --git a/arch/arm64/include/asm/system.h b/arch/arm64/include/asm/system.h
> new file mode 100644
> index 0000000..a4f9a71
> --- /dev/null
> +++ b/arch/arm64/include/asm/system.h
> @@ -0,0 +1,125 @@
> +#ifndef __ASM_ARM_SYSTEM_H
> +#define __ASM_ARM_SYSTEM_H
> +
> +#define isb() __asm__ __volatile__ ("isb" : : : "memory")
> +#define dsb() __asm__ __volatile__ ("dsb" : : : "memory")
> +#define dmb() __asm__ __volatile__ ("dmb" : : : "memory")
> +
> +/*
> + * SCTLR_EL1/SCTLR_EL2/SCTLR_EL3 bits definitions
> + */
> +#define CR_M (1 << 0) /* MMU enable */
> +#define CR_A (1 << 1) /* Alignment abort enable */
> +#define CR_C (1 << 2) /* Dcache enable */
> +#define CR_SA (1 << 3) /* Stack Alignment Check Enable */
> +#define CR_I (1 << 12) /* Icache enable */
> +#define CR_WXN (1 << 19) /* Write Permision Imply XN */
> +#define CR_EE (1 << 25) /* Exception (Big) Endian */
> +
> +#ifndef CONFIG_SYS_FULL_VA
> +#define PGTABLE_SIZE (0x10000)
> +#else
> +#define PGTABLE_SIZE CONFIG_SYS_PGTABLE_SIZE
> +#endif
> +
> +/* 2MB granularity */
> +#define MMU_SECTION_SHIFT 21
> +#define MMU_SECTION_SIZE (1 << MMU_SECTION_SHIFT)
> +
> +#ifndef __ASSEMBLY__
> +
> +enum dcache_option {
> + DCACHE_OFF = 0x3,
> +};
> +
> +#define wfi() \
> + ({asm volatile( \
> + "wfi" : : : "memory"); \
> + })
> +
> +static inline unsigned int current_el(void)
> +{
> + unsigned int el;
> + asm volatile("mrs %0, CurrentEL" : "=r" (el) : : "cc");
> + return el >> 2;
> +}
> +
> +static inline unsigned int get_sctlr(void)
> +{
> + unsigned int el, val;
> +
> + el = current_el();
> + if (el == 1)
> + asm volatile("mrs %0, sctlr_el1" : "=r" (val) : : "cc");
> + else if (el == 2)
> + asm volatile("mrs %0, sctlr_el2" : "=r" (val) : : "cc");
> + else
> + asm volatile("mrs %0, sctlr_el3" : "=r" (val) : : "cc");
> +
> + return val;
> +}
> +
> +static inline void set_sctlr(unsigned int val)
> +{
> + unsigned int el;
> +
> + el = current_el();
> + if (el == 1)
> + asm volatile("msr sctlr_el1, %0" : : "r" (val) : "cc");
> + else if (el == 2)
> + asm volatile("msr sctlr_el2, %0" : : "r" (val) : "cc");
> + else
> + asm volatile("msr sctlr_el3, %0" : : "r" (val) : "cc");
> +
> + asm volatile("isb");
> +}
> +
> +static inline unsigned long read_mpidr(void)
> +{
> + unsigned long val;
> +
> + asm volatile("mrs %0, mpidr_el1" : "=r" (val));
> +
> + return val;
> +}
> +
> +#define BSP_COREID 0
> +
> +void __asm_flush_dcache_all(void);
> +void __asm_invalidate_dcache_all(void);
> +void __asm_flush_dcache_range(u64 start, u64 end);
> +void __asm_invalidate_tlb_all(void);
> +void __asm_invalidate_icache_all(void);
> +int __asm_flush_l3_cache(void);
> +
> +void armv8_switch_to_el2(void);
> +void armv8_switch_to_el1(void);
> +void gic_init(void);
> +void gic_send_sgi(unsigned long sgino);
> +void wait_for_wakeup(void);
> +void protect_secure_region(void);
> +void smp_kick_all_cpus(void);
> +
> +void flush_l3_cache(void);
> +
> +/*
> + *Issue a hypervisor call in accordance with ARM "SMC Calling convention",
> + * DEN0028A
> + *
> + * @args: input and output arguments
> + *
> + */
> +void hvc_call(struct pt_regs *args);
> +
> +/*
> + *Issue a secure monitor call in accordance with ARM "SMC Calling convention",
> + * DEN0028A
> + *
> + * @args: input and output arguments
> + *
> + */
> +void smc_call(struct pt_regs *args);
> +
> +#endif /* __ASSEMBLY__ */
> +
> +#endif /* __ASM_ARM_SYSTEM_H */
> diff --git a/arch/arm64/include/asm/system_info.h b/arch/arm64/include/asm/system_info.h
> new file mode 100644
> index 0000000..f595aae
> --- /dev/null
> +++ b/arch/arm64/include/asm/system_info.h
> @@ -0,0 +1,194 @@
> +#ifndef __ASM_ARM_SYSTEM_INFO_H
> +#define __ASM_ARM_SYSTEM_INFO_H
> +
> +#include <asm/cputype.h>
> +
> +#define CPU_ARCH_UNKNOWN 0
> +#define CPU_ARCH_ARMv3 1
> +#define CPU_ARCH_ARMv4 2
> +#define CPU_ARCH_ARMv4T 3
> +#define CPU_ARCH_ARMv5 4
> +#define CPU_ARCH_ARMv5T 5
> +#define CPU_ARCH_ARMv5TE 6
> +#define CPU_ARCH_ARMv5TEJ 7
> +#define CPU_ARCH_ARMv6 8
> +#define CPU_ARCH_ARMv7 9
> +#define CPU_ARCH_ARMv8 10
> +
> +#define CPU_IS_ARM720 0x41007200
> +#define CPU_IS_ARM720_MASK 0xff00fff0
> +
> +#define CPU_IS_ARM920 0x41009200
> +#define CPU_IS_ARM920_MASK 0xff00fff0
> +
> +#define CPU_IS_ARM926 0x41069260
> +#define CPU_IS_ARM926_MASK 0xff0ffff0
> +
> +#define CPU_IS_ARM1176 0x410fb760
> +#define CPU_IS_ARM1176_MASK 0xff0ffff0
> +
> +#define CPU_IS_CORTEX_A8 0x410fc080
> +#define CPU_IS_CORTEX_A8_MASK 0xff0ffff0
> +
> +#define CPU_IS_CORTEX_A5 0x410fc050
> +#define CPU_IS_CORTEX_A5_MASK 0xff0ffff0
> +
> +#define CPU_IS_CORTEX_A9 0x410fc090
> +#define CPU_IS_CORTEX_A9_MASK 0xff0ffff0
> +
> +#define CPU_IS_CORTEX_A7 0x410fc070
> +#define CPU_IS_CORTEX_A7_MASK 0xff0ffff0
> +
> +#define CPU_IS_CORTEX_A15 0x410fc0f0
> +#define CPU_IS_CORTEX_A15_MASK 0xff0ffff0
> +
> +#define CPU_IS_CORTEX_A53 0x410fd034
> +#define CPU_IS_CORTEX_A53_MASK 0xff0ffff0
> +
> +#define CPU_IS_CORTEX_A57 0x411fd070
> +#define CPU_IS_CORTEX_A57_MASK 0xff0ffff0
> +
> +#define CPU_IS_PXA250 0x69052100
> +#define CPU_IS_PXA250_MASK 0xfffff7f0
> +
> +#define CPU_IS_PXA255 0x69052d00
> +#define CPU_IS_PXA255_MASK 0xfffffff0
> +
> +#define CPU_IS_PXA270 0x69054110
> +#define CPU_IS_PXA270_MASK 0xfffff7f0
> +
> +#define cpu_is_arm(core) ((read_cpuid_id() & CPU_IS_##core##_MASK) == CPU_IS_##core)
> +
> +#ifdef CONFIG_CPU_32v4T
> +#ifdef ARM_ARCH
> +#define ARM_MULTIARCH
> +#else
> +#define ARM_ARCH CPU_ARCH_ARMv4T
> +#endif
> +#define cpu_is_arm720() cpu_is_arm(ARM720)
> +#define cpu_is_arm920() cpu_is_arm(ARM920)
> +#define cpu_is_pxa250() cpu_is_arm(PXA250)
> +#define cpu_is_pxa255() cpu_is_arm(PXA255)
> +#define cpu_is_pxa270() cpu_is_arm(PXA270)
> +#else
> +#define cpu_is_arm720() (0)
> +#define cpu_is_arm920() (0)
> +#define cpu_is_pxa250() (0)
> +#define cpu_is_pxa255() (0)
> +#define cpu_is_pxa270() (0)
> +#endif
> +
> +#ifdef CONFIG_CPU_32v5
> +#ifdef ARM_ARCH
> +#define ARM_MULTIARCH
> +#else
> +#define ARM_ARCH CPU_ARCH_ARMv5
> +#endif
> +#define cpu_is_arm926() cpu_is_arm(ARM926)
> +#else
> +#define cpu_is_arm926() (0)
> +#endif
> +
> +#ifdef CONFIG_CPU_32v6
> +#ifdef ARM_ARCH
> +#define ARM_MULTIARCH
> +#else
> +#define ARM_ARCH CPU_ARCH_ARMv6
> +#endif
> +#define cpu_is_arm1176() cpu_is_arm(ARM1176)
> +#else
> +#define cpu_is_arm1176() (0)
> +#endif
> +
> +#ifdef CONFIG_CPU_32v7
> +#ifdef ARM_ARCH
> +#define ARM_MULTIARCH
> +#else
> +#define ARM_ARCH CPU_ARCH_ARMv7
> +#endif
> +#define cpu_is_cortex_a8() cpu_is_arm(CORTEX_A8)
> +#define cpu_is_cortex_a5() cpu_is_arm(CORTEX_A5)
> +#define cpu_is_cortex_a9() cpu_is_arm(CORTEX_A9)
> +#define cpu_is_cortex_a7() cpu_is_arm(CORTEX_A7)
> +#define cpu_is_cortex_a15() cpu_is_arm(CORTEX_A15)
> +#else
> +#define cpu_is_cortex_a8() (0)
> +#define cpu_is_cortex_a5() (0)
> +#define cpu_is_cortex_a9() (0)
> +#define cpu_is_cortex_a7() (0)
> +#define cpu_is_cortex_a15() (0)
> +#endif
> +
> +
> +#ifdef CONFIG_CPU_64v8
> +#ifdef ARM_ARCH
> +#define ARM_MULTIARCH
> +#else
> +#define ARM_ARCH CPU_ARCH_ARMv8
> +#endif
> +#define cpu_is_cortex_a53() cpu_is_arm(CORTEX_A53)
> +#define cpu_is_cortex_a57() cpu_is_arm(CORTEX_A57)
> +#else
> +#define cpu_is_cortex_a53() (0)
> +#define cpu_is_cortex_a57() (0)
> +#endif
> +
> +#ifndef __ASSEMBLY__
> +
> +#ifdef ARM_MULTIARCH
> +/*
> + * Early version to get the ARM cpu architecture. Only needed during
> + * early startup when the C environment is not yet fully initialized.
> + * Normally you should use cpu_architecture() instead.
> + */
> +static inline int arm_early_get_cpu_architecture(void)
> +{
> + int cpu_arch;
> +
> +// if ((read_cpuid_id() & 0x0008f000) == 0) {
> +// cpu_arch = CPU_ARCH_UNKNOWN;
> +// } else if ((read_cpuid_id() & 0x0008f000) == 0x00007000) {
> +// cpu_arch = (read_cpuid_id() & (1 << 23)) ? CPU_ARCH_ARMv4T : CPU_ARCH_ARMv3;
> +// } else if ((read_cpuid_id() & 0x00080000) == 0x00000000) {
> +// cpu_arch = (read_cpuid_id() >> 16) & 7;
> +// if (cpu_arch)
> +// cpu_arch += CPU_ARCH_ARMv3;
> +// } else if ((read_cpuid_id() & 0x000f0000) == 0x000f0000) {
> +// unsigned int mmfr0;
> +//
> +// /* Revised CPUID format. Read the Memory Model Feature
> +// * Register 0 and check for VMSAv7 or PMSAv7 */
> +// asm("mrc p15, 0, %0, c0, c1, 4"
> +// : "=r" (mmfr0));
> +// if ((mmfr0 & 0x0000000f) >= 0x00000003 ||
> +// (mmfr0 & 0x000000f0) >= 0x00000030)
> +// cpu_arch = CPU_ARCH_ARMv7;
> +// else if ((mmfr0 & 0x0000000f) == 0x00000002 ||
> +// (mmfr0 & 0x000000f0) == 0x00000020)
> +// cpu_arch = CPU_ARCH_ARMv6;
> +// else
> +// cpu_arch = CPU_ARCH_UNKNOWN;
> +// } else
> +// cpu_arch = CPU_ARCH_UNKNOWN;
> +
> + cpu_arch = CPU_ARCH_ARMv8;
> +
> + return cpu_arch;
> +}
> +
> +extern int __pure cpu_architecture(void);
> +#else
> +static inline int __pure arm_early_get_cpu_architecture(void)
> +{
> + return ARM_ARCH;
> +}
> +
> +static inline int __pure cpu_architecture(void)
> +{
> + return ARM_ARCH;
> +}
> +#endif
> +
> +#endif /* !__ASSEMBLY__ */
> +
> +#endif /* __ASM_ARM_SYSTEM_INFO_H */
> diff --git a/arch/arm64/include/asm/types.h b/arch/arm64/include/asm/types.h
> new file mode 100644
> index 0000000..1a7f47a
> --- /dev/null
> +++ b/arch/arm64/include/asm/types.h
> @@ -0,0 +1,54 @@
> +#ifndef __ASM_ARM_TYPES_H
> +#define __ASM_ARM_TYPES_H
> +
> +#ifndef __ASSEMBLY__
> +
> +typedef unsigned short umode_t;
> +
> +/*
> + * __xx is ok: it doesn't pollute the POSIX namespace. Use these in the
> + * header files exported to user space
> + */
> +
> +typedef __signed__ char __s8;
> +typedef unsigned char __u8;
> +
> +typedef __signed__ short __s16;
> +typedef unsigned short __u16;
> +
> +typedef __signed__ int __s32;
> +typedef unsigned int __u32;
> +
> +#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
> +typedef __signed__ long long __s64;
> +typedef unsigned long long __u64;
> +#endif
> +
> +#endif /* __ASSEMBLY__ */
> +
> +/*
> + * These aren't exported outside the kernel to avoid name space clashes
> + */
> +#ifdef __KERNEL__
> +
> +#include <asm/bitsperlong.h>
> +
> +#ifndef __ASSEMBLY__
> +
> +typedef signed char s8;
> +typedef unsigned char u8;
> +
> +typedef signed short s16;
> +typedef unsigned short u16;
> +
> +typedef signed int s32;
> +typedef unsigned int u32;
> +
> +typedef signed long long s64;
> +typedef unsigned long long u64;
> +
> +#endif /* __ASSEMBLY__ */
> +
> +#endif /* __KERNEL__ */
> +
> +#endif
> diff --git a/arch/arm64/include/asm/unaligned.h b/arch/arm64/include/asm/unaligned.h
> new file mode 100644
> index 0000000..44593a8
> --- /dev/null
> +++ b/arch/arm64/include/asm/unaligned.h
> @@ -0,0 +1,19 @@
> +#ifndef _ASM_ARM_UNALIGNED_H
> +#define _ASM_ARM_UNALIGNED_H
> +
> +#include <linux/unaligned/le_byteshift.h>
> +#include <linux/unaligned/be_byteshift.h>
> +#include <linux/unaligned/generic.h>
> +
> +/*
> + * Select endianness
> + */
> +#ifndef __ARMEB__
> +#define get_unaligned __get_unaligned_le
> +#define put_unaligned __put_unaligned_le
> +#else
> +#define get_unaligned __get_unaligned_be
> +#define put_unaligned __put_unaligned_be
> +#endif
> +
> +#endif /* _ASM_ARM_UNALIGNED_H */
> diff --git a/arch/arm64/include/asm/unified.h b/arch/arm64/include/asm/unified.h
> new file mode 100644
> index 0000000..13a2bff
> --- /dev/null
> +++ b/arch/arm64/include/asm/unified.h
> @@ -0,0 +1,127 @@
> +/*
> + * include/asm-arm/unified.h - Unified Assembler Syntax helper macros
> + *
> + * Copyright (C) 2008 ARM Limited
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * 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.
> + *
> + */
> +
> +#ifndef __ASM_UNIFIED_H
> +#define __ASM_UNIFIED_H
> +
> +#if defined(__ASSEMBLY__) && defined(CONFIG_ARM_ASM_UNIFIED)
> + .syntax unified
> +#endif
> +
> +#ifdef CONFIG_THUMB2_BAREBOX
> +
> +#if __GNUC__ < 4
> +#error Thumb-2 barebox requires gcc >= 4
> +#endif
> +
> +/* The CPSR bit describing the instruction set (Thumb) */
> +#define PSR_ISETSTATE PSR_T_BIT
> +
> +#define ARM(x...)
> +#define THUMB(x...) x
> +#ifdef __ASSEMBLY__
> +#define W(instr) instr.w
> +#endif
> +#define BSYM(sym) sym + 1
> +
> +#else /* !CONFIG_THUMB2_BAREBOX */
> +
> +/* The CPSR bit describing the instruction set (ARM) */
> +#define PSR_ISETSTATE 0
> +
> +#define ARM(x...) x
> +#define THUMB(x...)
> +#ifdef __ASSEMBLY__
> +#define W(instr) instr
> +#endif
> +#define BSYM(sym) sym
> +
> +#endif /* CONFIG_THUMB2_BAREBOX */
> +
> +#ifndef CONFIG_ARM_ASM_UNIFIED
> +
> +/*
> + * If the unified assembly syntax isn't used (in ARM mode), these
> + * macros expand to an empty string
> + */
> +#ifdef __ASSEMBLY__
> + .macro it, cond
> + .endm
> + .macro itt, cond
> + .endm
> + .macro ite, cond
> + .endm
> + .macro ittt, cond
> + .endm
> + .macro itte, cond
> + .endm
> + .macro itet, cond
> + .endm
> + .macro itee, cond
> + .endm
> + .macro itttt, cond
> + .endm
> + .macro ittte, cond
> + .endm
> + .macro ittet, cond
> + .endm
> + .macro ittee, cond
> + .endm
> + .macro itett, cond
> + .endm
> + .macro itete, cond
> + .endm
> + .macro iteet, cond
> + .endm
> + .macro iteee, cond
> + .endm
> +#else /* !__ASSEMBLY__ */
> +__asm__(
> +" .macro it, cond\n"
> +" .endm\n"
> +" .macro itt, cond\n"
> +" .endm\n"
> +" .macro ite, cond\n"
> +" .endm\n"
> +" .macro ittt, cond\n"
> +" .endm\n"
> +" .macro itte, cond\n"
> +" .endm\n"
> +" .macro itet, cond\n"
> +" .endm\n"
> +" .macro itee, cond\n"
> +" .endm\n"
> +" .macro itttt, cond\n"
> +" .endm\n"
> +" .macro ittte, cond\n"
> +" .endm\n"
> +" .macro ittet, cond\n"
> +" .endm\n"
> +" .macro ittee, cond\n"
> +" .endm\n"
> +" .macro itett, cond\n"
> +" .endm\n"
> +" .macro itete, cond\n"
> +" .endm\n"
> +" .macro iteet, cond\n"
> +" .endm\n"
> +" .macro iteee, cond\n"
> +" .endm\n");
> +#endif /* __ASSEMBLY__ */
> +
> +#endif /* CONFIG_ARM_ASM_UNIFIED */
> +
> +#endif /* !__ASM_UNIFIED_H */
> diff --git a/arch/arm64/include/asm/unwind.h b/arch/arm64/include/asm/unwind.h
> new file mode 100644
> index 0000000..311ad3d
> --- /dev/null
> +++ b/arch/arm64/include/asm/unwind.h
> @@ -0,0 +1,51 @@
> +/*
> + * arch/arm/include/asm/unwind.h
> + *
> + * Copyright (C) 2008 ARM Limited
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * 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.
> + *
> + */
> +
> +#ifndef __ASM_UNWIND_H
> +#define __ASM_UNWIND_H
> +
> +#ifndef __ASSEMBLY__
> +
> +/* Unwind reason code according the the ARM EABI documents */
> +enum unwind_reason_code {
> + URC_OK = 0, /* operation completed successfully */
> + URC_CONTINUE_UNWIND = 8,
> + URC_FAILURE = 9 /* unspecified failure of some kind */
> +};
> +
> +struct unwind_idx {
> + unsigned long addr;
> + unsigned long insn;
> +};
> +
> +struct unwind_table {
> + struct list_head list;
> + struct unwind_idx *start;
> + struct unwind_idx *stop;
> + unsigned long begin_addr;
> + unsigned long end_addr;
> +};
> +
> +extern struct unwind_table *unwind_table_add(unsigned long start,
> + unsigned long size,
> + unsigned long text_addr,
> + unsigned long text_size);
> +extern void unwind_table_del(struct unwind_table *tab);
> +extern void unwind_backtrace(struct pt_regs *regs);
> +
> +#endif /* !__ASSEMBLY__ */
> +
> +#endif /* __ASM_UNWIND_H */
> diff --git a/arch/arm64/lib/Makefile b/arch/arm64/lib/Makefile
> new file mode 100644
> index 0000000..5b9d4a5
> --- /dev/null
> +++ b/arch/arm64/lib/Makefile
> @@ -0,0 +1,16 @@
> +obj-$(CONFIG_ARM_LINUX) += armlinux.o
> +obj-$(CONFIG_BOOTM) += bootm.o
> +obj-$(CONFIG_CMD_BOOTZ) += bootz.o
> +obj-$(CONFIG_CMD_BOOTU) += bootu.o
> +obj-y += div0.o
> +obj-y += runtime-offset.o
> +pbl-y += runtime-offset.o
> +obj-$(CONFIG_ARM_OPTIMZED_STRING_FUNCTIONS) += memcpy.o
> +obj-$(CONFIG_ARM_OPTIMZED_STRING_FUNCTIONS) += memset.o
> +obj-$(CONFIG_ARM_UNWIND) += unwind.o
> +obj-$(CONFIG_MODULES) += module.o
> +extra-y += barebox.lds
> +
> +pbl-y += lib1funcs.o
> +pbl-y += ashldi3.o
> +pbl-y += div0.o
> diff --git a/arch/arm64/lib/armlinux.c b/arch/arm64/lib/armlinux.c
> new file mode 100644
> index 0000000..21a2292
> --- /dev/null
> +++ b/arch/arm64/lib/armlinux.c
> @@ -0,0 +1,275 @@
> +/*
> + * (C) Copyright 2002
> + * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
> + * Marius Groeger <mgroeger at sysgo.de>
> + *
> + * Copyright (C) 2001 Erik Mouw (J.A.K.Mouw at its.tudelft.nl)
> + *
> + * 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.
> + */
> +
> +#include <boot.h>
> +#include <common.h>
> +#include <command.h>
> +#include <driver.h>
> +#include <environment.h>
> +#include <image.h>
> +#include <init.h>
> +#include <fs.h>
> +#include <linux/list.h>
> +#include <xfuncs.h>
> +#include <malloc.h>
> +#include <fcntl.h>
> +#include <errno.h>
> +#include <memory.h>
> +#include <of.h>
> +#include <magicvar.h>
> +
> +#include <asm/byteorder.h>
> +#include <asm/setup.h>
> +#include <asm/barebox-arm.h>
> +#include <asm/armlinux.h>
> +#include <asm/system.h>
> +
> +static struct tag *params;
> +static void *armlinux_bootparams = NULL;
> +
> +static int armlinux_architecture;
> +static u32 armlinux_system_rev;
> +static u64 armlinux_system_serial;
> +
> +BAREBOX_MAGICVAR(armlinux_architecture, "ARM machine ID");
> +BAREBOX_MAGICVAR(armlinux_system_rev, "ARM system revision");
> +BAREBOX_MAGICVAR(armlinux_system_serial, "ARM system serial");
> +
> +void armlinux_set_architecture(int architecture)
> +{
> + export_env_ull("armlinux_architecture", architecture);
> + armlinux_architecture = architecture;
> +}
> +
> +int armlinux_get_architecture(void)
> +{
> + getenv_uint("armlinux_architecture", &armlinux_architecture);
> +
> + return armlinux_architecture;
> +}
> +
> +void armlinux_set_revision(unsigned int rev)
> +{
> + export_env_ull("armlinux_system_rev", rev);
> + armlinux_system_rev = rev;
> +}
> +
> +unsigned int armlinux_get_revision(void)
> +{
> + getenv_uint("armlinux_system_rev", &armlinux_system_rev);
> +
> + return armlinux_system_rev;
> +}
> +
> +void armlinux_set_serial(u64 serial)
> +{
> + export_env_ull("armlinux_system_serial", serial);
> + armlinux_system_serial = serial;
> +}
> +
> +u64 armlinux_get_serial(void)
> +{
> + getenv_ull("armlinux_system_serial", &armlinux_system_serial);
> +
> + return armlinux_system_serial;
> +}
> +
> +void armlinux_set_bootparams(void *params)
> +{
> + armlinux_bootparams = params;
> +}
> +
> +static struct tag *armlinux_get_bootparams(void)
> +{
> + struct memory_bank *mem;
> +
> + if (armlinux_bootparams)
> + return armlinux_bootparams;
> +
> + for_each_memory_bank(mem)
> + return (void *)mem->start + 0x100;
> +
> + BUG();
> +}
> +
> +#ifdef CONFIG_ARM_BOARD_APPEND_ATAG
> +static struct tag *(*atag_appender)(struct tag *);
> +void armlinux_set_atag_appender(struct tag *(*func)(struct tag *))
> +{
> + atag_appender = func;
> +}
> +#endif
> +
> +static void setup_start_tag(void)
> +{
> + params = armlinux_get_bootparams();
> +
> + params->hdr.tag = ATAG_CORE;
> + params->hdr.size = tag_size(tag_core);
> +
> + params->u.core.flags = 0;
> + params->u.core.pagesize = 0;
> + params->u.core.rootdev = 0;
> +
> + params = tag_next(params);
> +}
> +
> +static void setup_memory_tags(void)
> +{
> + struct memory_bank *bank;
> +
> + for_each_memory_bank(bank) {
> + params->hdr.tag = ATAG_MEM;
> + params->hdr.size = tag_size(tag_mem32);
> +
> + params->u.mem.start = bank->start;
> + params->u.mem.size = bank->size;
> +
> + params = tag_next(params);
> + }
> +}
> +
> +static void setup_commandline_tag(const char *commandline, int swap)
> +{
> + const char *p;
> + size_t words;
> +
> + if (!commandline)
> + return;
> +
> + /* eat leading white space */
> + for (p = commandline; *p == ' '; p++) ;
> +
> + /*
> + * skip non-existent command lines so the kernel will still
> + * use its default command line.
> + */
> + if (*p == '\0')
> + return;
> +
> + words = (strlen(p) + 1 /* NUL */ + 3 /* round up */) >> 2;
> + params->hdr.tag = ATAG_CMDLINE;
> + params->hdr.size = (sizeof(struct tag_header) >> 2) + words;
> +
> + strcpy(params->u.cmdline.cmdline, p);
> +
> +#ifdef CONFIG_BOOT_ENDIANNESS_SWITCH
> + if (swap) {
> + u32 *cmd = (u32 *)params->u.cmdline.cmdline;
> + while (words--)
> + cmd[words] = swab32(cmd[words]);
> + }
> +#endif
> +
> + params = tag_next(params);
> +}
> +
> +static void setup_revision_tag(void)
> +{
> + u32 system_rev = armlinux_get_revision();
> +
> + if (system_rev) {
> + params->hdr.tag = ATAG_REVISION;
> + params->hdr.size = tag_size(tag_revision);
> +
> + params->u.revision.rev = system_rev;
> +
> + params = tag_next(params);
> + }
> +}
> +
> +static void setup_serial_tag(void)
> +{
> + u64 system_serial = armlinux_get_serial();
> +
> + if (system_serial) {
> + params->hdr.tag = ATAG_SERIAL;
> + params->hdr.size = tag_size(tag_serialnr);
> +
> + params->u.serialnr.low = system_serial & 0xffffffff;
> + params->u.serialnr.high = system_serial >> 32;
> +
> + params = tag_next(params);
> + }
> +}
> +
> +static void setup_initrd_tag(unsigned long start, unsigned long size)
> +{
> + /* an ATAG_INITRD node tells the kernel where the compressed
> + * ramdisk can be found. ATAG_RDIMG is a better name, actually.
> + */
> + params->hdr.tag = ATAG_INITRD2;
> + params->hdr.size = tag_size(tag_initrd);
> +
> + params->u.initrd.start = start;
> + params->u.initrd.size = size;
> +
> + params = tag_next(params);
> +}
> +
> +static void setup_end_tag (void)
> +{
> + params->hdr.tag = ATAG_NONE;
> + params->hdr.size = 0;
> +}
> +
> +static void setup_tags(unsigned long initrd_address,
> + unsigned long initrd_size, int swap)
> +{
> + const char *commandline = linux_bootargs_get();
> +
> + setup_start_tag();
> + setup_memory_tags();
> + setup_commandline_tag(commandline, swap);
> +
> + if (initrd_size)
> + setup_initrd_tag(initrd_address, initrd_size);
> +
> + setup_revision_tag();
> + setup_serial_tag();
> +#ifdef CONFIG_ARM_BOARD_APPEND_ATAG
> + if (atag_appender != NULL)
> + params = atag_appender(params);
> +#endif
> + setup_end_tag();
> +
> + printf("commandline: %s\n"
> + "arch_number: %d\n", commandline, armlinux_get_architecture());
> +
> +}
> +
> +void start_linux(void *adr, int swap, unsigned long initrd_address,
> + unsigned long initrd_size, void *oftree)
> +{
> + void (*kernel)(int zero, int arch, void *params) = adr;
> + void *params = NULL;
> + int architecture;
> +
> + if (oftree) {
> + pr_debug("booting kernel with devicetree\n");
> + params = oftree;
> + } else {
> + setup_tags(initrd_address, initrd_size, swap);
> + params = armlinux_get_bootparams();
> + }
> + architecture = armlinux_get_architecture();
> +
> + shutdown_barebox();
> +
> + kernel(0, architecture, params);
> +}
> diff --git a/arch/arm64/lib/asm-offsets.c b/arch/arm64/lib/asm-offsets.c
> new file mode 100644
> index 0000000..7bf6d12
> --- /dev/null
> +++ b/arch/arm64/lib/asm-offsets.c
> @@ -0,0 +1,16 @@
> +/*
> + * Generate definitions needed by assembly language modules.
> + * This code generates raw asm output which is post-processed to extract
> + * and format the required data.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/kbuild.h>
> +
> +int main(void)
> +{
> + return 0;
> +}
> diff --git a/arch/arm64/lib/barebox.lds b/arch/arm64/lib/barebox.lds
> new file mode 100644
> index 0000000..a626ff9
> --- /dev/null
> +++ b/arch/arm64/lib/barebox.lds
> @@ -0,0 +1,125 @@
> +/*
> + *
> + * Automatically generated file; DO NOT EDIT.
> + * Barebox/arm64 2016.02.0 Configuration
> + *
> + */
> +/*
> + * Helper macros to use CONFIG_ options in C expressions. Note that
> + * these only work with boolean and tristate options.
> + */
> +/*
> + * Getting something that works in C and CPP for an arg that may or may
> + * not be defined is tricky. Here, if we have "#define CONFIG_BOOGER 1"
> + * we match on the placeholder define, insert the "0," for arg1 and generate
> + * the triplet (0, 1, 0). Then the last step cherry picks the 2nd arg (a one).
> + * When CONFIG_BOOGER is not defined, we generate a (... 1, 0) pair, and when
> + * the last step cherry picks the 2nd arg, we get a zero.
> + */
> +/*
> + * IS_ENABLED(CONFIG_FOO) evaluates to 1 if CONFIG_FOO is set to 'y' or 'm',
> + * 0 otherwise.
> + *
> + */
> +/*
> + * IS_BUILTIN(CONFIG_FOO) evaluates to 1 if CONFIG_FOO is set to 'y', 0
> + * otherwise. For boolean options, this is equivalent to
> + * IS_ENABLED(CONFIG_FOO).
> + */
> +/*
> + * IS_MODULE(CONFIG_FOO) evaluates to 1 if CONFIG_FOO is set to 'm', 0
> + * otherwise.
> + */
> +/*
> + * (C) Copyright 2000-2004
> + * Wolfgang Denk, DENX Software Engineering, wd at 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.
> + *
> + *
> + */
> +/*
> + * Align to a 32 byte boundary equal to the
> + * alignment gcc 4.5 uses for a struct
> + */
> +/* Indirect stringification. Doing two levels allows the parameter to be a
> + * macro itself. For example, compile with -DFOO=bar, __stringify(FOO)
> + * converts to "bar".
> + */
> +/* use 2 ASSERT because ld can not accept '"size" "10"' format */
> +OUTPUT_FORMAT("elf64-littleaarch64", "elf64-littleaarch64", "elf64-littleaarch64")
> +OUTPUT_ARCH(aarch64)
> +ENTRY(start)
> +SECTIONS
> +{
> + . = 0x40000000;
> +
> + . = ALIGN(4);
> + .text :
> + {
> + _stext = .;
> + _text = .;
> + *(.text_entry*)
> + __bare_init_start = .;
> + *(.text_bare_init*)
> + __bare_init_end = .;
> + __exceptions_start = .;
> + KEEP(*(.text_exceptions*))
> + __exceptions_stop = .;
> + *(.text*)
> + }
> + _barebox_bare_init_size = __bare_init_end - _text; ASSERT(_barebox_bare_init_size < 0x01000000, "Barebox bare_init size > ") ASSERT(_barebox_bare_init_size < 0x01000000, "0x01000000")
> + . = ALIGN(4);
> + .rodata : { *(.rodata*) }
> + _etext = .; /* End of text and rodata section */
> + _sdata = .;
> + . = ALIGN(4);
> + .data : { *(.data*) }
> + .barebox_imd : { KEEP(*(.barebox_imd_start)) KEEP(*(.barebox_imd_1*)) *(.barebox_imd_0*) KEEP(*(.barebox_imd_end)) }
> + . = .;
> + __barebox_cmd_start = .;
> + .barebox_cmd : { KEEP(*(SORT_BY_NAME(.barebox_cmd*))) }
> + __barebox_cmd_end = .;
> + __barebox_magicvar_start = .;
> + .barebox_magicvar : { KEEP(*(SORT_BY_NAME(.barebox_magicvar*))) }
> + __barebox_magicvar_end = .;
> + __barebox_initcalls_start = .;
> + .barebox_initcalls : { KEEP(*(.initcall.0)) KEEP(*(.initcall.1)) KEEP(*(.initcall.2)) KEEP(*(.initcall.3)) KEEP(*(.initcall.4)) KEEP(*(.initcall.5)) KEEP(*(.initcall.6)) KEEP(*(.initcall.7)) KEEP(*(.initcall.8)) KEEP(*(.initcall.9)) KEEP(*(.initcall.10)) KEEP(*(.initcall.11)) KEEP(*(.initcall.12)) KEEP(*(.initcall.13)) KEEP(*(.initcall.14)) }
> + __barebox_initcalls_end = .;
> + __barebox_exitcalls_start = .;
> + .barebox_exitcalls : { KEEP(*(.exitcall.0)) KEEP(*(.exitcall.1)) KEEP(*(.exitcall.2)) KEEP(*(.exitcall.3)) KEEP(*(.exitcall.4)) KEEP(*(.exitcall.5)) KEEP(*(.exitcall.6)) }
> + __barebox_exitcalls_end = .;
> + __usymtab_start = .;
> + __usymtab : { KEEP(*(__usymtab)) }
> + __usymtab_end = .;
> + .oftables : { . = ALIGN(8); __clk_of_table_start = .; KEEP(*(.__clk_of_table)); KEEP(*(.__clk_of_table_end)); __clk_of_table_end = .; }
> + .dtb : { . = ALIGN(8); __dtb_start = .; KEEP(*(.dtb.rodata.*)); __dtb_end = .; }
> + .rel.dyn : {
> + __rel_dyn_start = .;
> + *(.rel*)
> + __rel_dyn_end = .;
> + }
> + .dynsym : {
> + __dynsym_start = .;
> + *(.dynsym)
> + __dynsym_end = .;
> + }
> + _edata = .;
> + . = ALIGN(4);
> + __bss_start = .;
> + .bss : { *(.bss*) }
> + __bss_stop = .;
> + _end = .;
> + _barebox_image_size = __bss_start - 0x40000000;
> +}
> diff --git a/arch/arm64/lib/barebox.lds.S b/arch/arm64/lib/barebox.lds.S
> new file mode 100644
> index 0000000..240699f
> --- /dev/null
> +++ b/arch/arm64/lib/barebox.lds.S
> @@ -0,0 +1,125 @@
> +/*
> + * (C) Copyright 2000-2004
> + * Wolfgang Denk, DENX Software Engineering, wd at 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.
> + *
> + *
> + */
> +
> +#include <asm-generic/barebox.lds.h>
> +
> +OUTPUT_FORMAT("elf64-littleaarch64", "elf64-littleaarch64", "elf64-littleaarch64")
> +OUTPUT_ARCH(aarch64)
> +ENTRY(start)
> +SECTIONS
> +{
> +#ifdef CONFIG_RELOCATABLE
> + . = 0x0;
> +#else
> + . = TEXT_BASE;
> +#endif
> +
> +#ifndef CONFIG_PBL_IMAGE
> + PRE_IMAGE
> +#endif
> + . = ALIGN(4);
> + .text :
> + {
> + _stext = .;
> + _text = .;
> + *(.text_entry*)
> + __bare_init_start = .;
> + *(.text_bare_init*)
> + __bare_init_end = .;
> + __exceptions_start = .;
> + KEEP(*(.text_exceptions*))
> + __exceptions_stop = .;
> + *(.text*)
> + }
> + BAREBOX_BARE_INIT_SIZE
> +
> + . = ALIGN(4);
> + .rodata : { *(.rodata*) }
> +
> +#ifdef CONFIG_ARM_UNWIND
> + /*
> + * Stack unwinding tables
> + */
> + . = ALIGN(8);
> + .ARM.unwind_idx : {
> + __start_unwind_idx = .;
> + *(.ARM.exidx*)
> + __stop_unwind_idx = .;
> + }
> + .ARM.unwind_tab : {
> + __start_unwind_tab = .;
> + *(.ARM.extab*)
> + __stop_unwind_tab = .;
> + }
> +#endif
> + _etext = .; /* End of text and rodata section */
> + _sdata = .;
> +
> + . = ALIGN(4);
> + .data : { *(.data*) }
> +
> + .barebox_imd : { BAREBOX_IMD }
> +
> + . = .;
> + __barebox_cmd_start = .;
> + .barebox_cmd : { BAREBOX_CMDS }
> + __barebox_cmd_end = .;
> +
> + __barebox_magicvar_start = .;
> + .barebox_magicvar : { BAREBOX_MAGICVARS }
> + __barebox_magicvar_end = .;
> +
> + __barebox_initcalls_start = .;
> + .barebox_initcalls : { INITCALLS }
> + __barebox_initcalls_end = .;
> +
> + __barebox_exitcalls_start = .;
> + .barebox_exitcalls : { EXITCALLS }
> + __barebox_exitcalls_end = .;
> +
> + __usymtab_start = .;
> + __usymtab : { BAREBOX_SYMS }
> + __usymtab_end = .;
> +
> + .oftables : { BAREBOX_CLK_TABLE() }
> +
> + .dtb : { BAREBOX_DTB() }
> +
> + .rel.dyn : {
> + __rel_dyn_start = .;
> + *(.rel*)
> + __rel_dyn_end = .;
> + }
> +
> + .dynsym : {
> + __dynsym_start = .;
> + *(.dynsym)
> + __dynsym_end = .;
> + }
> +
> + _edata = .;
> +
> + . = ALIGN(4);
> + __bss_start = .;
> + .bss : { *(.bss*) }
> + __bss_stop = .;
> + _end = .;
> + _barebox_image_size = __bss_start - TEXT_BASE;
> +}
> diff --git a/arch/arm64/lib/bootm.c b/arch/arm64/lib/bootm.c
> new file mode 100644
> index 0000000..1913d5f
> --- /dev/null
> +++ b/arch/arm64/lib/bootm.c
> @@ -0,0 +1,572 @@
> +#include <boot.h>
> +#include <common.h>
> +#include <command.h>
> +#include <driver.h>
> +#include <environment.h>
> +#include <image.h>
> +#include <init.h>
> +#include <fs.h>
> +#include <libfile.h>
> +#include <linux/list.h>
> +#include <xfuncs.h>
> +#include <malloc.h>
> +#include <fcntl.h>
> +#include <errno.h>
> +#include <linux/sizes.h>
> +#include <libbb.h>
> +#include <magicvar.h>
> +#include <binfmt.h>
> +#include <restart.h>
> +
> +#include <asm/byteorder.h>
> +#include <asm/setup.h>
> +#include <asm/barebox-arm.h>
> +#include <asm/armlinux.h>
> +#include <asm/system.h>
> +
> +/*
> + * sdram_start_and_size() - determine place for putting the kernel/oftree/initrd
> + *
> + * @start: returns the start address of the first RAM bank
> + * @size: returns the usable space at the beginning of the first RAM bank
> + *
> + * This function returns the base address of the first RAM bank and the free
> + * space found there.
> + *
> + * return: 0 for success, negative error code otherwise
> + */
> +static int sdram_start_and_size(unsigned long *start, unsigned long *size)
> +{
> + struct memory_bank *bank;
> + struct resource *res;
> +
> + /*
> + * We use the first memory bank for the kernel and other resources
> + */
> + bank = list_first_entry_or_null(&memory_banks, struct memory_bank,
> + list);
> + if (!bank) {
> + printf("cannot find first memory bank\n");
> + return -EINVAL;
> + }
> +
> + /*
> + * If the first memory bank has child resources we can use the bank up
> + * to the beginning of the first child resource, otherwise we can use
> + * the whole bank.
> + */
> + res = list_first_entry_or_null(&bank->res->children, struct resource,
> + sibling);
> + if (res)
> + *size = res->start - bank->start;
> + else
> + *size = bank->size;
> +
> + *start = bank->start;
> +
> + return 0;
> +}
> +
> +static int __do_bootm_linux(struct image_data *data, unsigned long free_mem, int swap)
> +{
> + unsigned long kernel;
> + unsigned long initrd_start = 0, initrd_size = 0, initrd_end = 0;
> + int ret;
> +
> + kernel = data->os_res->start + data->os_entry;
> +
> + initrd_start = data->initrd_address;
> +
> + if (initrd_start == UIMAGE_INVALID_ADDRESS) {
> + initrd_start = PAGE_ALIGN(free_mem);
> +
> + if (bootm_verbose(data)) {
> + printf("no initrd load address, defaulting to 0x%08lx\n",
> + initrd_start);
> + }
> + }
> +
> + if (bootm_has_initrd(data)) {
> + ret = bootm_load_initrd(data, initrd_start);
> + if (ret)
> + return ret;
> + }
> +
> + if (data->initrd_res) {
> + initrd_start = data->initrd_res->start;
> + initrd_end = data->initrd_res->end;
> + initrd_size = resource_size(data->initrd_res);
> + free_mem = PAGE_ALIGN(initrd_end);
> + }
> +
> + ret = bootm_load_devicetree(data, free_mem);
> + if (ret)
> + return ret;
> +
> + if (bootm_verbose(data)) {
> + printf("\nStarting kernel at 0x%08lx", kernel);
> + if (initrd_size)
> + printf(", initrd at 0x%08lx", initrd_start);
> + if (data->oftree)
> + printf(", oftree at 0x%p", data->oftree);
> + printf("...\n");
> + }
> +
> + if (data->dryrun)
> + return 0;
> +
> + start_linux((void *)kernel, swap, initrd_start, initrd_size, data->oftree);
> +
> + restart_machine();
> +
> + return -ERESTARTSYS;
> +}
> +
> +static int do_bootm_linux(struct image_data *data)
> +{
> + unsigned long load_address, mem_start, mem_size, mem_free;
> + int ret;
> +
> + ret = sdram_start_and_size(&mem_start, &mem_size);
> + if (ret)
> + return ret;
> +
> + load_address = data->os_address;
> +
> + if (load_address == UIMAGE_INVALID_ADDRESS) {
> + /*
> + * Just use a conservative default of 4 times the size of the
> + * compressed image, to avoid the need for the kernel to
> + * relocate itself before decompression.
> + */
> + load_address = mem_start + PAGE_ALIGN(
> + bootm_get_os_size(data) * 4);
> + if (bootm_verbose(data))
> + printf("no OS load address, defaulting to 0x%08lx\n",
> + load_address);
> + }
> +
> + ret = bootm_load_os(data, load_address);
> + if (ret)
> + return ret;
> +
> + /*
> + * put oftree/initrd close behind compressed kernel image to avoid
> + * placing it outside of the kernels lowmem.
> + */
> + mem_free = PAGE_ALIGN(data->os_res->end + SZ_1M);
> +
> + return __do_bootm_linux(data, mem_free, 0);
> +}
> +
> +static struct image_handler uimage_handler = {
> + .name = "ARM Linux uImage",
> + .bootm = do_bootm_linux,
> + .filetype = filetype_uimage,
> + .ih_os = IH_OS_LINUX,
> +};
> +
> +static struct image_handler rawimage_handler = {
> + .name = "ARM raw image",
> + .bootm = do_bootm_linux,
> + .filetype = filetype_unknown,
> +};
> +
> +struct zimage_header {
> + u32 unused[9];
> + u32 magic;
> + u32 start;
> + u32 end;
> +};
> +
> +#define ZIMAGE_MAGIC 0x016F2818
> +
> +static int do_bootz_linux_fdt(int fd, struct image_data *data)
> +{
> + struct fdt_header __header, *header;
> + void *oftree;
> + int ret;
> +
> + u32 end;
> +
> + if (data->oftree)
> + return -ENXIO;
> +
> + header = &__header;
> + ret = read(fd, header, sizeof(*header));
> + if (ret < sizeof(*header))
> + return ret;
> +
> + if (file_detect_type(header, sizeof(*header)) != filetype_oftree)
> + return -ENXIO;
> +
> + end = be32_to_cpu(header->totalsize);
> +
> + oftree = malloc(end + 0x8000);
> + if (!oftree) {
> + perror("zImage: oftree malloc");
> + return -ENOMEM;
> + }
> +
> + memcpy(oftree, header, sizeof(*header));
> +
> + end -= sizeof(*header);
> +
> + ret = read_full(fd, oftree + sizeof(*header), end);
> + if (ret < 0)
> + goto err_free;
> + if (ret < end) {
> + printf("premature end of image\n");
> + ret = -EIO;
> + goto err_free;
> + }
> +
> + if (IS_BUILTIN(CONFIG_OFTREE)) {
> + data->of_root_node = of_unflatten_dtb(oftree);
> + if (!data->of_root_node) {
> + pr_err("unable to unflatten devicetree\n");
> + ret = -EINVAL;
> + goto err_free;
> + }
> + free(oftree);
> + } else {
> + data->oftree = oftree;
> + }
> +
> + pr_info("zImage: concatenated oftree detected\n");
> +
> + return 0;
> +
> +err_free:
> + free(oftree);
> +
> + return ret;
> +}
> +
> +static int do_bootz_linux(struct image_data *data)
> +{
> + int fd, ret, swap = 0;
> + struct zimage_header __header, *header;
> + void *zimage;
> + u32 end, start;
> + size_t image_size;
> + unsigned long load_address = data->os_address;
> + unsigned long mem_start, mem_size, mem_free;
> +
> + ret = sdram_start_and_size(&mem_start, &mem_size);
> + if (ret)
> + return ret;
> +
> + fd = open(data->os_file, O_RDONLY);
> + if (fd < 0) {
> + perror("open");
> + return 1;
> + }
> +
> + header = &__header;
> + ret = read(fd, header, sizeof(*header));
> + if (ret < sizeof(*header)) {
> + printf("could not read %s\n", data->os_file);
> + goto err_out;
> + }
> +
> + switch (header->magic) {
> + case swab32(ZIMAGE_MAGIC):
> + swap = 1;
> + /* fall through */
> + case ZIMAGE_MAGIC:
> + break;
> + default:
> + printf("invalid magic 0x%08x\n", header->magic);
> + ret = -EINVAL;
> + goto err_out;
> + }
> +
> + end = header->end;
> + start = header->start;
> +
> + if (swap) {
> + end = swab32(end);
> + start = swab32(start);
> + }
> +
> + image_size = end - start;
> +
> + if (load_address == UIMAGE_INVALID_ADDRESS) {
> + /*
> + * Just use a conservative default of 4 times the size of the
> + * compressed image, to avoid the need for the kernel to
> + * relocate itself before decompression.
> + */
> + data->os_address = mem_start + PAGE_ALIGN(image_size * 4);
> +
> + load_address = data->os_address;
> + if (bootm_verbose(data))
> + printf("no OS load address, defaulting to 0x%08lx\n",
> + load_address);
> + }
> +
> + data->os_res = request_sdram_region("zimage", load_address, image_size);
> + if (!data->os_res) {
> + pr_err("bootm/zImage: failed to request memory at 0x%lx to 0x%lx (%d).\n",
> + load_address, load_address + image_size, image_size);
> + ret = -ENOMEM;
> + goto err_out;
> + }
> +
> + zimage = (void *)data->os_res->start;
> +
> + memcpy(zimage, header, sizeof(*header));
> +
> + ret = read_full(fd, zimage + sizeof(*header),
> + image_size - sizeof(*header));
> + if (ret < 0)
> + goto err_out;
> + if (ret < image_size - sizeof(*header)) {
> + printf("premature end of image\n");
> + ret = -EIO;
> + goto err_out;
> + }
> +
> + if (swap) {
> + void *ptr;
> + for (ptr = zimage; ptr < zimage + end; ptr += 4)
> + *(u32 *)ptr = swab32(*(u32 *)ptr);
> + }
> +
> + ret = do_bootz_linux_fdt(fd, data);
> + if (ret && ret != -ENXIO)
> + goto err_out;
> +
> + close(fd);
> +
> + /*
> + * put oftree/initrd close behind compressed kernel image to avoid
> + * placing it outside of the kernels lowmem.
> + */
> + mem_free = PAGE_ALIGN(data->os_res->end + SZ_1M);
> +
> + return __do_bootm_linux(data, mem_free, swap);
> +
> +err_out:
> + close(fd);
> +
> + return ret;
> +}
> +
> +static struct image_handler zimage_handler = {
> + .name = "ARM zImage",
> + .bootm = do_bootz_linux,
> + .filetype = filetype_arm_zimage,
> +};
> +
> +static struct image_handler barebox_handler = {
> + .name = "ARM barebox",
> + .bootm = do_bootm_linux,
> + .filetype = filetype_arm_barebox,
> +};
> +
> +#include <aimage.h>
> +
> +static int aimage_load_resource(int fd, struct resource *r, void* buf, int ps)
> +{
> + int ret;
> + void *image = (void *)r->start;
> + unsigned to_read = ps - resource_size(r) % ps;
> +
> + ret = read_full(fd, image, resource_size(r));
> + if (ret < 0)
> + return ret;
> +
> + ret = read_full(fd, buf, to_read);
> + if (ret < 0)
> + printf("could not read dummy %u\n", to_read);
> +
> + return ret;
> +}
> +
> +static int do_bootm_aimage(struct image_data *data)
> +{
> + struct resource *snd_stage_res;
> + int fd, ret;
> + struct android_header __header, *header;
> + void *buf;
> + int to_read;
> + struct android_header_comp *cmp;
> + unsigned long mem_free;
> + unsigned long mem_start, mem_size;
> +
> + ret = sdram_start_and_size(&mem_start, &mem_size);
> + if (ret)
> + return ret;
> +
> + fd = open(data->os_file, O_RDONLY);
> + if (fd < 0) {
> + perror("open");
> + return 1;
> + }
> +
> + header = &__header;
> + ret = read(fd, header, sizeof(*header));
> + if (ret < sizeof(*header)) {
> + printf("could not read %s\n", data->os_file);
> + goto err_out;
> + }
> +
> + printf("Android Image for '%s'\n", header->name);
> +
> + /*
> + * As on tftp we do not support lseek and we will just have to seek
> + * for the size of a page - 1 max just buffer instead to read to dummy
> + * data
> + */
> + buf = xmalloc(header->page_size);
> +
> + to_read = header->page_size - sizeof(*header);
> + ret = read_full(fd, buf, to_read);
> + if (ret < 0) {
> + printf("could not read dummy %d from %s\n", to_read, data->os_file);
> + goto err_out;
> + }
> +
> + cmp = &header->kernel;
> + data->os_res = request_sdram_region("akernel", cmp->load_addr, cmp->size);
> + if (!data->os_res) {
> + pr_err("Cannot request region 0x%08x - 0x%08x, using default load address\n",
> + cmp->load_addr, cmp->size);
> +
> + data->os_address = mem_start + PAGE_ALIGN(cmp->size * 4);
> + data->os_res = request_sdram_region("akernel", data->os_address, cmp->size);
> + if (!data->os_res) {
> + pr_err("Cannot request region 0x%08x - 0x%08x\n",
> + cmp->load_addr, cmp->size);
> + ret = -ENOMEM;
> + goto err_out;
> + }
> + }
> +
> + ret = aimage_load_resource(fd, data->os_res, buf, header->page_size);
> + if (ret < 0) {
> + perror("could not read kernel");
> + goto err_out;
> + }
> +
> + /*
> + * fastboot always expect a ramdisk
> + * in barebox we can be less restrictive
> + */
> + cmp = &header->ramdisk;
> + if (cmp->size) {
> + data->initrd_res = request_sdram_region("ainitrd", cmp->load_addr, cmp->size);
> + if (!data->initrd_res) {
> + ret = -ENOMEM;
> + goto err_out;
> + }
> +
> + ret = aimage_load_resource(fd, data->initrd_res, buf, header->page_size);
> + if (ret < 0) {
> + perror("could not read initrd");
> + goto err_out;
> + }
> + }
> +
> + if (!getenv("aimage_noverwrite_bootargs"))
> + linux_bootargs_overwrite(header->cmdline);
> +
> + if (!getenv("aimage_noverwrite_tags"))
> + armlinux_set_bootparams((void*)header->tags_addr);
> +
> + cmp = &header->second_stage;
> + if (cmp->size) {
> + void (*second)(void);
> +
> + snd_stage_res = request_sdram_region("asecond", cmp->load_addr, cmp->size);
> + if (!snd_stage_res) {
> + ret = -ENOMEM;
> + goto err_out;
> + }
> +
> + ret = aimage_load_resource(fd, snd_stage_res, buf, header->page_size);
> + if (ret < 0) {
> + perror("could not read initrd");
> + goto err_out;
> + }
> +
> + second = (void*)snd_stage_res->start;
> + shutdown_barebox();
> +
> + second();
> +
> + restart_machine();
> + }
> +
> + close(fd);
> +
> + /*
> + * Put devicetree right after initrd if present or after the kernel
> + * if not.
> + */
> + if (data->initrd_res)
> + mem_free = PAGE_ALIGN(data->initrd_res->end);
> + else
> + mem_free = PAGE_ALIGN(data->os_res->end + SZ_1M);
> +
> + return __do_bootm_linux(data, mem_free, 0);
> +
> +err_out:
> + linux_bootargs_overwrite(NULL);
> + close(fd);
> +
> + return ret;
> +}
> +
> +static struct image_handler aimage_handler = {
> + .name = "ARM Android Image",
> + .bootm = do_bootm_aimage,
> + .filetype = filetype_aimage,
> +};
> +
> +#ifdef CONFIG_CMD_BOOTM_AIMAGE
> +BAREBOX_MAGICVAR(aimage_noverwrite_bootargs, "Disable overwrite of the bootargs with the one present in aimage");
> +BAREBOX_MAGICVAR(aimage_noverwrite_tags, "Disable overwrite of the tags addr with the one present in aimage");
> +#endif
> +
> +static struct image_handler arm_fit_handler = {
> + .name = "FIT image",
> + .bootm = do_bootm_linux,
> + .filetype = filetype_oftree,
> +};
> +
> +static struct binfmt_hook binfmt_aimage_hook = {
> + .type = filetype_aimage,
> + .exec = "bootm",
> +};
> +
> +static struct binfmt_hook binfmt_arm_zimage_hook = {
> + .type = filetype_arm_zimage,
> + .exec = "bootm",
> +};
> +
> +static struct binfmt_hook binfmt_barebox_hook = {
> + .type = filetype_arm_barebox,
> + .exec = "bootm",
> +};
> +
> +static int armlinux_register_image_handler(void)
> +{
> + register_image_handler(&barebox_handler);
> + register_image_handler(&uimage_handler);
> + register_image_handler(&rawimage_handler);
> + register_image_handler(&zimage_handler);
> + if (IS_BUILTIN(CONFIG_CMD_BOOTM_AIMAGE)) {
> + register_image_handler(&aimage_handler);
> + binfmt_register(&binfmt_aimage_hook);
> + }
> + if (IS_BUILTIN(CONFIG_CMD_BOOTM_FITIMAGE))
> + register_image_handler(&arm_fit_handler);
> + binfmt_register(&binfmt_arm_zimage_hook);
> + binfmt_register(&binfmt_barebox_hook);
> +
> + return 0;
> +}
> +late_initcall(armlinux_register_image_handler);
> diff --git a/arch/arm64/lib/bootu.c b/arch/arm64/lib/bootu.c
> new file mode 100644
> index 0000000..19009c8
> --- /dev/null
> +++ b/arch/arm64/lib/bootu.c
> @@ -0,0 +1,44 @@
> +#include <common.h>
> +#include <command.h>
> +#include <fs.h>
> +#include <fcntl.h>
> +#include <errno.h>
> +#include <of.h>
> +#include <asm/armlinux.h>
> +
> +static int do_bootu(int argc, char *argv[])
> +{
> + int fd;
> + void *kernel = NULL;
> + void *oftree = NULL;
> +
> + if (argc != 2)
> + return COMMAND_ERROR_USAGE;
> +
> + fd = open(argv[1], O_RDONLY);
> + if (fd > 0)
> + kernel = (void *)memmap(fd, PROT_READ);
> +
> + if (!kernel)
> + kernel = (void *)simple_strtoul(argv[1], NULL, 0);
> +
> +#ifdef CONFIG_OFTREE
> + oftree = of_get_fixed_tree(NULL);
> +#endif
> +
> + start_linux(kernel, 0, 0, 0, oftree);
> +
> + return 1;
> +}
> +
> +static const __maybe_unused char cmd_bootu_help[] =
> +"Usage: bootu <address>\n";
> +
> +BAREBOX_CMD_START(bootu)
> + .cmd = do_bootu,
> + BAREBOX_CMD_DESC("boot into already loaded Linux kernel")
> + BAREBOX_CMD_OPTS("ADDRESS")
> + BAREBOX_CMD_GROUP(CMD_GRP_BOOT)
> + BAREBOX_CMD_HELP(cmd_bootu_help)
> +BAREBOX_CMD_END
> +
> diff --git a/arch/arm64/lib/bootz.c b/arch/arm64/lib/bootz.c
> new file mode 100644
> index 0000000..5167c9d
> --- /dev/null
> +++ b/arch/arm64/lib/bootz.c
> @@ -0,0 +1,136 @@
> +#include <common.h>
> +#include <command.h>
> +#include <fs.h>
> +#include <of.h>
> +#include <fcntl.h>
> +#include <errno.h>
> +#include <malloc.h>
> +#include <linux/sizes.h>
> +#include <asm/byteorder.h>
> +#include <asm/armlinux.h>
> +#include <asm/system.h>
> +#include <asm-generic/memory_layout.h>
> +#include <memory.h>
> +
> +struct zimage_header {
> + u32 unused[9];
> + u32 magic;
> + u32 start;
> + u32 end;
> +};
> +
> +#define ZIMAGE_MAGIC 0x016F2818
> +
> +static int do_bootz(int argc, char *argv[])
> +{
> + int fd, ret, swap = 0;
> + struct zimage_header __header, *header;
> + void *zimage;
> + void *oftree = NULL;
> + u32 end;
> + int usemap = 0;
> + struct memory_bank *bank = list_first_entry(&memory_banks, struct memory_bank, list);
> + struct resource *res = NULL;
> +
> + if (argc != 2)
> + return COMMAND_ERROR_USAGE;
> +
> + fd = open(argv[1], O_RDONLY);
> + if (fd < 0) {
> + perror("open");
> + return 1;
> + }
> +
> + /*
> + * We can save the memcpy of the zImage if it already is in
> + * the first 128MB of SDRAM.
> + */
> + zimage = memmap(fd, PROT_READ);
> + if (zimage && (unsigned long)zimage >= bank->start &&
> + (unsigned long)zimage < bank->start + SZ_128M) {
> + usemap = 1;
> + header = zimage;
> + }
> +
> + if (!usemap) {
> + header = &__header;
> + ret = read(fd, header, sizeof(*header));
> + if (ret < sizeof(*header)) {
> + printf("could not read %s\n", argv[1]);
> + goto err_out;
> + }
> + }
> +
> + switch (header->magic) {
> +#ifdef CONFIG_BOOT_ENDIANNESS_SWITCH
> + case swab32(ZIMAGE_MAGIC):
> + swap = 1;
> + /* fall through */
> +#endif
> + case ZIMAGE_MAGIC:
> + break;
> + default:
> + printf("invalid magic 0x%08x\n", header->magic);
> + goto err_out;
> + }
> +
> + end = header->end;
> +
> + if (swap)
> + end = swab32(end);
> +
> + if (!usemap) {
> + if (bank->size <= SZ_128M) {
> + zimage = xmalloc(end);
> + } else {
> + zimage = (void *)bank->start + SZ_8M;
> + res = request_sdram_region("zimage",
> + bank->start + SZ_8M, end);
> + if (!res) {
> + printf("can't request region for kernel\n");
> + goto err_out1;
> + }
> + }
> +
> + memcpy(zimage, header, sizeof(*header));
> +
> + ret = read(fd, zimage + sizeof(*header), end - sizeof(*header));
> + if (ret < end - sizeof(*header)) {
> + printf("could not read %s\n", argv[1]);
> + goto err_out2;
> + }
> + }
> +
> + if (swap) {
> + void *ptr;
> + for (ptr = zimage; ptr < zimage + end; ptr += 4)
> + *(u32 *)ptr = swab32(*(u32 *)ptr);
> + }
> +
> + printf("loaded zImage from %s with size %d\n", argv[1], end);
> +#ifdef CONFIG_OFTREE
> + oftree = of_get_fixed_tree(NULL);
> +#endif
> +
> + start_linux(zimage, swap, 0, 0, oftree);
> +
> + return 0;
> +
> +err_out2:
> + if (res)
> + release_sdram_region(res);
> +err_out1:
> + free(zimage);
> +err_out:
> + close(fd);
> +
> + return 1;
> +}
> +
> +BAREBOX_CMD_START(bootz)
> + .cmd = do_bootz,
> + BAREBOX_CMD_DESC("boot Linux zImage")
> + BAREBOX_CMD_OPTS("FILE")
> + BAREBOX_CMD_GROUP(CMD_GRP_BOOT)
> +BAREBOX_CMD_END
> +
> diff --git a/arch/arm64/lib/copy_template.S b/arch/arm64/lib/copy_template.S
> new file mode 100644
> index 0000000..cc9a842
> --- /dev/null
> +++ b/arch/arm64/lib/copy_template.S
> @@ -0,0 +1,192 @@
> +/*
> + * Copyright (C) 2013 ARM Ltd.
> + * Copyright (C) 2013 Linaro.
> + *
> + * This code is based on glibc cortex strings work originally authored by Linaro
> + * and re-licensed under GPLv2 for the Linux kernel. The original code can
> + * be found @
> + *
> + * http://bazaar.launchpad.net/~linaro-toolchain-dev/cortex-strings/trunk/
> + * files/head:/src/aarch64/
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * 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, see <http://www.gnu.org/licenses/>.
> + */
> +
> +
> +/*
> + * Copy a buffer from src to dest (alignment handled by the hardware)
> + *
> + * Parameters:
> + * x0 - dest
> + * x1 - src
> + * x2 - n
> + * Returns:
> + * x0 - dest
> + */
> +dstin .req x0
> +src .req x1
> +count .req x2
> +tmp1 .req x3
> +tmp1w .req w3
> +tmp2 .req x4
> +tmp2w .req w4
> +dst .req x6
> +
> +A_l .req x7
> +A_h .req x8
> +B_l .req x9
> +B_h .req x10
> +C_l .req x11
> +C_h .req x12
> +D_l .req x13
> +D_h .req x14
> +
> + mov dst, dstin
> + cmp count, #16
> + /*When memory length is less than 16, the accessed are not aligned.*/
> + b.lo .Ltiny15
> +
> + neg tmp2, src
> + ands tmp2, tmp2, #15/* Bytes to reach alignment. */
> + b.eq .LSrcAligned
> + sub count, count, tmp2
> + /*
> + * Copy the leading memory data from src to dst in an increasing
> + * address order.By this way,the risk of overwritting the source
> + * memory data is eliminated when the distance between src and
> + * dst is less than 16. The memory accesses here are alignment.
> + */
> + tbz tmp2, #0, 1f
> + ldrb1 tmp1w, src, #1
> + strb1 tmp1w, dst, #1
> +1:
> + tbz tmp2, #1, 2f
> + ldrh1 tmp1w, src, #2
> + strh1 tmp1w, dst, #2
> +2:
> + tbz tmp2, #2, 3f
> + ldr1 tmp1w, src, #4
> + str1 tmp1w, dst, #4
> +3:
> + tbz tmp2, #3, .LSrcAligned
> + ldr1 tmp1, src, #8
> + str1 tmp1, dst, #8
> +
> +.LSrcAligned:
> + cmp count, #64
> + b.ge .Lcpy_over64
> + /*
> + * Deal with small copies quickly by dropping straight into the
> + * exit block.
> + */
> +.Ltail63:
> + /*
> + * Copy up to 48 bytes of data. At this point we only need the
> + * bottom 6 bits of count to be accurate.
> + */
> + ands tmp1, count, #0x30
> + b.eq .Ltiny15
> + cmp tmp1w, #0x20
> + b.eq 1f
> + b.lt 2f
> + ldp1 A_l, A_h, src, #16
> + stp1 A_l, A_h, dst, #16
> +1:
> + ldp1 A_l, A_h, src, #16
> + stp1 A_l, A_h, dst, #16
> +2:
> + ldp1 A_l, A_h, src, #16
> + stp1 A_l, A_h, dst, #16
> +.Ltiny15:
> + /*
> + * Prefer to break one ldp/stp into several load/store to access
> + * memory in an increasing address order,rather than to load/store 16
> + * bytes from (src-16) to (dst-16) and to backward the src to aligned
> + * address,which way is used in original cortex memcpy. If keeping
> + * the original memcpy process here, memmove need to satisfy the
> + * precondition that src address is at least 16 bytes bigger than dst
> + * address,otherwise some source data will be overwritten when memove
> + * call memcpy directly. To make memmove simpler and decouple the
> + * memcpy's dependency on memmove, withdrew the original process.
> + */
> + tbz count, #3, 1f
> + ldr1 tmp1, src, #8
> + str1 tmp1, dst, #8
> +1:
> + tbz count, #2, 2f
> + ldr1 tmp1w, src, #4
> + str1 tmp1w, dst, #4
> +2:
> + tbz count, #1, 3f
> + ldrh1 tmp1w, src, #2
> + strh1 tmp1w, dst, #2
> +3:
> + tbz count, #0, .Lexitfunc
> + ldrb1 tmp1w, src, #1
> + strb1 tmp1w, dst, #1
> +
> + b .Lexitfunc
> +
> +.Lcpy_over64:
> + subs count, count, #128
> + b.ge .Lcpy_body_large
> + /*
> + * Less than 128 bytes to copy, so handle 64 here and then jump
> + * to the tail.
> + */
> + ldp1 A_l, A_h, src, #16
> + stp1 A_l, A_h, dst, #16
> + ldp1 B_l, B_h, src, #16
> + ldp1 C_l, C_h, src, #16
> + stp1 B_l, B_h, dst, #16
> + stp1 C_l, C_h, dst, #16
> + ldp1 D_l, D_h, src, #16
> + stp1 D_l, D_h, dst, #16
> +
> + tst count, #0x3f
> + b.ne .Ltail63
> + b .Lexitfunc
> +
> + /*
> + * Critical loop. Start at a new cache line boundary. Assuming
> + * 64 bytes per line this ensures the entire loop is in one line.
> + */
> +.Lcpy_body_large:
> + /* pre-get 64 bytes data. */
> + ldp1 A_l, A_h, src, #16
> + ldp1 B_l, B_h, src, #16
> + ldp1 C_l, C_h, src, #16
> + ldp1 D_l, D_h, src, #16
> +1:
> + /*
> + * interlace the load of next 64 bytes data block with store of the last
> + * loaded 64 bytes data.
> + */
> + stp1 A_l, A_h, dst, #16
> + ldp1 A_l, A_h, src, #16
> + stp1 B_l, B_h, dst, #16
> + ldp1 B_l, B_h, src, #16
> + stp1 C_l, C_h, dst, #16
> + ldp1 C_l, C_h, src, #16
> + stp1 D_l, D_h, dst, #16
> + ldp1 D_l, D_h, src, #16
> + subs count, count, #64
> + b.ge 1b
> + stp1 A_l, A_h, dst, #16
> + stp1 B_l, B_h, dst, #16
> + stp1 C_l, C_h, dst, #16
> + stp1 D_l, D_h, dst, #16
> +
> + tst count, #0x3f
> + b.ne .Ltail63
> +.Lexitfunc:
> diff --git a/arch/arm64/lib/div0.c b/arch/arm64/lib/div0.c
> new file mode 100644
> index 0000000..852cb72
> --- /dev/null
> +++ b/arch/arm64/lib/div0.c
> @@ -0,0 +1,27 @@
> +/*
> + * (C) Copyright 2002
> + * Wolfgang Denk, DENX Software Engineering, wd at 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.
> + *
> + */
> +#include <common.h>
> +
> +extern void __div0(void);
> +
> +/* Replacement (=dummy) for GNU/Linux division-by zero handler */
> +void __div0 (void)
> +{
> + panic("division by zero\n");
> +}
> diff --git a/arch/arm64/lib/memcpy.S b/arch/arm64/lib/memcpy.S
> new file mode 100644
> index 0000000..cfed319
> --- /dev/null
> +++ b/arch/arm64/lib/memcpy.S
> @@ -0,0 +1,74 @@
> +/*
> + * Copyright (C) 2013 ARM Ltd.
> + * Copyright (C) 2013 Linaro.
> + *
> + * This code is based on glibc cortex strings work originally authored by Linaro
> + * and re-licensed under GPLv2 for the Linux kernel. The original code can
> + * be found @
> + *
> + * http://bazaar.launchpad.net/~linaro-toolchain-dev/cortex-strings/trunk/
> + * files/head:/src/aarch64/
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * 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, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <linux/linkage.h>
> +#include <asm/assembler.h>
> +
> +/*
> + * Copy a buffer from src to dest (alignment handled by the hardware)
> + *
> + * Parameters:
> + * x0 - dest
> + * x1 - src
> + * x2 - n
> + * Returns:
> + * x0 - dest
> + */
> + .macro ldrb1 ptr, regB, val
> + ldrb \ptr, [\regB], \val
> + .endm
> +
> + .macro strb1 ptr, regB, val
> + strb \ptr, [\regB], \val
> + .endm
> +
> + .macro ldrh1 ptr, regB, val
> + ldrh \ptr, [\regB], \val
> + .endm
> +
> + .macro strh1 ptr, regB, val
> + strh \ptr, [\regB], \val
> + .endm
> +
> + .macro ldr1 ptr, regB, val
> + ldr \ptr, [\regB], \val
> + .endm
> +
> + .macro str1 ptr, regB, val
> + str \ptr, [\regB], \val
> + .endm
> +
> + .macro ldp1 ptr, regB, regC, val
> + ldp \ptr, \regB, [\regC], \val
> + .endm
> +
> + .macro stp1 ptr, regB, regC, val
> + stp \ptr, \regB, [\regC], \val
> + .endm
> +
> + .weak memcpy
> +ENTRY(memcpy)
> +#include "copy_template.S"
> + ret
> +ENDPROC(memcpy)
> diff --git a/arch/arm64/lib/memset.S b/arch/arm64/lib/memset.S
> new file mode 100644
> index 0000000..380a540
> --- /dev/null
> +++ b/arch/arm64/lib/memset.S
> @@ -0,0 +1,215 @@
> +/*
> + * Copyright (C) 2013 ARM Ltd.
> + * Copyright (C) 2013 Linaro.
> + *
> + * This code is based on glibc cortex strings work originally authored by Linaro
> + * and re-licensed under GPLv2 for the Linux kernel. The original code can
> + * be found @
> + *
> + * http://bazaar.launchpad.net/~linaro-toolchain-dev/cortex-strings/trunk/
> + * files/head:/src/aarch64/
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * 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, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <linux/linkage.h>
> +#include <asm/assembler.h>
> +
> +/*
> + * Fill in the buffer with character c (alignment handled by the hardware)
> + *
> + * Parameters:
> + * x0 - buf
> + * x1 - c
> + * x2 - n
> + * Returns:
> + * x0 - buf
> + */
> +
> +dstin .req x0
> +val .req w1
> +count .req x2
> +tmp1 .req x3
> +tmp1w .req w3
> +tmp2 .req x4
> +tmp2w .req w4
> +zva_len_x .req x5
> +zva_len .req w5
> +zva_bits_x .req x6
> +
> +A_l .req x7
> +A_lw .req w7
> +dst .req x8
> +tmp3w .req w9
> +tmp3 .req x9
> +
> + .weak memset
> +ENTRY(memset)
> + mov dst, dstin /* Preserve return value. */
> + and A_lw, val, #255
> + orr A_lw, A_lw, A_lw, lsl #8
> + orr A_lw, A_lw, A_lw, lsl #16
> + orr A_l, A_l, A_l, lsl #32
> +
> + cmp count, #15
> + b.hi .Lover16_proc
> + /*All store maybe are non-aligned..*/
> + tbz count, #3, 1f
> + str A_l, [dst], #8
> +1:
> + tbz count, #2, 2f
> + str A_lw, [dst], #4
> +2:
> + tbz count, #1, 3f
> + strh A_lw, [dst], #2
> +3:
> + tbz count, #0, 4f
> + strb A_lw, [dst]
> +4:
> + ret
> +
> +.Lover16_proc:
> + /*Whether the start address is aligned with 16.*/
> + neg tmp2, dst
> + ands tmp2, tmp2, #15
> + b.eq .Laligned
> +/*
> +* The count is not less than 16, we can use stp to store the start 16 bytes,
> +* then adjust the dst aligned with 16.This process will make the current
> +* memory address at alignment boundary.
> +*/
> + stp A_l, A_l, [dst] /*non-aligned store..*/
> + /*make the dst aligned..*/
> + sub count, count, tmp2
> + add dst, dst, tmp2
> +
> +.Laligned:
> + cbz A_l, .Lzero_mem
> +
> +.Ltail_maybe_long:
> + cmp count, #64
> + b.ge .Lnot_short
> +.Ltail63:
> + ands tmp1, count, #0x30
> + b.eq 3f
> + cmp tmp1w, #0x20
> + b.eq 1f
> + b.lt 2f
> + stp A_l, A_l, [dst], #16
> +1:
> + stp A_l, A_l, [dst], #16
> +2:
> + stp A_l, A_l, [dst], #16
> +/*
> +* The last store length is less than 16,use stp to write last 16 bytes.
> +* It will lead some bytes written twice and the access is non-aligned.
> +*/
> +3:
> + ands count, count, #15
> + cbz count, 4f
> + add dst, dst, count
> + stp A_l, A_l, [dst, #-16] /* Repeat some/all of last store. */
> +4:
> + ret
> +
> + /*
> + * Critical loop. Start at a new cache line boundary. Assuming
> + * 64 bytes per line, this ensures the entire loop is in one line.
> + */
> +.Lnot_short:
> + sub dst, dst, #16/* Pre-bias. */
> + sub count, count, #64
> +1:
> + stp A_l, A_l, [dst, #16]
> + stp A_l, A_l, [dst, #32]
> + stp A_l, A_l, [dst, #48]
> + stp A_l, A_l, [dst, #64]!
> + subs count, count, #64
> + b.ge 1b
> + tst count, #0x3f
> + add dst, dst, #16
> + b.ne .Ltail63
> +.Lexitfunc:
> + ret
> +
> + /*
> + * For zeroing memory, check to see if we can use the ZVA feature to
> + * zero entire 'cache' lines.
> + */
> +.Lzero_mem:
> + cmp count, #63
> + b.le .Ltail63
> + /*
> + * For zeroing small amounts of memory, it's not worth setting up
> + * the line-clear code.
> + */
> + cmp count, #128
> + b.lt .Lnot_short /*count is at least 128 bytes*/
> +
> + mrs tmp1, dczid_el0
> + tbnz tmp1, #4, .Lnot_short
> + mov tmp3w, #4
> + and zva_len, tmp1w, #15 /* Safety: other bits reserved. */
> + lsl zva_len, tmp3w, zva_len
> +
> + ands tmp3w, zva_len, #63
> + /*
> + * ensure the zva_len is not less than 64.
> + * It is not meaningful to use ZVA if the block size is less than 64.
> + */
> + b.ne .Lnot_short
> +.Lzero_by_line:
> + /*
> + * Compute how far we need to go to become suitably aligned. We're
> + * already at quad-word alignment.
> + */
> + cmp count, zva_len_x
> + b.lt .Lnot_short /* Not enough to reach alignment. */
> + sub zva_bits_x, zva_len_x, #1
> + neg tmp2, dst
> + ands tmp2, tmp2, zva_bits_x
> + b.eq 2f /* Already aligned. */
> + /* Not aligned, check that there's enough to copy after alignment.*/
> + sub tmp1, count, tmp2
> + /*
> + * grantee the remain length to be ZVA is bigger than 64,
> + * avoid to make the 2f's process over mem range.*/
> + cmp tmp1, #64
> + ccmp tmp1, zva_len_x, #8, ge /* NZCV=0b1000 */
> + b.lt .Lnot_short
> + /*
> + * We know that there's at least 64 bytes to zero and that it's safe
> + * to overrun by 64 bytes.
> + */
> + mov count, tmp1
> +1:
> + stp A_l, A_l, [dst]
> + stp A_l, A_l, [dst, #16]
> + stp A_l, A_l, [dst, #32]
> + subs tmp2, tmp2, #64
> + stp A_l, A_l, [dst, #48]
> + add dst, dst, #64
> + b.ge 1b
> + /* We've overrun a bit, so adjust dst downwards.*/
> + add dst, dst, tmp2
> +2:
> + sub count, count, zva_len_x
> +3:
> + dc zva, dst
> + add dst, dst, zva_len_x
> + subs count, count, zva_len_x
> + b.ge 3b
> + ands count, count, zva_bits_x
> + b.ne .Ltail_maybe_long
> + ret
> +ENDPROC(memset)
> diff --git a/arch/arm64/lib/module.c b/arch/arm64/lib/module.c
> new file mode 100644
> index 0000000..be7965d
> --- /dev/null
> +++ b/arch/arm64/lib/module.c
> @@ -0,0 +1,98 @@
> +/*
> + * linux/arch/arm/kernel/module.c
> + *
> + * Copyright (C) 2002 Russell King.
> + * Modified for nommu by Hyok S. Choi
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * Module allocation method suggested by Andi Kleen.
> + */
> +
> +//#include <asm/pgtable.h>
> +#include <common.h>
> +#include <elf.h>
> +#include <module.h>
> +#include <errno.h>
> +
> +int
> +apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex,
> + unsigned int relindex, struct module *module)
> +{
> + Elf32_Shdr *symsec = sechdrs + symindex;
> + Elf32_Shdr *relsec = sechdrs + relindex;
> + Elf32_Shdr *dstsec = sechdrs + relsec->sh_info;
> + Elf32_Rel *rel = (void *)relsec->sh_addr;
> + unsigned int i;
> +
> + for (i = 0; i < relsec->sh_size / sizeof(Elf32_Rel); i++, rel++) {
> + unsigned long loc;
> + Elf32_Sym *sym;
> + s32 offset;
> +
> + offset = ELF32_R_SYM(rel->r_info);
> + if (offset < 0 || offset > (symsec->sh_size / sizeof(Elf32_Sym))) {
> + printf("%s: bad relocation, section %u reloc %u\n",
> + module->name, relindex, i);
> + return -ENOEXEC;
> + }
> +
> + sym = ((Elf32_Sym *)symsec->sh_addr) + offset;
> +
> + if (rel->r_offset < 0 || rel->r_offset > dstsec->sh_size - sizeof(u32)) {
> + printf("%s: out of bounds relocation, "
> + "section %u reloc %u offset %d size %d\n",
> + module->name, relindex, i, rel->r_offset,
> + dstsec->sh_size);
> + return -ENOEXEC;
> + }
> +
> + loc = dstsec->sh_addr + rel->r_offset;
> +
> + switch (ELF32_R_TYPE(rel->r_info)) {
> + case R_ARM_ABS32:
> + *(u32 *)loc += sym->st_value;
> + break;
> +
> + case R_ARM_PC24:
> + case R_ARM_CALL:
> + case R_ARM_JUMP24:
> + offset = (*(u32 *)loc & 0x00ffffff) << 2;
> + if (offset & 0x02000000)
> + offset -= 0x04000000;
> +
> + offset += sym->st_value - loc;
> + if (offset & 3 ||
> + offset <= (s32)0xfe000000 ||
> + offset >= (s32)0x02000000) {
> + printf("%s: relocation out of range, section "
> + "%u reloc %u sym '%s'\n", module->name,
> + relindex, i, strtab + sym->st_name);
> + return -ENOEXEC;
> + }
> +
> + offset >>= 2;
> +
> + *(u32 *)loc &= 0xff000000;
> + *(u32 *)loc |= offset & 0x00ffffff;
> + break;
> +
> + default:
> + printf("%s: unknown relocation: %u\n",
> + module->name, ELF32_R_TYPE(rel->r_info));
> + return -ENOEXEC;
> + }
> + }
> + return 0;
> +}
> +
> +int
> +apply_relocate_add(Elf32_Shdr *sechdrs, const char *strtab,
> + unsigned int symindex, unsigned int relsec, struct module *module)
> +{
> + printf("module %s: ADD RELOCATION unsupported\n",
> + module->name);
> + return -ENOEXEC;
> +}
> diff --git a/arch/arm64/lib/pbl.lds.S b/arch/arm64/lib/pbl.lds.S
> new file mode 100644
> index 0000000..73baff0
> --- /dev/null
> +++ b/arch/arm64/lib/pbl.lds.S
> @@ -0,0 +1,96 @@
> +/*
> + * (C) Copyright 2012 Sascha Hauer <s.hauer at pengutronix.de>, Pengutronix
> + *
> + * 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.
> + *
> + */
> +#include <linux/sizes.h>
> +#include <asm-generic/barebox.lds.h>
> +#include <asm-generic/memory_layout.h>
> +
> +#ifdef CONFIG_PBL_RELOCATABLE
> +#define BASE 0x0
> +#else
> +#define BASE (TEXT_BASE - SZ_2M)
> +#endif
> +
> +OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
> +OUTPUT_ARCH(arm)
> +SECTIONS
> +{
> + . = BASE;
> +
> + PRE_IMAGE
> +
> + . = ALIGN(4);
> + .text :
> + {
> + _stext = .;
> + _text = .;
> + *(.text_head_entry*)
> + __bare_init_start = .;
> + *(.text_bare_init*)
> + __bare_init_end = .;
> + *(.text*)
> + }
> +
> + /* Discard unwind if enable in barebox */
> + /DISCARD/ : { *(.ARM.ex*) }
> +
> + BAREBOX_BARE_INIT_SIZE
> + BAREBOX_PBL_SIZE
> +
> + . = ALIGN(4);
> + .rodata : { *(.rodata*) }
> +
> + .barebox_imd : { BAREBOX_IMD }
> +
> + _etext = .; /* End of text and rodata section */
> +
> + . = ALIGN(4);
> + .data : { *(.data*) }
> +
> + .rel.dyn : {
> + __rel_dyn_start = .;
> + *(.rel*)
> + __rel_dyn_end = .;
> + }
> +
> + .dynsym : {
> + __dynsym_start = .;
> + *(.dynsym)
> + __dynsym_end = .;
> + }
> +
> + . = ALIGN(4);
> + __bss_start = .;
> + .bss : { *(.bss*) }
> + __bss_stop = .;
> + _end = .;
> +
> + . = ALIGN(4);
> + __piggydata_start = .;
> + .piggydata : {
> + *(.piggydata)
> + }
> + __piggydata_end = .;
> +
> + . = ALIGN(4);
> + .image_end : {
> + KEEP(*(.image_end))
> + }
> + __image_end = .;
> + _barebox_image_size = __image_end - BASE;
> + _barebox_pbl_size = __bss_start - BASE;
> +}
> diff --git a/arch/arm64/lib/runtime-offset.S b/arch/arm64/lib/runtime-offset.S
> new file mode 100644
> index 0000000..e368baa
> --- /dev/null
> +++ b/arch/arm64/lib/runtime-offset.S
> @@ -0,0 +1,52 @@
> +#include <linux/linkage.h>
> +#include <asm/assembler.h>
> +
> +.section ".text_bare_init","ax"
> +
> +/*
> + * Get the offset between the link address and the address
> + * we are currently running at.
> + */
> +ENTRY(get_runtime_offset)
> +1: adr x0, 1b
> + adr x1, get_runtime_offset
> + subs x0, x1, x0
> + subs x0, x0, #1
> + ret
> +
> +linkadr:
> +.word get_runtime_offset
> +ENDPROC(get_runtime_offset)
> +
> +.globl __ld_var_base
> +__ld_var_base:
> +
> +/*
> + * Functions to calculate selected linker supplied variables during runtime.
> + * This is needed for relocatable binaries when the linker variables are
> + * needed before finxing up the relocations.
> + */
> +.macro ld_var_entry name
> + ENTRY(__ld_var_\name)
> + ldr x0, __\name
> + b 1f
> + __\name: .word \name - __ld_var_base
> + ENDPROC(__ld_var_\name)
> +.endm
> +
> +ld_var_entry _text
> +ld_var_entry __rel_dyn_start
> +ld_var_entry __rel_dyn_end
> +ld_var_entry __dynsym_start
> +ld_var_entry __dynsym_end
> +ld_var_entry _barebox_image_size
> +ld_var_entry __bss_start
> +ld_var_entry __bss_stop
> +#ifdef __PBL__
> +ld_var_entry __image_end
> +#endif
> +
> +1:
> + ldr x1, =__ld_var_base
> + adds x0, x0, x1
> + ret
> diff --git a/arch/arm64/lib/unwind.c b/arch/arm64/lib/unwind.c
> new file mode 100644
> index 0000000..c3dca5b
> --- /dev/null
> +++ b/arch/arm64/lib/unwind.c
> @@ -0,0 +1,349 @@
> +#include <common.h>
> +#include <init.h>
> +#include <asm/stacktrace.h>
> +#include <asm/unwind.h>
> +#include <asm/sections.h>
> +
> +/* Dummy functions to avoid linker complaints */
> +void __aeabi_unwind_cpp_pr0(void)
> +{
> +};
> +EXPORT_SYMBOL(__aeabi_unwind_cpp_pr0);
> +
> +void __aeabi_unwind_cpp_pr1(void)
> +{
> +};
> +EXPORT_SYMBOL(__aeabi_unwind_cpp_pr1);
> +
> +void __aeabi_unwind_cpp_pr2(void)
> +{
> +};
> +EXPORT_SYMBOL(__aeabi_unwind_cpp_pr2);
> +
> +struct unwind_ctrl_block {
> + unsigned long vrs[16]; /* virtual register set */
> + unsigned long *insn; /* pointer to the current instructions word */
> + int entries; /* number of entries left to interpret */
> + int byte; /* current byte number in the instructions word */
> +};
> +
> +enum regs {
> + FP = 11,
> + SP = 13,
> + LR = 14,
> + PC = 15
> +};
> +
> +#define THREAD_SIZE 8192
> +
> +extern struct unwind_idx __start_unwind_idx[];
> +extern struct unwind_idx __stop_unwind_idx[];
> +
> +/* Convert a prel31 symbol to an absolute address */
> +#define prel31_to_addr(ptr) \
> +({ \
> + /* sign-extend to 32 bits */ \
> + long offset = (((long)*(ptr)) << 1) >> 1; \
> + (unsigned long)(ptr) + offset; \
> +})
> +
> +static inline int is_kernel_text(unsigned long addr)
> +{
> + if ((addr >= (unsigned long)_stext && addr <= (unsigned long)_etext))
> + return 1;
> + return 0;
> +}
> +
> +void dump_backtrace_entry(unsigned long where, unsigned long from, unsigned long frame)
> +{
> +#ifdef CONFIG_KALLSYMS
> + printk("[<%08lx>] (%pS) from [<%08lx>] (%pS)\n", where, (void *)where, from, (void *)from);
> +#else
> + printk("Function entered at [<%08lx>] from [<%08lx>]\n", where, from);
> +#endif
> +}
> +
> +/*
> + * Binary search in the unwind index. The entries entries are
> + * guaranteed to be sorted in ascending order by the linker.
> + */
> +static struct unwind_idx *search_index(unsigned long addr,
> + struct unwind_idx *first,
> + struct unwind_idx *last)
> +{
> + pr_debug("%s(%08lx, %p, %p)\n", __func__, addr, first, last);
> +
> + if (addr < first->addr) {
> + pr_warning("unwind: Unknown symbol address %08lx\n", addr);
> + return NULL;
> + } else if (addr >= last->addr)
> + return last;
> +
> + while (first < last - 1) {
> + struct unwind_idx *mid = first + ((last - first + 1) >> 1);
> +
> + if (addr < mid->addr)
> + last = mid;
> + else
> + first = mid;
> + }
> +
> + return first;
> +}
> +
> +static struct unwind_idx *unwind_find_idx(unsigned long addr)
> +{
> + struct unwind_idx *idx = NULL;
> +
> + pr_debug("%s(%08lx)\n", __func__, addr);
> +
> + if (is_kernel_text(addr))
> + /* main unwind table */
> + idx = search_index(addr, __start_unwind_idx,
> + __stop_unwind_idx - 1);
> + else {
> + /* module unwinding not supported */
> + }
> +
> + pr_debug("%s: idx = %p\n", __func__, idx);
> + return idx;
> +}
> +
> +static unsigned long unwind_get_byte(struct unwind_ctrl_block *ctrl)
> +{
> + unsigned long ret;
> +
> + if (ctrl->entries <= 0) {
> + pr_warning("unwind: Corrupt unwind table\n");
> + return 0;
> + }
> +
> + ret = (*ctrl->insn >> (ctrl->byte * 8)) & 0xff;
> +
> + if (ctrl->byte == 0) {
> + ctrl->insn++;
> + ctrl->entries--;
> + ctrl->byte = 3;
> + } else
> + ctrl->byte--;
> +
> + return ret;
> +}
> +
> +/*
> + * Execute the current unwind instruction.
> + */
> +static int unwind_exec_insn(struct unwind_ctrl_block *ctrl)
> +{
> + unsigned long insn = unwind_get_byte(ctrl);
> +
> + pr_debug("%s: insn = %08lx\n", __func__, insn);
> +
> + if ((insn & 0xc0) == 0x00)
> + ctrl->vrs[SP] += ((insn & 0x3f) << 2) + 4;
> + else if ((insn & 0xc0) == 0x40)
> + ctrl->vrs[SP] -= ((insn & 0x3f) << 2) + 4;
> + else if ((insn & 0xf0) == 0x80) {
> + unsigned long mask;
> + unsigned long *vsp = (unsigned long *)ctrl->vrs[SP];
> + int load_sp, reg = 4;
> +
> + insn = (insn << 8) | unwind_get_byte(ctrl);
> + mask = insn & 0x0fff;
> + if (mask == 0) {
> + pr_warning("unwind: 'Refuse to unwind' instruction %04lx\n",
> + insn);
> + return -URC_FAILURE;
> + }
> +
> + /* pop R4-R15 according to mask */
> + load_sp = mask & (1 << (13 - 4));
> + while (mask) {
> + if (mask & 1)
> + ctrl->vrs[reg] = *vsp++;
> + mask >>= 1;
> + reg++;
> + }
> + if (!load_sp)
> + ctrl->vrs[SP] = (unsigned long)vsp;
> + } else if ((insn & 0xf0) == 0x90 &&
> + (insn & 0x0d) != 0x0d)
> + ctrl->vrs[SP] = ctrl->vrs[insn & 0x0f];
> + else if ((insn & 0xf0) == 0xa0) {
> + unsigned long *vsp = (unsigned long *)ctrl->vrs[SP];
> + int reg;
> +
> + /* pop R4-R[4+bbb] */
> + for (reg = 4; reg <= 4 + (insn & 7); reg++)
> + ctrl->vrs[reg] = *vsp++;
> + if (insn & 0x80)
> + ctrl->vrs[14] = *vsp++;
> + ctrl->vrs[SP] = (unsigned long)vsp;
> + } else if (insn == 0xb0) {
> + if (ctrl->vrs[PC] == 0)
> + ctrl->vrs[PC] = ctrl->vrs[LR];
> + /* no further processing */
> + ctrl->entries = 0;
> + } else if (insn == 0xb1) {
> + unsigned long mask = unwind_get_byte(ctrl);
> + unsigned long *vsp = (unsigned long *)ctrl->vrs[SP];
> + int reg = 0;
> +
> + if (mask == 0 || mask & 0xf0) {
> + pr_warning("unwind: Spare encoding %04lx\n",
> + (insn << 8) | mask);
> + return -URC_FAILURE;
> + }
> +
> + /* pop R0-R3 according to mask */
> + while (mask) {
> + if (mask & 1)
> + ctrl->vrs[reg] = *vsp++;
> + mask >>= 1;
> + reg++;
> + }
> + ctrl->vrs[SP] = (unsigned long)vsp;
> + } else if (insn == 0xb2) {
> + unsigned long uleb128 = unwind_get_byte(ctrl);
> +
> + ctrl->vrs[SP] += 0x204 + (uleb128 << 2);
> + } else {
> + pr_warning("unwind: Unhandled instruction %02lx\n", insn);
> + return -URC_FAILURE;
> + }
> +
> + pr_debug("%s: fp = %08lx sp = %08lx lr = %08lx pc = %08lx\n", __func__,
> + ctrl->vrs[FP], ctrl->vrs[SP], ctrl->vrs[LR], ctrl->vrs[PC]);
> +
> + return URC_OK;
> +}
> +
> +/*
> + * Unwind a single frame starting with *sp for the symbol at *pc. It
> + * updates the *pc and *sp with the new values.
> + */
> +int unwind_frame(struct stackframe *frame)
> +{
> + unsigned long high, low;
> + struct unwind_idx *idx;
> + struct unwind_ctrl_block ctrl;
> +
> + /* only go to a higher address on the stack */
> + low = frame->sp;
> + high = ALIGN(low, THREAD_SIZE);
> +
> + pr_debug("%s(pc = %08lx lr = %08lx sp = %08lx)\n", __func__,
> + frame->pc, frame->lr, frame->sp);
> +
> + if (!is_kernel_text(frame->pc))
> + return -URC_FAILURE;
> +
> + idx = unwind_find_idx(frame->pc);
> + if (!idx) {
> + pr_warning("unwind: Index not found %08lx\n", frame->pc);
> + return -URC_FAILURE;
> + }
> +
> + ctrl.vrs[FP] = frame->fp;
> + ctrl.vrs[SP] = frame->sp;
> + ctrl.vrs[LR] = frame->lr;
> + ctrl.vrs[PC] = 0;
> +
> + if (idx->insn == 1)
> + /* can't unwind */
> + return -URC_FAILURE;
> + else if ((idx->insn & 0x80000000) == 0)
> + /* prel31 to the unwind table */
> + ctrl.insn = (unsigned long *)prel31_to_addr(&idx->insn);
> + else if ((idx->insn & 0xff000000) == 0x80000000)
> + /* only personality routine 0 supported in the index */
> + ctrl.insn = &idx->insn;
> + else {
> + pr_warning("unwind: Unsupported personality routine %08lx in the index at %p\n",
> + idx->insn, idx);
> + return -URC_FAILURE;
> + }
> +
> + /* check the personality routine */
> + if ((*ctrl.insn & 0xff000000) == 0x80000000) {
> + ctrl.byte = 2;
> + ctrl.entries = 1;
> + } else if ((*ctrl.insn & 0xff000000) == 0x81000000) {
> + ctrl.byte = 1;
> + ctrl.entries = 1 + ((*ctrl.insn & 0x00ff0000) >> 16);
> + } else {
> + pr_warning("unwind: Unsupported personality routine %08lx at %p\n",
> + *ctrl.insn, ctrl.insn);
> + return -URC_FAILURE;
> + }
> +
> + while (ctrl.entries > 0) {
> + int urc = unwind_exec_insn(&ctrl);
> + if (urc < 0)
> + return urc;
> + if (ctrl.vrs[SP] < low || ctrl.vrs[SP] >= high)
> + return -URC_FAILURE;
> + }
> +
> + if (ctrl.vrs[PC] == 0)
> + ctrl.vrs[PC] = ctrl.vrs[LR];
> +
> + /* check for infinite loop */
> + if (frame->pc == ctrl.vrs[PC])
> + return -URC_FAILURE;
> +
> + frame->fp = ctrl.vrs[FP];
> + frame->sp = ctrl.vrs[SP];
> + frame->lr = ctrl.vrs[LR];
> + frame->pc = ctrl.vrs[PC];
> +
> + return URC_OK;
> +}
> +
> +void unwind_backtrace(struct pt_regs *regs)
> +{
> + struct stackframe frame;
> + register unsigned long current_sp asm ("sp");
> +
> + pr_debug("%s\n", __func__);
> +
> + if (regs) {
> + frame.fp = regs->ARM_fp;
> + frame.sp = regs->ARM_sp;
> + frame.lr = regs->ARM_lr;
> + /* PC might be corrupted, use LR in that case. */
> + frame.pc = is_kernel_text(regs->ARM_pc)
> + ? regs->ARM_pc : regs->ARM_lr;
> + } else {
> + frame.sp = current_sp;
> + frame.lr = (unsigned long)__builtin_return_address(0);
> + frame.pc = (unsigned long)unwind_backtrace;
> + }
> +
> + while (1) {
> + int urc;
> + unsigned long where = frame.pc;
> +
> + urc = unwind_frame(&frame);
> + if (urc < 0)
> + break;
> + dump_backtrace_entry(where, frame.pc, frame.sp - 4);
> + }
> +}
> +
> +void dump_stack(void)
> +{
> + unwind_backtrace(NULL);
> +}
> +
> +static int unwind_init(void)
> +{
> + struct unwind_idx *idx;
> +
> + /* Convert the symbol addresses to absolute values */
> + for (idx = __start_unwind_idx; idx < __stop_unwind_idx; idx++)
> + idx->addr = prel31_to_addr(&idx->addr);
> +
> + return 0;
> +}
> +core_initcall(unwind_init);
> diff --git a/arch/arm64/mach-virt/Kconfig b/arch/arm64/mach-virt/Kconfig
> new file mode 100644
> index 0000000..1f43606
> --- /dev/null
> +++ b/arch/arm64/mach-virt/Kconfig
> @@ -0,0 +1,15 @@
> +if ARCH_VIRT
> +
> +config ARCH_TEXT_BASE
> + hex
> + default 0x40000000
> +
> +choice
> + prompt "ARM Board type"
> +
> +config MACH_VIRT
> + bool "ARM QEMU virt"
> +
> +endchoice
> +
> +endif
> diff --git a/arch/arm64/mach-virt/Makefile b/arch/arm64/mach-virt/Makefile
> new file mode 100644
> index 0000000..5662311
> --- /dev/null
> +++ b/arch/arm64/mach-virt/Makefile
> @@ -0,0 +1 @@
> +obj-y += devices.o reset.o
> diff --git a/arch/arm64/mach-virt/devices.c b/arch/arm64/mach-virt/devices.c
> new file mode 100644
> index 0000000..391f4bf
> --- /dev/null
> +++ b/arch/arm64/mach-virt/devices.c
> @@ -0,0 +1,30 @@
> +/*
> + * Copyright (C) 2016 Raphaël Poggi <poggi.raph at gmail.com>
> + *
> + * GPLv2 only
> + */
> +
> +#include <common.h>
> +#include <linux/amba/bus.h>
> +#include <asm/memory.h>
> +#include <mach/devices.h>
> +#include <linux/ioport.h>
> +
> +void virt_add_ddram(u32 size)
> +{
> + arm_add_mem_device("ram0", 0x50000000, size);
> +}
> +
> +void virt_register_uart(unsigned id)
> +{
> + resource_size_t start;
> +
> + switch (id) {
> + case 0:
> + start = 0x09000000;
> + break;
> + default:
> + return;
> + }
> + amba_apb_device_add(NULL, "uart-pl011", id, start, 4096, NULL, 0);
> +}
> diff --git a/arch/arm64/mach-virt/include/mach/debug_ll.h b/arch/arm64/mach-virt/include/mach/debug_ll.h
> new file mode 100644
> index 0000000..89b0692
> --- /dev/null
> +++ b/arch/arm64/mach-virt/include/mach/debug_ll.h
> @@ -0,0 +1,24 @@
> +/*
> + * Copyright 2013 Jean-Christophe PLAGNIOL-VILLARD <plagniol at jcrosoft.com>
> + *
> + * GPLv2 only
> + */
> +
> +#ifndef __MACH_DEBUG_LL_H__
> +#define __MACH_DEBUG_LL_H__
> +
> +#include <linux/amba/serial.h>
> +#include <io.h>
> +
> +#define DEBUG_LL_PHYS_BASE 0x10000000
> +#define DEBUG_LL_PHYS_BASE_RS1 0x1c000000
> +
> +#ifdef MP
> +#define DEBUG_LL_UART_ADDR DEBUG_LL_PHYS_BASE
> +#else
> +#define DEBUG_LL_UART_ADDR DEBUG_LL_PHYS_BASE_RS1
> +#endif
> +
> +#include <asm/debug_ll_pl011.h>
> +
> +#endif
> diff --git a/arch/arm64/mach-virt/include/mach/devices.h b/arch/arm64/mach-virt/include/mach/devices.h
> new file mode 100644
> index 0000000..9872c61
> --- /dev/null
> +++ b/arch/arm64/mach-virt/include/mach/devices.h
> @@ -0,0 +1,13 @@
> +/*
> + * Copyright (C) 2016 Raphaël Poggi <poggi.raph at gmail.com>
> + *
> + * GPLv2 only
> + */
> +
> +#ifndef __ASM_ARCH_DEVICES_H__
> +#define __ASM_ARCH_DEVICES_H__
> +
> +void virt_add_ddram(u32 size);
> +void virt_register_uart(unsigned id);
> +
> +#endif /* __ASM_ARCH_DEVICES_H__ */
> diff --git a/arch/arm64/mach-virt/reset.c b/arch/arm64/mach-virt/reset.c
> new file mode 100644
> index 0000000..fb895eb
> --- /dev/null
> +++ b/arch/arm64/mach-virt/reset.c
> @@ -0,0 +1,24 @@
> +/*
> + * Copyright (C) 2016 Raphaël Poggi <poggi.raph at gmail.com>
> + *
> + * GPLv2 only
> + */
> +
> +#include <common.h>
> +#include <io.h>
> +#include <init.h>
> +#include <restart.h>
> +#include <mach/devices.h>
> +
> +static void virt_reset_soc(struct restart_handler *rst)
> +{
> + hang();
> +}
> +
> +static int restart_register_feature(void)
> +{
> + restart_handler_register_fn(virt_reset_soc);
> +
> + return 0;
> +}
> +coredevice_initcall(restart_register_feature);
> diff --git a/arch/arm64/pbl/Makefile b/arch/arm64/pbl/Makefile
> new file mode 100644
> index 0000000..1ff39db
> --- /dev/null
> +++ b/arch/arm64/pbl/Makefile
> @@ -0,0 +1,58 @@
> +
> +suffix_$(CONFIG_IMAGE_COMPRESSION_GZIP) = gzip
> +suffix_$(CONFIG_IMAGE_COMPRESSION_LZO) = lzo
> +suffix_$(CONFIG_IMAGE_COMPRESSION_LZ4) = lz4
> +suffix_$(CONFIG_IMAGE_COMPRESSION_XZKERN) = xzkern
> +suffix_$(CONFIG_IMAGE_COMPRESSION_NONE) = shipped
> +
> +OBJCOPYFLAGS_zbarebox.bin = -O binary
> +piggy_o := piggy.$(suffix_y).o
> +
> +targets := zbarebox.lds zbarebox zbarebox.bin zbarebox.S \
> + $(piggy_o) piggy.$(suffix_y)
> +
> +# Make sure files are removed during clean
> +extra-y += piggy.gzip piggy.lz4 piggy.lzo piggy.lzma piggy.xzkern piggy.shipped zbarebox.map
> +
> +ifeq ($(CONFIG_CPU_BIG_ENDIAN),y)
> +FIX_SIZE=-b
> +else
> +FIX_SIZE=
> +endif
> +
> +$(obj)/zbarebox.bin: $(obj)/zbarebox FORCE
> + $(call if_changed,objcopy)
> + $(call cmd,check_file_size,$@,$(CONFIG_BAREBOX_MAX_IMAGE_SIZE))
> + $(Q)$(kecho) ' Barebox: fix size'
> + $(Q)$(objtree)/scripts/fix_size -i -f $(objtree)/$@ $(FIX_SIZE)
> + $(Q)$(kecho) ' Barebox: $@ is ready'
> +
> +$(obj)/zbarebox.S: $(obj)/zbarebox FORCE
> + $(call if_changed,disasm)
> +
> +PBL_CPPFLAGS += -fdata-sections -ffunction-sections
> +LDFLAGS_zbarebox := -Map $(obj)/zbarebox.map --gc-sections
> +ifdef CONFIG_PBL_RELOCATABLE
> +LDFLAGS_zbarebox += -pie
> +else
> +LDFLAGS_zbarebox += -static
> +endif
> +zbarebox-common := $(barebox-pbl-common) $(obj)/$(piggy_o)
> +zbarebox-lds := $(obj)/zbarebox.lds
> +
> +$(zbarebox-lds): $(obj)/../lib/pbl.lds.S FORCE
> + $(call if_changed_dep,cpp_lds_S)
> +
> +quiet_cmd_zbarebox__ ?= LD $@
> + cmd_zbarebox__ ?= $(LD) $(LDFLAGS) $(LDFLAGS_zbarebox) -o $@ \
> + -e pbl_start -T $(zbarebox-lds) \
> + --start-group $(zbarebox-common) --end-group \
> + $(filter-out $(zbarebox-lds) $(zbarebox-common) FORCE ,$^)
> +
> +$(obj)/zbarebox: $(zbarebox-lds) $(zbarebox-common) FORCE
> + $(call if_changed,zbarebox__)
> +
> +$(obj)/piggy.$(suffix_y): $(obj)/../../../barebox.bin FORCE
> + $(call if_changed,$(suffix_y))
> +
> +$(obj)/$(piggy_o): $(obj)/piggy.$(suffix_y) FORCE
> diff --git a/arch/arm64/pbl/piggy.gzip.S b/arch/arm64/pbl/piggy.gzip.S
> new file mode 100644
> index 0000000..4a623c0
> --- /dev/null
> +++ b/arch/arm64/pbl/piggy.gzip.S
> @@ -0,0 +1,6 @@
> + .section .piggydata,#alloc
> + .globl input_data
> +input_data:
> + .incbin "arch/arm/pbl/piggy.gzip"
> + .globl input_data_end
> +input_data_end:
> diff --git a/arch/arm64/pbl/piggy.lz4.S b/arch/arm64/pbl/piggy.lz4.S
> new file mode 100644
> index 0000000..fa9b246
> --- /dev/null
> +++ b/arch/arm64/pbl/piggy.lz4.S
> @@ -0,0 +1,6 @@
> + .section .piggydata,#alloc
> + .globl input_data
> +input_data:
> + .incbin "arch/arm/pbl/piggy.lz4"
> + .globl input_data_end
> +input_data_end:
> diff --git a/arch/arm64/pbl/piggy.lzo.S b/arch/arm64/pbl/piggy.lzo.S
> new file mode 100644
> index 0000000..e0484c7
> --- /dev/null
> +++ b/arch/arm64/pbl/piggy.lzo.S
> @@ -0,0 +1,6 @@
> + .section .piggydata,#alloc
> + .globl input_data
> +input_data:
> + .incbin "arch/arm/pbl/piggy.lzo"
> + .globl input_data_end
> +input_data_end:
> diff --git a/arch/arm64/pbl/piggy.shipped.S b/arch/arm64/pbl/piggy.shipped.S
> new file mode 100644
> index 0000000..dbc2569
> --- /dev/null
> +++ b/arch/arm64/pbl/piggy.shipped.S
> @@ -0,0 +1,6 @@
> + .section .piggydata,#alloc
> + .globl input_data
> +input_data:
> + .incbin "arch/arm/pbl/piggy.shipped"
> + .globl input_data_end
> +input_data_end:
> diff --git a/arch/arm64/pbl/piggy.xzkern.S b/arch/arm64/pbl/piggy.xzkern.S
> new file mode 100644
> index 0000000..a7c0259
> --- /dev/null
> +++ b/arch/arm64/pbl/piggy.xzkern.S
> @@ -0,0 +1,6 @@
> + .section .piggydata,#alloc
> + .globl input_data
> +input_data:
> + .incbin "arch/arm/pbl/piggy.xzkern"
> + .globl input_data_end
> +input_data_end:
> --
> 2.1.0
>
>
> _______________________________________________
> barebox mailing list
> barebox at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/barebox
--
--
Best regards,
Antony Pavlov
More information about the barebox
mailing list