Skip to content

Instantly share code, notes, and snippets.

@Riebart
Created June 4, 2021 05:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Riebart/0b6ff09f66e9d4120b56ba61e990b41d to your computer and use it in GitHub Desktop.
Save Riebart/0b6ff09f66e9d4120b56ba61e990b41d to your computer and use it in GitHub Desktop.
#
# These variables are device properties. For people who are very
# curious about this, you can download the Windows Driver Kit headers and
# look for pciprop.h. All of these are contained in that file.
#
$devpkey_PciDevice_DeviceType = "{3AB22E31-8264-4b4e-9AF5-A8D2D8E33E62} 1"
$devpkey_PciDevice_RequiresReservedMemoryRegion = "{3AB22E31-8264-4b4e-9AF5-A8D2D8E33E62} 34"
$devpkey_PciDevice_AcsCompatibleUpHierarchy = "{3AB22E31-8264-4b4e-9AF5-A8D2D8E33E62} 31"
$devprop_PciDevice_DeviceType_PciConventional = 0
$devprop_PciDevice_DeviceType_PciX = 1
$devprop_PciDevice_DeviceType_PciExpressEndpoint = 2
$devprop_PciDevice_DeviceType_PciExpressLegacyEndpoint = 3
$devprop_PciDevice_DeviceType_PciExpressRootComplexIntegratedEndpoint= 4
$devprop_PciDevice_DeviceType_PciExpressTreatedAsPci = 5
$devprop_PciDevice_BridgeType_PciConventional = 6
$devprop_PciDevice_BridgeType_PciX = 7
$devprop_PciDevice_BridgeType_PciExpressRootPort = 8
$devprop_PciDevice_BridgeType_PciExpressUpstreamSwitchPort = 9
$devprop_PciDevice_BridgeType_PciExpressDownstreamSwitchPort = 10
$devprop_PciDevice_BridgeType_PciExpressToPciXBridge = 11
$devprop_PciDevice_BridgeType_PciXToExpressBridge = 12
$devprop_PciDevice_BridgeType_PciExpressTreatedAsPci = 13
$devprop_PciDevice_BridgeType_PciExpressEventCollector = 14
$devprop_PciDevice_AcsCompatibleUpHierarchy_NotSupported = 0
$devprop_PciDevice_AcsCompatibleUpHierarchy_SingleFunctionSupported = 1
$devprop_PciDevice_AcsCompatibleUpHierarchy_NoP2PSupported = 2
$devprop_PciDevice_AcsCompatibleUpHierarchy_Supported = 3
write-host "Generating a list of PCI Express endpoint devices"
$pnpdevs = Get-PnpDevice -PresentOnly
$pcidevs = $pnpdevs | Where-Object {$_.InstanceId -like "PCI*"}
foreach ($pcidev in $pcidevs) {
Write-Host ""
Write-Host ""
Write-Host -ForegroundColor White -BackgroundColor Black $pcidev.FriendlyName
$rmrr = ($pcidev | Get-PnpDeviceProperty $devpkey_PciDevice_RequiresReservedMemoryRegion).Data
if ($rmrr -ne 0) {
write-host -ForegroundColor Red -BackgroundColor Black "BIOS requires that this device remain attached to BIOS-owned memory. Not assignable."
continue
}
$acsUp = ($pcidev | Get-PnpDeviceProperty $devpkey_PciDevice_AcsCompatibleUpHierarchy).Data
if ($acsUp -eq $devprop_PciDevice_AcsCompatibleUpHierarchy_NotSupported) {
write-host -ForegroundColor Red -BackgroundColor Black "Traffic from this device may be redirected to other devices in the system. Not assignable."
continue
}
$devtype = ($pcidev | Get-PnpDeviceProperty $devpkey_PciDevice_DeviceType).Data
if ($devtype -eq $devprop_PciDevice_DeviceType_PciExpressEndpoint) {
Write-Host "Express Endpoint -- more secure."
} else {
if ($devtype -eq $devprop_PciDevice_DeviceType_PciExpressRootComplexIntegratedEndpoint) {
Write-Host "Embedded Endpoint -- less secure."
} else {
if ($devtype -eq $devprop_PciDevice_DeviceType_PciExpressTreatedAsPci) {
Write-Host -ForegroundColor Red -BackgroundColor Black "BIOS kept control of PCI Express for this device. Not assignable."
} else {
Write-Host -ForegroundColor Red -BackgroundColor Black "Old-style PCI device, switch port, etc. Not assignable."
}
continue
}
}
$locationpath = ($pcidev | get-pnpdeviceproperty DEVPKEY_Device_LocationPaths).data[0]
#
# If the device is disabled, we can't check the resources, report a warning and continue on.
#
#
if ($pcidev.ConfigManagerErrorCode -eq "CM_PROB_DISABLED")
{
Write-Host -ForegroundColor Yellow -BackgroundColor Black "Device is Disabled, unable to check resource requirements, it may be assignable."
Write-Host -ForegroundColor Yellow -BackgroundColor Black "Enable the device and rerun this script to confirm."
$locationpath
continue
}
#
# Now do a check for the interrupts that the device uses. Line-based interrupts
# aren't assignable.
#
$doubleslashDevId = "*" + $pcidev.PNPDeviceID.Replace("\","\\") + "*"
$irqAssignments = gwmi -query "select * from Win32_PnPAllocatedResource" | Where-Object {$_.__RELPATH -like "*Win32_IRQResource*"} | Where-Object {$_.Dependent -like $doubleslashDevId}
#$irqAssignments | Format-Table -Property __RELPATH
if ($irqAssignments.length -eq 0) {
Write-Host -ForegroundColor Green -BackgroundColor Black " And it has no interrupts at all -- assignment can work."
} else {
#
# Find the message-signaled interrupts. They are reported with a really big number in
# decimal, one which always happens to start with "42949...".
#
$msiAssignments = $irqAssignments | Where-Object {$_.Antecedent -like "*IRQNumber=42949*"}
#$msiAssignments | Format-Table -Property __RELPATH
if ($msiAssignments.length -eq 0) {
Write-Host -ForegroundColor Red -BackgroundColor Black "All of the interrupts are line-based, no assignment can work."
continue
} else {
Write-Host -ForegroundColor Green -BackgroundColor Black " And its interrupts are message-based, assignment can work."
}
}
#
# Check how much MMIO space the device needs
# not strictly an issue devices, but very useful when you want to set MMIO gap sizes
#
$mmioAssignments = gwmi -query "select * from Win32_PnPAllocatedResource" | Where-Object {$_.__RELPATH -like "*Win32_DeviceMemoryAddress*"} | Where-Object {$_.Dependent -like $doubleslashDevId}
$mmioTotal = 0
foreach ($mem in $mmioAssignments)
{
$baseAdd =$mem.Antecedent.SubString($mem.Antecedent.IndexOf("""")+1)
$baseAdd=$baseAdd.SubString(0,$baseAdd.IndexOf(""""))
$mmioRange = gwmi -query "select * from Win32_DeviceMemoryAddress" | Where-Object{$_.StartingAddress -like $baseAdd}
$mmioTotal = $mmioTotal + $mmioRange.EndingAddress - $mmioRange.StartingAddress
}
if ($mmioTotal -eq 0)
{
Write-Host -ForegroundColor Green -BackgroundColor Black " And it has no MMIO space"
} else {
[int]$mmioMB = [math]::ceiling($mmioTotal / 1MB)
Write-Host -ForegroundColor Green -BackgroundColor Black " And it requires at least:" $mmioMB "MB of MMIO gap space"
}
#
# Print out the location path, as that's the way to refer to this device that won't
# change even if you add or remove devices from the machine or change the way that
# the BIOS is configured.
#
$locationpath
}
#
# Now look at the host as a whole. Asking whether the host supports SR-IOV
# is mostly equivalent to asking whether it supports Discrete Device
# Assignment.
#
if ((Get-VMHost).IovSupport -eq $false) {
Write-Host ""
write-host "Unfortunately, this machine doesn't support using them in a VM."
Write-Host ""
(Get-VMHost).IovSupportReasons
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment