1515#include " startup/baremetal/fini.h"
1616#include " startup/baremetal/init.h"
1717
18+ #include < arm_acle.h> // For __arm_wsr
19+
1820extern " C" {
1921int main (int argc, char **argv);
2022void _start ();
@@ -33,6 +35,7 @@ extern uintptr_t __bss_size[];
3335} // extern "C"
3436
3537namespace {
38+ #if __ARM_ARCH_PROFILE == 'M'
3639// Based on
3740// https://developer.arm.com/documentation/107565/0101/Use-case-examples/Generic-Information/What-is-inside-a-program-image-/Vector-table
3841void NMI_Handler () {}
@@ -55,8 +58,8 @@ const HandlerType vector_table[] = {
5558 reinterpret_cast <HandlerType>(&__stack), // SP
5659 _start, // Reset
5760 NMI_Handler, // NMI Handler
58- HardFault_Handler, // Hard Fault Handlerß
59- MemManage_Handler, // MPU Fault Han`dler
61+ HardFault_Handler, // Hard Fault Handler
62+ MemManage_Handler, // MPU Fault Handler
6063 BusFault_Handler, // Bus Fault Handler
6164 UsageFault_Handler, // Usage Fault Handler
6265 0 , // Reserved
@@ -70,12 +73,64 @@ const HandlerType vector_table[] = {
7073 SysTick_Handler, // SysTick Handler
7174 // Unused
7275};
76+ #else
77+ // Based on
78+ // https://developer.arm.com/documentation/den0013/0400/Boot-Code/Booting-a-bare-metal-system
79+ void Reset_Handler () { LIBC_NAMESPACE::exit (1 ); }
80+ void Undefined_Handler () { LIBC_NAMESPACE::exit (1 ); }
81+ void SWI_Handler () { LIBC_NAMESPACE::exit (1 ); }
82+ void PrefetchAbort_Handler () { LIBC_NAMESPACE::exit (1 ); }
83+ void DataAbort_Handler () { LIBC_NAMESPACE::exit (1 ); }
84+ void IRQ_Handler () { LIBC_NAMESPACE::exit (1 ); }
85+ void FIQ_Handler () { LIBC_NAMESPACE::exit (1 ); }
86+
87+ // The AArch32 exception vector table has 8 entries, each of which is 4
88+ // bytes long, and contains code. The whole table must be 32-byte aligned.
89+ // The table may also be relocated, so we make it position-independent by
90+ // having a table of handler addresses and loading the address to pc.
91+ [[gnu::section(" .vectors" ), gnu::aligned(32 ), gnu::used, gnu::naked,
92+ gnu::target (" arm" )]]
93+ void vector_table() {
94+ asm (" LDR pc, [pc, #24]" );
95+ asm (" LDR pc, [pc, #24]" );
96+ asm (" LDR pc, [pc, #24]" );
97+ asm (" LDR pc, [pc, #24]" );
98+ asm (" LDR pc, [pc, #24]" );
99+ asm (" LDR pc, [pc, #24]" );
100+ asm (" LDR pc, [pc, #24]" );
101+ asm (" LDR pc, [pc, #24]" );
102+ asm (" .word %c0" : : " X" (Reset_Handler));
103+ asm (" .word %c0" : : " X" (Undefined_Handler));
104+ asm (" .word %c0" : : " X" (SWI_Handler));
105+ asm (" .word %c0" : : " X" (PrefetchAbort_Handler));
106+ asm (" .word %c0" : : " X" (DataAbort_Handler));
107+ asm (" .word %c0" : : " X" (0 ));
108+ asm (" .word %c0" : : " X" (IRQ_Handler));
109+ asm (" .word %c0" : : " X" (FIQ_Handler));
110+ }
111+ #endif
73112} // namespace
74113
75114namespace LIBC_NAMESPACE_DECL {
76115[[noreturn]] void do_start () {
77116 // FIXME: set up the QEMU test environment
78117
118+ #if __ARM_ARCH_PROFILE == 'A' || __ARM_ARCH_PROFILE == 'R'
119+ // Set up registers to be used in exception handling
120+ // Copy the current sp value to each of the banked copies of sp.
121+ __arm_wsr (" CPSR_c" , 0x11 ); // FIQ
122+ asm volatile (" mov sp, %0" : : " r" (__builtin_frame_address (0 )));
123+ __arm_wsr (" CPSR_c" , 0x12 ); // IRQ
124+ asm volatile (" mov sp, %0" : : " r" (__builtin_frame_address (0 )));
125+ __arm_wsr (" CPSR_c" , 0x17 ); // ABT
126+ asm volatile (" mov sp, %0" : : " r" (__builtin_frame_address (0 )));
127+ __arm_wsr (" CPSR_c" , 0x1B ); // UND
128+ asm volatile (" mov sp, %0" : : " r" (__builtin_frame_address (0 )));
129+ __arm_wsr (" CPSR_c" , 0x1F ); // SYS
130+ asm volatile (" mov sp, %0" : : " r" (__builtin_frame_address (0 )));
131+ __arm_wsr (" CPSR_c" , 0x13 ); // SVC
132+ #endif
133+
79134 // Perform the equivalent of scatterloading
80135 LIBC_NAMESPACE::memcpy (__data_start, __data_source,
81136 reinterpret_cast <uintptr_t >(__data_size));
@@ -89,7 +144,13 @@ namespace LIBC_NAMESPACE_DECL {
89144}
90145} // namespace LIBC_NAMESPACE_DECL
91146
92- extern " C" void _start () {
147+ extern " C" {
148+ #ifdef __ARM_ARCH_ISA_ARM
149+ // If ARM state is supported, it must be used (instead of Thumb)
150+ [[gnu::naked, gnu::target(" arm" )]]
151+ #endif
152+ void _start () {
93153 asm volatile (" mov sp, %0" : : " r" (&__stack));
94154 asm volatile (" bl %0" : : " X" (LIBC_NAMESPACE::do_start));
95155}
156+ } // extern "C"
0 commit comments