blob: 6d3eec5ff4eebe986c5df04886dc7ce7fbba856a [file] [log] [blame]
/****************************************************************************
* arch/arm/src/armv8-r/arm_head.S
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <arch/irq.h>
#include "arm.h"
#include "cp15_cacheops.h"
#include "sctlr.h"
#include "arm_internal.h"
.file "arm_head.S"
/****************************************************************************
* Configuration
****************************************************************************/
/* There are three operational memory configurations:
*
* 1. We execute in place in FLASH (CONFIG_BOOT_RUNFROMFLASH=y). In this case
* the boot logic must:
*
* - Configure SDRAM (if present),
* - Initialize the .data section in RAM, and
* - Clear .bss section
*
* 2. We boot in FLASH but copy ourselves to SDRAM from better performance.
* (CONFIG_BOOT_RUNFROMFLASH=n && CONFIG_BOOT_COPYTORAM=y). In this case
* the boot logic must:
*
* - Configure SDRAM (if present),
* - Copy ourself to DRAM, and
* - Clear .bss section (data should be fully initialized)
*
* In this case, we assume that the logic within this file executes from FLASH.
*
* 3. There is bootloader that copies us to SDRAM (but probably not to the beginning)
* (CONFIG_BOOT_RUNFROMFLASH=n && CONFIG_BOOT_COPYTORAM=n). In this case SDRAM
* was initialized by the boot loader, and this boot logic must:
*
* - Clear .bss section (data should be fully initialized)
*/
/* Beginning (BOTTOM/BASE) and End+1 (TOP) of the IDLE stack.
*
* The IDLE stack is the stack that is used during initialization and,
* eventually, becomes the stack of the IDLE task when initialization
* is complete.
*
* REVISIT: There are issues here in some configurations. The stack
* pointer is initialized very early in the boot sequence. But in some
* architectures the memory supporting the stack may not yet be
* initialized (SDRAM, for example, would not be ready yet). In that
* case, ideally the IDLE stack should be in some other memory that does
* not require initialization (such as internal SRAM)
*/
#ifndef IDLE_STACK_BASE
# ifdef CONFIG_SMP
# define IDLE_STACK_BASE _enoinit
# else
# define IDLE_STACK_BASE _ebss
# endif
#endif
#define IDLE_STACK_TOP IDLE_STACK_BASE+CONFIG_IDLETHREAD_STACKSIZE
/****************************************************************************
* Global Symbols
****************************************************************************/
/* Imported symbols */
.global arm_boot /* Branch to continue initialization in C */
.global _sbss /* Start of .bss in RAM */
.global _ebss /* End+1 of .bss in RAM */
.global _hyp_vector_start
.global _sys_vector_start
#ifdef CONFIG_BOOT_RUNFROMFLASH
.global _eronly /* Where .data defaults are stored in FLASH */
.global _sdata /* Where .data needs to reside in SDRAM */
.global _edata
#endif
#ifdef CONFIG_ARCH_RAMFUNCS
.global _framfuncs /* Where RAM functions are stored in FLASH */
.global _sramfuncs /* Where RAM functions needs to reside in RAM */
.global _eramfuncs
#endif
/* Exported symbols */
.global __start /* Power-up/Reset entry point */
.global arm_data_initialize /* Perform C data initialization */
.global g_idle_topstack /* Top of the initial/IDLE stack */
/****************************************************************************
* Name: __start
****************************************************************************/
/* We assume the bootloader has already initialized most of the h/w for
* us and that only leaves us having to do some os specific things
* below.
*/
.text
.syntax unified
.arm
.global __start
.type __start, #function
__start:
/* Get cpuindex, cpu0 continue boot, others wait event from cpu0 */
mrc CP15_MPIDR(r0)
and r0, r0, #0x3
cmp r0, #0
#if defined(CONFIG_SMP) && CONFIG_SMP_NCPUS > 1
beq __cpu0_start
#ifdef CONFIG_ARM_BUSY_WAIT
ldr r2, =CONFIG_ARM_BUSY_WAIT_FLAG_ADDR
1:
ldr r1, [r2, #0]
cmp r1, #0
beq 1b
#else
wfe
#endif
cmp r0, #1
beq __cpu1_start
# if CONFIG_SMP_NCPUS > 2
cmp r0, #2
beq __cpu2_start
# endif
# if CONFIG_SMP_NCPUS > 3
cmp r0, #3
beq __cpu3_start
# endif
# if CONFIG_SMP_NCPUS > 4
cmp r0, #4
beq __cpu4_start
# endif
#else
beq __cpu0_start
__cpux_wfi:
/* Clear all pending data access */
dsb sy
wfi
b __cpux_wfi
#endif
__cpu0_start:
/* Make sure that IRQs and FIQs are disabled */
cpsid if
/* Set up the stack pointer and clear the frame pointer. */
ldr sp, .Lstackpointer
mov fp, #0
/* Set Hyp/PL2 Vector table base register */
ldr r0, .Lhypvectorstart
mcr CP15_HVBAR(r0)
/* Invalidate caches and TLBs.
*
* NOTE: "The ARMv7 Virtual Memory System Architecture (VMSA) does not
* support a CP15 operation to invalidate the entire data cache. ...
* In normal usage the only time the entire data cache has to be
* invalidated is on reset."
*
* The instruction cache is virtually indexed and physically tagged but
* the data cache is physically indexed and physically tagged. So it
* should not be an issue if the system comes up with a dirty Dcache;
* the ICache, however, must be invalidated.
*/
mov r0, #0
mcr CP15_TPIDRPRW(r0) /* Initialize percpu reg TPIDRPRW */
mcr CP15_BPIALL(r0) /* Invalidate entire branch prediction array */
mcr CP15_ICIALLU(r0) /* Invalidate I-cache */
mov r1, CP15_CACHE_INVALIDATE
bl cp15_dcache_op_level
isb
bl hsctlr_initialize /* Init Hyp system control register */
ldr r0, =HACTLR_INIT
mcr CP15_HACTLR(r0) /* Enable EL1 access all IMP DEFINED registers */
#ifdef CONFIG_ARCH_FPU
bl arm_fpuconfig
#endif
/* Initialize .bss and .data assumt that RAM that is ready to use. */
bl arm_data_initialize
/* Platform hook for highest EL */
bl arm_el_init
/* Move to PL1 SYS with all exceptions masked */
mov r0, #(PSR_MODE_SYS | PSR_I_BIT | PSR_F_BIT | PSR_A_BIT)
msr spsr_hyp, r0
adr r0, 1f
msr elr_hyp, r0
dsb
isb
eret
1:
/* Set up the stack pointer and clear the frame pointer. */
ldr sp, .Lstackpointer
mov fp, #0
/* Set PL1 Vector table base register */
ldr r0, .Lsysvectorstart
mcr CP15_VBAR(r0)
bl sctlr_initialize
bl arm_boot
mov lr, #0 /* LR = return address (none) */
b nx_start /* Branch to nx_start */
#if defined(CONFIG_ARM_BUSY_WAIT) && defined(CONFIG_SMP)
ldr r0, =CONFIG_ARM_BUSY_WAIT_FLAG_ADDR
mov r1, #1
str r1, [r0]
dsb sy
#endif
/* .text Data */
.Lstackpointer:
.long IDLE_STACK_TOP
.size __start, .-__start
/***************************************************************************
* Name: arm_data_initialize
***************************************************************************/
.global arm_data_initialize
.type arm_data_initialize, #function
arm_data_initialize:
/* Zero BSS */
adr r0, .Linitparms
ldmia r0, {r0, r1}
mov r2, #0
1:
cmp r0, r1 /* Clear up to _bss_end_ */
strcc r2, [r0], #4
bcc 1b
#ifdef CONFIG_BOOT_RUNFROMFLASH
/* If the .data section is in a separate, uninitialized address space,
* then we will also need to copy the initial values of the .data
* section from the .text region into that .data region. This would
* be the case if we are executing from FLASH and the .data section
* lies in a different physical address region OR if we are support
* on-demand paging and the .data section lies in a different virtual
* address region.
*/
adr r3, .Ldatainit
ldmia r3, {r0, r1, r2}
2:
ldr r3, [r0], #4
str r3, [r1], #4
cmp r1, r2
blt 2b
#endif
#ifdef CONFIG_ARCH_RAMFUNCS
/* Copy any necessary code sections from FLASH to RAM. The correct
* destination in SRAM is given by _sramfuncs and _eramfuncs. The
* temporary location is in flash after the data initialization code
* at _framfuncs
*/
adr r3, .Lfuncinit
ldmia r3, {r0, r1, r2}
3:
ldr r3, [r0], #4
str r3, [r1], #4
cmp r1, r2
blt 3b
#ifndef CONFIG_ARMV8R_DCACHE_DISABLE
/* Flush the copied RAM functions into physical RAM so that will
* be available when fetched into the I-Cache.
*
* Note that this is a branch, not a call and so will return
* directly to the caller without returning here.
*/
adr r3, ..Lramfunc
ldmia r3, {r0, r1}
ldr r3, =up_clean_dcache
b r3
#else
/* Otherwise return to the caller */
bx lr
#endif
#else
/* Return to the caller */
bx lr
#endif
/***************************************************************************
* Name: hsctlr_initialize
***************************************************************************/
.global hsctlr_initialize
.type hsctlr_initialize, #function
hsctlr_initialize:
mrc CP15_HSCTLR(r0) /* Get Hyp System Control Register */
#if !defined(CONFIG_ARMV8R_DCACHE_DISABLE)
/* Dcache enable
*
* SCTLR_C Bit 2: DCache enable
*/
orr r0, r0, #(SCTLR_C)
#endif
#if !defined(CONFIG_ARMV8R_ICACHE_DISABLE)
/* Icache enable
*
* SCTLR_I Bit 12: ICache enable
*/
orr r0, r0, #(SCTLR_I)
#endif
mcr CP15_HSCTLR(r0) /* Write Hyp System Control Register */
bx lr
/***************************************************************************
* Name: sctlr_initialize
***************************************************************************/
.global sctlr_initialize
.type sctlr_initialize, #function
sctlr_initialize:
/* Configure the system control register (see sctrl.h) */
mrc CP15_SCTLR(r0) /* Get control register */
/* Clear bits to reset values. This is only necessary in situations like, for
* example, we get here via a bootloader and the control register is in some
* unknown state.
*
* SCTLR_M Bit 0: MPU enable bit
* SCTLR_A Bit 1: Strict alignment disabled
* SCTLR_C Bit 2: DCache disabled
* SCTLR_CCP15BEN Bit 5: CP15 barrier enable
* SCTLR_B Bit 7: Should be zero on ARMv7R
*
* SCTLR_SW Bit 10: SWP/SWPB not enabled
* SCTLR_I Bit 12: ICache disabled
* SCTLR_V Bit 13: Assume low vectors
* SCTLR_RR Bit 14: Round-robin replacement strategy.
*
* SCTLR_BR Bit 17: Background Region bit
* SCTLR_DZ Bit 19: Divide by Zero fault enable bit
* SCTLR_FI Bit 21: Fast interrupts configuration enable bit
* SCTLR_U Bit 22: Unaligned access model (always one)
*
* SCTLR_VE Bit 24: Interrupt Vectors Enable bit
* SCTLR_EE Bit 25: 0=Little endian.
* SCTLR_NMFI Bit 27: Non-maskable FIQ (NMFI) support
* SCTLR_TE Bit 30: All exceptions handled in ARM state.
*/
/* Clear all configurable bits */
bic r0, r0, #(SCTLR_A | SCTLR_C | SCTLR_CCP15BEN | SCTLR_B)
bic r0, r0, #(SCTLR_SW | SCTLR_I | SCTLR_V | SCTLR_RR)
bic r0, r0, #(SCTLR_BR | SCTLR_DZ | SCTLR_FI)
bic r0, r0, #(SCTLR_VE | SCTLR_EE | SCTLR_NMFI | SCTLR_TE)
#ifndef CONFIG_SMP
/* Set bits to enable the MPU
*
* SCTLR_M Bit 0: Enable the MPU
*/
orr r0, r0, #(SCTLR_M)
#endif
/* Set configured bits */
#ifdef CONFIG_ARMV8R_ALIGNMENT_TRAP
/* Alignment abort enable
*
* SCTLR_A Bit 1: Strict alignment enabled
*/
orr r0, r0, #(SCTLR_A)
#endif
#if !defined(CONFIG_ARMV8R_DCACHE_DISABLE) && !defined(CONFIG_SMP)
/* Dcache enable
*
* SCTLR_C Bit 2: DCache enable
*/
orr r0, r0, #(SCTLR_C)
#endif
#ifdef CONFIG_ARMV8R_SCTLR_CCP15BEN
/* Enable memory barriers
*
* SCTLR_CCP15BEN Bit 5: CP15 barrier enable
*/
orr r0, r0, #(SCTLR_CCP15BEN)
#endif
#if !defined(CONFIG_ARMV8R_ICACHE_DISABLE) && !defined(CONFIG_SMP)
/* Icache enable
*
* SCTLR_I Bit 12: ICache enable
*/
orr r0, r0, #(SCTLR_I)
#endif
#ifdef CONFIG_ARMV8R_CACHE_ROUND_ROBIN
/* Round Robin cache replacement
*
* SCTLR_RR Bit 14: Round-robin replacement strategy.
*/
orr r0, r0, #(SCTLR_RR)
#endif
#ifdef CONFIG_ARMV8R_BACKGROUND_REGION
/* Allow PL1 access to back region when MPU is enabled
*
* SCTLR_BR Bit 17: Background Region bit
*/
orr r0, r0, #(SCTLR_BR)
#endif
#ifdef CONFIG_ARMV8R_DIV0_FAULT
/* Enable divide by zero faults
*
* SCTLR_DZ Bit 19: Divide by Zero fault enable bit
*/
orr r0, r0, #(SCTLR_DZ)
#endif
#ifdef CONFIG_ARMV8R_FAST_INTERRUPT
/* Fast interrupts configuration enable bit
*
* SCTLR_FI Bit 21: Fast interrupts configuration enable bit
*/
orr r0, r0, #(SCTLR_FI)
#endif
#ifdef CONFIG_ENDIAN_BIG
/* Big endian mode
*
* SCTLR_EE Bit 25: 1=Big endian.
*/
orr r0, r0, #(SCTLR_EE)
#endif
#ifdef CONFIG_ARMV8R_NONMASKABLE_FIQ
/* Non-maskable FIQ support
*
* SCTLR_NMFI Bit 27: Non-maskable FIQ (NMFI) support
*/
orr r0, r0, #(SCTLR_NMFI)
#endif
/* Then write the configured control register */
mcr CP15_SCTLR(r0) /* Write control reg */
isb
.rept 12 /* Some CPUs want want lots of NOPs here */
nop
.endr
/* Return to the caller */
bx lr
/***************************************************************************
* Text-section constants
***************************************************************************/
/* Text-section constants:
*
* _sbss is the start of the BSS region (see linker script)
* _ebss is the end of the BSS region (see linker script)
*
* Typical Configuration:
* The idle task stack usually starts at the end of BSS and is of size
* CONFIG_IDLETHREAD_STACKSIZE. The heap continues from there until the
* end of memory. See g_idle_topstack below.
*/
.type .Linitparms, %object
.Linitparms:
.long _sbss
.long _ebss
.Lhypvectorstart:
.long _hyp_vector_start
.Lsysvectorstart:
.long _sys_vector_start
#ifdef CONFIG_BOOT_RUNFROMFLASH
.type .Ldatainit, %object
.Ldatainit:
.long _eronly /* Where .data defaults are stored in FLASH */
.long _sdata /* Where .data needs to reside in SDRAM */
.long _edata
#endif
#ifdef CONFIG_ARCH_RAMFUNCS
.type .Lfuncinit, %object
.Lfuncinit:
.long _framfuncs /* Where RAM functions are stored in FLASH */
.Lramfuncs:
.long _sramfuncs /* Where RAM functions needs to reside in RAM */
.long _eramfuncs
#endif
.size arm_data_initialize, . - arm_data_initialize
/***************************************************************************
* Data section variables
***************************************************************************/
/* This global variable is unsigned long g_idle_topstack and is
* exported from here only because of its coupling to .Lstackpointer
* above.
*/
.section .rodata, "a"
.align 4
.globl g_idle_topstack
.type g_idle_topstack, object
g_idle_topstack:
.long IDLE_STACK_TOP
.size g_idle_topstack, .-g_idle_topstack
.end