ui_panel was written for this screen during the loader restyle and then never called -- dead code sitting in boot/common/ui.c waiting for the row that would use it. This is that row: F8 -> System Information, showing firmware vendor and revision, UEFI revision, CPU brand, usable memory, current mode and whether ACPI was found. Everything is read when the screen is drawn rather than captured at startup, because the resolution row above it can have changed the mode, and a panel still reporting what the machine booted with is worse than no panel at all. Two facts are deliberately read through the same code that feeds the kernel -- efi_type_to_e820() for what counts as usable memory, and find_rsdp() for ACPI. A panel with its own idea of either would be a second implementation to keep in step, and the ACPI line exists precisely because a missing RSDP means no MADT, no IOAPIC and no SMP, which has already been debugged once from the far end. The screenshot caught a bug in the screen it was taken to verify: UEFI revision read "21587.2286". EFI_TABLE_HEADER begins with a UINT64 Signature, so Revision is at offset 8 and I had read offset 4 -- the upper half of "IBI SYST", formatted as a version number. It now reads 2.7 under OVMF, which is correct. Verified by driving the menu over the QEMU monitor and reading the pixels: five rows with the hint updated to 1-5, the panel centred, and every value cross-checkable -- EDK II, firmware 1.0, UEFI 2.7, "QEMU Virtual CPU version 2.5+" against -cpu qemu64, 1018 MB of the 1 GB given, 1280x800 matching what fbshot captures, ACPI present. The highlight sits 9 px inside both panel borders, symmetric. F8 has a 1.5 s window, so the capture presses it repeatedly through boot rather than guessing when OVMF finishes -- and only F8, since any other key breaks the wait and boots. Also: every ESP drive now says format=raw. QEMU warned about probing the format on each of the fifteen or so places that attach it, which is new noise on what is now the only boot path. 110 [ok], no failures, no warnings.
149 lines
6 KiB
PowerShell
149 lines
6 KiB
PowerShell
# SchOS launcher (Windows side).
|
|
#
|
|
# Why this exists: without it you hand-type a QEMU command line, and a
|
|
# hand-typed one drifts -- notably onto the wrong disk as hdb, which boots
|
|
# straight into a PSOGM reading "no SchFS volume on the root device".
|
|
#
|
|
# The build runs natively rather than through WSL. WSL2 runs a real Linux
|
|
# kernel inside a Hyper-V VM, so it hard-requires virtualisation, and enabling
|
|
# that puts the Hyper-V hypervisor underneath the whole machine -- which makes
|
|
# VMware run nested on top of it and slows the box down permanently. Not a
|
|
# trade worth making for a build environment.
|
|
#
|
|
# Instead: clang/lld cross-compile the kernel to bare-metal ELF, mingw-w64
|
|
# builds the host tools, and Git Bash supplies make, perl, sed and dd. See the
|
|
# Toolchain section of the Makefile, and docs/building.md.
|
|
#
|
|
# .\run.ps1 build then boot, windowed
|
|
# .\run.ps1 -NoBuild boot whatever is already built
|
|
# .\run.ps1 -Headless no window; serial captured to build/serial.log
|
|
# .\run.ps1 -Gdb wait for a debugger on :26000 before executing
|
|
#
|
|
# There is no -SchFS switch. SchFS is the root filesystem now, not an extra
|
|
# volume to attach, so every boot is a SchFS boot.
|
|
|
|
param(
|
|
[switch]$NoBuild,
|
|
[switch]$Headless,
|
|
[switch]$Gdb,
|
|
[string]$Qemu
|
|
)
|
|
|
|
$ErrorActionPreference = 'Stop'
|
|
$root = $PSScriptRoot
|
|
|
|
if (-not $Qemu) {
|
|
$found = Get-Command 'qemu-system-x86_64.exe' -ErrorAction SilentlyContinue
|
|
if ($found) {
|
|
$Qemu = $found.Source
|
|
} else {
|
|
$Qemu = Join-Path $env:USERPROFILE 'scoop/apps/qemu/current/qemu-system-x86_64.exe'
|
|
}
|
|
}
|
|
if (-not (Test-Path $Qemu)) { throw "QEMU not found: $Qemu (install it, or pass -Qemu <path>)" }
|
|
|
|
# The two images QEMU needs. Keep in sync with the 'qemu' target in the
|
|
# Makefile.
|
|
#
|
|
# esp the staged EFI system partition: the loader and the kernel
|
|
# hdb the root filesystem, mounted as / by forkret()
|
|
#
|
|
# hdb was build/fs.img until SchFS became the root. Nothing builds fs.img on
|
|
# the default path any more, so the old default pointed at a file that no
|
|
# longer exists -- QEMU came up with no usable disk on device 1 and the kernel
|
|
# panicked with SCHFS_ROOT. That is the failure this script is supposed to
|
|
# prevent, so it is worth naming.
|
|
$esp = Join-Path $root 'build/esp'
|
|
$hdb = Join-Path $root 'build/schfs.img'
|
|
$code = Join-Path $root 'build/OVMF_CODE.fd'
|
|
$vars = Join-Path $root 'build/OVMF_VARS.fd'
|
|
|
|
if (-not $NoBuild) {
|
|
Write-Host '==> building (native, no WSL)' -ForegroundColor Cyan
|
|
|
|
# The three toolchain directories, prepended so the build sees them whether
|
|
# or not the current shell happened to inherit them: scoop's shims (make),
|
|
# mingw-w64 (host gcc), and LLVM (clang, ld.lld, llvm-objcopy/objdump).
|
|
$bashCandidates = @(
|
|
(Join-Path $env:ProgramFiles 'Git/bin/bash.exe')
|
|
(Join-Path ${env:ProgramFiles(x86)} 'Git/bin/bash.exe')
|
|
(Join-Path $env:USERPROFILE 'scoop/apps/git/current/bin/bash.exe')
|
|
(Join-Path $env:LOCALAPPDATA 'Programs/Git/bin/bash.exe')
|
|
)
|
|
$bash = $bashCandidates | Where-Object { $_ -and (Test-Path $_) } | Select-Object -First 1
|
|
if (-not $bash) { throw "Git Bash not found; looked in:`n $($bashCandidates -join "`n ")" }
|
|
|
|
$toolPath = @(
|
|
"$env:USERPROFILE\scoop\shims"
|
|
"$env:USERPROFILE\scoop\apps\mingw\current\bin"
|
|
"$env:ProgramFiles\LLVM\bin"
|
|
) -join ';'
|
|
$env:PATH = "$toolPath;$env:PATH"
|
|
|
|
# The repo's own path, not a hardcoded one. This used to say
|
|
# `cd /d/DEV/SchOS`, which survived the Schunix -> SchOS rename only by
|
|
# luck and would break the moment the tree is cloned anywhere else.
|
|
$posixRoot = ($root -replace '\\', '/') -replace '^([A-Za-z]):', '/$1'
|
|
$posixRoot = $posixRoot.Substring(0, 2).ToLower() + $posixRoot.Substring(2)
|
|
|
|
& $bash -lc "cd '$posixRoot' && make"
|
|
if ($LASTEXITCODE -ne 0) { throw "build failed (exit $LASTEXITCODE)" }
|
|
}
|
|
|
|
foreach ($img in @($hdb, (Join-Path $esp 'EFI/BOOT/BOOTX64.EFI'))) {
|
|
if (-not (Test-Path $img)) {
|
|
throw "missing: $img (run without -NoBuild, or: make)"
|
|
}
|
|
}
|
|
foreach ($f in @($code, $vars)) {
|
|
if (-not (Test-Path $f)) { throw "no $f -- run 'make qemu-uefi' once to fetch OVMF" }
|
|
}
|
|
$runVars = Join-Path $root 'build/run-OVMF_VARS.fd'
|
|
Copy-Item -Force $vars $runVars
|
|
|
|
# Guard against the exact failure this script exists to prevent: booting
|
|
# against a stale, empty or wrong-format root disk. The first uberblock sits in
|
|
# block 1 at SCHFS_BLKSIZE 4096, and starts with the magic "SchF" -- stored
|
|
# little-endian, so the bytes on disk read 46 68 63 53.
|
|
$fs = [System.IO.File]::OpenRead($hdb)
|
|
try {
|
|
$buf = New-Object byte[] 4
|
|
$null = $fs.Seek(4096, 'Begin')
|
|
$null = $fs.Read($buf, 0, 4)
|
|
} finally { $fs.Close() }
|
|
|
|
if ($buf[0] -ne 0x46 -or $buf[1] -ne 0x68 -or $buf[2] -ne 0x63 -or $buf[3] -ne 0x53) {
|
|
throw ("$hdb is not a SchFS volume (bad uberblock magic: " +
|
|
('{0:x2} {1:x2} {2:x2} {3:x2}' -f $buf[0], $buf[1], $buf[2], $buf[3]) +
|
|
").`n Rebuild it: rm -f build/schfs.img && make")
|
|
}
|
|
|
|
$qemuArgs = @(
|
|
'-drive', "if=pflash,format=raw,unit=0,readonly=on,file=$code"
|
|
'-drive', "if=pflash,format=raw,unit=1,file=$runVars"
|
|
'-drive', "file=fat:rw:$esp,index=0,media=disk,format=raw"
|
|
'-drive', "file=$hdb,format=raw,index=1,media=disk"
|
|
'-m', '1G'
|
|
'-smp', '2'
|
|
'-cpu', 'qemu64,+rdtscp'
|
|
'-machine', 'pc-i440fx-9.2'
|
|
)
|
|
|
|
if ($Headless) {
|
|
$log = Join-Path $root 'build/serial.log'
|
|
$qemuArgs += @('-display', 'none', '-serial', "file:$log")
|
|
Write-Host "==> headless; serial -> $log" -ForegroundColor Cyan
|
|
} else {
|
|
# Both display devices, matching QEMU_DISPLAY in the Makefile: the
|
|
# bootloader draws its splash through VBE in 16-bit real mode and there is
|
|
# no virtio path that early, so stdvga carries the splash and the text
|
|
# console while virtio-gpu is what the display class binds.
|
|
$qemuArgs += @('-vga', 'std', '-device', 'virtio-gpu-pci', '-serial', 'stdio')
|
|
}
|
|
|
|
if ($Gdb) {
|
|
$qemuArgs += @('-gdb', 'tcp::26000', '-S')
|
|
Write-Host '==> paused for gdb on localhost:26000' -ForegroundColor Yellow
|
|
}
|
|
|
|
& $Qemu @qemuArgs
|