# ARM targets (`arm` and `aarch64`)

danos aims to run on Raspberry Pi hardware eventually. "ARM" isn't one target,
though — the Pis span **two different CPU architectures** (32-bit `arm` and 64-bit
`aarch64`) and (stock) a different boot protocol from x86-64's UEFI. **danos targets
`aarch64` only** (see the decision below); the `arm`/`aarch64` distinction still
matters for understanding why. This page maps the landscape so the
[arch split](arch.md) and build system can be planned for it.

## `arm` vs `aarch64` — 32-bit vs 64-bit

- **`arm`** = **32-bit** ARM (the *AArch32* state, A32/T32 instruction sets).
  ARMv7 and earlier, plus the 32-bit compatibility mode of newer cores. 16 × 32-bit
  registers.
- **`aarch64`** = **64-bit** ARM (the *AArch64* state, A64 instruction set), from
  **ARMv8-A** on. Also called **arm64**. 31 × 64-bit registers, a fixed 32-bit
  instruction width, a redesigned exception model — *not* a widening of A32, a clean
  new ISA.

They are as different from each other as either is from x86-64: separate registers,
page-table formats, and calling conventions. Each needs its own `system/kernel/arch/<name>/`.

## The Raspberry Pi models

| Model | SoC | Core | Architecture | danos target |
|-------|-----|------|--------------|--------------|
| Pi Zero / Zero W | BCM2835 | ARM1176JZF-S | ARMv6, 32-bit only | `arm` (not planned) |
| **Pi Zero 2 W** ← target | BCM2710 | Cortex-A53 | ARMv8-A, 64-bit | **`aarch64`** |
| **Pi 3 / 3B+** | BCM2837 | Cortex-A53 | ARMv8-A, 64-bit | **`aarch64`** |
| **Pi 4** | BCM2711 | Cortex-A72 | ARMv8-A, 64-bit | **`aarch64`** |
| **Pi 5** | BCM2712 | Cortex-A76 | ARMv8.2-A, 64-bit | **`aarch64`** |

> **Decision: `aarch64` only.** The target small board is a **Pi Zero 2 W** (BCM2710,
> Cortex-A53) — which is **`aarch64`**, *not* the original Zero W's 32-bit ARMv6. So
> every ARM board danos targets (Zero 2 W and Pi 3-5) is `aarch64`, and the 32-bit
> `arm`/ARMv6 backend is **not planned** — one ARM CPU port, not two. The original
> Zero W (ARMv6) would only re-enter scope if that specific older board were ever
> needed; the row above is kept only to explain the distinction.

## Booting: UEFI is not x86-only

The boot protocol is a **separate axis** from the CPU (see [arch.md](arch.md)):

- **UEFI** exists for ARM too — ARM servers require it (SBSA/SBBR), QEMU boots it
  with **AAVMF** (the AArch64 build of the same EDK2 firmware as x86's OVMF), and
  the Pi can even run it with community UEFI firmware. Under UEFI the handoff is the
  *same* as x86-64: system table, boot services, memory map, GOP framebuffer — so
  the loader logic largely carries over.
- **Device tree / firmware boot** — the **stock** Raspberry Pi firmware (VideoCore
  bootloader) is *not* UEFI: it loads the kernel and jumps to it with a **device-tree
  blob (DTB)** pointer. Both the Zero W and stock Pi 3-5 boot this way.

Note that even under UEFI on ARM, the OS still gets its hardware description from
**ACPI or a device tree** (often the DTB passed via a UEFI configuration table). So
"UEFI on ARM" doesn't remove the device tree — UEFI gives you memory + framebuffer;
the DTB/ACPI tells you what devices exist.

## What danos needs, layer by layer

- **One CPU arch module: `system/kernel/arch/aarch64/`** — covering the Zero 2 W and Pi 3-5,
  providing the same `arch` interface as x86_64: `halt`, context switch,
  interrupt/exception vectors, page tables, a UART, a timer. No `system/kernel/arch/arm/` is
  planned (see the decision above), so there's a single ARM backend to write.
- **A device-tree boot path.** Since stock Pis boot via DTB, danos needs an entry
  that parses the DTB's `/memory` and `/reserved-memory` into the neutral
  [`MemoryMap`](memory-map.md) — the same neutral handoff `efi.zig` produces, just
  from a different source. This is where keeping boot-protocol knowledge on the
  loader side (as we did for the UEFI memory-map classification) pays off.
- **The UEFI loader mostly carries over.** `boot/efi.zig` is largely
  boot-*protocol* code (`std.os.uefi` protocol calls), not x86 code. Its only truly
  x86-specific bits are the ELF machine check (`.X86_64`) and the SysV calling
  convention for the kernel jump. So an `aarch64`-UEFI target (QEMU `virt` + AAVMF)
  can reuse it — which makes **aarch64-UEFI the easiest second target**, easier than
  the device-tree Pi.

## Pi hardware quirks (for when we port)

The Pi is not a "standard" ARM platform — expect Broadcom-specific peripherals:

- **Peripheral base moves per SoC**: `0x2000_0000` (BCM2835, Zero W),
  `0x3F00_0000` (BCM2837, Pi 3), `0xFE00_0000` (BCM2711, Pi 4), different again on
  Pi 5. Everything below is an offset from it.
- **UART**: a **PL011** (at base + `0x20_1000`) plus a mini-UART; on some boards the
  PL011 is wired to Bluetooth, so which one is the console varies. This is the
  `aarch64`/`arm` equivalent of our x86 [COM1 serial](testing.md).
- **Interrupt controller**: *not* a standard ARM GIC on the older parts — the Zero W
  and Pi 3 use Broadcom's own ARMCTRL controller (Pi 3 adds a per-core "local"
  controller for timers/mailboxes). The **Pi 4 and 5 do have a GIC-400**. So the
  interrupt backend differs even within the `aarch64` Pis.
- **Timer**: the ARM generic timer (`CNTPCT`/`CNTFRQ`) on ARMv8, or the BCM system
  timer — the counterpart to our calibrated LAPIC/TSC clock.

## Building each (intended)

`build.zig` currently pins the kernel to `x86_64`; supporting these means selecting
the target and `arch` module together (e.g. a `-Darch=` option). The Zig target
queries would be roughly:

- **Pi Zero W**: `.cpu_arch = .arm`, `.cpu_model = arm1176jzf_s`, `.os_tag = .freestanding`
- **Pi 3**: `.cpu_arch = .aarch64`, `.cpu_model = cortex_a53`, `.os_tag = .freestanding`
- **Pi 4**: `.cpu_arch = .aarch64`, `.cpu_model = cortex_a72`
- **Pi 5**: `.cpu_arch = .aarch64`, `.cpu_model = cortex_a76`

## Testing in QEMU

Two routes, mirroring how we test x86-64 with OVMF:

- **Board emulation**: `qemu-system-aarch64 -machine raspi3b` (and `raspi4b` on
  recent QEMU) for the Pi 3/4; `qemu-system-arm -machine raspi0`/`raspi1ap` for the
  ARMv6 Zero-class board — closest to real hardware, device-tree boot.
- **Generic aarch64-UEFI**: `qemu-system-aarch64 -machine virt` + AAVMF — the
  cleanest way to bring up the `aarch64` kernel via the reused UEFI loader before
  tackling Pi-specific boards. A future `run-aarch64` build step would use this.

## Related

- [arch.md](arch.md) — the arch-module boundary these targets plug into, and the
  CPU-arch vs boot-protocol "two axes".
- [efi.md](efi.md) — the UEFI loader that carries over to aarch64-UEFI.
- [vision.md](vision.md) — why isolated, portable-across-architectures is the goal.
