/* * Copyright 2014, General Dynamics C4 Systems * * SPDX-License-Identifier: GPL-2.0-only */ #include #include #include #include #include #ifndef ALLOW_UNALIGNED_ACCESS #define ALLOW_UNALIGNED_ACCESS 1 #endif #if ALLOW_UNALIGNED_ACCESS #define CR_ALIGN_SET BIT(CONTROL_U) #define CR_ALIGN_CLEAR BIT(CONTROL_A) #else #define CR_ALIGN_SET BIT(CONTROL_A) #define CR_ALIGN_CLEAR BIT(CONTROL_U) #endif #ifndef CONFIG_DEBUG_DISABLE_L1_ICACHE #define CR_L1_ICACHE_SET BIT(CONTROL_I) #define CR_L1_ICACHE_CLEAR 0 #else #define CR_L1_ICACHE_SET 0 #define CR_L1_ICACHE_CLEAR BIT(CONTROL_I) #endif #ifndef CONFIG_DEBUG_DISABLE_L1_DCACHE #define CR_L1_DCACHE_SET BIT(CONTROL_C) #define CR_L1_DCACHE_CLEAR 0 #else #define CR_L1_DCACHE_SET 0 #define CR_L1_DCACHE_CLEAR BIT(CONTROL_C) #endif #ifndef CONFIG_DEBUG_DISABLE_BRANCH_PREDICTION #define CR_BRANCH_PREDICTION_SET BIT(CONTROL_Z) #define CR_BRANCH_PREDICTION_CLEAR 0 #else #define CR_BRANCH_PREDICTION_SET 0 #define CR_BRANCH_PREDICTION_CLEAR BIT(CONTROL_Z) #endif #define CR_BITS_SET (CR_ALIGN_SET | \ CR_L1_ICACHE_SET | \ CR_L1_DCACHE_SET | \ BIT(CONTROL_M) | \ CR_BRANCH_PREDICTION_SET | \ BIT(CONTROL_V) | \ BIT(CONTROL_XP)) #define CR_BITS_CLEAR (CR_ALIGN_CLEAR | \ CR_L1_ICACHE_CLEAR | \ CR_L1_DCACHE_CLEAR | \ CR_BRANCH_PREDICTION_CLEAR | \ BIT(CONTROL_B) | \ BIT(CONTROL_S) | \ BIT(CONTROL_R) | \ BIT(CONTROL_VE) | \ BIT(CONTROL_RR) | \ BIT(CONTROL_EE) | \ BIT(CONTROL_TRE) | \ BIT(CONTROL_AP)) /* * Entry point of the kernel ELF image. * R0-R3 contain parameters that are passed to init_kernel(), * and we put arguments 5 and 6 (DTB address/size) in r7 and r8. */ .code 32 .section .boot.text, "ax" BEGIN_FUNC(_start) /* * Get the dtb and dtb size from the elfloader stack. Do this first because * sp might change when we switch to supervisor mode. */ pop {r7, r8} /* Supervisor/hypervisor mode, interrupts disabled */ ldr r5, =CPSR_KERNEL msr cpsr_fc, r5 /* Initialise CP15 control register */ #ifdef CONFIG_ARM_HYPERVISOR_SUPPORT mrc p15, 4, r4, c1, c0, 0 #else mrc p15, 0, r4, c1, c0, 0 #endif ldr r5, =CR_BITS_SET ldr r6, =CR_BITS_CLEAR orr r4, r4, r5 bic r4, r4, r6 #ifdef CONFIG_ARM_HYPERVISOR_SUPPORT mcr p15, 4, r4, c1, c0, 0 /* Initialise vector base */ ldr r4, =PPTR_VECTOR_TABLE mcr p15, 4, r4, c12, c0, 0 #else mcr p15, 0, r4, c1, c0, 0 #endif #if defined(CONFIG_ARM_CORTEX_A9) && defined(CONFIG_ENABLE_A9_PREFETCHER) /* Set bit 2 in the ACTLR, which on the cortex-a9 is the l1 prefetch enable * bit. See section 4.3.10 of the Cortex-A9 Technical Reference Manual */ mrc p15, 0, r4, c1, c0, 1 ldr r5, =BIT(2) orr r4, r4, r5 mcr p15, 0, r4, c1, c0, 1 #endif #if defined(CONFIG_PLAT_HIKEY) /* Prefetcher configuration */ mrrc p15, 0, r4, r5, c15 ldr r6, =PREFETCHER_MASK bic r4, r4, r6 ldr r6, =PREFETCHER orr r4, r4, r6 mcrr p15, 0, r4, r5, c15 #endif /* Load kernel stack pointer * On ARM SMP, kernel_stack_alloc is indexed by CPU ID * to get different stacks for each core */ ldr sp, =kernel_stack_alloc + BIT(CONFIG_KERNEL_STACK_BITS) #ifdef ENABLE_SMP_SUPPORT /* * Read MPIDR in r4 * See ARM Referce Manual (ARMv7-A and ARMv7-R edition), Section B4.1.106 * for more details about MPIDR register. */ mrc p15, 0, r4, c0, c0, 5 and r4, r4, #0xff /* Set the sp for each core assuming linear indices */ ldr r5, =BIT(CONFIG_KERNEL_STACK_BITS) mul r5, r4 add sp, sp, r5 #endif /* ENABLE_SMP_SUPPORT */ /* Attempt to workaround any known ARM errata. */ push {r0-r3,r7-r8} blx arm_errata pop {r0-r3,r7-r8} /* Hyp kernel always run in Hyp mode. */ #ifndef CONFIG_ARM_HYPERVISOR_SUPPORT /* Initialise ABORT stack pointer */ cps #PMODE_ABORT ldr sp, =_breakpoint_stack_top cps #PMODE_SUPERVISOR #endif /* Put the DTB address back on the new stack for init_kernel. */ push {r7, r8} /* Call bootstrapping implemented in C */ blx init_kernel /* Restore the initial thread */ b restore_user_context END_FUNC(_start)