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

XFESystem

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

公开
关注 0 Fork 0 Star 0
UTF-8
[CmdletBinding()]
param(
    [ValidateSet('Desktop','Console')][string]$Edition='Desktop',
    [Parameter(Mandatory=$true)][string]$ImagePath,
    [Parameter(Mandatory=$true)][string]$VerifiedBootResult,
    [Parameter(Mandatory=$true)][string]$VerifiedHostResult,
    [string]$ToolsRoot,
    [string]$Version='dev',
    [string]$OutputDirectory
)
$ErrorActionPreference='Stop'
$Edition=if($Edition -eq 'Console'){'Console'}else{'Desktop'}
$taskRoot=[IO.Path]::GetFullPath((Join-Path $PSScriptRoot '../..'))
if($Version -cnotmatch '^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$'){throw 'Version must be a short filename-safe label.'}
# The launcher owns the same mandatory image, kernel, source and desktop gates.
$verified=. (Join-Path $PSScriptRoot 'Open.ps1') -Edition $Edition -ImagePath $ImagePath -VerifiedBootResult $VerifiedBootResult -ToolsRoot $ToolsRoot -ValidateOnly
if($verified.Packaged){throw 'Package a verified repository build, rather than repackaging an existing distribution.'}
if($verified.ImageManifest.Edition -ceq 'Dual'){throw 'Edition packages require their separately verified single-edition images.'}
if($verified.ImageManifest.DeploymentPolicy -cne 'SingleEditionOnly' -or $verified.Boot.SingleEditionImageProof.Passed -ne $true) {
    throw 'New packages require actual single-system image inspection and a boot proof with no edition selection menu.'
}
# Validation-only dot-sourcing shares validators without opening a guest.
$hostPath=(Resolve-Path -LiteralPath $VerifiedHostResult).Path
$hostProof=Read-IndependentJson $hostPath
if($hostProof.HostOnly -ne $true -or $hostProof.GuestExecution -ne $false -or $hostProof.Passed -ne $true -or !$hostProof.SourceHashes -or !$hostProof.Suites) {
    throw 'A passing source-bound host test receipt is required.'
}
Assert-IndependentSourceMap $hostProof.SourceHashes $taskRoot 'host verification'
if(!$hostProof.SourceHashes.PSObject.Properties['Source/XFESystem.NativeKernel/Ps2Decoder.cs'] -or
   !$hostProof.SourceHashes.PSObject.Properties['Tests/XFESystem.Platform.Tests/XFESystem.Platform.Tests.csproj']) {
    throw 'Host verification must include the independent Platform tests and the production PS/2 decoder.'
}
foreach($entry in $verified.Snapshot.PSObject.Properties) {
    $hostEntry=$hostProof.SourceHashes.PSObject.Properties[$entry.Name]
    if($hostEntry -and [string]$hostEntry.Value -cne [string]$entry.Value) { throw ('Host and guest source hashes differ: '+$entry.Name) }
}
$hostArtifacts=@()
$suiteNames=@()
foreach($suite in $hostProof.Suites) {
    if([string]$suite.Suite -cnotmatch '^[A-Za-z0-9._-]+$' -or $suiteNames -contains $suite.Suite -or $suite.Failed -ne 0 -or [int]$suite.Passed -le 0) {
        throw 'Host suite names and successful counters are required.'
    }
    $suiteNames+=([string]$suite.Suite)
    $logPath=(Resolve-Path -LiteralPath $suite.Log).Path
    if($suite.LogSha256){Assert-IndependentHash $logPath $suite.LogSha256 ('host log '+$suite.Suite)}
    $hostArtifacts+= [pscustomobject]@{Source=$logPath;Destination=('Validation/Host/'+$suite.Suite+'.log');Sha256=(Get-IndependentHash $logPath)}
    if($suite.Trx) {
        $trxPath=(Resolve-Path -LiteralPath $suite.Trx).Path
        if($suite.TrxSha256){Assert-IndependentHash $trxPath $suite.TrxSha256 ('host TRX '+$suite.Suite)}
        [xml]$trx=Get-Content -LiteralPath $trxPath -Raw -Encoding UTF8
        $counter=$trx.SelectSingleNode("//*[local-name()='Counters']")
        if(!$counter -or [int]$counter.failed -ne 0 -or [int]$counter.passed -ne [int]$suite.Passed -or
           [int]$counter.executed -ne [int]$counter.passed -or [int]$counter.total -ne [int]$counter.passed) {
            throw ('Actual host TRX counters are incomplete or differ: '+$suite.Suite)
        }
        $hostArtifacts+= [pscustomobject]@{Source=$trxPath;Destination=('Validation/Host/'+$suite.Suite+'.trx');Sha256=(Get-IndependentHash $trxPath)}
    } elseif($suite.Receipt -and $suite.ReceiptSha256) {
        $nativePath=(Resolve-Path -LiteralPath $suite.Receipt).Path
        Assert-IndependentHash $nativePath $suite.ReceiptSha256 ('native host receipt '+$suite.Suite)
        $native=Read-IndependentJson $nativePath
        if($native.Passed -ne $true -or $native.Failed -ne 0 -or $null -eq $native.ExitCode -or $native.ExitCode -ne 0 -or
           [int]$native.PassedCount -ne [int]$suite.Passed) { throw ('Native host test execution did not pass: '+$suite.Suite) }
        $hostArtifacts+= [pscustomobject]@{Source=$nativePath;Destination=('Validation/Host/'+$suite.Suite+'.json');Sha256=(Get-IndependentHash $nativePath)}
    } else {throw ('Actual TRX or source-bound native execution receipt is required: '+$suite.Suite)}
}
if($suiteNames -notcontains 'Platform' -or $suiteNames -notcontains 'NativeContracts' -or $suiteNames -notcontains 'Network' -or $suiteNames -notcontains 'NativeTls' -or $suiteNames -notcontains 'ConsoleEdition') {
    throw 'The final host receipt must include Platform, NativeContracts, Network, NativeTls and ConsoleEdition suites. Network/NativeTls host acceptance does not prove guest HTTPS acceptance.'
}
$licensesRoot=Join-Path $PSScriptRoot 'Licenses'
$licensesPath=Get-IndependentFile $licensesRoot 'Manifest.json'
$licenses=Read-IndependentJson $licensesPath
if($licenses.Schema -cne 'XFESystem.IndependentLicenses.V1' -or $licenses.ContainsCosmos -ne $false -or
   $licenses.ExcludesLegacyCollectedGraph -ne $true -or !$licenses.Files -or [int]$licenses.PackageCount -ne @($licenses.Packages).Count) {
    throw 'The complete independent application license manifest is required.'
}
Assert-IndependentHash (Get-IndependentFile $taskRoot 'Source/XFESystem.NativeRuntime/Application/packages.lock.json') $licenses.ApplicationLockSha256 'license application lock'
Assert-IndependentHash (Get-IndependentFile $taskRoot 'Tools/IndependentKernel/Runtime/NativeToolchain.json') $licenses.RuntimeToolchainLockSha256 'license runtime toolchain lock'
Assert-IndependentHash (Get-IndependentFile $taskRoot 'Tools/JintCleanupPatch/packages.lock.json') $licenses.JintPatchToolLockSha256 'license Jint patch tool lock'
Assert-IndependentHash (Get-IndependentFile $licensesRoot 'LicenseSources.json') $licenses.SourcesSha256 'license sources manifest'
foreach($binding in @(
    @('Tools/TlsEntropyPatch/Packages.lock.json','TlsEntropyPatchToolLockSha256'),
    @('Source/XFESystem.Tls/DependencyManifest.json','TlsDependencyManifestSha256'),
    @('Source/XFESystem.Tls/Packages.lock.json','TlsProjectLockSha256'),
    @('Source/XFESystem.NativeRuntime/Application/Security/Manifest.json','TrustedRootManifestSha256'),
    @('Source/XFESystem.NativeRuntime/Application/Security/MozillaRoots.pem','TrustedRootSnapshotSha256')
)) {
    $expected=$licenses.PSObject.Properties[$binding[1]]
    if(!$expected -or [string]$expected.Value -cnotmatch '^[a-f0-9]{64}$') {throw ('Missing TLS/root license source binding: '+$binding[1])}
    Assert-IndependentHash (Get-IndependentFile $taskRoot $binding[0]) ([string]$expected.Value) ('license '+$binding[0])
}
if($licenses.GuestAcceptancePassed -ne $false -or $licenses.NativeTlsAcceptancePassed -ne $false -or $licenses.FullReleaseQualified -ne $false) {
    throw 'License collection cannot assert guest TLS acceptance or full release qualification.'
}
$tlsLicense=@($licenses.Packages | Where-Object {$_.Id -ceq 'BouncyCastle.Cryptography'})
if($tlsLicense.Count -ne 1 -or $tlsLicense[0].Version -cne '2.7.0' -or !$tlsLicense[0].LicenseFiles -or
   $tlsLicense[0].DependencyManifestSha256 -cne $licenses.TlsDependencyManifestSha256) {
    throw 'The pinned BouncyCastle package and full license are required.'
}
$rootLicenseNames=@('Security/MozillaRoots-20260925.pem','Security/MozillaRoots-Manifest.json','Security/MozillaRoots-MPL-2.0.txt')
foreach($required in $rootLicenseNames) {
    if(@($licenses.Files | Where-Object {$_.Path -ceq $required}).Count -ne 1) {throw ('Missing trusted root source/license: '+$required)}
}
foreach($binding in @(
    @('Security/MozillaRoots-20260925.pem','TrustedRootSnapshotSha256'),
    @('Security/MozillaRoots-Manifest.json','TrustedRootManifestSha256')
)) {
    $entry=@($licenses.Files | Where-Object {$_.Path -ceq $binding[0]})[0]
    if($entry.Sha256 -cne $licenses.PSObject.Properties[$binding[1]].Value) {throw ('Collected trusted root source differs: '+$binding[0])}
}
$licenseNames=@()
foreach($entry in $licenses.Files) {
    if($licenseNames -contains $entry.Path) {throw ('Duplicate license path: '+$entry.Path)}
    $licenseNames+=([string]$entry.Path)
    $path=Get-IndependentFile $licensesRoot $entry.Path
    Assert-IndependentHash $path $entry.Sha256 ('license '+$entry.Path)
    if((Get-Item -LiteralPath $path).Length -ne $entry.Bytes) {throw ('License length differs: '+$entry.Path)}
}
if(!$OutputDirectory){$OutputDirectory=Join-Path $taskRoot 'dist'}
$outputRoot=[IO.Path]::GetFullPath($OutputDirectory)
[void][IO.Directory]::CreateDirectory($outputRoot)
$storageLabel=if($verified.ImageManifest.UsbWorkspace -eq $true){'USB'}else{'RAM'}
$packageId='XFESystem-'+$Edition+'-Independent-'+$storageLabel+'-'+$Version+'-'+[DateTimeOffset]::UtcNow.ToUnixTimeMilliseconds()+'-'+[Guid]::NewGuid().ToString('N').Substring(0,8)
$package=Join-Path $outputRoot $packageId
$zipPath=$package+'.zip'
if((Test-Path -LiteralPath $package) -or (Test-Path -LiteralPath $zipPath)){throw 'Refusing to overwrite an existing package or ZIP.'}
[void][IO.Directory]::CreateDirectory($package)
function Copy-IndependentBoundFile([string]$Source,[string]$Relative,[string]$Expected) {
    Assert-IndependentHash $Source $Expected ('package input '+$Relative)
    if([IO.Path]::IsPathRooted($Relative)){throw 'Package destination must be relative.'}
    $destination=[IO.Path]::GetFullPath((Join-Path $package $Relative))
    if(!$destination.StartsWith($package+[IO.Path]::DirectorySeparatorChar,[StringComparison]::OrdinalIgnoreCase)) {throw 'Package destination escaped the output directory.'}
    [void][IO.Directory]::CreateDirectory((Split-Path -Parent $destination))
    Copy-Item -LiteralPath $Source -Destination $destination
    Assert-IndependentHash $destination $Expected ('package copy '+$Relative)
}
try {
    Copy-IndependentBoundFile $verified.ImagePath 'System.img' $verified.Boot.ImageSha256
    Copy-IndependentBoundFile $verified.ImageManifestPath 'System.img.json' (Get-IndependentHash $verified.ImageManifestPath)
    Copy-IndependentBoundFile $verified.KernelPath 'Kernel.elf' $verified.Boot.KernelSha256
    Copy-IndependentBoundFile $verified.BootPath 'Validation/Boot.json' (Get-IndependentHash $verified.BootPath)
    Copy-IndependentBoundFile $verified.BuildPath 'Validation/BuildReceipt.json' $verified.Boot.BuildReceiptSha256
    Copy-IndependentBoundFile $verified.SnapshotPath 'Validation/SourceSnapshot.json' $verified.Boot.SourceSnapshotSha256
    Copy-IndependentBoundFile $hostPath 'Validation/Host.json' (Get-IndependentHash $hostPath)
    foreach($entry in $verified.Snapshot.PSObject.Properties) {
        Copy-IndependentBoundFile (Get-IndependentFile $taskRoot $entry.Name) ('SourceSnapshot/'+$entry.Name) ([string]$entry.Value)
    }
    foreach($entry in $hostProof.SourceHashes.PSObject.Properties) {
        Copy-IndependentBoundFile (Get-IndependentFile $taskRoot $entry.Name) ('HostSourceSnapshot/'+$entry.Name) ([string]$entry.Value)
    }
    foreach($artifact in $hostArtifacts) {Copy-IndependentBoundFile $artifact.Source $artifact.Destination $artifact.Sha256}
    foreach($file in Get-ChildItem -LiteralPath $licensesRoot -File -Recurse) {
        $relative=$file.FullName.Substring($licensesRoot.Length+1).Replace('\','/')
        Copy-IndependentBoundFile $file.FullName ('Licenses/'+$relative) (Get-IndependentHash $file.FullName)
    }
    foreach($firmware in @($verified.FirmwareCode,$verified.FirmwareVars)) {
        Copy-IndependentBoundFile $firmware ('Firmware/'+[IO.Path]::GetFileName($firmware)) (Get-IndependentHash $firmware)
    }
    [void][IO.Directory]::CreateDirectory((Join-Path $package 'Tools/IndependentKernel'))
    Copy-IndependentBoundFile (Join-Path $PSScriptRoot 'Open.ps1') 'Tools/IndependentKernel/Open.ps1' (Get-IndependentHash (Join-Path $PSScriptRoot 'Open.ps1'))
    Copy-IndependentBoundFile $PSCommandPath 'Tools/IndependentKernel/Package.ps1' (Get-IndependentHash $PSCommandPath)
    Copy-IndependentBoundFile (Join-Path $taskRoot 'THIRD_PARTY.md') 'ThirdParty.md' (Get-IndependentHash (Join-Path $taskRoot 'THIRD_PARTY.md'))
    if($verified.BingNativeHttpsPassed -eq $true) {
        Copy-IndependentBoundFile $verified.BingEvidencePath 'Validation/Guest/BingEvidence.json' $verified.BingEvidenceSha256
    }
    if($verified.Boot.GpuDiscoveryEvidence) {
        Copy-IndependentBoundFile (Get-IndependentFile (Split-Path -Parent $verified.BootPath) 'GpuDiscoveryEvidence.json') 'Validation/Guest/GpuDiscoveryEvidence.json' $verified.Boot.GpuDiscoveryEvidence.Sha256
    }
    if($verified.UsbStorageProofPath) {
        Copy-IndependentBoundFile $verified.UsbStorageProofPath 'Validation/UsbStorage/Result.json' $verified.Boot.UsbStorageProof.Sha256
        foreach($file in $verified.UsbStorageProof.EvidenceFiles) {
            Copy-IndependentBoundFile (Get-IndependentFile $verified.UsbStorageProofRoot $file.Path) ('Validation/UsbStorage/'+$file.Path) $file.Sha256
        }
    }
    foreach($file in Get-ChildItem -LiteralPath (Split-Path -Parent $verified.BootPath) -File) {
        if($file.Extension -notin @('.png','.log','.txt') -or ($file.Attributes -band [IO.FileAttributes]::ReparsePoint)) {continue}
        Copy-IndependentBoundFile $file.FullName ('Validation/Guest/'+$file.Name) (Get-IndependentHash $file.FullName)
    }
    [ordered]@{Kind='XfeIndependentFirmwareLock';Firmware=$verified.FirmwareLock.Firmware} | ConvertTo-Json -Depth 4 |
        Set-Content -LiteralPath (Join-Path $package 'Validation/Firmware.json') -Encoding UTF8
    @'
[CmdletBinding()]
param([string]$QemuPath,[ValidateSet('gtk','sdl')][string]$DisplayBackend='gtk',[switch]$Fullscreen,[switch]$FitToWindow,[switch]$NativePixels,[switch]$TraceConsoleRefresh,[switch]$PlanOnly)
$ErrorActionPreference='Stop'
& (Join-Path $PSScriptRoot 'Tools/IndependentKernel/Open.ps1') -Edition '__EDITION__' -ImagePath (Join-Path $PSScriptRoot 'System.img') -VerifiedBootResult (Join-Path $PSScriptRoot 'Validation/Boot.json') -QemuPath $QemuPath -DisplayBackend $DisplayBackend -Fullscreen:$Fullscreen -FitToWindow:$FitToWindow -NativePixels:$NativePixels -TraceConsoleRefresh:$TraceConsoleRefresh -PlanOnly:$PlanOnly
'@.Replace('__EDITION__',$Edition) | Set-Content -LiteralPath (Join-Path $package 'Start.ps1') -Encoding UTF8
    @'
# XFESystem 独立内核 RAM 实验版

此包使用自研 C# 内核/HAL/调度与 Microsoft .NET 10 NativeAOT 运行时,不包含 Cosmos 内核或运行时。完整第三方声明位于 Licenses;自研范围和外部引用见 ThirdParty.md。

文件保存在内存中,退出或关机后消失。当前执行一个 BSP,CPU 软件绘制,x87/SSE 上下文;没有持久化存储或独立进程隔离。

Validation/Boot.json 记录本包同一镜像的真实 QEMU 桌面、PS/2 输入和浏览器 DOM 验收;BrowserAcceptancePassed 字段单独说明 Monaco 验收结果。Validation/Host.json 与逐项 TRX/原生测试记录保留宿主结果,宿主通过不能替代来宾执行。

Validation/Boot.json 与 Validation/Guest/BingEvidence.json(仅通过时携带)记录独立 QEMU 来宾的原生 Bing HTTPS 验收;包清单 BingNativeHttpsPassed/NetworkAcceptancePassed 只绑定这份真实证据,不由网卡启用状态推断。其范围仅 QEMU e1000 82540EM、显式静态 NAT 地址、验证证书的 Bing HTML/DOM 和实际像素呈现;不表示完整 CSS/JavaScript 或 Windows 浏览器像素一致。FullCssParityVerified 仍为 false。

这是 RAM 实验版。实体启动、实体 USB HID 输入、实体网络/DHCP、CUDA/GPU 和完整稳定性均未验收,不能标为完整发行版。CMOS RTC 按 UTC 解释;实体机的 RTC 配置和准确性尚未验收。

在 Windows 安装 QEMU 后执行:

    powershell -NoProfile -ExecutionPolicy Bypass -File .\Start.ps1 -QemuPath "C:\Program Files\qemu\qemu-system-x86_64.exe"

默认打开 TCG / Q35 / x86_64 / 1 GiB 的 GTK 交互窗口,使用 Q35 内置 PS/2 键盘鼠标,RTC 设为 UTC。网络参数以已绑定的 NativeNetworkProfile 为准;启用时使用 QEMU user NAT/e1000 与显式静态地址,不使用宿主代理。可选择 -DisplayBackend sdl 或 -Fullscreen。启动前核验完整包、镜像、ELF、固件、验收记录及所有编译源码快照;每次复制镜像和固件变量到新的 build/IndependentKernel/Interactive-* 会话目录,串口日志位于同目录 Serial.log。关闭 QEMU 窗口结束。

源码与资源快照在 SourceSnapshot,宿主测试源码快照在 HostSourceSnapshot,所有文件 SHA256 在 Manifest.json。它们保存本次实际构建和测试的字节;完整复现命令与版本锁要求见 Reproduce.md。
'@ | Set-Content -LiteralPath (Join-Path $package 'Readme.md') -Encoding UTF8
    @'
# 复现与校验

在 XFESystem 仓库中使用 Manifest.json 的源码哈希核对 SourceSnapshot 中所有文件;保留仓库目录结构,按各 packages.lock.json 恢复固定依赖,工具版本锁位于 Tools/IndependentKernel/Runtime/NativeToolchain.json 与 Tools/CSharpBoot/BflatToolchain.json。

    powershell -NoProfile -ExecutionPolicy Bypass -File Tools/IndependentKernel/BuildSystem.ps1
    python Tools/IndependentKernel/TestBoot.py <新生成的Kernel.elf> --virtual-cpus 8 --desktop --browser --documents --bing --timeout 360
    powershell -NoProfile -ExecutionPolicy Bypass -File Tools/TestCSharp.ps1
    python Tools/IndependentKernel/CollectLicenses.py
    powershell -NoProfile -ExecutionPolicy Bypass -File Tools/IndependentKernel/Package.ps1 -ImagePath <通过的System.img> -VerifiedBootResult <通过的Result.json> -VerifiedHostResult <宿主Result.json>

编译、链接成功不等于运行验收;每次新建产物需要新 guest/host 记录。本包原始精确编译命令保存在 Validation/BuildReceipt.json;完整包与携带的源码快照、固件可通过下列命令只读核验:

    powershell -NoProfile -ExecutionPolicy Bypass -File Tools/IndependentKernel/Open.ps1 -ImagePath System.img -VerifiedBootResult Validation/Boot.json -ValidateOnly

SourceSnapshot 只保存实际编译输入,复现需要完整仓库中匹配的工具与锁文件。HostSourceSnapshot 保存实际宿主检查输入。各原始 JSON 的旧绝对路径用于出处记录;打包启动入口通过包内固定相对路径定位已验证文件。
'@ | Set-Content -LiteralPath (Join-Path $package 'Reproduce.md') -Encoding UTF8
    if($Edition -eq 'Console') {
        @'
# XFESystem Console 独立内核 RAM 实验版

这是独立构建的纯控制台系统,保留以前 Rust 控制台的黑底、彩色启动标题、文本提示符和键盘操作方式。系统内核仍为自研 C# 内核,运行时为 Microsoft .NET 10 NativeAOT;不启动图形桌面、窗口、浏览器或文档编辑器。

输入 help 查看命令。支持目录、RAM 文件读写、命令历史和光标编辑,也可运行内置 ConsoleIL 与 XFEConsole 示例。网络关闭。文件只保存在本次 RAM 会话,关机后消失。

在 Windows 安装 QEMU 后执行:

    powershell -NoProfile -ExecutionPolicy Bypass -File .\Start.ps1 -QemuPath "C:\Program Files\qemu\qemu-system-x86_64.exe"

默认打开 TCG / Q35 / x86_64 / 1 GiB 的 GTK 控制台窗口,使用 Q35 内置 PS/2 键盘。可选择 -DisplayBackend sdl 或 -Fullscreen。启动前核验镜像、内核、固件、实际来宾命令执行证据和全部源码快照。每次启动使用独立镜像副本,串口日志在 build/IndependentKernel/Interactive-Console-* 下。

Validation/Boot.json 记录本包同一镜像的真实 QEMU 键盘输入、RAM 文件读写、命令历史、光标编辑与帧缓冲证据;Validation/Host.json 和逐项 TRX/原生记录保存宿主检查结果。第三方许可位于 Licenses,自研范围见 ThirdParty.md。源码及资源快照位于 SourceSnapshot,宿主检查源码位于 HostSourceSnapshot,文件 SHA256 位于 Manifest.json。

这是 RAM 实验版,实体启动与输入、持久存储、SMP、GPU/CUDA 和长期稳定性仍未验收,FullReleaseQualified=false。
'@ | Set-Content -LiteralPath (Join-Path $package 'Readme.md') -Encoding UTF8
        @'
# 复现与校验

从完整 XFESystem 仓库按锁文件恢复依赖,并核对包内 SourceSnapshot 与 Manifest.json 的源码哈希。

    powershell -NoProfile -ExecutionPolicy Bypass -File Tools/IndependentKernel/BuildSystem.ps1 -Edition Console
    python Tools/IndependentKernel/TestBoot.py <新生成的Kernel.elf> --virtual-cpus 8 --console --timeout 360
    powershell -NoProfile -ExecutionPolicy Bypass -File Tools/TestCSharp.ps1
    python Tools/IndependentKernel/CollectLicenses.py
    powershell -NoProfile -ExecutionPolicy Bypass -File Tools/IndependentKernel/Package.ps1 -Edition Console -ImagePath <通过的System.img> -VerifiedBootResult <通过的Result.json> -VerifiedHostResult <宿主Result.json>

每次新建产物都需要新的 guest/host 记录。包内只读核验:

    powershell -NoProfile -ExecutionPolicy Bypass -File Tools/IndependentKernel/Open.ps1 -Edition Console -ImagePath System.img -VerifiedBootResult Validation/Boot.json -ValidateOnly

Validation/BuildReceipt.json 保存精确编译命令。SourceSnapshot 只保存实际编译输入,复现仍需要完整仓库及匹配的工具和锁文件。JSON 内旧绝对路径用于出处记录,包内启动入口使用固定相对路径。
'@ | Set-Content -LiteralPath (Join-Path $package 'Reproduce.md') -Encoding UTF8
    }
    Assert-IndependentSourceMap $verified.Snapshot $taskRoot 'final guest source snapshot'
    Assert-IndependentSourceMap $hostProof.SourceHashes $taskRoot 'final host source snapshot'
    $files=@(foreach($file in Get-ChildItem -LiteralPath $package -File -Recurse | Sort-Object FullName) {
        [ordered]@{Path=$file.FullName.Substring($package.Length+1).Replace('\','/');Bytes=$file.Length;Sha256=(Get-IndependentHash $file.FullName)}
    })
    if($verified.ImageManifest.UsbWorkspace -eq $true) {
        @'
# XFESystem USB 工作区实验版

此包只包含所选的一个系统。启动 U 盘可用时,X: 的文件和外观设置提交到 Workspace.bin 的双数据区,UsbFiles 对应启动 FAT32 卷的 UserFiles 文件夹。

run X:\UsbFiles\UsbHello.dll 可运行 U 盘普通 FAT 文件中的标准 .NET 控制台示例,仍受 ConsoleIL 指令与 API 范围限制。Workspace.bin 为 64 MiB 容器,两个数据区交替提交;现有每文件及工作区配额继续生效。Temporary 和 System/Diagnostics 是临时数据。

没有唯一匹配启动分区的可用 USB BOT 设备时,明确回退到 RAM,会话文件不保留。验证范围为 QEMU xHCI/USB BOT,实体 UAS、实体启动输入和掉电行为仍需实测;这不是完整发行版。第三方来源与许可见 Licenses。

Start.ps1 使用独立的虚拟 USB 工作盘;系统原始镜像和验证记录保留。Validation/UsbStorage/Result.json 记录两次真实冷启动、文件和设置回读、FAT 程序加载与实际 framebuffer 证据。
'@ | Set-Content -LiteralPath (Join-Path $package 'Readme.md') -Encoding UTF8
        $files=@(foreach($file in Get-ChildItem -LiteralPath $package -File -Recurse | Sort-Object FullName) {
            [ordered]@{Path=$file.FullName.Substring($package.Length+1).Replace('\','/');Bytes=$file.Length;Sha256=(Get-IndependentHash $file.FullName)}
        })
    }
    $manifest=[ordered]@{Kind=$(if($storageLabel -ceq 'USB'){if($Edition -eq 'Console'){'XfeIndependentUsbConsolePackage'}else{'XfeIndependentUsbDesktopPackage'}}else{if($Edition -eq 'Console'){'XfeIndependentRamConsolePackage'}else{'XfeIndependentRamDesktopPackage'}});Edition=$Edition;Version=$Version;ContainsCosmos=$false;
        RamOnly=[bool]$verified.Boot.RamOnly;StorageEnabled=[bool]$verified.Boot.StorageEnabled;FullReleaseQualified=$false;PhysicalHardwareAcceptancePassed=$false;
        UsbStorageAcceptancePassed=[bool]$verified.Boot.UsbStorageAcceptancePassed;
        UsbHidAcceptancePassed=$false;NetworkAcceptancePassed=($verified.BingNativeHttpsPassed -eq $true);GpuAcceptancePassed=$false;
        BingNativeHttpsPassed=($verified.BingNativeHttpsPassed -eq $true);FullCssParityVerified=$false;
        NetworkAcceptanceScope='Only image-bound QEMU e1000/static user NAT and validated native HTTPS Bing HTML/DOM/presentation when BingNativeHttpsPassed is true; physical NIC/DHCP/general web compatibility are unverified';
        NativeNetworkProfile=$verified.Boot.NativeNetworkProfile;
        GuestAcceptancePassed=$true;HostAcceptancePassed=$true;BrowserAcceptancePassed=[bool]$verified.Boot.BrowserAcceptancePassed;
        NoRenderFailures=[bool]$verified.NoRenderFailures;MonacoRasterPaintCompleted=[bool]$verified.MonacoRasterPaintCompleted;
        DocumentWorkflowPassed=[bool]$verified.DocumentWorkflowPassed;
        TerminalWorkflowPassed=[bool]$verified.TerminalWorkflowPassed;ConsoleAcceptancePassed=[bool]$verified.ConsoleAcceptancePassed;
        MonacoKeyboardEditedModel=[bool]$verified.MonacoKeyboardEditedModel;
        ImageSha256=$verified.Boot.ImageSha256;KernelSha256=$verified.Boot.KernelSha256;
        SourceSnapshotSha256=$verified.Boot.SourceSnapshotSha256;BootReceiptSha256=(Get-IndependentHash $verified.BootPath);
        HostReceiptSha256=(Get-IndependentHash $hostPath);LicenseManifestSha256=(Get-IndependentHash $licensesPath);
        Files=$files}
    $manifest | ConvertTo-Json -Depth 6 | Set-Content -LiteralPath (Join-Path $package 'Manifest.json') -Encoding UTF8
    # Exercise the relocated package's own verifier before creating the ZIP.
    $null=& (Join-Path $package 'Tools/IndependentKernel/Open.ps1') -Edition $Edition -ImagePath (Join-Path $package 'System.img') -VerifiedBootResult (Join-Path $package 'Validation/Boot.json') -ValidateOnly
    Compress-Archive -Path (Join-Path $package '*') -DestinationPath $zipPath -CompressionLevel Optimal
    Add-Type -AssemblyName System.IO.Compression.FileSystem
    $expectedEntries=[Collections.Generic.Dictionary[string,object]]::new([StringComparer]::Ordinal)
    foreach($file in $files){$expectedEntries.Add([string]$file.Path,$file)}
    $expectedEntries.Add('Manifest.json',[pscustomobject]@{Bytes=(Get-Item -LiteralPath (Join-Path $package 'Manifest.json')).Length;
        Sha256=(Get-IndependentHash (Join-Path $package 'Manifest.json'))})
    $zip= [IO.Compression.ZipFile]::OpenRead($zipPath)
    try {
        foreach($entry in $zip.Entries) {
            $name=$entry.FullName.Replace('\','/')
            if($name.EndsWith('/')){continue}
            if(!$expectedEntries.ContainsKey($name)){throw ('Unexpected or duplicate ZIP entry: '+$name)}
            $expected=$expectedEntries[$name]
            if($entry.Length -ne $expected.Bytes){throw ('ZIP entry length changed: '+$name)}
            $stream=$entry.Open();$sha=[Security.Cryptography.SHA256]::Create()
            try {$actual=[BitConverter]::ToString($sha.ComputeHash($stream)).Replace('-','').ToLowerInvariant()}
            finally {$stream.Dispose();$sha.Dispose()}
            if($actual -cne $expected.Sha256){throw ('ZIP readback SHA256 differs: '+$name)}
            [void]$expectedEntries.Remove($name)
        }
        if($expectedEntries.Count){throw ('ZIP is missing files: '+($expectedEntries.Keys -join ', '))}
    } finally {$zip.Dispose()}
    $receipt=[ordered]@{Kind='XfeIndependentKernelPackageReceipt';Edition=$Edition;Passed=$true;PackageDirectory=$package;ZipPath=$zipPath;
        ZipSha256=(Get-IndependentHash $zipPath);ManifestSha256=(Get-IndependentHash (Join-Path $package 'Manifest.json'));
        ImageSha256=$verified.Boot.ImageSha256;KernelSha256=$verified.Boot.KernelSha256;GuestAcceptancePassed=$true;
        HostAcceptancePassed=$true;RelocatedPackageVerificationPassed=$true;ZipReadbackPassed=$true;
        NoRenderFailures=[bool]$verified.NoRenderFailures;MonacoRasterPaintCompleted=[bool]$verified.MonacoRasterPaintCompleted;
        DocumentWorkflowPassed=[bool]$verified.DocumentWorkflowPassed;
        TerminalWorkflowPassed=[bool]$verified.TerminalWorkflowPassed;ConsoleAcceptancePassed=[bool]$verified.ConsoleAcceptancePassed;
        MonacoKeyboardEditedModel=[bool]$verified.MonacoKeyboardEditedModel;
        NetworkAcceptancePassed=($verified.BingNativeHttpsPassed -eq $true);BingNativeHttpsPassed=($verified.BingNativeHttpsPassed -eq $true);
        FullCssParityVerified=$false;
        FullReleaseQualified=$false;FinishedUtc=[DateTime]::UtcNow.ToString('o')}
    $receipt | ConvertTo-Json -Depth 5 | Set-Content -LiteralPath ($package+'.json') -Encoding UTF8
    Write-Host ('Independent RAM experiment package: '+$zipPath)
    return [pscustomobject]$receipt
} catch {
    [ordered]@{Kind='XfeIndependentKernelPackageReceipt';Edition=$Edition;Passed=$false;PackageDirectory=$package;Error=$_.Exception.Message} |
        ConvertTo-Json -Depth 4 | Set-Content -LiteralPath ($package+'.failure.json') -Encoding UTF8
    throw
}