Add x86_64 kernel bring-up with build-selected platform adapters

This commit is contained in:
Aaron committed 2026-11-07 20:13:20 +00:00
1 parent e8e4061564
commit 6a1eb5e2ac
69 files changed
+4981 -1502

No files matched your search

+43
View File
@@ -0,0 +1,43 @@
#!/usr/bin/env python3
# Copyright 2026 Aaron Hance
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Prevent shared Pascal units from selecting architecture implementations."""
from pathlib import Path
import re
import sys
cpu_directive = re.compile(r"\{\$\s*if(?:def|ndef)?\b[^}]*\bCPU\w*", re.I)
arch_import = re.compile(r"\barch\.(?:x86|x86_64)\.", re.I)
errors = []
for path in sorted(Path("src").rglob("*")):
if path.suffix not in (".pas", ".inc"):
continue
if path.parts[1] == "arch" and path.parts[2] != "common":
continue
source = path.read_text(encoding="utf-8")
# Ignore prose comments but retain compiler directives.
source = re.sub(r"\{(?!\$).*?\}|\(\*.*?\*\)|//[^\n]*", "", source, flags=re.S)
if cpu_directive.search(source):
errors.append(f"{path}: CPU conditional belongs in build selection")
# Existing i386-only services outside the port still import their drivers.
# The migrated units must depend on stable platform names instead.
migrated = path.as_posix() in {
"src/core/core.util.pas", "src/core/strings/core.strings.pas",
"src/io/io.stdio.pas", "src/proc/proc.mgr.pas",
"src/memory/memory.heap.pas", "src/memory/memory.raw.pas",
} or path.parts[1:3] == ("arch", "common")
if migrated and arch_import.search(source):
errors.append(f"{path}: shared unit imports an architecture implementation")
if errors:
print("\n".join(errors), file=sys.stderr)
sys.exit(1)
print("Shared architecture boundaries verified.")
+22 -5
View File
@@ -1,4 +1,5 @@
#!/usr/bin/env bash
# Multi-architecture build updates: Copyright 2026 Aaron Hance.
ERRCOUNT=0
echo " "
echo "======================="
@@ -6,8 +7,11 @@ echo " "
echo "Asuro Compilation"
echo " "
#Compile Stub.asm
rm -f lib/*
TOOLCHAIN_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$TOOLCHAIN_DIR/target.sh"
mkdir -p "$OBJ_DIR" "$BIN_DIR"
# Clean only this target's generated objects; preserve other architectures.
find "$OBJ_DIR" -maxdepth 1 -type f \( -name '*.o' -o -name '*.ppu' -o -name '*.a' \) -delete
runOrFail() {
local binary=$1
@@ -20,8 +24,6 @@ runOrFail() {
fi
}
TOOLCHAIN_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
declare -a run_steps=(
"compile_stub.sh" "Failed to compile stub!"
"compile_vergen.sh" "Versions failed to compile"
@@ -35,6 +37,16 @@ declare -a run_steps=(
"compile_docs.sh" "Failed to generate documentation!"
)
if [ "$ASURO_ARCH" = x86_64 ]; then
# Bootstrap milestone: no desktop/runtime dependencies until they are ported.
run_steps=(
"compile_stub.sh" "Failed to compile stub!"
"compile_sources.sh" "Failed to compile FPC Sources!"
"compile_link.sh" "Failed linking!"
"compile_isogen.sh" "Failed to create ISO!"
)
fi
for ((i=0; i<${#run_steps[@]}; i+=2))
do
if [ "$ERRCOUNT" -eq "0" ]
@@ -46,6 +58,11 @@ do
done
#Call generate final artifacts based on failure or success of the above.
if [ "$ASURO_ARCH" = x86_64 ]; then
if [ "$ERRCOUNT" -ne 0 ]; then exit 1; fi
echo "No errors. Bootstrap image: $ISO_FILE"
exit 0
fi
if [ "$ERRCOUNT" -ne "0" ]
then
. "${TOOLCHAIN_DIR}/compile_finish.sh" "failed"
@@ -53,4 +70,4 @@ else
. "${TOOLCHAIN_DIR}/compile_finish.sh" "success"
fi
cd ..
cd ..
+9 -2
View File
@@ -1,8 +1,15 @@
#!/usr/bin/env bash
# Multi-architecture build updates: Copyright 2026 Aaron Hance.
set -e
source "$(dirname "${BASH_SOURCE[0]}")/target.sh"
echo " "
echo "======================="
echo " "
echo "Creating ISO..."
echo " "
cp bin/kernel.bin iso/boot/asuro.bin
grub-mkrescue -o Asuro.iso iso
mkdir -p "$ISO_ROOT/boot/grub"
if [ "$ASURO_ARCH" != x86 ]; then
cp iso/boot/grub/grub.cfg "$ISO_ROOT/boot/grub/grub.cfg"
fi
cp "$BIN_DIR/kernel.bin" "$ISO_ROOT/boot/asuro.bin"
grub-mkrescue -o "$ISO_FILE" "$ISO_ROOT"
+11 -2
View File
@@ -1,11 +1,20 @@
#!/usr/bin/env bash
# Multi-architecture build updates: Copyright 2026 Aaron Hance.
set -e
source "$(dirname "${BASH_SOURCE[0]}")/target.sh"
echo " "
echo "======================="
echo " "
echo "Linking..."
echo " "
if [ "$ASURO_ARCH" = x86_64 ]; then
ld -m "$LD_FORMAT" --gc-sections --no-warn-execstack \
-T"$LINKER_SCRIPT" -o "$BIN_DIR/kernel.bin" "$OBJ_DIR/"*.o
grub-file --is-x86-multiboot "$BIN_DIR/kernel.bin"
exit
fi
objstring="";
for object in `find lib/ -name "*.o"`; do
for object in `find lib/ -maxdepth 1 -name "*.o"`; do
if [ "$object" != "lib/stub.o" ]
then
objstring=$objstring$object" ";
@@ -19,4 +28,4 @@ echo " "
LIBGCC=$(gcc -m32 -print-libgcc-file-name)
echo "libgcc: ${LIBGCC}"
ld -m elf_i386 -s --gc-sections --no-warn-execstack -Ttoolchain/linker.script -o bin/kernel.bin $objstring --start-group lib/liblvgl.a ${LIBGCC} --end-group
ld -m elf_i386 -s --gc-sections --no-warn-execstack -Ttoolchain/linker.script -o bin/kernel.bin $objstring --start-group lib/liblvgl.a ${LIBGCC} --end-group
+24 -4
View File
@@ -1,13 +1,33 @@
#!/usr/bin/env bash
# Multi-architecture build updates: Copyright 2026 Aaron Hance.
set -e
source "$(dirname "${BASH_SOURCE[0]}")/target.sh"
echo " "
echo "======================="
echo " "
echo "Compiling FPC Sources..."
echo " "
# Build -Fu flags for all directories under src/, wasuro/ and compat/
FU_PATHS="-Fusrc -Fuwasuro -Fucompat"
for dir in $(find src wasuro compat -type d 2>/dev/null); do
# The build selects one platform implementation; shared units cannot select CPUs.
python3 toolchain/check_arch_boundaries.py
# Build -Fu flags for the selected architecture and shared sources.
if [ "$ASURO_ARCH" = x86_64 ]; then
test_flags=()
case "${ASURO_BOOT_TEST:-none}" in
none) ;;
ud) test_flags=(-dASURO_TEST_UD) ;;
pf) test_flags=(-dASURO_TEST_PF) ;;
df) test_flags=(-dASURO_TEST_DF) ;;
*) echo "Unknown ASURO_BOOT_TEST" >&2; exit 1 ;;
esac
# Restrict search paths: never accidentally select the i386 system unit.
exec ppcx64 -n -O2 -Si -Sc -Sg -Xd -CX -Rintel -Tlinux \
-Fu"src/arch/$ASURO_ARCH/platform" -Fusrc/core -Fusrc/core/strings -Fusrc/driver/storage -Fusrc/arch/x86_64/proc -Fusrc/core/ds -Fusrc/proc -Fusrc/io -Fusrc/arch/common -Fusrc/debug -Fusrc/boot -Fusrc/memory -Fusrc/arch/x86_64/memory -Fu"src/arch/x86_64" -FU"$OBJ_DIR" -FE"$BIN_DIR" "${test_flags[@]}" \
src/arch/x86_64/arch.x86_64.boot.pas
fi
FU_PATHS="-Fusrc/arch/$ASURO_ARCH/platform -Fusrc -Fuwasuro -Fucompat"
for dir in $(find src wasuro compat -type d -not -path 'src/arch/*' 2>/dev/null) \
$(find "src/arch/$ASURO_ARCH" src/arch/common -type d -not -path '*/platform*'); do
FU_PATHS="$FU_PATHS -Fu$dir"
done
fpc -Aelf -gw -g -gl -n -v0e -O3 -OpPENTIUM3 -Si -Sc -Sg -Xd -CX -XXs -CfSSE -CfSSE2 -Rintel -Pi386 -Tlinux -FElib/ $FU_PATHS src/asuro.pas
fpc -Aelf -gw -g -gl -n -v0e -O3 -OpPENTIUM3 -Si -Sc -Sg -Xd -CX -XXs -CfSSE -CfSSE2 -Rintel -Pi386 -Tlinux -FElib/ $FU_PATHS src/asuro.pas
+9 -2
View File
@@ -1,8 +1,15 @@
#!/usr/bin/env bash
# Multi-architecture build updates: Copyright 2026 Aaron Hance.
set -e
source "$(dirname "${BASH_SOURCE[0]}")/target.sh"
echo " "
echo "======================="
echo " "
echo "Compiling Stub..."
echo " "
nasm -f elf src/arch/x86/boot/stub.asm -o lib/stub.o
nasm -f elf src/boot/splash_tga.asm -o lib/splash_tga.o
nasm -f "$NASM_FORMAT" "src/arch/$ASURO_ARCH/boot/stub.asm" -o "$OBJ_DIR/stub.o"
if [ "$ASURO_ARCH" = x86 ]; then
nasm -f "$NASM_FORMAT" src/boot/splash_tga.asm -o "$OBJ_DIR/splash_tga.o"
else
nasm -f "$NASM_FORMAT" src/arch/x86_64/isr/entry.asm -o "$OBJ_DIR/isr_entry.o"
fi
+36
View File
@@ -0,0 +1,36 @@
#!/usr/bin/env bash
# Copyright 2026 Aaron Hance
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Shared target selection. Source this file from build steps.
ASURO_ARCH="${ASURO_ARCH:-x86}"
case "$ASURO_ARCH" in
x86)
OBJ_DIR=lib
BIN_DIR=bin
ISO_ROOT=iso
ISO_FILE=Asuro.iso
NASM_FORMAT=elf
LD_FORMAT=elf_i386
LINKER_SCRIPT=toolchain/linker.script
;;
x86_64)
OBJ_DIR=lib/x86_64
BIN_DIR=bin/x86_64
ISO_ROOT=bin/x86_64/iso
ISO_FILE=Asuro-x86_64.iso
NASM_FORMAT=elf64
LD_FORMAT=elf_x86_64
LINKER_SCRIPT=toolchain/x86_64/linker.script
;;
*) echo "Unsupported ASURO_ARCH: $ASURO_ARCH" >&2; exit 1 ;;
esac
export ASURO_ARCH OBJ_DIR BIN_DIR ISO_ROOT ISO_FILE NASM_FORMAT LD_FORMAT LINKER_SCRIPT
+31
View File
@@ -0,0 +1,31 @@
/* Copyright 2026 Aaron Hance
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
OUTPUT_FORMAT(elf64-x86-64)
ENTRY(loader)
SECTIONS
{
/* Bootstrap-only low mapping. Final kernel address-space policy is a
separate milestone; do not inherit the i386 0xC0000000 offset. */
. = 0x100000;
kernel_start = .;
.multiboot : { KEEP(*(.multiboot)) }
.text ALIGN(4096) : { *(.text .text.*) }
.rodata ALIGN(4096) : { *(.rodata .rodata.*) }
.data ALIGN(4096) : { *(.data .data.*) }
load_end = .;
.bss ALIGN(4096) (NOLOAD) : { *(COMMON) *(.bss .bss.*) }
. = ALIGN(4096);
kernel_end = .;
ASSERT(kernel_end < 0x100000000, "Bootstrap must fit below 4 GiB")
/DISCARD/ : { *(.comment) *(.note*) *(.eh_frame*) }
}
+112
View File
@@ -0,0 +1,112 @@
# Copyright 2026 Aaron Hance
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Run from the workspace root after building the selected ASURO_BOOT_TEST.
# Restore temporary optical medium and optional RAM changes after the test.
param(
[ValidateSet('none', 'ud', 'pf', 'df')][string]$Test = 'none',
[ValidateRange(0, 8192)][int]$MemoryMB = 0,
[string]$Controller = 'AHCI',
[int]$Port = 1,
[int]$Device = 0,
[ValidateRange(5, 45)][int]$TimeoutSeconds = 35
)
$ErrorActionPreference = 'Stop'
$config = Get-Content -LiteralPath .\localenv.json -Raw | ConvertFrom-Json
$vm = $config.virtualbox.MachineName
$serialPath = $config.virtualbox.LogLocation
if (-not $serialPath) { throw 'VirtualBox serial LogLocation is required.' }
$isoPath = (Resolve-Path -LiteralPath .\Asuro-x86_64.iso).Path
$state = & VBoxManage.exe showvminfo $vm --machinereadable
if ($LASTEXITCODE -ne 0) { throw 'Cannot inspect VirtualBox VM.' }
if ($state -notcontains 'VMState="poweroff"') {
throw 'The configured VM must already be powered off before boot validation.'
}
$mediumKey = '"{0}-{1}-{2}"=' -f $Controller, $Port, $Device
$mediumLine = @($state | Where-Object { $_.StartsWith($mediumKey) })
if ($mediumLine.Count -ne 1) { throw 'Cannot identify original optical medium.' }
$originalMedium = $mediumLine[0].Substring($mediumKey.Length).Trim('"').Replace('\\', '\')
if ($originalMedium -notin @('none', 'emptydrive') -and $originalMedium -notmatch '(?i)\.iso$') {
throw 'Selected port is not an ISO/empty optical drive; refusing to replace it.'
}
if ($originalMedium -eq 'none') { $originalMedium = 'emptydrive' }
$evidence = Join-Path (Get-Location) 'bin\x86_64'
New-Item -ItemType Directory -Path $evidence -Force | Out-Null
$originalMemory = [int](($state | Where-Object { $_ -match '^memory=' }) -replace '^memory=', '')
if ($originalMemory -le 0) { throw 'Cannot identify original VM RAM size.' }
$started = $false
try {
if ($MemoryMB -ne 0) {
& VBoxManage.exe modifyvm $vm --memory $MemoryMB
if ($LASTEXITCODE -ne 0) { throw 'Cannot set test RAM size.' }
}
& VBoxManage.exe storageattach $vm --storagectl $Controller --port $Port --device $Device --type dvddrive --medium $isoPath
if ($LASTEXITCODE -ne 0) { throw 'Cannot attach bootstrap ISO.' }
& .\virtualbox-wrapper.ps1 -command up -Headless -NoMonitor
if ($LASTEXITCODE -ne 0) { throw 'Cannot start test VM.' }
$started = $true
$deadline = [DateTime]::UtcNow.AddSeconds($TimeoutSeconds)
$output = ''
$marker = if ($Test -eq 'none') { 'bootstrap complete; interrupts disabled' } else { 'HALTED: exception diagnostics complete' }
do {
if (Test-Path -LiteralPath $serialPath) {
$output = Get-Content -LiteralPath $serialPath -Raw
}
if ($output -and ($output.Contains($marker) -or $output.Contains('FAIL:'))) { break }
Start-Sleep -Milliseconds 200
} while ([DateTime]::UtcNow -lt $deadline)
$output | Set-Content -LiteralPath (Join-Path $evidence "boot-$Test-$MemoryMB.log")
& VBoxManage.exe debugvm $vm getregisters rip rsp cs cr0 cr2 cr3 cr4 efer tr |
Set-Content -LiteralPath (Join-Path $evidence "registers-$Test-$MemoryMB.log")
if ($LASTEXITCODE -ne 0) { throw 'Cannot capture CPU registers.' }
Write-Output $output
if (-not $output -or -not $output.Contains($marker) -or $output.Contains('FAIL:')) {
throw 'Boot did not reach its expected completion marker.'
}
foreach ($required in @('EXCEPTION_TESTS_PASSED=0000000000000002', 'EXCEPTION_TESTS_FAILED=0000000000000000',
'PMM_TESTS_FAILED=0000000000000000', 'VMM_TESTS_FAILED=0000000000000000',
'HEAP_TESTS_FAILED=0000000000000000', 'IRQ_TESTS_FAILED=0000000000000000', 'CONTEXT_TESTS_FAILED=0000000000000000', 'PROCESS_TESTS_FAILED=0000000000000000', 'FD_TESTS_FAILED=0000000000000000', 'STRINGS_TESTS_FAILED=0000000000000000', 'STDIO_TESTS_FAILED=0000000000000000')) {
if (-not $output.Contains($required)) { throw "Missing check: $required" }
}
if ($MemoryMB -gt 4096 -and $output.Contains('SKIP: no available physical RAM above 4 GiB')) {
throw 'High physical memory test was skipped.'
}
if ($Test -ne 'none') {
$vector = @{ud = '6'; pf = 'E'; df = '8'}[$Test]
$errorCode = if ($Test -eq 'pf') { '2' } else { '0' }
foreach ($required in @("VECTOR=000000000000000$vector", "ERROR=000000000000000$errorCode", 'CS=0000000000000018')) {
if (-not $output.Contains($required)) { throw "Missing diagnostic: $required" }
}
if ($Test -eq 'pf' -and -not $output.Contains('CR2=0000000100000000')) {
throw 'Page fault did not preserve the expected CR2.'
}
if ($Test -eq 'df' -and (-not $output.Contains('STACK=double-fault IST1') -or
-not $output.Contains('RSP=0000000100001000'))) {
throw 'Double fault did not switch from the broken stack to IST1.'
}
}
Write-Output "PASS: VirtualBox x86_64 boot test '$Test'"
} finally {
try {
if ($started) {
& .\virtualbox-wrapper.ps1 -command down
if ($LASTEXITCODE -ne 0) { throw 'Cannot stop test VM.' }
}
} finally {
& VBoxManage.exe storageattach $vm --storagectl $Controller --port $Port --device $Device --type dvddrive --medium $originalMedium
if ($LASTEXITCODE -ne 0) { throw 'Cannot restore original optical medium.' }
if ($MemoryMB -ne 0) {
& VBoxManage.exe modifyvm $vm --memory $originalMemory
if ($LASTEXITCODE -ne 0) { throw 'Cannot restore original VM RAM size.' }
}
}
}