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

XFESystem

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

公开
关注 0 Fork 0 Star 0
UTF-8
[CmdletBinding()]
param(
    [switch]$BootstrapOnly,
    [string[]]$RuntimeObjects = @(),
    [string]$RuntimePortReceipt,
    [string]$MathReceipt,
    [string]$ToolsRoot
)
$ErrorActionPreference = 'Stop'
$taskRoot = [IO.Path]::GetFullPath((Join-Path $PSScriptRoot '../..'))
if (!$ToolsRoot) { $ToolsRoot = Join-Path $taskRoot '.tools' }
$ToolsRoot = [IO.Path]::GetFullPath($ToolsRoot)
$sourceRoot = Join-Path $taskRoot 'Source/XFESystem.NativeKernel'
$buildId = 'Build-' + [DateTimeOffset]::UtcNow.ToUnixTimeMilliseconds() + '-' + [Guid]::NewGuid().ToString('N').Substring(0,8)
$outputRoot = Join-Path $taskRoot ('build/IndependentKernel/' + $buildId)
[void][IO.Directory]::CreateDirectory($outputRoot)
$receipt = [ordered]@{ Kind='XfeIndependentKernelBuild'; Target='x86_64-none'; Passed=$false;
    ContainsCosmos=$false; BootstrapOnly=[bool]$BootstrapOnly; FullDotNet10=$false;
    Stage='preflight'; SourceSha256=[ordered]@{}; ToolSha256=[ordered]@{}; Commands=@(); OutputRoot=$outputRoot }
function Get-TaskHash([string]$Path) { (Get-FileHash -LiteralPath $Path -Algorithm SHA256).Hash.ToLowerInvariant() }
function Invoke-TaskTool([string]$Tool, [string[]]$Arguments, [string]$Name) {
    $receipt.Commands += [ordered]@{Executable=$Tool;Arguments=$Arguments}
    $savedAction=$ErrorActionPreference
    try {
        $ErrorActionPreference='Continue'
        & $Tool @Arguments 2>&1 | Tee-Object -FilePath (Join-Path $outputRoot ($Name+'.log'))
        $taskExit=$LASTEXITCODE
    } finally { $ErrorActionPreference=$savedAction }
    if ($taskExit -ne 0) { throw ($Name+' failed with exit code '+$taskExit) }
}
$previousLib=[Environment]::GetEnvironmentVariable('BFLAT_LIB','Process')
$previousLd=[Environment]::GetEnvironmentVariable('BFLAT_LD','Process')
Push-Location $taskRoot
try {
    $compiler=Join-Path $ToolsRoot 'bflat-8.0.2/bflat.exe'
    $clang=Join-Path $ToolsRoot 'llvm/bin/clang.exe'
    $linker=Join-Path $ToolsRoot 'llvm/bin/ld.lld.exe'
    $nm=Join-Path $ToolsRoot 'llvm/bin/llvm-nm.exe'
    $objcopy=Join-Path $ToolsRoot 'llvm/bin/llvm-objcopy.exe'
    $compilerLock=Get-Content -LiteralPath (Join-Path $taskRoot 'Tools/CSharpBoot/BflatToolchain.json') -Raw -Encoding UTF8 | ConvertFrom-Json
    foreach($tool in @($compiler,$clang,$linker,$nm,$objcopy)) {
        if (!(Test-Path -LiteralPath $tool)) { throw ('Required compiler tool is missing: '+$tool) }
        $receipt.ToolSha256[$tool]=Get-TaskHash $tool
    }
    if ((Get-TaskHash $compiler) -cne $compilerLock.ToolSha256.'bflat.exe') { throw 'The locked bflat compiler differs.' }
    $zero=Join-Path $ToolsRoot 'bflat-8.0.2/lib/linux/x64/zerolib.dll'
    $receipt.ToolSha256[$zero]=Get-TaskHash $zero
    $csharp=@(Get-ChildItem -LiteralPath $sourceRoot -File -Filter '*.cs' | Sort-Object Name | Select-Object -ExpandProperty FullName)
    $csharp+=Join-Path $taskRoot 'Source/XFESystem.Boot/GpuContracts.cs'
    $native=@(Get-ChildItem -LiteralPath (Join-Path $sourceRoot 'Native') -File | Where-Object {$_.Extension -in '.c','.s'} | Sort-Object Name | Select-Object -ExpandProperty FullName)
    if ($BootstrapOnly) {
        $native+=Join-Path $taskRoot 'Source/XFESystem.NativeRuntime/Native/BasicLibc.c'
        $native+=Join-Path $taskRoot 'Source/XFESystem.NativeRuntime/Native/Stdio.c'
    }
    $script=Join-Path $sourceRoot 'linker.ld'
    if ($csharp.Count -eq 0 -or $native.Count -eq 0 -or !(Test-Path -LiteralPath $script)) { throw 'Independent kernel source files are incomplete.' }
    $headers=@(Get-ChildItem -LiteralPath (Join-Path $sourceRoot 'Native') -File -Filter '*.h' | Select-Object -ExpandProperty FullName)
    $profilePath=Join-Path $sourceRoot 'KernelProfile.json'
    $profile=Get-Content -LiteralPath $profilePath -Raw -Encoding UTF8 | ConvertFrom-Json
    if ($profile.Kind -cne 'XfeIndependentKernelConfiguration' -or $profile.Architecture -cne 'x86_64' -or
        $profile.ContainsCosmos -or !$profile.RamOnly -or $profile.StorageEnabled -or $profile.ExecutingCpuCount -ne 1) {
        throw 'Unsupported independent kernel configuration.'
    }
    $receipt.Configuration=$profile
    $boundFiles=@($csharp)+@($native)+@($headers)+@($script,$PSCommandPath,$profilePath)
    foreach($path in $boundFiles) {
        $relative=$path.Substring($taskRoot.Length+1).Replace('\','/')
        $receipt.SourceSha256[$relative]=Get-TaskHash $path
        if ([IO.File]::ReadAllText($path) -match '(?m)^\s*(using\s+Cosmos\.|#\s*include\s*[<"]Cosmos|<PackageReference\s+Include="Cosmos)') {
            throw ('Independent kernel has a Cosmos dependency: '+$relative)
        }
    }
    if (!$BootstrapOnly) {
        if (!$RuntimePortReceipt -and $RuntimeObjects.Count -eq 1) {
            $RuntimePortReceipt=Join-Path (Split-Path -Parent $RuntimeObjects[0]) 'PortReceipt.json'
        }
        if (!$RuntimePortReceipt) { throw 'A source-bound native runtime port receipt is required.' }
        $port=Get-Content -LiteralPath $RuntimePortReceipt -Raw -Encoding UTF8 | ConvertFrom-Json
        if ($port.Schema -cne 'XfeIndependentNativeRuntimePort1' -or $port.CosmosReferenced -or
            !$port.NativePortCompilationPassed -or !$port.RelocatableRuntimeLinkPassed -or
            $port.MicrosoftRuntimeVersion -cne '10.0.12' -or !$port.SourceSha256 -or
            (Get-TaskHash $port.CombinedObjectPath) -cne $port.CombinedObjectSha256 -or
            !$port.FinalLinkInputs -or !$port.FinalLinkInputsSha256) {
            throw 'Runtime objects must match the exact independently compiled source-bound port.'
        }
        if ($RuntimeObjects.Count -eq 1 -and [IO.Path]::GetFullPath($RuntimeObjects[0]) -ieq [IO.Path]::GetFullPath($port.CombinedObjectPath)) {
            # ld -r is useful for symbol inventory, but merged COMDAT unwind
            # sections must not become the final executable input. Link the
            # exact original managed/native objects and archives once.
            $RuntimeObjects=@($port.FinalLinkInputs)
        }
        if($RuntimeObjects.Count -ne $port.FinalLinkInputs.Count){throw 'Runtime link input count differs from its receipt.'}
        for($inputIndex=0;$inputIndex -lt $RuntimeObjects.Count;$inputIndex++) {
            $inputPath=[IO.Path]::GetFullPath($RuntimeObjects[$inputIndex])
            if($inputPath -ine [IO.Path]::GetFullPath($port.FinalLinkInputs[$inputIndex]) -or
                (Get-TaskHash $inputPath) -cne $port.FinalLinkInputsSha256.PSObject.Properties[$port.FinalLinkInputs[$inputIndex]].Value) {
                throw ('Runtime final link input differs: '+$inputPath)
            }
        }
        foreach($property in $port.SourceSha256.PSObject.Properties) {
            $path=[IO.Path]::GetFullPath((Join-Path $taskRoot $property.Name))
            if (!$path.StartsWith($taskRoot+[IO.Path]::DirectorySeparatorChar,[StringComparison]::OrdinalIgnoreCase) -or
                (Get-TaskHash $path) -cne $property.Value) { throw ('Runtime source changed: '+$property.Name) }
            $receipt.SourceSha256[$property.Name]=$property.Value
        }
        foreach($map in @($port.AssemblySha256,$port.RuntimeLibrariesSha256,$port.NativeObjectsSha256)) {
            if (!$map) { continue }
            foreach($property in $map.PSObject.Properties) {
                if ((Get-TaskHash $property.Name) -cne $property.Value) { throw ('Runtime input changed: '+$property.Name) }
            }
        }
        $receipt.ManagedRuntimeLinked=$true
        $receipt.RuntimePortReceipt=[ordered]@{Path=$RuntimePortReceipt;Sha256=(Get-TaskHash $RuntimePortReceipt);
            MicrosoftRuntimeVersion=$port.MicrosoftRuntimeVersion;MicrosoftSourceCommit=$port.MicrosoftSourceCommit;
            CombinedObjectSha256=$port.CombinedObjectSha256;RuntimeLibrariesSha256=$port.RuntimeLibrariesSha256;
            FinalLinkInputsSha256=$port.FinalLinkInputsSha256;RelocatableObjectUsedForFinalLink=$false}
    }
    Remove-Item Env:BFLAT_LIB -ErrorAction SilentlyContinue
    Remove-Item Env:BFLAT_LD -ErrorAction SilentlyContinue
    $receipt.Stage='compile-csharp'
    $managedObject=Join-Path $outputRoot 'KernelCoreRaw.o'
    $arguments=@('build')+$csharp+@('--os:linux','--arch:x64','--stdlib:zero','--target:Shared','--deterministic','--no-debug-info','-Ot','-c','-x',('-o:'+$managedObject),'-i:xfe_native')
    if (!$BootstrapOnly) { $arguments+=@('--define','XFE_DOTNET_RUNTIME') }
    Invoke-TaskTool $compiler $arguments 'CSharpCompile'
    # Zero has deliberately minimal Rhp helpers. Isolate every one of its
    # symbols and metadata sections so the full Microsoft runtime can never
    # accidentally resolve to those helpers or register the Zero module.
    $defined=@(& $nm --defined-only --extern-only --just-symbol-name $managedObject)
    if($LASTEXITCODE -ne 0){throw 'Cannot inspect bootstrap exports.'}
    $undefined=@(& $nm --undefined-only --just-symbol-name $managedObject)
    if($LASTEXITCODE -ne 0){throw 'Cannot inspect bootstrap imports.'}
    $prefixed=Join-Path $outputRoot 'KernelCorePrefixed.o'
    Invoke-TaskTool $objcopy @('--prefix-symbols=XfeZero_','--rename-section','__modules=__xfe_zero_modules','--rename-section','__managedcode=__xfe_zero_managedcode','--rename-section','__unbox=__xfe_zero_unbox',$managedObject,$prefixed) 'IsolateZeroRuntime'
    $renames=Join-Path $outputRoot 'BootstrapSymbols.txt'
    $restored=@($defined+$undefined | Where-Object {$_ -match '^(xfe_|XfeKernelMain$|XfeHandleInterrupt$|XfeRuntimeStart$)'} | Sort-Object -Unique | ForEach-Object {'XfeZero_'+$_+' '+$_})
    $restored+=@('XfeZero_SystemNative_Abort xfe_zero_abort','XfeZero_SystemNative_Malloc xfe_zero_malloc')
    # Large value-only GPU discovery records generate compiler libc intrinsics.
    # Bind byte-range operations to our freestanding C implementation, never to
    # an isolated managed helper or to an OS libc. No object ABI crosses here.
    $restored+=@('XfeZero_memcpy memcpy','XfeZero_memset memset','XfeZero_memmove memmove')
    $restored | Set-Content -LiteralPath $renames -Encoding ASCII
    $isolated=Join-Path $outputRoot 'KernelCore.o'
    Invoke-TaskTool $objcopy @(('--redefine-syms='+$renames),$prefixed,$isolated) 'RestoreKernelAbi'
    $objects=@($isolated)
    $receipt.Stage='compile-native'
    foreach($path in $native) {
        $object=Join-Path $outputRoot ([IO.Path]::GetFileName($path)+'.o')
        $arguments=@('--target=x86_64-unknown-none-elf','-ffreestanding','-fno-builtin','-fno-stack-protector','-fasynchronous-unwind-tables','-fno-pic','-fno-pie','-mno-red-zone','-mcmodel=kernel','-O2','-g','-c',$path,'-o',$object)
        Invoke-TaskTool $clang $arguments ([IO.Path]::GetFileName($path))
        $objects+=$object
    }
    if (!$BootstrapOnly -and $RuntimeObjects.Count -eq 0) { throw 'A complete native runtime bridge is required. BootstrapOnly is an explicit, limited diagnostic build, not the desktop system.' }
    foreach($path in $RuntimeObjects) {
        $runtimeObject=[IO.Path]::GetFullPath($path)
        if (!(Test-Path -LiteralPath $runtimeObject)) { throw ('Runtime object missing: '+$runtimeObject) }
        $objects+=$runtimeObject
        $receipt.ToolSha256[$runtimeObject]=Get-TaskHash $runtimeObject
    }
    if (!$MathReceipt) {
        $latestMath=Get-ChildItem -LiteralPath (Join-Path $taskRoot 'build/IndependentKernel') -Directory -Filter 'Math-*' |
            Sort-Object Name -Descending | Where-Object {Test-Path -LiteralPath (Join-Path $_.FullName 'BuildReceipt.json')} | Select-Object -First 1
        if (!$latestMath) { throw 'Build the pinned external mathematical library with Tools/IndependentKernel/Runtime/BuildMath.py first.' }
        $MathReceipt=Join-Path $latestMath.FullName 'BuildReceipt.json'
    }
    $math=Get-Content -LiteralPath $MathReceipt -Raw -Encoding UTF8 | ConvertFrom-Json
    if ($math.Kind -cne 'XfeExternalMathLibraryBuild' -or !$math.Passed -or $math.ContainsCosmos -or
        $math.ContainsMuslOperatingSystemCode -or $math.ArchiveSha256 -cne 'a9a118bbe84d8764da0ea0d28b3ab3fae8477fc7e4085d90102b8596fc7c75e4' -or
        (Get-TaskHash $math.LibraryPath) -cne $math.LibrarySha256) { throw 'Invalid external math build receipt.' }
    if ($objects -notcontains $math.LibraryPath) { $objects+=$math.LibraryPath }
    $receipt.ExternalMath=[ordered]@{Version=$math.Version;ArchiveUrl=$math.ArchiveUrl;ArchiveSha256=$math.ArchiveSha256;
        LibrarySha256=$math.LibrarySha256;ReceiptSha256=(Get-TaskHash $MathReceipt);ContainsOperatingSystemCode=$false}
    $receipt.SourceSha256['Tools/IndependentKernel/Runtime/BuildMath.py']=Get-TaskHash (Join-Path $taskRoot 'Tools/IndependentKernel/Runtime/BuildMath.py')
    $receipt.Stage='link'
    $kernel=Join-Path $outputRoot 'Kernel.elf'
    Invoke-TaskTool $linker (@('-m','elf_x86_64','-nostdlib','-static','--gc-sections','--eh-frame-hdr','--error-limit=0','-z','max-page-size=4096','-T',$script)+$objects+@('-o',$kernel)) 'Link'
    $symbols=@(& $nm --undefined-only $kernel)
    if ($LASTEXITCODE -ne 0) { throw 'Cannot inspect kernel imports.' }
    $optionalBootstrap=@('XfeRuntimeDetachThread','XfeRuntimeTlsCreate','XfeRuntimeTlsRelease','XfeRuntimeTryHijack','XfeRuntimeDispatchHardwareFault')
    $invalidImports=@($symbols | Where-Object {
        -not ($BootstrapOnly -and $_ -match '^\s+w\s+(\S+)\s*$' -and $optionalBootstrap -contains $Matches[1])
    })
    if ($invalidImports.Count) { throw ('The freestanding kernel has unresolved imports: '+($invalidImports -join ', ')) }
    $receipt.OptionalAbsentRuntimeServices=@($symbols)
    & $nm --defined-only $kernel | Set-Content -LiteralPath (Join-Path $outputRoot 'Symbols.txt') -Encoding UTF8
    if ($LASTEXITCODE -ne 0) { throw 'Cannot inspect final kernel symbols.' }
    if ([IO.File]::ReadAllText((Join-Path $outputRoot 'Symbols.txt')) -match 'Cosmos[._]') { throw 'Final kernel symbols contain Cosmos.' }
    $bytes=[IO.File]::ReadAllBytes($kernel)
    if ($bytes.Length -lt 64 -or $bytes[0] -ne 127 -or $bytes[1] -ne 69 -or $bytes[2] -ne 76 -or $bytes[3] -ne 70 -or
        $bytes[4] -ne 2 -or [BitConverter]::ToUInt16($bytes,16) -ne 2 -or [BitConverter]::ToUInt16($bytes,18) -ne 62) { throw 'Expected an executable x86_64 ELF.' }
    foreach($entry in $receipt.SourceSha256.GetEnumerator()) {
        if ((Get-TaskHash (Join-Path $taskRoot $entry.Key)) -cne $entry.Value) { throw ('Source changed during compilation: '+$entry.Key) }
    }
    $receipt.KernelPath=$kernel
    $receipt.KernelSha256=Get-TaskHash $kernel
    $receipt.StandardLibrary=if($BootstrapOnly){'bflat Zero 8.0.2 (MIT), bootstrap-only diagnostic'}else{'bflat Zero 8.0.2 for the isolated kernel core; Microsoft .NET NativeAOT 10.0.12 GC/BCL through the independently implemented PAL. Full API compatibility is not claimed.'}
    $receipt.Stage='built';$receipt.Passed=$true
    $receipt | ConvertTo-Json -Depth 12 | Set-Content -LiteralPath ($kernel+'.json') -Encoding UTF8
    $receipt | ConvertTo-Json -Depth 12 | Set-Content -LiteralPath (Join-Path $outputRoot 'BuildReceipt.json') -Encoding UTF8
    Write-Host ('Independent kernel build: '+$kernel)
} catch {
    $receipt.Error=$_.Exception.Message
    $receipt | ConvertTo-Json -Depth 12 | Set-Content -LiteralPath (Join-Path $outputRoot 'Failure.json') -Encoding UTF8
    throw
} finally {
    [Environment]::SetEnvironmentVariable('BFLAT_LIB',$previousLib,'Process')
    [Environment]::SetEnvironmentVariable('BFLAT_LD',$previousLd,'Process')
    Pop-Location
}