# DragonFly BSD AArch64 Cross-Build Blueprint

## 1. Strategic Assessment: Is Cross-Build the Right First Step?

**Yes, emphatically.** Your instinct is correct, and the reasoning is sound for several
reasons.

Every successful BSD architecture port has followed this sequence: cross-toolchain first,
then cross-build of userland, then kernel bring-up under emulation, and finally real
hardware. FreeBSD's arm64 port (2015–2016) followed exactly this path — the
cross-build infrastructure was solid before anyone booted a kernel on real AArch64
silicon. NetBSD's traditional approach via `build.sh` has always been
"cross-compile everything on any host." OpenBSD's approach was similar for their
arm64 port.

The advantages are practical:

- **Every developer can participate immediately.** Nobody needs AArch64 hardware.
  Any x86_64 DragonFly box becomes a development machine.
- **QEMU AArch64 virt machine** is a well-tested target. You can boot a kernel and
  run a full userland under emulation as soon as the cross-build produces working
  binaries.
- **Incremental progress.** You can cross-build individual programs and test them
  under `qemu-aarch64` (user-mode) before you even have a kernel.
- **CI/CD.** Once cross-build works, automated testing on every commit is
  straightforward.

---

## 2. Current Toolchain Status and Layout Analysis

### 2.1 DragonFly's Versioned Toolchain System

DragonFly has a distinctive approach to managing compilers and binutils. Unlike
FreeBSD (which switched to LLVM/Clang as its base compiler) or NetBSD (which uses
a `tools/` prefix approach in `build.sh`), DragonFly uses **versioned, parallel
toolchain instances** selected via environment variables at build time:

| Variable         | Purpose                          | Current Default |
|------------------|----------------------------------|-----------------|
| `CCVER`          | Selects GCC version for userland | `gcc80`         |
| `WORLD_CCVER`    | Selects GCC for buildworld       | `gcc80`         |
| `BINUTILSVER`    | Selects binutils version         | `binutils234`   |
| `LDVER`          | Selects linker variant           | `ld.bfd`        |
| `WORLD_LDVER`    | Selects linker for buildworld    | `ld.bfd`        |

After your GCC 12.5 upgrade, `WORLD_CCVER` will become `gcc125` (or whatever
naming convention you adopt), and the old `gcc80` directories remain until retired.

### 2.2 Source Tree Layout

The toolchain sources live under two primary trees:

```
/usr/src/
├── contrib/
│   ├── gcc-8.0/              # GCC 8.x source (upstream + DragonFly patches)
│   ├── gcc-12.5/             # GCC 12.5 source (your new import)
│   ├── binutils-2.34/        # Binutils 2.34 source
│   ├── gmp/                  # GMP library (GCC dependency)
│   ├── mpfr/                 # MPFR library (GCC dependency)
│   └── mpc/                  # MPC library (GCC dependency)
│
├── gnu/
│   ├── lib/
│   │   └── gcc80/            # Build infrastructure for GCC 8 runtime libs
│   │       ├── csu/          # C startup files (crt1.o, crti.o, crtn.o)
│   │       ├── libgcc/       # libgcc runtime
│   │       ├── libgcov/      # Coverage library
│   │       ├── libstdc++/    # C++ standard library
│   │       └── libsupc++/    # C++ support library
│   └── usr.bin/
│       ├── cc80/             # Build infrastructure for GCC 8 compiler
│       │   ├── Makefile.inc  # Shared configuration
│       │   ├── Makefile.langs # Language frontend selection
│       │   ├── Makefile.tgt  # TARGET-specific configuration
│       │   ├── cc_prep/      # Pre-generated config (auto-host.h, etc.)
│       │   ├── cc/           # C compiler (gcc)
│       │   ├── cc1/          # C frontend
│       │   ├── cc1plus/      # C++ frontend
│       │   ├── cpp/          # Preprocessor
│       │   └── backends/     # Various GCC backends
│       └── binutils234/
│           ├── as/           # GNU assembler
│           ├── ld/           # GNU linker (ld.bfd)
│           │   ├── Makefile.x86_64  # x86_64-specific linker config
│           │   └── ...
│           ├── ar/           # Archive tool
│           ├── nm/           # Symbol lister
│           ├── objdump/      # Object dump
│           ├── objcopy/      # Object copy/transform
│           ├── strip/        # Strip symbols
│           ├── ranlib/       # Archive index
│           ├── size/         # Section sizes
│           └── strings/      # String extraction
│
├── sys/
│   ├── cpu/
│   │   └── x86_64/          # CPU-specific kernel code (only x86_64 exists)
│   └── platform/
│       └── pc64/             # Platform-specific kernel code
│
└── share/mk/
    ├── bsd.cpu.mk            # CPU feature detection and flags
    └── bsd.sys.mk            # Compiler invocation logic
```

### 2.3 Installation Layout (on a running system)

The versioned toolchain installs into prefixed paths:

```
/usr/libexec/
├── gcc80/                # GCC 8.x compiler binaries
│   ├── cc1               # C compiler proper
│   ├── cc1plus           # C++ compiler proper
│   └── collect2          # Linker wrapper
└── binutils234/
    └── elf/
        ├── as            # Assembler
        ├── ld            # Linker (ld.bfd)
        ├── ld.gold       # Gold linker
        ├── ar            # Archiver
        ├── nm            # Symbol tool
        ├── objdump       # Object dump
        ├── objcopy       # Object copy
        ├── strip         # Strip
        └── ranlib        # Archive index

/usr/lib/gcc80/            # GCC 8 runtime libraries
    ├── libgcc.a
    ├── libgcc_s.so
    ├── libstdc++.so
    └── ...

/usr/bin/
    ├── gcc               # Wrapper/symlink → selected CCVER
    ├── g++
    ├── cpp
    ├── as                # Wrapper → selected BINUTILSVER
    ├── ld                # Wrapper → selected LDVER
    └── ...
```

### 2.4 The buildworld Pipeline

DragonFly's `Makefile.inc1` defines a 3-stage build:

1. **BTOOLS (bootstrap-tools)** — Built natively with the host compiler. These are
   basic utilities (mkdir, rm, yacc, lex, etc.) needed to build everything else.

2. **CTOOLS (cross-tools)** — Built natively but configured for the *target*
   architecture. This is where the cross-compiler and cross-binutils are built.
   The critical variables passed through:

   ```makefile
   CROSSENV= MAKEOBJDIRPREFIX=${WORLDDEST} \
             MACHINE_ARCH=${TARGET_ARCH} \
             MACHINE=${TARGET} \
             MACHINE_PLATFORM=${TARGET_PLATFORM} \
             HOST_CCVER=${HOST_CCVER} \
             CCVER=${WORLD_CCVER} \
             LDVER=${WORLD_LDVER} \
             BINUTILSVER=${WORLD_BINUTILSVER}
   ```

3. **WORLD** — Cross-built using only BTOOLS and CTOOLS. Everything in the world
   stage is compiled for `TARGET_ARCH` using the cross-compiler from stage 2.

The key constraint that currently blocks AArch64: the `TARGET_PLATFORM` mapping
in `Makefile.inc1` only knows about `x86_64` → `pc64`:

```makefile
.if ${TARGET_ARCH} == "x86_64"
TARGET_PLATFORM= pc64
.else
.error Unknown target architecture.
.endif
```

### 2.5 What Needs to Change

The current toolchain is hard-wired for x86_64 in several dimensions:

| Component             | Current State              | AArch64 Gap                  |
|-----------------------|----------------------------|------------------------------|
| GCC backend           | x86_64 target only         | Needs aarch64 backend built  |
| Binutils              | x86_64 target only         | Needs aarch64 target support |
| `Makefile.inc1`       | Only maps x86_64→pc64      | Needs aarch64→virt64 mapping |
| `gnu/usr.bin/cc*/`    | Makefile.tgt: x86_64 only  | Needs aarch64 .tgt files     |
| `gnu/usr.bin/binutils*/` | ld scripts: x86_64 only | Needs aarch64 emulations     |
| `cc_prep/auto-host.h` | Generated for x86_64 host | Needs cross-compile variant  |
| `share/mk/bsd.cpu.mk` | x86_64 CPUTYPE only       | Needs aarch64 CPUTYPE defs   |
| `sys/cpu/`, `sys/platform/` | Only x86_64          | Needs aarch64 + virt64 stubs |
| C startup files (csu) | x86_64 assembly            | Needs aarch64 crt*.S         |
| `lib/libc/`           | x86_64 MD sections         | Needs aarch64 MD code        |

---

## 3. Proposed Architecture

### 3.1 Design Principles

1. **Follow the existing versioned pattern.** Don't invent a new scheme. The
   cross-tools should appear as a natural extension of CCVER/BINUTILSVER.

2. **Cross-tools are native binaries.** The cross-compiler runs on x86_64 but
   produces aarch64 code. It installs alongside the native toolchain under a
   target-qualified path.

3. **The GNU triplet for DragonFly AArch64** will be:
   `aarch64-dragonfly-elf` (or `aarch64-unknown-dragonfly` following the
   convention established by the upstream GCC DragonFly target patches from
   John Marino's work).

4. **Reuse the CTOOLS stage.** The buildworld infrastructure already has a
   cross-tools concept. When `TARGET_ARCH=aarch64`, the CTOOLS stage should
   build an `aarch64-dragonfly` cross-compiler instead of the native one.

5. **Binutils upgrade is mandatory.** Binutils 2.34 has full AArch64 support,
   so the current version is sufficient in terms of upstream capabilities. But
   the in-tree build Makefiles only configure the x86_64 target. You need to
   either: (a) add aarch64 emulations to the existing binutils234 build, or
   (b) import a newer binutils (2.41+ recommended) that better handles newer
   AArch64 extensions (BTI, MTE, etc.). Option (b) is recommended since you're
   already upgrading GCC.

### 3.2 Target File Hierarchy

```
# Cross-toolchain installation layout (on x86_64 host):

/usr/cross/aarch64-dragonfly/
├── bin/
│   ├── as                     # aarch64 assembler
│   ├── ld                     # aarch64 linker
│   ├── ar, nm, objdump, ...   # aarch64 binutils
│   ├── gcc                    # aarch64 cross-compiler
│   └── g++                    # aarch64 cross C++ compiler
├── lib/
│   ├── ldscripts/             # aarch64 linker scripts
│   ├── libgcc.a               # cross-compiled libgcc
│   ├── libgcc_s.so            # cross-compiled libgcc_s
│   └── ...                    # other target-arch runtime libs
├── include/                   # target system headers (populated by buildworld)
└── libexec/
    ├── cc1                    # aarch64 C compiler backend
    └── cc1plus                # aarch64 C++ compiler backend
```

During a `buildworld TARGET_ARCH=aarch64`, the CTOOLS stage builds this tree
into `${CTOOLSDEST}`, and the WORLD stage uses it.

### 3.3 Platform/CPU Mapping

Add a new platform `virt64` for AArch64 (named after QEMU's "virt" machine,
which is the standard AArch64 development platform — later, a physical platform
like `rpi64` or `sbsa64` can be added):

```
TARGET_ARCH=aarch64 → TARGET_PLATFORM=virt64
                      MACHINE=arm64
                      MACHINE_ARCH=aarch64
```

---

## 4. Detailed Implementation Plan

### Phase 1: Binutils for AArch64 (Estimated: 1–2 weeks)

**Goal:** Build `aarch64-dragonfly-elf` binutils (as, ld, ar, nm, etc.) on the
x86_64 host.

#### Step 1.1: Import or Upgrade Binutils

Option A (minimal): Patch the existing `binutils234` build infrastructure.
Option B (recommended): Import binutils 2.42 as `contrib/binutils-2.42/` and
create `gnu/usr.bin/binutils242/`.

For option B:

```
# Fetch and extract
fetch https://ftp.gnu.org/gnu/binutils/binutils-2.42.tar.xz
tar xf binutils-2.42.tar.xz
# Copy into contrib/
cp -r binutils-2.42 /usr/src/contrib/binutils-2.42
```

#### Step 1.2: Create Cross-Binutils Build Makefiles

Create `gnu/usr.bin/binutils242/` with subdirectories mirroring the existing
`binutils234/` structure, but parameterized by `TARGET_ARCH`:

**`gnu/usr.bin/binutils242/Makefile.inc`** (key fragment):

```makefile
BINUTILSDIR=    ${.CURDIR}/../../../../contrib/binutils-2.42

.if ${TARGET_ARCH} == "aarch64"
BINUTILS_TARGET=    aarch64-dragonfly-elf
.elif ${TARGET_ARCH} == "x86_64"
BINUTILS_TARGET=    x86_64-dragonfly-elf
.endif
```

**`gnu/usr.bin/binutils242/as/Makefile`** — add aarch64 object files:

```makefile
.if ${TARGET_ARCH} == "aarch64"
TARGET_CPU=     aarch64
SRCS+=  tc-aarch64.c
.elif ${TARGET_ARCH} == "x86_64"
TARGET_CPU=     x86_64
SRCS+=  tc-i386.c
.endif
```

**`gnu/usr.bin/binutils242/ld/Makefile.aarch64`** — new file:

```makefile
# AArch64 emulation for ld.bfd
NATIVE_EMULATION=   aarch64elf_dragonfly
# Default emulations to compile in
EMULATIONS=         elf_aarch64 aarch64elf_dragonfly
```

You will also need to create or patch the linker emulation parameters file:
`contrib/binutils-2.42/ld/emulparams/aarch64elf_dragonfly.sh` — modeled on
FreeBSD's `aarch64elf_fbsd.sh`:

```sh
. ${srcdir}/emulparams/aarch64elf.sh
OUTPUT_FORMAT="elf64-littleaarch64"
TEXT_START_ADDR=0x200000
TARGET_PAGE_SIZE=0x1000
MAXPAGESIZE="CONSTANT (MAXPAGESIZE)"
# DragonFly dynamic linker
DYNAMIC_LINK="/usr/libexec/ld-elf.so.2"
```

#### Step 1.3: BFD Target Registration

Add `aarch64-*-dragonfly*` entries to:
- `contrib/binutils-2.42/bfd/config.bfd`
- `contrib/binutils-2.42/gas/configure.tgt`
- `contrib/binutils-2.42/ld/configure.tgt`

These are small patches modeling the existing `*-*-freebsd*` entries for
aarch64, changing them to match `*-*-dragonfly*`.

#### Step 1.4: Test

Build the cross-binutils manually first:

```sh
cd /usr/src
make -C gnu/usr.bin/binutils242 TARGET_ARCH=aarch64 obj
make -C gnu/usr.bin/binutils242 TARGET_ARCH=aarch64 depend
make -C gnu/usr.bin/binutils242 TARGET_ARCH=aarch64 all
```

Verify with:

```sh
echo '.text; .globl _start; _start: mov x0, #42; ret' > /tmp/test.s
/path/to/cross-as -o /tmp/test.o /tmp/test.s
/path/to/cross-objdump -d /tmp/test.o    # Should show aarch64 instructions
```

---

### Phase 2: GCC Cross-Compiler for AArch64 (Estimated: 2–3 weeks)

**Goal:** Build a GCC 12.5 cross-compiler that runs on x86_64 and produces
aarch64-dragonfly code.

#### Step 2.1: Upstream GCC AArch64 + DragonFly Target Support

GCC already has an AArch64 backend. The DragonFly target was upstreamed
(for x86) circa GCC 4.9 by John Marino. You need to extend it:

Create/patch `contrib/gcc-12.5/gcc/config/aarch64/dragonfly.h`:

```c
/* DragonFly/AArch64 target definitions */
#undef  TARGET_OS_CPP_BUILTINS
#define TARGET_OS_CPP_BUILTINS()        \
  do {                                  \
    builtin_define("__DragonFly__");    \
    builtin_define("__FreeBSD_kernel__"); /* for compat if needed */ \
    builtin_define("__ELF__");          \
    DRAGONFLY_TARGET_OS_CPP_BUILTINS(); \
  } while (0)

#undef  DYNAMIC_LINKER
#define DYNAMIC_LINKER       "/usr/libexec/ld-elf.so.2"

#undef  STARTFILE_SPEC
#define STARTFILE_SPEC       DRAGONFLY_STARTFILE_SPEC

#undef  ENDFILE_SPEC
#define ENDFILE_SPEC         DRAGONFLY_ENDFILE_SPEC

#undef  LIB_SPEC
#define LIB_SPEC             DRAGONFLY_LIB_SPEC

#undef  TARGET_DEFAULT_POINTER_AUTH
#define TARGET_DEFAULT_POINTER_AUTH 0
```

Register the target in GCC's configuration:

**`contrib/gcc-12.5/gcc/config.gcc`** — add:

```
aarch64*-*-dragonfly*)
    tm_file="${tm_file} elfos.h dragonfly.h dragonfly-stdint.h"
    tm_file="${tm_file} aarch64/aarch64-elf.h aarch64/dragonfly.h"
    tmake_file="${tmake_file} aarch64/t-aarch64"
    extra_options="${extra_options} aarch64/aarch64.opt"
    use_gcc_stdint=provide
    ;;
```

#### Step 2.2: Cross-Compiler Build Makefiles

Create `gnu/usr.bin/cc125/Makefile.tgt.aarch64`:

```makefile
TARGET_ARCH=    aarch64
GCC_TARGET=     aarch64-dragonfly-elf
GCC_CPU=        aarch64

# AArch64-specific source files for the backend
SRCS_TARGET=    aarch64.c aarch64-builtins.c aarch64-sve-builtins.c \
                aarch64-speculation.c cortex-a57-fma-steering.c \
                falkor-tag-collision-avoidance.c

# Disabling features not yet available on DragonFly/AArch64
GCC_FLAGS_TARGET= -DTARGET_DEFAULT_POINTER_AUTH=0
```

Modify `gnu/usr.bin/cc125/Makefile.inc` to select the target file:

```makefile
.if ${TARGET_ARCH} == "aarch64"
.  include "Makefile.tgt.aarch64"
.elif ${TARGET_ARCH} == "x86_64"
.  include "Makefile.tgt"      # existing x86_64 target
.endif
```

#### Step 2.3: Pre-generated Configuration Headers

GCC's build normally runs `./configure` to produce `auto-host.h` and related
files. DragonFly's in-tree build avoids autoconf by shipping pre-generated
headers in `cc_prep/`.

For the cross-compiler, `auto-host.h` describes the **host** (x86_64 DragonFly),
which is the same as the native build. The target-specific configuration comes
from `config.h` and the `tm_file` chain. You can reuse the existing `auto-host.h`
for the cross-compiler — the host hasn't changed, only the target.

However, you need a new `cc_prep/config/dragonfly-cross-aarch64.h` for any
target-specific overrides (page size, alignment, etc.):

```c
/* DragonFly AArch64 cross-build target config */
#define DEFAULT_SIGNED_CHAR  0   /* AArch64 uses unsigned char */
#define TARGET_PAGE_SIZE     4096
```

#### Step 2.4: Bootstrap libgcc for AArch64

The cross-compiler needs a minimal libgcc for the target architecture.
Create `gnu/lib/gcc125/libgcc/Makefile.aarch64`:

```makefile
.if ${TARGET_ARCH} == "aarch64"
LIB_SRCS=  libgcc2.c unwind-dw2.c unwind-dw2-fde-dip.c \
            unwind-c.c emutls.c
# AArch64-specific
LIB_SRCS+= aarch64/lse.S aarch64/lib1funcs.S
CFLAGS+=    -mlittle-endian -march=armv8-a
.endif
```

This will be cross-compiled during the CTOOLS stage using the freshly-built
cross-compiler (GCC bootstrap: build `cc1`, then use it to compile `libgcc`).

#### Step 2.5: Test

```sh
cat > /tmp/hello.c << 'EOF'
int main(void) { return 42; }
EOF

/path/to/cross-gcc -c -o /tmp/hello.o /tmp/hello.c
/path/to/cross-objdump -d /tmp/hello.o
# Verify: should show aarch64 instructions (mov, ret, etc.)
file /tmp/hello.o
# Expected: ELF 64-bit LSB relocatable, ARM aarch64, version 1 (SYSV)
```

---

### Phase 3: Build System Integration (Estimated: 2–3 weeks)

**Goal:** `make buildworld TARGET_ARCH=aarch64` works from an x86_64 host.

#### Step 3.1: Makefile.inc1 Modifications

Extend the target platform mapping:

```makefile
.if ${TARGET_ARCH} == "x86_64"
TARGET_PLATFORM= pc64
.elif ${TARGET_ARCH} == "aarch64"
TARGET_PLATFORM= virt64
.else
.error Unknown target architecture.
.endif
```

Add cross-compilation awareness to the CTOOLS stage. When
`TARGET_ARCH != MACHINE_ARCH`, the CTOOLS stage must build a cross-compiler
rather than a native one:

```makefile
.if ${TARGET_ARCH} != ${MACHINE_ARCH}
CTOOLS_CROSS=   yes
CROSS_GCC_TARGET=   ${TARGET_ARCH}-dragonfly-elf
.endif
```

Modify the `cross-tools` target to conditionally build cross-binutils and
cross-GCC when `CTOOLS_CROSS` is set.

#### Step 3.2: share/mk Changes

**`share/mk/bsd.cpu.mk`** — add AArch64 CPU type definitions:

```makefile
.if ${MACHINE_ARCH} == "aarch64"
MACHINE_CPU=    aarch64
CFLAGS+=        -mlittle-endian
.  if ${CPUTYPE} == "cortex-a72"
CFLAGS+=        -mcpu=cortex-a72
.  elif ${CPUTYPE} == "cortex-a76"
CFLAGS+=        -mcpu=cortex-a76
.  elif ${CPUTYPE} == "neoverse-n1"
CFLAGS+=        -mcpu=neoverse-n1
.  else
CFLAGS+=        -march=armv8-a
.  endif
.endif
```

**`share/mk/bsd.sys.mk`** — ensure cross-compiler is invoked when
`MACHINE_ARCH` differs from the host:

```makefile
.if defined(CTOOLS_CROSS)
CC=     ${CTOOLSDEST}/usr/bin/${TARGET_ARCH}-dragonfly-elf-gcc
CXX=    ${CTOOLSDEST}/usr/bin/${TARGET_ARCH}-dragonfly-elf-g++
CPP=    ${CTOOLSDEST}/usr/bin/${TARGET_ARCH}-dragonfly-elf-cpp
AS=     ${CTOOLSDEST}/usr/bin/${TARGET_ARCH}-dragonfly-elf-as
LD=     ${CTOOLSDEST}/usr/bin/${TARGET_ARCH}-dragonfly-elf-ld
AR=     ${CTOOLSDEST}/usr/bin/${TARGET_ARCH}-dragonfly-elf-ar
RANLIB= ${CTOOLSDEST}/usr/bin/${TARGET_ARCH}-dragonfly-elf-ranlib
STRIP=  ${CTOOLSDEST}/usr/bin/${TARGET_ARCH}-dragonfly-elf-strip
.endif
```

#### Step 3.3: C Startup Files (csu)

Create `lib/csu/aarch64/`:

```
lib/csu/aarch64/
├── Makefile
├── crt1.S          # Process entry point (_start)
├── crti.S          # .init prologue
├── crtn.S          # .init epilogue
└── crtbeginS.c     # (or use GCC's)
```

`crt1.S` for AArch64 (minimal skeleton):

```asm
        .text
        .align  2
        .globl  _start
        .type   _start, @function
_start:
        mov     x29, #0         /* Clear frame pointer */
        mov     x30, #0         /* Clear link register */
        mov     x0, sp          /* Argument: stack pointer */
        and     sp, x0, #-16    /* Align stack to 16 bytes */

        ldr     x0, [sp]        /* argc */
        add     x1, sp, #8      /* argv */
        /* envp = argv + (argc + 1) * 8 */
        add     x2, x0, #1
        lsl     x2, x2, #3
        add     x2, x1, x2

        bl      __start         /* Call runtime startup */
        /* NOTREACHED */
        brk     #0
```

#### Step 3.4: libc Machine-Dependent Code

Create `lib/libc/aarch64/` with stubs for:

```
lib/libc/aarch64/
├── SYS.h              # Syscall macros for AArch64
├── gen/               # setjmp/longjmp, sigsetjmp, etc.
│   ├── _setjmp.S
│   ├── setjmp.S
│   ├── sigsetjmp.S
│   ├── fabs.S
│   └── modf.S
├── string/            # Optimized string functions
│   ├── memcpy.S
│   ├── memset.S
│   ├── strlen.S
│   └── ...
├── sys/               # Syscall stubs
│   ├── syscall.S
│   ├── cerror.S
│   └── brk.S
└── Makefile.inc
```

Initially these can be simple C fallbacks rather than optimized assembly —
the goal is to get things linking and running; optimization comes later.

#### Step 3.5: Kernel Header Stubs

For the cross-build to succeed, you need minimal `sys/cpu/aarch64/` and
`sys/platform/virt64/` directories. During the buildworld, the kernel headers
are used by userland. Initially, you can create stubs that define the
essential machine-dependent types:

```
sys/cpu/aarch64/
├── include/
│   ├── param.h         # PAGE_SIZE, etc.
│   ├── types.h         # register_t, __int64_t, etc.
│   ├── endian.h        # Little-endian
│   ├── stdarg.h        # (use GCC builtins)
│   ├── signal.h        # mcontext_t
│   ├── pmap.h          # Stub for now
│   ├── atomic.h        # AArch64 atomics (LSE or LL/SC)
│   └── cpufunc.h       # Inline asm for barriers, cache ops
└── ...

sys/platform/virt64/
├── include/
│   └── ... (platform-level definitions)
└── ...
```

---

### Phase 4: Verification and Testing (Estimated: 1–2 weeks)

#### Step 4.1: Static Binary Test

Cross-build a statically-linked hello-world and run it under QEMU user-mode:

```sh
# On DragonFly x86_64 host:
make buildworld TARGET_ARCH=aarch64

# Or manually:
aarch64-dragonfly-elf-gcc -static -o hello hello.c

# Test with QEMU user-mode (install from dports):
qemu-aarch64 -L /path/to/aarch64/sysroot ./hello
```

#### Step 4.2: Full Userland Cross-Build

```sh
cd /usr/src
make buildworld TARGET_ARCH=aarch64 TARGET_PLATFORM=virt64
make DESTDIR=/usr/cross-root/aarch64 installworld TARGET_ARCH=aarch64
```

This produces a complete AArch64 filesystem tree in `/usr/cross-root/aarch64/`.

#### Step 4.3: QEMU System Emulation Boot Test

Once a minimal kernel is available:

```sh
qemu-system-aarch64 \
    -M virt \
    -cpu cortex-a72 \
    -m 1G \
    -nographic \
    -kernel /path/to/aarch64-dragonfly-kernel \
    -drive file=aarch64-root.img,format=raw \
    -append "console=ttyAMA0 root=/dev/vda"
```

---

## 5. Key Technical Decisions

### 5.1: Binutils Version

**Recommendation: Import binutils 2.42 as `binutils242`.**

Rationale: Binutils 2.34 technically supports AArch64, but 2.42 adds important
features (MTE support, BTI/PAC branch protection, better RELR relocation
support) that you will want for a modern AArch64 target. Since you're already
doing a major GCC upgrade, doing a binutils upgrade in parallel is the natural
time to do it. You can keep `binutils234` as a fallback for x86_64 during the
transition, just as DragonFly kept `binutils221` alongside `binutils222`.

### 5.2: ELF OS/ABI Byte

DragonFly uses `ELFOSABI_NONE` (0) in its ELF headers, same as FreeBSD. The
AArch64 binutils must produce ELF files with the correct OS/ABI marking. This
is configured in the BFD target — the `aarch64elf_dragonfly` emulation should
set `ELFOSABI_NONE`.

### 5.3: Thread-Local Storage Model

AArch64 uses the standard ELF TLS model with `TPIDR_EL0` as the thread pointer
register. GCC's AArch64 backend already handles this. The DragonFly libc and
rtld will eventually need AArch64 TLS support, but for the cross-build phase
this is transparent — GCC generates the correct relocations, and the linker
handles them.

### 5.4: Floating Point ABI

AArch64 has a single floating-point ABI (hardware FP is mandatory in the base
architecture). No soft-float/hard-float decision is needed, unlike ARM32.
GCC defaults to the correct ABI for `aarch64-*-*` targets.

### 5.5: Naming Convention

Follow the existing pattern. If GCC 12.5's CCVER is `gcc125`:

```
CCVER=gcc125          (native x86_64 compiler)
BINUTILSVER=binutils242

# For cross-build, the same CCVER/BINUTILSVER are used, but
# the CTOOLS stage builds them as cross-tools when TARGET_ARCH != MACHINE_ARCH
```

The cross-compiler binaries should be prefixed: `aarch64-dragonfly-elf-gcc`,
`aarch64-dragonfly-elf-as`, etc. This follows the universal GNU convention
and avoids name collisions with the native tools.

---

## 6. Dependency Graph and Order of Operations

```
                    ┌─────────────────────┐
                    │ Import binutils 2.42 │
                    │ into contrib/        │
                    └──────────┬──────────┘
                               │
                    ┌──────────▼──────────┐
                    │ Add DragonFly target │
                    │ to BFD/gas/ld config │
                    └──────────┬──────────┘
                               │
              ┌────────────────┼────────────────┐
              │                │                │
   ┌──────────▼─────┐  ┌──────▼──────┐  ┌──────▼──────┐
   │ Build cross-as  │  │ Build cross │  │ Build cross │
   │ (gas for aarch64)│ │ cross-ld    │  │ ar/nm/etc.  │
   └──────────┬─────┘  └──────┬──────┘  └──────┬──────┘
              └────────────────┼────────────────┘
                               │
                    ┌──────────▼──────────┐
                    │ Add aarch64 target  │
                    │ to GCC 12.5 config  │
                    └──────────┬──────────┘
                               │
                    ┌──────────▼──────────┐
                    │ Build cross-gcc     │
                    │ (cc1 for aarch64)   │
                    └──────────┬──────────┘
                               │
                    ┌──────────▼──────────┐
                    │ Cross-build libgcc  │
                    │ (using cross-gcc)   │
                    └──────────┬──────────┘
                               │
              ┌────────────────┼────────────────┐
              │                │                │
   ┌──────────▼─────┐  ┌──────▼──────┐  ┌──────▼──────┐
   │ aarch64 kernel  │  │ aarch64 csu │  │ aarch64 libc│
   │ headers (stubs) │  │ (crt1, etc) │  │ MD code     │
   └──────────┬─────┘  └──────┬──────┘  └──────┬──────┘
              └────────────────┼────────────────┘
                               │
                    ┌──────────▼──────────┐
                    │  Makefile.inc1 +    │
                    │  share/mk changes   │
                    └──────────┬──────────┘
                               │
                    ┌──────────▼──────────┐
                    │  make buildworld    │
                    │  TARGET_ARCH=aarch64│
                    └──────────┬──────────┘
                               │
                    ┌──────────▼──────────┐
                    │  QEMU user-mode     │
                    │  testing            │
                    └─────────────────────┘
```

---

## 7. Risks and Mitigations

| Risk | Impact | Mitigation |
|------|--------|------------|
| GCC 12 lacks upstream DragonFly/AArch64 target | High — must create target files | Model on FreeBSD/AArch64 target; DragonFly's x86_64 target is already upstream and serves as a template for OS-specific definitions |
| Binutils linker emulation missing | High — linker won't produce correct binaries | Copy FreeBSD's `aarch64elf_fbsd.sh` and adapt; the differences are small (dynamic linker path, OS/ABI byte) |
| libc MD assembly is substantial work | Medium — blocks full userland build | Start with C fallback implementations for everything; libc will build but be slow. Optimize later. |
| Kernel headers need machine-dependent types | Medium — blocks libc compilation | Create minimal stubs with correct type sizes/alignments matching AArch64 ABI. This is a small, well-defined task. |
| DPorts (third-party packages) won't build | Low for this phase — not the goal | DPorts cross-build is a future phase. The base system cross-build is the deliverable. |

---

## 8. Recommended Commit Sequence

1. **`contrib/binutils-2.42`** — import upstream source
2. **`contrib/binutils-2.42` patches** — add DragonFly/AArch64 target to BFD, gas, ld
3. **`gnu/usr.bin/binutils242/`** — build infrastructure, with aarch64 support
4. **`contrib/gcc-12.5` patches** — add `aarch64-*-dragonfly*` target
5. **`gnu/usr.bin/cc125/`** — extend build infra for aarch64 backend
6. **`gnu/lib/gcc125/`** — cross-build of libgcc for aarch64
7. **`sys/cpu/aarch64/include/`** — kernel header stubs
8. **`sys/platform/virt64/include/`** — platform header stubs
9. **`lib/csu/aarch64/`** — C startup files
10. **`lib/libc/aarch64/`** — machine-dependent libc code
11. **`share/mk/`** — bsd.cpu.mk and bsd.sys.mk updates
12. **`Makefile.inc1`** — TARGET_ARCH=aarch64 support
13. **Test and iterate** — fix build failures until `buildworld` completes

Each commit should be self-contained and independently reviewable. The first
six commits (toolchain) can be developed and tested independently of the
last six (userland support), since you can test the cross-compiler by
compiling standalone C files.

---

## 9. References and Prior Art

- **FreeBSD arm64 port** (2015–2016): The closest model. FreeBSD used LLVM/Clang
  (which is inherently a cross-compiler), but the build system integration
  patterns — `TARGET_ARCH=aarch64`, sysroot layout, csu code — are directly
  applicable.

- **NetBSD evbarm port**: NetBSD's `build.sh -m evbarm -a aarch64` has always
  supported full cross-builds and is a good reference for the libc MD code and
  kernel header organization.

- **GCC DragonFly target patches**: John Marino's original patches from 2014
  (upstreamed in GCC 4.9) established the `*-*-dragonfly*` target. The AArch64
  extension follows the same patterns in `gcc/config.gcc` and the target header
  files.

- **Binutils DragonFly support**: Already present upstream since the DragonFly
  target was added alongside the GCC patches. The AArch64 extension adds new
  emulation files but follows the same pattern.
