Skip to content

Instantly share code, notes, and snippets.

@rrampage
Last active July 22, 2025 14:19
Show Gist options
  • Save rrampage/c666e4bbd3a94d53847808bdd28d140c to your computer and use it in GitHub Desktop.
Save rrampage/c666e4bbd3a94d53847808bdd28d140c to your computer and use it in GitHub Desktop.
Tiny ARM64 ELF kernel
/*
ARM64 kernel to echo user input
Adapted from:
- http://wiki.osdev.org/QEMU_AArch64_Virt_Bare_Bones
- https://krinkinmu.github.io/2020/11/29/PL011.html
- https://wiki.osdev.org/Raspberry_Pi_Bare_Bones (getc and putc)
Compile: `as -o boot.o boot.S && ld -s -o asmkernel boot.o`
Run on QEMU using: `qemu-system-aarch64 -machine virt -cpu max -nographic -kernel asmkernel.elf`
*/
.equ UART_ADDR, 0x9000000 // UART base + dest
.equ UART_FLAG_REG, 0x9000018
.equ UART_TXFF, 0x20 // transmit fifo full
.equ UART_RXFE, 0x10 // receive fifo empty
.data
msg:
.ascii "Hello World!\n";
len = . - msg
.text
.global _start
/*
x20 -> UART address for reading/writing bytes
x19 -> UART flag address for checking status before r/w
w3 -> contains state of flag, not used for anything else
w4 -> byte read from/ to be written to UART
*/
_start:
mov x20, UART_ADDR
add x19, x20, #0x18 // move flag reg
adr x1, msg
ldr x2, =len
bl print
bl echo
b .
getc:
ldrb w3, [x19]
and w3, w3, #UART_RXFE
cbnz w3, getc
ldrb w4, [x20]
ret
putc:
ldrb w3, [x19]
and w3, w3, #UART_TXFF
cbnz w3, putc
strb w4, [x20]
ret
print:
mov x5, #0
loop:
cmp x5, x2
b.ge done
ldrb w6, [x1,x5]
strb w6, [x20]
add x5, x5, 1
b loop
done:
ret
echo:
bl getc
cmp w4, #0x08 // backspace
b.ne del
b backspace
del:
cmp w4, #0x7f // del
b.ne crlf
mov w4, #0x08 // backspace
backspace:
bl putc
mov w4, #0x20 // space
bl putc
mov w4, #0x08 // backspace
bl putc
crlf:
cmp w4, #0x0D // CR -> putc 'CR' + putc 'LF'
b.ne just_echo
bl putc
mov w4, #0x0A
just_echo:
bl putc
b echo
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment