1/* 2 * Copyright 2014, General Dynamics C4 Systems 3 * 4 * SPDX-License-Identifier: GPL-2.0-only 5 */ 6 7#include <config.h> 8#include <machine/assembler.h> 9#include <arch/machine/hardware.h> 10#include <arch/machine/registerset.h> 11#include <util.h> 12 13#ifndef ALLOW_UNALIGNED_ACCESS 14#define ALLOW_UNALIGNED_ACCESS 1 15#endif 16 17#if ALLOW_UNALIGNED_ACCESS 18#define CR_ALIGN_SET BIT(CONTROL_U) 19#define CR_ALIGN_CLEAR BIT(CONTROL_A) 20#else 21#define CR_ALIGN_SET BIT(CONTROL_A) 22#define CR_ALIGN_CLEAR BIT(CONTROL_U) 23#endif 24 25#ifndef CONFIG_DEBUG_DISABLE_L1_ICACHE 26 #define CR_L1_ICACHE_SET BIT(CONTROL_I) 27 #define CR_L1_ICACHE_CLEAR 0 28#else 29 #define CR_L1_ICACHE_SET 0 30 #define CR_L1_ICACHE_CLEAR BIT(CONTROL_I) 31#endif 32 33#ifndef CONFIG_DEBUG_DISABLE_L1_DCACHE 34 #define CR_L1_DCACHE_SET BIT(CONTROL_C) 35 #define CR_L1_DCACHE_CLEAR 0 36#else 37 #define CR_L1_DCACHE_SET 0 38 #define CR_L1_DCACHE_CLEAR BIT(CONTROL_C) 39#endif 40 41#ifndef CONFIG_DEBUG_DISABLE_BRANCH_PREDICTION 42 #define CR_BRANCH_PREDICTION_SET BIT(CONTROL_Z) 43 #define CR_BRANCH_PREDICTION_CLEAR 0 44#else 45 #define CR_BRANCH_PREDICTION_SET 0 46 #define CR_BRANCH_PREDICTION_CLEAR BIT(CONTROL_Z) 47#endif 48 49#define CR_BITS_SET (CR_ALIGN_SET | \ 50 CR_L1_ICACHE_SET | \ 51 CR_L1_DCACHE_SET | \ 52 BIT(CONTROL_M) | \ 53 CR_BRANCH_PREDICTION_SET | \ 54 BIT(CONTROL_V) | \ 55 BIT(CONTROL_XP)) 56 57#define CR_BITS_CLEAR (CR_ALIGN_CLEAR | \ 58 CR_L1_ICACHE_CLEAR | \ 59 CR_L1_DCACHE_CLEAR | \ 60 CR_BRANCH_PREDICTION_CLEAR | \ 61 BIT(CONTROL_B) | \ 62 BIT(CONTROL_S) | \ 63 BIT(CONTROL_R) | \ 64 BIT(CONTROL_VE) | \ 65 BIT(CONTROL_RR) | \ 66 BIT(CONTROL_EE) | \ 67 BIT(CONTROL_TRE) | \ 68 BIT(CONTROL_AP)) 69 70/* 71 * Entry point of the kernel ELF image. 72 * R0-R3 contain parameters that are passed to init_kernel(), 73 * and we put arguments 5 and 6 (DTB address/size) in r7 and r8. 74 */ 75 76.code 32 77.section .boot.text, "ax" 78BEGIN_FUNC(_start) 79 /* 80 * Get the dtb and dtb size from the elfloader stack. Do this first because 81 * sp might change when we switch to supervisor mode. 82 */ 83 pop {r7, r8} 84 85 /* Supervisor/hypervisor mode, interrupts disabled */ 86 ldr r5, =CPSR_KERNEL 87 msr cpsr_fc, r5 88 89 /* Initialise CP15 control register */ 90#ifdef CONFIG_ARM_HYPERVISOR_SUPPORT 91 mrc p15, 4, r4, c1, c0, 0 92#else 93 mrc p15, 0, r4, c1, c0, 0 94#endif 95 ldr r5, =CR_BITS_SET 96 ldr r6, =CR_BITS_CLEAR 97 orr r4, r4, r5 98 bic r4, r4, r6 99#ifdef CONFIG_ARM_HYPERVISOR_SUPPORT 100 mcr p15, 4, r4, c1, c0, 0 101 102 /* Initialise vector base */ 103 ldr r4, =PPTR_VECTOR_TABLE 104 mcr p15, 4, r4, c12, c0, 0 105#else 106 mcr p15, 0, r4, c1, c0, 0 107#endif 108 109#if defined(CONFIG_ARM_CORTEX_A9) && defined(CONFIG_ENABLE_A9_PREFETCHER) 110 /* Set bit 2 in the ACTLR, which on the cortex-a9 is the l1 prefetch enable 111 * bit. See section 4.3.10 of the Cortex-A9 Technical Reference Manual */ 112 mrc p15, 0, r4, c1, c0, 1 113 ldr r5, =BIT(2) 114 orr r4, r4, r5 115 mcr p15, 0, r4, c1, c0, 1 116#endif 117 118#if defined(CONFIG_PLAT_HIKEY) 119 /* Prefetcher configuration */ 120 mrrc p15, 0, r4, r5, c15 121 ldr r6, =PREFETCHER_MASK 122 bic r4, r4, r6 123 ldr r6, =PREFETCHER 124 orr r4, r4, r6 125 mcrr p15, 0, r4, r5, c15 126#endif 127 128 /* Load kernel stack pointer 129 * On ARM SMP, kernel_stack_alloc is indexed by CPU ID 130 * to get different stacks for each core 131 */ 132 ldr sp, =kernel_stack_alloc + BIT(CONFIG_KERNEL_STACK_BITS) 133 134#ifdef ENABLE_SMP_SUPPORT 135 /* 136 * Read MPIDR in r4 137 * See ARM Referce Manual (ARMv7-A and ARMv7-R edition), Section B4.1.106 138 * for more details about MPIDR register. 139 */ 140 mrc p15, 0, r4, c0, c0, 5 141 and r4, r4, #0xff 142 /* Set the sp for each core assuming linear indices */ 143 ldr r5, =BIT(CONFIG_KERNEL_STACK_BITS) 144 mul r5, r4 145 add sp, sp, r5 146#endif /* ENABLE_SMP_SUPPORT */ 147 148 /* Attempt to workaround any known ARM errata. */ 149 push {r0-r3,r7-r8} 150 blx arm_errata 151 pop {r0-r3,r7-r8} 152 153 /* Hyp kernel always run in Hyp mode. */ 154#ifndef CONFIG_ARM_HYPERVISOR_SUPPORT 155 /* Initialise ABORT stack pointer */ 156 cps #PMODE_ABORT 157 ldr sp, =_breakpoint_stack_top 158 cps #PMODE_SUPERVISOR 159#endif 160 161 /* Put the DTB address back on the new stack for init_kernel. */ 162 push {r7, r8} 163 /* Call bootstrapping implemented in C */ 164 blx init_kernel 165 166 /* Restore the initial thread */ 167 b restore_user_context 168 169END_FUNC(_start) 170