[libc] Add startup code for ARM v7-A, ARM v7-R variants (#153576)

These variants require a different exception table that requires a bit
of initialisation.

This allows us to enable testing for these variants downstream.
This commit is contained in:
William Huynh 2025-08-15 10:17:50 +01:00 committed by GitHub
parent 21b607adbe
commit 6b16a276ef
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -15,6 +15,8 @@
#include "startup/baremetal/fini.h"
#include "startup/baremetal/init.h"
#include <arm_acle.h> // For __arm_wsr
extern "C" {
int main(int argc, char **argv);
void _start();
@ -33,6 +35,7 @@ extern uintptr_t __bss_size[];
} // extern "C"
namespace {
#if __ARM_ARCH_PROFILE == 'M'
// Based on
// https://developer.arm.com/documentation/107565/0101/Use-case-examples/Generic-Information/What-is-inside-a-program-image-/Vector-table
void NMI_Handler() {}
@ -55,8 +58,8 @@ const HandlerType vector_table[] = {
reinterpret_cast<HandlerType>(&__stack), // SP
_start, // Reset
NMI_Handler, // NMI Handler
HardFault_Handler, // Hard Fault Handlerß
MemManage_Handler, // MPU Fault Han`dler
HardFault_Handler, // Hard Fault Handler
MemManage_Handler, // MPU Fault Handler
BusFault_Handler, // Bus Fault Handler
UsageFault_Handler, // Usage Fault Handler
0, // Reserved
@ -70,12 +73,64 @@ const HandlerType vector_table[] = {
SysTick_Handler, // SysTick Handler
// Unused
};
#else
// Based on
// https://developer.arm.com/documentation/den0013/0400/Boot-Code/Booting-a-bare-metal-system
void Reset_Handler() { LIBC_NAMESPACE::exit(1); }
void Undefined_Handler() { LIBC_NAMESPACE::exit(1); }
void SWI_Handler() { LIBC_NAMESPACE::exit(1); }
void PrefetchAbort_Handler() { LIBC_NAMESPACE::exit(1); }
void DataAbort_Handler() { LIBC_NAMESPACE::exit(1); }
void IRQ_Handler() { LIBC_NAMESPACE::exit(1); }
void FIQ_Handler() { LIBC_NAMESPACE::exit(1); }
// The AArch32 exception vector table has 8 entries, each of which is 4
// bytes long, and contains code. The whole table must be 32-byte aligned.
// The table may also be relocated, so we make it position-independent by
// having a table of handler addresses and loading the address to pc.
[[gnu::section(".vectors"), gnu::aligned(32), gnu::used, gnu::naked,
gnu::target("arm")]]
void vector_table() {
asm("LDR pc, [pc, #24]");
asm("LDR pc, [pc, #24]");
asm("LDR pc, [pc, #24]");
asm("LDR pc, [pc, #24]");
asm("LDR pc, [pc, #24]");
asm("LDR pc, [pc, #24]");
asm("LDR pc, [pc, #24]");
asm("LDR pc, [pc, #24]");
asm(".word %c0" : : "X"(Reset_Handler));
asm(".word %c0" : : "X"(Undefined_Handler));
asm(".word %c0" : : "X"(SWI_Handler));
asm(".word %c0" : : "X"(PrefetchAbort_Handler));
asm(".word %c0" : : "X"(DataAbort_Handler));
asm(".word %c0" : : "X"(0));
asm(".word %c0" : : "X"(IRQ_Handler));
asm(".word %c0" : : "X"(FIQ_Handler));
}
#endif
} // namespace
namespace LIBC_NAMESPACE_DECL {
[[noreturn]] void do_start() {
// FIXME: set up the QEMU test environment
#if __ARM_ARCH_PROFILE == 'A' || __ARM_ARCH_PROFILE == 'R'
// Set up registers to be used in exception handling
// Copy the current sp value to each of the banked copies of sp.
__arm_wsr("CPSR_c", 0x11); // FIQ
asm volatile("mov sp, %0" : : "r"(__builtin_frame_address(0)));
__arm_wsr("CPSR_c", 0x12); // IRQ
asm volatile("mov sp, %0" : : "r"(__builtin_frame_address(0)));
__arm_wsr("CPSR_c", 0x17); // ABT
asm volatile("mov sp, %0" : : "r"(__builtin_frame_address(0)));
__arm_wsr("CPSR_c", 0x1B); // UND
asm volatile("mov sp, %0" : : "r"(__builtin_frame_address(0)));
__arm_wsr("CPSR_c", 0x1F); // SYS
asm volatile("mov sp, %0" : : "r"(__builtin_frame_address(0)));
__arm_wsr("CPSR_c", 0x13); // SVC
#endif
// Perform the equivalent of scatterloading
LIBC_NAMESPACE::memcpy(__data_start, __data_source,
reinterpret_cast<uintptr_t>(__data_size));
@ -89,7 +144,13 @@ namespace LIBC_NAMESPACE_DECL {
}
} // namespace LIBC_NAMESPACE_DECL
extern "C" void _start() {
extern "C" {
#ifdef __ARM_ARCH_ISA_ARM
// If ARM state is supported, it must be used (instead of Thumb)
[[gnu::naked, gnu::target("arm")]]
#endif
void _start() {
asm volatile("mov sp, %0" : : "r"(&__stack));
asm volatile("bl %0" : : "X"(LIBC_NAMESPACE::do_start));
}
} // extern "C"