Minimal runnable example
Source: https://github.com/cirosantilli/aarch64-bare-metal-qemu/tree/27537fb1dd0c27d6d91516bf4fc7e1d9564f5a40
Run with:
make
qemu-system-aarch64 -M virt -cpu cortex-a57 -nographic -kernel test64.elf -serial mon:stdio
Outcome: prints a single character H
to the UART and then goes into an infinite loop.
Source:
==> test64.ld <==
ENTRY(_Reset)
SECTIONS
{
. = 0x40000000;
.startup . : { startup64.o(.text) }
.text : { *(.text) }
.data : { *(.data) }
.bss : { *(.bss COMMON) }
. = ALIGN(8);
. = . + 0x1000; /* 4kB of stack memory */
stack_top = .;
}
==> test64.c <==
volatile unsigned int * const UART0DR = (unsigned int *) 0x09000000;
void print_uart0(const char *s) {
while(*s != '') { /* Loop until end of string */
*UART0DR = (unsigned int)(*s); /* Transmit char */
s++; /* Next char */
}
}
void c_entry() {
print_uart0("Hello world!
");
}
==> startup64.s <==
.global _Reset
_Reset:
mov x0, 0x48
ldr x1, =0x09000000
str x0, [x1]
b .
==> Makefile <==
CROSS_PREFIX=aarch64-linux-gnu-
all: test64.elf
startup64.o: startup64.s
$(CROSS_PREFIX)as -g -c $< -o $@
test64.elf: startup64.o
$(CROSS_PREFIX)ld -Ttest64.ld $^ -o $@
clean:
rm -f test64.elf startup64.o test64.o
You may change the entry address 0x40000000
to almost anything (as long as it is not mapped to the memory of some device?).
QEMU just parses the entry address from the Elf file, and puts the PC there to start with. You can verify that with GDB:
qemu-system-aarch64 -M virt -cpu cortex-a57 -nographic -kernel test64.elf -S -s &
gdb-multiarch -q -ex 'file test64.elf' -ex 'target remote localhost:1234'
Here I list a few other setups that may be of interest: How to make bare metal ARM programs and run them on QEMU?
Tested on Ubuntu 18.04.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…