# SchOS launcher (Windows side). # # Why this exists: without it you have to hand-type a QEMU command line, and a # hand-typed one drifts -- notably onto a stale fs.img, which boots to # "fsinit: invalid file system" because the wrong disk is attached as hdb. # # The build no longer goes 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 it builds natively: 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. # # .\run.ps1 build (native) 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 # .\run.ps1 -SchFS boot the ramdisk-root kernel with a SchFS volume # attached as hdb; then run cat /proc/schfs param( [switch]$NoBuild, [switch]$Headless, [switch]$Gdb, [switch]$SchFS, [string]$Qemu = "$env:USERPROFILE\scoop\apps\qemu\current\qemu-system-x86_64.exe" ) $ErrorActionPreference = 'Stop' $root = $PSScriptRoot # The two images QEMU needs. These paths are the single source of truth -- # keep them in sync with the 'qemu' and 'qemu-schfs' targets in the Makefile. $hda = Join-Path $root 'schos.img' $hdb = if ($SchFS) { Join-Path $root 'build\schfs.img' } else { Join-Path $root 'build\fs.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). $bash = Join-Path $env:ProgramFiles 'Git\bin\bash.exe' if (-not (Test-Path $bash)) { throw "Git Bash not found at $bash" } $toolPath = @( "$env:USERPROFILE\scoop\shims" "$env:USERPROFILE\scoop\apps\mingw\current\bin" "$env:ProgramFiles\LLVM\bin" ) -join ';' $env:PATH = "$toolPath;$env:PATH" # -SchFS needs the ramdisk-root kernel: the root filesystem then comes out # of memory, which leaves device 1 free for the SchFS volume. Booting the # normal kernel with a SchFS disk as hdb would leave it with no root. $target = if ($SchFS) { 'make ramroot && make build/schfs.img' } else { 'make' } & $bash -lc "cd /d/DEV/SchOS && $target" 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)" } } # Guard against the exact failure this script exists to prevent: booting against # a stale or empty hdb. Each format has its own magic in its own place. $fs = [System.IO.File]::OpenRead($hdb) try { $buf = New-Object byte[] 4 # v1: superblock in block 1 with BSIZE 1024, FSMAGIC 0x10203040. # SchFS: first uberblock in block 1 with SCHFS_BLKSIZE 4096, magic "SchF". $null = $fs.Seek($(if ($SchFS) { 4096 } else { 1024 }), 'Begin') $null = $fs.Read($buf, 0, 4) } finally { $fs.Close() } if ($SchFS) { # 0x53636846 little-endian on disk: 46 68 63 53 ("FhcS" byte order). 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 valid SchFS image (bad uberblock magic). Rebuild it: make build/schfs.img" } } else { if ($buf[0] -ne 0x40 -or $buf[1] -ne 0x30 -or $buf[2] -ne 0x20 -or $buf[3] -ne 0x10) { throw "$hdb is not a valid SCHFS image (bad superblock magic). Rebuild it: rm -f build/fs.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 { $qemuArgs += @('-vga', 'std', '-serial', 'stdio') } if ($Gdb) { $qemuArgs += @('-gdb', 'tcp::26000', '-S') Write-Host '==> paused for gdb on localhost:26000' -ForegroundColor Yellow } & $Qemu @qemuArgs