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 Signed-off-by: Raphael Poggi <poggi.raph@xxxxxxxxx> --- 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@xxxxxxxxx> + * + * 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@xxxxxxxxxxxx> + * + * 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@xxxxxxxxxxxxxx> + * + * 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@xxxxxxxxxxxxxx>, 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@xxxxxxxxxxxxxx>, 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@xxxxxxxxxxxxxx> + * + * 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@xxxxxxxxxxxxxx>, 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@xxxxxxxxxxxxxx>, 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@xxxxxxxxxxxxxx>, 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@xxxxxxxxx> + * + * 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@xxxxxxxxxxxxxx>, Pengutronix + * Copyright (c) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@xxxxxxxxxxxx> + * + * 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@xxxxxxxxxxxxxx>, 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@xxxxxxxxxxxxxx>, Pengutronix + * Copyright (c) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@xxxxxxxxxxxx> + * + * 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@xxxxxxxx> + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Alex Zuepke <azu@xxxxxxxx> + * + * 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@xxxxxxxxxxxxxx> + * + * 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@xxxxxxxxx> + * + * 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@xxxxxxxx> + * + * Copyright (C) 2001 Erik Mouw (J.A.K.Mouw@xxxxxxxxxxxxxx) + * + * 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@xxxxxxx. + * + * 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@xxxxxxx. + * + * 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@xxxxxxx. + * + * 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@xxxxxxxxxxxxxx>, 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@xxxxxxxxx> + * + * 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@xxxxxxxxxxxx> + * + * 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@xxxxxxxxx> + * + * 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@xxxxxxxxx> + * + * 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@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/barebox