Skip to content

Commit 9a42e9d

Browse files
committed
[libc] Add boot code for AArch64
This is required in hermetic testing downstream. It is not complete, and will not work on hardware, however it runs on QEMU, and can report a pass/fail on our tests.
1 parent c39b1ae commit 9a42e9d

File tree

3 files changed

+127
-1
lines changed

3 files changed

+127
-1
lines changed

libc/cmake/modules/LLVMLibCTestRules.cmake

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -836,7 +836,7 @@ function(add_libc_hermetic test_name)
836836
${fq_deps_list})
837837
# TODO: currently the dependency chain is broken such that getauxval cannot properly
838838
# propagate to hermetic tests. This is a temporary workaround.
839-
if (LIBC_TARGET_ARCHITECTURE_IS_AARCH64)
839+
if (LIBC_TARGET_ARCHITECTURE_IS_AARCH64 AND NOT(LIBC_TARGET_OS_IS_BAREMETAL))
840840
target_link_libraries(
841841
${fq_build_target_name}
842842
PRIVATE
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
add_startup_object(
2+
crt1
3+
SRC
4+
start.cpp
5+
DEPENDS
6+
libc.src.stdlib.atexit
7+
libc.src.stdlib.exit
8+
libc.src.string.memcpy
9+
libc.src.string.memset
10+
libc.startup.baremetal.init
11+
libc.startup.baremetal.fini
12+
COMPILE_OPTIONS
13+
-ffreestanding # To avoid compiler warnings about calling the main function.
14+
-fno-builtin
15+
-Wno-global-constructors # To allow vector table initialization
16+
)
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
//===-- Implementation of crt for aarch64 ---------------------------------===//
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-exception
6+
//
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>
19+
20+
extern "C" {
21+
int main(int argc, char **argv);
22+
void _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 by
28+
// a standard.
29+
extern uintptr_t __stack;
30+
extern uintptr_t __data_source[];
31+
extern uintptr_t __data_start[];
32+
extern uintptr_t __data_size[];
33+
extern uintptr_t __bss_start[];
34+
extern uintptr_t __bss_size[];
35+
} // extern "C"
36+
37+
namespace {
38+
// The Arm ARM for the A-profile architecture (D14.1.5) defines the exceptions.
39+
// However, for simplicity, we don't bother logging, and just exit.
40+
void GenericException_Handler() { LIBC_NAMESPACE::exit(1); }
41+
42+
// The AArch64 exception vector table has 16 entries, each of which is 128
43+
// bytes long, and contains code. The whole table must be 2048-byte aligned.
44+
// For our purposes, each entry just contains one branch instruction to the
45+
// exception reporting function, since we never want to resume after an
46+
// exception.
47+
[[gnu::section(".vectors"), gnu::aligned(2048), gnu::used, gnu::naked]]
48+
void vector_table() {
49+
#define VECTOR_TABLE_ENTRY \
50+
asm(".balign 128"); \
51+
asm("B %0" : : "X"(GenericException_Handler));
52+
53+
VECTOR_TABLE_ENTRY;
54+
VECTOR_TABLE_ENTRY;
55+
VECTOR_TABLE_ENTRY;
56+
VECTOR_TABLE_ENTRY;
57+
VECTOR_TABLE_ENTRY;
58+
VECTOR_TABLE_ENTRY;
59+
VECTOR_TABLE_ENTRY;
60+
VECTOR_TABLE_ENTRY;
61+
VECTOR_TABLE_ENTRY;
62+
VECTOR_TABLE_ENTRY;
63+
VECTOR_TABLE_ENTRY;
64+
VECTOR_TABLE_ENTRY;
65+
VECTOR_TABLE_ENTRY;
66+
VECTOR_TABLE_ENTRY;
67+
VECTOR_TABLE_ENTRY;
68+
VECTOR_TABLE_ENTRY;
69+
}
70+
} // namespace
71+
72+
namespace LIBC_NAMESPACE_DECL {
73+
74+
[[noreturn]] void do_start() {
75+
// TODO: This startup code is not extensive, but rather the MVP for QEMU
76+
// testing.
77+
78+
// Set up exception handling
79+
__arm_wsr64("VBAR_EL1", reinterpret_cast<uint64_t>(&vector_table));
80+
81+
#ifdef __ARM_FP
82+
// Do not trap FP/SME/SVE instructions
83+
static constexpr uint64_t CPACR_SHIFT_FPEN = 20;
84+
static constexpr uint64_t CPACR_SHIFT_SMEN = 24;
85+
uint64_t cpacr = __arm_rsr64("CPACR_EL1");
86+
cpacr |= (0x3 << CPACR_SHIFT_FPEN);
87+
cpacr |= (0x3 << CPACR_SHIFT_SMEN);
88+
__arm_wsr64("CPACR_EL1", cpacr);
89+
#endif
90+
91+
// Perform the equivalent of scatterloading
92+
LIBC_NAMESPACE::memcpy(__data_start, __data_source,
93+
reinterpret_cast<uintptr_t>(__data_size));
94+
LIBC_NAMESPACE::memset(__bss_start, '\0',
95+
reinterpret_cast<uintptr_t>(__bss_size));
96+
__libc_init_array();
97+
98+
_platform_init();
99+
LIBC_NAMESPACE::atexit(&__libc_fini_array);
100+
LIBC_NAMESPACE::exit(main(0, 0));
101+
}
102+
} // namespace LIBC_NAMESPACE_DECL
103+
104+
extern "C" {
105+
[[gnu::section(".text.init.enter"), gnu::naked]]
106+
void _start() {
107+
asm volatile("mov sp, %0" : : "r"(&__stack));
108+
asm volatile("bl %0" : : "X"(LIBC_NAMESPACE::do_start));
109+
}
110+
} // extern "C"

0 commit comments

Comments
 (0)