Skip to content

Commit e0dd48e

Browse files
authored
[ATfE] Add AArch64 samples for LLVM-libc (#496)
This is based on the AArch64 sample from picolibc. This requires a minor hack. We need to place the _start at the beginning of the boot_flash section, and run QEMU from 0x0. This allows QEMU to turn off multithreading, and reach the _start symbol. We use the section `.text.init.enter` for this. We do need extra space in `boot_flash`, because we also put the page table in this section.
1 parent f920059 commit e0dd48e

File tree

6 files changed

+140
-6
lines changed

6 files changed

+140
-6
lines changed
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/* Copyright (c) 2025, Arm Limited and affiliates.
2+
*
3+
* Part of the Arm Toolchain 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+
Raspberry Pi does not have flash, but to accommodate for the llvmlibc.ld, we
9+
put the boot_flash, flash and ram momory in Raspberry's RAM. The boot_flash
10+
memory has to be put at fixed address. The flash and ram memory are placed
11+
arbitrarily.
12+
13+
This is enough for simple testing, for real projects appropriate custom
14+
linker script file should be provided.
15+
*/
16+
17+
__boot_flash = 0x80000; /* Default firmware address for Rapberry Pi 3 */
18+
__boot_flash_size = 0x2000; /* 8K of space for added page table */
19+
__flash = 0x10000000;
20+
__flash_size = 0x10000000;
21+
__ram = 0x20000000;
22+
__ram_size = 0x20000000;
23+
__stack_size = 4096;
24+
25+
INCLUDE llvmlibc.ld
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#
2+
# Copyright (c) 2025, Arm Limited and affiliates.
3+
# Part of the Arm Toolchain 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+
include ../../Makefile.conf
9+
10+
build: hello.elf
11+
12+
hello.elf: *.c
13+
$(BIN_PATH)/clang --config=llvmlibc.cfg $(AARCH64_TARGET) $(CRT_SEMIHOST) -lm -g -T ../../ldscripts/llvmlibc-raspi3b.ld -o hello.elf $^
14+
15+
%.img: %.elf
16+
$(BIN_PATH)/llvm-objcopy -O binary $< $@
17+
18+
run: hello.img
19+
qemu-system-aarch64 -M raspi3b -semihosting -nographic -kernel $<
20+
21+
debug: hello.img
22+
qemu-system-aarch64 -M raspi3b -semihosting -nographic -kernel $< -s -S
23+
24+
clean:
25+
rm -f *.img *.elf
26+
27+
.PHONY: clean run debug
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/* Copyright (c) 2025, Arm Limited and affiliates.
2+
*
3+
* Part of the Arm Toolchain 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+
#include <assert.h>
8+
#include <stdio.h>
9+
#include <stdlib.h>
10+
#include <string.h>
11+
#include <math.h>
12+
13+
// Example that uses heap, string and math library.
14+
15+
int main(void) {
16+
const char *hello_s = "hello ";
17+
const char *world_s = "world";
18+
const size_t hello_s_len = strlen(hello_s);
19+
const size_t world_s_len = strlen(world_s);
20+
const size_t out_s_len = hello_s_len + world_s_len + 1;
21+
char *out_s = (char*) malloc(out_s_len);
22+
assert(out_s_len >= hello_s_len + 1);
23+
strncpy(out_s, hello_s, hello_s_len + 1);
24+
assert(out_s_len >= strlen(out_s) + world_s_len + 1);
25+
strncat(out_s, world_s, world_s_len + 1);
26+
printf("%s\npi = %f\n", out_s, 4.0f * atanf(1.0f));
27+
free(out_s);
28+
return 0;
29+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
@REM Copyright (c) 2025, Arm Limited and affiliates.
2+
@REM
3+
@REM Part of the Arm Toolchain project, under the Apache License v2.0 with LLVM Exceptions.
4+
@REM See https://llvm.org/LICENSE.txt for license information.
5+
@REM SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
7+
@if [%1]==[] goto :target_empty
8+
@set target=%1
9+
@goto :make
10+
:target_empty
11+
@set target=build
12+
13+
:make
14+
@if [%target%]==[build] goto :build
15+
@if [%target%]==[run] goto :run
16+
@if [%target%]==[clean] goto :clean
17+
@echo Error: unknown target "%target%"
18+
@exit /B 1
19+
20+
:build
21+
@if [%BIN_PATH%]==[] goto :bin_path_empty
22+
@call :build_fn
23+
@exit /B
24+
25+
:run
26+
@if exist hello.img goto :do_run
27+
@if [%BIN_PATH%]==[] goto :bin_path_empty
28+
@call :build_fn
29+
:do_run
30+
qemu-system-aarch64.exe -M raspi3b -semihosting -nographic -kernel hello.img
31+
@exit /B
32+
33+
:clean
34+
if exist hello.elf del /q hello.elf
35+
if exist hello.img del /q hello.img
36+
@exit /B
37+
38+
:bin_path_empty
39+
@echo Error: BIN_PATH environment variable is not set
40+
@exit /B 1
41+
42+
:build_fn
43+
%BIN_PATH%\clang.exe --config=llvmlibc.cfg --target=aarch64-none-elf -nostartfiles -lcrt0-semihost -lsemihost -g -T ..\..\ldscripts\llvmlibc-raspi3b.ld -o hello.elf hello.c
44+
%BIN_PATH%\llvm-objcopy.exe -O binary hello.elf hello.img
45+
@exit /B

arm-software/embedded/llvmlibc-support/crt0/bootcode.cpp

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,13 +77,18 @@ extern "C" void __startup() {
7777
exit(main(0, 0));
7878
}
7979

80+
extern "C" {
8081
// The entry point sets sp and branches to the main startup function.
8182
#ifdef __ARM_ARCH_ISA_ARM
82-
// If the target supports the A32 instruction set then the entry point has to
83-
// use it.
83+
// If the target supports the A32 instruction set then the entry point has
84+
// to use it.
8485
__attribute__((target("arm")))
86+
#elif defined(__ARM_ARCH_ISA_A64)
87+
// QEMU (AArch64) will jump to the first section when running from a .bin/.hex
88+
// file after boot. Therefore, place the entrypoint there.
89+
__attribute__((section(".text.init.enter")))
8590
#endif
86-
__attribute__((naked)) extern "C" void _start() {
91+
__attribute__((naked)) void _start() {
8792
#if __ARM_ARCH_PROFILE != 'M' && __ARM_ARCH >= 8 && !defined(__ARM_ARCH_ISA_A64)
8893
// Check if we're in hypervisor mode
8994
asm("mrs r0, CPSR\n\t"
@@ -109,3 +114,4 @@ __attribute__((naked)) extern "C" void _start() {
109114
asm("mov sp, %0" : : "r"(&__stack));
110115
asm("bl %0" : : "X"(__startup));
111116
}
117+
} // extern "C"

arm-software/embedded/llvmlibc-support/llvmlibc.ld.in

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,11 @@ SECTIONS
6565
{
6666
PROVIDE(__stack = ORIGIN(ram) + LENGTH(ram));
6767

68-
.boot_flash : {
69-
KEEP (*(.vectors))
70-
} >boot_flash AT>boot_flash :text_boot_flash
68+
.boot_flash : {
69+
KEEP (*(.text.init.enter))
70+
KEEP (*(.vectors))
71+
KEEP (*(.init))
72+
} >boot_flash AT>boot_flash :text_boot_flash
7173

7274
.text : {
7375

0 commit comments

Comments
 (0)