On 8/27/2026 9:38 AM, Ard Biesheuvel wrote:
> 
> On Thu, 27 Aug 2026, at 15:47, Alex Williamson via groups.io wrote:
>> On Thu, 27 Aug 2026 09:18:50 +0200
>> Gerd Hoffmann <[email protected]> wrote:
>>
>>>   Hi,
>>>
>>>> Following the feedback, RFC v2 keeps PCI enumeration and resource
>>>> assignment in firmware. QEMU only validates the user-provided fixed
>>>> BAR configuration and provides the required metadata to firmware
>>>> through the "etc/fixed-bars" fw_cfg file.  
>>>
>>> qemu already has vendor-specific pci capabilities.  They are used to
>>> pass hints for the bridge window sizes of pci bridges (including pcie
>>> root ports) with hotplug support.  See OvmfPkg/PciHotPlugInitDxe/ for
>>> the firmware side support.
>>>
>>> I'd strongly recommend to do the same for the fixed bars:  Add a pci
>>> capability to pass that information.  All the logic you have today to
>>> link the information in the fw_cfg file to the correct pci device is
>>> simply not needed any more then.
>>
>> Placement of a VMM defined capability into a vfio-pci device is not
>> such a trivial problem as it is for emulated devices.  Space may not be
>> readily available and the capability may mask non-architected registers.
>>
> 
> Is this the reason we cannot rely on the Enhanced Allocation (EA)
> capability here?

AFAICT, this was explored on RFC v1.
EFI_INCOMPATIBLE_PCI_DEVICE_SUPPORT_PROTOCOL was suggested as the
shorter path at the time, which is what this series uses.
> 
>> Does this suggestion relate to fixing the gap between mapping fw_cfg
>> entries by vendor/device IDs or is there something fundamentally
>> undesirable about using fw_cfg here?
>>
> 
> I much prefer this approach over the previous one, as the PCI resource
> allocation logic remains in the firmware where it belongs.
> 
> However, the OS may still re-assign/re-balance things in some cases, and
> so using a non-standard mechanism here means that the OS needs to learn
> that these devices are special.

This fixed-bar design already accounted for this using ACPI _DSM in
patch 4/5 — fixed BAR placement requires ACPI and emits the standard
_DSM function 5 (Preserve PCI Boot Configuration) for the hierarchy, so
the OS is told not to reassign these BARs.

> 
> ...
>>
>>>> On the firmware side, a new DXE driver, QemuFixedBarsDxe, installs
>>>> EFI_INCOMPATIBLE_PCI_DEVICE_SUPPORT_PROTOCOL before PciBusDxe starts.
>>>> When PciBusDxe calls CheckDevice() for a discovered PCI function, the
>>>> driver returns ACPI address descriptors with _MIF|_MAF set for fixed
>>>> BARs. Two small changes to PciBusDxe preserve these fixed addresses and
>>>> program them into the BAR registers during BAR programming.  
>>>
>>> Expecting PciBusDxe respecting AddrRangeMin looks sensible to me ...
>>>
>>>> After PciEnumerationComplete, QemuFixedBarsDxe walks each fixed
>>>> root-port hierarchy and programs the bridge memory windows to cover
>>>> the fixed BAR ranges assigned to endpoint devices.  
>>>
>>> ... but changing things after-the-fact in platform code is a complete
>>> non-starter.  PciBusDxe needs to do that, i.e. take care that the bridge
>>> window assigned actually cover the fixed pci bars.
>>>
> 
> Agreed - if the bridge windows are not programmed correctly on the first
> pass, there is something in the code that needs to be fixed. I don't think
> papering over it like this is the right approach.

That's a fair point. I did the window-sizing after PciBusDxe because I
didn't want to touch existing PciBusDxe code too much.

As per my understanding, PciBusDxe's enumeration splits into three phases:

Phase 1 (PciHostBridgeEnumerator) walks the whole tree and calls
CheckDevice() per device — by the time this phase finishes, every fixed
BAR address is already known and cached on the device
(PciBar[Bar].FixedBaseAddress).

Phase 2 (PciHostBridgeResourceAllocator) prepares an address for every
resource node in the tree — both individual BARs and bridge windows
alike — purely from size and alignment; PCI_RESOURCE_NODE has no address
field at all, so this is entirely blind to whether a fixed address was
already required.

Phase 3 (ProgramResource) then writes the actual PCI config-space
registers, and by default it just writes whatever address Phase 2
prepared, for both BARs and bridge windows. The one exception is
ProgramBar() — it specifically checks whether that particular BAR was
marked fixed back in Phase 1, and if so, overrides Phase 2's prepared
base address with the real fixed one. However, ProgramPpbApperture(),
which writes the bridge's own window registers, has no equivalent
override — it always writes whatever Phase 2 prepared, with no awareness
of a fixed BAR anywhere underneath it. And that needs fixing, and for
that I have to change the existing code.

I think the fix would be to extend Phase 2's own sizing step
(CalculateResourceAperture() in PciResourceSupport.c) to check for the
already-known fixed address on each child and, when present, size and
position the window as the exact union of those addresses instead of the
blind size-only sum. Does that match the direction you had in mind, or
is there a different integration point you'd suggest?


Thanks.
-Tushar




Reply via email to