192 lines · cpp
1//===-- Implementation of crt for arm -------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "hdr/stdint_proxy.h"10#include "src/__support/macros/config.h"11#include "src/stdlib/atexit.h"12#include "src/stdlib/exit.h"13#include "src/string/memcpy.h"14#include "src/string/memset.h"15#include "startup/baremetal/fini.h"16#include "startup/baremetal/init.h"17 18#include <arm_acle.h> // For __arm_wsr19 20extern "C" {21int main(int argc, char **argv);22void _start();23 24// Semihosting library initialisation if applicable. Required for printf, etc.25[[gnu::weak]] void _platform_init() {}26 27// These symbols are provided by the linker. The exact names are not defined by28// a standard.29extern uintptr_t __stack;30extern uintptr_t __data_source[];31extern uintptr_t __data_start[];32extern uintptr_t __data_size[];33extern uintptr_t __bss_start[];34extern uintptr_t __bss_size[];35} // extern "C"36 37namespace {38#if __ARM_ARCH_PROFILE == 'M'39// Based on40// https://developer.arm.com/documentation/107565/0101/Use-case-examples/Generic-Information/What-is-inside-a-program-image-/Vector-table41void NMI_Handler() {}42void HardFault_Handler() { LIBC_NAMESPACE::exit(1); }43void MemManage_Handler() { LIBC_NAMESPACE::exit(1); }44void BusFault_Handler() { LIBC_NAMESPACE::exit(1); }45void UsageFault_Handler() { LIBC_NAMESPACE::exit(1); }46void SVC_Handler() {}47void DebugMon_Handler() {}48void PendSV_Handler() {}49void SysTick_Handler() {}50 51// Architecturally the bottom 7 bits of VTOR are zero, meaning the vector table52// has to be 128-byte aligned, however an implementation can require more bits53// to be zero and Cortex-M23 can require up to 10, so 1024-byte align the vector54// table.55using HandlerType = void (*)(void);56[[gnu::section(".vectors"), gnu::aligned(1024), gnu::used]]57const HandlerType vector_table[] = {58 reinterpret_cast<HandlerType>(&__stack), // SP59 _start, // Reset60 NMI_Handler, // NMI Handler61 HardFault_Handler, // Hard Fault Handler62 MemManage_Handler, // MPU Fault Handler63 BusFault_Handler, // Bus Fault Handler64 UsageFault_Handler, // Usage Fault Handler65 0, // Reserved66 0, // Reserved67 0, // Reserved68 0, // Reserved69 SVC_Handler, // SVC Handler70 DebugMon_Handler, // Debug Monitor Handler71 0, // Reserved72 PendSV_Handler, // PendSV Handler73 SysTick_Handler, // SysTick Handler74 // Unused75};76#else77// Based on78// https://developer.arm.com/documentation/den0013/0400/Boot-Code/Booting-a-bare-metal-system79void Reset_Handler() { LIBC_NAMESPACE::exit(1); }80void Undefined_Handler() { LIBC_NAMESPACE::exit(1); }81void SWI_Handler() { LIBC_NAMESPACE::exit(1); }82void PrefetchAbort_Handler() { LIBC_NAMESPACE::exit(1); }83void DataAbort_Handler() { LIBC_NAMESPACE::exit(1); }84void IRQ_Handler() { LIBC_NAMESPACE::exit(1); }85void FIQ_Handler() { LIBC_NAMESPACE::exit(1); }86 87// The AArch32 exception vector table has 8 entries, each of which is 488// 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 by90// 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")]]93void 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#endif112} // namespace113 114namespace LIBC_NAMESPACE_DECL {115[[noreturn]] void do_start() {116 // FIXME: set up the QEMU test environment117 118#if __ARM_ARCH_PROFILE == 'A' || __ARM_ARCH_PROFILE == 'R'119 // Set up registers to be used in exception handling120 // Copy the current sp value to each of the banked copies of sp.121 __arm_wsr("CPSR_c", 0x11); // FIQ122 asm volatile("mov sp, %0" : : "r"(__builtin_frame_address(0)));123 __arm_wsr("CPSR_c", 0x12); // IRQ124 asm volatile("mov sp, %0" : : "r"(__builtin_frame_address(0)));125 __arm_wsr("CPSR_c", 0x17); // ABT126 asm volatile("mov sp, %0" : : "r"(__builtin_frame_address(0)));127 __arm_wsr("CPSR_c", 0x1B); // UND128 asm volatile("mov sp, %0" : : "r"(__builtin_frame_address(0)));129 __arm_wsr("CPSR_c", 0x1F); // SYS130 asm volatile("mov sp, %0" : : "r"(__builtin_frame_address(0)));131 __arm_wsr("CPSR_c", 0x13); // SVC132#endif133 134#if __ARM_ARCH_PROFILE == 'M' && \135 (defined(__ARM_FP) || defined(__ARM_FEATURE_MVE))136 // Enable FPU and MVE. They can't be enabled independently: the two are137 // governed by the same bits in CPACR.138 // Based on139 // https://developer.arm.com/documentation/dui0646/c/Cortex-M7-Peripherals/Floating-Point-Unit/Enabling-the-FPU140 // Set CPACR cp10 and cp11.141 auto cpacr = reinterpret_cast<volatile uint32_t *const>(0xE000ED88);142 *cpacr |= (0xF << 20);143 __dsb(0xF);144 __isb(0xF);145#if defined(__ARM_FEATURE_MVE)146 // Initialize low-overhead-loop tail predication to its neutral state147 uint32_t fpscr;148 __asm__ __volatile__("vmrs %0, FPSCR" : "=r"(fpscr) : :);149 fpscr |= (0x4 << 16);150 __asm__ __volatile__("vmsr FPSCR, %0" : : "r"(fpscr) :);151#endif152#elif (__ARM_ARCH_PROFILE == 'A' || __ARM_ARCH_PROFILE == 'R') && \153 defined(__ARM_FP)154 // Enable FPU.155 // Based on156 // https://developer.arm.com/documentation/dui0472/m/Compiler-Coding-Practices/Enabling-NEON-and-FPU-for-bare-metal157 // Set CPACR cp10 and cp11.158 uint32_t cpacr = __arm_rsr("p15:0:c1:c0:2");159 cpacr |= (0xF << 20);160 __arm_wsr("p15:0:c1:c0:2", cpacr);161 __isb(0xF);162 // Set FPEXC.EN163 uint32_t fpexc;164 __asm__ __volatile__("vmrs %0, FPEXC" : "=r"(fpexc) : :);165 fpexc |= (0x1 << 30);166 __asm__ __volatile__("vmsr FPEXC, %0" : : "r"(fpexc) :);167#endif168 169 // Perform the equivalent of scatterloading170 LIBC_NAMESPACE::memcpy(__data_start, __data_source,171 reinterpret_cast<uintptr_t>(__data_size));172 LIBC_NAMESPACE::memset(__bss_start, '\0',173 reinterpret_cast<uintptr_t>(__bss_size));174 __libc_init_array();175 176 _platform_init();177 LIBC_NAMESPACE::atexit(&__libc_fini_array);178 LIBC_NAMESPACE::exit(main(0, 0));179}180} // namespace LIBC_NAMESPACE_DECL181 182extern "C" {183#ifdef __ARM_ARCH_ISA_ARM184// If ARM state is supported, it must be used (instead of Thumb)185[[gnu::naked, gnu::target("arm")]]186#endif187void _start() {188 asm volatile("mov sp, %0" : : "r"(&__stack));189 asm volatile("bl %0" : : "X"(LIBC_NAMESPACE::do_start));190}191} // extern "C"192