Skip to content

joabech/hello-world

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Bare-Metal Hello-World for AArch64

This is a minimal bare-metal AArch64 application that demonstrates how U-Boot loads and executes a standalone binary. It's meant to be used in conjunction with U-boot build as a Code-in-Motion project. Which is the reason we see relatevies pre-defined paths here.

What It Does

The application:

  1. Runs directly on the hardware (or QEMU) without an operating system
  2. Outputs "Hello from bare-metal AArch64!" to the UART

Files

File Description
start.S Assembly entry point - sets up stack and calls C main
main.c C code that prints the hello message via UART
linker.ld Linker script defining memory layout at 0x40400000
Makefile Build rules using the aarch64-none-elf toolchain
boot.cmd U-Boot script source (text)
boot.scr U-Boot script binary (auto-generated by mkimage)
run-hello.sh Automated test script using expect

Building

Simply run:

make

Output files:

  • hello-world.elf - ELF binary (for reference)
  • hello-world.bin - Raw binary (loaded by U-Boot)
  • boot.scr - U-Boot script (auto-boot capable)

Running

Automated Method (Recommended)

If you have expect installed:

./hello-world/run-hello.sh

This will automatically:

  1. Start QEMU with U-Boot
  2. Load hello-world.bin from the virtio disk (or use auto-boot)
  3. Execute it using the go command
  4. Show the output

Auto-Boot Method

Since boot.scr is generated, U-Boot will auto-boot it:

make qemu-hello

Wait for U-Boot to scan bootflows - it will find boot.scr and auto-execute it!

Manual Method

  1. Start QEMU with the hello-world directory as a virtio disk:

    make qemu-hello
  2. At the U-Boot prompt (=>), type:

    fatload virtio 0:1 0x40400000 hello-world.bin
    go 0x40400000
    
  3. See the output, then quit with Ctrl+A then X.

How It Works

Boot Flow

With auto-boot (boot.scr):

- QEMU starts:
- U-Boot loads (from u-boot.bin)
- U-Boot scans bootflows
- Finds boot.scr on virtio disk
- Executes script automatically
- fatload + go commands run
- hello-world runs
- Returns to U-Boot

Manual method:

QEMU is started
- U-Boot loads (from u-boot.bin)
- U-Boot waits for commands
- fatload virtio 0:1 0x40400000 hello-world.bin
- Binary loaded from disk to memory at 0x40400000
- go 0x40400000
- U-Boot jumps to the binary
- hello-world runs
- Returns to U-Boot via 'ret' instruction

Memory Layout

  • 0x40000000: QEMU virt RAM start
  • 0x40400000: Hello-world load address (defined in linker.ld)
  • 0x40500000: Stack top (grows down toward 0x40400000)

U-Boot Commands

Command Purpose
fatload <dev> <part> <addr> <file> Load file from FAT filesystem to memory
go <addr> Jump to and execute code at address
bootelf <addr> Parse and execute ELF file at address (not used here)

Why go Instead of bootelf?

We use the go command with a raw binary because:

  • It's simpler - no ELF parsing needed
  • It avoids potential issues with 64-bit ELF validation in U-Boot
  • It's faster to load (smaller binary)
  • For bare-metal learning, it's more explicit about what's happening

From Here to Linux

The same pattern applies to booting Linux:

  1. Build Linux kernel → produces arch/arm64/boot/Image
  2. Load kernelfatload virtio 0:1 0x40400000 Image
  3. Load device treefatload virtio 0:1 0x43000000 qemu-arm64.dtb
  4. Bootbooti 0x40400000 - 0x43000000

The main differences:

  • Linux uses booti (boot image) instead of go
  • Linux needs a device tree blob (DTB)
  • Linux may need an initramfs
  • Linux doesn't return to U-Boot (it takes over the system)

Troubleshooting

Q: I get "Unknown command 'go'" A: Your U-Boot build doesn't have the go command enabled. Check that CONFIG_CMD_GO=y is in your U-Boot config.

Q: Nothing is printed A: Check that the UART address (0x09000000 in main.c) matches your QEMU machine type. The virt machine uses this address for PL011 UART0.

Q: "Bad Linux ARM64 Image magic!" when using bootelf A: The bootelf command has stricter requirements. Use the go command with the raw binary instead.

About

Simple hello-world example meant to be used from U-Boot

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors