XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFESystem

【Rust】XFE系统,基于Rust和汇编

公开
关注 0 Fork 0 Star 0
UTF-8
[CmdletBinding()]
param(
    [Parameter(Mandatory=$true)][string]$ImagePath,
    [Parameter(Mandatory=$true)][string]$VerifiedBootResult,
    [string]$QemuPath,
    [string]$ToolsRoot,
    [ValidateSet('gtk','sdl')][string]$DisplayBackend='gtk',
    [switch]$Fullscreen,
    [switch]$PlanOnly,
    [switch]$ValidateOnly
)
$ErrorActionPreference='Stop'
$taskRoot=[IO.Path]::GetFullPath((Join-Path $PSScriptRoot '../..'))
function Get-IndependentHash([string]$Path) {
    (Get-FileHash -LiteralPath $Path -Algorithm SHA256).Hash.ToLowerInvariant()
}
function Read-IndependentJson([string]$Path) {
    Get-Content -LiteralPath $Path -Raw -Encoding UTF8 | ConvertFrom-Json
}
function Get-IndependentFile([string]$Root,[string]$Relative) {
    if([IO.Path]::IsPathRooted($Relative)) { throw ('Expected a relative artifact path: '+$Relative) }
    $prefix=[IO.Path]::GetFullPath($Root).TrimEnd([char]'\',[char]'/')+[IO.Path]::DirectorySeparatorChar
    $path=[IO.Path]::GetFullPath((Join-Path $Root $Relative))
    if(!$path.StartsWith($prefix,[StringComparison]::OrdinalIgnoreCase) -or !(Test-Path -LiteralPath $path -PathType Leaf)) {
        throw ('Artifact is missing or outside its root: '+$Relative)
    }
    return $path
}
function Assert-IndependentHash([string]$Path,[string]$Expected,[string]$Label) {
    if($Expected -cnotmatch '^[0-9a-f]{64}$' -or (Get-IndependentHash $Path) -cne $Expected) {
        throw ('SHA256 verification failed: '+$Label)
    }
}
function Assert-IndependentSourceMap($Map,[string]$Root,[string]$Label) {
    if(!$Map -or @($Map.PSObject.Properties).Count -eq 0) { throw ('Empty source map: '+$Label) }
    foreach($entry in $Map.PSObject.Properties) {
        Assert-IndependentHash (Get-IndependentFile $Root $entry.Name) ([string]$entry.Value) ($Label+': '+$entry.Name)
    }
}
function Assert-IndependentSourceSubset($Expected,$Actual,[string]$Label) {
    if(!$Expected -or !$Actual) { throw ('Missing source binding: '+$Label) }
    foreach($entry in $Expected.PSObject.Properties) {
        $bound=$Actual.PSObject.Properties[$entry.Name]
        if(!$bound -or [string]$bound.Value -cne [string]$entry.Value) { throw ('Source binding differs: '+$Label+': '+$entry.Name) }
    }
}
$sourceImage=(Resolve-Path -LiteralPath $ImagePath).Path
$bootPath=(Resolve-Path -LiteralPath $VerifiedBootResult).Path
$boot=Read-IndependentJson $bootPath
if($boot.Kind -cne 'XfeIndependentKernelBootProof' -or $boot.Passed -ne $true -or
   $boot.ManagedRuntimeAcceptancePassed -ne $true -or $boot.DesktopAcceptanceRequired -ne $true -or
   $boot.DesktopAcceptancePassed -ne $true -or $boot.ContainsCosmos -ne $false -or
   $boot.BrowserAcceptanceRequired -ne $true -or $boot.BrowserAcceptancePassed -ne $true -or
   $boot.RamOnly -ne $true -or $boot.StorageEnabled -ne $false -or $boot.ExecutingCpus -ne 1 -or
   $boot.ImageUnchanged -ne $true -or $null -eq $boot.QemuExitCode -or $boot.QemuExitCode -ne 0 -or $boot.ForcedCleanup) {
    throw 'A passing, cleaned-up independent managed desktop AppBoot proof is required; bootstrap and runtime-probe proofs are insufficient.'
}
$desktopInput=$boot.DesktopInputProof
if(!$desktopInput -or $desktopInput.MouseCreatedEditor -ne $true -or $desktopInput.KeyboardSavedRamFile -ne $true -or
   $desktopInput.AltF4ClosedEditor -ne $true -or $desktopInput.StartMenuKeyboardNavigation -ne $true -or
   $desktopInput.JavaScriptDomResult -cne 'JavaScript ready: 12') { throw 'The proof lacks actual desktop PS/2 input and browser DOM acceptance.' }
if($desktopInput.NoRenderFailures -ne $true){throw 'Actual desktop rendering must complete without a browser paint failure; older model-ready-only proofs are insufficient.'}
if($boot.BrowserAcceptanceRequired -eq $true){
    $monacoPaint=$desktopInput.MonacoRasterPaintCompleted
    $monacoEdited=$desktopInput.MonacoKeyboardEditedModel
    if($monacoPaint -ne $true -or $monacoEdited -ne $true){throw 'Monaco must actually complete raster painting and change its model through real PS/2 keyboard input.'}
}
$arguments=@($boot.QemuArguments)
foreach($required in @(@('-machine','q35'),@('-accel','tcg'),@('-cpu','max'),@('-m','1024M'),@('-rtc','base=utc'),@('-net','none'))) {
    $index=[Array]::IndexOf($arguments,[string]$required[0])
    if($index -lt 0 -or $index+1 -ge $arguments.Count -or $arguments[$index+1] -cne $required[1]) {
        throw ('Unsupported or missing verified QEMU profile: '+($required -join ' '))
    }
}
Assert-IndependentHash $sourceImage $boot.ImageSha256 'verified image'
$imageManifestPath=$sourceImage+'.json'
$imageManifest=Read-IndependentJson $imageManifestPath
if($imageManifest.Kind -cne 'CSharpGptFat32Image' -or $imageManifest.KernelImplementation -cne 'XFESystem independent kernel' -or
   $imageManifest.FullImageReadback -ne $true -or $imageManifest.ImageSha256 -cne $boot.ImageSha256 -or
   $imageManifest.KernelSha256 -cne $boot.KernelSha256 -or (Get-Item -LiteralPath $sourceImage).Length -ne $imageManifest.ImageBytes) {
    throw 'The image manifest must identify the exact verified independent kernel image.'
}
$packaged=$false
$packageManifestPath=Join-Path $taskRoot 'Manifest.json'
if(Test-Path -LiteralPath $packageManifestPath -PathType Leaf) {
    $packageManifest=Read-IndependentJson $packageManifestPath
    if($packageManifest.Kind -ceq 'XfeIndependentRamDesktopPackage') {
        $packaged=$true
        if($packageManifest.GuestAcceptancePassed -ne $true -or $packageManifest.HostAcceptancePassed -ne $true -or
           $packageManifest.NoRenderFailures -ne $true -or $packageManifest.MonacoRasterPaintCompleted -ne $true -or
           $packageManifest.MonacoKeyboardEditedModel -ne $true -or
           $packageManifest.ContainsCosmos -ne $false -or !$packageManifest.Files) { throw 'Invalid independent package manifest.' }
        foreach($entry in $packageManifest.Files) {
            $path=Get-IndependentFile $taskRoot ([string]$entry.Path)
            Assert-IndependentHash $path ([string]$entry.Sha256) ('packaged '+$entry.Path)
            if((Get-Item -LiteralPath $path).Length -ne $entry.Bytes) { throw ('Packaged file length changed: '+$entry.Path) }
        }
        if($packageManifest.ImageSha256 -cne $boot.ImageSha256 -or $packageManifest.BootReceiptSha256 -cne (Get-IndependentHash $bootPath) -or
           $packageManifest.SourceSnapshotSha256 -cne $boot.SourceSnapshotSha256) { throw 'Package and AppBoot proof bindings differ.' }
    }
}
$sourceRoot=if($packaged){Join-Path $taskRoot 'SourceSnapshot'}else{$taskRoot}
$guestEvidenceRoot=if($packaged){Join-Path $taskRoot 'Validation/Guest'}else{Split-Path -Parent $bootPath}
Assert-IndependentHash (Get-IndependentFile $guestEvidenceRoot 'Frame.png') $boot.ScreenshotSha256 'actual guest framebuffer evidence'
foreach($capture in @(@('Files','Desktop-Files.png'),@('EditorSaved','Desktop-Editor-Saved.png'),@('Browser','Browser-JavaScript.png'))) {
    Assert-IndependentHash (Get-IndependentFile $guestEvidenceRoot $capture[1]) ([string]$desktopInput.Screenshots.PSObject.Properties[$capture[0]].Value) ('actual desktop input '+$capture[0])
}
if($boot.BrowserAcceptanceRequired -eq $true){
    if($boot.BrowserAcceptancePassed -ne $true -or $desktopInput.OfficialMonacoReady -ne $true){throw 'Required real Monaco acceptance is incomplete.'}
    Assert-IndependentHash (Get-IndependentFile $guestEvidenceRoot 'Browser-Monaco.png') $desktopInput.Screenshots.Monaco 'actual Monaco framebuffer evidence'
}
foreach($capture in @(@('ConsoleIL','Terminal-ConsoleIL.png'),@('ConsoleDemo','Terminal-Console-Demo.png'))) {
    $boundCapture=$desktopInput.Screenshots.PSObject.Properties[$capture[0]]
    if($boundCapture){Assert-IndependentHash (Get-IndependentFile $guestEvidenceRoot $capture[1]) ([string]$boundCapture.Value) ('actual terminal '+$capture[0])}
}
$snapshotPath=if($packaged){Get-IndependentFile $taskRoot 'Validation/SourceSnapshot.json'}else{(Resolve-Path -LiteralPath $boot.SourceSnapshotPath).Path}
$buildPath=if($packaged){Get-IndependentFile $taskRoot 'Validation/BuildReceipt.json'}else{(Resolve-Path -LiteralPath $boot.BuildReceipt).Path}
Assert-IndependentHash $snapshotPath $boot.SourceSnapshotSha256 'compiled source snapshot'
Assert-IndependentHash $buildPath $boot.BuildReceiptSha256 'independent kernel build receipt'
$snapshot=Read-IndependentJson $snapshotPath
$build=Read-IndependentJson $buildPath
if($build.Kind -cne 'XfeIndependentKernelBuild' -or $build.Passed -ne $true -or $build.BootstrapOnly -ne $false -or
   $build.ManagedRuntimeLinked -ne $true -or $build.ContainsCosmos -ne $false -or $build.Target -cne 'x86_64-none' -or
   $build.KernelSha256 -cne $boot.KernelSha256 -or
   !$build.SourceSha256.PSObject.Properties['Source/XFESystem.NativeRuntime/Application/NativeApplication.csproj']) {
    throw 'A complete NativeApplication kernel build is required; a diagnostic probe cannot be launched as the desktop.'
}
$kernelPath=if($packaged){Get-IndependentFile $taskRoot 'Kernel.elf'}else{(Resolve-Path -LiteralPath $build.KernelPath).Path}
Assert-IndependentHash $kernelPath $boot.KernelSha256 'compiled kernel'
Assert-IndependentSourceMap $snapshot $sourceRoot 'compiled snapshot'
Assert-IndependentSourceMap $build.SourceSha256 $sourceRoot 'kernel build'
Assert-IndependentSourceSubset $build.SourceSha256 $snapshot 'kernel to snapshot'
Assert-IndependentSourceSubset $imageManifest.BootShimSourceSha256 $snapshot 'EFI to snapshot'
Assert-IndependentSourceSubset $boot.ImageVerification.BootShimSourceSha256 $imageManifest.BootShimSourceSha256 'verified EFI to image manifest'
Assert-IndependentSourceSubset $imageManifest.BootShimSourceSha256 $boot.ImageVerification.BootShimSourceSha256 'image manifest to verified EFI'
Assert-IndependentSourceSubset $build.SourceSha256 $imageManifest.IndependentKernelBuild.SourceSha256 'kernel to image manifest'
Assert-IndependentSourceSubset $imageManifest.IndependentKernelBuild.SourceSha256 $build.SourceSha256 'image manifest to kernel'
if($imageManifest.IndependentKernelBuild.Passed -ne $true -or $imageManifest.IndependentKernelBuild.BootstrapOnly -ne $false -or
   $imageManifest.IndependentKernelBuild.ManagedRuntimeLinked -ne $true -or $imageManifest.IndependentKernelBuild.ContainsCosmos -ne $false -or
   $imageManifest.IndependentKernelBuild.KernelSha256 -cne $boot.KernelSha256 -or
   $boot.ImageVerification.Files.'System/Kernel.elf' -cne $boot.KernelSha256 -or
   $boot.ImageVerification.Files.'EFI/BOOT/BOOTX64.EFI' -cne $imageManifest.BootloaderSha256 -or
   $boot.ImageVerification.Files.'EFI/XFE/Limine.efi' -cne $imageManifest.ChainloaderSha256 -or
   $boot.ImageVerification.GptPrimaryAndBackupVerified -ne $true -or $boot.ImageVerification.FatMirrorsVerified -ne $true) {
    throw 'Embedded kernel, EFI and GPT/FAT verification bindings are incomplete.'
}
if(!$ToolsRoot){$ToolsRoot=Join-Path $taskRoot '.tools'}
$firmwareRoot=if($packaged){Join-Path $taskRoot 'Firmware'}else{Join-Path $ToolsRoot 'firmware'}
$firmwareLockPath=if($packaged){Get-IndependentFile $taskRoot 'Validation/Firmware.json'}else{Get-IndependentFile $taskRoot 'Tools/CSharpBoot/Dependencies.json'}
$firmwareLock=Read-IndependentJson $firmwareLockPath
$firmwareCode=Get-IndependentFile $firmwareRoot 'edk2-x86_64-code.fd'
$firmwareVars=Get-IndependentFile $firmwareRoot 'edk2-i386-vars.fd'
foreach($firmware in @($firmwareCode,$firmwareVars)) {
    Assert-IndependentHash $firmware ([string]$firmwareLock.Firmware.PSObject.Properties[[IO.Path]::GetFileName($firmware)].Value) ('pinned firmware '+[IO.Path]::GetFileName($firmware))
}
$verified=[pscustomobject]@{ImagePath=$sourceImage;BootPath=$bootPath;Boot=$boot;ImageManifestPath=$imageManifestPath;
    ImageManifest=$imageManifest;BuildPath=$buildPath;Build=$build;KernelPath=$kernelPath;
    SnapshotPath=$snapshotPath;Snapshot=$snapshot;SourceRoot=$sourceRoot;Packaged=$packaged;
    FirmwareCode=$firmwareCode;FirmwareVars=$firmwareVars;FirmwareLock=$firmwareLock;
    NoRenderFailures=$desktopInput.NoRenderFailures;MonacoRasterPaintCompleted=$monacoPaint;MonacoKeyboardEditedModel=$monacoEdited}
if($ValidateOnly){return $verified}
if(!$QemuPath){
    $localQemu=Join-Path $ToolsRoot 'qemu/qemu-system-x86_64.exe'
    if(Test-Path -LiteralPath $localQemu -PathType Leaf){$QemuPath=$localQemu}
    else{$command=Get-Command qemu-system-x86_64.exe -ErrorAction SilentlyContinue;if(!$command){throw 'Pass -QemuPath for an installed x86_64 QEMU.'};$QemuPath=$command.Source}
}
$QemuPath=(Resolve-Path -LiteralPath $QemuPath).Path
$runId='Interactive-'+[DateTimeOffset]::UtcNow.ToUnixTimeMilliseconds()+'-'+[Guid]::NewGuid().ToString('N').Substring(0,8)
$runRoot=Join-Path $taskRoot ('build/IndependentKernel/'+$runId)
[void][IO.Directory]::CreateDirectory($runRoot)
$runImage=Join-Path $runRoot 'System.img'
$runVars=Join-Path $runRoot 'FirmwareVars.fd'
$serialLog=Join-Path $runRoot 'Serial.log'
Copy-Item -LiteralPath $sourceImage -Destination $runImage
Copy-Item -LiteralPath $firmwareVars -Destination $runVars
Assert-IndependentHash $runImage $boot.ImageSha256 'private interactive image copy'
Assert-IndependentHash $runVars (Get-IndependentHash $firmwareVars) 'private firmware variable copy'
$display=if($DisplayBackend -eq 'gtk'){'gtk,zoom-to-fit=on'}else{'sdl,gl=off'}
$qemuArguments=@('-name','XFESystem | XFEstudio - Independent RAM experiment','-machine','q35','-accel','tcg','-cpu','max',
    '-smp','1','-m','1024M','-vga','std','-global','VGA.vgamem_mb=64','-display',$display,'-net','none','-rtc','base=utc',
    '-drive',('if=pflash,format=raw,readonly=on,file='+$firmwareCode.Replace(',',',,')),
    '-drive',('if=pflash,format=raw,file='+$runVars.Replace(',',',,')),
    '-drive',('file='+$runImage.Replace(',',',,')+',format=raw,if=ide,snapshot=on'),
    '-serial',('file:'+$serialLog),'-monitor','none','-no-reboot')
if($Fullscreen){$qemuArguments+='-full-screen'}
$launch=[ordered]@{Kind='XfeIndependentKernelInteractiveLaunch';AppBootReceiptSha256=(Get-IndependentHash $bootPath);
    ImageSha256=$boot.ImageSha256;KernelSha256=$boot.KernelSha256;SourceSnapshotSha256=$boot.SourceSnapshotSha256;
    RunDirectory=$runRoot;SerialLog=$serialLog;QemuPath=$QemuPath;QemuArguments=$qemuArguments;
    Acceleration='tcg';Machine='q35';MemoryMiB=1024;VirtualCpus=1;ExecutingCpus=1;
    InputDevices='Q35 built-in i8042 PS/2 keyboard and mouse';Rtc='UTC';RamOnly=$true;StorageEnabled=$false;
    ContainsCosmos=$false;InteractiveStarted=$false;InteractiveAcceptancePassed=$false;PlanOnly=[bool]$PlanOnly}
$launchPath=Join-Path $runRoot 'Launch.json'
try {
    if(!$PlanOnly){
        $quoted=@($qemuArguments | ForEach-Object {if($_.Contains('"')){throw 'Unexpected quote in QEMU argument.'};'"'+($_ -replace '(\\+)$','$1$1')+'"'})
        $process=Start-Process -FilePath $QemuPath -ArgumentList ($quoted -join ' ') -WorkingDirectory $runRoot -WindowStyle Normal -PassThru
        $launch.ProcessId=$process.Id;$launch.InteractiveStarted=$true
    }
} catch {$launch.Error=$_.Exception.Message;throw}
finally {$launch | ConvertTo-Json -Depth 7 | Set-Content -LiteralPath $launchPath -Encoding UTF8}
Write-Host ('Independent RAM experiment '+$(if($PlanOnly){'launch plan'}else{'interactive window'})+': '+$runRoot)
Write-Host ('Serial log: '+$serialLog)
return [pscustomobject]$launch