I agree. Reviewed-by: Ruiyu Ni <[email protected]>
>-----Original Message----- >From: Laszlo Ersek [mailto:[email protected]] >Sent: Thursday, May 19, 2016 3:38 PM >To: Ni, Ruiyu <[email protected]>; edk2-devel-01 <[email protected]> >Cc: Justen, Jordan L <[email protected]> >Subject: Re: [edk2] [PATCH] OvmfPkg: prevent 64-bit MMIO BAR degradation if >there is no CSM > >On 05/19/16 04:02, Ni, Ruiyu wrote: >> Laszlo, >> All are good except: can you use EfiCreateProtocolNotifyEvent() >> exposed by UefiLib? > >I am aware of that function, but I dislike it. The reason I dislike it >is that (in my opinion) its internal error handling is inferior. For the >return values of gBS->CreateEvent() and gBS->RegisterProtocolNotify(), >is only uses ASSERT_EFI_ERROR(), and to the return value of >gBS->SignalEvent(), it doesn't apply any check. > >I think the error handling in my code below is superior. CreateEvent() >can legitimately fail with EFI_OUT_OF_RESOURCES. So can >RegisterProtocolNotify(). > >I wondered before how the error handling could be fixed in >EfiCreateProtocolNotifyEvent(). One problem I see is that it returns an >EFI_EVENT object, not an EFI_STATUS one. > >Given that EFI_EVENT is just a typedef for VOID*, we could return a NULL >if something fails. However, in the library class header file, such a >return value is not permitted: > > @return The notification event that was created. > >This means that the ASSERT_EFI_ERROR() macro invocations in the function >body actually conform to the specification: namely, >EfiCreateProtocolNotifyEvent() is never supposed to fail (and I guess >all of its callers rely on this). > >Too bad that this function specification doesn't actually reflect >reality. (See the above EFI_OUT_OF_RESOURCES failure modes for >CreateEvent() and RegisterProtocolNotify().) > >Which is, I guess, my ultimate reason for never using this utility >function, and always open-coding CreateEvent() + >RegisterProtocolNotify() + SignalEvent() with proper error checking >(using an assert for SignalEvent(), which really can't fail, according >to the UEFI spec). > >Thanks >Laszlo > >>> -----Original Message----- >>> From: edk2-devel [mailto:[email protected]] On Behalf Of >>> Laszlo Ersek >>> Sent: Thursday, May 19, 2016 6:13 AM >>> To: edk2-devel-01 <[email protected]> >>> Cc: Ni, Ruiyu <[email protected]>; Justen, Jordan L >>> <[email protected]> >>> Subject: [edk2] [PATCH] OvmfPkg: prevent 64-bit MMIO BAR degradation if >>> there is no CSM >>> >>> According to edk2 commit >>> >>> "MdeModulePkg/PciBus: do not improperly degrade resource" >>> >>> and to the EFI_INCOMPATIBLE_PCI_DEVICE_SUPPORT_PROTOCOL definition in the >>> Platform Init 1.4a specification, a platform can provide such a protocol >>> in order to influence the PCI resource allocation performed by the PCI Bus >>> driver. >>> >>> In particular it is possible instruct the PCI Bus driver, with a >>> "wildcard" hint, to allocate the 64-bit MMIO BARs of a device in 64-bit >>> address space, regardless of whether the device features an option ROM. >>> >>> (By default, the PCI Bus driver considers an option ROM reason enough for >>> allocating the 64-bit MMIO BARs in 32-bit address space. It cannot know if >>> BDS will launch a legacy boot option, and under legacy boot, a legacy BIOS >>> binary from a combined option ROM could be dispatched, and fail to access >>> MMIO BARs in 64-bit address space.) >>> >>> In platform code we can ascertain whether a CSM is present or not. If not, >>> then legacy BIOS binaries in option ROMs can't be dispatched, hence the >>> BAR degradation is detrimental, and we should prevent it. This is expected >>> to conserve the 32-bit address space for 32-bit MMIO BARs. >>> >>> The driver added in this patch could be simplified based on the following >>> facts: >>> >>> - In the Ia32 build, the 64-bit MMIO aperture is always zero-size, hence >>> the driver will exit immediately. Therefore the driver could be omitted >>> from the Ia32 build. >>> >>> - In the Ia32X64 and X64 builds, the driver could be omitted if CSM_ENABLE >>> was defined (because in that case the degradation would be justified). >>> On the other hand, if CSM_ENABLE was undefined, then the driver could be >>> included, and it could provide the hint unconditionally (without looking >>> for the Legacy BIOS protocol). >>> >>> These short-cuts are not taken because they would increase the differences >>> between the OVMF DSC/FDF files. If we can manage without extreme >>> complexity, we should use dynamic logic (vs. build time configuration), >>> plus keep conditional compilation to a minimum. >>> >>> Cc: Jordan Justen <[email protected]> >>> Cc: Ruiyu Ni <[email protected]> >>> Contributed-under: TianoCore Contribution Agreement 1.0 >>> Signed-off-by: Laszlo Ersek <[email protected]> >>> --- >>> >>> Notes: >>> This patch will make a difference only when Ray's patch at >>> <http://thread.gmane.org/gmane.comp.bios.edk2.devel/12290/focus=12292> >>> is committed. >>> >>> OvmfPkg/OvmfPkgIa32.dsc | >>> 1 + >>> OvmfPkg/OvmfPkgIa32X64.dsc | >>> 1 + >>> OvmfPkg/OvmfPkgX64.dsc | >>> 1 + >>> OvmfPkg/OvmfPkgIa32.fdf | >>> 1 + >>> OvmfPkg/OvmfPkgIa32X64.fdf | >>> 1 + >>> OvmfPkg/OvmfPkgX64.fdf | >>> 1 + >>> OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.inf | >>> 50 +++ >>> OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.c | >>> 353 ++++++++++++++++++++ >>> 8 files changed, 409 insertions(+) >>> >>> diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc >>> index 45569f2875b5..1becb65cd878 100644 >>> --- a/OvmfPkg/OvmfPkgIa32.dsc >>> +++ b/OvmfPkg/OvmfPkgIa32.dsc >>> @@ -552,6 +552,7 @@ [Components] >>> UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf >>> UefiCpuPkg/CpuDxe/CpuDxe.inf >>> PcAtChipsetPkg/8254TimerDxe/8254Timer.inf >>> + OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.inf >>> MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf { >>> <LibraryClasses> >>> PciHostBridgeLib|OvmfPkg/Library/PciHostBridgeLib/PciHostBridgeLib.inf >>> diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc >>> index 05ff1c914455..3d838cdcb125 100644 >>> --- a/OvmfPkg/OvmfPkgIa32X64.dsc >>> +++ b/OvmfPkg/OvmfPkgIa32X64.dsc >>> @@ -561,6 +561,7 @@ [Components.X64] >>> UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf >>> UefiCpuPkg/CpuDxe/CpuDxe.inf >>> PcAtChipsetPkg/8254TimerDxe/8254Timer.inf >>> + OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.inf >>> MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf { >>> <LibraryClasses> >>> PciHostBridgeLib|OvmfPkg/Library/PciHostBridgeLib/PciHostBridgeLib.inf >>> diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc >>> index 54d4413f11f6..16d58bad7865 100644 >>> --- a/OvmfPkg/OvmfPkgX64.dsc >>> +++ b/OvmfPkg/OvmfPkgX64.dsc >>> @@ -559,6 +559,7 @@ [Components] >>> UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf >>> UefiCpuPkg/CpuDxe/CpuDxe.inf >>> PcAtChipsetPkg/8254TimerDxe/8254Timer.inf >>> + OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.inf >>> MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf { >>> <LibraryClasses> >>> PciHostBridgeLib|OvmfPkg/Library/PciHostBridgeLib/PciHostBridgeLib.inf >>> diff --git a/OvmfPkg/OvmfPkgIa32.fdf b/OvmfPkg/OvmfPkgIa32.fdf >>> index 594e84fd713b..8ab1633f832a 100644 >>> --- a/OvmfPkg/OvmfPkgIa32.fdf >>> +++ b/OvmfPkg/OvmfPkgIa32.fdf >>> @@ -207,6 +207,7 @@ [FV.DXEFV] >>> INF UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf >>> INF UefiCpuPkg/CpuDxe/CpuDxe.inf >>> INF PcAtChipsetPkg/8254TimerDxe/8254Timer.inf >>> +INF >>> OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.inf >>> INF MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf >>> INF MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf >>> INF PcAtChipsetPkg/KbcResetDxe/Reset.inf >>> diff --git a/OvmfPkg/OvmfPkgIa32X64.fdf b/OvmfPkg/OvmfPkgIa32X64.fdf >>> index 36a8f7e279c3..85fead07e957 100644 >>> --- a/OvmfPkg/OvmfPkgIa32X64.fdf >>> +++ b/OvmfPkg/OvmfPkgIa32X64.fdf >>> @@ -207,6 +207,7 @@ [FV.DXEFV] >>> INF UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf >>> INF UefiCpuPkg/CpuDxe/CpuDxe.inf >>> INF PcAtChipsetPkg/8254TimerDxe/8254Timer.inf >>> +INF >>> OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.inf >>> INF MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf >>> INF MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf >>> INF PcAtChipsetPkg/KbcResetDxe/Reset.inf >>> diff --git a/OvmfPkg/OvmfPkgX64.fdf b/OvmfPkg/OvmfPkgX64.fdf >>> index 4b1fa944ad1b..dd5ea30662d6 100644 >>> --- a/OvmfPkg/OvmfPkgX64.fdf >>> +++ b/OvmfPkg/OvmfPkgX64.fdf >>> @@ -207,6 +207,7 @@ [FV.DXEFV] >>> INF UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf >>> INF UefiCpuPkg/CpuDxe/CpuDxe.inf >>> INF PcAtChipsetPkg/8254TimerDxe/8254Timer.inf >>> +INF >>> OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.inf >>> INF MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf >>> INF MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf >>> INF PcAtChipsetPkg/KbcResetDxe/Reset.inf >>> diff --git >>> a/OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.inf >>> b/OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.inf >>> new file mode 100644 >>> index 000000000000..883e45c17436 >>> --- /dev/null >>> +++ >>> b/OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.inf >>> @@ -0,0 +1,50 @@ >>> +## @file >>> +# A simple DXE_DRIVER that causes the PCI Bus UEFI_DRIVER to allocate >>> 64-bit >>> +# MMIO BARs above 4 GB, regardless of option ROM availability (as long as >>> a CSM >>> +# is not present), conserving 32-bit MMIO aperture for 32-bit BARs. >>> +# >>> +# Copyright (C) 2016, Red Hat, Inc. >>> +# >>> +# This program and the accompanying materials are licensed and made >>> available >>> +# under the terms and conditions of the BSD License which accompanies this >>> +# distribution. The full text of the license may be found at >>> +# http://opensource.org/licenses/bsd-license.php >>> +# >>> +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, >>> WITHOUT >>> +# WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. >>> +## >>> + >>> +[Defines] >>> + INF_VERSION = 0x00010005 >>> + BASE_NAME = IncompatiblePciDeviceSupportDxe >>> + FILE_GUID = F6697AC4-A776-4EE1-B643-1FEFF2B615BB >>> + MODULE_TYPE = DXE_DRIVER >>> + VERSION_STRING = 1.0 >>> + ENTRY_POINT = DriverInitialize >>> + >>> +[Sources] >>> + IncompatiblePciDeviceSupport.c >>> + >>> +[Packages] >>> + IntelFrameworkPkg/IntelFrameworkPkg.dec >>> + MdeModulePkg/MdeModulePkg.dec >>> + MdePkg/MdePkg.dec >>> + OvmfPkg/OvmfPkg.dec >>> + >>> +[LibraryClasses] >>> + DebugLib >>> + MemoryAllocationLib >>> + PcdLib >>> + UefiBootServicesTableLib >>> + UefiDriverEntryPoint >>> + >>> +[Protocols] >>> + gEfiIncompatiblePciDeviceSupportProtocolGuid ## SOMETIMES_PRODUCES >>> + gEfiLegacyBiosProtocolGuid ## NOTIFY >>> + >>> +[Pcd] >>> + gEfiMdeModulePkgTokenSpaceGuid.PcdPciDisableBusEnumeration ## CONSUMES >>> + gUefiOvmfPkgTokenSpaceGuid.PcdPciMmio64Size ## CONSUMES >>> + >>> +[Depex] >>> + TRUE >>> diff --git >>> a/OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.c >>> b/OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.c >>> new file mode 100644 >>> index 000000000000..b6ff12842c21 >>> --- /dev/null >>> +++ b/OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.c >>> @@ -0,0 +1,353 @@ >>> +/** @file >>> + A simple DXE_DRIVER that causes the PCI Bus UEFI_DRIVER to allocate >>> 64-bit >>> + MMIO BARs above 4 GB, regardless of option ROM availability (as long as >>> a CSM >>> + is not present), conserving 32-bit MMIO aperture for 32-bit BARs. >>> + >>> + Copyright (C) 2016, Red Hat, Inc. >>> + >>> + This program and the accompanying materials are licensed and made >>> available >>> + under the terms and conditions of the BSD License which accompanies this >>> + distribution. The full text of the license may be found at >>> + http://opensource.org/licenses/bsd-license.php >>> + >>> + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, >>> WITHOUT >>> + WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. >>> +**/ >>> + >>> +#include <IndustryStandard/Acpi10.h> >>> +#include <IndustryStandard/Pci22.h> >>> + >>> +#include <Library/DebugLib.h> >>> +#include <Library/MemoryAllocationLib.h> >>> +#include <Library/PcdLib.h> >>> +#include <Library/UefiBootServicesTableLib.h> >>> + >>> +#include <Protocol/IncompatiblePciDeviceSupport.h> >>> +#include <Protocol/LegacyBios.h> >>> + >>> +// >>> +// The Legacy BIOS protocol has been located. >>> +// >>> +STATIC BOOLEAN mLegacyBiosInstalled; >>> + >>> +// >>> +// The protocol interface this driver produces. >>> +// >>> +STATIC EFI_INCOMPATIBLE_PCI_DEVICE_SUPPORT_PROTOCOL >>> + >>> mIncompatiblePciDeviceSupport; >>> + >>> +// >>> +// Configuration template for the CheckDevice() protocol member function. >>> +// >>> +// Refer to Table 20 "ACPI 2.0 & 3.0 QWORD Address Space Descriptor Usage" >>> in >>> +// the Platform Init 1.4a Spec, Volume 5. >>> +// >>> +// This structure is interpreted by the UpdatePciInfo() function in the >>> edk2 >>> +// PCI Bus UEFI_DRIVER. >>> +// >>> +#pragma pack (1) >>> +typedef struct { >>> + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR AddressSpaceDesc; >>> + EFI_ACPI_END_TAG_DESCRIPTOR EndDesc; >>> +} MMIO64_PREFERENCE; >>> +#pragma pack () >>> + >>> +STATIC CONST MMIO64_PREFERENCE mConfiguration = { >>> + // >>> + // AddressSpaceDesc >>> + // >>> + { >>> + ACPI_ADDRESS_SPACE_DESCRIPTOR, // Desc >>> + (UINT16)( // Len >>> + sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - >>> + OFFSET_OF ( >>> + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR, >>> + ResType >>> + ) >>> + ), >>> + ACPI_ADDRESS_SPACE_TYPE_MEM, // ResType >>> + PCI_ACPI_UNUSED, // GenFlag >>> + PCI_ACPI_UNUSED, // SpecificFlag >>> + 64, // AddrSpaceGranularity: >>> + // aperture selection >>> hint >>> + // for BAR allocation >>> + PCI_ACPI_UNUSED, // AddrRangeMin >>> + PCI_BAR_OLD_ALIGN, // AddrRangeMax: >>> + // no special >>> alignment >>> + // for affected BARs >>> + PCI_BAR_ALL, // >>> AddrTranslationOffset: >>> + // hint covers all >>> + // eligible BARs >>> + PCI_BAR_NOCHANGE // AddrLen: >>> + // use probed BAR size >>> + }, >>> + // >>> + // EndDesc >>> + // >>> + { >>> + ACPI_END_TAG_DESCRIPTOR, // Desc >>> + 0 // Checksum: to be >>> ignored >>> + } >>> +}; >>> + >>> +// >>> +// The CheckDevice() member function has been called. >>> +// >>> +STATIC BOOLEAN mCheckDeviceCalled; >>> + >>> + >>> +/** >>> + Notification callback for Legacy BIOS protocol installation. >>> + >>> + @param[in] Event Event whose notification function is being invoked. >>> + >>> + @param[in] Context The pointer to the notification function's context, >>> which >>> + is implementation-dependent. >>> +**/ >>> +STATIC >>> +VOID >>> +EFIAPI >>> +LegacyBiosInstalled ( >>> + IN EFI_EVENT Event, >>> + IN VOID *Context >>> + ) >>> +{ >>> + EFI_STATUS Status; >>> + EFI_LEGACY_BIOS_PROTOCOL *LegacyBios; >>> + >>> + ASSERT (!mCheckDeviceCalled); >>> + >>> + Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, >>> + NULL /* Registration */, (VOID **)&LegacyBios); >>> + if (EFI_ERROR (Status)) { >>> + return; >>> + } >>> + >>> + mLegacyBiosInstalled = TRUE; >>> + >>> + // >>> + // Close the event and deregister this callback. >>> + // >>> + Status = gBS->CloseEvent (Event); >>> + ASSERT_EFI_ERROR (Status); >>> +} >>> + >>> + >>> +/** >>> + Returns a list of ACPI resource descriptors that detail the special >>> resource >>> + configuration requirements for an incompatible PCI device. >>> + >>> + Prior to bus enumeration, the PCI bus driver will look for the presence >>> of >>> + the EFI_INCOMPATIBLE_PCI_DEVICE_SUPPORT_PROTOCOL. Only one instance of >>> this >>> + protocol can be present in the system. For each PCI device that the PCI >>> bus >>> + driver discovers, the PCI bus driver calls this function with the >>> device's >>> + vendor ID, device ID, revision ID, subsystem vendor ID, and subsystem >>> device >>> + ID. If the VendorId, DeviceId, RevisionId, SubsystemVendorId, or >>> + SubsystemDeviceId value is set to (UINTN)-1, that field will be ignored. >>> The >>> + ID values that are not (UINTN)-1 will be used to identify the current >>> device. >>> + >>> + This function will only return EFI_SUCCESS. However, if the device is an >>> + incompatible PCI device, a list of ACPI resource descriptors will be >>> returned >>> + in Configuration. Otherwise, NULL will be returned in Configuration >>> instead. >>> + The PCI bus driver does not need to allocate memory for Configuration. >>> + However, it is the PCI bus driver's responsibility to free it. The PCI >>> bus >>> + driver then can configure this device with the information that is >>> derived >>> + from this list of resource nodes, rather than the result of BAR probing. >>> + >>> + Only the following two resource descriptor types from the ACPI >>> Specification >>> + may be used to describe the incompatible PCI device resource >>> requirements: >>> + - QWORD Address Space Descriptor (ACPI 2.0, section 6.4.3.5.1; also ACPI >>> 3.0) >>> + - End Tag (ACPI 2.0, section 6.4.2.8; also ACPI 3.0) >>> + >>> + The QWORD Address Space Descriptor can describe memory, I/O, and bus >>> number >>> + ranges for dynamic or fixed resources. The configuration of a PCI root >>> bridge >>> + is described with one or more QWORD Address Space Descriptors, followed >>> by an >>> + End Tag. See the ACPI Specification for details on the field values. >>> + >>> + @param[in] This Pointer to the >>> + >>> EFI_INCOMPATIBLE_PCI_DEVICE_SUPPORT_PROTOCOL >>> + instance. >>> + >>> + @param[in] VendorId A unique ID to identify the manufacturer >>> of >>> + the PCI device. See the Conventional PCI >>> + Specification 3.0 for details. >>> + >>> + @param[in] DeviceId A unique ID to identify the particular >>> PCI >>> + device. See the Conventional PCI >>> + Specification 3.0 for details. >>> + >>> + @param[in] RevisionId A PCI device-specific revision >>> identifier. >>> + See the Conventional PCI Specification >>> 3.0 >>> + for details. >>> + >>> + @param[in] SubsystemVendorId Specifies the subsystem vendor ID. See >>> the >>> + Conventional PCI Specification 3.0 for >>> + details. >>> + >>> + @param[in] SubsystemDeviceId Specifies the subsystem device ID. See >>> the >>> + Conventional PCI Specification 3.0 for >>> + details. >>> + >>> + @param[out] Configuration A list of ACPI resource descriptors that >>> + detail the configuration requirement. >>> + >>> + @retval EFI_SUCCESS The function always returns EFI_SUCCESS. >>> +**/ >>> +STATIC >>> +EFI_STATUS >>> +EFIAPI >>> +CheckDevice ( >>> + IN EFI_INCOMPATIBLE_PCI_DEVICE_SUPPORT_PROTOCOL *This, >>> + IN UINTN VendorId, >>> + IN UINTN DeviceId, >>> + IN UINTN RevisionId, >>> + IN UINTN SubsystemVendorId, >>> + IN UINTN SubsystemDeviceId, >>> + OUT VOID **Configuration >>> + ) >>> +{ >>> + mCheckDeviceCalled = TRUE; >>> + >>> + // >>> + // Unlike the general description of this protocol member suggests, >>> there is >>> + // nothing incompatible about the PCI devices that we'll match here. >>> We'll >>> + // match all PCI devices, and generate exactly one QWORD Address Space >>> + // Descriptor for each. That descriptor will instruct the PCI Bus >>> UEFI_DRIVER >>> + // not to degrade 64-bit MMIO BARs for the device, even if a PCI option >>> ROM >>> + // BAR is present on the device. >>> + // >>> + // The concern captured in the PCI Bus UEFI_DRIVER is that a legacy BIOS >>> boot >>> + // (via a CSM) could dispatch a legacy option ROM on the device, which >>> might >>> + // have trouble with MMIO BARs that have been allocated outside of the >>> 32-bit >>> + // address space. But, if we don't support legacy option ROMs at all, >>> then >>> + // this problem cannot arise. >>> + // >>> + if (mLegacyBiosInstalled) { >>> + // >>> + // Don't interfere with resource degradation. >>> + // >>> + *Configuration = NULL; >>> + return EFI_SUCCESS; >>> + } >>> + >>> + // >>> + // This member function is mis-specified actually: it is supposed to >>> allocate >>> + // memory, but as specified, it could not return an error status. >>> Thankfully, >>> + // the edk2 PCI Bus UEFI_DRIVER actually handles error codes; see the >>> + // UpdatePciInfo() function. >>> + // >>> + *Configuration = AllocateCopyPool (sizeof mConfiguration, >>> &mConfiguration); >>> + if (*Configuration == NULL) { >>> + DEBUG ((EFI_D_WARN, >>> + "%a: 64-bit MMIO BARs may be degraded for PCI 0x%04x:0x%04x (rev >>> %d)\n", >>> + __FUNCTION__, (UINT32)VendorId, (UINT32)DeviceId, >>> (UINT8)RevisionId)); >>> + return EFI_OUT_OF_RESOURCES; >>> + } >>> + return EFI_SUCCESS; >>> +} >>> + >>> + >>> +/** >>> + Entry point for this driver. >>> + >>> + @param[in] ImageHandle Image handle of this driver. >>> + @param[in] SystemTable Pointer to SystemTable. >>> + >>> + @retval EFI_SUCESS Driver has loaded successfully. >>> + @retval EFI_UNSUPPORTED PCI resource allocation has been disabled. >>> + @retval EFI_UNSUPPORTED There is no 64-bit PCI MMIO aperture. >>> + @return Error codes from lower level functions. >>> + >>> +**/ >>> +EFI_STATUS >>> +EFIAPI >>> +DriverInitialize ( >>> + IN EFI_HANDLE ImageHandle, >>> + IN EFI_SYSTEM_TABLE *SystemTable >>> + ) >>> +{ >>> + EFI_STATUS Status; >>> + EFI_EVENT Event; >>> + VOID *Registration; >>> + >>> + // >>> + // If the PCI Bus driver is not supposed to allocate resources, then it >>> makes >>> + // no sense to install a protocol that influences the resource >>> allocation. >>> + // >>> + // Similarly, if there is no 64-bit PCI MMIO aperture, then 64-bit MMIO >>> BARs >>> + // have to be allocated under 4 GB unconditionally. >>> + // >>> + if (PcdGetBool (PcdPciDisableBusEnumeration) || >>> + PcdGet64 (PcdPciMmio64Size) == 0) { >>> + return EFI_UNSUPPORTED; >>> + } >>> + >>> + // >>> + // Otherwise, create a protocol notify to see if a CSM is present. (With >>> the >>> + // CSM absent, the PCI Bus driver won't have to worry about allocating >>> 64-bit >>> + // MMIO BARs in the 32-bit MMIO aperture, for the sake of a legacy BIOS.) >>> + // >>> + // If the Legacy BIOS Protocol is present at the time of this driver >>> starting >>> + // up, we can mark immediately that the PCI Bus driver should perform the >>> + // usual 64-bit MMIO BAR degradation. >>> + // >>> + // Otherwise, if the Legacy BIOS Protocol is absent at startup, it may be >>> + // installed later. However, if it doesn't show up until the first >>> + // EFI_INCOMPATIBLE_PCI_DEVICE_SUPPORT_PROTOCOL.CheckDevice() call from >>> the >>> + // PCI Bus driver, then it never will: >>> + // >>> + // 1. The following drivers are dispatched in some unspecified order: >>> + // - PCI Host Bridge DXE_DRIVER, >>> + // - PCI Bus UEFI_DRIVER, >>> + // - this DXE_DRIVER, >>> + // - Legacy BIOS DXE_DRIVER. >>> + // >>> + // 2. The DXE_CORE enters BDS. >>> + // >>> + // 3. The platform BDS connects the PCI Root Bridge IO instances >>> (produced by >>> + // the PCI Host Bridge DXE_DRIVER). >>> + // >>> + // 4. The PCI Bus UEFI_DRIVER enumerates resources and calls into this >>> + // DXE_DRIVER (CheckDevice()). >>> + // >>> + // 5. This driver remembers if EFI_LEGACY_BIOS_PROTOCOL has been >>> installed >>> + // sometime during step 1 (produced by the Legacy BIOS DXE_DRIVER). >>> + // >>> + // For breaking this order, the Legacy BIOS DXE_DRIVER would have to >>> install >>> + // its protocol after the firmware enters BDS, which cannot happen. >>> + // >>> + Status = gBS->CreateEvent (EVT_NOTIFY_SIGNAL, TPL_CALLBACK, >>> + LegacyBiosInstalled, NULL /* Context */, &Event); >>> + if (EFI_ERROR (Status)) { >>> + return Status; >>> + } >>> + >>> + Status = gBS->RegisterProtocolNotify (&gEfiLegacyBiosProtocolGuid, Event, >>> + &Registration); >>> + if (EFI_ERROR (Status)) { >>> + goto CloseEvent; >>> + } >>> + >>> + Status = gBS->SignalEvent (Event); >>> + ASSERT_EFI_ERROR (Status); >>> + >>> + mIncompatiblePciDeviceSupport.CheckDevice = CheckDevice; >>> + Status = gBS->InstallMultipleProtocolInterfaces (&ImageHandle, >>> + &gEfiIncompatiblePciDeviceSupportProtocolGuid, >>> + &mIncompatiblePciDeviceSupport, NULL); >>> + if (EFI_ERROR (Status)) { >>> + goto CloseEvent; >>> + } >>> + >>> + return EFI_SUCCESS; >>> + >>> +CloseEvent: >>> + if (!mLegacyBiosInstalled) { >>> + EFI_STATUS CloseStatus; >>> + >>> + CloseStatus = gBS->CloseEvent (Event); >>> + ASSERT_EFI_ERROR (CloseStatus); >>> + } >>> + >>> + return Status; >>> +} >>> -- >>> 1.8.3.1 >>> >>> _______________________________________________ >>> edk2-devel mailing list >>> [email protected] >>> https://lists.01.org/mailman/listinfo/edk2-devel _______________________________________________ edk2-devel mailing list [email protected] https://lists.01.org/mailman/listinfo/edk2-devel

