run.ps1 is a .ps1 that does not live under tools/, so every sweep that
fixed the other launchers went straight past it:
- hdb defaulted to build/fs.img, which nothing builds since SchFS
became the root, so it pointed at a file that does not exist. QEMU
came up with no usable disk on device 1 and the kernel panicked with
SCHFS_ROOT -- "no SchFS volume on the root device". That is exactly
the failure this script exists to prevent.
- a -SchFS switch built around the old arrangement, where SchFS was a
secondary volume and needed `make ramroot` to free device 1. There
is no such arrangement now; every boot is a SchFS boot.
- `cd /d/DEV/SchOS` hardcoded into the build invocation. It survived
the Schunix -> SchOS rename by luck and would break on any clone.
Derived from $PSScriptRoot now.
- a hardcoded scoop QEMU path, and build\ backslash literals.
- only -vga std, where the Makefile also attaches virtio-gpu-pci.
The magic check is SchFS-only now and prints the bytes it actually read
when it fails.
SchFS itself is fine: it mounts on 1, 2 and 4 CPUs, and all seven
bootcheck suites pass.
140 lines
5.6 KiB
PowerShell
140 lines
5.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.
|
|
#
|
|
# hda the boot disk: bootblock, stage 2 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.
|
|
$hda = Join-Path $root 'schos.img'
|
|
$hdb = Join-Path $root 'build/schfs.img'
|
|
|
|
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 @($hda, $hdb)) {
|
|
if (-not (Test-Path $img)) {
|
|
throw "missing image: $img (run without -NoBuild, or: make)"
|
|
}
|
|
}
|
|
|
|
# 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', "file=$hda,format=raw,index=0,media=disk"
|
|
'-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
|