I try to create a trivial kernel for aarch64 (cortex-a72).
NB: What for? - Just for fun! It's interesting for me.
loader.s:
.global _reset
_reset:
# Set up stack pointer
LDR X2, =stack_top
MOV SP, X2
# Magic number
MOV X13, #0x1337
# Call kernel entrypoint
bl start
# Loop endlessly
B .
main.c:
void start(void) {
for(;;) {
}
}
linker.ld:
SECTIONS {
. = 0x40100000;
.text : { *(.text) }
. = ALIGN(8);
. = . + 0x1000;
stack_top = .;
}
And Makefile:
BUILD_DIR=build
LLVM_BIN=/opt/homebrew/opt/llvm/bin
BINTOOLS_BIN=/opt/homebrew/Cellar/aarch64-elf-binutils/2.41/bin
OBJCOPY=$(LLVM_BIN)/llvm-objcopy
OBJDUMP=$(LLVM_BIN)/llvm-objdump
HEXDUMP=hexdump
CC=/$(LLVM_BIN)/clang
AS=$(BINTOOLS_BIN)/aarch64-elf-as
LD=$(BINTOOLS_BIN)/aarch64-elf-ld
QEMU_VERSION=8.1.1
all: kernel
kernel: linker
$(OBJCOPY) $(BUILD_DIR)/kernel.elf -O binary $(BUILD_DIR)/kernel.bin
linker: loader.o main.o
$(LD) -m aarch64elf -nostdlib -T linker.ld $(BUILD_DIR)/loader.o $(BUILD_DIR)/main.o -o $(BUILD_DIR)/kernel.elf
loader.o: mkdir
$(AS) loader.s -o $(BUILD_DIR)/loader.o
main.o: mkdir
$(CC) -c --target=aarch64-none-linux -Wall -O2 -fomit-frame-pointer -fno-exceptions -fno-asynchronous-unwind-tables -fno-unwind-tables main.c -o $(BUILD_DIR)/main.o
mkdir:
mkdir -p $(BUILD_DIR)
dump:
$(OBJDUMP) -D $(BUILD_DIR)/kernel.elf
dump_binary:
$(HEXDUMP) -C $(BUILD_DIR)/kernel.bin
run:
qemu-system-aarch64 -M virt \
-cpu cortex-a72 \
-bios "/opt/homebrew/Cellar/qemu/$(QEMU_VERSION)/share/qemu/edk2-aarch64-code.fd" \
-m 128M \
-nographic \
-device loader,file=$(BUILD_DIR)/kernel.elf \
-device loader,addr=0x40100000,cpu-num=0 \
-s \
-S
clean:
rm -rf $(BUILD_DIR)/*.o
I am a noobie in a low-level programming, so I've combined this code from decades of web-sites. Need to say it's a little hard on macOS (M1 Pro) using LLVM.
So this code is compiled and Qemu even launches it BUT when I execute in Qemu info registers it shows "empty" registers:
QEMU 8.1.1 monitor - type 'help' for more information
(qemu) info registers
CPU#0
PC=0000000040100000 X00=0000000000000000 X01=0000000000000000
X02=0000000000000000 X03=0000000000000000 X04=0000000000000000
X05=0000000000000000 X06=0000000000000000 X07=0000000000000000
X08=0000000000000000 X09=0000000000000000 X10=0000000000000000
X11=0000000000000000 X12=0000000000000000 X13=0000000000000000
X14=0000000000000000 X15=0000000000000000 X16=0000000000000000
X17=0000000000000000 X18=0000000000000000 X19=0000000000000000
X20=0000000000000000 X21=0000000000000000 X22=0000000000000000
X23=0000000000000000 X24=0000000000000000 X25=0000000000000000
X26=0000000000000000 X27=0000000000000000 X28=0000000000000000
X29=0000000000000000 X30=0000000000000000 SP=0000000000000000
PSTATE=400003c5 -Z-- EL1h FPU disabled
X13 doesn't contain a magic number too.
What am I doing wrongly?
If it will help kernel.elf dump is below:
/opt/homebrew/opt/llvm/bin/llvm-objdump -D build/kernel.elf
build/kernel.elf: file format elf64-littleaarch64
Disassembly of section .text:
0000000040100000 <_reset>:
40100000: 580000c2 ldr x2, 0x40100018 <_reset+0x18>
40100004: 9100005f mov sp, x2
40100008: d28266ed mov x13, #0x1337 // =4919
4010000c: 94000005 bl 0x40100020 <start>
40100010: 14000000 b 0x40100010 <_reset+0x10>
40100014: 00000000 udf #0x0
0000000040100018 <$d>:
40100018: 28 10 10 40 .word 0x40101028
4010001c: 00 00 00 00 .word 0x00000000
0000000040100020 <start>:
40100020: 14000000 b 0x40100020 <start>
Disassembly of section .comment:
0000000000000000 <.comment>:
0: 656d6f48 fnmls z8.h, p3/m, z26.h, z13.h
4: 77657262 <unknown>
8: 616c6320 <unknown>
c: 7620676e <unknown>
10: 69737265 ldpsw x5, x28, [x19, #-0x68]
14: 31206e6f adds w15, w19, #0x81b
18: 2e302e37 uqsub v23.8b, v17.8b, v16.8b
1c: 31 00 <unknown>
000000000000001d <$d.1>:
1d: 00 .byte 0x00
Disassembly of section .symtab:
0000000000000000 <.symtab>:
...
1c: 00010003 <unknown>
20: 40100000 <unknown>
...
34: 00020003 <unknown>
...
48: 00000001 udf #0x1
4c: fff10004 <unknown>
...
60: 0000000a udf #0xa
64: 00010000 <unknown>
68: 40100000 <unknown>
...
78: 0000000d udf #0xd
7c: 00010000 <unknown>
80: 40100018 <unknown>
...
90: 00000010 udf #0x10
94: fff10004 <unknown>
...
a8: 00000017 udf #0x17
ac: 00010000 <unknown>
b0: 40100020 <unknown>
...
c0: 0000001c udf #0x1c
c4: 00020000 <unknown>
c8: 0000001d udf #0x1d
...
d8: 00000021 udf #0x21
dc: 00010010 <unknown>
e0: 40101028 <unknown>
...
f0: 0000002b udf #0x2b
f4: 00010010 <unknown>
f8: 40100000 <unknown>
...
108: 00000032 udf #0x32
10c: 00010012 <unknown>
110: 40100020 <unknown>
114: 00000000 udf #0x0
118: 00000004 udf #0x4
11c: 00000000 udf #0x0
Disassembly of section .strtab:
0000000000000000 <.strtab>:
0: 616f6c00 <unknown>
4: 2e726564 umax v4.4h, v11.4h, v18.4h
8: 7824006f ldaddh w4, w15, [x3]
c: 00642400 <unknown>
10: 6e69616d rsubhn2 v13.8h, v11.4s, v9.4s
14: 2400632e cmplt p14.b, p0/z, z25.b, z0.d
18: 00302e78 <unknown>
1c: 312e6424 adds w4, w1, #0xb99
20: 61747300 <unknown>
24: 745f6b63 <unknown>
28: 5f00706f <unknown>
2c: 65736572 fnmls z18.h, p1/m, z11.h, z19.h
30: 74730074 <unknown>
34: 00747261 <unknown>
Disassembly of section .shstrtab:
0000000000000000 <.shstrtab>:
0: 79732e00 ldrh w0, [x16, #0x1996]
4: 6261746d <unknown>
8: 74732e00 <unknown>
c: 62617472 <unknown>
10: 68732e00 <unknown>
14: 74727473 <unknown>
18: 2e006261 <unknown>
1c: 74786574 <unknown>
20: 6f632e00 <unknown>
24: 6e656d6d umin v13.8h, v11.8h, v5.8h
28: 74 00 <unknown>