1 /*
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * Copyright © 2019 Keith Packard
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
17 *
18 * 3. Neither the name of the copyright holder nor the names of its
19 * contributors may be used to endorse or promote products derived
20 * from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
27 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
31 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
33 * OF THE POSSIBILITY OF SUCH DAMAGE.
34 */
35
36 #include "../../crt0.h"
37
38 #if __ARM_ARCH_PROFILE == 'M'
39
40 /*
41 * Cortex-mM includes an NVIC and starts with SP initialized, so start
42 * is a C function
43 */
44
45 extern const void *__interrupt_vector[];
46
47 #define CPACR ((volatile uint32_t *) (0xE000ED88))
48
49 #ifdef __clang__
50 const void *__interrupt_reference = __interrupt_vector;
51 #endif
52
53 void
_start(void)54 _start(void)
55 {
56 /* Generate a reference to __interrupt_vector so we get one loaded */
57 __asm__(".equ __my_interrupt_vector, __interrupt_vector");
58 #ifndef __SOFTFP__
59 /* Enable FPU */
60 *CPACR |= 0xf << 20;
61 /*
62 * Wait for the write enabling FPU to reach memory before
63 * executing the instruction accessing the status register
64 */
65 __asm__("dsb");
66 __asm__("isb");
67
68 /* Clear FPU status register. 0x40000 will initialize FPSCR.LTPSIZE to
69 * a valid value for 8.1-m low overhead loops. */
70 #if __ARM_ARCH >= 8 && __ARM_ARCH_PROFILE == 'M'
71 #define INIT_FPSCR 0x40000
72 #else
73 #define INIT_FPSCR 0x0
74 #endif
75 __asm__("vmsr fpscr, %0" : : "r" (INIT_FPSCR));
76 #endif
77 __start();
78 }
79
80 #else
81
82 /*
83 * Regular ARM has an 8-entry exception vector and starts without SP
84 * initialized, so start is a naked function
85 */
86
87 static void __attribute__((used)) __section(".init")
_cstart(void)88 _cstart(void)
89 {
90 __start();
91 }
92
93 extern char __stack[];
94
95 void __attribute__((naked)) __section(".init") __attribute__((used))
_start(void)96 _start(void)
97 {
98 /* Generate a reference to __vector_table so we get one loaded */
99 __asm__(".equ __my_vector_table, __vector_table");
100
101 /* Initialize stack pointer */
102 __asm__("mov sp, %0" : : "r" (__stack));
103
104 #if __ARM_ARCH == 7
105 #ifdef __thumb__
106 /* Make exceptions run in Thumb mode */
107 uint32_t sctlr;
108 __asm__("mrc p15, 0, %0, c1, c0, 0" : "=r" (sctlr));
109 sctlr |= (1 << 30);
110 __asm__("mcr p15, 0, %0, c1, c0, 0" : : "r" (sctlr));
111 #endif
112 #ifndef __SOFTFP__
113 /* Set CPACR for access to CP10 and 11 */
114 __asm__("mcr p15, 0, %0, c1, c0, 2" : : "r" (0xf << 20));
115 /* Enable FPU */
116 __asm__("vmsr fpexc, %0" : : "r" (0x40000000));
117 #endif
118 #endif
119
120 /* Branch to C code */
121 __asm__("b _cstart");
122 }
123
124 #endif
125
126 #ifdef CRT0_SEMIHOST
127
128 /*
129 * Trap faults, print message and exit when running under semihost
130 */
131
132 #include <semihost.h>
133 #include <unistd.h>
134 #include <stdio.h>
135
136 #define _REASON(r) #r
137 #define REASON(r) _REASON(r)
138
139 #if __ARM_ARCH_PROFILE == 'M'
140
141 #define GET_SP struct fault *sp; __asm__ ("mov %0, sp" : "=r" (sp))
142
143 struct fault {
144 unsigned int r0;
145 unsigned int r1;
146 unsigned int r2;
147 unsigned int r3;
148 unsigned int r12;
149 unsigned int lr;
150 unsigned int pc;
151 unsigned int xpsr;
152 };
153
154 static const char *const reasons[] = {
155 "hardfault",
156 "memmanage",
157 "busfault",
158 "usagefault"
159 };
160
161 #define REASON_HARDFAULT 0
162 #define REASON_MEMMANAGE 1
163 #define REASON_BUSFAULT 2
164 #define REASON_USAGE 3
165
166 static void __attribute__((used))
arm_fault(struct fault * f,int reason)167 arm_fault(struct fault *f, int reason)
168 {
169 printf("ARM fault: %s\n", reasons[reason]);
170 printf("\tR0: 0x%08x\n", f->r0);
171 printf("\tR1: 0x%08x\n", f->r1);
172 printf("\tR2: 0x%08x\n", f->r2);
173 printf("\tR3: 0x%08x\n", f->r3);
174 printf("\tR12: 0x%08x\n", f->r12);
175 printf("\tLR: 0x%08x\n", f->lr);
176 printf("\tPC: 0x%08x\n", f->pc);
177 printf("\tXPSR: 0x%08x\n", f->xpsr);
178 _exit(1);
179 }
180
181 void __attribute__((naked))
arm_hardfault_isr(void)182 arm_hardfault_isr(void)
183 {
184 __asm__("mov r0, sp");
185 __asm__("movs r1, #" REASON(REASON_HARDFAULT));
186 __asm__("bl arm_fault");
187 }
188
189 void __attribute__((naked))
arm_memmange_isr(void)190 arm_memmange_isr(void)
191 {
192 __asm__("mov r0, sp");
193 __asm__("movs r1, #" REASON(REASON_MEMMANAGE));
194 __asm__("bl arm_fault");
195 }
196
197 void __attribute__((naked))
arm_busfault_isr(void)198 arm_busfault_isr(void)
199 {
200 __asm__("mov r0, sp");
201 __asm__("movs r1, #" REASON(REASON_BUSFAULT));
202 __asm__("bl arm_fault");
203 }
204
205 void __attribute__((naked))
arm_usagefault_isr(void)206 arm_usagefault_isr(void)
207 {
208 __asm__("mov r0, sp");
209 __asm__("movs r1, #" REASON(REASON_USAGE));
210 __asm__("bl arm_fault");
211 }
212
213 #else
214
215 struct fault {
216 unsigned int r[7];
217 unsigned int pc;
218 };
219
220 static const char *const reasons[] = {
221 "undef",
222 "svc",
223 "prefetch_abort",
224 "data_abort"
225 };
226
227 #define REASON_UNDEF 0
228 #define REASON_SVC 1
229 #define REASON_PREFETCH_ABORT 2
230 #define REASON_DATA_ABORT 3
231
232 static void __attribute__((used))
arm_fault(struct fault * f,int reason)233 arm_fault(struct fault *f, int reason)
234 {
235 int r;
236 printf("ARM fault: %s\n", reasons[reason]);
237 for (r = 0; r <= 6; r++)
238 printf("\tR%d: 0x%08x\n", r, f->r[r]);
239 printf("\tPC: 0x%08x\n", f->pc);
240 _exit(1);
241 }
242
243 #define VECTOR_COMMON \
244 __asm__("mov r7, %0" : : "r" (__stack)); \
245 __asm__("mov sp, r7"); \
246 __asm__("push {lr}"); \
247 __asm__("push {r0-r6}"); \
248 __asm__("mov r0, sp")
249
250 void __attribute__((naked)) __section(".init")
arm_undef_vector(void)251 arm_undef_vector(void)
252 {
253 VECTOR_COMMON;
254 __asm__("mov r1, #" REASON(REASON_UNDEF));
255 __asm__("bl arm_fault");
256 }
257
258 void __attribute__((naked)) __section(".init")
arm_prefetch_abort_vector(void)259 arm_prefetch_abort_vector(void)
260 {
261 VECTOR_COMMON;
262 __asm__("mov r1, #" REASON(REASON_UNDEF));
263 __asm__("bl arm_fault");
264 }
265
266 void __attribute__((naked)) __section(".init")
arm_data_abort_vector(void)267 arm_data_abort_vector(void)
268 {
269 VECTOR_COMMON;
270 __asm__("mov r1, #" REASON(REASON_UNDEF));
271 __asm__("bl arm_fault");
272 }
273
274 #endif
275
276 #endif
277
278