Compare commits
17 Commits
8ceb38c3dd
...
fix/brandi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f44fa150e2 | ||
| dfae1f136b | |||
|
|
74e48aa1e5 | ||
| a6ac6ce355 | |||
|
|
9832121dbb | ||
| d0a5925652 | |||
|
|
e91c4de7ed | ||
| 51ab88b1f8 | |||
|
|
709744d533 | ||
|
|
ddd8784b56 | ||
| 226a823c68 | |||
|
|
67befa56df | ||
|
|
13df66d137 | ||
| 541a17c792 | |||
|
|
9fa613b8c1 | ||
| 8f61d5fb61 | |||
|
|
09e1f94b7d |
11
.gitattributes
vendored
Normal file
11
.gitattributes
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
# Keep binary assets verbatim (no EOL/charset normalization on checkout).
|
||||
*.sys binary
|
||||
*.cat binary
|
||||
*.exe binary
|
||||
*.dll binary
|
||||
*.iso binary
|
||||
*.png binary
|
||||
*.jpg binary
|
||||
*.ico binary
|
||||
*.cab binary
|
||||
windows/drivers/** binary
|
||||
@@ -184,6 +184,15 @@ jobs:
|
||||
# RUNNER_TEMP is per-job/ephemeral. Keep the latest validated build at a
|
||||
# stable path so it can be retrieved (e.g. for VM boot-testing) out of band.
|
||||
New-Item -ItemType Directory -Force 'C:\silvermetal\out' | Out-Null
|
||||
# The ISO is already built + validated; free the build working set (extracted ISO
|
||||
# tree + the mounted/expanded install.wim + the 5GB base ISO) BEFORE the ~5GB persist
|
||||
# copy, or the single-volume runner runs out of space mid-copy. The ISO itself lives
|
||||
# in RUNNER_TEMP\out (untouched) and the SBOM/SHA uploads read from there too.
|
||||
$before = [math]::Round((Get-PSDrive C).Free/1GB,1)
|
||||
Remove-Item "$env:RUNNER_TEMP\smbuild" -Recurse -Force -ErrorAction SilentlyContinue
|
||||
Remove-Item "$env:RUNNER_TEMP\base.iso" -Force -ErrorAction SilentlyContinue
|
||||
$after = [math]::Round((Get-PSDrive C).Free/1GB,1)
|
||||
Write-Host " freed build working set: C: ${before}GB -> ${after}GB before persist"
|
||||
Copy-Item "$env:RUNNER_TEMP\out\*" 'C:\silvermetal\out\' -Force
|
||||
Get-ChildItem 'C:\silvermetal\out' | ForEach-Object { Write-Host $_.Name }
|
||||
|
||||
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -68,3 +68,7 @@ coverage/
|
||||
|
||||
# SBOM intermediates (final SBOMs are committed; intermediates are not)
|
||||
sbom/work/
|
||||
|
||||
# Driver binaries (e.g. virtio NetKVM netkvmp.exe) must be tracked despite the global
|
||||
# *.exe / *.msi ignores above -- they are referenced by the .inf and DISM needs them.
|
||||
!windows/drivers/**
|
||||
|
||||
@@ -1,5 +1,68 @@
|
||||
#Requires -Version 5.1
|
||||
$ErrorActionPreference='SilentlyContinue'
|
||||
# Register the inbox App Installer if present, else nothing to do (offline image w/o it).
|
||||
# Provision winget (the App Installer) when absent. Windows IoT Enterprise LTSC
|
||||
# ships WITHOUT the inbox Microsoft.DesktopAppInstaller package, so re-registering
|
||||
# it is not enough - we download and install it (plus dependencies) online at apply
|
||||
# time. Best-effort and idempotent: exit 0 if winget ends up available, else 1.
|
||||
$ErrorActionPreference = 'SilentlyContinue'
|
||||
|
||||
function Test-Winget {
|
||||
return [bool](Get-Command winget -ErrorAction SilentlyContinue)
|
||||
}
|
||||
|
||||
# Fast path 1: winget already on PATH.
|
||||
if (Test-Winget) { exit 0 }
|
||||
|
||||
# Fast path 2: an inbox App Installer package is present - just re-register it.
|
||||
Get-AppxPackage -AllUsers Microsoft.DesktopAppInstaller |
|
||||
ForEach-Object { Add-AppxPackage -DisableDevelopmentMode -Register "$($_.InstallLocation)\AppXManifest.xml" }
|
||||
ForEach-Object { Add-AppxPackage -DisableDevelopmentMode -Register "$($_.InstallLocation)\AppXManifest.xml" }
|
||||
if (Test-Winget) { exit 0 }
|
||||
|
||||
# Slow path: download + install the App Installer and its dependencies online.
|
||||
$temp = $env:TEMP
|
||||
$bundlePath = Join-Path $temp 'Microsoft.DesktopAppInstaller.msixbundle'
|
||||
$vclibsPath = Join-Path $temp 'Microsoft.VCLibs.x64.14.00.Desktop.appx'
|
||||
$uixamlNupkg = Join-Path $temp 'microsoft.ui.xaml.2.8.6.nupkg'
|
||||
$uixamlExtract = Join-Path $temp 'uixaml.2.8.6'
|
||||
$uixamlAppx = Join-Path $uixamlExtract 'tools\AppX\x64\Release\Microsoft.UI.Xaml.2.8.appx'
|
||||
|
||||
$bundleUrl = 'https://aka.ms/getwinget'
|
||||
$vclibsUrl = 'https://aka.ms/Microsoft.VCLibs.x64.14.00.Desktop.appx'
|
||||
$uixamlUrl = 'https://globalcdn.nuget.org/packages/microsoft.ui.xaml.2.8.6.nupkg'
|
||||
|
||||
function Get-File {
|
||||
param([string]$Url, [string]$Destination)
|
||||
try {
|
||||
Invoke-WebRequest -Uri $Url -OutFile $Destination -UseBasicParsing
|
||||
return (Test-Path $Destination)
|
||||
} catch {
|
||||
return $false
|
||||
}
|
||||
}
|
||||
|
||||
# Download the App Installer bundle (required).
|
||||
if (-not (Get-File -Url $bundleUrl -Destination $bundlePath)) { exit 1 }
|
||||
|
||||
# Download the VCLibs desktop dependency (required).
|
||||
if (-not (Get-File -Url $vclibsUrl -Destination $vclibsPath)) { exit 1 }
|
||||
|
||||
# Download the UI.Xaml 2.8 nuget package (a .zip) and extract the appx from it.
|
||||
if (-not (Get-File -Url $uixamlUrl -Destination $uixamlNupkg)) { exit 1 }
|
||||
try {
|
||||
if (Test-Path $uixamlExtract) { Remove-Item -Path $uixamlExtract -Recurse -Force }
|
||||
Add-Type -AssemblyName System.IO.Compression.FileSystem
|
||||
[System.IO.Compression.ZipFile]::ExtractToDirectory($uixamlNupkg, $uixamlExtract)
|
||||
} catch {
|
||||
exit 1
|
||||
}
|
||||
if (-not (Test-Path $uixamlAppx)) { exit 1 }
|
||||
|
||||
# Install order: VCLibs dependency, then UI.Xaml dependency, then the bundle with
|
||||
# both supplied as DependencyPath. Per-user Add-AppxPackage (toolbox runs as the
|
||||
# real admin user at first logon).
|
||||
Add-AppxPackage -Path $vclibsPath
|
||||
Add-AppxPackage -Path $uixamlAppx
|
||||
Add-AppxPackage -Path $bundlePath -DependencyPath $vclibsPath, $uixamlAppx
|
||||
|
||||
# Final re-check.
|
||||
if (Test-Winget) { exit 0 }
|
||||
exit 1
|
||||
|
||||
@@ -42,6 +42,14 @@ function Write-Stage { param($m) Write-Host "==> $m" -ForegroundColor Cyan }
|
||||
|
||||
if ($Mode -eq 'Offline' -and -not $MountPath) { throw 'Offline mode requires -MountPath.' }
|
||||
|
||||
# Resolve the manifest/assets robustly. The param defaults reference $PSScriptRoot,
|
||||
# which can come back unrooted when this script is launched via -File from
|
||||
# SetupComplete.cmd (the online re-apply crashed looking for C:\branding.manifest.json,
|
||||
# wiping all branding after OOBE). Fall back to the script's own directory.
|
||||
$scriptDir = if ($PSScriptRoot) { $PSScriptRoot } else { Split-Path -Parent $MyInvocation.MyCommand.Path }
|
||||
if (-not (Test-Path -LiteralPath $Manifest)) { $Manifest = Join-Path $scriptDir 'branding.manifest.json' }
|
||||
if (-not (Test-Path -LiteralPath $AssetsDir)) { $AssetsDir = Join-Path $scriptDir 'assets' }
|
||||
|
||||
$m = Get-Content $Manifest -Raw | ConvertFrom-Json
|
||||
|
||||
|
||||
|
||||
@@ -1,375 +1,375 @@
|
||||
;-------------------------------------------------------------------------------
|
||||
;Copyright (c) 2008-2021 Red Hat Inc.
|
||||
;
|
||||
;
|
||||
;Module Name:
|
||||
; netkvm.inf
|
||||
;
|
||||
; VirtIO Ethernet Adapter
|
||||
;
|
||||
;-------------------------------------------------------------------------------
|
||||
;Installation Notes:
|
||||
; Step by step driver installation wiki:
|
||||
; https://github.com/virtio-win/kvm-guest-drivers-windows/wiki/Driver-installation
|
||||
;
|
||||
|
||||
[version]
|
||||
Signature = "$Windows NT$"
|
||||
Class = Net
|
||||
CatalogFile = netkvm.cat
|
||||
ClassGUID = {4d36e972-e325-11ce-bfc1-08002be10318}
|
||||
Provider=%VENDOR%
|
||||
DriverVer = 07/09/2025,100.101.104.28500
|
||||
DriverPackageType = PlugAndPlay
|
||||
DriverPackageDisplayName = %kvmnet6.DeviceDesc%
|
||||
PnpLockDown=1
|
||||
|
||||
[Manufacturer]
|
||||
%VENDOR% = NetKVM, NTamd64.10.0...16299
|
||||
|
||||
[NetKVM.NTamd64.10.0...16299]
|
||||
%kvmnet6.DeviceDesc% = kvmnet6.ndi, PCI\VEN_1AF4&DEV_1000&SUBSYS_00011AF4&REV_00, PCI\VEN_1AF4&DEV_1000
|
||||
%kvmnet6.DeviceDesc% = kvmnet6.ndi, PCI\VEN_1AF4&DEV_1041&SUBSYS_11001AF4&REV_01, PCI\VEN_1AF4&DEV_1041
|
||||
|
||||
[kvmnet6.ndi.hw]
|
||||
AddReg = kvmnet6.EnableMSI
|
||||
|
||||
[kvmnet6.EnableMSI]
|
||||
;HKR, "Interrupt Management",, 0x00000010
|
||||
;HKR, "Interrupt Management\MessageSignaledInterruptProperties",, 0x00000010
|
||||
HKR, "Interrupt Management\MessageSignaledInterruptProperties", MSISupported, 0x00010001, 1
|
||||
HKR, "Interrupt Management\MessageSignaledInterruptProperties", MessageNumberLimit, 0x00010001, 2048
|
||||
;HKR, "Interrupt Management\Affinity Policy",, 0x00000010
|
||||
HKR, "Interrupt Management\Affinity Policy", DevicePolicy, 0x00010001, 0
|
||||
HKR, "Interrupt Management\Affinity Policy", DevicePriority, 0x00010001, 2
|
||||
|
||||
[kvmnet6.ndi]
|
||||
Characteristics = 0x84 ; NCF_PHYSICAL | NCF_HAS_UI
|
||||
BusType = 5 ; PCI
|
||||
AddReg = kvmnet6.Reg, Parameters
|
||||
CopyFiles = kvmnet6.CopyFiles, netkvmp.CopyFiles
|
||||
*IfType = 6
|
||||
*MediaType = 0 ; NdisMedium802_3
|
||||
*PhysicalMediaType = 0 ; NdisPhysicalMediumUnspecified
|
||||
|
||||
[kvmnet6.ndi.Services]
|
||||
AddService = netkvm, 2, kvmnet6.Service, kvmnet6.EventLog
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
; Red Hat ParaVirtualized Miniport Common
|
||||
;-----------------------------------------------------------------------------
|
||||
[Parameters]
|
||||
|
||||
HKR, Ndi\Params\Priority, ParamDesc, 0, %Priority%
|
||||
HKR, Ndi\Params\Priority, Default, 0, "1"
|
||||
HKR, Ndi\Params\Priority, type, 0, "enum"
|
||||
HKR, Ndi\Params\Priority\enum, "1", 0, %Enable%
|
||||
HKR, Ndi\Params\Priority\enum, "0", 0, %Disable%
|
||||
|
||||
HKR, Ndi\Params\*PriorityVLANTag, ParamDesc, 0, %PriorityVlanTag%
|
||||
HKR, Ndi\Params\*PriorityVLANTag, Default, 0, "3"
|
||||
HKR, Ndi\Params\*PriorityVLANTag, type, 0, "enum"
|
||||
HKR, Ndi\Params\*PriorityVLANTag\enum, "3", 0, %Priority_Vlan%
|
||||
HKR, Ndi\Params\*PriorityVLANTag\enum, "2", 0, %VLan%
|
||||
HKR, Ndi\Params\*PriorityVLANTag\enum, "1", 0, %PriorityOnly%
|
||||
HKR, Ndi\Params\*PriorityVLANTag\enum, "0", 0, %Disable%
|
||||
|
||||
HKR, Ndi\params\VlanID, ParamDesc, 0, %VLan_ID%
|
||||
HKR, Ndi\params\VlanID, type, 0, "long"
|
||||
HKR, Ndi\params\VlanID, default, 0, "0"
|
||||
HKR, Ndi\params\VlanID, min, 0, "0"
|
||||
HKR, Ndi\params\VlanID, max, 0, "4094"
|
||||
|
||||
HKR, Ndi\Params\DoLog, ParamDesc, 0, %EnableLogging%
|
||||
HKR, Ndi\Params\DoLog, Default, 0, "1"
|
||||
HKR, Ndi\Params\DoLog, type, 0, "enum"
|
||||
HKR, Ndi\Params\DoLog\enum, "1", 0, %Enable%
|
||||
HKR, Ndi\Params\DoLog\enum, "0", 0, %Disable%
|
||||
|
||||
HKR, Ndi\params\DebugLevel, ParamDesc, 0, %DebugLevel%
|
||||
HKR, Ndi\params\DebugLevel, type, 0, "int"
|
||||
HKR, Ndi\params\DebugLevel, default, 0, "0"
|
||||
HKR, Ndi\params\DebugLevel, min, 0, "0"
|
||||
HKR, Ndi\params\DebugLevel, max, 0, "8"
|
||||
HKR, Ndi\params\DebugLevel, step, 0, "1"
|
||||
|
||||
HKR, Ndi\params\*JumboPacket, ParamDesc, 0, %JumboPacket%
|
||||
HKR, Ndi\params\*JumboPacket, type, 0, "long"
|
||||
HKR, Ndi\params\*JumboPacket, default, 0, "1514"
|
||||
HKR, Ndi\params\*JumboPacket, min, 0, "590"
|
||||
HKR, Ndi\params\*JumboPacket, max, 0, "65500"
|
||||
HKR, Ndi\params\*JumboPacket, step, 0, "1"
|
||||
|
||||
HKR, Ndi\params\TxCapacity, ParamDesc, 0, %TxCapacity%
|
||||
HKR, Ndi\params\TxCapacity, type, 0, "enum"
|
||||
HKR, Ndi\params\TxCapacity, default, 0, "1024"
|
||||
HKR, Ndi\Params\TxCapacity\enum, "16", 0, %String_16%
|
||||
HKR, Ndi\Params\TxCapacity\enum, "32", 0, %String_32%
|
||||
HKR, Ndi\Params\TxCapacity\enum, "64", 0, %String_64%
|
||||
HKR, Ndi\Params\TxCapacity\enum, "128", 0, %String_128%
|
||||
HKR, Ndi\Params\TxCapacity\enum, "256", 0, %String_256%
|
||||
HKR, Ndi\Params\TxCapacity\enum, "512", 0, %String_512%
|
||||
HKR, Ndi\Params\TxCapacity\enum, "1024", 0, %String_1024%
|
||||
|
||||
HKR, Ndi\params\RxCapacity, ParamDesc, 0, %RxCapacity%
|
||||
HKR, Ndi\params\RxCapacity, type, 0, "enum"
|
||||
HKR, Ndi\params\RxCapacity, default, 0, "1024"
|
||||
HKR, Ndi\Params\RxCapacity\enum, "16", 0, %String_16%
|
||||
HKR, Ndi\Params\RxCapacity\enum, "32", 0, %String_32%
|
||||
HKR, Ndi\Params\RxCapacity\enum, "64", 0, %String_64%
|
||||
HKR, Ndi\Params\RxCapacity\enum, "128", 0, %String_128%
|
||||
HKR, Ndi\Params\RxCapacity\enum, "256", 0, %String_256%
|
||||
HKR, Ndi\Params\RxCapacity\enum, "512", 0, %String_512%
|
||||
HKR, Ndi\Params\RxCapacity\enum, "1024", 0, %String_1024%
|
||||
HKR, Ndi\Params\RxCapacity\enum, "2048", 0, %String_2048%
|
||||
HKR, Ndi\Params\RxCapacity\enum, "4096", 0, %String_4096%
|
||||
|
||||
HKR, Ndi\Params\SeparateTail, ParamDesc, 0, %SeparateTail%
|
||||
HKR, Ndi\Params\SeparateTail, Default, 0, "1"
|
||||
HKR, Ndi\Params\SeparateTail, type, 0, "enum"
|
||||
HKR, Ndi\Params\SeparateTail\enum, "1", 0, %Enable%
|
||||
HKR, Ndi\Params\SeparateTail\enum, "0", 0, %Disable%
|
||||
|
||||
HKR, Ndi\Params\FastInit, ParamDesc, 0, %FastInit%
|
||||
HKR, Ndi\Params\FastInit, Default, 0, "1"
|
||||
HKR, Ndi\Params\FastInit, type, 0, "enum"
|
||||
HKR, Ndi\Params\FastInit\enum, "1", 0, %Enable%
|
||||
HKR, Ndi\Params\FastInit\enum, "0", 0, %Disable%
|
||||
|
||||
HKR, Ndi\params\NetworkAddress, ParamDesc, 0, %NetworkAddress%
|
||||
HKR, Ndi\params\NetworkAddress, type, 0, "edit"
|
||||
HKR, Ndi\params\NetworkAddress, Optional, 0, "1"
|
||||
|
||||
HKR, Ndi\Params\OffLoad.TxChecksum, ParamDesc, 0, %OffLoad.TxChecksum%
|
||||
HKR, Ndi\Params\OffLoad.TxChecksum, Default, 0, "31"
|
||||
HKR, Ndi\Params\OffLoad.TxChecksum, type, 0, "enum"
|
||||
HKR, Ndi\Params\OffLoad.TxChecksum\enum, "31", 0, %All%
|
||||
HKR, Ndi\Params\OffLoad.TxChecksum\enum, "27", 0, %TCPUDPAll%
|
||||
HKR, Ndi\Params\OffLoad.TxChecksum\enum, "3", 0, %TCPUDPv4%
|
||||
HKR, Ndi\Params\OffLoad.TxChecksum\enum, "1", 0, %TCPv4%
|
||||
HKR, Ndi\Params\OffLoad.TxChecksum\enum, "0", 0, %Disable%
|
||||
|
||||
HKR, Ndi\Params\OffLoad.TxLSO, ParamDesc, 0, %OffLoad.TxLSO%
|
||||
HKR, Ndi\Params\OffLoad.TxLSO, Default, 0, "2"
|
||||
HKR, Ndi\Params\OffLoad.TxLSO, type, 0, "enum"
|
||||
HKR, Ndi\Params\OffLoad.TxLSO\enum, "2", 0, %Maximal%
|
||||
HKR, Ndi\Params\OffLoad.TxLSO\enum, "1", 0, %IPv4%
|
||||
HKR, Ndi\Params\OffLoad.TxLSO\enum, "0", 0, %Disable%
|
||||
|
||||
HKR, Ndi\Params\OffLoad.RxCS, ParamDesc, 0, %OffLoad.RxCS%
|
||||
HKR, Ndi\Params\OffLoad.RxCS, Default, 0, "31"
|
||||
HKR, Ndi\Params\OffLoad.RxCS, type, 0, "enum"
|
||||
HKR, Ndi\Params\OffLoad.RxCS\enum, "31", 0, %All%
|
||||
HKR, Ndi\Params\OffLoad.RxCS\enum, "27", 0, %TCPUDPAll%
|
||||
HKR, Ndi\Params\OffLoad.RxCS\enum, "3", 0, %TCPUDPv4%
|
||||
HKR, Ndi\Params\OffLoad.RxCS\enum, "1", 0, %TCPv4%
|
||||
HKR, Ndi\Params\OffLoad.RxCS\enum, "0", 0, %Disable%
|
||||
|
||||
HKR, Ndi\Params\*IPChecksumOffloadIPv4, ParamDesc, 0, %Std.IPChecksumOffloadv4%
|
||||
HKR, Ndi\Params\*IPChecksumOffloadIPv4, Default, 0, "3"
|
||||
HKR, Ndi\Params\*IPChecksumOffloadIPv4, type, 0, "enum"
|
||||
HKR, Ndi\Params\*IPChecksumOffloadIPv4\enum, "3", 0, %TxRx%
|
||||
HKR, Ndi\Params\*IPChecksumOffloadIPv4\enum, "2", 0, %Rx%
|
||||
HKR, Ndi\Params\*IPChecksumOffloadIPv4\enum, "1", 0, %Tx%
|
||||
HKR, Ndi\Params\*IPChecksumOffloadIPv4\enum, "0", 0, %Disable%
|
||||
|
||||
HKR, Ndi\Params\*LsoV2IPv4, ParamDesc, 0, %Std.LsoV2IPv4%
|
||||
HKR, Ndi\Params\*LsoV2IPv4, Default, 0, "1"
|
||||
HKR, Ndi\Params\*LsoV2IPv4, type, 0, "enum"
|
||||
HKR, Ndi\Params\*LsoV2IPv4\enum, "1", 0, %Enable%
|
||||
HKR, Ndi\Params\*LsoV2IPv4\enum, "0", 0, %Disable%
|
||||
|
||||
HKR, Ndi\Params\*LsoV2IPv6, ParamDesc, 0, %Std.LsoV2IPv6%
|
||||
HKR, Ndi\Params\*LsoV2IPv6, Default, 0, "1"
|
||||
HKR, Ndi\Params\*LsoV2IPv6, type, 0, "enum"
|
||||
HKR, Ndi\Params\*LsoV2IPv6\enum, "1", 0, %Enable%
|
||||
HKR, Ndi\Params\*LsoV2IPv6\enum, "0", 0, %Disable%
|
||||
|
||||
HKR, Ndi\Params\*UDPChecksumOffloadIPv4, ParamDesc, 0, %Std.UDPChecksumOffloadIPv4%
|
||||
HKR, Ndi\Params\*UDPChecksumOffloadIPv4, Default, 0, "3"
|
||||
HKR, Ndi\Params\*UDPChecksumOffloadIPv4, type, 0, "enum"
|
||||
HKR, Ndi\Params\*UDPChecksumOffloadIPv4\enum, "3", 0, %TxRx%
|
||||
HKR, Ndi\Params\*UDPChecksumOffloadIPv4\enum, "2", 0, %Rx%
|
||||
HKR, Ndi\Params\*UDPChecksumOffloadIPv4\enum, "1", 0, %Tx%
|
||||
HKR, Ndi\Params\*UDPChecksumOffloadIPv4\enum, "0", 0, %Disable%
|
||||
|
||||
HKR, Ndi\Params\*TCPChecksumOffloadIPv4, ParamDesc, 0, %Std.TCPChecksumOffloadIPv4%
|
||||
HKR, Ndi\Params\*TCPChecksumOffloadIPv4, Default, 0, "3"
|
||||
HKR, Ndi\Params\*TCPChecksumOffloadIPv4, type, 0, "enum"
|
||||
HKR, Ndi\Params\*TCPChecksumOffloadIPv4\enum, "3", 0, %TxRx%
|
||||
HKR, Ndi\Params\*TCPChecksumOffloadIPv4\enum, "2", 0, %Rx%
|
||||
HKR, Ndi\Params\*TCPChecksumOffloadIPv4\enum, "1", 0, %Tx%
|
||||
HKR, Ndi\Params\*TCPChecksumOffloadIPv4\enum, "0", 0, %Disable%
|
||||
|
||||
HKR, Ndi\Params\*TCPChecksumOffloadIPv6, ParamDesc, 0, %Std.TCPChecksumOffloadIPv6%
|
||||
HKR, Ndi\Params\*TCPChecksumOffloadIPv6, Default, 0, "3"
|
||||
HKR, Ndi\Params\*TCPChecksumOffloadIPv6, type, 0, "enum"
|
||||
HKR, Ndi\Params\*TCPChecksumOffloadIPv6\enum, "3", 0, %TxRx%
|
||||
HKR, Ndi\Params\*TCPChecksumOffloadIPv6\enum, "2", 0, %Rx%
|
||||
HKR, Ndi\Params\*TCPChecksumOffloadIPv6\enum, "1", 0, %Tx%
|
||||
HKR, Ndi\Params\*TCPChecksumOffloadIPv6\enum, "0", 0, %Disable%
|
||||
|
||||
HKR, Ndi\Params\*UDPChecksumOffloadIPv6, ParamDesc, 0, %Std.UDPChecksumOffloadIPv6%
|
||||
HKR, Ndi\Params\*UDPChecksumOffloadIPv6, Default, 0, "3"
|
||||
HKR, Ndi\Params\*UDPChecksumOffloadIPv6, type, 0, "enum"
|
||||
HKR, Ndi\Params\*UDPChecksumOffloadIPv6\enum, "3", 0, %TxRx%
|
||||
HKR, Ndi\Params\*UDPChecksumOffloadIPv6\enum, "2", 0, %Rx%
|
||||
HKR, Ndi\Params\*UDPChecksumOffloadIPv6\enum, "1", 0, %Tx%
|
||||
HKR, Ndi\Params\*UDPChecksumOffloadIPv6\enum, "0", 0, %Disable%
|
||||
|
||||
HKR, Ndi\params\MinRxBufferPercent, ParamDesc, 0, %MinRxBufferPercent%
|
||||
HKR, Ndi\params\MinRxBufferPercent, type, 0, "int"
|
||||
HKR, Ndi\params\MinRxBufferPercent, default, 0, "0"
|
||||
HKR, Ndi\params\MinRxBufferPercent, min, 0, "0"
|
||||
HKR, Ndi\params\MinRxBufferPercent, max, 0, "100"
|
||||
HKR, Ndi\params\MinRxBufferPercent, step, 0, "1"
|
||||
|
||||
[kvmnet6.CopyFiles]
|
||||
netkvm.sys,,,2
|
||||
|
||||
[netkvmp.CopyFiles]
|
||||
netkvmp.exe,,,2
|
||||
|
||||
[kvmnet6.Service]
|
||||
DisplayName = %kvmnet6.Service.DispName%
|
||||
ServiceType = 1 ;%SERVICE_KERNEL_DRIVER%
|
||||
StartType = 3 ;%SERVICE_DEMAND_START%
|
||||
ErrorControl = 1 ;%SERVICE_ERROR_NORMAL%
|
||||
ServiceBinary = %13%\netkvm.sys
|
||||
LoadOrderGroup = NDIS
|
||||
AddReg = TextModeFlags.Reg
|
||||
|
||||
[kvmnet6.EventLog]
|
||||
AddReg = kvmnet6.AddEventLog.Reg
|
||||
|
||||
[kvmnet6.AddEventLog.Reg]
|
||||
HKR, , EventMessageFile, 0x00020000, "%%SystemRoot%%\System32\netevent.dll"
|
||||
HKR, , TypesSupported, 0x00010001, 7
|
||||
|
||||
[TextModeFlags.Reg]
|
||||
HKR,,TextModeFlags,0x00010001, 0x0001
|
||||
HKR,Parameters,DisableMSI,,"0"
|
||||
HKR,Parameters,EarlyDebug,,"3"
|
||||
HKR,Parameters,DmaRemappingCompatible,0x00010001,2
|
||||
|
||||
|
||||
[SourceDisksNames]
|
||||
1 = %DiskId1%,,,""
|
||||
|
||||
[SourceDisksFiles]
|
||||
netkvm.sys = 1,,
|
||||
netkvmp.exe = 1,,
|
||||
|
||||
[DestinationDirs]
|
||||
kvmnet6.CopyFiles = 13
|
||||
netkvmp.CopyFiles = 11
|
||||
|
||||
[Strings]
|
||||
VENDOR = "Red Hat, Inc."
|
||||
kvmnet6.DeviceDesc = "Red Hat VirtIO Ethernet Adapter"
|
||||
kvmnet6.Service.DispName = "Red Hat VirtIO Ethernet Adapter Service"
|
||||
DiskId1 = "Red Hat VirtIO Ethernet Adapter Driver Disk #1"
|
||||
NetworkAddress = "Assign MAC"
|
||||
Priority = "Init.Do802.1PQ"
|
||||
JumboPacket = "Jumbo Packet"
|
||||
TxCapacity = "Init.MaxTxBuffers"
|
||||
RxCapacity = "Init.MaxRxBuffers"
|
||||
SeparateTail = "Init.SeparateRxTail"
|
||||
FastInit = "Fast Initialization"
|
||||
Offload.TxChecksum = "Offload.Tx.Checksum"
|
||||
Offload.TxLSO = "Offload.Tx.LSO"
|
||||
Offload.RxCS = "Offload.Rx.Checksum"
|
||||
EnableLogging = "Logging.Enable"
|
||||
DebugLevel = "Logging.Level"
|
||||
Tx = "Tx Enabled";
|
||||
Rx = "Rx Enabled";
|
||||
TxRx = "Rx & Tx Enabled";
|
||||
Std.LsoV2IPv4 = "Large Send Offload V2 (IPv4)"
|
||||
Std.LsoV2IPv6 = "Large Send Offload V2 (IPv6)"
|
||||
Std.UDPChecksumOffloadIPv4 = "UDP Checksum Offload (IPv4)"
|
||||
Std.TCPChecksumOffloadIPv4 = "TCP Checksum Offload (IPv4)"
|
||||
Std.UDPChecksumOffloadIPv6 = "UDP Checksum Offload (IPv6)"
|
||||
Std.TCPChecksumOffloadIPv6 = "TCP Checksum Offload (IPv6)"
|
||||
Std.IPChecksumOffloadv4 = "IPv4 Checksum Offload"
|
||||
Disable = "Disabled"
|
||||
Enable = "Enabled"
|
||||
Enable* = "Enabled*"
|
||||
String_16 = "16"
|
||||
String_32 = "32"
|
||||
String_64 = "64"
|
||||
String_128 = "128"
|
||||
String_256 = "256"
|
||||
String_512 = "512"
|
||||
String_1024 = "1024"
|
||||
String_2048 = "2048"
|
||||
String_4096 = "4096"
|
||||
PriorityVlanTag = "Priority and VLAN tagging"
|
||||
PriorityOnly = "Priority"
|
||||
VLan = "VLan"
|
||||
VLan_ID = "VLan ID"
|
||||
Priority_Vlan = "All"
|
||||
10M = "10M"
|
||||
100M = "100M"
|
||||
1G = "1G"
|
||||
10G = "10G"
|
||||
TCPv4 = "TCP(v4)"
|
||||
TCPUDPv4 = "TCP/UDP(v4)"
|
||||
TCPUDPAll = "TCP/UDP(v4,v6)"
|
||||
All = "All"
|
||||
IPv4 = "IPv4"
|
||||
Maximal = "Maximal"
|
||||
MinRxBufferPercent = "MinRxBufferPercent"
|
||||
|
||||
[kvmnet6.Reg]
|
||||
HKR, , BusNumber, 0, "0"
|
||||
HKR, Ndi, Service, 0, "netkvm"
|
||||
HKR, Ndi\Interfaces, UpperRange, 0, "ndis5"
|
||||
HKR, Ndi\Interfaces, LowerRange, 0, "ethernet"
|
||||
|
||||
HKR, Ndi\params\*RSS, ParamDesc, 0, "Receive Side Scaling"
|
||||
HKR, Ndi\params\*RSS, Type, 0, "enum"
|
||||
HKR, Ndi\params\*RSS, Default, 0, "1"
|
||||
HKR, Ndi\params\*RSS, Optional, 0, "0"
|
||||
HKR, Ndi\params\*RSS\enum, "0", 0, "Disabled"
|
||||
HKR, Ndi\params\*RSS\enum, "1", 0, "Enabled"
|
||||
|
||||
HKR, Ndi\params\*NumRssQueues, ParamDesc, 0, "Maximum Number of RSS Queues"
|
||||
HKR, Ndi\params\*NumRssQueues, type, 0, "int"
|
||||
HKR, Ndi\params\*NumRssQueues, default, 0, "16"
|
||||
HKR, Ndi\params\*NumRssQueues, min, 0, "1"
|
||||
HKR, Ndi\params\*NumRssQueues, max, 0, "32"
|
||||
HKR, Ndi\params\*NumRssQueues, step, 0, "1"
|
||||
|
||||
HKR, Ndi\params\*RscIPv4, ParamDesc, 0, "Recv Segment Coalescing (IPv4)"
|
||||
HKR, Ndi\params\*RscIPv4, Type, 0, "enum"
|
||||
HKR, Ndi\params\*RscIPv4, Default, 0, "1"
|
||||
HKR, Ndi\params\*RscIPv4, Optional, 0, "0"
|
||||
HKR, Ndi\params\*RscIPv4\enum, "0", 0, "Disabled"
|
||||
HKR, Ndi\params\*RscIPv4\enum, "1", 0, "Enabled"
|
||||
|
||||
HKR, Ndi\params\*RscIPv6, ParamDesc, 0, "Recv Segment Coalescing (IPv6)"
|
||||
HKR, Ndi\params\*RscIPv6, Type, 0, "enum"
|
||||
HKR, Ndi\params\*RscIPv6, Default, 0, "1"
|
||||
HKR, Ndi\params\*RscIPv6, Optional, 0, "0"
|
||||
HKR, Ndi\params\*RscIPv6\enum, "0", 0, "Disabled"
|
||||
HKR, Ndi\params\*RscIPv6\enum, "1", 0, "Enabled"
|
||||
HKR, Ndi\params\*UsoIPv4, ParamDesc, 0, "UDP Segmentation Offload (IPv4)"
|
||||
HKR, Ndi\params\*UsoIPv4, Type, 0, "enum"
|
||||
HKR, Ndi\params\*UsoIPv4, Default, 0, "1"
|
||||
HKR, Ndi\params\*UsoIPv4, Optional, 0, "0"
|
||||
HKR, Ndi\params\*UsoIPv4\enum, "0", 0, "Disabled"
|
||||
HKR, Ndi\params\*UsoIPv4\enum, "1", 0, "Enabled"
|
||||
|
||||
HKR, Ndi\params\*UsoIPv6, ParamDesc, 0, "UDP Segmentation Offload (IPv6)"
|
||||
HKR, Ndi\params\*UsoIPv6, Type, 0, "enum"
|
||||
HKR, Ndi\params\*UsoIPv6, Default, 0, "1"
|
||||
HKR, Ndi\params\*UsoIPv6, Optional, 0, "0"
|
||||
HKR, Ndi\params\*UsoIPv6\enum, "0", 0, "Disabled"
|
||||
HKR, Ndi\params\*UsoIPv6\enum, "1", 0, "Enabled"
|
||||
|
||||
HKR, Ndi\params\*NdisPoll, ParamDesc, 0, "Ndis Poll Mode"
|
||||
HKR, Ndi\params\*NdisPoll, Type, 0, "enum"
|
||||
HKR, Ndi\params\*NdisPoll, Default, 0, "1"
|
||||
HKR, Ndi\params\*NdisPoll, Optional, 0, "0"
|
||||
HKR, Ndi\params\*NdisPoll\enum, "0", 0, "Disabled"
|
||||
HKR, Ndi\params\*NdisPoll\enum, "1", 0, "Enabled"
|
||||
;-------------------------------------------------------------------------------
|
||||
;Copyright (c) 2008-2021 Red Hat Inc.
|
||||
;
|
||||
;
|
||||
;Module Name:
|
||||
; netkvm.inf
|
||||
;
|
||||
; VirtIO Ethernet Adapter
|
||||
;
|
||||
;-------------------------------------------------------------------------------
|
||||
;Installation Notes:
|
||||
; Step by step driver installation wiki:
|
||||
; https://github.com/virtio-win/kvm-guest-drivers-windows/wiki/Driver-installation
|
||||
;
|
||||
|
||||
[version]
|
||||
Signature = "$Windows NT$"
|
||||
Class = Net
|
||||
CatalogFile = netkvm.cat
|
||||
ClassGUID = {4d36e972-e325-11ce-bfc1-08002be10318}
|
||||
Provider=%VENDOR%
|
||||
DriverVer = 07/09/2025,100.101.104.28500
|
||||
DriverPackageType = PlugAndPlay
|
||||
DriverPackageDisplayName = %kvmnet6.DeviceDesc%
|
||||
PnpLockDown=1
|
||||
|
||||
[Manufacturer]
|
||||
%VENDOR% = NetKVM, NTamd64.10.0...16299
|
||||
|
||||
[NetKVM.NTamd64.10.0...16299]
|
||||
%kvmnet6.DeviceDesc% = kvmnet6.ndi, PCI\VEN_1AF4&DEV_1000&SUBSYS_00011AF4&REV_00, PCI\VEN_1AF4&DEV_1000
|
||||
%kvmnet6.DeviceDesc% = kvmnet6.ndi, PCI\VEN_1AF4&DEV_1041&SUBSYS_11001AF4&REV_01, PCI\VEN_1AF4&DEV_1041
|
||||
|
||||
[kvmnet6.ndi.hw]
|
||||
AddReg = kvmnet6.EnableMSI
|
||||
|
||||
[kvmnet6.EnableMSI]
|
||||
;HKR, "Interrupt Management",, 0x00000010
|
||||
;HKR, "Interrupt Management\MessageSignaledInterruptProperties",, 0x00000010
|
||||
HKR, "Interrupt Management\MessageSignaledInterruptProperties", MSISupported, 0x00010001, 1
|
||||
HKR, "Interrupt Management\MessageSignaledInterruptProperties", MessageNumberLimit, 0x00010001, 2048
|
||||
;HKR, "Interrupt Management\Affinity Policy",, 0x00000010
|
||||
HKR, "Interrupt Management\Affinity Policy", DevicePolicy, 0x00010001, 0
|
||||
HKR, "Interrupt Management\Affinity Policy", DevicePriority, 0x00010001, 2
|
||||
|
||||
[kvmnet6.ndi]
|
||||
Characteristics = 0x84 ; NCF_PHYSICAL | NCF_HAS_UI
|
||||
BusType = 5 ; PCI
|
||||
AddReg = kvmnet6.Reg, Parameters
|
||||
CopyFiles = kvmnet6.CopyFiles, netkvmp.CopyFiles
|
||||
*IfType = 6
|
||||
*MediaType = 0 ; NdisMedium802_3
|
||||
*PhysicalMediaType = 0 ; NdisPhysicalMediumUnspecified
|
||||
|
||||
[kvmnet6.ndi.Services]
|
||||
AddService = netkvm, 2, kvmnet6.Service, kvmnet6.EventLog
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
; Red Hat ParaVirtualized Miniport Common
|
||||
;-----------------------------------------------------------------------------
|
||||
[Parameters]
|
||||
|
||||
HKR, Ndi\Params\Priority, ParamDesc, 0, %Priority%
|
||||
HKR, Ndi\Params\Priority, Default, 0, "1"
|
||||
HKR, Ndi\Params\Priority, type, 0, "enum"
|
||||
HKR, Ndi\Params\Priority\enum, "1", 0, %Enable%
|
||||
HKR, Ndi\Params\Priority\enum, "0", 0, %Disable%
|
||||
|
||||
HKR, Ndi\Params\*PriorityVLANTag, ParamDesc, 0, %PriorityVlanTag%
|
||||
HKR, Ndi\Params\*PriorityVLANTag, Default, 0, "3"
|
||||
HKR, Ndi\Params\*PriorityVLANTag, type, 0, "enum"
|
||||
HKR, Ndi\Params\*PriorityVLANTag\enum, "3", 0, %Priority_Vlan%
|
||||
HKR, Ndi\Params\*PriorityVLANTag\enum, "2", 0, %VLan%
|
||||
HKR, Ndi\Params\*PriorityVLANTag\enum, "1", 0, %PriorityOnly%
|
||||
HKR, Ndi\Params\*PriorityVLANTag\enum, "0", 0, %Disable%
|
||||
|
||||
HKR, Ndi\params\VlanID, ParamDesc, 0, %VLan_ID%
|
||||
HKR, Ndi\params\VlanID, type, 0, "long"
|
||||
HKR, Ndi\params\VlanID, default, 0, "0"
|
||||
HKR, Ndi\params\VlanID, min, 0, "0"
|
||||
HKR, Ndi\params\VlanID, max, 0, "4094"
|
||||
|
||||
HKR, Ndi\Params\DoLog, ParamDesc, 0, %EnableLogging%
|
||||
HKR, Ndi\Params\DoLog, Default, 0, "1"
|
||||
HKR, Ndi\Params\DoLog, type, 0, "enum"
|
||||
HKR, Ndi\Params\DoLog\enum, "1", 0, %Enable%
|
||||
HKR, Ndi\Params\DoLog\enum, "0", 0, %Disable%
|
||||
|
||||
HKR, Ndi\params\DebugLevel, ParamDesc, 0, %DebugLevel%
|
||||
HKR, Ndi\params\DebugLevel, type, 0, "int"
|
||||
HKR, Ndi\params\DebugLevel, default, 0, "0"
|
||||
HKR, Ndi\params\DebugLevel, min, 0, "0"
|
||||
HKR, Ndi\params\DebugLevel, max, 0, "8"
|
||||
HKR, Ndi\params\DebugLevel, step, 0, "1"
|
||||
|
||||
HKR, Ndi\params\*JumboPacket, ParamDesc, 0, %JumboPacket%
|
||||
HKR, Ndi\params\*JumboPacket, type, 0, "long"
|
||||
HKR, Ndi\params\*JumboPacket, default, 0, "1514"
|
||||
HKR, Ndi\params\*JumboPacket, min, 0, "590"
|
||||
HKR, Ndi\params\*JumboPacket, max, 0, "65500"
|
||||
HKR, Ndi\params\*JumboPacket, step, 0, "1"
|
||||
|
||||
HKR, Ndi\params\TxCapacity, ParamDesc, 0, %TxCapacity%
|
||||
HKR, Ndi\params\TxCapacity, type, 0, "enum"
|
||||
HKR, Ndi\params\TxCapacity, default, 0, "1024"
|
||||
HKR, Ndi\Params\TxCapacity\enum, "16", 0, %String_16%
|
||||
HKR, Ndi\Params\TxCapacity\enum, "32", 0, %String_32%
|
||||
HKR, Ndi\Params\TxCapacity\enum, "64", 0, %String_64%
|
||||
HKR, Ndi\Params\TxCapacity\enum, "128", 0, %String_128%
|
||||
HKR, Ndi\Params\TxCapacity\enum, "256", 0, %String_256%
|
||||
HKR, Ndi\Params\TxCapacity\enum, "512", 0, %String_512%
|
||||
HKR, Ndi\Params\TxCapacity\enum, "1024", 0, %String_1024%
|
||||
|
||||
HKR, Ndi\params\RxCapacity, ParamDesc, 0, %RxCapacity%
|
||||
HKR, Ndi\params\RxCapacity, type, 0, "enum"
|
||||
HKR, Ndi\params\RxCapacity, default, 0, "1024"
|
||||
HKR, Ndi\Params\RxCapacity\enum, "16", 0, %String_16%
|
||||
HKR, Ndi\Params\RxCapacity\enum, "32", 0, %String_32%
|
||||
HKR, Ndi\Params\RxCapacity\enum, "64", 0, %String_64%
|
||||
HKR, Ndi\Params\RxCapacity\enum, "128", 0, %String_128%
|
||||
HKR, Ndi\Params\RxCapacity\enum, "256", 0, %String_256%
|
||||
HKR, Ndi\Params\RxCapacity\enum, "512", 0, %String_512%
|
||||
HKR, Ndi\Params\RxCapacity\enum, "1024", 0, %String_1024%
|
||||
HKR, Ndi\Params\RxCapacity\enum, "2048", 0, %String_2048%
|
||||
HKR, Ndi\Params\RxCapacity\enum, "4096", 0, %String_4096%
|
||||
|
||||
HKR, Ndi\Params\SeparateTail, ParamDesc, 0, %SeparateTail%
|
||||
HKR, Ndi\Params\SeparateTail, Default, 0, "1"
|
||||
HKR, Ndi\Params\SeparateTail, type, 0, "enum"
|
||||
HKR, Ndi\Params\SeparateTail\enum, "1", 0, %Enable%
|
||||
HKR, Ndi\Params\SeparateTail\enum, "0", 0, %Disable%
|
||||
|
||||
HKR, Ndi\Params\FastInit, ParamDesc, 0, %FastInit%
|
||||
HKR, Ndi\Params\FastInit, Default, 0, "1"
|
||||
HKR, Ndi\Params\FastInit, type, 0, "enum"
|
||||
HKR, Ndi\Params\FastInit\enum, "1", 0, %Enable%
|
||||
HKR, Ndi\Params\FastInit\enum, "0", 0, %Disable%
|
||||
|
||||
HKR, Ndi\params\NetworkAddress, ParamDesc, 0, %NetworkAddress%
|
||||
HKR, Ndi\params\NetworkAddress, type, 0, "edit"
|
||||
HKR, Ndi\params\NetworkAddress, Optional, 0, "1"
|
||||
|
||||
HKR, Ndi\Params\OffLoad.TxChecksum, ParamDesc, 0, %OffLoad.TxChecksum%
|
||||
HKR, Ndi\Params\OffLoad.TxChecksum, Default, 0, "31"
|
||||
HKR, Ndi\Params\OffLoad.TxChecksum, type, 0, "enum"
|
||||
HKR, Ndi\Params\OffLoad.TxChecksum\enum, "31", 0, %All%
|
||||
HKR, Ndi\Params\OffLoad.TxChecksum\enum, "27", 0, %TCPUDPAll%
|
||||
HKR, Ndi\Params\OffLoad.TxChecksum\enum, "3", 0, %TCPUDPv4%
|
||||
HKR, Ndi\Params\OffLoad.TxChecksum\enum, "1", 0, %TCPv4%
|
||||
HKR, Ndi\Params\OffLoad.TxChecksum\enum, "0", 0, %Disable%
|
||||
|
||||
HKR, Ndi\Params\OffLoad.TxLSO, ParamDesc, 0, %OffLoad.TxLSO%
|
||||
HKR, Ndi\Params\OffLoad.TxLSO, Default, 0, "2"
|
||||
HKR, Ndi\Params\OffLoad.TxLSO, type, 0, "enum"
|
||||
HKR, Ndi\Params\OffLoad.TxLSO\enum, "2", 0, %Maximal%
|
||||
HKR, Ndi\Params\OffLoad.TxLSO\enum, "1", 0, %IPv4%
|
||||
HKR, Ndi\Params\OffLoad.TxLSO\enum, "0", 0, %Disable%
|
||||
|
||||
HKR, Ndi\Params\OffLoad.RxCS, ParamDesc, 0, %OffLoad.RxCS%
|
||||
HKR, Ndi\Params\OffLoad.RxCS, Default, 0, "31"
|
||||
HKR, Ndi\Params\OffLoad.RxCS, type, 0, "enum"
|
||||
HKR, Ndi\Params\OffLoad.RxCS\enum, "31", 0, %All%
|
||||
HKR, Ndi\Params\OffLoad.RxCS\enum, "27", 0, %TCPUDPAll%
|
||||
HKR, Ndi\Params\OffLoad.RxCS\enum, "3", 0, %TCPUDPv4%
|
||||
HKR, Ndi\Params\OffLoad.RxCS\enum, "1", 0, %TCPv4%
|
||||
HKR, Ndi\Params\OffLoad.RxCS\enum, "0", 0, %Disable%
|
||||
|
||||
HKR, Ndi\Params\*IPChecksumOffloadIPv4, ParamDesc, 0, %Std.IPChecksumOffloadv4%
|
||||
HKR, Ndi\Params\*IPChecksumOffloadIPv4, Default, 0, "3"
|
||||
HKR, Ndi\Params\*IPChecksumOffloadIPv4, type, 0, "enum"
|
||||
HKR, Ndi\Params\*IPChecksumOffloadIPv4\enum, "3", 0, %TxRx%
|
||||
HKR, Ndi\Params\*IPChecksumOffloadIPv4\enum, "2", 0, %Rx%
|
||||
HKR, Ndi\Params\*IPChecksumOffloadIPv4\enum, "1", 0, %Tx%
|
||||
HKR, Ndi\Params\*IPChecksumOffloadIPv4\enum, "0", 0, %Disable%
|
||||
|
||||
HKR, Ndi\Params\*LsoV2IPv4, ParamDesc, 0, %Std.LsoV2IPv4%
|
||||
HKR, Ndi\Params\*LsoV2IPv4, Default, 0, "1"
|
||||
HKR, Ndi\Params\*LsoV2IPv4, type, 0, "enum"
|
||||
HKR, Ndi\Params\*LsoV2IPv4\enum, "1", 0, %Enable%
|
||||
HKR, Ndi\Params\*LsoV2IPv4\enum, "0", 0, %Disable%
|
||||
|
||||
HKR, Ndi\Params\*LsoV2IPv6, ParamDesc, 0, %Std.LsoV2IPv6%
|
||||
HKR, Ndi\Params\*LsoV2IPv6, Default, 0, "1"
|
||||
HKR, Ndi\Params\*LsoV2IPv6, type, 0, "enum"
|
||||
HKR, Ndi\Params\*LsoV2IPv6\enum, "1", 0, %Enable%
|
||||
HKR, Ndi\Params\*LsoV2IPv6\enum, "0", 0, %Disable%
|
||||
|
||||
HKR, Ndi\Params\*UDPChecksumOffloadIPv4, ParamDesc, 0, %Std.UDPChecksumOffloadIPv4%
|
||||
HKR, Ndi\Params\*UDPChecksumOffloadIPv4, Default, 0, "3"
|
||||
HKR, Ndi\Params\*UDPChecksumOffloadIPv4, type, 0, "enum"
|
||||
HKR, Ndi\Params\*UDPChecksumOffloadIPv4\enum, "3", 0, %TxRx%
|
||||
HKR, Ndi\Params\*UDPChecksumOffloadIPv4\enum, "2", 0, %Rx%
|
||||
HKR, Ndi\Params\*UDPChecksumOffloadIPv4\enum, "1", 0, %Tx%
|
||||
HKR, Ndi\Params\*UDPChecksumOffloadIPv4\enum, "0", 0, %Disable%
|
||||
|
||||
HKR, Ndi\Params\*TCPChecksumOffloadIPv4, ParamDesc, 0, %Std.TCPChecksumOffloadIPv4%
|
||||
HKR, Ndi\Params\*TCPChecksumOffloadIPv4, Default, 0, "3"
|
||||
HKR, Ndi\Params\*TCPChecksumOffloadIPv4, type, 0, "enum"
|
||||
HKR, Ndi\Params\*TCPChecksumOffloadIPv4\enum, "3", 0, %TxRx%
|
||||
HKR, Ndi\Params\*TCPChecksumOffloadIPv4\enum, "2", 0, %Rx%
|
||||
HKR, Ndi\Params\*TCPChecksumOffloadIPv4\enum, "1", 0, %Tx%
|
||||
HKR, Ndi\Params\*TCPChecksumOffloadIPv4\enum, "0", 0, %Disable%
|
||||
|
||||
HKR, Ndi\Params\*TCPChecksumOffloadIPv6, ParamDesc, 0, %Std.TCPChecksumOffloadIPv6%
|
||||
HKR, Ndi\Params\*TCPChecksumOffloadIPv6, Default, 0, "3"
|
||||
HKR, Ndi\Params\*TCPChecksumOffloadIPv6, type, 0, "enum"
|
||||
HKR, Ndi\Params\*TCPChecksumOffloadIPv6\enum, "3", 0, %TxRx%
|
||||
HKR, Ndi\Params\*TCPChecksumOffloadIPv6\enum, "2", 0, %Rx%
|
||||
HKR, Ndi\Params\*TCPChecksumOffloadIPv6\enum, "1", 0, %Tx%
|
||||
HKR, Ndi\Params\*TCPChecksumOffloadIPv6\enum, "0", 0, %Disable%
|
||||
|
||||
HKR, Ndi\Params\*UDPChecksumOffloadIPv6, ParamDesc, 0, %Std.UDPChecksumOffloadIPv6%
|
||||
HKR, Ndi\Params\*UDPChecksumOffloadIPv6, Default, 0, "3"
|
||||
HKR, Ndi\Params\*UDPChecksumOffloadIPv6, type, 0, "enum"
|
||||
HKR, Ndi\Params\*UDPChecksumOffloadIPv6\enum, "3", 0, %TxRx%
|
||||
HKR, Ndi\Params\*UDPChecksumOffloadIPv6\enum, "2", 0, %Rx%
|
||||
HKR, Ndi\Params\*UDPChecksumOffloadIPv6\enum, "1", 0, %Tx%
|
||||
HKR, Ndi\Params\*UDPChecksumOffloadIPv6\enum, "0", 0, %Disable%
|
||||
|
||||
HKR, Ndi\params\MinRxBufferPercent, ParamDesc, 0, %MinRxBufferPercent%
|
||||
HKR, Ndi\params\MinRxBufferPercent, type, 0, "int"
|
||||
HKR, Ndi\params\MinRxBufferPercent, default, 0, "0"
|
||||
HKR, Ndi\params\MinRxBufferPercent, min, 0, "0"
|
||||
HKR, Ndi\params\MinRxBufferPercent, max, 0, "100"
|
||||
HKR, Ndi\params\MinRxBufferPercent, step, 0, "1"
|
||||
|
||||
[kvmnet6.CopyFiles]
|
||||
netkvm.sys,,,2
|
||||
|
||||
[netkvmp.CopyFiles]
|
||||
netkvmp.exe,,,2
|
||||
|
||||
[kvmnet6.Service]
|
||||
DisplayName = %kvmnet6.Service.DispName%
|
||||
ServiceType = 1 ;%SERVICE_KERNEL_DRIVER%
|
||||
StartType = 3 ;%SERVICE_DEMAND_START%
|
||||
ErrorControl = 1 ;%SERVICE_ERROR_NORMAL%
|
||||
ServiceBinary = %13%\netkvm.sys
|
||||
LoadOrderGroup = NDIS
|
||||
AddReg = TextModeFlags.Reg
|
||||
|
||||
[kvmnet6.EventLog]
|
||||
AddReg = kvmnet6.AddEventLog.Reg
|
||||
|
||||
[kvmnet6.AddEventLog.Reg]
|
||||
HKR, , EventMessageFile, 0x00020000, "%%SystemRoot%%\System32\netevent.dll"
|
||||
HKR, , TypesSupported, 0x00010001, 7
|
||||
|
||||
[TextModeFlags.Reg]
|
||||
HKR,,TextModeFlags,0x00010001, 0x0001
|
||||
HKR,Parameters,DisableMSI,,"0"
|
||||
HKR,Parameters,EarlyDebug,,"3"
|
||||
HKR,Parameters,DmaRemappingCompatible,0x00010001,2
|
||||
|
||||
|
||||
[SourceDisksNames]
|
||||
1 = %DiskId1%,,,""
|
||||
|
||||
[SourceDisksFiles]
|
||||
netkvm.sys = 1,,
|
||||
netkvmp.exe = 1,,
|
||||
|
||||
[DestinationDirs]
|
||||
kvmnet6.CopyFiles = 13
|
||||
netkvmp.CopyFiles = 11
|
||||
|
||||
[Strings]
|
||||
VENDOR = "Red Hat, Inc."
|
||||
kvmnet6.DeviceDesc = "Red Hat VirtIO Ethernet Adapter"
|
||||
kvmnet6.Service.DispName = "Red Hat VirtIO Ethernet Adapter Service"
|
||||
DiskId1 = "Red Hat VirtIO Ethernet Adapter Driver Disk #1"
|
||||
NetworkAddress = "Assign MAC"
|
||||
Priority = "Init.Do802.1PQ"
|
||||
JumboPacket = "Jumbo Packet"
|
||||
TxCapacity = "Init.MaxTxBuffers"
|
||||
RxCapacity = "Init.MaxRxBuffers"
|
||||
SeparateTail = "Init.SeparateRxTail"
|
||||
FastInit = "Fast Initialization"
|
||||
Offload.TxChecksum = "Offload.Tx.Checksum"
|
||||
Offload.TxLSO = "Offload.Tx.LSO"
|
||||
Offload.RxCS = "Offload.Rx.Checksum"
|
||||
EnableLogging = "Logging.Enable"
|
||||
DebugLevel = "Logging.Level"
|
||||
Tx = "Tx Enabled";
|
||||
Rx = "Rx Enabled";
|
||||
TxRx = "Rx & Tx Enabled";
|
||||
Std.LsoV2IPv4 = "Large Send Offload V2 (IPv4)"
|
||||
Std.LsoV2IPv6 = "Large Send Offload V2 (IPv6)"
|
||||
Std.UDPChecksumOffloadIPv4 = "UDP Checksum Offload (IPv4)"
|
||||
Std.TCPChecksumOffloadIPv4 = "TCP Checksum Offload (IPv4)"
|
||||
Std.UDPChecksumOffloadIPv6 = "UDP Checksum Offload (IPv6)"
|
||||
Std.TCPChecksumOffloadIPv6 = "TCP Checksum Offload (IPv6)"
|
||||
Std.IPChecksumOffloadv4 = "IPv4 Checksum Offload"
|
||||
Disable = "Disabled"
|
||||
Enable = "Enabled"
|
||||
Enable* = "Enabled*"
|
||||
String_16 = "16"
|
||||
String_32 = "32"
|
||||
String_64 = "64"
|
||||
String_128 = "128"
|
||||
String_256 = "256"
|
||||
String_512 = "512"
|
||||
String_1024 = "1024"
|
||||
String_2048 = "2048"
|
||||
String_4096 = "4096"
|
||||
PriorityVlanTag = "Priority and VLAN tagging"
|
||||
PriorityOnly = "Priority"
|
||||
VLan = "VLan"
|
||||
VLan_ID = "VLan ID"
|
||||
Priority_Vlan = "All"
|
||||
10M = "10M"
|
||||
100M = "100M"
|
||||
1G = "1G"
|
||||
10G = "10G"
|
||||
TCPv4 = "TCP(v4)"
|
||||
TCPUDPv4 = "TCP/UDP(v4)"
|
||||
TCPUDPAll = "TCP/UDP(v4,v6)"
|
||||
All = "All"
|
||||
IPv4 = "IPv4"
|
||||
Maximal = "Maximal"
|
||||
MinRxBufferPercent = "MinRxBufferPercent"
|
||||
|
||||
[kvmnet6.Reg]
|
||||
HKR, , BusNumber, 0, "0"
|
||||
HKR, Ndi, Service, 0, "netkvm"
|
||||
HKR, Ndi\Interfaces, UpperRange, 0, "ndis5"
|
||||
HKR, Ndi\Interfaces, LowerRange, 0, "ethernet"
|
||||
|
||||
HKR, Ndi\params\*RSS, ParamDesc, 0, "Receive Side Scaling"
|
||||
HKR, Ndi\params\*RSS, Type, 0, "enum"
|
||||
HKR, Ndi\params\*RSS, Default, 0, "1"
|
||||
HKR, Ndi\params\*RSS, Optional, 0, "0"
|
||||
HKR, Ndi\params\*RSS\enum, "0", 0, "Disabled"
|
||||
HKR, Ndi\params\*RSS\enum, "1", 0, "Enabled"
|
||||
|
||||
HKR, Ndi\params\*NumRssQueues, ParamDesc, 0, "Maximum Number of RSS Queues"
|
||||
HKR, Ndi\params\*NumRssQueues, type, 0, "int"
|
||||
HKR, Ndi\params\*NumRssQueues, default, 0, "16"
|
||||
HKR, Ndi\params\*NumRssQueues, min, 0, "1"
|
||||
HKR, Ndi\params\*NumRssQueues, max, 0, "32"
|
||||
HKR, Ndi\params\*NumRssQueues, step, 0, "1"
|
||||
|
||||
HKR, Ndi\params\*RscIPv4, ParamDesc, 0, "Recv Segment Coalescing (IPv4)"
|
||||
HKR, Ndi\params\*RscIPv4, Type, 0, "enum"
|
||||
HKR, Ndi\params\*RscIPv4, Default, 0, "1"
|
||||
HKR, Ndi\params\*RscIPv4, Optional, 0, "0"
|
||||
HKR, Ndi\params\*RscIPv4\enum, "0", 0, "Disabled"
|
||||
HKR, Ndi\params\*RscIPv4\enum, "1", 0, "Enabled"
|
||||
|
||||
HKR, Ndi\params\*RscIPv6, ParamDesc, 0, "Recv Segment Coalescing (IPv6)"
|
||||
HKR, Ndi\params\*RscIPv6, Type, 0, "enum"
|
||||
HKR, Ndi\params\*RscIPv6, Default, 0, "1"
|
||||
HKR, Ndi\params\*RscIPv6, Optional, 0, "0"
|
||||
HKR, Ndi\params\*RscIPv6\enum, "0", 0, "Disabled"
|
||||
HKR, Ndi\params\*RscIPv6\enum, "1", 0, "Enabled"
|
||||
HKR, Ndi\params\*UsoIPv4, ParamDesc, 0, "UDP Segmentation Offload (IPv4)"
|
||||
HKR, Ndi\params\*UsoIPv4, Type, 0, "enum"
|
||||
HKR, Ndi\params\*UsoIPv4, Default, 0, "1"
|
||||
HKR, Ndi\params\*UsoIPv4, Optional, 0, "0"
|
||||
HKR, Ndi\params\*UsoIPv4\enum, "0", 0, "Disabled"
|
||||
HKR, Ndi\params\*UsoIPv4\enum, "1", 0, "Enabled"
|
||||
|
||||
HKR, Ndi\params\*UsoIPv6, ParamDesc, 0, "UDP Segmentation Offload (IPv6)"
|
||||
HKR, Ndi\params\*UsoIPv6, Type, 0, "enum"
|
||||
HKR, Ndi\params\*UsoIPv6, Default, 0, "1"
|
||||
HKR, Ndi\params\*UsoIPv6, Optional, 0, "0"
|
||||
HKR, Ndi\params\*UsoIPv6\enum, "0", 0, "Disabled"
|
||||
HKR, Ndi\params\*UsoIPv6\enum, "1", 0, "Enabled"
|
||||
|
||||
HKR, Ndi\params\*NdisPoll, ParamDesc, 0, "Ndis Poll Mode"
|
||||
HKR, Ndi\params\*NdisPoll, Type, 0, "enum"
|
||||
HKR, Ndi\params\*NdisPoll, Default, 0, "1"
|
||||
HKR, Ndi\params\*NdisPoll, Optional, 0, "0"
|
||||
HKR, Ndi\params\*NdisPoll\enum, "0", 0, "Disabled"
|
||||
HKR, Ndi\params\*NdisPoll\enum, "1", 0, "Enabled"
|
||||
|
||||
BIN
windows/drivers/netkvm/netkvmco.exe
Normal file
BIN
windows/drivers/netkvm/netkvmco.exe
Normal file
Binary file not shown.
BIN
windows/drivers/netkvm/netkvmp.exe
Normal file
BIN
windows/drivers/netkvm/netkvmp.exe
Normal file
Binary file not shown.
@@ -160,6 +160,12 @@ function Invoke-PublishWelcome {
|
||||
Write-Stage 'Stage 3b: publish SilverOS Welcome app (win-x64 self-contained)'
|
||||
$proj = Join-Path $WindowsDir 'welcome\src\SilverOS.Welcome.App'
|
||||
$out = Join-Path $WorkDir 'welcome-publish'
|
||||
# Force a CLEAN compile. The CI runner reuses build artifacts across runs, and dotnet's
|
||||
# incremental build has shipped a STALE SilverOS.Welcome.Core.dll (old code despite fixed
|
||||
# source) -- so wipe every bin/obj under welcome/ before publishing (a clean tree forces a
|
||||
# full recompile; note `dotnet publish` does NOT accept --no-incremental).
|
||||
Get-ChildItem (Join-Path $WindowsDir 'welcome') -Recurse -Directory -EA SilentlyContinue |
|
||||
Where-Object { $_.Name -in 'bin', 'obj' } | Remove-Item -Recurse -Force -EA SilentlyContinue
|
||||
& dotnet publish $proj -c Release -f net9.0-windows10.0.19041.0 -r win-x64 --self-contained true -o $out
|
||||
if ($LASTEXITCODE -ne 0) { throw 'Welcome app dotnet publish failed' }
|
||||
Write-Host " Published to: $out"
|
||||
@@ -232,6 +238,48 @@ function Copy-WelcomePayload {
|
||||
Write-Host " Welcome payload staged at $dest"
|
||||
}
|
||||
|
||||
# Provision winget (App Installer) + its runtime deps into the OFFLINE image.
|
||||
# IoT Enterprise LTSC ships no winget and the runtime online bootstrap proved
|
||||
# unreliable (silent Add-AppxPackage failures), so we bake it in: download the
|
||||
# msixbundle + VCLibs + UI.Xaml on the (internet-connected) build host, then
|
||||
# Add-AppxProvisionedPackage into the mount so every first-boot user gets winget.
|
||||
# Non-fatal: a transient download failure must not brick the whole ISO build — the
|
||||
# staged runtime bootstrap-winget.ps1 remains as a last-resort fallback.
|
||||
function Add-WingetToImage {
|
||||
param([Parameter(Mandatory)][string]$MountPath, [Parameter(Mandatory)][string]$CacheDir)
|
||||
Write-Stage 'Stage 3c2: provision winget (App Installer + VCLibs + UI.Xaml) into image'
|
||||
try {
|
||||
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
|
||||
$null = New-Item -ItemType Directory -Force $CacheDir
|
||||
|
||||
$bundle = Join-Path $CacheDir 'Microsoft.DesktopAppInstaller.msixbundle'
|
||||
$vclibs = Join-Path $CacheDir 'Microsoft.VCLibs.x64.14.00.Desktop.appx'
|
||||
$xamlNupkg = Join-Path $CacheDir 'microsoft.ui.xaml.2.8.6.nupkg'
|
||||
$xamlDir = Join-Path $CacheDir 'uixaml'
|
||||
|
||||
Write-Host ' downloading App Installer (aka.ms/getwinget)'
|
||||
Invoke-WebRequest -UseBasicParsing 'https://aka.ms/getwinget' -OutFile $bundle
|
||||
Write-Host ' downloading VCLibs desktop framework'
|
||||
Invoke-WebRequest -UseBasicParsing 'https://aka.ms/Microsoft.VCLibs.x64.14.00.Desktop.appx' -OutFile $vclibs
|
||||
Write-Host ' downloading Microsoft.UI.Xaml 2.8.6 (nupkg)'
|
||||
Invoke-WebRequest -UseBasicParsing 'https://globalcdn.nuget.org/packages/microsoft.ui.xaml.2.8.6.nupkg' -OutFile $xamlNupkg
|
||||
|
||||
# The UI.Xaml appx lives inside the nupkg (a zip): tools\AppX\x64\Release\Microsoft.UI.Xaml.2.8.appx
|
||||
if (Test-Path $xamlDir) { Remove-Item $xamlDir -Recurse -Force }
|
||||
Expand-Archive -LiteralPath $xamlNupkg -DestinationPath $xamlDir -Force
|
||||
$xaml = Get-ChildItem (Join-Path $xamlDir 'tools\AppX\x64\Release') -Filter 'Microsoft.UI.Xaml.*.appx' -EA SilentlyContinue |
|
||||
Select-Object -First 1
|
||||
if (-not $xaml) { throw "UI.Xaml appx not found inside nupkg at tools\AppX\x64\Release" }
|
||||
|
||||
Write-Host ' provisioning App Installer into image (Add-AppxProvisionedPackage)'
|
||||
Add-AppxProvisionedPackage -Path $MountPath -PackagePath $bundle `
|
||||
-DependencyPackagePath $vclibs, $xaml.FullName -SkipLicense | Out-Null
|
||||
Write-Host ' winget provisioned into image OK' -ForegroundColor Green
|
||||
} catch {
|
||||
Write-Warning " winget provisioning FAILED (continuing; runtime bootstrap remains as fallback): $($_.Exception.Message)"
|
||||
}
|
||||
}
|
||||
|
||||
# --- 3. Service the WIM offline (DISM) -------------------------------------
|
||||
function Invoke-ServiceWim {
|
||||
Write-Stage 'Stage 3: offline-service install.wim'
|
||||
@@ -254,7 +302,13 @@ function Invoke-ServiceWim {
|
||||
# Drivers (GPD Pocket 4 pack) -- skipped silently if dir empty (e.g. VM test).
|
||||
$drv = Join-Path $WindowsDir 'drivers'
|
||||
if ((Get-ChildItem $drv -Recurse -Filter *.inf -EA SilentlyContinue)) {
|
||||
Write-Host ' adding drivers'; Add-WindowsDriver -Path $mount -Driver $drv -Recurse | Out-Null
|
||||
# -ForceUnsigned: skip the offline-inject signature check (the virtio NetKVM
|
||||
# driver is WHQL-signed and loads fine at boot; the offline check can still
|
||||
# reject it on the build host). Non-fatal: a driver issue must not brick the
|
||||
# whole image build -- warn and continue without it.
|
||||
Write-Host ' adding drivers'
|
||||
try { Add-WindowsDriver -Path $mount -Driver $drv -Recurse -ForceUnsigned -ErrorAction Stop | Out-Null }
|
||||
catch { Write-Warning " driver inject failed (continuing without it): $($_.Exception.Message)" }
|
||||
} else { Write-Host ' no .inf drivers staged (ok for VM test)' }
|
||||
|
||||
# Kiosk features (Shell Launcher v2 + Keyboard Filter) — IoT Enterprise LTSC.
|
||||
@@ -291,6 +345,14 @@ function Invoke-ServiceWim {
|
||||
# Stage Welcome app + flavours while the WIM is still mounted.
|
||||
Copy-WelcomePayload
|
||||
|
||||
# Provision winget (App Installer) + its deps INTO the image. IoT Enterprise LTSC
|
||||
# ships no winget, and the runtime online bootstrap proved unreliable (silent
|
||||
# Add-AppxPackage failures). Baking it in means winget is present for every user
|
||||
# at first boot, so the toolbox's app installs work without a runtime download.
|
||||
if ($env:SILVERMETAL_WELCOME_ENABLED -ne '0') {
|
||||
Add-WingetToImage -MountPath $mount -CacheDir (Join-Path $WorkDir 'winget')
|
||||
}
|
||||
|
||||
# Bake the four branding layers into the offline hives (must be inside the mount).
|
||||
Write-Stage 'Stage 3d: bake SilverMetal branding (OEM/lockscreen/desktop/bitlocker)'
|
||||
& (Join-Path $WindowsDir 'branding\Apply-Branding.ps1') -Mode Offline -MountPath $mount
|
||||
|
||||
@@ -54,11 +54,13 @@ public static class MauiProgram
|
||||
builder.Services.AddSingleton<IFlavourLoader, FlavourLoader>();
|
||||
builder.Services.AddSingleton<IAppCatalog, AppCatalog>();
|
||||
builder.Services.AddSingleton<IBitLockerService, BitLockerService>();
|
||||
builder.Services.AddSingleton<IHardeningService, HardeningService>();
|
||||
var appsDir = Path.Combine(AppContext.BaseDirectory, "apps");
|
||||
builder.Services.AddSingleton<IAppInstaller>(sp => new AppInstaller(sp.GetRequiredService<IProcessRunner>(), appsDir));
|
||||
builder.Services.AddSingleton<IApplyService>(sp => new ApplyService(
|
||||
sp.GetRequiredService<IBitLockerService>(),
|
||||
sp.GetRequiredService<IAppInstaller>()));
|
||||
sp.GetRequiredService<IAppInstaller>(),
|
||||
sp.GetRequiredService<IHardeningService>()));
|
||||
builder.Services.AddSingleton<IPreconfigStore>(_ => new PreconfigStore(@"C:\ProgramData\SilverMetal"));
|
||||
builder.Services.AddScoped<WizardState>();
|
||||
|
||||
|
||||
@@ -754,12 +754,28 @@ h1:focus { outline: none; }
|
||||
animation: step-enter 0.35s var(--ease-out) both;
|
||||
}
|
||||
|
||||
.apply-stage-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.55rem;
|
||||
margin-bottom: 0.6rem;
|
||||
}
|
||||
|
||||
.apply-spinner {
|
||||
width: 13px;
|
||||
height: 13px;
|
||||
border-radius: 50%;
|
||||
border: 2px solid var(--clr-accent-glow);
|
||||
border-top-color: var(--clr-accent);
|
||||
animation: sm-spin 0.8s linear infinite;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.apply-stage-label {
|
||||
font-family: var(--font-mono);
|
||||
font-size: 0.8rem;
|
||||
color: var(--clr-accent);
|
||||
letter-spacing: 0.04em;
|
||||
margin-bottom: 0.6rem;
|
||||
}
|
||||
|
||||
.apply-progress-track {
|
||||
@@ -772,11 +788,29 @@ h1:focus { outline: none; }
|
||||
}
|
||||
|
||||
.apply-progress-bar {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
background: linear-gradient(90deg, var(--clr-accent) 0%, var(--clr-success) 100%);
|
||||
border-radius: 99px;
|
||||
transition: width 0.4s var(--ease-out);
|
||||
box-shadow: 0 0 10px var(--clr-accent-glow);
|
||||
overflow: hidden;
|
||||
min-width: 2px;
|
||||
}
|
||||
|
||||
/* Continuous sheen so the bar visibly animates even when a single step (e.g. a
|
||||
long winget install) holds the percentage static — it never looks hung. */
|
||||
.apply-progress-bar.working::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: linear-gradient(90deg, transparent 0%, rgba(255,255,255,0.5) 50%, transparent 100%);
|
||||
transform: translateX(-100%);
|
||||
animation: sm-shimmer 1.3s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes sm-shimmer {
|
||||
to { transform: translateX(100%); }
|
||||
}
|
||||
|
||||
.apply-percent-label {
|
||||
@@ -787,6 +821,13 @@ h1:focus { outline: none; }
|
||||
margin-top: 0.3rem;
|
||||
}
|
||||
|
||||
.apply-hint {
|
||||
font-size: 0.74rem;
|
||||
color: var(--clr-text-lo);
|
||||
margin-top: 0.9rem;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
/* Complete state */
|
||||
.apply-complete {
|
||||
display: flex;
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
using SilverOS.Welcome.Core.Apps;
|
||||
namespace SilverOS.Welcome.Core.Apply;
|
||||
|
||||
// Toolbox Apply pipeline: apps -> bitlocker -> done.
|
||||
// Account creation moved to Windows Setup (WinPE collector); OS hardening runs from
|
||||
// SetupComplete; sm-bootstrap teardown is owned by Setup, not the toolbox.
|
||||
public sealed class ApplyService(IBitLockerService bitlocker, IAppInstaller installer) : IApplyService
|
||||
// Toolbox Apply pipeline: apps -> bitlocker -> hardening -> done.
|
||||
// Account creation moved to Windows Setup (WinPE collector); sm-bootstrap teardown is
|
||||
// owned by Setup. Hardening is DEFERRED to the toolbox by SetupComplete.cmd, so it runs
|
||||
// HERE (last, after the network-dependent app installs and the disk enrol).
|
||||
public sealed class ApplyService(IBitLockerService bitlocker, IAppInstaller installer, IHardeningService hardening) : IApplyService
|
||||
{
|
||||
public async Task RunAsync(ApplyRequest req, IProgress<ApplyProgress> progress, CancellationToken ct = default)
|
||||
{
|
||||
@@ -16,6 +17,12 @@ public sealed class ApplyService(IBitLockerService bitlocker, IAppInstaller inst
|
||||
progress.Report(new("Encrypting the disk", 75));
|
||||
await bitlocker.EnableAsync(req.BitLockerPin, ct);
|
||||
}
|
||||
|
||||
// Run hardening last: it can lock down the network/execution surface, so it must
|
||||
// come after the (network-dependent) app installs and the BitLocker PowerShell call.
|
||||
progress.Report(new("Applying security hardening", 90));
|
||||
await hardening.RunAsync(req.Flavour?.Hardening.Modules ?? Array.Empty<string>(), ct);
|
||||
|
||||
progress.Report(new("Done", 100));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
namespace SilverOS.Welcome.Core.Apply;
|
||||
|
||||
// Runs the §A–H hardening modules. SetupComplete.cmd DEFERS hardening to the toolbox
|
||||
// when the Welcome app is present ("hardening deferred to SilverOS Welcome"), so the
|
||||
// toolbox MUST actually run it here — a collector slim-down dropped this call, which
|
||||
// left hardening staged-but-never-executed on every install.
|
||||
public sealed class HardeningService(IProcessRunner runner) : IHardeningService
|
||||
{
|
||||
// build.ps1 stages the payload here (Windows\Setup\Scripts\hardening).
|
||||
private const string ScriptPath = @"C:\Windows\Setup\Scripts\hardening\Invoke-Hardening.ps1";
|
||||
|
||||
public async Task RunAsync(IReadOnlyList<string> modules, CancellationToken ct = default)
|
||||
{
|
||||
// Dev/VM image without the staged payload: no-op rather than crash the apply.
|
||||
if (!File.Exists(ScriptPath)) return;
|
||||
|
||||
var args = $"-NoProfile -ExecutionPolicy Bypass -File \"{ScriptPath}\"";
|
||||
if (modules is { Count: > 0 })
|
||||
// Invoke-Hardening.ps1 takes a single CSV token ("00,03,05") so -File binding
|
||||
// delivers it reliably regardless of quoting.
|
||||
args += $" -Modules \"{string.Join(",", modules)}\"";
|
||||
|
||||
// Invoke-Hardening.ps1 runs with ErrorActionPreference=Continue and try/catches each
|
||||
// module, so it returns 0 and logs its own per-module warnings. We deliberately do NOT
|
||||
// EnsureSuccess: a single hardening warning must never block onboarding completion.
|
||||
await runner.RunAsync("powershell.exe", args, ct);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace SilverOS.Welcome.Core.Apply;
|
||||
|
||||
public interface IHardeningService
|
||||
{
|
||||
/// <summary>
|
||||
/// Runs the §A–H hardening modules from the image-staged payload. <paramref name="modules"/>
|
||||
/// is the flavour's numeric module selection (e.g. ["00","03","05"]); empty = all modules.
|
||||
/// </summary>
|
||||
Task RunAsync(IReadOnlyList<string> modules, CancellationToken ct = default);
|
||||
}
|
||||
@@ -4,17 +4,38 @@ namespace SilverOS.Welcome.Core.Apps;
|
||||
|
||||
public sealed class AppInstaller(IProcessRunner runner, string appsDir) : IAppInstaller
|
||||
{
|
||||
// Best-effort diagnostic log (winget resolution, bootstrap output, per-app results).
|
||||
// Lives under ProgramData so it survives + is readable post-install. Never throws.
|
||||
private static readonly string LogPath = Path.Combine(
|
||||
Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "SilverMetal", "appinstall.log");
|
||||
|
||||
private static void Log(string msg)
|
||||
{
|
||||
try
|
||||
{
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(LogPath)!);
|
||||
File.AppendAllText(LogPath, $"{DateTime.Now:HH:mm:ss.fff} {msg}{Environment.NewLine}");
|
||||
}
|
||||
catch { /* logging is best-effort */ }
|
||||
}
|
||||
|
||||
private static string Snip(string? s) =>
|
||||
string.IsNullOrWhiteSpace(s) ? "" : s.Trim().Replace("\r", " ").Replace("\n", " ") is var t && t.Length > 300 ? t[..300] : t;
|
||||
|
||||
public async Task<IReadOnlyList<AppInstallResult>> InstallAsync(
|
||||
IReadOnlyList<AppCatalogEntry> apps, IProgress<ApplyProgress> progress, CancellationToken ct = default)
|
||||
{
|
||||
var results = new List<AppInstallResult>();
|
||||
if (apps.Count == 0) return results;
|
||||
|
||||
Log($"InstallAsync: {apps.Count} app(s) requested: {string.Join(", ", apps.Select(a => a.Id))}");
|
||||
|
||||
// App installs are non-critical: a missing/broken winget (e.g. offline IoT LTSC) must
|
||||
// NEVER fail onboarding. Resolve winget defensively; if it can't be found, skip installs.
|
||||
var winget = await ResolveWingetAsync(progress, ct);
|
||||
if (winget is null)
|
||||
{
|
||||
Log($"winget UNAVAILABLE -> skipping all {apps.Count} app(s)");
|
||||
progress.Report(new($"App installer unavailable - skipping {apps.Count} app(s)", 80));
|
||||
foreach (var app in apps) results.Add(new AppInstallResult(app.Id, false));
|
||||
return results;
|
||||
@@ -24,7 +45,9 @@ public sealed class AppInstaller(IProcessRunner runner, string appsDir) : IAppIn
|
||||
foreach (var app in apps)
|
||||
{
|
||||
i++;
|
||||
progress.Report(new($"Installing {app.Name} ({i}/{apps.Count})", 80));
|
||||
// Spread app installs across 30→70% (monotonic: BitLocker=75, hardening=90 follow).
|
||||
var pct = 30 + (int)(40.0 * (i - 1) / Math.Max(1, apps.Count));
|
||||
progress.Report(new($"Installing {app.Name} ({i}/{apps.Count})", pct));
|
||||
var ok = false;
|
||||
var id = app.Source.Winget;
|
||||
if (!string.IsNullOrWhiteSpace(id))
|
||||
@@ -33,6 +56,7 @@ public sealed class AppInstaller(IProcessRunner runner, string appsDir) : IAppIn
|
||||
$"install --id {id} --silent --accept-package-agreements --accept-source-agreements --disable-interactivity",
|
||||
ct);
|
||||
ok = r.ExitCode == 0;
|
||||
Log($"install {id}: exit={r.ExitCode} ok={ok} err={Snip(r.StdErr)}");
|
||||
if (ok && !string.IsNullOrWhiteSpace(app.Configure))
|
||||
{
|
||||
var script = Path.Combine(appsDir, "configure", app.Configure);
|
||||
@@ -43,6 +67,7 @@ public sealed class AppInstaller(IProcessRunner runner, string appsDir) : IAppIn
|
||||
}
|
||||
results.Add(new AppInstallResult(app.Id, ok));
|
||||
}
|
||||
Log($"InstallAsync done: {results.Count(r => r.Installed)}/{results.Count} installed");
|
||||
return results;
|
||||
}
|
||||
|
||||
@@ -52,22 +77,34 @@ public sealed class AppInstaller(IProcessRunner runner, string appsDir) : IAppIn
|
||||
private async Task<string?> ResolveWingetAsync(IProgress<ApplyProgress> progress, CancellationToken ct)
|
||||
{
|
||||
// 1) Already launchable by name (on PATH for this process)?
|
||||
if ((await TryRunAsync("winget", "--version", ct)).ExitCode == 0) return "winget";
|
||||
var p1 = await TryRunAsync("winget", "--version", ct);
|
||||
Log($"winget probe (PATH): exit={p1.ExitCode} out={Snip(p1.StdOut)}");
|
||||
if (p1.ExitCode == 0) return "winget";
|
||||
|
||||
// 2) Provision App Installer via the bundled bootstrap (or registered package), then re-probe.
|
||||
// 2) Provision App Installer, then re-probe. Run the bootstrap SCRIPT FILE directly
|
||||
// (it checks for winget and installs it online if absent). Invoking the .ps1 file
|
||||
// avoids an inline -Command (a prior inline if/else had an unbalanced-brace parse bug
|
||||
// from a non-interpolated string, so the bootstrap never actually ran).
|
||||
progress.Report(new("Preparing app installer", 68));
|
||||
var bootstrap = Path.Combine(appsDir, "bootstrap-winget.ps1");
|
||||
await TryRunAsync("powershell.exe",
|
||||
$"-NoProfile -ExecutionPolicy Bypass -Command \"if (Test-Path '{bootstrap}') {{ & '{bootstrap}' }} else {{ " +
|
||||
"Add-AppxPackage -RegisterByFamilyName -MainPackage Microsoft.DesktopAppInstaller_8wekyb3d8bbwe -EA SilentlyContinue }}\"",
|
||||
ct);
|
||||
if ((await TryRunAsync("winget", "--version", ct)).ExitCode == 0) return "winget";
|
||||
var b = File.Exists(bootstrap)
|
||||
? await TryRunAsync("powershell.exe", $"-NoProfile -ExecutionPolicy Bypass -File \"{bootstrap}\"", ct)
|
||||
: await TryRunAsync("powershell.exe",
|
||||
"-NoProfile -ExecutionPolicy Bypass -Command \"Add-AppxPackage -RegisterByFamilyName -MainPackage Microsoft.DesktopAppInstaller_8wekyb3d8bbwe -EA SilentlyContinue\"",
|
||||
ct);
|
||||
Log($"bootstrap-winget: exit={b.ExitCode} out={Snip(b.StdOut)} err={Snip(b.StdErr)}");
|
||||
var p2 = await TryRunAsync("winget", "--version", ct);
|
||||
Log($"winget probe (post-bootstrap): exit={p2.ExitCode} out={Snip(p2.StdOut)}");
|
||||
if (p2.ExitCode == 0) return "winget";
|
||||
|
||||
// 3) Fall back to the WindowsApps execution-alias path (bare-name launch can fail under
|
||||
// UseShellExecute=false even when winget is installed).
|
||||
var local = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
|
||||
var aliased = Path.Combine(local, "Microsoft", "WindowsApps", "winget.exe");
|
||||
if (File.Exists(aliased) && (await TryRunAsync(aliased, "--version", ct)).ExitCode == 0) return aliased;
|
||||
var aliasExists = File.Exists(aliased);
|
||||
var p3Exit = aliasExists ? (await TryRunAsync(aliased, "--version", ct)).ExitCode : -1;
|
||||
Log($"winget alias path '{aliased}': exists={aliasExists} probe={p3Exit}");
|
||||
if (aliasExists && p3Exit == 0) return aliased;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
@inject IAppCatalog AppCatalog
|
||||
@inject IPreconfigStore PreconfigStore
|
||||
@inject WizardState State
|
||||
@inject SilverOS.Welcome.Core.Apply.IProcessRunner ProcessRunner
|
||||
|
||||
@if (_toolboxHome)
|
||||
{
|
||||
@@ -83,6 +84,10 @@ else
|
||||
@(_currentStep == _stepTitles.Length - 2 ? "Apply" : "Next")
|
||||
</button>
|
||||
}
|
||||
else if (_currentStep == _stepTitles.Length - 1)
|
||||
{
|
||||
<button class="btn-primary" @onclick="RestartNow">Restart now</button>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
@@ -108,6 +113,11 @@ else
|
||||
private string? _error;
|
||||
private IReadOnlyList<FlavourManifest> _flavours = Array.Empty<FlavourManifest>();
|
||||
|
||||
private async Task RestartNow()
|
||||
{
|
||||
await ProcessRunner.RunAsync("cmd.exe", "/c shutdown /r /t 5", default);
|
||||
}
|
||||
|
||||
private bool CanGoNext => _currentStep switch
|
||||
{
|
||||
1 => State.Flavour is not null,
|
||||
|
||||
@@ -30,11 +30,24 @@
|
||||
else
|
||||
{
|
||||
<div class="apply-progress-container">
|
||||
<div class="apply-stage-label">@_stageLabel</div>
|
||||
<div class="apply-stage-row">
|
||||
@if (!_complete)
|
||||
{
|
||||
<span class="apply-spinner" aria-hidden="true"></span>
|
||||
}
|
||||
<div class="apply-stage-label">@_stageLabel</div>
|
||||
</div>
|
||||
<div class="apply-progress-track">
|
||||
<div class="apply-progress-bar" style="width: @(_percent)%"></div>
|
||||
<div class="apply-progress-bar @(_complete ? "" : "working")" style="width: @(_percent)%"></div>
|
||||
</div>
|
||||
<div class="apply-percent-label">@(_percent)%</div>
|
||||
@if (!_complete)
|
||||
{
|
||||
<p class="apply-hint">
|
||||
Installing your apps and applying security hardening — this can take several
|
||||
minutes. Please leave the device powered on.
|
||||
</p>
|
||||
}
|
||||
</div>
|
||||
|
||||
@if (_complete)
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
@using QRCoder
|
||||
@inject SilverOS.Welcome.Core.Apply.IProcessRunner ProcessRunner
|
||||
|
||||
<div class="step done-step">
|
||||
<h1>All Done!</h1>
|
||||
@@ -27,8 +26,6 @@
|
||||
</small></p>
|
||||
</div>
|
||||
}
|
||||
|
||||
<button class="btn-primary btn-restart" @onclick="RestartNow">Restart Now</button>
|
||||
</div>
|
||||
|
||||
@code {
|
||||
@@ -56,9 +53,4 @@
|
||||
catch { /* QR is best-effort; the key text still shows */ }
|
||||
}
|
||||
}
|
||||
|
||||
private async Task RestartNow()
|
||||
{
|
||||
await ProcessRunner.RunAsync("cmd.exe", "/c shutdown /r /t 5", CancellationToken.None);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,12 +19,9 @@ public class ApplyServiceTests
|
||||
new() { Id = "daily-driver", Hardening = new HardeningSpec { Modules = new[] { "00" } } };
|
||||
|
||||
[Fact]
|
||||
public async Task Runs_apps_then_bitlocker_when_pin_supplied()
|
||||
public async Task Runs_apps_then_bitlocker_then_hardening_when_pin_supplied()
|
||||
{
|
||||
var order = new List<string>();
|
||||
var run = new Mock<IProcessRunner>();
|
||||
run.Setup(r => r.RunAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(new ProcessResult(0, "", ""));
|
||||
var bl = new Mock<IBitLockerService>();
|
||||
bl.Setup(b => b.EnableAsync(It.IsAny<string>(), It.IsAny<CancellationToken>()))
|
||||
.Callback(() => order.Add("bitlocker")).Returns(Task.CompletedTask);
|
||||
@@ -32,25 +29,26 @@ public class ApplyServiceTests
|
||||
installer.Setup(i => i.InstallAsync(It.IsAny<IReadOnlyList<AppCatalogEntry>>(),
|
||||
It.IsAny<IProgress<ApplyProgress>>(), It.IsAny<CancellationToken>()))
|
||||
.Callback(() => order.Add("apps")).ReturnsAsync(Array.Empty<AppInstallResult>());
|
||||
var hard = new Mock<IHardeningService>();
|
||||
hard.Setup(h => h.RunAsync(It.IsAny<IReadOnlyList<string>>(), It.IsAny<CancellationToken>()))
|
||||
.Callback(() => order.Add("hardening")).Returns(Task.CompletedTask);
|
||||
|
||||
var sut = new ApplyService(bl.Object, installer.Object);
|
||||
var sut = new ApplyService(bl.Object, installer.Object, hard.Object);
|
||||
var req = new ApplyRequest(Flavour(), "123456", System.Array.Empty<AppCatalogEntry>());
|
||||
var progress = new List<string>();
|
||||
|
||||
await sut.RunAsync(req, new Progress<ApplyProgress>(p => progress.Add(p.Stage)));
|
||||
|
||||
Assert.Equal(new[] { "apps", "bitlocker" }, order);
|
||||
Assert.Equal(new[] { "apps", "bitlocker", "hardening" }, order);
|
||||
Assert.Contains("Installing apps", progress);
|
||||
Assert.Contains("Applying security hardening", progress);
|
||||
Assert.Contains("Done", progress);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Empty_pin_skips_bitlocker()
|
||||
public async Task Empty_pin_skips_bitlocker_but_still_hardens()
|
||||
{
|
||||
var order = new List<string>();
|
||||
var run = new Mock<IProcessRunner>();
|
||||
run.Setup(r => r.RunAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(new ProcessResult(0, "", ""));
|
||||
var bl = new Mock<IBitLockerService>();
|
||||
bl.Setup(b => b.EnableAsync(It.IsAny<string>(), It.IsAny<CancellationToken>()))
|
||||
.Callback(() => order.Add("bitlocker")).Returns(Task.CompletedTask);
|
||||
@@ -58,27 +56,46 @@ public class ApplyServiceTests
|
||||
installer.Setup(i => i.InstallAsync(It.IsAny<IReadOnlyList<AppCatalogEntry>>(),
|
||||
It.IsAny<IProgress<ApplyProgress>>(), It.IsAny<CancellationToken>()))
|
||||
.Callback(() => order.Add("apps")).ReturnsAsync(Array.Empty<AppInstallResult>());
|
||||
var hard = new Mock<IHardeningService>();
|
||||
hard.Setup(h => h.RunAsync(It.IsAny<IReadOnlyList<string>>(), It.IsAny<CancellationToken>()))
|
||||
.Callback(() => order.Add("hardening")).Returns(Task.CompletedTask);
|
||||
|
||||
var sut = new ApplyService(bl.Object, installer.Object);
|
||||
var sut = new ApplyService(bl.Object, installer.Object, hard.Object);
|
||||
var req = new ApplyRequest(Flavour(), "", System.Array.Empty<AppCatalogEntry>());
|
||||
|
||||
await sut.RunAsync(req, new Progress<ApplyProgress>(_ => { }));
|
||||
|
||||
Assert.Equal(new[] { "apps" }, order);
|
||||
Assert.Equal(new[] { "apps", "hardening" }, order);
|
||||
bl.Verify(b => b.EnableAsync(It.IsAny<string>(), It.IsAny<CancellationToken>()), Times.Never);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Hardening_runs_with_the_flavour_modules()
|
||||
{
|
||||
var bl = new Mock<IBitLockerService>();
|
||||
var installer = NoApps();
|
||||
var hard = new Mock<IHardeningService>();
|
||||
|
||||
var sut = new ApplyService(bl.Object, installer.Object, hard.Object);
|
||||
var req = new ApplyRequest(Flavour(), "123456", System.Array.Empty<AppCatalogEntry>());
|
||||
|
||||
await sut.RunAsync(req, new Progress<ApplyProgress>(_ => { }));
|
||||
|
||||
// Flavour() declares Modules = ["00"]; hardening must be invoked with exactly that.
|
||||
hard.Verify(h => h.RunAsync(
|
||||
It.Is<IReadOnlyList<string>>(m => m.Count == 1 && m[0] == "00"),
|
||||
It.IsAny<CancellationToken>()), Times.Once);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Installs_the_requested_apps()
|
||||
{
|
||||
var run = new Mock<IProcessRunner>();
|
||||
run.Setup(r => r.RunAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(new ProcessResult(0, "", ""));
|
||||
var bl = new Mock<IBitLockerService>();
|
||||
var installer = NoApps();
|
||||
var hard = new Mock<IHardeningService>();
|
||||
var apps = new[] { new AppCatalogEntry { Id = "firefox", Name = "Firefox" } };
|
||||
|
||||
var sut = new ApplyService(bl.Object, installer.Object);
|
||||
var sut = new ApplyService(bl.Object, installer.Object, hard.Object);
|
||||
var req = new ApplyRequest(Flavour(), "123456", apps);
|
||||
|
||||
await sut.RunAsync(req, new Progress<ApplyProgress>(_ => { }));
|
||||
|
||||
Reference in New Issue
Block a user