1/*
2 * Copyright (c) 2013-2014 Wind River Systems, Inc.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7/**
8 * @file
9 * @brief Reset handler
10 *
11 * Reset handler that prepares the system for running C code.
12 */
13
14#include <zephyr/toolchain.h>
15#include <zephyr/linker/sections.h>
16#include <zephyr/arch/cpu.h>
17#include "vector_table.h"
18
19_ASM_FILE_PROLOGUE
20
21GTEXT(z_arm_reset)
22GTEXT(z_early_memset)
23GDATA(z_interrupt_stacks)
24#if defined(CONFIG_DEBUG_THREAD_INFO)
25GDATA(z_sys_post_kernel)
26#endif
27#if defined(CONFIG_SOC_RESET_HOOK)
28GTEXT(soc_reset_hook)
29#endif
30#if defined(CONFIG_INIT_ARCH_HW_AT_BOOT)
31GTEXT(z_arm_init_arch_hw_at_boot)
32GDATA(z_main_stack)
33#endif
34#if defined(CONFIG_PM_S2RAM)
35GTEXT(arch_pm_s2ram_resume)
36#endif
37
38/**
39 *
40 * @brief Reset vector
41 *
42 * Ran when the system comes out of reset, or when the firmware image is chain-
43 * loaded by another application (for instance, a bootloader). At minimum, the
44 * processor must be in thread mode with privileged level. At this point, the
45 * main stack pointer (MSP) should be already pointing to a valid area in SRAM.
46 *
47 * Locking interrupts prevents anything but NMIs and hard faults from
48 * interrupting the CPU. A default NMI handler is already in place in the
49 * vector table, and the boot code should not generate hard fault, or we're in
50 * deep trouble.
51 *
52 * We want to use the process stack pointer (PSP) instead of the MSP, since the
53 * MSP is to be set up to point to the one-and-only interrupt stack during
54 * later boot. That would not be possible if in use for running C code.
55 *
56 * When these steps are completed, jump to z_prep_c(), which will finish
57 * setting up the system for running C code.
58 *
59 */
60
61SECTION_SUBSEC_FUNC(TEXT,_reset_section,z_arm_reset)
62
63/*
64 * The entry point is located at the z_arm_reset symbol, which
65 * is fetched by a XIP image playing the role of a bootloader, which jumps to
66 * it, not through the reset vector mechanism. Such bootloaders might want to
67 * search for a __start symbol instead, so create that alias here.
68 */
69SECTION_SUBSEC_FUNC(TEXT,_reset_section,__start)
70
71#if defined(CONFIG_DEBUG_THREAD_INFO)
72    /* Clear z_sys_post_kernel flag for RTOS aware debuggers */
73    movs.n r0, #0
74    ldr r1, =z_sys_post_kernel
75    strb r0, [r1]
76#endif /* CONFIG_DEBUG_THREAD_INFO */
77
78#if defined(CONFIG_INIT_ARCH_HW_AT_BOOT)
79    /* Reset CONTROL register */
80    movs.n r0, #0
81    msr CONTROL, r0
82    isb
83#if defined(CONFIG_CPU_CORTEX_M_HAS_SPLIM)
84    /* Clear SPLIM registers */
85    movs.n r0, #0
86    msr MSPLIM, r0
87    msr PSPLIM, r0
88#endif /* CONFIG_CPU_CORTEX_M_HAS_SPLIM */
89
90#endif /* CONFIG_INIT_ARCH_HW_AT_BOOT */
91
92#if defined(CONFIG_PM_S2RAM)
93    bl arch_pm_s2ram_resume
94#endif /* CONFIG_PM_S2RAM */
95
96#if defined(CONFIG_SOC_RESET_HOOK)
97    bl soc_reset_hook
98#endif
99
100#if defined(CONFIG_INIT_ARCH_HW_AT_BOOT)
101#if defined(CONFIG_CPU_HAS_ARM_MPU)
102    /* Disable MPU */
103    movs.n r0, #0
104    ldr r1, =_SCS_MPU_CTRL
105    str r0, [r1]
106    dsb
107#endif /* CONFIG_CPU_HAS_ARM_MPU */
108    ldr r0, =z_main_stack + CONFIG_MAIN_STACK_SIZE
109    msr msp, r0
110
111    /* Initialize core architecture registers and system blocks */
112    bl z_arm_init_arch_hw_at_boot
113#endif /* CONFIG_INIT_ARCH_HW_AT_BOOT */
114
115    /* lock interrupts: will get unlocked when switch to main task */
116#if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE)
117    cpsid i
118#elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE)
119    movs.n r0, #_EXC_IRQ_DEFAULT_PRIO
120    msr BASEPRI, r0
121#else
122#error Unknown ARM architecture
123#endif
124
125#ifdef CONFIG_WDOG_INIT
126    /* board-specific watchdog initialization is necessary */
127    bl z_arm_watchdog_init
128#endif
129
130/*
131 *
132 * Note: in all Cortex-M variants the interrupt stack area is at
133 * least equal to CONFIG_ISR_STACK_SIZE + MPU_GUARD_ALIGN_AND_SIZE
134 * (may be larger due to rounding up for stack pointer aligning
135 * purposes but this is sufficient during initialization).
136 */
137
138#ifdef CONFIG_INIT_STACKS
139    ldr r0, =z_interrupt_stacks
140    ldr r1, =0xaa
141    ldr r2, =CONFIG_ISR_STACK_SIZE + MPU_GUARD_ALIGN_AND_SIZE
142    bl z_early_memset
143#endif
144
145    /*
146     * Set PSP and use it to boot without using MSP, so that it
147     * gets set to z_interrupt_stacks during initialization.
148     */
149    ldr r0, =z_interrupt_stacks
150    ldr r1, =CONFIG_ISR_STACK_SIZE + MPU_GUARD_ALIGN_AND_SIZE
151    adds r0, r0, r1
152    msr PSP, r0
153    mrs r0, CONTROL
154    movs r1, #2
155    orrs r0, r1 /* CONTROL_SPSEL_Msk */
156    msr CONTROL, r0
157    /*
158     * When changing the stack pointer, software must use an ISB instruction
159     * immediately after the MSR instruction. This ensures that instructions
160     * after the ISB instruction execute using the new stack pointer.
161     */
162    isb
163
164    /*
165     * 'bl' jumps the furthest of the branch instructions that are
166     * supported on all platforms. So it is used when jumping to z_prep_c
167     * (even though we do not intend to return).
168     */
169    bl z_prep_c
170