GK SDK 源码库: XMIPCLinuxV100R005C00SPC030 (kernel/tools/open_source excluded)
This commit is contained in:
@@ -0,0 +1,114 @@
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
# (C) Copyright 2002-2006
|
||||
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
|
||||
lib-$(CONFIG_USE_PRIVATE_LIBGCC) += ashldi3.o ashrdi3.o lshrdi3.o \
|
||||
lib1funcs.o uldivmod.o div0.o \
|
||||
div64.o muldi3.o
|
||||
|
||||
ifdef CONFIG_CPU_V7M
|
||||
obj-y += vectors_m.o crt0.o
|
||||
else ifdef CONFIG_ARM64
|
||||
obj-y += crt0_64.o
|
||||
else
|
||||
obj-y += vectors.o crt0.o
|
||||
endif
|
||||
|
||||
ifdef CONFIG_ARM64
|
||||
obj-y += setjmp_aarch64.o
|
||||
else
|
||||
obj-y += setjmp.o
|
||||
endif
|
||||
|
||||
ifndef CONFIG_SPL_BUILD
|
||||
ifdef CONFIG_ARM64
|
||||
obj-y += relocate_64.o
|
||||
else
|
||||
obj-y += relocate.o
|
||||
endif
|
||||
|
||||
obj-$(CONFIG_CPU_V7M) += cmd_boot.o
|
||||
obj-$(CONFIG_OF_LIBFDT) += bootm-fdt.o
|
||||
obj-$(CONFIG_CMD_BOOTI) += bootm.o image.o
|
||||
obj-$(CONFIG_CMD_BOOTM) += bootm.o
|
||||
obj-$(CONFIG_CMD_BOOTZ) += bootm.o zimage.o
|
||||
obj-$(CONFIG_SYS_L2_PL310) += cache-pl310.o
|
||||
else
|
||||
obj-$(CONFIG_$(SPL_TPL_)FRAMEWORK) += spl.o
|
||||
obj-$(CONFIG_SPL_FRAMEWORK) += zimage.o
|
||||
obj-$(CONFIG_OF_LIBFDT) += bootm-fdt.o
|
||||
endif
|
||||
obj-$(CONFIG_$(SPL_TPL_)USE_ARCH_MEMSET) += memset.o
|
||||
obj-$(CONFIG_$(SPL_TPL_)USE_ARCH_MEMCPY) += memcpy.o
|
||||
obj-$(CONFIG_SEMIHOSTING) += semihosting.o
|
||||
|
||||
obj-y += sections.o
|
||||
obj-y += stack.o
|
||||
ifdef CONFIG_CPU_V7M
|
||||
obj-y += interrupts_m.o
|
||||
else ifdef CONFIG_ARM64
|
||||
obj-$(CONFIG_FSL_LAYERSCAPE) += ccn504.o
|
||||
ifneq ($(CONFIG_GICV2)$(CONFIG_GICV3),)
|
||||
obj-y += gic_64.o
|
||||
endif
|
||||
obj-y += interrupts_64.o
|
||||
else
|
||||
obj-y += interrupts.o
|
||||
endif
|
||||
ifndef CONFIG_SYSRESET
|
||||
obj-y += reset.o
|
||||
endif
|
||||
|
||||
obj-y += cache.o
|
||||
obj-$(CONFIG_SYS_ARM_CACHE_CP15) += cache-cp15.o
|
||||
|
||||
obj-y += psci-dt.o
|
||||
|
||||
obj-$(CONFIG_DEBUG_LL) += debug.o
|
||||
|
||||
# For EABI conformant tool chains, provide eabi_compat()
|
||||
ifneq (,$(findstring -mabi=aapcs-linux,$(PLATFORM_CPPFLAGS)))
|
||||
extra-y += eabi_compat.o
|
||||
endif
|
||||
|
||||
# some files can only build in ARM or THUMB2, not THUMB1
|
||||
|
||||
ifdef CONFIG_$(SPL_)SYS_THUMB_BUILD
|
||||
asflags-$(CONFIG_HAS_THUMB2) += -DCONFIG_THUMB2_KERNEL
|
||||
ifndef CONFIG_HAS_THUMB2
|
||||
|
||||
# for C files, just apend -marm, which will override previous -mthumb*
|
||||
|
||||
ifndef CONFIG_ARM64
|
||||
CFLAGS_cache.o := -marm
|
||||
CFLAGS_cache-cp15.o := -marm
|
||||
endif
|
||||
|
||||
# For .S, drop -mthumb* and other thumb-related options.
|
||||
# CFLAGS_REMOVE_* would not have an effet, so AFLAGS_REMOVE_*
|
||||
# was implemented and is used here.
|
||||
# Also, define ${target}_NO_THUMB_BUILD for these two targets
|
||||
# so that the code knows it should not use Thumb.
|
||||
|
||||
AFLAGS_REMOVE_memset.o := -mthumb -mthumb-interwork
|
||||
AFLAGS_REMOVE_memcpy.o := -mthumb -mthumb-interwork
|
||||
AFLAGS_memset.o := -DMEMSET_NO_THUMB_BUILD
|
||||
AFLAGS_memcpy.o := -DMEMCPY_NO_THUMB_BUILD
|
||||
endif
|
||||
endif
|
||||
|
||||
# For building EFI apps
|
||||
CFLAGS_$(EFI_CRT0) := $(CFLAGS_EFI)
|
||||
CFLAGS_REMOVE_$(EFI_CRT0) := $(CFLAGS_NON_EFI)
|
||||
|
||||
CFLAGS_$(EFI_RELOC) := $(CFLAGS_EFI)
|
||||
CFLAGS_REMOVE_$(EFI_RELOC) := $(CFLAGS_NON_EFI)
|
||||
|
||||
extra-$(CONFIG_CMD_BOOTEFI_HELLO_COMPILE) += $(EFI_CRT0) $(EFI_RELOC)
|
||||
# TODO: As of v2019.01 the relocation code for the EFI application cannot
|
||||
# be built on ARMv7-M.
|
||||
ifndef CONFIG_CPU_V7M
|
||||
#extra-$(CONFIG_CMD_BOOTEFI_SELFTEST) += $(EFI_CRT0) $(EFI_RELOC)
|
||||
endif
|
||||
extra-$(CONFIG_EFI) += $(EFI_CRT0) $(EFI_RELOC)
|
||||
@@ -0,0 +1,33 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/* Copyright 1995, 1996, 1998, 1999, 2000, 2003, 2004, 2005
|
||||
Free Software Foundation, Inc.
|
||||
*/
|
||||
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/assembler.h>
|
||||
|
||||
#ifdef __ARMEB__
|
||||
#define al r1
|
||||
#define ah r0
|
||||
#else
|
||||
#define al r0
|
||||
#define ah r1
|
||||
#endif
|
||||
|
||||
.pushsection .text.__ashldi3, "ax"
|
||||
ENTRY(__ashldi3)
|
||||
ENTRY(__aeabi_llsl)
|
||||
|
||||
subs r3, r2, #32
|
||||
rsb ip, r2, #32
|
||||
movmi ah, ah, lsl r2
|
||||
movpl ah, al, lsl r3
|
||||
ARM( orrmi ah, ah, al, lsr ip )
|
||||
THUMB( lsrmi r3, al, ip )
|
||||
THUMB( orrmi ah, ah, r3 )
|
||||
mov al, al, lsl r2
|
||||
ret lr
|
||||
|
||||
ENDPROC(__ashldi3)
|
||||
ENDPROC(__aeabi_llsl)
|
||||
.popsection
|
||||
@@ -0,0 +1,33 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/* Copyright 1995, 1996, 1998, 1999, 2000, 2003, 2004, 2005
|
||||
Free Software Foundation, Inc.
|
||||
*/
|
||||
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/assembler.h>
|
||||
|
||||
#ifdef __ARMEB__
|
||||
#define al r1
|
||||
#define ah r0
|
||||
#else
|
||||
#define al r0
|
||||
#define ah r1
|
||||
#endif
|
||||
|
||||
.pushsection .text.__ashrdi3, "ax"
|
||||
ENTRY(__ashrdi3)
|
||||
ENTRY(__aeabi_lasr)
|
||||
|
||||
subs r3, r2, #32
|
||||
rsb ip, r2, #32
|
||||
movmi al, al, lsr r2
|
||||
movpl al, ah, asr r3
|
||||
ARM( orrmi al, al, ah, lsl ip )
|
||||
THUMB( lslmi r3, ah, ip )
|
||||
THUMB( orrmi al, al, r3 )
|
||||
mov ah, ah, asr r2
|
||||
ret lr
|
||||
|
||||
ENDPROC(__ashrdi3)
|
||||
ENDPROC(__aeabi_lasr)
|
||||
.popsection
|
||||
@@ -0,0 +1,209 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Adapted from Linux v2.6.36 kernel: arch/powerpc/kernel/asm-offsets.c
|
||||
*
|
||||
* This program is used to generate definitions needed by
|
||||
* assembly language modules.
|
||||
*
|
||||
* We use the technique used in the OSF Mach kernel code:
|
||||
* generate asm statements containing #defines,
|
||||
* compile this file to assembler, and then extract the
|
||||
* #defines from the assembly-language output.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <linux/kbuild.h>
|
||||
#include <linux/arm-smccc.h>
|
||||
|
||||
#if defined(CONFIG_MX25) || defined(CONFIG_MX27) || defined(CONFIG_MX35) \
|
||||
|| defined(CONFIG_MX51) || defined(CONFIG_MX53)
|
||||
#include <asm/arch/imx-regs.h>
|
||||
#endif
|
||||
|
||||
int main(void)
|
||||
{
|
||||
/*
|
||||
* TODO : Check if each entry in this file is really necessary.
|
||||
* - struct esdramc_regs
|
||||
* - struct max_regs
|
||||
* - struct aips_regs
|
||||
* - struct aipi_regs
|
||||
* - struct clkctl
|
||||
* - struct dpll
|
||||
* are used only for generating asm-offsets.h.
|
||||
* It means their offset addresses are referenced only from assembly
|
||||
* code. Is it better to define the macros directly in headers?
|
||||
*/
|
||||
|
||||
#if defined(CONFIG_MX25)
|
||||
/* Clock Control Module */
|
||||
DEFINE(CCM_CCTL, offsetof(struct ccm_regs, cctl));
|
||||
DEFINE(CCM_CGCR0, offsetof(struct ccm_regs, cgr0));
|
||||
DEFINE(CCM_CGCR1, offsetof(struct ccm_regs, cgr1));
|
||||
DEFINE(CCM_CGCR2, offsetof(struct ccm_regs, cgr2));
|
||||
DEFINE(CCM_PCDR2, offsetof(struct ccm_regs, pcdr[2]));
|
||||
DEFINE(CCM_MCR, offsetof(struct ccm_regs, mcr));
|
||||
|
||||
/* Enhanced SDRAM Controller */
|
||||
DEFINE(ESDRAMC_ESDCTL0, offsetof(struct esdramc_regs, ctl0));
|
||||
DEFINE(ESDRAMC_ESDCFG0, offsetof(struct esdramc_regs, cfg0));
|
||||
DEFINE(ESDRAMC_ESDMISC, offsetof(struct esdramc_regs, misc));
|
||||
|
||||
/* Multi-Layer AHB Crossbar Switch */
|
||||
DEFINE(MAX_MPR0, offsetof(struct max_regs, mpr0));
|
||||
DEFINE(MAX_SGPCR0, offsetof(struct max_regs, sgpcr0));
|
||||
DEFINE(MAX_MPR1, offsetof(struct max_regs, mpr1));
|
||||
DEFINE(MAX_SGPCR1, offsetof(struct max_regs, sgpcr1));
|
||||
DEFINE(MAX_MPR2, offsetof(struct max_regs, mpr2));
|
||||
DEFINE(MAX_SGPCR2, offsetof(struct max_regs, sgpcr2));
|
||||
DEFINE(MAX_MPR3, offsetof(struct max_regs, mpr3));
|
||||
DEFINE(MAX_SGPCR3, offsetof(struct max_regs, sgpcr3));
|
||||
DEFINE(MAX_MPR4, offsetof(struct max_regs, mpr4));
|
||||
DEFINE(MAX_SGPCR4, offsetof(struct max_regs, sgpcr4));
|
||||
DEFINE(MAX_MGPCR0, offsetof(struct max_regs, mgpcr0));
|
||||
DEFINE(MAX_MGPCR1, offsetof(struct max_regs, mgpcr1));
|
||||
DEFINE(MAX_MGPCR2, offsetof(struct max_regs, mgpcr2));
|
||||
DEFINE(MAX_MGPCR3, offsetof(struct max_regs, mgpcr3));
|
||||
DEFINE(MAX_MGPCR4, offsetof(struct max_regs, mgpcr4));
|
||||
|
||||
/* AHB <-> IP-Bus Interface */
|
||||
DEFINE(AIPS_MPR_0_7, offsetof(struct aips_regs, mpr_0_7));
|
||||
DEFINE(AIPS_MPR_8_15, offsetof(struct aips_regs, mpr_8_15));
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_MX27)
|
||||
DEFINE(AIPI1_PSR0, IMX_AIPI1_BASE + offsetof(struct aipi_regs, psr0));
|
||||
DEFINE(AIPI1_PSR1, IMX_AIPI1_BASE + offsetof(struct aipi_regs, psr1));
|
||||
DEFINE(AIPI2_PSR0, IMX_AIPI2_BASE + offsetof(struct aipi_regs, psr0));
|
||||
DEFINE(AIPI2_PSR1, IMX_AIPI2_BASE + offsetof(struct aipi_regs, psr1));
|
||||
|
||||
DEFINE(CSCR, IMX_PLL_BASE + offsetof(struct pll_regs, cscr));
|
||||
DEFINE(MPCTL0, IMX_PLL_BASE + offsetof(struct pll_regs, mpctl0));
|
||||
DEFINE(SPCTL0, IMX_PLL_BASE + offsetof(struct pll_regs, spctl0));
|
||||
DEFINE(PCDR0, IMX_PLL_BASE + offsetof(struct pll_regs, pcdr0));
|
||||
DEFINE(PCDR1, IMX_PLL_BASE + offsetof(struct pll_regs, pcdr1));
|
||||
DEFINE(PCCR0, IMX_PLL_BASE + offsetof(struct pll_regs, pccr0));
|
||||
DEFINE(PCCR1, IMX_PLL_BASE + offsetof(struct pll_regs, pccr1));
|
||||
|
||||
DEFINE(ESDCTL0_ROF, offsetof(struct esdramc_regs, esdctl0));
|
||||
DEFINE(ESDCFG0_ROF, offsetof(struct esdramc_regs, esdcfg0));
|
||||
DEFINE(ESDCTL1_ROF, offsetof(struct esdramc_regs, esdctl1));
|
||||
DEFINE(ESDCFG1_ROF, offsetof(struct esdramc_regs, esdcfg1));
|
||||
DEFINE(ESDMISC_ROF, offsetof(struct esdramc_regs, esdmisc));
|
||||
|
||||
DEFINE(GPCR, IMX_SYSTEM_CTL_BASE +
|
||||
offsetof(struct system_control_regs, gpcr));
|
||||
DEFINE(FMCR, IMX_SYSTEM_CTL_BASE +
|
||||
offsetof(struct system_control_regs, fmcr));
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_MX35)
|
||||
/* Round up to make sure size gives nice stack alignment */
|
||||
DEFINE(CLKCTL_CCMR, offsetof(struct ccm_regs, ccmr));
|
||||
DEFINE(CLKCTL_PDR0, offsetof(struct ccm_regs, pdr0));
|
||||
DEFINE(CLKCTL_PDR1, offsetof(struct ccm_regs, pdr1));
|
||||
DEFINE(CLKCTL_PDR2, offsetof(struct ccm_regs, pdr2));
|
||||
DEFINE(CLKCTL_PDR3, offsetof(struct ccm_regs, pdr3));
|
||||
DEFINE(CLKCTL_PDR4, offsetof(struct ccm_regs, pdr4));
|
||||
DEFINE(CLKCTL_RCSR, offsetof(struct ccm_regs, rcsr));
|
||||
DEFINE(CLKCTL_MPCTL, offsetof(struct ccm_regs, mpctl));
|
||||
DEFINE(CLKCTL_PPCTL, offsetof(struct ccm_regs, ppctl));
|
||||
DEFINE(CLKCTL_ACMR, offsetof(struct ccm_regs, acmr));
|
||||
DEFINE(CLKCTL_COSR, offsetof(struct ccm_regs, cosr));
|
||||
DEFINE(CLKCTL_CGR0, offsetof(struct ccm_regs, cgr0));
|
||||
DEFINE(CLKCTL_CGR1, offsetof(struct ccm_regs, cgr1));
|
||||
DEFINE(CLKCTL_CGR2, offsetof(struct ccm_regs, cgr2));
|
||||
DEFINE(CLKCTL_CGR3, offsetof(struct ccm_regs, cgr3));
|
||||
|
||||
/* Multi-Layer AHB Crossbar Switch */
|
||||
DEFINE(MAX_MPR0, offsetof(struct max_regs, mpr0));
|
||||
DEFINE(MAX_SGPCR0, offsetof(struct max_regs, sgpcr0));
|
||||
DEFINE(MAX_MPR1, offsetof(struct max_regs, mpr1));
|
||||
DEFINE(MAX_SGPCR1, offsetof(struct max_regs, sgpcr1));
|
||||
DEFINE(MAX_MPR2, offsetof(struct max_regs, mpr2));
|
||||
DEFINE(MAX_SGPCR2, offsetof(struct max_regs, sgpcr2));
|
||||
DEFINE(MAX_MPR3, offsetof(struct max_regs, mpr3));
|
||||
DEFINE(MAX_SGPCR3, offsetof(struct max_regs, sgpcr3));
|
||||
DEFINE(MAX_MPR4, offsetof(struct max_regs, mpr4));
|
||||
DEFINE(MAX_SGPCR4, offsetof(struct max_regs, sgpcr4));
|
||||
DEFINE(MAX_MGPCR0, offsetof(struct max_regs, mgpcr0));
|
||||
DEFINE(MAX_MGPCR1, offsetof(struct max_regs, mgpcr1));
|
||||
DEFINE(MAX_MGPCR2, offsetof(struct max_regs, mgpcr2));
|
||||
DEFINE(MAX_MGPCR3, offsetof(struct max_regs, mgpcr3));
|
||||
DEFINE(MAX_MGPCR4, offsetof(struct max_regs, mgpcr4));
|
||||
DEFINE(MAX_MGPCR5, offsetof(struct max_regs, mgpcr5));
|
||||
|
||||
/* AHB <-> IP-Bus Interface */
|
||||
DEFINE(AIPS_MPR_0_7, offsetof(struct aips_regs, mpr_0_7));
|
||||
DEFINE(AIPS_MPR_8_15, offsetof(struct aips_regs, mpr_8_15));
|
||||
DEFINE(AIPS_PACR_0_7, offsetof(struct aips_regs, pacr_0_7));
|
||||
DEFINE(AIPS_PACR_8_15, offsetof(struct aips_regs, pacr_8_15));
|
||||
DEFINE(AIPS_PACR_16_23, offsetof(struct aips_regs, pacr_16_23));
|
||||
DEFINE(AIPS_PACR_24_31, offsetof(struct aips_regs, pacr_24_31));
|
||||
DEFINE(AIPS_OPACR_0_7, offsetof(struct aips_regs, opacr_0_7));
|
||||
DEFINE(AIPS_OPACR_8_15, offsetof(struct aips_regs, opacr_8_15));
|
||||
DEFINE(AIPS_OPACR_16_23, offsetof(struct aips_regs, opacr_16_23));
|
||||
DEFINE(AIPS_OPACR_24_31, offsetof(struct aips_regs, opacr_24_31));
|
||||
DEFINE(AIPS_OPACR_32_39, offsetof(struct aips_regs, opacr_32_39));
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_MX51) || defined(CONFIG_MX53)
|
||||
/* Round up to make sure size gives nice stack alignment */
|
||||
DEFINE(CLKCTL_CCMR, offsetof(struct clkctl, ccr));
|
||||
DEFINE(CLKCTL_CCDR, offsetof(struct clkctl, ccdr));
|
||||
DEFINE(CLKCTL_CSR, offsetof(struct clkctl, csr));
|
||||
DEFINE(CLKCTL_CCSR, offsetof(struct clkctl, ccsr));
|
||||
DEFINE(CLKCTL_CACRR, offsetof(struct clkctl, cacrr));
|
||||
DEFINE(CLKCTL_CBCDR, offsetof(struct clkctl, cbcdr));
|
||||
DEFINE(CLKCTL_CBCMR, offsetof(struct clkctl, cbcmr));
|
||||
DEFINE(CLKCTL_CSCMR1, offsetof(struct clkctl, cscmr1));
|
||||
DEFINE(CLKCTL_CSCMR2, offsetof(struct clkctl, cscmr2));
|
||||
DEFINE(CLKCTL_CSCDR1, offsetof(struct clkctl, cscdr1));
|
||||
DEFINE(CLKCTL_CS1CDR, offsetof(struct clkctl, cs1cdr));
|
||||
DEFINE(CLKCTL_CS2CDR, offsetof(struct clkctl, cs2cdr));
|
||||
DEFINE(CLKCTL_CDCDR, offsetof(struct clkctl, cdcdr));
|
||||
DEFINE(CLKCTL_CHSCCDR, offsetof(struct clkctl, chsccdr));
|
||||
DEFINE(CLKCTL_CSCDR2, offsetof(struct clkctl, cscdr2));
|
||||
DEFINE(CLKCTL_CSCDR3, offsetof(struct clkctl, cscdr3));
|
||||
DEFINE(CLKCTL_CSCDR4, offsetof(struct clkctl, cscdr4));
|
||||
DEFINE(CLKCTL_CWDR, offsetof(struct clkctl, cwdr));
|
||||
DEFINE(CLKCTL_CDHIPR, offsetof(struct clkctl, cdhipr));
|
||||
DEFINE(CLKCTL_CDCR, offsetof(struct clkctl, cdcr));
|
||||
DEFINE(CLKCTL_CTOR, offsetof(struct clkctl, ctor));
|
||||
DEFINE(CLKCTL_CLPCR, offsetof(struct clkctl, clpcr));
|
||||
DEFINE(CLKCTL_CISR, offsetof(struct clkctl, cisr));
|
||||
DEFINE(CLKCTL_CIMR, offsetof(struct clkctl, cimr));
|
||||
DEFINE(CLKCTL_CCOSR, offsetof(struct clkctl, ccosr));
|
||||
DEFINE(CLKCTL_CGPR, offsetof(struct clkctl, cgpr));
|
||||
DEFINE(CLKCTL_CCGR0, offsetof(struct clkctl, ccgr0));
|
||||
DEFINE(CLKCTL_CCGR1, offsetof(struct clkctl, ccgr1));
|
||||
DEFINE(CLKCTL_CCGR2, offsetof(struct clkctl, ccgr2));
|
||||
DEFINE(CLKCTL_CCGR3, offsetof(struct clkctl, ccgr3));
|
||||
DEFINE(CLKCTL_CCGR4, offsetof(struct clkctl, ccgr4));
|
||||
DEFINE(CLKCTL_CCGR5, offsetof(struct clkctl, ccgr5));
|
||||
DEFINE(CLKCTL_CCGR6, offsetof(struct clkctl, ccgr6));
|
||||
DEFINE(CLKCTL_CMEOR, offsetof(struct clkctl, cmeor));
|
||||
#if defined(CONFIG_MX53)
|
||||
DEFINE(CLKCTL_CCGR7, offsetof(struct clkctl, ccgr7));
|
||||
#endif
|
||||
|
||||
/* DPLL */
|
||||
DEFINE(PLL_DP_CTL, offsetof(struct dpll, dp_ctl));
|
||||
DEFINE(PLL_DP_CONFIG, offsetof(struct dpll, dp_config));
|
||||
DEFINE(PLL_DP_OP, offsetof(struct dpll, dp_op));
|
||||
DEFINE(PLL_DP_MFD, offsetof(struct dpll, dp_mfd));
|
||||
DEFINE(PLL_DP_MFN, offsetof(struct dpll, dp_mfn));
|
||||
DEFINE(PLL_DP_HFS_OP, offsetof(struct dpll, dp_hfs_op));
|
||||
DEFINE(PLL_DP_HFS_MFD, offsetof(struct dpll, dp_hfs_mfd));
|
||||
DEFINE(PLL_DP_HFS_MFN, offsetof(struct dpll, dp_hfs_mfn));
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ARM_SMCCC
|
||||
DEFINE(ARM_SMCCC_RES_X0_OFFS, offsetof(struct arm_smccc_res, a0));
|
||||
DEFINE(ARM_SMCCC_RES_X2_OFFS, offsetof(struct arm_smccc_res, a2));
|
||||
DEFINE(ARM_SMCCC_QUIRK_ID_OFFS, offsetof(struct arm_smccc_quirk, id));
|
||||
DEFINE(ARM_SMCCC_QUIRK_STATE_OFFS, offsetof(struct arm_smccc_quirk, state));
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (c) 2013, Google Inc.
|
||||
*
|
||||
* Copyright (C) 2011
|
||||
* Corscience GmbH & Co. KG - Simon Schwarz <schwarz@corscience.de>
|
||||
* - Added prep subcommand support
|
||||
* - Reorganized source - modeled after powerpc version
|
||||
*
|
||||
* (C) Copyright 2002
|
||||
* Sysgo Real-Time Solutions, GmbH <www.elinos.com>
|
||||
* Marius Groeger <mgroeger@sysgo.de>
|
||||
*
|
||||
* Copyright (C) 2001 Erik Mouw (J.A.K.Mouw@its.tudelft.nl)
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <fdt_support.h>
|
||||
#ifdef CONFIG_ARMV7_NONSEC
|
||||
#include <asm/armv7.h>
|
||||
#endif
|
||||
#include <asm/psci.h>
|
||||
#include <asm/spin_table.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
#ifdef CONFIG_FMAN_ENET
|
||||
__weak int fdt_update_ethernet_dt(void *blob)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int arch_fixup_fdt(void *blob)
|
||||
{
|
||||
__maybe_unused int ret = 0;
|
||||
#if defined(CONFIG_ARMV7_NONSEC) || defined(CONFIG_OF_LIBFDT)
|
||||
bd_t *bd = gd->bd;
|
||||
int bank;
|
||||
u64 start[CONFIG_NR_DRAM_BANKS];
|
||||
u64 size[CONFIG_NR_DRAM_BANKS];
|
||||
|
||||
for (bank = 0; bank < CONFIG_NR_DRAM_BANKS; bank++) {
|
||||
start[bank] = bd->bi_dram[bank].start;
|
||||
size[bank] = bd->bi_dram[bank].size;
|
||||
#ifdef CONFIG_ARMV7_NONSEC
|
||||
ret = armv7_apply_memory_carveout(&start[bank], &size[bank]);
|
||||
if (ret)
|
||||
return ret;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF_LIBFDT
|
||||
ret = fdt_fixup_memory_banks(blob, start, size, CONFIG_NR_DRAM_BANKS);
|
||||
if (ret)
|
||||
return ret;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ARMV8_SPIN_TABLE
|
||||
ret = spin_table_update_dt(blob);
|
||||
if (ret)
|
||||
return ret;
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_ARMV7_NONSEC) || defined(CONFIG_ARMV8_PSCI) || \
|
||||
defined(CONFIG_SEC_FIRMWARE_ARMV8_PSCI)
|
||||
ret = psci_update_dt(blob);
|
||||
if (ret)
|
||||
return ret;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_FMAN_ENET
|
||||
ret = fdt_update_ethernet_dt(blob);
|
||||
if (ret)
|
||||
return ret;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,489 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/* Copyright (C) 2011
|
||||
* Corscience GmbH & Co. KG - Simon Schwarz <schwarz@corscience.de>
|
||||
* - Added prep subcommand support
|
||||
* - Reorganized source - modeled after powerpc version
|
||||
*
|
||||
* (C) Copyright 2002
|
||||
* Sysgo Real-Time Solutions, GmbH <www.elinos.com>
|
||||
* Marius Groeger <mgroeger@sysgo.de>
|
||||
*
|
||||
* Copyright (C) 2001 Erik Mouw (J.A.K.Mouw@its.tudelft.nl)
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <cpu_func.h>
|
||||
#include <dm.h>
|
||||
#include <dm/root.h>
|
||||
#include <env.h>
|
||||
#include <image.h>
|
||||
#include <u-boot/zlib.h>
|
||||
#include <asm/byteorder.h>
|
||||
#include <linux/libfdt.h>
|
||||
#include <mapmem.h>
|
||||
#include <fdt_support.h>
|
||||
#include <asm/bootm.h>
|
||||
#include <asm/secure.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <bootm.h>
|
||||
#include <vxworks.h>
|
||||
|
||||
#ifdef CONFIG_ARMV7_NONSEC
|
||||
#include <asm/armv7.h>
|
||||
#endif
|
||||
#include <asm/setup.h>
|
||||
|
||||
#include <linux/lotus/atf.h>
|
||||
#include <linux/lotus/common.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
static struct tag *params;
|
||||
|
||||
static ulong get_sp(void)
|
||||
{
|
||||
ulong ret;
|
||||
|
||||
asm("mov %0, sp" : "=r"(ret) : );
|
||||
return ret;
|
||||
}
|
||||
|
||||
void arch_lmb_reserve(struct lmb *lmb)
|
||||
{
|
||||
ulong sp, bank_end;
|
||||
int bank;
|
||||
|
||||
/*
|
||||
* Booting a (Linux) kernel image
|
||||
*
|
||||
* Allocate space for command line and board info - the
|
||||
* address should be as high as possible within the reach of
|
||||
* the kernel (see CONFIG_SYS_BOOTMAPSZ settings), but in unused
|
||||
* memory, which means far enough below the current stack
|
||||
* pointer.
|
||||
*/
|
||||
sp = get_sp();
|
||||
debug("## Current stack ends at 0x%08lx ", sp);
|
||||
|
||||
/* adjust sp by 4K to be safe */
|
||||
sp -= 4096;
|
||||
for (bank = 0; bank < CONFIG_NR_DRAM_BANKS; bank++) {
|
||||
if (!gd->bd->bi_dram[bank].size ||
|
||||
sp < gd->bd->bi_dram[bank].start)
|
||||
continue;
|
||||
/* Watch out for RAM at end of address space! */
|
||||
bank_end = gd->bd->bi_dram[bank].start +
|
||||
gd->bd->bi_dram[bank].size - 1;
|
||||
if (sp > bank_end)
|
||||
continue;
|
||||
lmb_reserve(lmb, sp, bank_end - sp + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
__weak void board_quiesce_devices(void)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* announce_and_cleanup() - Print message and prepare for kernel boot
|
||||
*
|
||||
* @fake: non-zero to do everything except actually boot
|
||||
*/
|
||||
static void announce_and_cleanup(int fake)
|
||||
{
|
||||
bootstage_mark_name(BOOTSTAGE_ID_BOOTM_HANDOFF, "start_kernel");
|
||||
#ifdef CONFIG_BOOTSTAGE_FDT
|
||||
bootstage_fdt_add_report();
|
||||
#endif
|
||||
#ifdef CONFIG_BOOTSTAGE_REPORT
|
||||
bootstage_report();
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_DEVICE
|
||||
udc_disconnect();
|
||||
#endif
|
||||
|
||||
board_quiesce_devices();
|
||||
|
||||
printf("\nStarting kernel ...%s\n\n", fake ?
|
||||
"(fake run for tracing)" : "");
|
||||
/*
|
||||
* Call remove function of all devices with a removal flag set.
|
||||
* This may be useful for last-stage operations, like cancelling
|
||||
* of DMA operation or releasing device internal buffers.
|
||||
*/
|
||||
dm_remove_devices_flags(DM_REMOVE_ACTIVE_ALL);
|
||||
|
||||
cleanup_before_linux();
|
||||
}
|
||||
|
||||
static void setup_start_tag (bd_t *bd)
|
||||
{
|
||||
params = (struct tag *)bd->bi_boot_params;
|
||||
|
||||
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(bd_t *bd)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
|
||||
params->hdr.tag = ATAG_MEM;
|
||||
params->hdr.size = tag_size (tag_mem32);
|
||||
|
||||
params->u.mem.start = bd->bi_dram[i].start;
|
||||
params->u.mem.size = bd->bi_dram[i].size;
|
||||
|
||||
params = tag_next (params);
|
||||
}
|
||||
}
|
||||
|
||||
static void setup_commandline_tag(bd_t *bd, char *commandline)
|
||||
{
|
||||
char *p;
|
||||
|
||||
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;
|
||||
|
||||
params->hdr.tag = ATAG_CMDLINE;
|
||||
params->hdr.size =
|
||||
(sizeof (struct tag_header) + strlen (p) + 1 + 4) >> 2;
|
||||
|
||||
strcpy (params->u.cmdline.cmdline, p);
|
||||
|
||||
params = tag_next (params);
|
||||
}
|
||||
|
||||
static void setup_initrd_tag(bd_t *bd, ulong initrd_start, ulong initrd_end)
|
||||
{
|
||||
/* 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 = initrd_start;
|
||||
params->u.initrd.size = initrd_end - initrd_start;
|
||||
|
||||
params = tag_next (params);
|
||||
}
|
||||
|
||||
static void setup_serial_tag(struct tag **tmp)
|
||||
{
|
||||
struct tag *params = *tmp;
|
||||
struct tag_serialnr serialnr;
|
||||
|
||||
get_board_serial(&serialnr);
|
||||
params->hdr.tag = ATAG_SERIAL;
|
||||
params->hdr.size = tag_size (tag_serialnr);
|
||||
params->u.serialnr.low = serialnr.low;
|
||||
params->u.serialnr.high= serialnr.high;
|
||||
params = tag_next (params);
|
||||
*tmp = params;
|
||||
}
|
||||
|
||||
static void setup_revision_tag(struct tag **in_params)
|
||||
{
|
||||
u32 rev = 0;
|
||||
|
||||
rev = get_board_rev();
|
||||
params->hdr.tag = ATAG_REVISION;
|
||||
params->hdr.size = tag_size (tag_revision);
|
||||
params->u.revision.rev = rev;
|
||||
params = tag_next (params);
|
||||
}
|
||||
|
||||
static void setup_end_tag(bd_t *bd)
|
||||
{
|
||||
params->hdr.tag = ATAG_NONE;
|
||||
params->hdr.size = 0;
|
||||
}
|
||||
|
||||
__weak void setup_board_tags(struct tag **in_params) {}
|
||||
|
||||
#ifdef CONFIG_ARM64
|
||||
static void do_nonsec_virt_switch(void)
|
||||
{
|
||||
smp_kick_all_cpus();
|
||||
dcache_disable(); /* flush cache before swtiching to EL2 */
|
||||
}
|
||||
#endif
|
||||
|
||||
__weak void board_prep_linux(bootm_headers_t *images) { }
|
||||
|
||||
/* Subcommand: PREP */
|
||||
static void boot_prep_linux(bootm_headers_t *images)
|
||||
{
|
||||
char *commandline = env_get("bootargs");
|
||||
|
||||
if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len) {
|
||||
#ifdef CONFIG_OF_LIBFDT
|
||||
debug("using: FDT\n");
|
||||
if (image_setup_linux(images)) {
|
||||
printf("FDT creation failed! hanging...");
|
||||
hang();
|
||||
}
|
||||
#endif
|
||||
} else if (BOOTM_ENABLE_TAGS) {
|
||||
debug("using: ATAGS\n");
|
||||
setup_start_tag(gd->bd);
|
||||
if (BOOTM_ENABLE_SERIAL_TAG)
|
||||
setup_serial_tag(¶ms);
|
||||
if (BOOTM_ENABLE_CMDLINE_TAG)
|
||||
setup_commandline_tag(gd->bd, commandline);
|
||||
if (BOOTM_ENABLE_REVISION_TAG)
|
||||
setup_revision_tag(¶ms);
|
||||
if (BOOTM_ENABLE_MEMORY_TAGS)
|
||||
setup_memory_tags(gd->bd);
|
||||
if (BOOTM_ENABLE_INITRD_TAG) {
|
||||
/*
|
||||
* In boot_ramdisk_high(), it may relocate ramdisk to
|
||||
* a specified location. And set images->initrd_start &
|
||||
* images->initrd_end to relocated ramdisk's start/end
|
||||
* addresses. So use them instead of images->rd_start &
|
||||
* images->rd_end when possible.
|
||||
*/
|
||||
if (images->initrd_start && images->initrd_end) {
|
||||
setup_initrd_tag(gd->bd, images->initrd_start,
|
||||
images->initrd_end);
|
||||
} else if (images->rd_start && images->rd_end) {
|
||||
setup_initrd_tag(gd->bd, images->rd_start,
|
||||
images->rd_end);
|
||||
}
|
||||
}
|
||||
setup_board_tags(¶ms);
|
||||
setup_end_tag(gd->bd);
|
||||
} else {
|
||||
printf("FDT and ATAGS support not compiled in - hanging\n");
|
||||
hang();
|
||||
}
|
||||
|
||||
board_prep_linux(images);
|
||||
}
|
||||
|
||||
__weak bool armv7_boot_nonsec_default(void)
|
||||
{
|
||||
#ifdef CONFIG_ARMV7_BOOT_SEC_DEFAULT
|
||||
return false;
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ARMV7_NONSEC
|
||||
bool armv7_boot_nonsec(void)
|
||||
{
|
||||
char *s = env_get("bootm_boot_mode");
|
||||
bool nonsec = armv7_boot_nonsec_default();
|
||||
|
||||
if (s && !strcmp(s, "sec"))
|
||||
nonsec = false;
|
||||
|
||||
if (s && !strcmp(s, "nonsec"))
|
||||
nonsec = true;
|
||||
|
||||
return nonsec;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ARM64
|
||||
__weak void update_os_arch_secondary_cores(uint8_t os_arch)
|
||||
{
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ARMV8_SWITCH_TO_EL1
|
||||
static void switch_to_el1(void)
|
||||
{
|
||||
if ((IH_ARCH_DEFAULT == IH_ARCH_ARM64) &&
|
||||
(images.os.arch == IH_ARCH_ARM))
|
||||
armv8_switch_to_el1(0, (u64)gd->bd->bi_arch_number,
|
||||
(u64)images.ft_addr, 0,
|
||||
(u64)images.ep,
|
||||
ES_TO_AARCH32);
|
||||
else
|
||||
armv8_switch_to_el1((u64)images.ft_addr, 0, 0, 0,
|
||||
images.ep,
|
||||
ES_TO_AARCH64);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Subcommand: GO */
|
||||
static void boot_jump_linux(bootm_headers_t *images, int flag)
|
||||
{
|
||||
#ifdef CONFIG_ARM64
|
||||
void (*kernel_entry)(void *fdt_addr, void *res0, void *res1,
|
||||
void *res2);
|
||||
int fake = (flag & BOOTM_STATE_OS_FAKE_GO);
|
||||
|
||||
kernel_entry = (void (*)(void *fdt_addr, void *res0, void *res1,
|
||||
void *res2))images->ep;
|
||||
|
||||
debug("## Transferring control to Linux (at address %lx)...\n",
|
||||
(ulong) kernel_entry);
|
||||
bootstage_mark(BOOTSTAGE_ID_RUN_OS);
|
||||
|
||||
announce_and_cleanup(fake);
|
||||
|
||||
if (!fake) {
|
||||
#ifdef CONFIG_ARMV8_PSCI
|
||||
armv8_setup_psci();
|
||||
#endif
|
||||
do_nonsec_virt_switch();
|
||||
|
||||
update_os_arch_secondary_cores(images->os.arch);
|
||||
|
||||
#ifdef CONFIG_ARMV8_SWITCH_TO_EL1
|
||||
armv8_switch_to_el2((u64)images->ft_addr, 0, 0, 0,
|
||||
(u64)switch_to_el1, ES_TO_AARCH64);
|
||||
#else
|
||||
if ((IH_ARCH_DEFAULT == IH_ARCH_ARM64) &&
|
||||
(images->os.arch == IH_ARCH_ARM))
|
||||
armv8_switch_to_el2(0, (u64)gd->bd->bi_arch_number,
|
||||
(u64)images->ft_addr, 0,
|
||||
(u64)images->ep,
|
||||
ES_TO_AARCH32);
|
||||
else
|
||||
armv8_switch_to_el2((u64)images->ft_addr, 0, 0, 0,
|
||||
images->ep,
|
||||
ES_TO_AARCH64);
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
unsigned long machid = gd->bd->bi_arch_number;
|
||||
char *s;
|
||||
void (*kernel_entry)(int zero, int arch, uint params);
|
||||
unsigned long r2;
|
||||
int fake = (flag & BOOTM_STATE_OS_FAKE_GO);
|
||||
|
||||
kernel_entry = (void (*)(int, int, uint))images->ep;
|
||||
#ifdef CONFIG_CPU_V7M
|
||||
ulong addr = (ulong)kernel_entry | 1;
|
||||
kernel_entry = (void *)addr;
|
||||
#endif
|
||||
s = env_get("machid");
|
||||
if (s) {
|
||||
if (strict_strtoul(s, 16, &machid) < 0) {
|
||||
debug("strict_strtoul failed!\n");
|
||||
return;
|
||||
}
|
||||
printf("Using machid 0x%lx from environment\n", machid);
|
||||
}
|
||||
|
||||
debug("## Transferring control to Linux (at address %08lx)" \
|
||||
"...\n", (ulong) kernel_entry);
|
||||
bootstage_mark(BOOTSTAGE_ID_RUN_OS);
|
||||
announce_and_cleanup(fake);
|
||||
|
||||
if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len)
|
||||
r2 = (unsigned long)images->ft_addr;
|
||||
else
|
||||
r2 = gd->bd->bi_boot_params;
|
||||
|
||||
if (!fake) {
|
||||
#ifdef CONFIG_ARMV7_NONSEC
|
||||
if (armv7_boot_nonsec()) {
|
||||
armv7_init_nonsec();
|
||||
secure_ram_addr(_do_nonsec_entry)(kernel_entry,
|
||||
0, machid, r2);
|
||||
} else
|
||||
#endif
|
||||
#if defined(CONFIG_ARCH_LOTUS)
|
||||
#ifdef CONFIG_TARGET_XMORCA
|
||||
r2 = relocate_dtb(images);
|
||||
show_boot_timestamp();
|
||||
kernel_entry(0, machid, r2);
|
||||
#else
|
||||
do {
|
||||
int use_bl31 = 1;
|
||||
s = env_get("use_bl31");
|
||||
if (s && (*s == 'n')) {
|
||||
use_bl31 = 0;
|
||||
}
|
||||
if (use_bl31 || (image_get_arch(&(images->legacy_hdr_os_copy)) == IH_ARCH_ARM64))
|
||||
run_bl31(images, machid);
|
||||
else
|
||||
kernel_entry(0, machid, r2);
|
||||
} while(0);
|
||||
#endif
|
||||
#else
|
||||
kernel_entry(0, machid, r2);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Main Entry point for arm bootm implementation
|
||||
*
|
||||
* Modeled after the powerpc implementation
|
||||
* DIFFERENCE: Instead of calling prep and go at the end
|
||||
* they are called if subcommand is equal 0.
|
||||
*/
|
||||
int do_bootm_linux(int flag, int argc, char * const argv[],
|
||||
bootm_headers_t *images)
|
||||
{
|
||||
/* No need for those on ARM */
|
||||
if (flag & BOOTM_STATE_OS_BD_T || flag & BOOTM_STATE_OS_CMDLINE)
|
||||
return -1;
|
||||
|
||||
if (flag & BOOTM_STATE_OS_PREP) {
|
||||
boot_prep_linux(images);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (flag & (BOOTM_STATE_OS_GO | BOOTM_STATE_OS_FAKE_GO)) {
|
||||
boot_jump_linux(images, flag);
|
||||
return 0;
|
||||
}
|
||||
|
||||
boot_prep_linux(images);
|
||||
boot_jump_linux(images, flag);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BOOTM_VXWORKS)
|
||||
void boot_prep_vxworks(bootm_headers_t *images)
|
||||
{
|
||||
#if defined(CONFIG_OF_LIBFDT)
|
||||
int off;
|
||||
|
||||
if (images->ft_addr) {
|
||||
off = fdt_path_offset(images->ft_addr, "/memory");
|
||||
if (off > 0) {
|
||||
if (arch_fixup_fdt(images->ft_addr))
|
||||
puts("## WARNING: fixup memory failed!\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
cleanup_before_linux();
|
||||
}
|
||||
void boot_jump_vxworks(bootm_headers_t *images)
|
||||
{
|
||||
#if defined(CONFIG_ARM64) && defined(CONFIG_ARMV8_PSCI)
|
||||
armv8_setup_psci();
|
||||
smp_kick_all_cpus();
|
||||
#endif
|
||||
|
||||
/* ARM VxWorks requires device tree physical address to be passed */
|
||||
((void (*)(void *))images->ep)(images->ft_addr);
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,318 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2002
|
||||
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <cpu_func.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/cache.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <asm/armv7_mpu.h>
|
||||
|
||||
#if !(CONFIG_IS_ENABLED(SYS_ICACHE_OFF) && CONFIG_IS_ENABLED(SYS_DCACHE_OFF))
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
#ifdef CONFIG_SYS_ARM_MMU
|
||||
__weak void arm_init_before_mmu(void)
|
||||
{
|
||||
}
|
||||
|
||||
__weak void arm_init_domains(void)
|
||||
{
|
||||
}
|
||||
|
||||
void set_section_dcache(int section, enum dcache_option option)
|
||||
{
|
||||
#ifdef CONFIG_ARMV7_LPAE
|
||||
u64 *page_table = (u64 *)gd->arch.tlb_addr;
|
||||
/* Need to set the access flag to not fault */
|
||||
u64 value = TTB_SECT_AP | TTB_SECT_AF;
|
||||
#else
|
||||
u32 *page_table = (u32 *)gd->arch.tlb_addr;
|
||||
u32 value = TTB_SECT_AP;
|
||||
#endif
|
||||
|
||||
/* Add the page offset */
|
||||
value |= ((u32)section << MMU_SECTION_SHIFT);
|
||||
|
||||
/* Add caching bits */
|
||||
value |= option;
|
||||
|
||||
/* Set PTE */
|
||||
page_table[section] = value;
|
||||
}
|
||||
|
||||
__weak void mmu_page_table_flush(unsigned long start, unsigned long stop)
|
||||
{
|
||||
debug("%s: Warning: not implemented\n", __func__);
|
||||
}
|
||||
|
||||
void mmu_set_region_dcache_behaviour(phys_addr_t start, size_t size,
|
||||
enum dcache_option option)
|
||||
{
|
||||
#ifdef CONFIG_ARMV7_LPAE
|
||||
u64 *page_table = (u64 *)gd->arch.tlb_addr;
|
||||
#else
|
||||
u32 *page_table = (u32 *)gd->arch.tlb_addr;
|
||||
#endif
|
||||
unsigned long startpt, stoppt;
|
||||
unsigned long upto, end;
|
||||
|
||||
end = ALIGN(start + size, MMU_SECTION_SIZE) >> MMU_SECTION_SHIFT;
|
||||
start = start >> MMU_SECTION_SHIFT;
|
||||
#ifdef CONFIG_ARMV7_LPAE
|
||||
debug("%s: start=%pa, size=%zu, option=%llx\n", __func__, &start, size,
|
||||
option);
|
||||
#else
|
||||
debug("%s: start=%pa, size=%zu, option=0x%x\n", __func__, &start, size,
|
||||
option);
|
||||
#endif
|
||||
for (upto = start; upto < end; upto++)
|
||||
set_section_dcache(upto, option);
|
||||
|
||||
/*
|
||||
* Make sure range is cache line aligned
|
||||
* Only CPU maintains page tables, hence it is safe to always
|
||||
* flush complete cache lines...
|
||||
*/
|
||||
|
||||
startpt = (unsigned long)&page_table[start];
|
||||
startpt &= ~(CONFIG_SYS_CACHELINE_SIZE - 1);
|
||||
stoppt = (unsigned long)&page_table[end];
|
||||
stoppt = ALIGN(stoppt, CONFIG_SYS_CACHELINE_SIZE);
|
||||
mmu_page_table_flush(startpt, stoppt);
|
||||
}
|
||||
|
||||
__weak void dram_bank_mmu_setup(int bank)
|
||||
{
|
||||
bd_t *bd = gd->bd;
|
||||
int i;
|
||||
|
||||
debug("%s: bank: %d\n", __func__, bank);
|
||||
for (i = bd->bi_dram[bank].start >> MMU_SECTION_SHIFT;
|
||||
i < (bd->bi_dram[bank].start >> MMU_SECTION_SHIFT) +
|
||||
(bd->bi_dram[bank].size >> MMU_SECTION_SHIFT);
|
||||
i++) {
|
||||
#if defined(CONFIG_SYS_ARM_CACHE_WRITETHROUGH)
|
||||
set_section_dcache(i, DCACHE_WRITETHROUGH);
|
||||
#elif defined(CONFIG_SYS_ARM_CACHE_WRITEALLOC)
|
||||
set_section_dcache(i, DCACHE_WRITEALLOC);
|
||||
#else
|
||||
set_section_dcache(i, DCACHE_WRITEBACK);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/* to activate the MMU we need to set up virtual memory: use 1M areas */
|
||||
static inline void mmu_setup(void)
|
||||
{
|
||||
int i;
|
||||
u32 reg;
|
||||
|
||||
arm_init_before_mmu();
|
||||
/* Set up an identity-mapping for all 4GB, rw for everyone */
|
||||
for (i = 0; i < ((4096ULL * 1024 * 1024) >> MMU_SECTION_SHIFT); i++)
|
||||
set_section_dcache(i, DCACHE_OFF);
|
||||
|
||||
for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
|
||||
dram_bank_mmu_setup(i);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_ARMV7_LPAE) && __LINUX_ARM_ARCH__ != 4
|
||||
/* Set up 4 PTE entries pointing to our 4 1GB page tables */
|
||||
for (i = 0; i < 4; i++) {
|
||||
u64 *page_table = (u64 *)(gd->arch.tlb_addr + (4096 * 4));
|
||||
u64 tpt = gd->arch.tlb_addr + (4096 * i);
|
||||
page_table[i] = tpt | TTB_PAGETABLE;
|
||||
}
|
||||
|
||||
reg = TTBCR_EAE;
|
||||
#if defined(CONFIG_SYS_ARM_CACHE_WRITETHROUGH)
|
||||
reg |= TTBCR_ORGN0_WT | TTBCR_IRGN0_WT;
|
||||
#elif defined(CONFIG_SYS_ARM_CACHE_WRITEALLOC)
|
||||
reg |= TTBCR_ORGN0_WBWA | TTBCR_IRGN0_WBWA;
|
||||
#else
|
||||
reg |= TTBCR_ORGN0_WBNWA | TTBCR_IRGN0_WBNWA;
|
||||
#endif
|
||||
|
||||
if (is_hyp()) {
|
||||
/* Set HTCR to enable LPAE */
|
||||
asm volatile("mcr p15, 4, %0, c2, c0, 2"
|
||||
: : "r" (reg) : "memory");
|
||||
/* Set HTTBR0 */
|
||||
asm volatile("mcrr p15, 4, %0, %1, c2"
|
||||
:
|
||||
: "r"(gd->arch.tlb_addr + (4096 * 4)), "r"(0)
|
||||
: "memory");
|
||||
/* Set HMAIR */
|
||||
asm volatile("mcr p15, 4, %0, c10, c2, 0"
|
||||
: : "r" (MEMORY_ATTRIBUTES) : "memory");
|
||||
} else {
|
||||
/* Set TTBCR to enable LPAE */
|
||||
asm volatile("mcr p15, 0, %0, c2, c0, 2"
|
||||
: : "r" (reg) : "memory");
|
||||
/* Set 64-bit TTBR0 */
|
||||
asm volatile("mcrr p15, 0, %0, %1, c2"
|
||||
:
|
||||
: "r"(gd->arch.tlb_addr + (4096 * 4)), "r"(0)
|
||||
: "memory");
|
||||
/* Set MAIR */
|
||||
asm volatile("mcr p15, 0, %0, c10, c2, 0"
|
||||
: : "r" (MEMORY_ATTRIBUTES) : "memory");
|
||||
}
|
||||
#elif defined(CONFIG_CPU_V7A)
|
||||
if (is_hyp()) {
|
||||
/* Set HTCR to disable LPAE */
|
||||
asm volatile("mcr p15, 4, %0, c2, c0, 2"
|
||||
: : "r" (0) : "memory");
|
||||
} else {
|
||||
/* Set TTBCR to disable LPAE */
|
||||
asm volatile("mcr p15, 0, %0, c2, c0, 2"
|
||||
: : "r" (0) : "memory");
|
||||
}
|
||||
/* Set TTBR0 */
|
||||
reg = gd->arch.tlb_addr & TTBR0_BASE_ADDR_MASK;
|
||||
#if defined(CONFIG_SYS_ARM_CACHE_WRITETHROUGH)
|
||||
reg |= TTBR0_RGN_WT | TTBR0_IRGN_WT;
|
||||
#elif defined(CONFIG_SYS_ARM_CACHE_WRITEALLOC)
|
||||
reg |= TTBR0_RGN_WBWA | TTBR0_IRGN_WBWA;
|
||||
#else
|
||||
reg |= TTBR0_RGN_WB | TTBR0_IRGN_WB;
|
||||
#endif
|
||||
asm volatile("mcr p15, 0, %0, c2, c0, 0"
|
||||
: : "r" (reg) : "memory");
|
||||
#else
|
||||
/* Copy the page table address to cp15 */
|
||||
asm volatile("mcr p15, 0, %0, c2, c0, 0"
|
||||
: : "r" (gd->arch.tlb_addr) : "memory");
|
||||
#endif
|
||||
/* Set the access control to all-supervisor */
|
||||
asm volatile("mcr p15, 0, %0, c3, c0, 0"
|
||||
: : "r" (~0));
|
||||
|
||||
arm_init_domains();
|
||||
|
||||
/* and enable the mmu */
|
||||
reg = get_cr(); /* get control reg. */
|
||||
set_cr(reg | CR_M);
|
||||
}
|
||||
|
||||
static int mmu_enabled(void)
|
||||
{
|
||||
return get_cr() & CR_M;
|
||||
}
|
||||
#endif /* CONFIG_SYS_ARM_MMU */
|
||||
|
||||
/* cache_bit must be either CR_I or CR_C */
|
||||
static void cache_enable(uint32_t cache_bit)
|
||||
{
|
||||
uint32_t reg;
|
||||
|
||||
/* The data cache is not active unless the mmu/mpu is enabled too */
|
||||
#ifdef CONFIG_SYS_ARM_MMU
|
||||
if ((cache_bit == CR_C) && !mmu_enabled())
|
||||
mmu_setup();
|
||||
#elif defined(CONFIG_SYS_ARM_MPU)
|
||||
if ((cache_bit == CR_C) && !mpu_enabled()) {
|
||||
printf("Consider enabling MPU before enabling caches\n");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
reg = get_cr(); /* get control reg. */
|
||||
set_cr(reg | cache_bit);
|
||||
}
|
||||
|
||||
/* cache_bit must be either CR_I or CR_C */
|
||||
static void cache_disable(uint32_t cache_bit)
|
||||
{
|
||||
uint32_t reg;
|
||||
|
||||
reg = get_cr();
|
||||
|
||||
if (cache_bit == CR_C) {
|
||||
/* if cache isn;t enabled no need to disable */
|
||||
if ((reg & CR_C) != CR_C)
|
||||
return;
|
||||
#ifdef CONFIG_SYS_ARM_MMU
|
||||
/* if disabling data cache, disable mmu too */
|
||||
cache_bit |= CR_M;
|
||||
#endif
|
||||
}
|
||||
reg = get_cr();
|
||||
|
||||
#ifdef CONFIG_SYS_ARM_MMU
|
||||
if (cache_bit == (CR_C | CR_M))
|
||||
#elif defined(CONFIG_SYS_ARM_MPU)
|
||||
if (cache_bit == CR_C)
|
||||
#endif
|
||||
flush_dcache_all();
|
||||
set_cr(reg & ~cache_bit);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if CONFIG_IS_ENABLED(SYS_ICACHE_OFF)
|
||||
void icache_enable(void)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void icache_disable(void)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int icache_status(void)
|
||||
{
|
||||
return 0; /* always off */
|
||||
}
|
||||
#else
|
||||
void icache_enable(void)
|
||||
{
|
||||
cache_enable(CR_I);
|
||||
}
|
||||
|
||||
void icache_disable(void)
|
||||
{
|
||||
cache_disable(CR_I);
|
||||
}
|
||||
|
||||
int icache_status(void)
|
||||
{
|
||||
return (get_cr() & CR_I) != 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if CONFIG_IS_ENABLED(SYS_DCACHE_OFF)
|
||||
void dcache_enable(void)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void dcache_disable(void)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int dcache_status(void)
|
||||
{
|
||||
return 0; /* always off */
|
||||
}
|
||||
#else
|
||||
void dcache_enable(void)
|
||||
{
|
||||
cache_enable(CR_C);
|
||||
}
|
||||
|
||||
void dcache_disable(void)
|
||||
{
|
||||
cache_disable(CR_C);
|
||||
}
|
||||
|
||||
int dcache_status(void)
|
||||
{
|
||||
return (get_cr() & CR_C) != 0;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,101 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2010
|
||||
* Texas Instruments, <www.ti.com>
|
||||
* Aneesh V <aneesh@ti.com>
|
||||
*/
|
||||
#include <linux/types.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/armv7.h>
|
||||
#include <asm/pl310.h>
|
||||
#include <config.h>
|
||||
#include <common.h>
|
||||
|
||||
struct pl310_regs *const pl310 = (struct pl310_regs *)CONFIG_SYS_PL310_BASE;
|
||||
|
||||
static void pl310_cache_sync(void)
|
||||
{
|
||||
writel(0, &pl310->pl310_cache_sync);
|
||||
}
|
||||
|
||||
static void pl310_background_op_all_ways(u32 *op_reg)
|
||||
{
|
||||
u32 assoc_16, associativity, way_mask;
|
||||
|
||||
assoc_16 = readl(&pl310->pl310_aux_ctrl) &
|
||||
PL310_AUX_CTRL_ASSOCIATIVITY_MASK;
|
||||
if (assoc_16)
|
||||
associativity = 16;
|
||||
else
|
||||
associativity = 8;
|
||||
|
||||
way_mask = (1 << associativity) - 1;
|
||||
/* Invalidate all ways */
|
||||
writel(way_mask, op_reg);
|
||||
/* Wait for all ways to be invalidated */
|
||||
while (readl(op_reg) & way_mask)
|
||||
;
|
||||
pl310_cache_sync();
|
||||
}
|
||||
|
||||
void v7_outer_cache_inval_all(void)
|
||||
{
|
||||
pl310_background_op_all_ways(&pl310->pl310_inv_way);
|
||||
}
|
||||
|
||||
void v7_outer_cache_flush_all(void)
|
||||
{
|
||||
pl310_background_op_all_ways(&pl310->pl310_clean_inv_way);
|
||||
}
|
||||
|
||||
/* Flush(clean invalidate) memory from start to stop-1 */
|
||||
void v7_outer_cache_flush_range(u32 start, u32 stop)
|
||||
{
|
||||
/* PL310 currently supports only 32 bytes cache line */
|
||||
u32 pa, line_size = 32;
|
||||
|
||||
/*
|
||||
* Align to the beginning of cache-line - this ensures that
|
||||
* the first 5 bits are 0 as required by PL310 TRM
|
||||
*/
|
||||
start &= ~(line_size - 1);
|
||||
|
||||
for (pa = start; pa < stop; pa = pa + line_size)
|
||||
writel(pa, &pl310->pl310_clean_inv_line_pa);
|
||||
|
||||
pl310_cache_sync();
|
||||
}
|
||||
|
||||
/* invalidate memory from start to stop-1 */
|
||||
void v7_outer_cache_inval_range(u32 start, u32 stop)
|
||||
{
|
||||
/* PL310 currently supports only 32 bytes cache line */
|
||||
u32 pa, line_size = 32;
|
||||
|
||||
/*
|
||||
* If start address is not aligned to cache-line do not
|
||||
* invalidate the first cache-line
|
||||
*/
|
||||
if (start & (line_size - 1)) {
|
||||
printf("ERROR: %s - start address is not aligned - 0x%08x\n",
|
||||
__func__, start);
|
||||
/* move to next cache line */
|
||||
start = (start + line_size - 1) & ~(line_size - 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* If stop address is not aligned to cache-line do not
|
||||
* invalidate the last cache-line
|
||||
*/
|
||||
if (stop & (line_size - 1)) {
|
||||
printf("ERROR: %s - stop address is not aligned - 0x%08x\n",
|
||||
__func__, stop);
|
||||
/* align to the beginning of this cache line */
|
||||
stop &= ~(line_size - 1);
|
||||
}
|
||||
|
||||
for (pa = start; pa < stop; pa = pa + line_size)
|
||||
writel(pa, &pl310->pl310_inv_line_pa);
|
||||
|
||||
pl310_cache_sync();
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2002
|
||||
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
*/
|
||||
|
||||
/* for now: just dummy functions to satisfy the linker */
|
||||
|
||||
#include <common.h>
|
||||
#include <cpu_func.h>
|
||||
#include <malloc.h>
|
||||
|
||||
/*
|
||||
* Flush range from all levels of d-cache/unified-cache.
|
||||
* Affects the range [start, start + size - 1].
|
||||
*/
|
||||
__weak void flush_cache(unsigned long start, unsigned long size)
|
||||
{
|
||||
flush_dcache_range(start, start + size);
|
||||
}
|
||||
|
||||
/*
|
||||
* Default implementation:
|
||||
* do a range flush for the entire range
|
||||
*/
|
||||
__weak void flush_dcache_all(void)
|
||||
{
|
||||
flush_cache(0, ~0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Default implementation of enable_caches()
|
||||
* Real implementation should be in platform code
|
||||
*/
|
||||
__weak void enable_caches(void)
|
||||
{
|
||||
puts("WARNING: Caches not enabled\n");
|
||||
}
|
||||
|
||||
__weak void invalidate_dcache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
/* An empty stub, real implementation should be in platform code */
|
||||
}
|
||||
__weak void flush_dcache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
/* An empty stub, real implementation should be in platform code */
|
||||
}
|
||||
|
||||
int check_cache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
int ok = 1;
|
||||
|
||||
if (start & (CONFIG_SYS_CACHELINE_SIZE - 1))
|
||||
ok = 0;
|
||||
|
||||
if (stop & (CONFIG_SYS_CACHELINE_SIZE - 1))
|
||||
ok = 0;
|
||||
|
||||
if (!ok) {
|
||||
warn_non_spl("CACHE: Misaligned operation at range [%08lx, %08lx]\n",
|
||||
start, stop);
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SYS_NONCACHED_MEMORY
|
||||
/*
|
||||
* Reserve one MMU section worth of address space below the malloc() area that
|
||||
* will be mapped uncached.
|
||||
*/
|
||||
static unsigned long noncached_start;
|
||||
static unsigned long noncached_end;
|
||||
static unsigned long noncached_next;
|
||||
|
||||
void noncached_init(void)
|
||||
{
|
||||
phys_addr_t start, end;
|
||||
size_t size;
|
||||
|
||||
/* If this calculation changes, update board_f.c:reserve_noncached() */
|
||||
end = ALIGN(mem_malloc_start, MMU_SECTION_SIZE) - MMU_SECTION_SIZE;
|
||||
size = ALIGN(CONFIG_SYS_NONCACHED_MEMORY, MMU_SECTION_SIZE);
|
||||
start = end - size;
|
||||
|
||||
debug("mapping memory %pa-%pa non-cached\n", &start, &end);
|
||||
|
||||
noncached_start = start;
|
||||
noncached_end = end;
|
||||
noncached_next = start;
|
||||
|
||||
#if !CONFIG_IS_ENABLED(SYS_DCACHE_OFF)
|
||||
mmu_set_region_dcache_behaviour(noncached_start, size, DCACHE_OFF);
|
||||
#endif
|
||||
}
|
||||
|
||||
phys_addr_t noncached_alloc(size_t size, size_t align)
|
||||
{
|
||||
phys_addr_t next = ALIGN(noncached_next, align);
|
||||
|
||||
if (next >= noncached_end || (noncached_end - next) < size)
|
||||
return 0;
|
||||
|
||||
debug("allocated %zu bytes of uncached memory @%pa\n", size, &next);
|
||||
noncached_next = next + size;
|
||||
|
||||
return next;
|
||||
}
|
||||
#endif /* CONFIG_SYS_NONCACHED_MEMORY */
|
||||
|
||||
#if CONFIG_IS_ENABLED(SYS_THUMB_BUILD)
|
||||
void invalidate_l2_cache(void)
|
||||
{
|
||||
unsigned int val = 0;
|
||||
|
||||
asm volatile("mcr p15, 1, %0, c15, c11, 0 @ invl l2 cache"
|
||||
: : "r" (val) : "cc");
|
||||
isb();
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,81 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* (C) Copyright 2015 Freescale Semiconductor
|
||||
*
|
||||
* Extracted from gic_64.S
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/macro.h>
|
||||
|
||||
/*************************************************************************
|
||||
*
|
||||
* void ccn504_add_masters_to_dvm(CCI_MN_BASE, CCI_MN_RNF_NODEID_LIST,
|
||||
* CCI_MN_DVM_DOMAIN_CTL_SET);
|
||||
*
|
||||
* Add fully-coherent masters to DVM domain
|
||||
*
|
||||
*************************************************************************/
|
||||
ENTRY(ccn504_add_masters_to_dvm)
|
||||
/*
|
||||
* x0: CCI_MN_BASE
|
||||
* x1: CCI_MN_RNF_NODEID_LIST
|
||||
* x2: CCI_MN_DVM_DOMAIN_CTL_SET
|
||||
*/
|
||||
|
||||
/* Add fully-coherent masters to DVM domain */
|
||||
ldr x9, [x0, x1]
|
||||
str x9, [x0, x2]
|
||||
1: ldr x10, [x0, x2]
|
||||
mvn x11, x10
|
||||
tst x11, x10 /* Wait for domain addition to complete */
|
||||
b.ne 1b
|
||||
|
||||
ret
|
||||
ENDPROC(ccn504_add_masters_to_dvm)
|
||||
|
||||
/*************************************************************************
|
||||
*
|
||||
* void ccn504_set_qos(CCI_Sx_QOS_CONTROL_BASE, QoS Value);
|
||||
*
|
||||
* Initialize QoS settings for AR/AW override.
|
||||
* Right now, this function sets the same QoS value for all RN-I ports
|
||||
*
|
||||
*************************************************************************/
|
||||
ENTRY(ccn504_set_qos)
|
||||
/*
|
||||
* x0: CCI_Sx_QOS_CONTROL_BASE
|
||||
* x1: QoS Value
|
||||
*/
|
||||
|
||||
/* Set all RN-I ports to QoS value denoted by x1 */
|
||||
ldr x9, [x0]
|
||||
mov x10, x1
|
||||
orr x9, x9, x10
|
||||
str x9, [x0]
|
||||
|
||||
ret
|
||||
ENDPROC(ccn504_set_qos)
|
||||
|
||||
/*************************************************************************
|
||||
*
|
||||
* void ccn504_set_aux(CCI_AUX_CONTROL_BASE, Value);
|
||||
*
|
||||
* Initialize AUX control settings
|
||||
*
|
||||
*************************************************************************/
|
||||
ENTRY(ccn504_set_aux)
|
||||
/*
|
||||
* x0: CCI_AUX_CONTROL_BASE
|
||||
* x1: Value
|
||||
*/
|
||||
|
||||
ldr x9, [x0]
|
||||
mov x10, x1
|
||||
orr x9, x9, x10
|
||||
str x9, [x0]
|
||||
|
||||
ret
|
||||
ENDPROC(ccn504_set_aux)
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2008-2011
|
||||
* Graeme Russ, <graeme.russ@gmail.com>
|
||||
*
|
||||
* (C) Copyright 2002
|
||||
* Daniel Engström, Omicron Ceti AB, <daniel@omicron.se>
|
||||
*
|
||||
* (C) Copyright 2002
|
||||
* Wolfgang Denk, DENX Software Engineering, <wd@denx.de>
|
||||
*
|
||||
* (C) Copyright 2002
|
||||
* Sysgo Real-Time Solutions, GmbH <www.elinos.com>
|
||||
* Marius Groeger <mgroeger@sysgo.de>
|
||||
*
|
||||
* Copyright 2015 ATS Advanced Telematics Systems GmbH
|
||||
* Copyright 2015 Konsulko Group, Matt Porter <mporter@konsulko.com>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
|
||||
/*
|
||||
* ARMv7M does not support ARM instruction mode. However, the
|
||||
* interworking BLX and BX instructions do encode the ARM/Thumb
|
||||
* field in bit 0. This means that when executing any Branch
|
||||
* and eXchange instruction we must set bit 0 to one to guarantee
|
||||
* that we keep the processor in Thumb instruction mode. From The
|
||||
* ARMv7-M Instruction Set A4.1.1:
|
||||
* "ARMv7-M only supports the Thumb instruction execution state,
|
||||
* therefore the value of address bit [0] must be 1 in interworking
|
||||
* instructions, otherwise a fault occurs."
|
||||
*/
|
||||
unsigned long do_go_exec(ulong (*entry)(int, char * const []),
|
||||
int argc, char * const argv[])
|
||||
{
|
||||
ulong addr = (ulong)entry | 1;
|
||||
entry = (void *)addr;
|
||||
|
||||
return entry(argc, argv);
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* crt0 - C-runtime startup Code for ARM U-Boot
|
||||
*
|
||||
* Copyright (c) 2012 Albert ARIBAUD <albert.u.boot@aribaud.net>
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <asm-offsets.h>
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/assembler.h>
|
||||
|
||||
#include <linux/lotus/step.h>
|
||||
|
||||
/*
|
||||
* This file handles the target-independent stages of the U-Boot
|
||||
* start-up where a C runtime environment is needed. Its entry point
|
||||
* is _main and is branched into from the target's start.S file.
|
||||
*
|
||||
* _main execution sequence is:
|
||||
*
|
||||
* 1. Set up initial environment for calling board_init_f().
|
||||
* This environment only provides a stack and a place to store
|
||||
* the GD ('global data') structure, both located in some readily
|
||||
* available RAM (SRAM, locked cache...). In this context, VARIABLE
|
||||
* global data, initialized or not (BSS), are UNAVAILABLE; only
|
||||
* CONSTANT initialized data are available. GD should be zeroed
|
||||
* before board_init_f() is called.
|
||||
*
|
||||
* 2. Call board_init_f(). This function prepares the hardware for
|
||||
* execution from system RAM (DRAM, DDR...) As system RAM may not
|
||||
* be available yet, , board_init_f() must use the current GD to
|
||||
* store any data which must be passed on to later stages. These
|
||||
* data include the relocation destination, the future stack, and
|
||||
* the future GD location.
|
||||
*
|
||||
* 3. Set up intermediate environment where the stack and GD are the
|
||||
* ones allocated by board_init_f() in system RAM, but BSS and
|
||||
* initialized non-const data are still not available.
|
||||
*
|
||||
* 4a.For U-Boot proper (not SPL), call relocate_code(). This function
|
||||
* relocates U-Boot from its current location into the relocation
|
||||
* destination computed by board_init_f().
|
||||
*
|
||||
* 4b.For SPL, board_init_f() just returns (to crt0). There is no
|
||||
* code relocation in SPL.
|
||||
*
|
||||
* 5. Set up final environment for calling board_init_r(). This
|
||||
* environment has BSS (initialized to 0), initialized non-const
|
||||
* data (initialized to their intended value), and stack in system
|
||||
* RAM (for SPL moving the stack and GD into RAM is optional - see
|
||||
* CONFIG_SPL_STACK_R). GD has retained values set by board_init_f().
|
||||
*
|
||||
* 6. For U-Boot proper (not SPL), some CPUs have some work left to do
|
||||
* at this point regarding memory, so call c_runtime_cpu_setup.
|
||||
*
|
||||
* 7. Branch to board_init_r().
|
||||
*
|
||||
* For more information see 'Board Initialisation Flow in README.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Macro for clearing BSS during SPL execution. Usually called during the
|
||||
* relocation process for most boards before entering board_init_r(), but
|
||||
* can also be done early before entering board_init_f() on plaforms that
|
||||
* can afford it due to sufficient memory being available early.
|
||||
*/
|
||||
|
||||
.macro SPL_CLEAR_BSS
|
||||
ldr r0, =__bss_start /* this is auto-relocated! */
|
||||
|
||||
#ifdef CONFIG_USE_ARCH_MEMSET
|
||||
ldr r3, =__bss_end /* this is auto-relocated! */
|
||||
mov r1, #0x00000000 /* prepare zero to clear BSS */
|
||||
|
||||
subs r2, r3, r0 /* r2 = memset len */
|
||||
bl memset
|
||||
#else
|
||||
ldr r1, =__bss_end /* this is auto-relocated! */
|
||||
mov r2, #0x00000000 /* prepare zero to clear BSS */
|
||||
|
||||
clbss_l:cmp r0, r1 /* while not at end of BSS */
|
||||
strlo r2, [r0] /* clear 32-bit BSS word */
|
||||
addlo r0, r0, #4 /* move to next */
|
||||
blo clbss_l
|
||||
#endif
|
||||
.endm
|
||||
|
||||
/*
|
||||
* entry point of crt0 sequence
|
||||
*/
|
||||
|
||||
ENTRY(_main)
|
||||
step_no_stack 52, r11, r12
|
||||
/*
|
||||
* Set up initial C runtime environment and call board_init_f(0).
|
||||
*/
|
||||
|
||||
#if defined(CONFIG_TPL_BUILD) && defined(CONFIG_TPL_NEEDS_SEPARATE_STACK)
|
||||
ldr r0, =(CONFIG_TPL_STACK)
|
||||
#elif defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK)
|
||||
ldr r0, =(CONFIG_SPL_STACK)
|
||||
#else
|
||||
ldr r0, =(CONFIG_SYS_INIT_SP_ADDR)
|
||||
#endif
|
||||
bic r0, r0, #7 /* 8-byte alignment for ABI compliance */
|
||||
mov sp, r0
|
||||
bl board_init_f_alloc_reserve
|
||||
mov sp, r0
|
||||
/* set up gd here, outside any C code */
|
||||
mov r9, r0
|
||||
bl board_init_f_init_reserve
|
||||
|
||||
step 53
|
||||
#if defined(CONFIG_SPL_EARLY_BSS)
|
||||
SPL_CLEAR_BSS
|
||||
#endif
|
||||
|
||||
mov r0, #0
|
||||
bl board_init_f
|
||||
|
||||
#if ! defined(CONFIG_SPL_BUILD)
|
||||
|
||||
/*
|
||||
* Set up intermediate environment (new sp and gd) and call
|
||||
* relocate_code(addr_moni). Trick here is that we'll return
|
||||
* 'here' but relocated.
|
||||
*/
|
||||
|
||||
ldr r0, [r9, #GD_START_ADDR_SP] /* sp = gd->start_addr_sp */
|
||||
bic r0, r0, #7 /* 8-byte alignment for ABI compliance */
|
||||
mov sp, r0
|
||||
ldr r9, [r9, #GD_BD] /* r9 = gd->bd */
|
||||
sub r9, r9, #GD_SIZE /* new GD is below bd */
|
||||
|
||||
adr lr, here
|
||||
ldr r0, [r9, #GD_RELOC_OFF] /* r0 = gd->reloc_off */
|
||||
add lr, lr, r0
|
||||
#if defined(CONFIG_CPU_V7M)
|
||||
orr lr, #1 /* As required by Thumb-only */
|
||||
#endif
|
||||
ldr r0, [r9, #GD_RELOCADDR] /* r0 = gd->relocaddr */
|
||||
b relocate_code
|
||||
here:
|
||||
/*
|
||||
* now relocate vectors
|
||||
*/
|
||||
|
||||
bl relocate_vectors
|
||||
|
||||
/* Set up final (full) environment */
|
||||
|
||||
bl c_runtime_cpu_setup /* we still call old routine here */
|
||||
#endif
|
||||
#if !defined(CONFIG_SPL_BUILD) || CONFIG_IS_ENABLED(FRAMEWORK)
|
||||
|
||||
#if !defined(CONFIG_SPL_EARLY_BSS)
|
||||
SPL_CLEAR_BSS
|
||||
#endif
|
||||
|
||||
# ifdef CONFIG_SPL_BUILD
|
||||
/* Use a DRAM stack for the rest of SPL, if requested */
|
||||
bl spl_relocate_stack_gd
|
||||
cmp r0, #0
|
||||
movne sp, r0
|
||||
movne r9, r0
|
||||
# endif
|
||||
|
||||
#if ! defined(CONFIG_SPL_BUILD)
|
||||
bl coloured_LED_init
|
||||
bl red_led_on
|
||||
#endif
|
||||
/* call board_init_r(gd_t *id, ulong dest_addr) */
|
||||
mov r0, r9 /* gd_t */
|
||||
ldr r1, [r9, #GD_RELOCADDR] /* dest_addr */
|
||||
/* call board_init_r */
|
||||
#if CONFIG_IS_ENABLED(SYS_THUMB_BUILD)
|
||||
ldr lr, =board_init_r /* this is auto-relocated! */
|
||||
bx lr
|
||||
#else
|
||||
ldr pc, =board_init_r /* this is auto-relocated! */
|
||||
#endif
|
||||
/* we should not return here. */
|
||||
#endif
|
||||
|
||||
ENDPROC(_main)
|
||||
@@ -0,0 +1,158 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* crt0 - C-runtime startup Code for AArch64 U-Boot
|
||||
*
|
||||
* (C) Copyright 2013
|
||||
* David Feng <fenghua@phytium.com.cn>
|
||||
*
|
||||
* (C) Copyright 2012
|
||||
* Albert ARIBAUD <albert.u.boot@aribaud.net>
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <asm-offsets.h>
|
||||
#include <asm/macro.h>
|
||||
#include <linux/linkage.h>
|
||||
|
||||
/*
|
||||
* This file handles the target-independent stages of the U-Boot
|
||||
* start-up where a C runtime environment is needed. Its entry point
|
||||
* is _main and is branched into from the target's start.S file.
|
||||
*
|
||||
* _main execution sequence is:
|
||||
*
|
||||
* 1. Set up initial environment for calling board_init_f().
|
||||
* This environment only provides a stack and a place to store
|
||||
* the GD ('global data') structure, both located in some readily
|
||||
* available RAM (SRAM, locked cache...). In this context, VARIABLE
|
||||
* global data, initialized or not (BSS), are UNAVAILABLE; only
|
||||
* CONSTANT initialized data are available. GD should be zeroed
|
||||
* before board_init_f() is called.
|
||||
*
|
||||
* 2. Call board_init_f(). This function prepares the hardware for
|
||||
* execution from system RAM (DRAM, DDR...) As system RAM may not
|
||||
* be available yet, , board_init_f() must use the current GD to
|
||||
* store any data which must be passed on to later stages. These
|
||||
* data include the relocation destination, the future stack, and
|
||||
* the future GD location.
|
||||
*
|
||||
* 3. Set up intermediate environment where the stack and GD are the
|
||||
* ones allocated by board_init_f() in system RAM, but BSS and
|
||||
* initialized non-const data are still not available.
|
||||
*
|
||||
* 4a.For U-Boot proper (not SPL), call relocate_code(). This function
|
||||
* relocates U-Boot from its current location into the relocation
|
||||
* destination computed by board_init_f().
|
||||
*
|
||||
* 4b.For SPL, board_init_f() just returns (to crt0). There is no
|
||||
* code relocation in SPL.
|
||||
*
|
||||
* 5. Set up final environment for calling board_init_r(). This
|
||||
* environment has BSS (initialized to 0), initialized non-const
|
||||
* data (initialized to their intended value), and stack in system
|
||||
* RAM (for SPL moving the stack and GD into RAM is optional - see
|
||||
* CONFIG_SPL_STACK_R). GD has retained values set by board_init_f().
|
||||
*
|
||||
* TODO: For SPL, implement stack relocation on AArch64.
|
||||
*
|
||||
* 6. For U-Boot proper (not SPL), some CPUs have some work left to do
|
||||
* at this point regarding memory, so call c_runtime_cpu_setup.
|
||||
*
|
||||
* 7. Branch to board_init_r().
|
||||
*
|
||||
* For more information see 'Board Initialisation Flow in README.
|
||||
*/
|
||||
|
||||
ENTRY(_main)
|
||||
|
||||
/*
|
||||
* Set up initial C runtime environment and call board_init_f(0).
|
||||
*/
|
||||
#if defined(CONFIG_TPL_BUILD) && defined(CONFIG_TPL_NEEDS_SEPARATE_STACK)
|
||||
ldr x0, =(CONFIG_TPL_STACK)
|
||||
#elif defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK)
|
||||
ldr x0, =(CONFIG_SPL_STACK)
|
||||
#elif defined(CONFIG_INIT_SP_RELATIVE)
|
||||
adr x0, __bss_start
|
||||
add x0, x0, #CONFIG_SYS_INIT_SP_BSS_OFFSET
|
||||
#else
|
||||
ldr x0, =(CONFIG_SYS_INIT_SP_ADDR)
|
||||
#endif
|
||||
bic sp, x0, #0xf /* 16-byte alignment for ABI compliance */
|
||||
mov x0, sp
|
||||
bl board_init_f_alloc_reserve
|
||||
mov sp, x0
|
||||
/* set up gd here, outside any C code */
|
||||
mov x18, x0
|
||||
bl board_init_f_init_reserve
|
||||
|
||||
mov x0, #0
|
||||
bl board_init_f
|
||||
|
||||
#if !defined(CONFIG_SPL_BUILD)
|
||||
/*
|
||||
* Set up intermediate environment (new sp and gd) and call
|
||||
* relocate_code(addr_moni). Trick here is that we'll return
|
||||
* 'here' but relocated.
|
||||
*/
|
||||
ldr x0, [x18, #GD_START_ADDR_SP] /* x0 <- gd->start_addr_sp */
|
||||
bic sp, x0, #0xf /* 16-byte alignment for ABI compliance */
|
||||
ldr x18, [x18, #GD_NEW_GD] /* x18 <- gd->new_gd */
|
||||
|
||||
adr lr, relocation_return
|
||||
#if CONFIG_POSITION_INDEPENDENT
|
||||
/* Add in link-vs-runtime offset */
|
||||
adr x0, _start /* x0 <- Runtime value of _start */
|
||||
ldr x9, _TEXT_BASE /* x9 <- Linked value of _start */
|
||||
sub x9, x9, x0 /* x9 <- Run-vs-link offset */
|
||||
add lr, lr, x9
|
||||
#endif
|
||||
/* Add in link-vs-relocation offset */
|
||||
ldr x9, [x18, #GD_RELOC_OFF] /* x9 <- gd->reloc_off */
|
||||
add lr, lr, x9 /* new return address after relocation */
|
||||
ldr x0, [x18, #GD_RELOCADDR] /* x0 <- gd->relocaddr */
|
||||
b relocate_code
|
||||
|
||||
relocation_return:
|
||||
|
||||
/*
|
||||
* Set up final (full) environment
|
||||
*/
|
||||
bl c_runtime_cpu_setup /* still call old routine */
|
||||
#endif /* !CONFIG_SPL_BUILD */
|
||||
#if !defined(CONFIG_SPL_BUILD) || CONFIG_IS_ENABLED(FRAMEWORK)
|
||||
#if defined(CONFIG_SPL_BUILD)
|
||||
bl spl_relocate_stack_gd /* may return NULL */
|
||||
/* set up gd here, outside any C code, if new stack is returned */
|
||||
cmp x0, #0
|
||||
csel x18, x0, x18, ne
|
||||
/*
|
||||
* Perform 'sp = (x0 != NULL) ? x0 : sp' while working
|
||||
* around the constraint that conditional moves can not
|
||||
* have 'sp' as an operand
|
||||
*/
|
||||
mov x1, sp
|
||||
cmp x0, #0
|
||||
csel x0, x0, x1, ne
|
||||
mov sp, x0
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Clear BSS section
|
||||
*/
|
||||
ldr x0, =__bss_start /* this is auto-relocated! */
|
||||
ldr x1, =__bss_end /* this is auto-relocated! */
|
||||
clear_loop:
|
||||
str xzr, [x0], #8
|
||||
cmp x0, x1
|
||||
b.lo clear_loop
|
||||
|
||||
/* call board_init_r(gd_t *id, ulong dest_addr) */
|
||||
mov x0, x18 /* gd_t */
|
||||
ldr x1, [x18, #GD_RELOCADDR] /* dest_addr */
|
||||
b board_init_r /* PC relative jump */
|
||||
|
||||
/* NOTREACHED - board_init_r() does not return */
|
||||
#endif
|
||||
|
||||
ENDPROC(_main)
|
||||
@@ -0,0 +1,134 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ OR BSD-2-Clause */
|
||||
/*
|
||||
* crt0-efi-aarch64.S - PE/COFF header for aarch64 EFI applications
|
||||
*
|
||||
* Copright (C) 2014 Linaro Ltd. <ard.biesheuvel@linaro.org>
|
||||
*
|
||||
*
|
||||
* This file is taken and modified from the gnu-efi project.
|
||||
*/
|
||||
|
||||
#include <asm-generic/pe.h>
|
||||
|
||||
.section .text.head
|
||||
|
||||
/*
|
||||
* Magic "MZ" signature for PE/COFF
|
||||
*/
|
||||
.globl ImageBase
|
||||
ImageBase:
|
||||
.short IMAGE_DOS_SIGNATURE /* 'MZ' */
|
||||
.skip 58 /* 'MZ' + pad + offset == 64 */
|
||||
.long pe_header - ImageBase /* Offset to the PE header */
|
||||
pe_header:
|
||||
.long IMAGE_NT_SIGNATURE /* 'PE' */
|
||||
coff_header:
|
||||
.short IMAGE_FILE_MACHINE_ARM64 /* AArch64 */
|
||||
.short 2 /* nr_sections */
|
||||
.long 0 /* TimeDateStamp */
|
||||
.long 0 /* PointerToSymbolTable */
|
||||
.long 0 /* NumberOfSymbols */
|
||||
.short section_table - optional_header /* SizeOfOptionalHeader */
|
||||
/* Characteristics */
|
||||
.short (IMAGE_FILE_EXECUTABLE_IMAGE | \
|
||||
IMAGE_FILE_LINE_NUMS_STRIPPED | \
|
||||
IMAGE_FILE_LOCAL_SYMS_STRIPPED | \
|
||||
IMAGE_FILE_DEBUG_STRIPPED)
|
||||
optional_header:
|
||||
.short IMAGE_NT_OPTIONAL_HDR64_MAGIC /* PE32+ format */
|
||||
.byte 0x02 /* MajorLinkerVersion */
|
||||
.byte 0x14 /* MinorLinkerVersion */
|
||||
.long _edata - _start /* SizeOfCode */
|
||||
.long 0 /* SizeOfInitializedData */
|
||||
.long 0 /* SizeOfUninitializedData */
|
||||
.long _start - ImageBase /* AddressOfEntryPoint */
|
||||
.long _start - ImageBase /* BaseOfCode */
|
||||
|
||||
extra_header_fields:
|
||||
.quad 0 /* ImageBase */
|
||||
.long 0x20 /* SectionAlignment */
|
||||
.long 0x8 /* FileAlignment */
|
||||
.short 0 /* MajorOperatingSystemVersion */
|
||||
.short 0 /* MinorOperatingSystemVersion */
|
||||
.short 0 /* MajorImageVersion */
|
||||
.short 0 /* MinorImageVersion */
|
||||
.short 0 /* MajorSubsystemVersion */
|
||||
.short 0 /* MinorSubsystemVersion */
|
||||
.long 0 /* Win32VersionValue */
|
||||
|
||||
.long _edata - ImageBase /* SizeOfImage */
|
||||
|
||||
/*
|
||||
* Everything before the kernel image is considered part of the header
|
||||
*/
|
||||
.long _start - ImageBase /* SizeOfHeaders */
|
||||
.long 0 /* CheckSum */
|
||||
.short IMAGE_SUBSYSTEM_EFI_APPLICATION /* Subsystem */
|
||||
.short 0 /* DllCharacteristics */
|
||||
.quad 0 /* SizeOfStackReserve */
|
||||
.quad 0 /* SizeOfStackCommit */
|
||||
.quad 0 /* SizeOfHeapReserve */
|
||||
.quad 0 /* SizeOfHeapCommit */
|
||||
.long 0 /* LoaderFlags */
|
||||
.long 0x6 /* NumberOfRvaAndSizes */
|
||||
|
||||
.quad 0 /* ExportTable */
|
||||
.quad 0 /* ImportTable */
|
||||
.quad 0 /* ResourceTable */
|
||||
.quad 0 /* ExceptionTable */
|
||||
.quad 0 /* CertificationTable */
|
||||
.quad 0 /* BaseRelocationTable */
|
||||
|
||||
/* Section table */
|
||||
section_table:
|
||||
|
||||
/*
|
||||
* The EFI application loader requires a relocation section
|
||||
* because EFI applications must be relocatable. This is a
|
||||
* dummy section as far as we are concerned.
|
||||
*/
|
||||
.ascii ".reloc"
|
||||
.byte 0
|
||||
.byte 0 /* end of 0 padding of section name */
|
||||
.long 0
|
||||
.long 0
|
||||
.long 0 /* SizeOfRawData */
|
||||
.long 0 /* PointerToRawData */
|
||||
.long 0 /* PointerToRelocations */
|
||||
.long 0 /* PointerToLineNumbers */
|
||||
.short 0 /* NumberOfRelocations */
|
||||
.short 0 /* NumberOfLineNumbers */
|
||||
.long 0x42100040 /* Characteristics (section flags) */
|
||||
|
||||
|
||||
.ascii ".text"
|
||||
.byte 0
|
||||
.byte 0
|
||||
.byte 0 /* end of 0 padding of section name */
|
||||
.long _edata - _start /* VirtualSize */
|
||||
.long _start - ImageBase /* VirtualAddress */
|
||||
.long _edata - _start /* SizeOfRawData */
|
||||
.long _start - ImageBase /* PointerToRawData */
|
||||
|
||||
.long 0 /* PointerToRelocations (0 for executables) */
|
||||
.long 0 /* PointerToLineNumbers (0 for executables) */
|
||||
.short 0 /* NumberOfRelocations (0 for executables) */
|
||||
.short 0 /* NumberOfLineNumbers (0 for executables) */
|
||||
.long 0xe0500020 /* Characteristics (section flags) */
|
||||
|
||||
_start:
|
||||
stp x29, x30, [sp, #-32]!
|
||||
mov x29, sp
|
||||
|
||||
stp x0, x1, [sp, #16]
|
||||
adr x0, ImageBase
|
||||
adrp x1, _DYNAMIC
|
||||
add x1, x1, #:lo12:_DYNAMIC
|
||||
bl _relocate
|
||||
cbnz x0, 0f
|
||||
|
||||
ldp x0, x1, [sp, #16]
|
||||
bl efi_main
|
||||
|
||||
0: ldp x29, x30, [sp], #32
|
||||
ret
|
||||
@@ -0,0 +1,136 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ OR BSD-2-Clause */
|
||||
/*
|
||||
* crt0-efi-arm.S - PE/COFF header for ARM EFI applications
|
||||
*
|
||||
* Copright (C) 2014 Linaro Ltd. <ard.biesheuvel@linaro.org>
|
||||
*
|
||||
* This file is taken and modified from the gnu-efi project.
|
||||
*/
|
||||
|
||||
#include <asm-generic/pe.h>
|
||||
|
||||
.section .text.head
|
||||
|
||||
/*
|
||||
* Magic "MZ" signature for PE/COFF
|
||||
*/
|
||||
.globl image_base
|
||||
image_base:
|
||||
.short IMAGE_DOS_SIGNATURE /* 'MZ' */
|
||||
.skip 58 /* 'MZ' + pad + offset == 64 */
|
||||
.long pe_header - image_base /* Offset to the PE header */
|
||||
pe_header:
|
||||
.long IMAGE_NT_SIGNATURE /* 'PE' */
|
||||
coff_header:
|
||||
.short IMAGE_FILE_MACHINE_THUMB /* Mixed ARM/Thumb */
|
||||
.short 2 /* nr_sections */
|
||||
.long 0 /* TimeDateStamp */
|
||||
.long 0 /* PointerToSymbolTable */
|
||||
.long 0 /* NumberOfSymbols */
|
||||
.short section_table - optional_header /* SizeOfOptionalHeader */
|
||||
/* Characteristics */
|
||||
.short (IMAGE_FILE_EXECUTABLE_IMAGE | \
|
||||
IMAGE_FILE_LINE_NUMS_STRIPPED | \
|
||||
IMAGE_FILE_LOCAL_SYMS_STRIPPED | \
|
||||
IMAGE_FILE_32BIT_MACHINE | \
|
||||
IMAGE_FILE_DEBUG_STRIPPED)
|
||||
optional_header:
|
||||
.short IMAGE_NT_OPTIONAL_HDR32_MAGIC /* PE32 format */
|
||||
.byte 0x02 /* MajorLinkerVersion */
|
||||
.byte 0x14 /* MinorLinkerVersion */
|
||||
.long _edata - _start /* SizeOfCode */
|
||||
.long 0 /* SizeOfInitializedData */
|
||||
.long 0 /* SizeOfUninitializedData */
|
||||
.long _start - image_base /* AddressOfEntryPoint */
|
||||
.long _start - image_base /* BaseOfCode */
|
||||
.long 0 /* BaseOfData */
|
||||
|
||||
extra_header_fields:
|
||||
.long 0 /* image_base */
|
||||
.long 0x20 /* SectionAlignment */
|
||||
.long 0x8 /* FileAlignment */
|
||||
.short 0 /* MajorOperatingSystemVersion */
|
||||
.short 0 /* MinorOperatingSystemVersion */
|
||||
.short 0 /* MajorImageVersion */
|
||||
.short 0 /* MinorImageVersion */
|
||||
.short 0 /* MajorSubsystemVersion */
|
||||
.short 0 /* MinorSubsystemVersion */
|
||||
.long 0 /* Win32VersionValue */
|
||||
|
||||
.long _edata - image_base /* SizeOfImage */
|
||||
|
||||
/*
|
||||
* Everything before the kernel image is considered part of the header
|
||||
*/
|
||||
.long _start - image_base /* SizeOfHeaders */
|
||||
.long 0 /* CheckSum */
|
||||
.short IMAGE_SUBSYSTEM_EFI_APPLICATION /* Subsystem */
|
||||
.short 0 /* DllCharacteristics */
|
||||
.long 0 /* SizeOfStackReserve */
|
||||
.long 0 /* SizeOfStackCommit */
|
||||
.long 0 /* SizeOfHeapReserve */
|
||||
.long 0 /* SizeOfHeapCommit */
|
||||
.long 0 /* LoaderFlags */
|
||||
.long 0x6 /* NumberOfRvaAndSizes */
|
||||
|
||||
.quad 0 /* ExportTable */
|
||||
.quad 0 /* ImportTable */
|
||||
.quad 0 /* ResourceTable */
|
||||
.quad 0 /* ExceptionTable */
|
||||
.quad 0 /* CertificationTable */
|
||||
.quad 0 /* BaseRelocationTable */
|
||||
|
||||
section_table:
|
||||
|
||||
/*
|
||||
* The EFI application loader requires a relocation section
|
||||
* because EFI applications must be relocatable. This is a
|
||||
* dummy section as far as we are concerned.
|
||||
*/
|
||||
.ascii ".reloc"
|
||||
.byte 0
|
||||
.byte 0 /* end of 0 padding of section name */
|
||||
.long 0
|
||||
.long 0
|
||||
.long 0 /* SizeOfRawData */
|
||||
.long 0 /* PointerToRawData */
|
||||
.long 0 /* PointerToRelocations */
|
||||
.long 0 /* PointerToLineNumbers */
|
||||
.short 0 /* NumberOfRelocations */
|
||||
.short 0 /* NumberOfLineNumbers */
|
||||
.long 0x42100040 /* Characteristics (section flags) */
|
||||
|
||||
.ascii ".text"
|
||||
.byte 0
|
||||
.byte 0
|
||||
.byte 0 /* end of 0 padding of section name */
|
||||
.long _edata - _start /* VirtualSize */
|
||||
.long _start - image_base /* VirtualAddress */
|
||||
.long _edata - _start /* SizeOfRawData */
|
||||
.long _start - image_base /* PointerToRawData */
|
||||
|
||||
.long 0 /* PointerToRelocations (0 for executables) */
|
||||
.long 0 /* PointerToLineNumbers (0 for executables) */
|
||||
.short 0 /* NumberOfRelocations (0 for executables) */
|
||||
.short 0 /* NumberOfLineNumbers (0 for executables) */
|
||||
.long 0xe0500020 /* Characteristics (section flags) */
|
||||
|
||||
_start:
|
||||
stmfd sp!, {r0-r2, lr}
|
||||
|
||||
adr r1, .L_DYNAMIC
|
||||
ldr r0, [r1]
|
||||
add r1, r0, r1
|
||||
adr r0, image_base
|
||||
bl _relocate
|
||||
teq r0, #0
|
||||
bne 0f
|
||||
|
||||
ldmfd sp, {r0-r1}
|
||||
bl efi_main
|
||||
|
||||
0: add sp, sp, #12
|
||||
ldr pc, [sp], #4
|
||||
|
||||
.L_DYNAMIC:
|
||||
.word _DYNAMIC - .
|
||||
@@ -0,0 +1,135 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* linux/arch/arm/kernel/debug.S
|
||||
*
|
||||
* Copyright (C) 1994-1999 Russell King
|
||||
*
|
||||
* 32-bit debugging code
|
||||
*/
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/assembler.h>
|
||||
|
||||
.text
|
||||
|
||||
/*
|
||||
* Some debugging routines (useful if you've got MM problems and
|
||||
* printk isn't working). For DEBUGGING ONLY!!! Do not leave
|
||||
* references to these in a production kernel!
|
||||
*/
|
||||
|
||||
#if !defined(CONFIG_DEBUG_SEMIHOSTING)
|
||||
#include CONFIG_DEBUG_LL_INCLUDE
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MMU
|
||||
.macro addruart_current, rx, tmp1, tmp2
|
||||
addruart \tmp1, \tmp2, \rx
|
||||
mrc p15, 0, \rx, c1, c0
|
||||
tst \rx, #1
|
||||
moveq \rx, \tmp1
|
||||
movne \rx, \tmp2
|
||||
.endm
|
||||
|
||||
#else /* !CONFIG_MMU */
|
||||
.macro addruart_current, rx, tmp1, tmp2
|
||||
addruart \rx, \tmp1, \tmp2
|
||||
.endm
|
||||
|
||||
#endif /* CONFIG_MMU */
|
||||
|
||||
/*
|
||||
* Useful debugging routines
|
||||
*/
|
||||
ENTRY(printhex8)
|
||||
mov r1, #8
|
||||
b printhex
|
||||
ENDPROC(printhex8)
|
||||
|
||||
ENTRY(printhex4)
|
||||
mov r1, #4
|
||||
b printhex
|
||||
ENDPROC(printhex4)
|
||||
|
||||
ENTRY(printhex2)
|
||||
mov r1, #2
|
||||
printhex: adr r2, hexbuf
|
||||
add r3, r2, r1
|
||||
mov r1, #0
|
||||
strb r1, [r3]
|
||||
1: and r1, r0, #15
|
||||
mov r0, r0, lsr #4
|
||||
cmp r1, #10
|
||||
addlt r1, r1, #'0'
|
||||
addge r1, r1, #'a' - 10
|
||||
strb r1, [r3, #-1]!
|
||||
teq r3, r2
|
||||
bne 1b
|
||||
mov r0, r2
|
||||
b printascii
|
||||
ENDPROC(printhex2)
|
||||
|
||||
hexbuf: .space 16
|
||||
|
||||
.ltorg
|
||||
|
||||
#ifndef CONFIG_DEBUG_SEMIHOSTING
|
||||
|
||||
ENTRY(printascii)
|
||||
addruart_current r3, r1, r2
|
||||
b 2f
|
||||
1: waituart r2, r3
|
||||
senduart r1, r3
|
||||
busyuart r2, r3
|
||||
teq r1, #'\n'
|
||||
moveq r1, #'\r'
|
||||
beq 1b
|
||||
2: teq r0, #0
|
||||
ldrneb r1, [r0], #1
|
||||
teqne r1, #0
|
||||
bne 1b
|
||||
mov pc, lr
|
||||
ENDPROC(printascii)
|
||||
|
||||
ENTRY(printch)
|
||||
addruart_current r3, r1, r2
|
||||
mov r1, r0
|
||||
mov r0, #0
|
||||
b 1b
|
||||
ENDPROC(printch)
|
||||
|
||||
#ifdef CONFIG_MMU
|
||||
ENTRY(debug_ll_addr)
|
||||
addruart r2, r3, ip
|
||||
str r2, [r0]
|
||||
str r3, [r1]
|
||||
mov pc, lr
|
||||
ENDPROC(debug_ll_addr)
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
ENTRY(printascii)
|
||||
mov r1, r0
|
||||
mov r0, #0x04 @ SYS_WRITE0
|
||||
ARM( svc #0x123456 )
|
||||
THUMB( svc #0xab )
|
||||
mov pc, lr
|
||||
ENDPROC(printascii)
|
||||
|
||||
ENTRY(printch)
|
||||
adr r1, hexbuf
|
||||
strb r0, [r1]
|
||||
mov r0, #0x03 @ SYS_WRITEC
|
||||
ARM( svc #0x123456 )
|
||||
THUMB( svc #0xab )
|
||||
mov pc, lr
|
||||
ENDPROC(printch)
|
||||
|
||||
ENTRY(debug_ll_addr)
|
||||
mov r2, #0
|
||||
str r2, [r0]
|
||||
str r2, [r1]
|
||||
mov pc, lr
|
||||
ENDPROC(debug_ll_addr)
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,13 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2002
|
||||
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
*/
|
||||
|
||||
/* Replacement (=dummy) for GNU/Linux division-by zero handler */
|
||||
void __div0 (void)
|
||||
{
|
||||
extern void hang (void);
|
||||
|
||||
hang();
|
||||
}
|
||||
@@ -0,0 +1,213 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* linux/arch/arm/lib/div64.S
|
||||
*
|
||||
* Optimized computation of 64-bit dividend / 32-bit divisor
|
||||
*
|
||||
* Author: Nicolas Pitre
|
||||
* Created: Oct 5, 2003
|
||||
* Copyright: Monta Vista Software, Inc.
|
||||
*/
|
||||
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/assembler.h>
|
||||
#ifdef __UBOOT__
|
||||
#define UNWIND(x...)
|
||||
#endif
|
||||
|
||||
#ifdef __ARMEB__
|
||||
#define xh r0
|
||||
#define xl r1
|
||||
#define yh r2
|
||||
#define yl r3
|
||||
#else
|
||||
#define xl r0
|
||||
#define xh r1
|
||||
#define yl r2
|
||||
#define yh r3
|
||||
#endif
|
||||
|
||||
/*
|
||||
* __do_div64: perform a division with 64-bit dividend and 32-bit divisor.
|
||||
*
|
||||
* Note: Calling convention is totally non standard for optimal code.
|
||||
* This is meant to be used by do_div() from include/asm/div64.h only.
|
||||
*
|
||||
* Input parameters:
|
||||
* xh-xl = dividend (clobbered)
|
||||
* r4 = divisor (preserved)
|
||||
*
|
||||
* Output values:
|
||||
* yh-yl = result
|
||||
* xh = remainder
|
||||
*
|
||||
* Clobbered regs: xl, ip
|
||||
*/
|
||||
|
||||
.pushsection .text.__do_div64, "ax"
|
||||
ENTRY(__do_div64)
|
||||
UNWIND(.fnstart)
|
||||
|
||||
@ Test for easy paths first.
|
||||
subs ip, r4, #1
|
||||
bls 9f @ divisor is 0 or 1
|
||||
tst ip, r4
|
||||
beq 8f @ divisor is power of 2
|
||||
|
||||
@ See if we need to handle upper 32-bit result.
|
||||
cmp xh, r4
|
||||
mov yh, #0
|
||||
blo 3f
|
||||
|
||||
@ Align divisor with upper part of dividend.
|
||||
@ The aligned divisor is stored in yl preserving the original.
|
||||
@ The bit position is stored in ip.
|
||||
|
||||
#if __LINUX_ARM_ARCH__ >= 5
|
||||
|
||||
clz yl, r4
|
||||
clz ip, xh
|
||||
sub yl, yl, ip
|
||||
mov ip, #1
|
||||
mov ip, ip, lsl yl
|
||||
mov yl, r4, lsl yl
|
||||
|
||||
#else
|
||||
|
||||
mov yl, r4
|
||||
mov ip, #1
|
||||
1: cmp yl, #0x80000000
|
||||
cmpcc yl, xh
|
||||
movcc yl, yl, lsl #1
|
||||
movcc ip, ip, lsl #1
|
||||
bcc 1b
|
||||
|
||||
#endif
|
||||
|
||||
@ The division loop for needed upper bit positions.
|
||||
@ Break out early if dividend reaches 0.
|
||||
2: cmp xh, yl
|
||||
orrcs yh, yh, ip
|
||||
subscs xh, xh, yl
|
||||
movsne ip, ip, lsr #1
|
||||
mov yl, yl, lsr #1
|
||||
bne 2b
|
||||
|
||||
@ See if we need to handle lower 32-bit result.
|
||||
3: cmp xh, #0
|
||||
mov yl, #0
|
||||
cmpeq xl, r4
|
||||
movlo xh, xl
|
||||
retlo lr
|
||||
|
||||
@ The division loop for lower bit positions.
|
||||
@ Here we shift remainer bits leftwards rather than moving the
|
||||
@ divisor for comparisons, considering the carry-out bit as well.
|
||||
mov ip, #0x80000000
|
||||
4: movs xl, xl, lsl #1
|
||||
adcs xh, xh, xh
|
||||
beq 6f
|
||||
cmpcc xh, r4
|
||||
5: orrcs yl, yl, ip
|
||||
subcs xh, xh, r4
|
||||
movs ip, ip, lsr #1
|
||||
bne 4b
|
||||
ret lr
|
||||
|
||||
@ The top part of remainder became zero. If carry is set
|
||||
@ (the 33th bit) this is a false positive so resume the loop.
|
||||
@ Otherwise, if lower part is also null then we are done.
|
||||
6: bcs 5b
|
||||
cmp xl, #0
|
||||
reteq lr
|
||||
|
||||
@ We still have remainer bits in the low part. Bring them up.
|
||||
|
||||
#if __LINUX_ARM_ARCH__ >= 5
|
||||
|
||||
clz xh, xl @ we know xh is zero here so...
|
||||
add xh, xh, #1
|
||||
mov xl, xl, lsl xh
|
||||
mov ip, ip, lsr xh
|
||||
|
||||
#else
|
||||
|
||||
7: movs xl, xl, lsl #1
|
||||
mov ip, ip, lsr #1
|
||||
bcc 7b
|
||||
|
||||
#endif
|
||||
|
||||
@ Current remainder is now 1. It is worthless to compare with
|
||||
@ divisor at this point since divisor can not be smaller than 3 here.
|
||||
@ If possible, branch for another shift in the division loop.
|
||||
@ If no bit position left then we are done.
|
||||
movs ip, ip, lsr #1
|
||||
mov xh, #1
|
||||
bne 4b
|
||||
ret lr
|
||||
|
||||
8: @ Division by a power of 2: determine what that divisor order is
|
||||
@ then simply shift values around
|
||||
|
||||
#if __LINUX_ARM_ARCH__ >= 5
|
||||
|
||||
clz ip, r4
|
||||
rsb ip, ip, #31
|
||||
|
||||
#else
|
||||
|
||||
mov yl, r4
|
||||
cmp r4, #(1 << 16)
|
||||
mov ip, #0
|
||||
movhs yl, yl, lsr #16
|
||||
movhs ip, #16
|
||||
|
||||
cmp yl, #(1 << 8)
|
||||
movhs yl, yl, lsr #8
|
||||
addhs ip, ip, #8
|
||||
|
||||
cmp yl, #(1 << 4)
|
||||
movhs yl, yl, lsr #4
|
||||
addhs ip, ip, #4
|
||||
|
||||
cmp yl, #(1 << 2)
|
||||
addhi ip, ip, #3
|
||||
addls ip, ip, yl, lsr #1
|
||||
|
||||
#endif
|
||||
|
||||
mov yh, xh, lsr ip
|
||||
mov yl, xl, lsr ip
|
||||
rsb ip, ip, #32
|
||||
ARM( orr yl, yl, xh, lsl ip )
|
||||
THUMB( lsl xh, xh, ip )
|
||||
THUMB( orr yl, yl, xh )
|
||||
mov xh, xl, lsl ip
|
||||
mov xh, xh, lsr ip
|
||||
ret lr
|
||||
|
||||
@ eq -> division by 1: obvious enough...
|
||||
9: moveq yl, xl
|
||||
moveq yh, xh
|
||||
moveq xh, #0
|
||||
reteq lr
|
||||
UNWIND(.fnend)
|
||||
|
||||
UNWIND(.fnstart)
|
||||
UNWIND(.pad #4)
|
||||
UNWIND(.save {lr})
|
||||
Ldiv0_64:
|
||||
@ Division by 0:
|
||||
str lr, [sp, #-8]!
|
||||
bl __div0
|
||||
|
||||
@ as wrong as it could be...
|
||||
mov yl, #0
|
||||
mov yh, #0
|
||||
mov xh, #0
|
||||
ldr pc, [sp], #8
|
||||
|
||||
UNWIND(.fnend)
|
||||
ENDPROC(__do_div64)
|
||||
.popsection
|
||||
@@ -0,0 +1,37 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Utility functions needed for (some) EABI conformant tool chains.
|
||||
*
|
||||
* (C) Copyright 2009 Wolfgang Denk <wd@denx.de>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
|
||||
int raise (int signum)
|
||||
{
|
||||
/* Even if printf() is available, it's large. Punt it for SPL builds */
|
||||
#if !defined(CONFIG_SPL_BUILD)
|
||||
printf("raise: Signal # %d caught\n", signum);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Dummy function to avoid linker complaints */
|
||||
void __aeabi_unwind_cpp_pr0(void)
|
||||
{
|
||||
}
|
||||
|
||||
void __aeabi_unwind_cpp_pr1(void)
|
||||
{
|
||||
}
|
||||
|
||||
/* Copy memory like memcpy, but no return value required. */
|
||||
void __aeabi_memcpy(void *dest, const void *src, size_t n)
|
||||
{
|
||||
(void) memcpy(dest, src, n);
|
||||
}
|
||||
|
||||
void __aeabi_memset(void *dest, size_t n, int c)
|
||||
{
|
||||
(void) memset(dest, c, n);
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
/*
|
||||
* U-Boot aarch64 EFI linker script
|
||||
*
|
||||
* Modified from elf_aarch64_efi.lds in gnu-efi
|
||||
*/
|
||||
|
||||
OUTPUT_FORMAT("elf64-littleaarch64", "elf64-littleaarch64", "elf64-littleaarch64")
|
||||
OUTPUT_ARCH(aarch64)
|
||||
ENTRY(_start)
|
||||
SECTIONS
|
||||
{
|
||||
.text 0x0 : {
|
||||
_text = .;
|
||||
*(.text.head)
|
||||
*(.text)
|
||||
*(.text.*)
|
||||
*(.gnu.linkonce.t.*)
|
||||
*(.srodata)
|
||||
*(.rodata*)
|
||||
. = ALIGN(16);
|
||||
}
|
||||
_etext = .;
|
||||
_text_size = . - _text;
|
||||
.dynamic : { *(.dynamic) }
|
||||
.data : {
|
||||
_data = .;
|
||||
*(.sdata)
|
||||
*(.data)
|
||||
*(.data1)
|
||||
*(.data.*)
|
||||
*(.got.plt)
|
||||
*(.got)
|
||||
|
||||
/*
|
||||
* The EFI loader doesn't seem to like a .bss section, so we
|
||||
* stick it all into .data:
|
||||
*/
|
||||
. = ALIGN(16);
|
||||
_bss = .;
|
||||
*(.sbss)
|
||||
*(.scommon)
|
||||
*(.dynbss)
|
||||
*(.bss)
|
||||
*(.bss.*)
|
||||
*(COMMON)
|
||||
. = ALIGN(16);
|
||||
_bss_end = .;
|
||||
_edata = .;
|
||||
}
|
||||
.rela.dyn : { *(.rela.dyn) }
|
||||
.rela.plt : { *(.rela.plt) }
|
||||
.rela.got : { *(.rela.got) }
|
||||
.rela.data : { *(.rela.data) *(.rela.data*) }
|
||||
_data_size = . - _etext;
|
||||
|
||||
. = ALIGN(4096);
|
||||
.dynsym : { *(.dynsym) }
|
||||
. = ALIGN(4096);
|
||||
.dynstr : { *(.dynstr) }
|
||||
. = ALIGN(4096);
|
||||
.note.gnu.build-id : { *(.note.gnu.build-id) }
|
||||
/DISCARD/ : {
|
||||
*(.rel.reloc)
|
||||
*(.eh_frame)
|
||||
*(.note.GNU-stack)
|
||||
}
|
||||
.comment 0 : { *(.comment) }
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
/*
|
||||
* U-Boot ARM EFI linker script
|
||||
*
|
||||
* Modified from elf_arm_efi.lds in gnu-efi
|
||||
*/
|
||||
|
||||
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
|
||||
OUTPUT_ARCH(arm)
|
||||
ENTRY(_start)
|
||||
SECTIONS
|
||||
{
|
||||
.text 0x0 : {
|
||||
_text = .;
|
||||
*(.text.head)
|
||||
*(.text)
|
||||
*(.text.*)
|
||||
*(.gnu.linkonce.t.*)
|
||||
*(.srodata)
|
||||
*(.rodata*)
|
||||
. = ALIGN(16);
|
||||
}
|
||||
_etext = .;
|
||||
_text_size = . - _text;
|
||||
.dynamic : { *(.dynamic) }
|
||||
.data : {
|
||||
_data = .;
|
||||
*(.sdata)
|
||||
*(.data)
|
||||
*(.data1)
|
||||
*(.data.*)
|
||||
*(.got.plt)
|
||||
*(.got)
|
||||
|
||||
/*
|
||||
* The EFI loader doesn't seem to like a .bss section, so we
|
||||
* stick it all into .data:
|
||||
*/
|
||||
. = ALIGN(16);
|
||||
_bss = .;
|
||||
*(.sbss)
|
||||
*(.scommon)
|
||||
*(.dynbss)
|
||||
*(.bss)
|
||||
*(.bss.*)
|
||||
*(COMMON)
|
||||
. = ALIGN(16);
|
||||
_bss_end = .;
|
||||
_edata = .;
|
||||
}
|
||||
.rel.dyn : { *(.rel.dyn) }
|
||||
.rel.plt : { *(.rel.plt) }
|
||||
.rel.got : { *(.rel.got) }
|
||||
.rel.data : { *(.rel.data) *(.rel.data*) }
|
||||
_data_size = . - _etext;
|
||||
|
||||
/DISCARD/ : {
|
||||
*(.rel.reloc)
|
||||
*(.eh_frame)
|
||||
*(.note.GNU-stack)
|
||||
*(.dynsym)
|
||||
*(.dynstr)
|
||||
*(.note.gnu.build-id)
|
||||
*(.comment)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* GIC Initialization Routines.
|
||||
*
|
||||
* (C) Copyright 2013
|
||||
* David Feng <fenghua@phytium.com.cn>
|
||||
*/
|
||||
|
||||
#include <asm-offsets.h>
|
||||
#include <config.h>
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/gic.h>
|
||||
#include <asm/macro.h>
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
*
|
||||
* void gic_init_secure(DistributorBase);
|
||||
*
|
||||
* Initialize secure copy of GIC at EL3.
|
||||
*
|
||||
*************************************************************************/
|
||||
ENTRY(gic_init_secure)
|
||||
/*
|
||||
* Initialize Distributor
|
||||
* x0: Distributor Base
|
||||
*/
|
||||
#if defined(CONFIG_GICV3)
|
||||
mov w9, #0x37 /* EnableGrp0 | EnableGrp1NS */
|
||||
/* EnableGrp1S | ARE_S | ARE_NS */
|
||||
str w9, [x0, GICD_CTLR] /* Secure GICD_CTLR */
|
||||
ldr w9, [x0, GICD_TYPER]
|
||||
and w10, w9, #0x1f /* ITLinesNumber */
|
||||
cbz w10, 1f /* No SPIs */
|
||||
add x11, x0, (GICD_IGROUPRn + 4)
|
||||
add x12, x0, (GICD_IGROUPMODRn + 4)
|
||||
mov w9, #~0
|
||||
0: str w9, [x11], #0x4
|
||||
str wzr, [x12], #0x4 /* Config SPIs as Group1NS */
|
||||
sub w10, w10, #0x1
|
||||
cbnz w10, 0b
|
||||
#elif defined(CONFIG_GICV2)
|
||||
mov w9, #0x3 /* EnableGrp0 | EnableGrp1 */
|
||||
str w9, [x0, GICD_CTLR] /* Secure GICD_CTLR */
|
||||
ldr w9, [x0, GICD_TYPER]
|
||||
and w10, w9, #0x1f /* ITLinesNumber */
|
||||
cbz w10, 1f /* No SPIs */
|
||||
add x11, x0, GICD_IGROUPRn
|
||||
mov w9, #~0 /* Config SPIs as Grp1 */
|
||||
str w9, [x11], #0x4
|
||||
0: str w9, [x11], #0x4
|
||||
sub w10, w10, #0x1
|
||||
cbnz w10, 0b
|
||||
|
||||
ldr x1, =GICC_BASE /* GICC_CTLR */
|
||||
mov w0, #3 /* EnableGrp0 | EnableGrp1 */
|
||||
str w0, [x1]
|
||||
|
||||
mov w0, #1 << 7 /* allow NS access to GICC_PMR */
|
||||
str w0, [x1, #4] /* GICC_PMR */
|
||||
#endif
|
||||
1:
|
||||
ret
|
||||
ENDPROC(gic_init_secure)
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
* For Gicv2:
|
||||
* void gic_init_secure_percpu(DistributorBase, CpuInterfaceBase);
|
||||
* For Gicv3:
|
||||
* void gic_init_secure_percpu(ReDistributorBase);
|
||||
*
|
||||
* Initialize secure copy of GIC at EL3.
|
||||
*
|
||||
*************************************************************************/
|
||||
ENTRY(gic_init_secure_percpu)
|
||||
#if defined(CONFIG_GICV3)
|
||||
/*
|
||||
* Initialize ReDistributor
|
||||
* x0: ReDistributor Base
|
||||
*/
|
||||
mrs x10, mpidr_el1
|
||||
lsr x9, x10, #32
|
||||
bfi x10, x9, #24, #8 /* w10 is aff3:aff2:aff1:aff0 */
|
||||
mov x9, x0
|
||||
1: ldr x11, [x9, GICR_TYPER]
|
||||
lsr x11, x11, #32 /* w11 is aff3:aff2:aff1:aff0 */
|
||||
cmp w10, w11
|
||||
b.eq 2f
|
||||
add x9, x9, #(2 << 16)
|
||||
b 1b
|
||||
|
||||
/* x9: ReDistributor Base Address of Current CPU */
|
||||
2: mov w10, #~0x2
|
||||
ldr w11, [x9, GICR_WAKER]
|
||||
and w11, w11, w10 /* Clear ProcessorSleep */
|
||||
str w11, [x9, GICR_WAKER]
|
||||
dsb st
|
||||
isb
|
||||
3: ldr w10, [x9, GICR_WAKER]
|
||||
tbnz w10, #2, 3b /* Wait Children be Alive */
|
||||
|
||||
add x10, x9, #(1 << 16) /* SGI_Base */
|
||||
mov w11, #~0
|
||||
str w11, [x10, GICR_IGROUPRn]
|
||||
str wzr, [x10, GICR_IGROUPMODRn] /* SGIs|PPIs Group1NS */
|
||||
mov w11, #0x1 /* Enable SGI 0 */
|
||||
str w11, [x10, GICR_ISENABLERn]
|
||||
|
||||
switch_el x10, 3f, 2f, 1f
|
||||
3:
|
||||
/* Initialize Cpu Interface */
|
||||
mrs x10, ICC_SRE_EL3
|
||||
orr x10, x10, #0xf /* SRE & Disable IRQ/FIQ Bypass & */
|
||||
/* Allow EL2 access to ICC_SRE_EL2 */
|
||||
msr ICC_SRE_EL3, x10
|
||||
isb
|
||||
|
||||
mov x10, #0x3 /* EnableGrp1NS | EnableGrp1S */
|
||||
msr ICC_IGRPEN1_EL3, x10
|
||||
isb
|
||||
|
||||
msr ICC_CTLR_EL3, xzr
|
||||
isb
|
||||
2:
|
||||
mrs x10, ICC_SRE_EL2
|
||||
orr x10, x10, #0xf /* SRE & Disable IRQ/FIQ Bypass & */
|
||||
/* Allow EL1 access to ICC_SRE_EL1 */
|
||||
msr ICC_SRE_EL2, x10
|
||||
isb
|
||||
1:
|
||||
msr ICC_CTLR_EL1, xzr /* NonSecure ICC_CTLR_EL1 */
|
||||
isb
|
||||
|
||||
mov x10, #0x1 << 7 /* Non-Secure access to ICC_PMR_EL1 */
|
||||
msr ICC_PMR_EL1, x10
|
||||
isb
|
||||
#elif defined(CONFIG_GICV2)
|
||||
/*
|
||||
* Initialize SGIs and PPIs
|
||||
* x0: Distributor Base
|
||||
* x1: Cpu Interface Base
|
||||
*/
|
||||
mov w9, #~0 /* Config SGIs and PPIs as Grp1 */
|
||||
str w9, [x0, GICD_IGROUPRn] /* GICD_IGROUPR0 */
|
||||
mov w9, #0x1 /* Enable SGI 0 */
|
||||
str w9, [x0, GICD_ISENABLERn]
|
||||
|
||||
/* Initialize Cpu Interface */
|
||||
mov w9, #0x1e7 /* Disable IRQ/FIQ Bypass & */
|
||||
/* Enable Ack Group1 Interrupt & */
|
||||
/* EnableGrp0 & EnableGrp1 */
|
||||
str w9, [x1, GICC_CTLR] /* Secure GICC_CTLR */
|
||||
|
||||
mov w9, #0x1 << 7 /* Non-Secure access to GICC_PMR */
|
||||
str w9, [x1, GICC_PMR]
|
||||
#endif
|
||||
ret
|
||||
ENDPROC(gic_init_secure_percpu)
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
* For Gicv2:
|
||||
* void gic_kick_secondary_cpus(DistributorBase);
|
||||
* For Gicv3:
|
||||
* void gic_kick_secondary_cpus(void);
|
||||
*
|
||||
*************************************************************************/
|
||||
ENTRY(gic_kick_secondary_cpus)
|
||||
#if defined(CONFIG_GICV3)
|
||||
mov x9, #(1 << 40)
|
||||
msr ICC_ASGI1R_EL1, x9
|
||||
isb
|
||||
#elif defined(CONFIG_GICV2)
|
||||
mov w9, #0x8000
|
||||
movk w9, #0x100, lsl #16
|
||||
str w9, [x0, GICD_SGIR]
|
||||
#endif
|
||||
ret
|
||||
ENDPROC(gic_kick_secondary_cpus)
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
* For Gicv2:
|
||||
* void gic_wait_for_interrupt(CpuInterfaceBase);
|
||||
* For Gicv3:
|
||||
* void gic_wait_for_interrupt(void);
|
||||
*
|
||||
* Wait for SGI 0 from master.
|
||||
*
|
||||
*************************************************************************/
|
||||
ENTRY(gic_wait_for_interrupt)
|
||||
#if defined(CONFIG_GICV3)
|
||||
gic_wait_for_interrupt_m x9
|
||||
#elif defined(CONFIG_GICV2)
|
||||
gic_wait_for_interrupt_m x0, w9
|
||||
#endif
|
||||
ret
|
||||
ENDPROC(gic_wait_for_interrupt)
|
||||
@@ -0,0 +1,77 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2000-2009
|
||||
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <mapmem.h>
|
||||
#include <linux/sizes.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
#define LINUX_ARM64_IMAGE_MAGIC 0x644d5241
|
||||
|
||||
/* See Documentation/arm64/booting.txt in the Linux kernel */
|
||||
struct Image_header {
|
||||
uint32_t code0; /* Executable code */
|
||||
uint32_t code1; /* Executable code */
|
||||
uint64_t text_offset; /* Image load offset, LE */
|
||||
uint64_t image_size; /* Effective Image size, LE */
|
||||
uint64_t flags; /* Kernel flags, LE */
|
||||
uint64_t res2; /* reserved */
|
||||
uint64_t res3; /* reserved */
|
||||
uint64_t res4; /* reserved */
|
||||
uint32_t magic; /* Magic number */
|
||||
uint32_t res5;
|
||||
};
|
||||
|
||||
int booti_setup(ulong image, ulong *relocated_addr, ulong *size,
|
||||
bool force_reloc)
|
||||
{
|
||||
struct Image_header *ih;
|
||||
uint64_t dst;
|
||||
uint64_t image_size, text_offset;
|
||||
|
||||
*relocated_addr = image;
|
||||
|
||||
ih = (struct Image_header *)map_sysmem(image, 0);
|
||||
|
||||
if (ih->magic != le32_to_cpu(LINUX_ARM64_IMAGE_MAGIC)) {
|
||||
puts("Bad Linux ARM64 Image magic!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Prior to Linux commit a2c1d73b94ed, the text_offset field
|
||||
* is of unknown endianness. In these cases, the image_size
|
||||
* field is zero, and we can assume a fixed value of 0x80000.
|
||||
*/
|
||||
if (ih->image_size == 0) {
|
||||
puts("Image lacks image_size field, assuming 16MiB\n");
|
||||
image_size = 16 << 20;
|
||||
text_offset = 0x80000;
|
||||
} else {
|
||||
image_size = le64_to_cpu(ih->image_size);
|
||||
text_offset = le64_to_cpu(ih->text_offset);
|
||||
}
|
||||
|
||||
*size = image_size;
|
||||
|
||||
/*
|
||||
* If bit 3 of the flags field is set, the 2MB aligned base of the
|
||||
* kernel image can be anywhere in physical memory, so respect
|
||||
* images->ep. Otherwise, relocate the image to the base of RAM
|
||||
* since memory below it is not accessible via the linear mapping.
|
||||
*/
|
||||
if (!force_reloc && (le64_to_cpu(ih->flags) & BIT(3)))
|
||||
dst = image - text_offset;
|
||||
else
|
||||
dst = gd->bd->bi_dram[0].start;
|
||||
|
||||
*relocated_addr = ALIGN(dst, SZ_2M) + text_offset;
|
||||
|
||||
unmap_sysmem(ih);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,201 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2003
|
||||
* Texas Instruments <www.ti.com>
|
||||
*
|
||||
* (C) Copyright 2002
|
||||
* Sysgo Real-Time Solutions, GmbH <www.elinos.com>
|
||||
* Marius Groeger <mgroeger@sysgo.de>
|
||||
*
|
||||
* (C) Copyright 2002
|
||||
* Sysgo Real-Time Solutions, GmbH <www.elinos.com>
|
||||
* Alex Zuepke <azu@sysgo.de>
|
||||
*
|
||||
* (C) Copyright 2002-2004
|
||||
* Gary Jennejohn, DENX Software Engineering, <garyj@denx.de>
|
||||
*
|
||||
* (C) Copyright 2004
|
||||
* Philippe Robin, ARM Ltd. <philippe.robin@arm.com>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <efi_loader.h>
|
||||
#include <irq_func.h>
|
||||
#include <asm/proc-armv/ptrace.h>
|
||||
#include <asm/u-boot-arm.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
int interrupt_init(void)
|
||||
{
|
||||
/*
|
||||
* setup up stacks if necessary
|
||||
*/
|
||||
IRQ_STACK_START_IN = gd->irq_sp + 8;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void enable_interrupts(void)
|
||||
{
|
||||
return;
|
||||
}
|
||||
int disable_interrupts(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void bad_mode (void)
|
||||
{
|
||||
panic ("Resetting CPU ...\n");
|
||||
reset_cpu (0);
|
||||
}
|
||||
|
||||
static void show_efi_loaded_images(struct pt_regs *regs)
|
||||
{
|
||||
efi_print_image_infos((void *)instruction_pointer(regs));
|
||||
}
|
||||
|
||||
static void dump_instr(struct pt_regs *regs)
|
||||
{
|
||||
unsigned long addr = instruction_pointer(regs);
|
||||
const int thumb = thumb_mode(regs);
|
||||
const int width = thumb ? 4 : 8;
|
||||
int i;
|
||||
|
||||
if (thumb)
|
||||
addr &= ~1L;
|
||||
else
|
||||
addr &= ~3L;
|
||||
printf("Code: ");
|
||||
for (i = -4; i < 1 + !!thumb; i++) {
|
||||
unsigned int val;
|
||||
|
||||
if (thumb)
|
||||
val = ((u16 *)addr)[i];
|
||||
else
|
||||
val = ((u32 *)addr)[i];
|
||||
printf(i == 0 ? "(%0*x) " : "%0*x ", width, val);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void show_regs (struct pt_regs *regs)
|
||||
{
|
||||
unsigned long __maybe_unused flags;
|
||||
const char __maybe_unused *processor_modes[] = {
|
||||
"USER_26", "FIQ_26", "IRQ_26", "SVC_26",
|
||||
"UK4_26", "UK5_26", "UK6_26", "UK7_26",
|
||||
"UK8_26", "UK9_26", "UK10_26", "UK11_26",
|
||||
"UK12_26", "UK13_26", "UK14_26", "UK15_26",
|
||||
"USER_32", "FIQ_32", "IRQ_32", "SVC_32",
|
||||
"UK4_32", "UK5_32", "UK6_32", "ABT_32",
|
||||
"UK8_32", "UK9_32", "HYP_32", "UND_32",
|
||||
"UK12_32", "UK13_32", "UK14_32", "SYS_32",
|
||||
};
|
||||
|
||||
flags = condition_codes (regs);
|
||||
|
||||
printf("pc : [<%08lx>] lr : [<%08lx>]\n",
|
||||
instruction_pointer(regs), regs->ARM_lr);
|
||||
if (gd->flags & GD_FLG_RELOC) {
|
||||
printf("reloc pc : [<%08lx>] lr : [<%08lx>]\n",
|
||||
instruction_pointer(regs) - gd->reloc_off,
|
||||
regs->ARM_lr - gd->reloc_off);
|
||||
}
|
||||
printf("sp : %08lx ip : %08lx fp : %08lx\n",
|
||||
regs->ARM_sp, regs->ARM_ip, regs->ARM_fp);
|
||||
printf ("r10: %08lx r9 : %08lx r8 : %08lx\n",
|
||||
regs->ARM_r10, regs->ARM_r9, regs->ARM_r8);
|
||||
printf ("r7 : %08lx r6 : %08lx r5 : %08lx r4 : %08lx\n",
|
||||
regs->ARM_r7, regs->ARM_r6, regs->ARM_r5, regs->ARM_r4);
|
||||
printf ("r3 : %08lx r2 : %08lx r1 : %08lx r0 : %08lx\n",
|
||||
regs->ARM_r3, regs->ARM_r2, regs->ARM_r1, regs->ARM_r0);
|
||||
printf ("Flags: %c%c%c%c",
|
||||
flags & CC_N_BIT ? 'N' : 'n',
|
||||
flags & CC_Z_BIT ? 'Z' : 'z',
|
||||
flags & CC_C_BIT ? 'C' : 'c', flags & CC_V_BIT ? 'V' : 'v');
|
||||
printf (" IRQs %s FIQs %s Mode %s%s\n",
|
||||
interrupts_enabled (regs) ? "on" : "off",
|
||||
fast_interrupts_enabled (regs) ? "on" : "off",
|
||||
processor_modes[processor_mode (regs)],
|
||||
thumb_mode (regs) ? " (T)" : "");
|
||||
dump_instr(regs);
|
||||
}
|
||||
|
||||
/* fixup PC to point to the instruction leading to the exception */
|
||||
static inline void fixup_pc(struct pt_regs *regs, int offset)
|
||||
{
|
||||
uint32_t pc = instruction_pointer(regs) + offset;
|
||||
regs->ARM_pc = pc | (regs->ARM_pc & PCMASK);
|
||||
}
|
||||
|
||||
void do_undefined_instruction (struct pt_regs *pt_regs)
|
||||
{
|
||||
efi_restore_gd();
|
||||
printf ("undefined instruction\n");
|
||||
fixup_pc(pt_regs, -4);
|
||||
show_regs (pt_regs);
|
||||
show_efi_loaded_images(pt_regs);
|
||||
bad_mode ();
|
||||
}
|
||||
|
||||
void do_software_interrupt (struct pt_regs *pt_regs)
|
||||
{
|
||||
efi_restore_gd();
|
||||
printf ("software interrupt\n");
|
||||
fixup_pc(pt_regs, -4);
|
||||
show_regs (pt_regs);
|
||||
show_efi_loaded_images(pt_regs);
|
||||
bad_mode ();
|
||||
}
|
||||
|
||||
void do_prefetch_abort (struct pt_regs *pt_regs)
|
||||
{
|
||||
efi_restore_gd();
|
||||
printf ("prefetch abort\n");
|
||||
fixup_pc(pt_regs, -8);
|
||||
show_regs (pt_regs);
|
||||
show_efi_loaded_images(pt_regs);
|
||||
bad_mode ();
|
||||
}
|
||||
|
||||
void do_data_abort (struct pt_regs *pt_regs)
|
||||
{
|
||||
efi_restore_gd();
|
||||
printf ("data abort\n");
|
||||
fixup_pc(pt_regs, -8);
|
||||
show_regs (pt_regs);
|
||||
show_efi_loaded_images(pt_regs);
|
||||
bad_mode ();
|
||||
}
|
||||
|
||||
void do_not_used (struct pt_regs *pt_regs)
|
||||
{
|
||||
efi_restore_gd();
|
||||
printf ("not used\n");
|
||||
fixup_pc(pt_regs, -8);
|
||||
show_regs (pt_regs);
|
||||
show_efi_loaded_images(pt_regs);
|
||||
bad_mode ();
|
||||
}
|
||||
|
||||
void do_fiq (struct pt_regs *pt_regs)
|
||||
{
|
||||
efi_restore_gd();
|
||||
printf ("fast interrupt request\n");
|
||||
fixup_pc(pt_regs, -8);
|
||||
show_regs (pt_regs);
|
||||
show_efi_loaded_images(pt_regs);
|
||||
bad_mode ();
|
||||
}
|
||||
|
||||
void do_irq (struct pt_regs *pt_regs)
|
||||
{
|
||||
efi_restore_gd();
|
||||
printf ("interrupt request\n");
|
||||
fixup_pc(pt_regs, -8);
|
||||
show_regs (pt_regs);
|
||||
show_efi_loaded_images(pt_regs);
|
||||
bad_mode ();
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2013
|
||||
* David Feng <fenghua@phytium.com.cn>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <irq_func.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <efi_loader.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
int interrupt_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void enable_interrupts(void)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int disable_interrupts(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void show_efi_loaded_images(struct pt_regs *regs)
|
||||
{
|
||||
efi_print_image_infos((void *)regs->elr);
|
||||
}
|
||||
|
||||
static void dump_instr(struct pt_regs *regs)
|
||||
{
|
||||
u32 *addr = (u32 *)(regs->elr & ~3UL);
|
||||
int i;
|
||||
|
||||
printf("Code: ");
|
||||
for (i = -4; i < 1; i++)
|
||||
printf(i == 0 ? "(%08x) " : "%08x ", addr[i]);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void show_regs(struct pt_regs *regs)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (gd->flags & GD_FLG_RELOC)
|
||||
printf("elr: %016lx lr : %016lx (reloc)\n",
|
||||
regs->elr - gd->reloc_off,
|
||||
regs->regs[30] - gd->reloc_off);
|
||||
printf("elr: %016lx lr : %016lx\n", regs->elr, regs->regs[30]);
|
||||
|
||||
for (i = 0; i < 29; i += 2)
|
||||
printf("x%-2d: %016lx x%-2d: %016lx\n",
|
||||
i, regs->regs[i], i+1, regs->regs[i+1]);
|
||||
printf("\n");
|
||||
dump_instr(regs);
|
||||
}
|
||||
|
||||
/*
|
||||
* do_bad_sync handles the impossible case in the Synchronous Abort vector.
|
||||
*/
|
||||
void do_bad_sync(struct pt_regs *pt_regs, unsigned int esr)
|
||||
{
|
||||
efi_restore_gd();
|
||||
printf("Bad mode in \"Synchronous Abort\" handler, esr 0x%08x\n", esr);
|
||||
show_regs(pt_regs);
|
||||
show_efi_loaded_images(pt_regs);
|
||||
panic("Resetting CPU ...\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* do_bad_irq handles the impossible case in the Irq vector.
|
||||
*/
|
||||
void do_bad_irq(struct pt_regs *pt_regs, unsigned int esr)
|
||||
{
|
||||
efi_restore_gd();
|
||||
printf("Bad mode in \"Irq\" handler, esr 0x%08x\n", esr);
|
||||
show_regs(pt_regs);
|
||||
show_efi_loaded_images(pt_regs);
|
||||
panic("Resetting CPU ...\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* do_bad_fiq handles the impossible case in the Fiq vector.
|
||||
*/
|
||||
void do_bad_fiq(struct pt_regs *pt_regs, unsigned int esr)
|
||||
{
|
||||
efi_restore_gd();
|
||||
printf("Bad mode in \"Fiq\" handler, esr 0x%08x\n", esr);
|
||||
show_regs(pt_regs);
|
||||
show_efi_loaded_images(pt_regs);
|
||||
panic("Resetting CPU ...\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* do_bad_error handles the impossible case in the Error vector.
|
||||
*/
|
||||
void do_bad_error(struct pt_regs *pt_regs, unsigned int esr)
|
||||
{
|
||||
efi_restore_gd();
|
||||
printf("Bad mode in \"Error\" handler, esr 0x%08x\n", esr);
|
||||
show_regs(pt_regs);
|
||||
show_efi_loaded_images(pt_regs);
|
||||
panic("Resetting CPU ...\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* do_sync handles the Synchronous Abort exception.
|
||||
*/
|
||||
void do_sync(struct pt_regs *pt_regs, unsigned int esr)
|
||||
{
|
||||
efi_restore_gd();
|
||||
printf("\"Synchronous Abort\" handler, esr 0x%08x\n", esr);
|
||||
show_regs(pt_regs);
|
||||
show_efi_loaded_images(pt_regs);
|
||||
panic("Resetting CPU ...\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* do_irq handles the Irq exception.
|
||||
*/
|
||||
void do_irq(struct pt_regs *pt_regs, unsigned int esr)
|
||||
{
|
||||
efi_restore_gd();
|
||||
printf("\"Irq\" handler, esr 0x%08x\n", esr);
|
||||
show_regs(pt_regs);
|
||||
show_efi_loaded_images(pt_regs);
|
||||
panic("Resetting CPU ...\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* do_fiq handles the Fiq exception.
|
||||
*/
|
||||
void do_fiq(struct pt_regs *pt_regs, unsigned int esr)
|
||||
{
|
||||
efi_restore_gd();
|
||||
printf("\"Fiq\" handler, esr 0x%08x\n", esr);
|
||||
show_regs(pt_regs);
|
||||
show_efi_loaded_images(pt_regs);
|
||||
panic("Resetting CPU ...\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* do_error handles the Error exception.
|
||||
* Errors are more likely to be processor specific,
|
||||
* it is defined with weak attribute and can be redefined
|
||||
* in processor specific code.
|
||||
*/
|
||||
void __weak do_error(struct pt_regs *pt_regs, unsigned int esr)
|
||||
{
|
||||
efi_restore_gd();
|
||||
printf("\"Error\" handler, esr 0x%08x\n", esr);
|
||||
show_regs(pt_regs);
|
||||
show_efi_loaded_images(pt_regs);
|
||||
panic("Resetting CPU ...\n");
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2015
|
||||
* Kamil Lulko, <kamil.lulko@gmail.com>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <irq_func.h>
|
||||
|
||||
/*
|
||||
* Upon exception entry ARMv7-M processors automatically save stack
|
||||
* frames containing some registers. For simplicity initial
|
||||
* implementation uses only this auto-saved stack frame.
|
||||
* This does not contain complete register set dump,
|
||||
* only R0-R3, R12, LR, PC and xPSR are saved.
|
||||
*/
|
||||
|
||||
struct autosave_regs {
|
||||
long uregs[8];
|
||||
};
|
||||
|
||||
#define ARM_XPSR uregs[7]
|
||||
#define ARM_PC uregs[6]
|
||||
#define ARM_LR uregs[5]
|
||||
#define ARM_R12 uregs[4]
|
||||
#define ARM_R3 uregs[3]
|
||||
#define ARM_R2 uregs[2]
|
||||
#define ARM_R1 uregs[1]
|
||||
#define ARM_R0 uregs[0]
|
||||
|
||||
int interrupt_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void enable_interrupts(void)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int disable_interrupts(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dump_regs(struct autosave_regs *regs)
|
||||
{
|
||||
printf("pc : %08lx lr : %08lx xPSR : %08lx\n",
|
||||
regs->ARM_PC, regs->ARM_LR, regs->ARM_XPSR);
|
||||
printf("r12 : %08lx r3 : %08lx r2 : %08lx\n"
|
||||
"r1 : %08lx r0 : %08lx\n",
|
||||
regs->ARM_R12, regs->ARM_R3, regs->ARM_R2,
|
||||
regs->ARM_R1, regs->ARM_R0);
|
||||
}
|
||||
|
||||
void bad_mode(void)
|
||||
{
|
||||
panic("Resetting CPU ...\n");
|
||||
reset_cpu(0);
|
||||
}
|
||||
|
||||
void do_hard_fault(struct autosave_regs *autosave_regs)
|
||||
{
|
||||
printf("Hard fault\n");
|
||||
dump_regs(autosave_regs);
|
||||
bad_mode();
|
||||
}
|
||||
|
||||
void do_mm_fault(struct autosave_regs *autosave_regs)
|
||||
{
|
||||
printf("Memory management fault\n");
|
||||
dump_regs(autosave_regs);
|
||||
bad_mode();
|
||||
}
|
||||
|
||||
void do_bus_fault(struct autosave_regs *autosave_regs)
|
||||
{
|
||||
printf("Bus fault\n");
|
||||
dump_regs(autosave_regs);
|
||||
bad_mode();
|
||||
}
|
||||
|
||||
void do_usage_fault(struct autosave_regs *autosave_regs)
|
||||
{
|
||||
printf("Usage fault\n");
|
||||
dump_regs(autosave_regs);
|
||||
bad_mode();
|
||||
}
|
||||
|
||||
void do_invalid_entry(struct autosave_regs *autosave_regs)
|
||||
{
|
||||
printf("Exception\n");
|
||||
dump_regs(autosave_regs);
|
||||
bad_mode();
|
||||
}
|
||||
@@ -0,0 +1,427 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* linux/arch/arm/lib/lib1funcs.S: Optimized ARM division routines
|
||||
*
|
||||
* Author: Nicolas Pitre <nico@fluxnic.net>
|
||||
* - contributed to gcc-3.4 on Sep 30, 2003
|
||||
* - adapted for the Linux kernel on Oct 2, 2003
|
||||
*/
|
||||
/*
|
||||
* Copyright 1995, 1996, 1998, 1999, 2000, 2003 Free Software Foundation, Inc.
|
||||
*/
|
||||
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/assembler.h>
|
||||
|
||||
/*
|
||||
* U-Boot compatibility bit, define empty UNWIND() macro as, since we
|
||||
* do not support stack unwinding and define CONFIG_AEABI to make all
|
||||
* of the functions available without diverging from Linux code.
|
||||
*/
|
||||
#ifdef __UBOOT__
|
||||
#define UNWIND(x...)
|
||||
#define CONFIG_AEABI
|
||||
#endif
|
||||
|
||||
.macro ARM_DIV_BODY dividend, divisor, result, curbit
|
||||
|
||||
#if __LINUX_ARM_ARCH__ >= 5
|
||||
|
||||
clz \curbit, \divisor
|
||||
clz \result, \dividend
|
||||
sub \result, \curbit, \result
|
||||
mov \curbit, #1
|
||||
mov \divisor, \divisor, lsl \result
|
||||
mov \curbit, \curbit, lsl \result
|
||||
mov \result, #0
|
||||
|
||||
#else
|
||||
|
||||
@ Initially shift the divisor left 3 bits if possible,
|
||||
@ set curbit accordingly. This allows for curbit to be located
|
||||
@ at the left end of each 4 bit nibbles in the division loop
|
||||
@ to save one loop in most cases.
|
||||
tst \divisor, #0xe0000000
|
||||
moveq \divisor, \divisor, lsl #3
|
||||
moveq \curbit, #8
|
||||
movne \curbit, #1
|
||||
|
||||
@ Unless the divisor is very big, shift it up in multiples of
|
||||
@ four bits, since this is the amount of unwinding in the main
|
||||
@ division loop. Continue shifting until the divisor is
|
||||
@ larger than the dividend.
|
||||
1: cmp \divisor, #0x10000000
|
||||
cmplo \divisor, \dividend
|
||||
movlo \divisor, \divisor, lsl #4
|
||||
movlo \curbit, \curbit, lsl #4
|
||||
blo 1b
|
||||
|
||||
@ For very big divisors, we must shift it a bit at a time, or
|
||||
@ we will be in danger of overflowing.
|
||||
1: cmp \divisor, #0x80000000
|
||||
cmplo \divisor, \dividend
|
||||
movlo \divisor, \divisor, lsl #1
|
||||
movlo \curbit, \curbit, lsl #1
|
||||
blo 1b
|
||||
|
||||
mov \result, #0
|
||||
|
||||
#endif
|
||||
|
||||
@ Division loop
|
||||
1: cmp \dividend, \divisor
|
||||
subhs \dividend, \dividend, \divisor
|
||||
orrhs \result, \result, \curbit
|
||||
cmp \dividend, \divisor, lsr #1
|
||||
subhs \dividend, \dividend, \divisor, lsr #1
|
||||
orrhs \result, \result, \curbit, lsr #1
|
||||
cmp \dividend, \divisor, lsr #2
|
||||
subhs \dividend, \dividend, \divisor, lsr #2
|
||||
orrhs \result, \result, \curbit, lsr #2
|
||||
cmp \dividend, \divisor, lsr #3
|
||||
subhs \dividend, \dividend, \divisor, lsr #3
|
||||
orrhs \result, \result, \curbit, lsr #3
|
||||
cmp \dividend, #0 @ Early termination?
|
||||
movsne \curbit, \curbit, lsr #4 @ No, any more bits to do?
|
||||
movne \divisor, \divisor, lsr #4
|
||||
bne 1b
|
||||
|
||||
.endm
|
||||
|
||||
|
||||
.macro ARM_DIV2_ORDER divisor, order
|
||||
|
||||
#if __LINUX_ARM_ARCH__ >= 5
|
||||
|
||||
clz \order, \divisor
|
||||
rsb \order, \order, #31
|
||||
|
||||
#else
|
||||
|
||||
cmp \divisor, #(1 << 16)
|
||||
movhs \divisor, \divisor, lsr #16
|
||||
movhs \order, #16
|
||||
movlo \order, #0
|
||||
|
||||
cmp \divisor, #(1 << 8)
|
||||
movhs \divisor, \divisor, lsr #8
|
||||
addhs \order, \order, #8
|
||||
|
||||
cmp \divisor, #(1 << 4)
|
||||
movhs \divisor, \divisor, lsr #4
|
||||
addhs \order, \order, #4
|
||||
|
||||
cmp \divisor, #(1 << 2)
|
||||
addhi \order, \order, #3
|
||||
addls \order, \order, \divisor, lsr #1
|
||||
|
||||
#endif
|
||||
|
||||
.endm
|
||||
|
||||
|
||||
.macro ARM_MOD_BODY dividend, divisor, order, spare
|
||||
|
||||
#if __LINUX_ARM_ARCH__ >= 5
|
||||
|
||||
clz \order, \divisor
|
||||
clz \spare, \dividend
|
||||
sub \order, \order, \spare
|
||||
mov \divisor, \divisor, lsl \order
|
||||
|
||||
#else
|
||||
|
||||
mov \order, #0
|
||||
|
||||
@ Unless the divisor is very big, shift it up in multiples of
|
||||
@ four bits, since this is the amount of unwinding in the main
|
||||
@ division loop. Continue shifting until the divisor is
|
||||
@ larger than the dividend.
|
||||
1: cmp \divisor, #0x10000000
|
||||
cmplo \divisor, \dividend
|
||||
movlo \divisor, \divisor, lsl #4
|
||||
addlo \order, \order, #4
|
||||
blo 1b
|
||||
|
||||
@ For very big divisors, we must shift it a bit at a time, or
|
||||
@ we will be in danger of overflowing.
|
||||
1: cmp \divisor, #0x80000000
|
||||
cmplo \divisor, \dividend
|
||||
movlo \divisor, \divisor, lsl #1
|
||||
addlo \order, \order, #1
|
||||
blo 1b
|
||||
|
||||
#endif
|
||||
|
||||
@ Perform all needed subtractions to keep only the reminder.
|
||||
@ Do comparisons in batch of 4 first.
|
||||
subs \order, \order, #3 @ yes, 3 is intended here
|
||||
blt 2f
|
||||
|
||||
1: cmp \dividend, \divisor
|
||||
subhs \dividend, \dividend, \divisor
|
||||
cmp \dividend, \divisor, lsr #1
|
||||
subhs \dividend, \dividend, \divisor, lsr #1
|
||||
cmp \dividend, \divisor, lsr #2
|
||||
subhs \dividend, \dividend, \divisor, lsr #2
|
||||
cmp \dividend, \divisor, lsr #3
|
||||
subhs \dividend, \dividend, \divisor, lsr #3
|
||||
cmp \dividend, #1
|
||||
mov \divisor, \divisor, lsr #4
|
||||
subsge \order, \order, #4
|
||||
bge 1b
|
||||
|
||||
tst \order, #3
|
||||
teqne \dividend, #0
|
||||
beq 5f
|
||||
|
||||
@ Either 1, 2 or 3 comparison/subtractions are left.
|
||||
2: cmn \order, #2
|
||||
blt 4f
|
||||
beq 3f
|
||||
cmp \dividend, \divisor
|
||||
subhs \dividend, \dividend, \divisor
|
||||
mov \divisor, \divisor, lsr #1
|
||||
3: cmp \dividend, \divisor
|
||||
subhs \dividend, \dividend, \divisor
|
||||
mov \divisor, \divisor, lsr #1
|
||||
4: cmp \dividend, \divisor
|
||||
subhs \dividend, \dividend, \divisor
|
||||
5:
|
||||
.endm
|
||||
|
||||
|
||||
.pushsection .text.__udivsi3, "ax"
|
||||
ENTRY(__udivsi3)
|
||||
ENTRY(__aeabi_uidiv)
|
||||
UNWIND(.fnstart)
|
||||
|
||||
subs r2, r1, #1
|
||||
reteq lr
|
||||
bcc Ldiv0
|
||||
cmp r0, r1
|
||||
bls 11f
|
||||
tst r1, r2
|
||||
beq 12f
|
||||
|
||||
ARM_DIV_BODY r0, r1, r2, r3
|
||||
|
||||
mov r0, r2
|
||||
ret lr
|
||||
|
||||
11: moveq r0, #1
|
||||
movne r0, #0
|
||||
ret lr
|
||||
|
||||
12: ARM_DIV2_ORDER r1, r2
|
||||
|
||||
mov r0, r0, lsr r2
|
||||
ret lr
|
||||
|
||||
UNWIND(.fnend)
|
||||
ENDPROC(__udivsi3)
|
||||
ENDPROC(__aeabi_uidiv)
|
||||
.popsection
|
||||
|
||||
.pushsection .text.__umodsi3, "ax"
|
||||
ENTRY(__umodsi3)
|
||||
UNWIND(.fnstart)
|
||||
|
||||
subs r2, r1, #1 @ compare divisor with 1
|
||||
bcc Ldiv0
|
||||
cmpne r0, r1 @ compare dividend with divisor
|
||||
moveq r0, #0
|
||||
tsthi r1, r2 @ see if divisor is power of 2
|
||||
andeq r0, r0, r2
|
||||
retls lr
|
||||
|
||||
ARM_MOD_BODY r0, r1, r2, r3
|
||||
|
||||
ret lr
|
||||
|
||||
UNWIND(.fnend)
|
||||
ENDPROC(__umodsi3)
|
||||
.popsection
|
||||
|
||||
.pushsection .text.__divsi3, "ax"
|
||||
ENTRY(__divsi3)
|
||||
ENTRY(__aeabi_idiv)
|
||||
UNWIND(.fnstart)
|
||||
|
||||
cmp r1, #0
|
||||
eor ip, r0, r1 @ save the sign of the result.
|
||||
beq Ldiv0
|
||||
rsbmi r1, r1, #0 @ loops below use unsigned.
|
||||
subs r2, r1, #1 @ division by 1 or -1 ?
|
||||
beq 10f
|
||||
movs r3, r0
|
||||
rsbmi r3, r0, #0 @ positive dividend value
|
||||
cmp r3, r1
|
||||
bls 11f
|
||||
tst r1, r2 @ divisor is power of 2 ?
|
||||
beq 12f
|
||||
|
||||
ARM_DIV_BODY r3, r1, r0, r2
|
||||
|
||||
cmp ip, #0
|
||||
rsbmi r0, r0, #0
|
||||
ret lr
|
||||
|
||||
10: teq ip, r0 @ same sign ?
|
||||
rsbmi r0, r0, #0
|
||||
ret lr
|
||||
|
||||
11: movlo r0, #0
|
||||
moveq r0, ip, asr #31
|
||||
orreq r0, r0, #1
|
||||
ret lr
|
||||
|
||||
12: ARM_DIV2_ORDER r1, r2
|
||||
|
||||
cmp ip, #0
|
||||
mov r0, r3, lsr r2
|
||||
rsbmi r0, r0, #0
|
||||
ret lr
|
||||
|
||||
UNWIND(.fnend)
|
||||
ENDPROC(__divsi3)
|
||||
ENDPROC(__aeabi_idiv)
|
||||
.popsection
|
||||
|
||||
.pushsection .text.__modsi3, "ax"
|
||||
ENTRY(__modsi3)
|
||||
UNWIND(.fnstart)
|
||||
|
||||
cmp r1, #0
|
||||
beq Ldiv0
|
||||
rsbmi r1, r1, #0 @ loops below use unsigned.
|
||||
movs ip, r0 @ preserve sign of dividend
|
||||
rsbmi r0, r0, #0 @ if negative make positive
|
||||
subs r2, r1, #1 @ compare divisor with 1
|
||||
cmpne r0, r1 @ compare dividend with divisor
|
||||
moveq r0, #0
|
||||
tsthi r1, r2 @ see if divisor is power of 2
|
||||
andeq r0, r0, r2
|
||||
bls 10f
|
||||
|
||||
ARM_MOD_BODY r0, r1, r2, r3
|
||||
|
||||
10: cmp ip, #0
|
||||
rsbmi r0, r0, #0
|
||||
ret lr
|
||||
|
||||
UNWIND(.fnend)
|
||||
ENDPROC(__modsi3)
|
||||
.popsection
|
||||
|
||||
#ifdef CONFIG_AEABI
|
||||
|
||||
.pushsection .text.__aeabi_uidivmod, "ax"
|
||||
ENTRY(__aeabi_uidivmod)
|
||||
UNWIND(.fnstart)
|
||||
UNWIND(.save {r0, r1, ip, lr} )
|
||||
|
||||
stmfd sp!, {r0, r1, ip, lr}
|
||||
bl __aeabi_uidiv
|
||||
ldmfd sp!, {r1, r2, ip, lr}
|
||||
mul r3, r0, r2
|
||||
sub r1, r1, r3
|
||||
ret lr
|
||||
|
||||
UNWIND(.fnend)
|
||||
ENDPROC(__aeabi_uidivmod)
|
||||
.popsection
|
||||
|
||||
.pushsection .text.__aeabi_uidivmod, "ax"
|
||||
ENTRY(__aeabi_idivmod)
|
||||
UNWIND(.fnstart)
|
||||
UNWIND(.save {r0, r1, ip, lr} )
|
||||
|
||||
stmfd sp!, {r0, r1, ip, lr}
|
||||
bl __aeabi_idiv
|
||||
ldmfd sp!, {r1, r2, ip, lr}
|
||||
mul r3, r0, r2
|
||||
sub r1, r1, r3
|
||||
ret lr
|
||||
|
||||
UNWIND(.fnend)
|
||||
ENDPROC(__aeabi_idivmod)
|
||||
.popsection
|
||||
|
||||
#endif
|
||||
|
||||
.pushsection .text.Ldiv0, "ax"
|
||||
Ldiv0:
|
||||
UNWIND(.fnstart)
|
||||
UNWIND(.pad #4)
|
||||
UNWIND(.save {lr})
|
||||
|
||||
str lr, [sp, #-8]!
|
||||
bl __div0
|
||||
mov r0, #0 @ About as wrong as it could be.
|
||||
ldr pc, [sp], #8
|
||||
|
||||
UNWIND(.fnend)
|
||||
ENDPROC(Ldiv0)
|
||||
.popsection
|
||||
|
||||
/* Thumb-1 specialities */
|
||||
#if CONFIG_IS_ENABLED(SYS_THUMB_BUILD) && !defined(CONFIG_HAS_THUMB2)
|
||||
.pushsection .text.__gnu_thumb1_case_sqi, "ax"
|
||||
ENTRY(__gnu_thumb1_case_sqi)
|
||||
push {r1}
|
||||
mov r1, lr
|
||||
lsrs r1, r1, #1
|
||||
lsls r1, r1, #1
|
||||
ldrsb r1, [r1, r0]
|
||||
lsls r1, r1, #1
|
||||
add lr, lr, r1
|
||||
pop {r1}
|
||||
bx lr
|
||||
ENDPROC(__gnu_thumb1_case_sqi)
|
||||
.popsection
|
||||
|
||||
.pushsection .text.__gnu_thumb1_case_uqi, "ax"
|
||||
ENTRY(__gnu_thumb1_case_uqi)
|
||||
push {r1}
|
||||
mov r1, lr
|
||||
lsrs r1, r1, #1
|
||||
lsls r1, r1, #1
|
||||
ldrb r1, [r1, r0]
|
||||
lsls r1, r1, #1
|
||||
add lr, lr, r1
|
||||
pop {r1}
|
||||
bx lr
|
||||
ENDPROC(__gnu_thumb1_case_uqi)
|
||||
.popsection
|
||||
|
||||
.pushsection .text.__gnu_thumb1_case_shi, "ax"
|
||||
ENTRY(__gnu_thumb1_case_shi)
|
||||
push {r0, r1}
|
||||
mov r1, lr
|
||||
lsrs r1, r1, #1
|
||||
lsls r0, r0, #1
|
||||
lsls r1, r1, #1
|
||||
ldrsh r1, [r1, r0]
|
||||
lsls r1, r1, #1
|
||||
add lr, lr, r1
|
||||
pop {r0, r1}
|
||||
bx lr
|
||||
ENDPROC(__gnu_thumb1_case_shi)
|
||||
.popsection
|
||||
|
||||
.pushsection .text.__gnu_thumb1_case_uhi, "ax"
|
||||
ENTRY(__gnu_thumb1_case_uhi)
|
||||
push {r0, r1}
|
||||
mov r1, lr
|
||||
lsrs r1, r1, #1
|
||||
lsls r0, r0, #1
|
||||
lsls r1, r1, #1
|
||||
ldrh r1, [r1, r0]
|
||||
lsls r1, r1, #1
|
||||
add lr, lr, r1
|
||||
pop {r0, r1}
|
||||
bx lr
|
||||
ENDPROC(__gnu_thumb1_case_uhi)
|
||||
.popsection
|
||||
#endif
|
||||
@@ -0,0 +1,33 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/* Copyright 1995, 1996, 1998, 1999, 2000, 2003, 2004, 2005
|
||||
Free Software Foundation, Inc.
|
||||
*/
|
||||
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/assembler.h>
|
||||
|
||||
#ifdef __ARMEB__
|
||||
#define al r1
|
||||
#define ah r0
|
||||
#else
|
||||
#define al r0
|
||||
#define ah r1
|
||||
#endif
|
||||
|
||||
.pushsection .text.__lshldi3, "ax"
|
||||
ENTRY(__lshrdi3)
|
||||
ENTRY(__aeabi_llsr)
|
||||
|
||||
subs r3, r2, #32
|
||||
rsb ip, r2, #32
|
||||
movmi al, al, lsr r2
|
||||
movpl al, ah, lsr r3
|
||||
ARM( orrmi al, al, ah, lsl ip )
|
||||
THUMB( lslmi r3, ah, ip )
|
||||
THUMB( orrmi al, al, r3 )
|
||||
mov ah, ah, lsr r2
|
||||
ret lr
|
||||
|
||||
ENDPROC(__lshrdi3)
|
||||
ENDPROC(__aeabi_llsr)
|
||||
.popsection
|
||||
@@ -0,0 +1,264 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* linux/arch/arm/lib/memcpy.S
|
||||
*
|
||||
* Author: Nicolas Pitre
|
||||
* Created: Sep 28, 2005
|
||||
* Copyright: MontaVista Software, Inc.
|
||||
*/
|
||||
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/assembler.h>
|
||||
|
||||
#define LDR1W_SHIFT 0
|
||||
#define STR1W_SHIFT 0
|
||||
|
||||
.macro ldr1w ptr reg abort
|
||||
W(ldr) \reg, [\ptr], #4
|
||||
.endm
|
||||
|
||||
.macro ldr4w ptr reg1 reg2 reg3 reg4 abort
|
||||
ldmia \ptr!, {\reg1, \reg2, \reg3, \reg4}
|
||||
.endm
|
||||
|
||||
.macro ldr8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort
|
||||
ldmia \ptr!, {\reg1, \reg2, \reg3, \reg4, \reg5, \reg6, \reg7, \reg8}
|
||||
.endm
|
||||
|
||||
.macro ldr1b ptr reg cond=al abort
|
||||
ldrb\cond\() \reg, [\ptr], #1
|
||||
.endm
|
||||
|
||||
.macro str1w ptr reg abort
|
||||
W(str) \reg, [\ptr], #4
|
||||
.endm
|
||||
|
||||
.macro str8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort
|
||||
stmia \ptr!, {\reg1, \reg2, \reg3, \reg4, \reg5, \reg6, \reg7, \reg8}
|
||||
.endm
|
||||
|
||||
.macro str1b ptr reg cond=al abort
|
||||
strb\cond\() \reg, [\ptr], #1
|
||||
.endm
|
||||
|
||||
.macro enter reg1 reg2
|
||||
stmdb sp!, {r0, \reg1, \reg2}
|
||||
.endm
|
||||
|
||||
.macro exit reg1 reg2
|
||||
ldmfd sp!, {r0, \reg1, \reg2}
|
||||
.endm
|
||||
|
||||
.text
|
||||
|
||||
/* Prototype: void *memcpy(void *dest, const void *src, size_t n); */
|
||||
.syntax unified
|
||||
#if CONFIG_IS_ENABLED(SYS_THUMB_BUILD) && !defined(MEMCPY_NO_THUMB_BUILD)
|
||||
.thumb
|
||||
.thumb_func
|
||||
#endif
|
||||
ENTRY(memcpy)
|
||||
cmp r0, r1
|
||||
bxeq lr
|
||||
|
||||
enter r4, lr
|
||||
|
||||
subs r2, r2, #4
|
||||
blt 8f
|
||||
ands ip, r0, #3
|
||||
PLD( pld [r1, #0] )
|
||||
bne 9f
|
||||
ands ip, r1, #3
|
||||
bne 10f
|
||||
|
||||
1: subs r2, r2, #(28)
|
||||
stmfd sp!, {r5 - r8}
|
||||
blt 5f
|
||||
|
||||
CALGN( ands ip, r0, #31 )
|
||||
CALGN( rsb r3, ip, #32 )
|
||||
CALGN( sbcsne r4, r3, r2 ) @ C is always set here
|
||||
CALGN( bcs 2f )
|
||||
CALGN( adr r4, 6f )
|
||||
CALGN( subs r2, r2, r3 ) @ C gets set
|
||||
CALGN( add pc, r4, ip )
|
||||
|
||||
PLD( pld [r1, #0] )
|
||||
2: PLD( subs r2, r2, #96 )
|
||||
PLD( pld [r1, #28] )
|
||||
PLD( blt 4f )
|
||||
PLD( pld [r1, #60] )
|
||||
PLD( pld [r1, #92] )
|
||||
|
||||
3: PLD( pld [r1, #124] )
|
||||
4: ldr8w r1, r3, r4, r5, r6, r7, r8, ip, lr, abort=20f
|
||||
subs r2, r2, #32
|
||||
str8w r0, r3, r4, r5, r6, r7, r8, ip, lr, abort=20f
|
||||
bge 3b
|
||||
PLD( cmn r2, #96 )
|
||||
PLD( bge 4b )
|
||||
|
||||
5: ands ip, r2, #28
|
||||
rsb ip, ip, #32
|
||||
#if LDR1W_SHIFT > 0
|
||||
lsl ip, ip, #LDR1W_SHIFT
|
||||
#endif
|
||||
addne pc, pc, ip @ C is always clear here
|
||||
b 7f
|
||||
6:
|
||||
.rept (1 << LDR1W_SHIFT)
|
||||
W(nop)
|
||||
.endr
|
||||
ldr1w r1, r3, abort=20f
|
||||
ldr1w r1, r4, abort=20f
|
||||
ldr1w r1, r5, abort=20f
|
||||
ldr1w r1, r6, abort=20f
|
||||
ldr1w r1, r7, abort=20f
|
||||
ldr1w r1, r8, abort=20f
|
||||
ldr1w r1, lr, abort=20f
|
||||
|
||||
#if LDR1W_SHIFT < STR1W_SHIFT
|
||||
lsl ip, ip, #STR1W_SHIFT - LDR1W_SHIFT
|
||||
#elif LDR1W_SHIFT > STR1W_SHIFT
|
||||
lsr ip, ip, #LDR1W_SHIFT - STR1W_SHIFT
|
||||
#endif
|
||||
add pc, pc, ip
|
||||
nop
|
||||
.rept (1 << STR1W_SHIFT)
|
||||
W(nop)
|
||||
.endr
|
||||
str1w r0, r3, abort=20f
|
||||
str1w r0, r4, abort=20f
|
||||
str1w r0, r5, abort=20f
|
||||
str1w r0, r6, abort=20f
|
||||
str1w r0, r7, abort=20f
|
||||
str1w r0, r8, abort=20f
|
||||
str1w r0, lr, abort=20f
|
||||
|
||||
CALGN( bcs 2b )
|
||||
|
||||
7: ldmfd sp!, {r5 - r8}
|
||||
|
||||
8: movs r2, r2, lsl #31
|
||||
ldr1b r1, r3, ne, abort=21f
|
||||
ldr1b r1, r4, cs, abort=21f
|
||||
ldr1b r1, ip, cs, abort=21f
|
||||
str1b r0, r3, ne, abort=21f
|
||||
str1b r0, r4, cs, abort=21f
|
||||
str1b r0, ip, cs, abort=21f
|
||||
|
||||
exit r4, lr
|
||||
bx lr
|
||||
|
||||
9: rsb ip, ip, #4
|
||||
cmp ip, #2
|
||||
ldr1b r1, r3, gt, abort=21f
|
||||
ldr1b r1, r4, ge, abort=21f
|
||||
ldr1b r1, lr, abort=21f
|
||||
str1b r0, r3, gt, abort=21f
|
||||
str1b r0, r4, ge, abort=21f
|
||||
subs r2, r2, ip
|
||||
str1b r0, lr, abort=21f
|
||||
blt 8b
|
||||
ands ip, r1, #3
|
||||
beq 1b
|
||||
|
||||
10: bic r1, r1, #3
|
||||
cmp ip, #2
|
||||
ldr1w r1, lr, abort=21f
|
||||
beq 17f
|
||||
bgt 18f
|
||||
|
||||
|
||||
.macro forward_copy_shift pull push
|
||||
|
||||
subs r2, r2, #28
|
||||
blt 14f
|
||||
|
||||
CALGN( ands ip, r0, #31 )
|
||||
CALGN( rsb ip, ip, #32 )
|
||||
CALGN( sbcsne r4, ip, r2 ) @ C is always set here
|
||||
CALGN( subcc r2, r2, ip )
|
||||
CALGN( bcc 15f )
|
||||
|
||||
11: stmfd sp!, {r5 - r9}
|
||||
|
||||
PLD( pld [r1, #0] )
|
||||
PLD( subs r2, r2, #96 )
|
||||
PLD( pld [r1, #28] )
|
||||
PLD( blt 13f )
|
||||
PLD( pld [r1, #60] )
|
||||
PLD( pld [r1, #92] )
|
||||
|
||||
12: PLD( pld [r1, #124] )
|
||||
13: ldr4w r1, r4, r5, r6, r7, abort=19f
|
||||
mov r3, lr, lspull #\pull
|
||||
subs r2, r2, #32
|
||||
ldr4w r1, r8, r9, ip, lr, abort=19f
|
||||
orr r3, r3, r4, lspush #\push
|
||||
mov r4, r4, lspull #\pull
|
||||
orr r4, r4, r5, lspush #\push
|
||||
mov r5, r5, lspull #\pull
|
||||
orr r5, r5, r6, lspush #\push
|
||||
mov r6, r6, lspull #\pull
|
||||
orr r6, r6, r7, lspush #\push
|
||||
mov r7, r7, lspull #\pull
|
||||
orr r7, r7, r8, lspush #\push
|
||||
mov r8, r8, lspull #\pull
|
||||
orr r8, r8, r9, lspush #\push
|
||||
mov r9, r9, lspull #\pull
|
||||
orr r9, r9, ip, lspush #\push
|
||||
mov ip, ip, lspull #\pull
|
||||
orr ip, ip, lr, lspush #\push
|
||||
str8w r0, r3, r4, r5, r6, r7, r8, r9, ip, , abort=19f
|
||||
bge 12b
|
||||
PLD( cmn r2, #96 )
|
||||
PLD( bge 13b )
|
||||
|
||||
ldmfd sp!, {r5 - r9}
|
||||
|
||||
14: ands ip, r2, #28
|
||||
beq 16f
|
||||
|
||||
15: mov r3, lr, lspull #\pull
|
||||
ldr1w r1, lr, abort=21f
|
||||
subs ip, ip, #4
|
||||
orr r3, r3, lr, lspush #\push
|
||||
str1w r0, r3, abort=21f
|
||||
bgt 15b
|
||||
CALGN( cmp r2, #0 )
|
||||
CALGN( bge 11b )
|
||||
|
||||
16: sub r1, r1, #(\push / 8)
|
||||
b 8b
|
||||
|
||||
.endm
|
||||
|
||||
|
||||
forward_copy_shift pull=8 push=24
|
||||
|
||||
17: forward_copy_shift pull=16 push=16
|
||||
|
||||
18: forward_copy_shift pull=24 push=8
|
||||
|
||||
|
||||
/*
|
||||
* Abort preamble and completion macros.
|
||||
* If a fixup handler is required then those macros must surround it.
|
||||
* It is assumed that the fixup code will handle the private part of
|
||||
* the exit macro.
|
||||
*/
|
||||
|
||||
.macro copy_abort_preamble
|
||||
19: ldmfd sp!, {r5 - r9}
|
||||
b 21f
|
||||
20: ldmfd sp!, {r5 - r8}
|
||||
21:
|
||||
.endm
|
||||
|
||||
.macro copy_abort_end
|
||||
ldmfd sp!, {r4, lr}
|
||||
bx lr
|
||||
.endm
|
||||
|
||||
ENDPROC(memcpy)
|
||||
@@ -0,0 +1,125 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* linux/arch/arm/lib/memset.S
|
||||
*
|
||||
* Copyright (C) 1995-2000 Russell King
|
||||
*
|
||||
* ASM optimised string functions
|
||||
*/
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/assembler.h>
|
||||
|
||||
.text
|
||||
.align 5
|
||||
|
||||
.syntax unified
|
||||
#if CONFIG_IS_ENABLED(SYS_THUMB_BUILD) && !defined(MEMSET_NO_THUMB_BUILD)
|
||||
.thumb
|
||||
.thumb_func
|
||||
#endif
|
||||
ENTRY(memset)
|
||||
ands r3, r0, #3 @ 1 unaligned?
|
||||
mov ip, r0 @ preserve r0 as return value
|
||||
bne 6f @ 1
|
||||
/*
|
||||
* we know that the pointer in ip is aligned to a word boundary.
|
||||
*/
|
||||
1: orr r1, r1, r1, lsl #8
|
||||
orr r1, r1, r1, lsl #16
|
||||
mov r3, r1
|
||||
cmp r2, #16
|
||||
blt 4f
|
||||
|
||||
#if ! CALGN(1)+0
|
||||
|
||||
/*
|
||||
* We need 2 extra registers for this loop - use r8 and the LR
|
||||
*/
|
||||
stmfd sp!, {r8, lr}
|
||||
mov r8, r1
|
||||
mov lr, r1
|
||||
|
||||
2: subs r2, r2, #64
|
||||
stmiage ip!, {r1, r3, r8, lr} @ 64 bytes at a time.
|
||||
stmiage ip!, {r1, r3, r8, lr}
|
||||
stmiage ip!, {r1, r3, r8, lr}
|
||||
stmiage ip!, {r1, r3, r8, lr}
|
||||
bgt 2b
|
||||
ldmfdeq sp!, {r8, pc} @ Now <64 bytes to go.
|
||||
/*
|
||||
* No need to correct the count; we're only testing bits from now on
|
||||
*/
|
||||
tst r2, #32
|
||||
stmiane ip!, {r1, r3, r8, lr}
|
||||
stmiane ip!, {r1, r3, r8, lr}
|
||||
tst r2, #16
|
||||
stmiane ip!, {r1, r3, r8, lr}
|
||||
ldmfd sp!, {r8, lr}
|
||||
|
||||
#else
|
||||
|
||||
/*
|
||||
* This version aligns the destination pointer in order to write
|
||||
* whole cache lines at once.
|
||||
*/
|
||||
|
||||
stmfd sp!, {r4-r8, lr}
|
||||
mov r4, r1
|
||||
mov r5, r1
|
||||
mov r6, r1
|
||||
mov r7, r1
|
||||
mov r8, r1
|
||||
mov lr, r1
|
||||
|
||||
cmp r2, #96
|
||||
tstgt ip, #31
|
||||
ble 3f
|
||||
|
||||
and r8, ip, #31
|
||||
rsb r8, r8, #32
|
||||
sub r2, r2, r8
|
||||
movs r8, r8, lsl #(32 - 4)
|
||||
stmiacs ip!, {r4, r5, r6, r7}
|
||||
stmiami ip!, {r4, r5}
|
||||
tst r8, #(1 << 30)
|
||||
mov r8, r1
|
||||
strne r1, [ip], #4
|
||||
|
||||
3: subs r2, r2, #64
|
||||
stmiage ip!, {r1, r3-r8, lr}
|
||||
stmiage ip!, {r1, r3-r8, lr}
|
||||
bgt 3b
|
||||
ldmfdeq sp!, {r4-r8, pc}
|
||||
|
||||
tst r2, #32
|
||||
stmiane ip!, {r1, r3-r8, lr}
|
||||
tst r2, #16
|
||||
stmiane ip!, {r4-r7}
|
||||
ldmfd sp!, {r4-r8, lr}
|
||||
|
||||
#endif
|
||||
|
||||
4: tst r2, #8
|
||||
stmiane ip!, {r1, r3}
|
||||
tst r2, #4
|
||||
strne r1, [ip], #4
|
||||
/*
|
||||
* When we get here, we've got less than 4 bytes to zero. We
|
||||
* may have an unaligned pointer as well.
|
||||
*/
|
||||
5: tst r2, #2
|
||||
strbne r1, [ip], #1
|
||||
strbne r1, [ip], #1
|
||||
tst r2, #1
|
||||
strbne r1, [ip], #1
|
||||
ret lr
|
||||
|
||||
6: subs r2, r2, #4 @ 1 do we have enough
|
||||
blt 5b @ 1 bytes to align with?
|
||||
cmp r3, #2 @ 1
|
||||
strblt r1, [ip], #1 @ 1
|
||||
strble r1, [ip], #1 @ 1
|
||||
strb r1, [ip], #1 @ 1
|
||||
add r2, r2, r3 @ 1 (r2 = r2 - (4 - r3))
|
||||
b 1b
|
||||
ENDPROC(memset)
|
||||
@@ -0,0 +1,47 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* linux/arch/arm/lib/muldi3.S
|
||||
*
|
||||
* Author: Nicolas Pitre
|
||||
* Created: Oct 19, 2005
|
||||
* Copyright: Monta Vista Software, Inc.
|
||||
*/
|
||||
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/assembler.h>
|
||||
|
||||
#ifdef __ARMEB__
|
||||
#define xh r0
|
||||
#define xl r1
|
||||
#define yh r2
|
||||
#define yl r3
|
||||
#else
|
||||
#define xl r0
|
||||
#define xh r1
|
||||
#define yl r2
|
||||
#define yh r3
|
||||
#endif
|
||||
|
||||
.pushsection .text.__muldi3, "ax"
|
||||
ENTRY(__muldi3)
|
||||
ENTRY(__aeabi_lmul)
|
||||
|
||||
mul xh, yl, xh
|
||||
mla xh, xl, yh, xh
|
||||
mov ip, xl, lsr #16
|
||||
mov yh, yl, lsr #16
|
||||
bic xl, xl, ip, lsl #16
|
||||
bic yl, yl, yh, lsl #16
|
||||
mla xh, yh, ip, xh
|
||||
mul yh, xl, yh
|
||||
mul xl, yl, xl
|
||||
mul ip, yl, ip
|
||||
adds xl, xl, yh, lsl #16
|
||||
adc xh, xh, yh, lsr #16
|
||||
adds xl, xl, ip, lsl #16
|
||||
adc xh, xh, ip, lsr #16
|
||||
ret lr
|
||||
|
||||
ENDPROC(__muldi3)
|
||||
ENDPROC(__aeabi_lmul)
|
||||
.popsection
|
||||
@@ -0,0 +1,125 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright 2016 NXP Semiconductor, Inc.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <linux/libfdt.h>
|
||||
#include <fdt_support.h>
|
||||
#include <linux/sizes.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <asm/psci.h>
|
||||
#ifdef CONFIG_ARMV8_SEC_FIRMWARE_SUPPORT
|
||||
#include <asm/armv8/sec_firmware.h>
|
||||
#endif
|
||||
|
||||
int fdt_psci(void *fdt)
|
||||
{
|
||||
#if defined(CONFIG_ARMV7_PSCI) || defined(CONFIG_ARMV8_PSCI) || \
|
||||
defined(CONFIG_SEC_FIRMWARE_ARMV8_PSCI)
|
||||
int nodeoff;
|
||||
unsigned int psci_ver = 0;
|
||||
int tmp;
|
||||
|
||||
nodeoff = fdt_path_offset(fdt, "/cpus");
|
||||
if (nodeoff < 0) {
|
||||
printf("couldn't find /cpus\n");
|
||||
return nodeoff;
|
||||
}
|
||||
|
||||
/* add 'enable-method = "psci"' to each cpu node */
|
||||
for (tmp = fdt_first_subnode(fdt, nodeoff);
|
||||
tmp >= 0;
|
||||
tmp = fdt_next_subnode(fdt, tmp)) {
|
||||
const struct fdt_property *prop;
|
||||
int len;
|
||||
|
||||
prop = fdt_get_property(fdt, tmp, "device_type", &len);
|
||||
if (!prop)
|
||||
continue;
|
||||
if (len < 4)
|
||||
continue;
|
||||
if (strcmp(prop->data, "cpu"))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Not checking rv here, our approach is to skip over errors in
|
||||
* individual cpu nodes, hopefully some of the nodes are
|
||||
* processed correctly and those will boot
|
||||
*/
|
||||
fdt_setprop_string(fdt, tmp, "enable-method", "psci");
|
||||
}
|
||||
|
||||
nodeoff = fdt_path_offset(fdt, "/psci");
|
||||
if (nodeoff >= 0)
|
||||
goto init_psci_node;
|
||||
|
||||
nodeoff = fdt_path_offset(fdt, "/");
|
||||
if (nodeoff < 0)
|
||||
return nodeoff;
|
||||
|
||||
nodeoff = fdt_add_subnode(fdt, nodeoff, "psci");
|
||||
if (nodeoff < 0)
|
||||
return nodeoff;
|
||||
|
||||
init_psci_node:
|
||||
#ifdef CONFIG_ARMV8_SEC_FIRMWARE_SUPPORT
|
||||
psci_ver = sec_firmware_support_psci_version();
|
||||
#elif defined(CONFIG_ARMV7_PSCI_1_0) || defined(CONFIG_ARMV8_PSCI)
|
||||
psci_ver = ARM_PSCI_VER_1_0;
|
||||
#elif defined(CONFIG_ARMV7_PSCI_0_2)
|
||||
psci_ver = ARM_PSCI_VER_0_2;
|
||||
#endif
|
||||
if (psci_ver >= ARM_PSCI_VER_1_0) {
|
||||
tmp = fdt_setprop_string(fdt, nodeoff,
|
||||
"compatible", "arm,psci-1.0");
|
||||
if (tmp)
|
||||
return tmp;
|
||||
}
|
||||
|
||||
if (psci_ver >= ARM_PSCI_VER_0_2) {
|
||||
tmp = fdt_appendprop_string(fdt, nodeoff,
|
||||
"compatible", "arm,psci-0.2");
|
||||
if (tmp)
|
||||
return tmp;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_ARMV8_SEC_FIRMWARE_SUPPORT
|
||||
/*
|
||||
* The Secure firmware framework isn't able to support PSCI version 0.1.
|
||||
*/
|
||||
if (psci_ver < ARM_PSCI_VER_0_2) {
|
||||
tmp = fdt_appendprop_string(fdt, nodeoff,
|
||||
"compatible", "arm,psci");
|
||||
if (tmp)
|
||||
return tmp;
|
||||
tmp = fdt_setprop_u32(fdt, nodeoff, "cpu_suspend",
|
||||
ARM_PSCI_FN_CPU_SUSPEND);
|
||||
if (tmp)
|
||||
return tmp;
|
||||
tmp = fdt_setprop_u32(fdt, nodeoff, "cpu_off",
|
||||
ARM_PSCI_FN_CPU_OFF);
|
||||
if (tmp)
|
||||
return tmp;
|
||||
tmp = fdt_setprop_u32(fdt, nodeoff, "cpu_on",
|
||||
ARM_PSCI_FN_CPU_ON);
|
||||
if (tmp)
|
||||
return tmp;
|
||||
tmp = fdt_setprop_u32(fdt, nodeoff, "migrate",
|
||||
ARM_PSCI_FN_MIGRATE);
|
||||
if (tmp)
|
||||
return tmp;
|
||||
}
|
||||
#endif
|
||||
|
||||
tmp = fdt_setprop_string(fdt, nodeoff, "method", "smc");
|
||||
if (tmp)
|
||||
return tmp;
|
||||
|
||||
tmp = fdt_setprop_string(fdt, nodeoff, "status", "okay");
|
||||
if (tmp)
|
||||
return tmp;
|
||||
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/* reloc_aarch64.c - position independent x86 ELF shared object relocator
|
||||
Copyright (C) 2014 Linaro Ltd. <ard.biesheuvel@linaro.org>
|
||||
Copyright (C) 1999 Hewlett-Packard Co.
|
||||
Contributed by David Mosberger <davidm@hpl.hp.com>.
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials
|
||||
provided with the distribution.
|
||||
* Neither the name of Hewlett-Packard Co. nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
|
||||
BE LIABLE FOR ANYDIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <efi.h>
|
||||
|
||||
#include <elf.h>
|
||||
|
||||
efi_status_t EFIAPI _relocate(long ldbase, Elf64_Dyn *dyn)
|
||||
{
|
||||
long relsz = 0, relent = 0;
|
||||
Elf64_Rela *rel = 0;
|
||||
unsigned long *addr;
|
||||
int i;
|
||||
|
||||
for (i = 0; dyn[i].d_tag != DT_NULL; ++i) {
|
||||
switch (dyn[i].d_tag) {
|
||||
case DT_RELA:
|
||||
rel = (Elf64_Rela *)((ulong)dyn[i].d_un.d_ptr + ldbase);
|
||||
break;
|
||||
case DT_RELASZ:
|
||||
relsz = dyn[i].d_un.d_val;
|
||||
break;
|
||||
case DT_RELAENT:
|
||||
relent = dyn[i].d_un.d_val;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!rel && relent == 0)
|
||||
return EFI_SUCCESS;
|
||||
|
||||
if (!rel || relent == 0)
|
||||
return EFI_LOAD_ERROR;
|
||||
|
||||
while (relsz > 0) {
|
||||
/* apply the relocs */
|
||||
switch (ELF64_R_TYPE(rel->r_info)) {
|
||||
case R_AARCH64_NONE:
|
||||
break;
|
||||
case R_AARCH64_RELATIVE:
|
||||
addr = (ulong *)(ldbase + rel->r_offset);
|
||||
*addr = ldbase + rel->r_addend;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
rel = (Elf64_Rela *)((char *)rel + relent);
|
||||
relsz -= relent;
|
||||
}
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
/*
|
||||
* reloc_arm.c - position-independent ARM ELF shared object relocator
|
||||
*
|
||||
* Copyright (C) 2014 Linaro Ltd. <ard.biesheuvel@linaro.org>
|
||||
* Copyright (C) 1999 Hewlett-Packard Co.
|
||||
* Contributed by David Mosberger <davidm@hpl.hp.com>.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* This file is taken and modified from the gnu-efi project.
|
||||
*/
|
||||
|
||||
#include <efi.h>
|
||||
#include <elf.h>
|
||||
|
||||
efi_status_t EFIAPI _relocate(long ldbase, Elf32_Dyn *dyn)
|
||||
{
|
||||
long relsz = 0, relent = 0;
|
||||
Elf32_Rel *rel = 0;
|
||||
ulong *addr;
|
||||
int i;
|
||||
|
||||
for (i = 0; dyn[i].d_tag != DT_NULL; ++i) {
|
||||
switch (dyn[i].d_tag) {
|
||||
case DT_REL:
|
||||
rel = (Elf32_Rel *)((ulong)dyn[i].d_un.d_ptr
|
||||
+ ldbase);
|
||||
break;
|
||||
case DT_RELSZ:
|
||||
relsz = dyn[i].d_un.d_val;
|
||||
break;
|
||||
case DT_RELENT:
|
||||
relent = dyn[i].d_un.d_val;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!rel && relent == 0)
|
||||
return EFI_SUCCESS;
|
||||
|
||||
if (!rel || relent == 0)
|
||||
return EFI_LOAD_ERROR;
|
||||
|
||||
while (relsz > 0) {
|
||||
/* apply the relocs */
|
||||
switch (ELF32_R_TYPE(rel->r_info)) {
|
||||
case R_ARM_NONE:
|
||||
break;
|
||||
case R_ARM_RELATIVE:
|
||||
addr = (ulong *)(ldbase + rel->r_offset);
|
||||
*addr += ldbase;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
rel = (Elf32_Rel *)((char *)rel + relent);
|
||||
relsz -= relent;
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* relocate - common relocation function for ARM U-Boot
|
||||
*
|
||||
* Copyright (c) 2013 Albert ARIBAUD <albert.u.boot@aribaud.net>
|
||||
*/
|
||||
|
||||
#include <asm-offsets.h>
|
||||
#include <asm/assembler.h>
|
||||
#include <config.h>
|
||||
#include <elf.h>
|
||||
#include <linux/linkage.h>
|
||||
#ifdef CONFIG_CPU_V7M
|
||||
#include <asm/armv7m.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Default/weak exception vectors relocation routine
|
||||
*
|
||||
* This routine covers the standard ARM cases: normal (0x00000000),
|
||||
* high (0xffff0000) and VBAR. SoCs which do not comply with any of
|
||||
* the standard cases must provide their own, strong, version.
|
||||
*/
|
||||
|
||||
.section .text.relocate_vectors,"ax",%progbits
|
||||
.weak relocate_vectors
|
||||
|
||||
ENTRY(relocate_vectors)
|
||||
|
||||
#ifdef CONFIG_CPU_V7M
|
||||
/*
|
||||
* On ARMv7-M we only have to write the new vector address
|
||||
* to VTOR register.
|
||||
*/
|
||||
ldr r0, [r9, #GD_RELOCADDR] /* r0 = gd->relocaddr */
|
||||
ldr r1, =V7M_SCB_BASE
|
||||
str r0, [r1, V7M_SCB_VTOR]
|
||||
#else
|
||||
#ifdef CONFIG_HAS_VBAR
|
||||
/*
|
||||
* If the ARM processor has the security extensions,
|
||||
* use VBAR to relocate the exception vectors.
|
||||
*/
|
||||
ldr r0, [r9, #GD_RELOCADDR] /* r0 = gd->relocaddr */
|
||||
mcr p15, 0, r0, c12, c0, 0 /* Set VBAR */
|
||||
#else
|
||||
/*
|
||||
* Copy the relocated exception vectors to the
|
||||
* correct address
|
||||
* CP15 c1 V bit gives us the location of the vectors:
|
||||
* 0x00000000 or 0xFFFF0000.
|
||||
*/
|
||||
ldr r0, [r9, #GD_RELOCADDR] /* r0 = gd->relocaddr */
|
||||
mrc p15, 0, r2, c1, c0, 0 /* V bit (bit[13]) in CP15 c1 */
|
||||
ands r2, r2, #(1 << 13)
|
||||
ldreq r1, =0x00000000 /* If V=0 */
|
||||
ldrne r1, =0xFFFF0000 /* If V=1 */
|
||||
ldmia r0!, {r2-r8,r10}
|
||||
stmia r1!, {r2-r8,r10}
|
||||
ldmia r0!, {r2-r8,r10}
|
||||
stmia r1!, {r2-r8,r10}
|
||||
#endif
|
||||
#endif
|
||||
bx lr
|
||||
|
||||
ENDPROC(relocate_vectors)
|
||||
|
||||
/*
|
||||
* void relocate_code(addr_moni)
|
||||
*
|
||||
* This function relocates the monitor code.
|
||||
*
|
||||
* NOTE:
|
||||
* To prevent the code below from containing references with an R_ARM_ABS32
|
||||
* relocation record type, we never refer to linker-defined symbols directly.
|
||||
* Instead, we declare literals which contain their relative location with
|
||||
* respect to relocate_code, and at run time, add relocate_code back to them.
|
||||
*/
|
||||
|
||||
ENTRY(relocate_code)
|
||||
ldr r1, =__image_copy_start /* r1 <- SRC &__image_copy_start */
|
||||
subs r4, r0, r1 /* r4 <- relocation offset */
|
||||
beq relocate_done /* skip relocation */
|
||||
ldr r2, =__image_copy_end /* r2 <- SRC &__image_copy_end */
|
||||
|
||||
copy_loop:
|
||||
ldmia r1!, {r10-r11} /* copy from source address [r1] */
|
||||
stmia r0!, {r10-r11} /* copy to target address [r0] */
|
||||
cmp r1, r2 /* until source end address [r2] */
|
||||
blo copy_loop
|
||||
|
||||
/*
|
||||
* fix .rel.dyn relocations
|
||||
*/
|
||||
ldr r2, =__rel_dyn_start /* r2 <- SRC &__rel_dyn_start */
|
||||
ldr r3, =__rel_dyn_end /* r3 <- SRC &__rel_dyn_end */
|
||||
fixloop:
|
||||
ldmia r2!, {r0-r1} /* (r0,r1) <- (SRC location,fixup) */
|
||||
and r1, r1, #0xff
|
||||
cmp r1, #R_ARM_RELATIVE
|
||||
bne fixnext
|
||||
|
||||
/* relative fix: increase location by offset */
|
||||
add r0, r0, r4
|
||||
ldr r1, [r0]
|
||||
add r1, r1, r4
|
||||
str r1, [r0]
|
||||
fixnext:
|
||||
cmp r2, r3
|
||||
blo fixloop
|
||||
|
||||
relocate_done:
|
||||
|
||||
#ifdef __XSCALE__
|
||||
/*
|
||||
* On xscale, icache must be invalidated and write buffers drained,
|
||||
* even with cache disabled - 4.2.7 of xscale core developer's manual
|
||||
*/
|
||||
mcr p15, 0, r0, c7, c7, 0 /* invalidate icache */
|
||||
mcr p15, 0, r0, c7, c10, 4 /* drain write buffer */
|
||||
#endif
|
||||
|
||||
/* ARMv4- don't know bx lr but the assembler fails to see that */
|
||||
|
||||
#ifdef __ARM_ARCH_4__
|
||||
mov pc, lr
|
||||
#else
|
||||
bx lr
|
||||
#endif
|
||||
|
||||
ENDPROC(relocate_code)
|
||||
@@ -0,0 +1,96 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* relocate - common relocation function for AArch64 U-Boot
|
||||
*
|
||||
* (C) Copyright 2013
|
||||
* Albert ARIBAUD <albert.u.boot@aribaud.net>
|
||||
* David Feng <fenghua@phytium.com.cn>
|
||||
*/
|
||||
|
||||
#include <asm-offsets.h>
|
||||
#include <config.h>
|
||||
#include <elf.h>
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/macro.h>
|
||||
|
||||
/*
|
||||
* void relocate_code (addr_moni)
|
||||
*
|
||||
* This function relocates the monitor code.
|
||||
* x0 holds the destination address.
|
||||
*/
|
||||
ENTRY(relocate_code)
|
||||
stp x29, x30, [sp, #-32]! /* create a stack frame */
|
||||
mov x29, sp
|
||||
str x0, [sp, #16]
|
||||
/*
|
||||
* Copy u-boot from flash to RAM
|
||||
*/
|
||||
adrp x1, __image_copy_start /* x1 <- address bits [31:12] */
|
||||
add x1, x1, :lo12:__image_copy_start/* x1 <- address bits [11:00] */
|
||||
subs x9, x0, x1 /* x9 <- Run to copy offset */
|
||||
b.eq relocate_done /* skip relocation */
|
||||
/*
|
||||
* Don't ldr x1, __image_copy_start here, since if the code is already
|
||||
* running at an address other than it was linked to, that instruction
|
||||
* will load the relocated value of __image_copy_start. To
|
||||
* correctly apply relocations, we need to know the linked value.
|
||||
*
|
||||
* Linked &__image_copy_start, which we know was at
|
||||
* CONFIG_SYS_TEXT_BASE, which is stored in _TEXT_BASE, as a non-
|
||||
* relocated value, since it isn't a symbol reference.
|
||||
*/
|
||||
ldr x1, _TEXT_BASE /* x1 <- Linked &__image_copy_start */
|
||||
subs x9, x0, x1 /* x9 <- Link to copy offset */
|
||||
|
||||
adrp x1, __image_copy_start /* x1 <- address bits [31:12] */
|
||||
add x1, x1, :lo12:__image_copy_start/* x1 <- address bits [11:00] */
|
||||
adrp x2, __image_copy_end /* x2 <- address bits [31:12] */
|
||||
add x2, x2, :lo12:__image_copy_end /* x2 <- address bits [11:00] */
|
||||
copy_loop:
|
||||
ldp x10, x11, [x1], #16 /* copy from source address [x1] */
|
||||
stp x10, x11, [x0], #16 /* copy to target address [x0] */
|
||||
cmp x1, x2 /* until source end address [x2] */
|
||||
b.lo copy_loop
|
||||
str x0, [sp, #24]
|
||||
|
||||
/*
|
||||
* Fix .rela.dyn relocations
|
||||
*/
|
||||
adrp x2, __rel_dyn_start /* x2 <- address bits [31:12] */
|
||||
add x2, x2, :lo12:__rel_dyn_start /* x2 <- address bits [11:00] */
|
||||
adrp x3, __rel_dyn_end /* x3 <- address bits [31:12] */
|
||||
add x3, x3, :lo12:__rel_dyn_end /* x3 <- address bits [11:00] */
|
||||
fixloop:
|
||||
ldp x0, x1, [x2], #16 /* (x0,x1) <- (SRC location, fixup) */
|
||||
ldr x4, [x2], #8 /* x4 <- addend */
|
||||
and x1, x1, #0xffffffff
|
||||
cmp x1, #R_AARCH64_RELATIVE
|
||||
bne fixnext
|
||||
|
||||
/* relative fix: store addend plus offset at dest location */
|
||||
add x0, x0, x9
|
||||
add x4, x4, x9
|
||||
str x4, [x0]
|
||||
fixnext:
|
||||
cmp x2, x3
|
||||
b.lo fixloop
|
||||
|
||||
relocate_done:
|
||||
switch_el x1, 3f, 2f, 1f
|
||||
bl hang
|
||||
3: mrs x0, sctlr_el3
|
||||
b 0f
|
||||
2: mrs x0, sctlr_el2
|
||||
b 0f
|
||||
1: mrs x0, sctlr_el1
|
||||
0: tbz w0, #2, 5f /* skip flushing cache if disabled */
|
||||
tbz w0, #12, 4f /* skip invalidating i-cache if disabled */
|
||||
ic iallu /* i-cache invalidate all */
|
||||
isb sy
|
||||
4: ldp x0, x1, [sp, #16]
|
||||
bl __asm_flush_dcache_range
|
||||
bl __asm_flush_l3_dcache
|
||||
5: ldp x29, x30, [sp],#32
|
||||
ret
|
||||
ENDPROC(relocate_code)
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2002
|
||||
* Sysgo Real-Time Solutions, GmbH <www.elinos.com>
|
||||
* Marius Groeger <mgroeger@sysgo.de>
|
||||
*
|
||||
* (C) Copyright 2002
|
||||
* Sysgo Real-Time Solutions, GmbH <www.elinos.com>
|
||||
* Alex Zuepke <azu@sysgo.de>
|
||||
*
|
||||
* (C) Copyright 2002
|
||||
* Gary Jennejohn, DENX Software Engineering, <garyj@denx.de>
|
||||
*
|
||||
* (C) Copyright 2004
|
||||
* DAVE Srl
|
||||
* http://www.dave-tech.it
|
||||
* http://www.wawnet.biz
|
||||
* mailto:info@wawnet.biz
|
||||
*
|
||||
* (C) Copyright 2004 Texas Insturments
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <irq_func.h>
|
||||
|
||||
__weak void reset_misc(void)
|
||||
{
|
||||
}
|
||||
|
||||
int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
puts ("resetting ...\n");
|
||||
|
||||
udelay (50000); /* wait 50 ms */
|
||||
|
||||
do_shutdown();
|
||||
|
||||
disable_interrupts();
|
||||
|
||||
reset_misc();
|
||||
reset_cpu(0);
|
||||
|
||||
/*NOTREACHED*/
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright 2013 Albert ARIBAUD <albert.u.boot@aribaud.net>
|
||||
*/
|
||||
|
||||
/**
|
||||
* These two symbols are declared in a C file so that the linker
|
||||
* uses R_ARM_RELATIVE relocation, rather than the R_ARM_ABS32 one
|
||||
* it would use if the symbols were defined in the linker file.
|
||||
* Using only R_ARM_RELATIVE relocation ensures that references to
|
||||
* the symbols are correct after as well as before relocation.
|
||||
*
|
||||
* We need a 0-byte-size type for these symbols, and the compiler
|
||||
* does not allow defining objects of C type 'void'. Using an empty
|
||||
* struct is allowed by the compiler, but causes gcc versions 4.4 and
|
||||
* below to complain about aliasing. Therefore we use the next best
|
||||
* thing: zero-sized arrays, which are both 0-byte-size and exempt from
|
||||
* aliasing warnings.
|
||||
*/
|
||||
|
||||
char __bss_start[0] __attribute__((section(".__bss_start")));
|
||||
char __bss_end[0] __attribute__((section(".__bss_end")));
|
||||
char __image_copy_start[0] __attribute__((section(".__image_copy_start")));
|
||||
char __image_copy_end[0] __attribute__((section(".__image_copy_end")));
|
||||
char __rel_dyn_start[0] __attribute__((section(".__rel_dyn_start")));
|
||||
char __rel_dyn_end[0] __attribute__((section(".__rel_dyn_end")));
|
||||
char __secure_start[0] __attribute__((section(".__secure_start")));
|
||||
char __secure_end[0] __attribute__((section(".__secure_end")));
|
||||
char __secure_stack_start[0] __attribute__((section(".__secure_stack_start")));
|
||||
char __secure_stack_end[0] __attribute__((section(".__secure_stack_end")));
|
||||
char __efi_runtime_start[0] __attribute__((section(".__efi_runtime_start")));
|
||||
char __efi_runtime_stop[0] __attribute__((section(".__efi_runtime_stop")));
|
||||
char __efi_runtime_rel_start[0] __attribute__((section(".__efi_runtime_rel_start")));
|
||||
char __efi_runtime_rel_stop[0] __attribute__((section(".__efi_runtime_rel_stop")));
|
||||
char _end[0] __attribute__((section(".__end")));
|
||||
@@ -0,0 +1,215 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright 2014 Broadcom Corporation
|
||||
*/
|
||||
|
||||
/*
|
||||
* Minimal semihosting implementation for reading files into memory. If more
|
||||
* features like writing files or console output are required they can be
|
||||
* added later. This code has been tested on arm64/aarch64 fastmodel only.
|
||||
* An untested placeholder exists for armv7 architectures, but since they
|
||||
* are commonly available in silicon now, fastmodel usage makes less sense
|
||||
* for them.
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
|
||||
#define SYSOPEN 0x01
|
||||
#define SYSCLOSE 0x02
|
||||
#define SYSREAD 0x06
|
||||
#define SYSFLEN 0x0C
|
||||
|
||||
#define MODE_READ 0x0
|
||||
#define MODE_READBIN 0x1
|
||||
|
||||
/*
|
||||
* Call the handler
|
||||
*/
|
||||
static noinline long smh_trap(unsigned int sysnum, void *addr)
|
||||
{
|
||||
register long result asm("r0");
|
||||
#if defined(CONFIG_ARM64)
|
||||
asm volatile ("hlt #0xf000" : "=r" (result) : "0"(sysnum), "r"(addr));
|
||||
#elif defined(CONFIG_CPU_V7M)
|
||||
asm volatile ("bkpt #0xAB" : "=r" (result) : "0"(sysnum), "r"(addr));
|
||||
#else
|
||||
/* Note - untested placeholder */
|
||||
asm volatile ("svc #0x123456" : "=r" (result) : "0"(sysnum), "r"(addr));
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Open a file on the host. Mode is "r" or "rb" currently. Returns a file
|
||||
* descriptor or -1 on error.
|
||||
*/
|
||||
static long smh_open(const char *fname, char *modestr)
|
||||
{
|
||||
long fd;
|
||||
unsigned long mode;
|
||||
struct smh_open_s {
|
||||
const char *fname;
|
||||
unsigned long mode;
|
||||
size_t len;
|
||||
} open;
|
||||
|
||||
debug("%s: file \'%s\', mode \'%s\'\n", __func__, fname, modestr);
|
||||
|
||||
/* Check the file mode */
|
||||
if (!(strcmp(modestr, "r"))) {
|
||||
mode = MODE_READ;
|
||||
} else if (!(strcmp(modestr, "rb"))) {
|
||||
mode = MODE_READBIN;
|
||||
} else {
|
||||
printf("%s: ERROR mode \'%s\' not supported\n", __func__,
|
||||
modestr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
open.fname = fname;
|
||||
open.len = strlen(fname);
|
||||
open.mode = mode;
|
||||
|
||||
/* Open the file on the host */
|
||||
fd = smh_trap(SYSOPEN, &open);
|
||||
if (fd == -1)
|
||||
printf("%s: ERROR fd %ld for file \'%s\'\n", __func__, fd,
|
||||
fname);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read 'len' bytes of file into 'memp'. Returns 0 on success, else failure
|
||||
*/
|
||||
static long smh_read(long fd, void *memp, size_t len)
|
||||
{
|
||||
long ret;
|
||||
struct smh_read_s {
|
||||
long fd;
|
||||
void *memp;
|
||||
size_t len;
|
||||
} read;
|
||||
|
||||
debug("%s: fd %ld, memp %p, len %zu\n", __func__, fd, memp, len);
|
||||
|
||||
read.fd = fd;
|
||||
read.memp = memp;
|
||||
read.len = len;
|
||||
|
||||
ret = smh_trap(SYSREAD, &read);
|
||||
if (ret < 0) {
|
||||
/*
|
||||
* The ARM handler allows for returning partial lengths,
|
||||
* but in practice this never happens so rather than create
|
||||
* hard to maintain partial read loops and such, just fail
|
||||
* with an error message.
|
||||
*/
|
||||
printf("%s: ERROR ret %ld, fd %ld, len %zu memp %p\n",
|
||||
__func__, ret, fd, len, memp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Close the file using the file descriptor
|
||||
*/
|
||||
static long smh_close(long fd)
|
||||
{
|
||||
long ret;
|
||||
|
||||
debug("%s: fd %ld\n", __func__, fd);
|
||||
|
||||
ret = smh_trap(SYSCLOSE, &fd);
|
||||
if (ret == -1)
|
||||
printf("%s: ERROR fd %ld\n", __func__, fd);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the file length from the file descriptor
|
||||
*/
|
||||
static long smh_len_fd(long fd)
|
||||
{
|
||||
long ret;
|
||||
|
||||
debug("%s: fd %ld\n", __func__, fd);
|
||||
|
||||
ret = smh_trap(SYSFLEN, &fd);
|
||||
if (ret == -1)
|
||||
printf("%s: ERROR ret %ld, fd %ld\n", __func__, ret, fd);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int smh_load_file(const char * const name, ulong load_addr,
|
||||
ulong *end_addr)
|
||||
{
|
||||
long fd;
|
||||
long len;
|
||||
long ret;
|
||||
|
||||
fd = smh_open(name, "rb");
|
||||
if (fd == -1)
|
||||
return -1;
|
||||
|
||||
len = smh_len_fd(fd);
|
||||
if (len < 0) {
|
||||
smh_close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = smh_read(fd, (void *)load_addr, len);
|
||||
smh_close(fd);
|
||||
|
||||
if (ret == 0) {
|
||||
*end_addr = load_addr + len - 1;
|
||||
printf("loaded file %s from %08lX to %08lX, %08lX bytes\n",
|
||||
name,
|
||||
load_addr,
|
||||
*end_addr,
|
||||
len);
|
||||
} else {
|
||||
printf("read failed\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_smhload(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
if (argc == 3 || argc == 4) {
|
||||
ulong load_addr;
|
||||
ulong end_addr = 0;
|
||||
int ret;
|
||||
char end_str[64];
|
||||
|
||||
load_addr = simple_strtoul(argv[2], NULL, 16);
|
||||
if (!load_addr)
|
||||
return -1;
|
||||
|
||||
ret = smh_load_file(argv[1], load_addr, &end_addr);
|
||||
if (ret < 0)
|
||||
return CMD_RET_FAILURE;
|
||||
|
||||
/* Optionally save returned end to the environment */
|
||||
if (argc == 4) {
|
||||
sprintf(end_str, "0x%08lx", end_addr);
|
||||
env_set(argv[3], end_str);
|
||||
}
|
||||
} else {
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
U_BOOT_CMD(smhload, 4, 0, do_smhload, "load a file using semihosting",
|
||||
"<file> 0x<address> [end var]\n"
|
||||
" - load a semihosted file to the address specified\n"
|
||||
" if the optional [end var] is specified, the end\n"
|
||||
" address of the file will be stored in this environment\n"
|
||||
" variable.\n");
|
||||
@@ -0,0 +1,36 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* (C) 2017 Theobroma Systems Design und Consulting GmbH
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <asm/assembler.h>
|
||||
#include <linux/linkage.h>
|
||||
|
||||
.pushsection .text.setjmp, "ax"
|
||||
ENTRY(setjmp)
|
||||
/*
|
||||
* A subroutine must preserve the contents of the registers
|
||||
* r4-r8, r10, r11 (v1-v5, v7 and v8) and SP (and r9 in PCS
|
||||
* variants that designate r9 as v6).
|
||||
*/
|
||||
mov ip, sp
|
||||
stm a1, {v1-v8, ip, lr}
|
||||
mov a1, #0
|
||||
bx lr
|
||||
ENDPROC(setjmp)
|
||||
.popsection
|
||||
|
||||
.pushsection .text.longjmp, "ax"
|
||||
ENTRY(longjmp)
|
||||
ldm a1, {v1-v8, ip, lr}
|
||||
mov sp, ip
|
||||
mov a1, a2
|
||||
/* If we were passed a return value of zero, return one instead */
|
||||
cmp a1, #0
|
||||
bne 1f
|
||||
mov a1, #1
|
||||
1:
|
||||
bx lr
|
||||
ENDPROC(longjmp)
|
||||
.popsection
|
||||
@@ -0,0 +1,41 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* (C) 2017 Theobroma Systems Design und Consulting GmbH
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <asm/macro.h>
|
||||
#include <linux/linkage.h>
|
||||
|
||||
.pushsection .text.setjmp, "ax"
|
||||
ENTRY(setjmp)
|
||||
/* Preserve all callee-saved registers and the SP */
|
||||
stp x19, x20, [x0,#0]
|
||||
stp x21, x22, [x0,#16]
|
||||
stp x23, x24, [x0,#32]
|
||||
stp x25, x26, [x0,#48]
|
||||
stp x27, x28, [x0,#64]
|
||||
stp x29, x30, [x0,#80]
|
||||
mov x2, sp
|
||||
str x2, [x0, #96]
|
||||
mov x0, #0
|
||||
ret
|
||||
ENDPROC(setjmp)
|
||||
.popsection
|
||||
|
||||
.pushsection .text.longjmp, "ax"
|
||||
ENTRY(longjmp)
|
||||
ldp x19, x20, [x0,#0]
|
||||
ldp x21, x22, [x0,#16]
|
||||
ldp x23, x24, [x0,#32]
|
||||
ldp x25, x26, [x0,#48]
|
||||
ldp x27, x28, [x0,#64]
|
||||
ldp x29, x30, [x0,#80]
|
||||
ldr x2, [x0,#96]
|
||||
mov sp, x2
|
||||
/* Move the return value in place, but return 1 if passed 0. */
|
||||
adds x0, xzr, x1
|
||||
csinc x0, x0, xzr, ne
|
||||
ret
|
||||
ENDPROC(longjmp)
|
||||
.popsection
|
||||
@@ -0,0 +1,75 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2010-2012
|
||||
* Texas Instruments, <www.ti.com>
|
||||
*
|
||||
* Aneesh V <aneesh@ti.com>
|
||||
* Tom Rini <trini@ti.com>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <config.h>
|
||||
#include <spl.h>
|
||||
#include <image.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <asm/mach-types.h>
|
||||
|
||||
#ifndef CONFIG_SPL_DM
|
||||
/* Pointer to as well as the global data structure for SPL */
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
/*
|
||||
* WARNING: This is going away very soon. Don't use it and don't submit
|
||||
* pafches that rely on it. The global_data area is set up in crt0.S.
|
||||
*/
|
||||
gd_t gdata __attribute__ ((section(".data")));
|
||||
#endif
|
||||
|
||||
/*
|
||||
* In the context of SPL, board_init_f() prepares the hardware for execution
|
||||
* from system RAM (DRAM, DDR...). As system RAM may not be available yet,
|
||||
* board_init_f() must use the current GD to store any data which must be
|
||||
* passed on to later stages. These data include the relocation destination,
|
||||
* the future stack, and the future GD location. BSS is cleared after this
|
||||
* function (and therefore must be accessible).
|
||||
*
|
||||
* We provide this version by default but mark it as __weak to allow for
|
||||
* platforms to do this in their own way if needed. Please see the top
|
||||
* level U-Boot README "Board Initialization Flow" section for info on what
|
||||
* to put in this function.
|
||||
*/
|
||||
void __weak board_init_f(ulong dummy)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* This function jumps to an image with argument. Normally an FDT or ATAGS
|
||||
* image.
|
||||
*/
|
||||
#ifdef CONFIG_SPL_OS_BOOT
|
||||
#ifdef CONFIG_ARM64
|
||||
void __noreturn jump_to_image_linux(struct spl_image_info *spl_image)
|
||||
{
|
||||
debug("Entering kernel arg pointer: 0x%p\n", spl_image->arg);
|
||||
cleanup_before_linux();
|
||||
armv8_switch_to_el2((u64)spl_image->arg, 0, 0, 0,
|
||||
spl_image->entry_point, ES_TO_AARCH64);
|
||||
}
|
||||
#else
|
||||
void __noreturn jump_to_image_linux(struct spl_image_info *spl_image)
|
||||
{
|
||||
unsigned long machid = 0xffffffff;
|
||||
#ifdef CONFIG_MACH_TYPE
|
||||
machid = CONFIG_MACH_TYPE;
|
||||
#endif
|
||||
|
||||
debug("Entering kernel arg pointer: 0x%p\n", spl_image->arg);
|
||||
typedef void (*image_entry_arg_t)(int, int, void *)
|
||||
__attribute__ ((noreturn));
|
||||
image_entry_arg_t image_entry =
|
||||
(image_entry_arg_t)(uintptr_t) spl_image->entry_point;
|
||||
cleanup_before_linux();
|
||||
image_entry(0, machid, spl_image->arg);
|
||||
}
|
||||
#endif /* CONFIG_ARM64 */
|
||||
#endif
|
||||
@@ -0,0 +1,33 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (c) 2015 Andreas Bießmann <andreas@biessmann.org>
|
||||
*
|
||||
* Copyright (c) 2011 The Chromium OS Authors.
|
||||
* (C) Copyright 2002-2006
|
||||
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
*
|
||||
* (C) Copyright 2002
|
||||
* Sysgo Real-Time Solutions, GmbH <www.elinos.com>
|
||||
* Marius Groeger <mgroeger@sysgo.de>
|
||||
*/
|
||||
#include <common.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
int arch_reserve_stacks(void)
|
||||
{
|
||||
#ifdef CONFIG_SPL_BUILD
|
||||
gd->start_addr_sp -= 128; /* leave 32 words for abort-stack */
|
||||
gd->irq_sp = gd->start_addr_sp;
|
||||
#else
|
||||
/* setup stack pointer for exceptions */
|
||||
gd->irq_sp = gd->start_addr_sp;
|
||||
|
||||
# if !defined(CONFIG_ARM64)
|
||||
/* leave 3 words for abort-stack, plus 1 for alignment */
|
||||
gd->start_addr_sp -= 16;
|
||||
# endif
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,245 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright 2010, Google Inc.
|
||||
*
|
||||
* Brought in from coreboot uldivmod.S
|
||||
*/
|
||||
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/assembler.h>
|
||||
|
||||
/*
|
||||
* A, Q = r0 + (r1 << 32)
|
||||
* B, R = r2 + (r3 << 32)
|
||||
* A / B = Q ... R
|
||||
*/
|
||||
|
||||
A_0 .req r0
|
||||
A_1 .req r1
|
||||
B_0 .req r2
|
||||
B_1 .req r3
|
||||
C_0 .req r4
|
||||
C_1 .req r5
|
||||
D_0 .req r6
|
||||
D_1 .req r7
|
||||
|
||||
Q_0 .req r0
|
||||
Q_1 .req r1
|
||||
R_0 .req r2
|
||||
R_1 .req r3
|
||||
|
||||
THUMB(
|
||||
TMP .req r8
|
||||
)
|
||||
|
||||
.pushsection .text.__aeabi_uldivmod, "ax"
|
||||
ENTRY(__aeabi_uldivmod)
|
||||
|
||||
stmfd sp!, {r4, r5, r6, r7, THUMB(TMP,) lr}
|
||||
@ Test if B == 0
|
||||
orrs ip, B_0, B_1 @ Z set -> B == 0
|
||||
beq L_div_by_0
|
||||
@ Test if B is power of 2: (B & (B - 1)) == 0
|
||||
subs C_0, B_0, #1
|
||||
sbc C_1, B_1, #0
|
||||
tst C_0, B_0
|
||||
tsteq B_1, C_1
|
||||
beq L_pow2
|
||||
@ Test if A_1 == B_1 == 0
|
||||
orrs ip, A_1, B_1
|
||||
beq L_div_32_32
|
||||
|
||||
L_div_64_64:
|
||||
/* CLZ only exists in ARM architecture version 5 and above. */
|
||||
#ifdef HAVE_CLZ
|
||||
mov C_0, #1
|
||||
mov C_1, #0
|
||||
@ D_0 = clz A
|
||||
teq A_1, #0
|
||||
clz D_0, A_1
|
||||
clzeq ip, A_0
|
||||
addeq D_0, D_0, ip
|
||||
@ D_1 = clz B
|
||||
teq B_1, #0
|
||||
clz D_1, B_1
|
||||
clzeq ip, B_0
|
||||
addeq D_1, D_1, ip
|
||||
@ if clz B - clz A > 0
|
||||
subs D_0, D_1, D_0
|
||||
bls L_done_shift
|
||||
@ B <<= (clz B - clz A)
|
||||
subs D_1, D_0, #32
|
||||
rsb ip, D_0, #32
|
||||
movmi B_1, B_1, lsl D_0
|
||||
ARM( orrmi B_1, B_1, B_0, lsr ip )
|
||||
THUMB( lsrmi TMP, B_0, ip )
|
||||
THUMB( orrmi B_1, B_1, TMP )
|
||||
movpl B_1, B_0, lsl D_1
|
||||
mov B_0, B_0, lsl D_0
|
||||
@ C = 1 << (clz B - clz A)
|
||||
movmi C_1, C_1, lsl D_0
|
||||
ARM( orrmi C_1, C_1, C_0, lsr ip )
|
||||
THUMB( lsrmi TMP, C_0, ip )
|
||||
THUMB( orrmi C_1, C_1, TMP )
|
||||
movpl C_1, C_0, lsl D_1
|
||||
mov C_0, C_0, lsl D_0
|
||||
L_done_shift:
|
||||
mov D_0, #0
|
||||
mov D_1, #0
|
||||
@ C: current bit; D: result
|
||||
#else
|
||||
@ C: current bit; D: result
|
||||
mov C_0, #1
|
||||
mov C_1, #0
|
||||
mov D_0, #0
|
||||
mov D_1, #0
|
||||
L_lsl_4:
|
||||
cmp B_1, #0x10000000
|
||||
cmpcc B_1, A_1
|
||||
cmpeq B_0, A_0
|
||||
bcs L_lsl_1
|
||||
@ B <<= 4
|
||||
mov B_1, B_1, lsl #4
|
||||
orr B_1, B_1, B_0, lsr #28
|
||||
mov B_0, B_0, lsl #4
|
||||
@ C <<= 4
|
||||
mov C_1, C_1, lsl #4
|
||||
orr C_1, C_1, C_0, lsr #28
|
||||
mov C_0, C_0, lsl #4
|
||||
b L_lsl_4
|
||||
L_lsl_1:
|
||||
cmp B_1, #0x80000000
|
||||
cmpcc B_1, A_1
|
||||
cmpeq B_0, A_0
|
||||
bcs L_subtract
|
||||
@ B <<= 1
|
||||
mov B_1, B_1, lsl #1
|
||||
orr B_1, B_1, B_0, lsr #31
|
||||
mov B_0, B_0, lsl #1
|
||||
@ C <<= 1
|
||||
mov C_1, C_1, lsl #1
|
||||
orr C_1, C_1, C_0, lsr #31
|
||||
mov C_0, C_0, lsl #1
|
||||
b L_lsl_1
|
||||
#endif
|
||||
L_subtract:
|
||||
@ if A >= B
|
||||
cmp A_1, B_1
|
||||
cmpeq A_0, B_0
|
||||
bcc L_update
|
||||
@ A -= B
|
||||
subs A_0, A_0, B_0
|
||||
sbc A_1, A_1, B_1
|
||||
@ D |= C
|
||||
orr D_0, D_0, C_0
|
||||
orr D_1, D_1, C_1
|
||||
L_update:
|
||||
@ if A == 0: break
|
||||
orrs ip, A_1, A_0
|
||||
beq L_exit
|
||||
@ C >>= 1
|
||||
movs C_1, C_1, lsr #1
|
||||
movs C_0, C_0, rrx
|
||||
@ if C == 0: break
|
||||
orrs ip, C_1, C_0
|
||||
beq L_exit
|
||||
@ B >>= 1
|
||||
movs B_1, B_1, lsr #1
|
||||
mov B_0, B_0, rrx
|
||||
b L_subtract
|
||||
L_exit:
|
||||
@ Note: A, B & Q, R are aliases
|
||||
mov R_0, A_0
|
||||
mov R_1, A_1
|
||||
mov Q_0, D_0
|
||||
mov Q_1, D_1
|
||||
ldmfd sp!, {r4, r5, r6, r7, THUMB(TMP,) pc}
|
||||
|
||||
L_div_32_32:
|
||||
@ Note: A_0 & r0 are aliases
|
||||
@ Q_1 r1
|
||||
mov r1, B_0
|
||||
bl __aeabi_uidivmod
|
||||
mov R_0, r1
|
||||
mov R_1, #0
|
||||
mov Q_1, #0
|
||||
ldmfd sp!, {r4, r5, r6, r7, THUMB(TMP,) pc}
|
||||
|
||||
L_pow2:
|
||||
#ifdef HAVE_CLZ
|
||||
@ Note: A, B and Q, R are aliases
|
||||
@ R = A & (B - 1)
|
||||
and C_0, A_0, C_0
|
||||
and C_1, A_1, C_1
|
||||
@ Q = A >> log2(B)
|
||||
@ Note: B must not be 0 here!
|
||||
clz D_0, B_0
|
||||
add D_1, D_0, #1
|
||||
rsbs D_0, D_0, #31
|
||||
bpl L_1
|
||||
clz D_0, B_1
|
||||
rsb D_0, D_0, #31
|
||||
mov A_0, A_1, lsr D_0
|
||||
add D_0, D_0, #32
|
||||
L_1:
|
||||
movpl A_0, A_0, lsr D_0
|
||||
ARM( orrpl A_0, A_0, A_1, lsl D_1 )
|
||||
THUMB( lslpl TMP, A_1, D_1 )
|
||||
THUMB( orrpl A_0, A_0, TMP )
|
||||
mov A_1, A_1, lsr D_0
|
||||
@ Mov back C to R
|
||||
mov R_0, C_0
|
||||
mov R_1, C_1
|
||||
ldmfd sp!, {r4, r5, r6, r7, THUMB(TMP,) pc}
|
||||
#else
|
||||
@ Note: A, B and Q, R are aliases
|
||||
@ R = A & (B - 1)
|
||||
and C_0, A_0, C_0
|
||||
and C_1, A_1, C_1
|
||||
@ Q = A >> log2(B)
|
||||
@ Note: B must not be 0 here!
|
||||
@ Count the leading zeroes in B.
|
||||
mov D_0, #0
|
||||
orrs B_0, B_0, B_0
|
||||
@ If B is greater than 1 << 31, divide A and B by 1 << 32.
|
||||
moveq A_0, A_1
|
||||
moveq A_1, #0
|
||||
moveq B_0, B_1
|
||||
@ Count the remaining leading zeroes in B.
|
||||
movs B_1, B_0, lsl #16
|
||||
addeq D_0, #16
|
||||
moveq B_0, B_0, lsr #16
|
||||
tst B_0, #0xff
|
||||
addeq D_0, #8
|
||||
moveq B_0, B_0, lsr #8
|
||||
tst B_0, #0xf
|
||||
addeq D_0, #4
|
||||
moveq B_0, B_0, lsr #4
|
||||
tst B_0, #0x3
|
||||
addeq D_0, #2
|
||||
moveq B_0, B_0, lsr #2
|
||||
tst B_0, #0x1
|
||||
addeq D_0, #1
|
||||
@ Shift A to the right by the appropriate amount.
|
||||
rsb D_1, D_0, #32
|
||||
mov Q_0, A_0, lsr D_0
|
||||
ARM( orr Q_0, Q_0, A_1, lsl D_1 )
|
||||
THUMB( lsl A_1, D_1 )
|
||||
THUMB( orr Q_0, A_1 )
|
||||
mov Q_1, A_1, lsr D_0
|
||||
@ Move C to R
|
||||
mov R_0, C_0
|
||||
mov R_1, C_1
|
||||
ldmfd sp!, {r4, r5, r6, r7, THUMB(TMP,) pc}
|
||||
#endif
|
||||
|
||||
L_div_by_0:
|
||||
bl __div0
|
||||
@ As wrong as it could be
|
||||
mov Q_0, #0
|
||||
mov Q_1, #0
|
||||
mov R_0, #0
|
||||
mov R_1, #0
|
||||
ldmfd sp!, {r4, r5, r6, r7, THUMB(TMP,) pc}
|
||||
ENDPROC(__aeabi_uldivmod)
|
||||
.popsection
|
||||
@@ -0,0 +1,292 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* vectors - Generic ARM exception table code
|
||||
*
|
||||
* Copyright (c) 1998 Dan Malek <dmalek@jlc.net>
|
||||
* Copyright (c) 1999 Magnus Damm <kieraypc01.p.y.kie.era.ericsson.se>
|
||||
* Copyright (c) 2000 Wolfgang Denk <wd@denx.de>
|
||||
* Copyright (c) 2001 Alex Züpke <azu@sysgo.de>
|
||||
* Copyright (c) 2001 Marius Gröger <mag@sysgo.de>
|
||||
* Copyright (c) 2002 Alex Züpke <azu@sysgo.de>
|
||||
* Copyright (c) 2002 Gary Jennejohn <garyj@denx.de>
|
||||
* Copyright (c) 2002 Kyle Harris <kharris@nexus-tech.net>
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
/*
|
||||
* A macro to allow insertion of an ARM exception vector either
|
||||
* for the non-boot0 case or by a boot0-header.
|
||||
*/
|
||||
.macro ARM_VECTORS
|
||||
#ifdef CONFIG_ARCH_K3
|
||||
ldr pc, _reset
|
||||
#else
|
||||
b reset
|
||||
#endif
|
||||
ldr pc, _undefined_instruction
|
||||
ldr pc, _software_interrupt
|
||||
ldr pc, _prefetch_abort
|
||||
ldr pc, _data_abort
|
||||
ldr pc, _not_used
|
||||
ldr pc, _irq
|
||||
ldr pc, _fiq
|
||||
.endm
|
||||
|
||||
|
||||
/*
|
||||
*************************************************************************
|
||||
*
|
||||
* Symbol _start is referenced elsewhere, so make it global
|
||||
*
|
||||
*************************************************************************
|
||||
*/
|
||||
|
||||
.globl _start
|
||||
|
||||
/*
|
||||
*************************************************************************
|
||||
*
|
||||
* Vectors have their own section so linker script can map them easily
|
||||
*
|
||||
*************************************************************************
|
||||
*/
|
||||
|
||||
.section ".vectors", "ax"
|
||||
|
||||
#if defined(CONFIG_ENABLE_ARM_SOC_BOOT0_HOOK)
|
||||
/*
|
||||
* Various SoCs need something special and SoC-specific up front in
|
||||
* order to boot, allow them to set that in their boot0.h file and then
|
||||
* use it here.
|
||||
*
|
||||
* To allow a boot0 hook to insert a 'special' sequence after the vector
|
||||
* table (e.g. for the socfpga), the presence of a boot0 hook supresses
|
||||
* the below vector table and assumes that the vector table is filled in
|
||||
* by the boot0 hook. The requirements for a boot0 hook thus are:
|
||||
* (1) defines '_start:' as appropriate
|
||||
* (2) inserts the vector table using ARM_VECTORS as appropriate
|
||||
*/
|
||||
#include <asm/arch/boot0.h>
|
||||
#else
|
||||
|
||||
/*
|
||||
*************************************************************************
|
||||
*
|
||||
* Exception vectors as described in ARM reference manuals
|
||||
*
|
||||
* Uses indirect branch to allow reaching handlers anywhere in memory.
|
||||
*
|
||||
*************************************************************************
|
||||
*/
|
||||
|
||||
_start:
|
||||
#ifdef CONFIG_SYS_DV_NOR_BOOT_CFG
|
||||
.word CONFIG_SYS_DV_NOR_BOOT_CFG
|
||||
#endif
|
||||
ARM_VECTORS
|
||||
#endif /* !defined(CONFIG_ENABLE_ARM_SOC_BOOT0_HOOK) */
|
||||
|
||||
/*
|
||||
*************************************************************************
|
||||
*
|
||||
* Indirect vectors table
|
||||
*
|
||||
* Symbols referenced here must be defined somewhere else
|
||||
*
|
||||
*************************************************************************
|
||||
*/
|
||||
|
||||
.globl _reset
|
||||
.globl _undefined_instruction
|
||||
.globl _software_interrupt
|
||||
.globl _prefetch_abort
|
||||
.globl _data_abort
|
||||
.globl _not_used
|
||||
.globl _irq
|
||||
.globl _fiq
|
||||
|
||||
#ifdef CONFIG_ARCH_K3
|
||||
_reset: .word reset
|
||||
#endif
|
||||
_undefined_instruction: .word undefined_instruction
|
||||
_software_interrupt: .word software_interrupt
|
||||
_prefetch_abort: .word prefetch_abort
|
||||
_data_abort: .word data_abort
|
||||
_not_used: .word not_used
|
||||
_irq: .word irq
|
||||
_fiq: .word fiq
|
||||
|
||||
.balignl 16,0xdeadbeef
|
||||
|
||||
/*
|
||||
*************************************************************************
|
||||
*
|
||||
* Interrupt handling
|
||||
*
|
||||
*************************************************************************
|
||||
*/
|
||||
|
||||
/* SPL interrupt handling: just hang */
|
||||
|
||||
#ifdef CONFIG_SPL_BUILD
|
||||
|
||||
.align 5
|
||||
undefined_instruction:
|
||||
software_interrupt:
|
||||
prefetch_abort:
|
||||
data_abort:
|
||||
not_used:
|
||||
irq:
|
||||
fiq:
|
||||
1:
|
||||
b 1b /* hang and never return */
|
||||
|
||||
#else /* !CONFIG_SPL_BUILD */
|
||||
|
||||
/* IRQ stack memory (calculated at run-time) + 8 bytes */
|
||||
.globl IRQ_STACK_START_IN
|
||||
IRQ_STACK_START_IN:
|
||||
#ifdef IRAM_BASE_ADDR
|
||||
.word IRAM_BASE_ADDR + 0x20
|
||||
#else
|
||||
.word 0x0badc0de
|
||||
#endif
|
||||
|
||||
@
|
||||
@ IRQ stack frame.
|
||||
@
|
||||
#define S_FRAME_SIZE 72
|
||||
|
||||
#define S_OLD_R0 68
|
||||
#define S_PSR 64
|
||||
#define S_PC 60
|
||||
#define S_LR 56
|
||||
#define S_SP 52
|
||||
|
||||
#define S_IP 48
|
||||
#define S_FP 44
|
||||
#define S_R10 40
|
||||
#define S_R9 36
|
||||
#define S_R8 32
|
||||
#define S_R7 28
|
||||
#define S_R6 24
|
||||
#define S_R5 20
|
||||
#define S_R4 16
|
||||
#define S_R3 12
|
||||
#define S_R2 8
|
||||
#define S_R1 4
|
||||
#define S_R0 0
|
||||
|
||||
#define MODE_SVC 0x13
|
||||
#define I_BIT 0x80
|
||||
|
||||
/*
|
||||
* use bad_save_user_regs for abort/prefetch/undef/swi ...
|
||||
* use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling
|
||||
*/
|
||||
|
||||
.macro bad_save_user_regs
|
||||
@ carve out a frame on current user stack
|
||||
sub sp, sp, #S_FRAME_SIZE
|
||||
stmia sp, {r0 - r12} @ Save user registers (now in svc mode) r0-r12
|
||||
ldr r2, IRQ_STACK_START_IN
|
||||
@ get values for "aborted" pc and cpsr (into parm regs)
|
||||
ldmia r2, {r2 - r3}
|
||||
add r0, sp, #S_FRAME_SIZE @ grab pointer to old stack
|
||||
add r5, sp, #S_SP
|
||||
mov r1, lr
|
||||
stmia r5, {r0 - r3} @ save sp_SVC, lr_SVC, pc, cpsr
|
||||
mov r0, sp @ save current stack into r0 (param register)
|
||||
.endm
|
||||
|
||||
.macro irq_save_user_regs
|
||||
sub sp, sp, #S_FRAME_SIZE
|
||||
stmia sp, {r0 - r12} @ Calling r0-r12
|
||||
@ !!!! R8 NEEDS to be saved !!!! a reserved stack spot would be good.
|
||||
add r8, sp, #S_PC
|
||||
stmdb r8, {sp, lr}^ @ Calling SP, LR
|
||||
str lr, [r8, #0] @ Save calling PC
|
||||
mrs r6, spsr
|
||||
str r6, [r8, #4] @ Save CPSR
|
||||
str r0, [r8, #8] @ Save OLD_R0
|
||||
mov r0, sp
|
||||
.endm
|
||||
|
||||
.macro irq_restore_user_regs
|
||||
ldmia sp, {r0 - lr}^ @ Calling r0 - lr
|
||||
mov r0, r0
|
||||
ldr lr, [sp, #S_PC] @ Get PC
|
||||
add sp, sp, #S_FRAME_SIZE
|
||||
subs pc, lr, #4 @ return & move spsr_svc into cpsr
|
||||
.endm
|
||||
|
||||
.macro get_bad_stack
|
||||
ldr r13, IRQ_STACK_START_IN @ setup our mode stack
|
||||
|
||||
str lr, [r13] @ save caller lr in position 0 of saved stack
|
||||
mrs lr, spsr @ get the spsr
|
||||
str lr, [r13, #4] @ save spsr in position 1 of saved stack
|
||||
mov r13, #MODE_SVC @ prepare SVC-Mode
|
||||
@ msr spsr_c, r13
|
||||
msr spsr, r13 @ switch modes, make sure moves will execute
|
||||
mov lr, pc @ capture return pc
|
||||
movs pc, lr @ jump to next instruction & switch modes.
|
||||
.endm
|
||||
|
||||
.macro get_irq_stack @ setup IRQ stack
|
||||
ldr sp, IRQ_STACK_START
|
||||
.endm
|
||||
|
||||
.macro get_fiq_stack @ setup FIQ stack
|
||||
ldr sp, FIQ_STACK_START
|
||||
.endm
|
||||
|
||||
/*
|
||||
* exception handlers
|
||||
*/
|
||||
|
||||
.align 5
|
||||
undefined_instruction:
|
||||
get_bad_stack
|
||||
bad_save_user_regs
|
||||
bl do_undefined_instruction
|
||||
|
||||
.align 5
|
||||
software_interrupt:
|
||||
get_bad_stack
|
||||
bad_save_user_regs
|
||||
bl do_software_interrupt
|
||||
|
||||
.align 5
|
||||
prefetch_abort:
|
||||
get_bad_stack
|
||||
bad_save_user_regs
|
||||
bl do_prefetch_abort
|
||||
|
||||
.align 5
|
||||
data_abort:
|
||||
get_bad_stack
|
||||
bad_save_user_regs
|
||||
bl do_data_abort
|
||||
|
||||
.align 5
|
||||
not_used:
|
||||
get_bad_stack
|
||||
bad_save_user_regs
|
||||
bl do_not_used
|
||||
|
||||
|
||||
.align 5
|
||||
irq:
|
||||
get_bad_stack
|
||||
bad_save_user_regs
|
||||
bl do_irq
|
||||
|
||||
.align 5
|
||||
fiq:
|
||||
get_bad_stack
|
||||
bad_save_user_regs
|
||||
bl do_fiq
|
||||
|
||||
#endif /* CONFIG_SPL_BUILD */
|
||||
@@ -0,0 +1,56 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* (C) Copyright 2015
|
||||
* Kamil Lulko, <kamil.lulko@gmail.com>
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <asm/assembler.h>
|
||||
#include <linux/linkage.h>
|
||||
|
||||
.type __hard_fault_entry, %function
|
||||
__hard_fault_entry:
|
||||
mov r0, sp @ pass auto-saved registers as argument
|
||||
b do_hard_fault
|
||||
|
||||
.type __mm_fault_entry, %function
|
||||
__mm_fault_entry:
|
||||
mov r0, sp @ pass auto-saved registers as argument
|
||||
b do_mm_fault
|
||||
|
||||
.type __bus_fault_entry, %function
|
||||
__bus_fault_entry:
|
||||
mov r0, sp @ pass auto-saved registers as argument
|
||||
b do_bus_fault
|
||||
|
||||
.type __usage_fault_entry, %function
|
||||
__usage_fault_entry:
|
||||
mov r0, sp @ pass auto-saved registers as argument
|
||||
b do_usage_fault
|
||||
|
||||
.type __invalid_entry, %function
|
||||
__invalid_entry:
|
||||
mov r0, sp @ pass auto-saved registers as argument
|
||||
b do_invalid_entry
|
||||
|
||||
.section .vectors
|
||||
ENTRY(_start)
|
||||
.long CONFIG_SYS_INIT_SP_ADDR @ 0 - Reset stack pointer
|
||||
.long reset @ 1 - Reset
|
||||
.long __invalid_entry @ 2 - NMI
|
||||
.long __hard_fault_entry @ 3 - HardFault
|
||||
.long __mm_fault_entry @ 4 - MemManage
|
||||
.long __bus_fault_entry @ 5 - BusFault
|
||||
.long __usage_fault_entry @ 6 - UsageFault
|
||||
.long __invalid_entry @ 7 - Reserved
|
||||
.long __invalid_entry @ 8 - Reserved
|
||||
.long __invalid_entry @ 9 - Reserved
|
||||
.long __invalid_entry @ 10 - Reserved
|
||||
.long __invalid_entry @ 11 - SVCall
|
||||
.long __invalid_entry @ 12 - Debug Monitor
|
||||
.long __invalid_entry @ 13 - Reserved
|
||||
.long __invalid_entry @ 14 - PendSV
|
||||
.long __invalid_entry @ 15 - SysTick
|
||||
.rept 255 - 16
|
||||
.long __invalid_entry @ 16..255 - External Interrupts
|
||||
.endr
|
||||
@@ -0,0 +1,41 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (C) 2016
|
||||
* Ladislav Michl <ladis@linux-mips.org>
|
||||
*
|
||||
* bootz code:
|
||||
* Copyright (C) 2012 Marek Vasut <marek.vasut@gmail.com>
|
||||
*/
|
||||
#include <common.h>
|
||||
|
||||
#define LINUX_ARM_ZIMAGE_MAGIC 0x016f2818
|
||||
#define BAREBOX_IMAGE_MAGIC 0x00786f62
|
||||
|
||||
struct arm_z_header {
|
||||
uint32_t code[9];
|
||||
uint32_t zi_magic;
|
||||
uint32_t zi_start;
|
||||
uint32_t zi_end;
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
int bootz_setup(ulong image, ulong *start, ulong *end)
|
||||
{
|
||||
struct arm_z_header *zi = (struct arm_z_header *)image;
|
||||
|
||||
if (zi->zi_magic != LINUX_ARM_ZIMAGE_MAGIC &&
|
||||
zi->zi_magic != BAREBOX_IMAGE_MAGIC) {
|
||||
#ifndef CONFIG_SPL_FRAMEWORK
|
||||
puts("zimage: Bad magic!\n");
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
*start = zi->zi_start;
|
||||
*end = zi->zi_end;
|
||||
#ifndef CONFIG_SPL_FRAMEWORK
|
||||
printf("Kernel image @ %#08lx [ %#08lx - %#08lx ]\n",
|
||||
image, *start, *end);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user