Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 64 additions & 3 deletions libc/startup/baremetal/arm/start.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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() {}
Expand All @@ -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
Expand All @@ -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));
Expand All @@ -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"
Loading