104 lines
4.0 KiB
Bash
Executable File
104 lines
4.0 KiB
Bash
Executable File
#!/bin/sh
|
|
# check-arch-neutral.sh - Verify the kernel's architecture boundary.
|
|
#
|
|
# 1. Static rules: outside kernel/src/Arch/, kernel code may not contain
|
|
# inline assembly, assembly sources, architecture #ifdefs, or includes of
|
|
# a specific port's headers (it must use the interfaces in Arch/*.hpp).
|
|
# 2. If clang is installed, compile the whole kernel for a second
|
|
# architecture (default aarch64) and report any symbol the generic code
|
|
# needs that the port does not define. Links too when ld.lld is found.
|
|
#
|
|
# Usage: ./scripts/check-arch-neutral.sh [arch]
|
|
#
|
|
# Copyright (c) 2026 Daniel Hammer
|
|
|
|
set -e
|
|
|
|
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
|
SRC="$ROOT/kernel/src"
|
|
ARCH="${1:-aarch64}"
|
|
status=0
|
|
|
|
cd "$SRC"
|
|
|
|
# Files allowed to name an architecture: the Limine adapter reads the
|
|
# per-architecture MP structures limine.h defines, and Io/IoPort.hpp is an
|
|
# interface header that dispatches to the port like Arch/*.hpp do.
|
|
ALLOW='^(limine\.h|Boot/Protocols/LimineProtocol\.cpp|Io/IoPort\.hpp)$'
|
|
|
|
generic=$(find . -type f \( -name '*.c' -o -name '*.cpp' -o -name '*.h' -o -name '*.hpp' \) \
|
|
! -path './Arch/*' | sed 's|^\./||' | LC_ALL=C sort)
|
|
|
|
report() {
|
|
echo "check-arch-neutral: $1" >&2
|
|
echo "$2" | sed 's/^/ /' >&2
|
|
status=1
|
|
}
|
|
|
|
hits=$(grep -nE '(^|[^_[:alnum:]])(asm|__asm__)[[:space:]]*(volatile|\()' $generic || true)
|
|
[ -n "$hits" ] && report "inline assembly outside src/Arch/:" "$hits"
|
|
|
|
hits=$(find . -type f \( -name '*.asm' -o -name '*.S' -o -name '*.s' \) ! -path './Arch/*')
|
|
[ -n "$hits" ] && report "assembly sources outside src/Arch/:" "$hits"
|
|
|
|
hits=$(echo "$generic" | grep -vE "$ALLOW" | xargs grep -nE \
|
|
'__(x86_64|i386|aarch64|arm|riscv|loongarch[0-9]*)__|MONTAUK_ARCH_(X86|AARCH|RISCV|LOONG)[A-Z0-9_]*' || true)
|
|
[ -n "$hits" ] && report "architecture conditionals outside src/Arch/:" "$hits"
|
|
|
|
hits=$(echo "$generic" | grep -vE "$ALLOW" | xargs grep -nE \
|
|
'#[[:space:]]*include[[:space:]]*[<"]Arch/[^/>"]+/' || true)
|
|
[ -n "$hits" ] && report "includes of a port's private headers:" "$hits"
|
|
|
|
if [ $status -eq 0 ]; then
|
|
echo "check-arch-neutral: static rules OK"
|
|
fi
|
|
|
|
# ---- Cross-compile check ----
|
|
if ! command -v clang >/dev/null 2>&1; then
|
|
echo "check-arch-neutral: clang not found, skipping the $ARCH build"
|
|
exit $status
|
|
fi
|
|
if [ ! -d "Arch/$ARCH" ]; then
|
|
echo "check-arch-neutral: no src/Arch/$ARCH port" >&2
|
|
exit 1
|
|
fi
|
|
|
|
echo "check-arch-neutral: compiling the kernel for $ARCH"
|
|
make -C "$ROOT/kernel" ARCH="$ARCH" objects -j"$(nproc 2>/dev/null || echo 4)" \
|
|
>/dev/null 2>"$ROOT/kernel/check-arch-$ARCH.log" || {
|
|
echo "check-arch-neutral: $ARCH compile failed (kernel/check-arch-$ARCH.log):" >&2
|
|
grep -E 'error' "$ROOT/kernel/check-arch-$ARCH.log" | head -20 >&2
|
|
exit 1
|
|
}
|
|
rm -f "$ROOT/kernel/check-arch-$ARCH.log"
|
|
|
|
NM="$(clang -print-prog-name=llvm-nm)"
|
|
command -v "$NM" >/dev/null 2>&1 || NM=nm
|
|
CXXFILT="$(clang -print-prog-name=llvm-cxxfilt)"
|
|
command -v "$CXXFILT" >/dev/null 2>&1 || CXXFILT=cat
|
|
|
|
cd "$ROOT/kernel"
|
|
objs=$(find "obj-$ARCH" -name '*.o')
|
|
tmp=$(mktemp -d)
|
|
trap 'rm -rf "$tmp"' EXIT
|
|
"$NM" --defined-only -j $objs "cc-runtime-$ARCH/cc-runtime.a" 2>/dev/null | LC_ALL=C sort -u > "$tmp/def"
|
|
"$NM" --undefined-only -j $objs | LC_ALL=C sort -u > "$tmp/undef"
|
|
# Provided by the linker script.
|
|
printf '%s\n' KernelStartSymbol KernelEndSymbol __init_array __init_array_end >> "$tmp/def"
|
|
LC_ALL=C sort -u -o "$tmp/def" "$tmp/def"
|
|
missing=$(LC_ALL=C comm -23 "$tmp/undef" "$tmp/def" | "$CXXFILT")
|
|
if [ -n "$missing" ]; then
|
|
report "symbols the $ARCH port must still provide:" "$missing"
|
|
exit 1
|
|
fi
|
|
echo "check-arch-neutral: $ARCH objects compile and every symbol resolves"
|
|
|
|
# Same lookup as kernel/GNUmakefile: a system ld.lld, else rustup's.
|
|
lld="${KERNEL_LD:-$(command -v ld.lld || ls "$HOME"/.rustup/toolchains/*/lib/rustlib/*/bin/gcc-ld/ld.lld 2>/dev/null | head -n 1)}"
|
|
if [ -n "$lld" ] && command -v "$lld" >/dev/null 2>&1; then
|
|
make ARCH="$ARCH" KERNEL_LD="$lld" >/dev/null
|
|
echo "check-arch-neutral: linked kernel/bin-$ARCH/kernel"
|
|
fi
|
|
|
|
exit $status
|