Skip to content

Conversation

@saturn691
Copy link
Contributor

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

This allows us to enable testing for these variants downstream.

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

This allows us to enable testing for these variants downstream.
@llvmbot llvmbot added the libc label Aug 14, 2025
@llvmbot
Copy link
Member

llvmbot commented Aug 14, 2025

@llvm/pr-subscribers-libc

Author: William Huynh (saturn691)

Changes

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

This allows us to enable testing for these variants downstream.


Full diff: https://github.com/llvm/llvm-project/pull/153576.diff

1 Files Affected:

  • (modified) libc/startup/baremetal/arm/start.cpp (+64-3)
diff --git a/libc/startup/baremetal/arm/start.cpp b/libc/startup/baremetal/arm/start.cpp
index 493445e2922b0..a926206c73a6f 100644
--- a/libc/startup/baremetal/arm/start.cpp
+++ b/libc/startup/baremetal/arm/start.cpp
@@ -15,6 +15,8 @@
 #include "startup/baremetal/fini.h"
 #include "startup/baremetal/init.h"
 
+#include <arm_acle.h>
+
 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"

Copy link
Contributor

@michaelrj-google michaelrj-google left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@saturn691 saturn691 enabled auto-merge (squash) August 15, 2025 09:13
@saturn691 saturn691 merged commit 6b16a27 into llvm:main Aug 15, 2025
19 checks passed
@saturn691 saturn691 deleted the libc-v7a-v7r branch August 15, 2025 09:25
@saturn691
Copy link
Contributor Author

I'm going to build upon this bootcode for more versions of Arm. If anyone has other nits please leave them here and I'll do a post-commit fixup. Please also feel free to approve if you're happy.

saturn691 added a commit to arm/arm-toolchain that referenced this pull request Aug 15, 2025
Support added in llvm/llvm-project#153576

Also update bootcode to support v7-A/v7-R outside of hermetic tests.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants