feat: add support for aarch64 timer/interrupts, port MontaukOS userspace

This commit is contained in:
daniel committed 2026-10-25 08:27:09 +01:00
1 parent 8b6379fb7e
commit 8c09ccef66
101 files changed
+1720 -629

No files matched your search

+92 -40
View File
@@ -1,9 +1,10 @@
#!/usr/bin/env bash
#
# build-montauk-toolchain.sh — Build an x86_64-montauk cross compiler
# build-montauk-toolchain.sh — Build an <arch>-montauk cross compiler
# (Binutils + GCC) for MontaukOS userspace programs.
#
# Usage: ./toolchain/build-montauk-toolchain.sh
# Usage: ./toolchain/build-montauk-toolchain.sh [x86_64|aarch64]
# (or ARCH=aarch64 ./toolchain/build-montauk-toolchain.sh)
#
# Unlike the bare-metal x86_64-elf toolchain (build-toolchain.sh), this
# target knows the Montauk userspace ABI: it links static ET_EXEC
@@ -13,9 +14,11 @@
#
# The toolchain is installed to toolchain/local/ and provides:
# x86_64-montauk-gcc, x86_64-montauk-g++, x86_64-montauk-ld, etc.
# (aarch64-montauk-* for ARCH=aarch64; both can live side by side).
#
# The target sysroot (libc headers + libs) is assembled into
# toolchain/sysroot/ from programs/include/libc and programs/lib/libc.
# toolchain/sysroot/ (x86_64) or toolchain/sysroot-<arch>/ from
# programs/include/libc and programs/lib/libc.
# Re-run this script after changing libc headers or rebuilding libc to
# refresh the sysroot (the sysroot step always runs; compiler builds
# are skipped once installed).
@@ -27,7 +30,12 @@ set -euo pipefail
# ── Versions (kept in lockstep with build-toolchain.sh) ───────────────────────
BINUTILS_VERSION="2.43.1"
GCC_VERSION="14.2.0"
TARGET="x86_64-montauk"
ARCH="${1:-${ARCH:-x86_64}}"
case "${ARCH}" in
x86_64|aarch64) ;;
*) echo "Unsupported architecture: ${ARCH}" >&2; exit 1 ;;
esac
TARGET="${ARCH}-montauk"
# ── Directories ───────────────────────────────────────────────────────────────
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
@@ -35,7 +43,13 @@ REPO_DIR="$(dirname "${SCRIPT_DIR}")"
PREFIX="${SCRIPT_DIR}/local"
SRC_DIR="${SCRIPT_DIR}/src"
BUILD_DIR="${SCRIPT_DIR}/build"
SYSROOT="${SCRIPT_DIR}/sysroot"
if [[ "${ARCH}" == x86_64 ]]; then
SYSROOT="${SCRIPT_DIR}/sysroot"
BUILD_SUFFIX=""
else
SYSROOT="${SCRIPT_DIR}/sysroot-${ARCH}"
BUILD_SUFFIX="-${ARCH}"
fi
PATCH_DIR="${SCRIPT_DIR}/patches"
FILES_DIR="${SCRIPT_DIR}/files"
@@ -104,54 +118,87 @@ apply_patch() {
fi
}
# The AArch64 target is a second patch on top of the first.
apply_arch_patch() {
local dir="$1" patch="$2" marker="$3"
if grep -q "aarch64-\*-montauk" "${dir}/${marker}"; then
bold "Already patched for aarch64: $(basename "${dir}")"
else
bold "Patching $(basename "${dir}") for aarch64..."
patch -d "${dir}" -p1 < "${patch}"
fi
}
apply_patch "${SRC_DIR}/binutils-${BINUTILS_VERSION}" "${PATCH_DIR}/binutils-${BINUTILS_VERSION}-montauk.patch"
apply_patch "${SRC_DIR}/gcc-${GCC_VERSION}" "${PATCH_DIR}/gcc-${GCC_VERSION}-montauk.patch"
apply_arch_patch "${SRC_DIR}/binutils-${BINUTILS_VERSION}" \
"${PATCH_DIR}/binutils-${BINUTILS_VERSION}-montauk-aarch64.patch" bfd/config.bfd
apply_arch_patch "${SRC_DIR}/gcc-${GCC_VERSION}" \
"${PATCH_DIR}/gcc-${GCC_VERSION}-montauk-aarch64.patch" gcc/config.gcc
cp "${FILES_DIR}/montauk.h" "${SRC_DIR}/gcc-${GCC_VERSION}/gcc/config/montauk.h"
cp "${FILES_DIR}/aarch64-montauk.h" "${SRC_DIR}/gcc-${GCC_VERSION}/gcc/config/aarch64/montauk.h"
# ── Assemble the target sysroot ───────────────────────────────────────────────
# usr/include — the Montauk libc headers (self-contained C; stddef/stdint/
# stdarg come from GCC itself) plus the montauk/ SDK headers.
# usr/lib — crt startup objects and the libc static library.
bold "Assembling sysroot from programs/lib/libc..."
make -C "${REPO_DIR}/programs" libc >/dev/null
rm -rf "${SYSROOT}"
mkdir -p "${SYSROOT}/usr/include" "${SYSROOT}/usr/lib"
cp -r "${REPO_DIR}/programs/include/libc/." "${SYSROOT}/usr/include/"
cp -r "${REPO_DIR}/programs/include/montauk" "${SYSROOT}/usr/include/montauk"
cp -r "${REPO_DIR}/programs/include/Api" "${SYSROOT}/usr/include/Api"
# Freestanding C++ headers (<cstdint>, <type_traits>, <atomic>, ...) —
# the subset the kernel and the in-tree programs build against. This is
# NOT the whole C++ story: a hosted libstdc++ is built further down and
# installs its own headers under ${PREFIX}/x86_64-montauk/include/c++.
# That directory comes first on the include path and this one comes
# last, so a plain g++ invocation gets the hosted headers and these are
# shadowed. See "C++ standard library" in README.md.
cp -r "${REPO_DIR}/kernel/freestnd-cxx-hdrs/x86_64/include/." "${SYSROOT}/usr/include/"
cp "${REPO_DIR}/programs/lib/libc/crt1.o" \
"${REPO_DIR}/programs/lib/libc/crti.o" \
"${REPO_DIR}/programs/lib/libc/crtn.o" "${SYSROOT}/usr/lib/"
cp "${REPO_DIR}/programs/lib/libc/liblibc.a" "${SYSROOT}/usr/lib/libc.a"
# libm is an empty stand-in (math lives inside libc.a; the g++ driver
# links -lm unconditionally). libstdc++ is copied from the toolchain
# once built - the empty stand-in only bridges the first bootstrap.
ar rcs "${SYSROOT}/usr/lib/libm.a"
if [[ -f "${PREFIX}/x86_64-montauk/lib/libstdc++.a" ]]; then
cp "${PREFIX}/x86_64-montauk/lib/libstdc++.a" "${SYSROOT}/usr/lib/libstdc++.a"
else
ar rcs "${SYSROOT}/usr/lib/libstdc++.a"
LIBC_DIR="${REPO_DIR}/programs/lib/libc"
if [[ "${ARCH}" != x86_64 ]]; then
LIBC_DIR="${LIBC_DIR}/build-${ARCH}"
fi
green "Sysroot ready."
# On a first build for a new architecture the libc cannot be compiled yet
# (it needs this compiler): the sysroot then holds only headers, which is
# all building GCC needs, and is completed once GCC exists.
assemble_sysroot() {
bold "Assembling sysroot from programs/lib/libc..."
local have_libc=1
make -C "${REPO_DIR}/programs" libc ARCH="${ARCH}" >/dev/null 2>&1 || have_libc=0
[[ -f "${LIBC_DIR}/liblibc.a" && -f "${LIBC_DIR}/crt1.o" ]] || have_libc=0
rm -rf "${SYSROOT}"
mkdir -p "${SYSROOT}/usr/include" "${SYSROOT}/usr/lib"
cp -r "${REPO_DIR}/programs/include/libc/." "${SYSROOT}/usr/include/"
cp -r "${REPO_DIR}/programs/include/montauk" "${SYSROOT}/usr/include/montauk"
cp -r "${REPO_DIR}/programs/include/Api" "${SYSROOT}/usr/include/Api"
# Freestanding C++ headers (<cstdint>, <type_traits>, <atomic>, ...) —
# the subset the kernel and the in-tree programs build against. This is
# NOT the whole C++ story: a hosted libstdc++ is built further down and
# installs its own headers under ${PREFIX}/${TARGET}/include/c++.
# That directory comes first on the include path and this one comes
# last, so a plain g++ invocation gets the hosted headers and these are
# shadowed. See "C++ standard library" in README.md.
cp -r "${REPO_DIR}/kernel/freestnd-cxx-hdrs/${ARCH}/include/." "${SYSROOT}/usr/include/"
if [[ ${have_libc} == 1 ]]; then
cp "${LIBC_DIR}/crt1.o" "${LIBC_DIR}/crti.o" "${LIBC_DIR}/crtn.o" "${SYSROOT}/usr/lib/"
cp "${LIBC_DIR}/liblibc.a" "${SYSROOT}/usr/lib/libc.a"
else
bold "libc not built yet - sysroot has headers only."
fi
# libm is an empty stand-in (math lives inside libc.a; the g++ driver
# links -lm unconditionally). libstdc++ is copied from the toolchain
# once built - the empty stand-in only bridges the first bootstrap.
ar rcs "${SYSROOT}/usr/lib/libm.a"
if [[ -f "${PREFIX}/${TARGET}/lib/libstdc++.a" ]]; then
cp "${PREFIX}/${TARGET}/lib/libstdc++.a" "${SYSROOT}/usr/lib/libstdc++.a"
else
ar rcs "${SYSROOT}/usr/lib/libstdc++.a"
fi
green "Sysroot ready."
return 0
}
assemble_sysroot
# ── Build Binutils ────────────────────────────────────────────────────────────
if [[ -x "${PREFIX}/bin/${TARGET}-ld" ]]; then
bold "Binutils already installed — skipping."
else
bold "Building Binutils ${BINUTILS_VERSION} for ${TARGET}..."
rm -rf "${BUILD_DIR}/binutils-montauk"
mkdir -p "${BUILD_DIR}/binutils-montauk"
rm -rf "${BUILD_DIR}/binutils-montauk${BUILD_SUFFIX}"
mkdir -p "${BUILD_DIR}/binutils-montauk${BUILD_SUFFIX}"
(
cd "${BUILD_DIR}/binutils-montauk"
cd "${BUILD_DIR}/binutils-montauk${BUILD_SUFFIX}"
"${SRC_DIR}/binutils-${BINUTILS_VERSION}/configure" \
--target="${TARGET}" \
--prefix="${PREFIX}" \
@@ -174,10 +221,10 @@ if [[ -x "${PREFIX}/bin/${TARGET}-gcc" ]]; then
bold "GCC already installed — skipping."
else
bold "Building GCC ${GCC_VERSION} for ${TARGET}..."
rm -rf "${BUILD_DIR}/gcc-montauk"
mkdir -p "${BUILD_DIR}/gcc-montauk"
rm -rf "${BUILD_DIR}/gcc-montauk${BUILD_SUFFIX}"
mkdir -p "${BUILD_DIR}/gcc-montauk${BUILD_SUFFIX}"
(
cd "${BUILD_DIR}/gcc-montauk"
cd "${BUILD_DIR}/gcc-montauk${BUILD_SUFFIX}"
"${SRC_DIR}/gcc-${GCC_VERSION}/configure" \
--target="${TARGET}" \
--prefix="${PREFIX}" \
@@ -203,6 +250,11 @@ else
green "GCC and libstdc++ installed."
fi
# A first build for this architecture had no libc: complete the sysroot.
if [[ ! -f "${SYSROOT}/usr/lib/libc.a" ]] || [[ ! -s "${SYSROOT}/usr/lib/libstdc++.a" ]]; then
assemble_sysroot
fi
# ── Done ──────────────────────────────────────────────────────────────────────
echo
green "=== ${TARGET} cross compiler ready ==="