diff --git a/OvmfPkg/Library/UefiDriverEntryPointFwCfgOverrideLib/UefiDriverEntryPointFwCfgOverrideLib.c b/OvmfPkg/Library/UefiDriverEntryPointFwCfgOverrideLib/UefiDriverEntryPointFwCfgOverrideLib.c new file mode 100644 index 0000000000..debbacb42f --- /dev/null +++ b/OvmfPkg/Library/UefiDriverEntryPointFwCfgOverrideLib/UefiDriverEntryPointFwCfgOverrideLib.c @@ -0,0 +1,148 @@ +/** @file + Entry point to a EFI/DXE driver. This version is specific to QEMU, and ties + dispatch of the driver in question on the value of a QEMU fw_cfg boolean + variable which is referenced by name via a fixed pointer PCD. + +Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+Copyright (c) 2022, Google LLC. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include + +#include + +#include +#include +#include +#include +#include + +/** + Unloads an image from memory. + + This function is a callback that a driver registers to do cleanup + when the UnloadImage boot service function is called. + + @param ImageHandle The handle to the image to unload. + + @return Status returned by all unload(). + +**/ +STATIC +EFI_STATUS +EFIAPI +_DriverUnloadHandler ( + EFI_HANDLE ImageHandle + ) +{ + EFI_STATUS Status; + + // + // If an UnloadImage() handler is specified, then call it + // + Status = ProcessModuleUnloadList (ImageHandle); + + // + // If the driver specific unload handler does not return an error, then call + // all of the library destructors. If the unload handler returned an error, + // then the driver can not be unloaded, and the library destructors should + // not be called + // + if (!EFI_ERROR (Status)) { + ProcessLibraryDestructorList (ImageHandle, gST); + } + + // + // Return the status from the driver specific unload handler + // + return Status; +} + +/** + The entry point of PE/COFF Image for a DXE Driver, DXE Runtime Driver, or + UEFI Driver. + + @param ImageHandle The image handle of the DXE Driver, DXE + Runtime Driver, or UEFI Driver. + @param SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The DXE Driver, DXE Runtime Driver, or + UEFI Driver exited normally. + @retval EFI_INCOMPATIBLE_VERSION _gUefiDriverRevision is greater than + SystemTable->Hdr.Revision. + @retval Other Return value from + ProcessModuleEntryPointList(). + +**/ +EFI_STATUS +EFIAPI +_ModuleEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; + RETURN_STATUS RetStatus; + BOOLEAN Enabled; + + if (_gUefiDriverRevision != 0) { + // + // Make sure that the EFI/UEFI spec revision of the platform is >= EFI/UEFI + // spec revision of the driver + // + if (SystemTable->Hdr.Revision < _gUefiDriverRevision) { + return EFI_INCOMPATIBLE_VERSION; + } + } + + // + // Call constructor for all libraries + // + ProcessLibraryConstructorList (ImageHandle, SystemTable); + + // + // Install unload handler... + // + if (_gDriverUnloadImageCount != 0) { + Status = gBS->HandleProtocol ( + ImageHandle, + &gEfiLoadedImageProtocolGuid, + (VOID **)&LoadedImage + ); + ASSERT_EFI_ERROR (Status); + LoadedImage->Unload = _DriverUnloadHandler; + } + + RetStatus = QemuFwCfgParseBool ( + FixedPcdGetPtr (PcdEntryPointOverrideFwCfgVarName), + &Enabled + ); + if (!RETURN_ERROR (RetStatus) && !Enabled) { + // + // The QEMU fw_cfg variable tells us not to load this image. So abort. + // + Status = EFI_ABORTED; + } else { + // + // Call the driver entry point + // + Status = ProcessModuleEntryPointList (ImageHandle, SystemTable); + } + + // + // If all of the drivers returned errors, or we if are aborting, then invoke + // all of the library destructors + // + if (EFI_ERROR (Status)) { + ProcessLibraryDestructorList (ImageHandle, SystemTable); + } + + // + // Return the cumulative return status code from all of the driver entry + // points + // + return Status; +} diff --git a/OvmfPkg/Library/UefiDriverEntryPointFwCfgOverrideLib/UefiDriverEntryPointFwCfgOverrideLib.inf b/OvmfPkg/Library/UefiDriverEntryPointFwCfgOverrideLib/UefiDriverEntryPointFwCfgOverrideLib.inf new file mode 100644 index 0000000000..263e00ceef --- /dev/null +++ b/OvmfPkg/Library/UefiDriverEntryPointFwCfgOverrideLib/UefiDriverEntryPointFwCfgOverrideLib.inf @@ -0,0 +1,57 @@ +## @file +# Entry point to a EFI/DXE driver. This version is specific to QEMU, and ties +# dispatch of the driver in question on the value of a QEMU fw_cfg boolean +# variable which is referenced by name via a fixed pointer PCD. +# +# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.
+# Copyright (c) 2022, Google LLC. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION = 1.29 + BASE_NAME = UefiDriverEntryPointFwCfgOverrideLib + FILE_GUID = 73349b79-f148-43b8-b24e-9098a6f3e1db + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = UefiDriverEntryPoint|DXE_DRIVER DXE_RUNTIME_DRIVER UEFI_DRIVER + +[Sources] + UefiDriverEntryPointFwCfgOverrideLib.c + +[Packages] + MdePkg/MdePkg.dec + OvmfPkg/OvmfPkg.dec + +[LibraryClasses] + BaseLib + DebugLib + QemuFwCfgSimpleParserLib + UefiBootServicesTableLib + +[Protocols] + gEfiLoadedImageProtocolGuid ## SOMETIMES_CONSUMES + +[FixedPcd] + gUefiOvmfPkgTokenSpaceGuid.PcdEntryPointOverrideFwCfgVarName + +# +# For UEFI drivers, these architectural protocols defined in PI 1.0 spec need +# to be appended and merged to the final dependency section. +# +[Depex.common.UEFI_DRIVER] + gEfiBdsArchProtocolGuid AND + gEfiCpuArchProtocolGuid AND + gEfiMetronomeArchProtocolGuid AND + gEfiMonotonicCounterArchProtocolGuid AND + gEfiRealTimeClockArchProtocolGuid AND + gEfiResetArchProtocolGuid AND + gEfiRuntimeArchProtocolGuid AND + gEfiSecurityArchProtocolGuid AND + gEfiTimerArchProtocolGuid AND + gEfiVariableWriteArchProtocolGuid AND + gEfiVariableArchProtocolGuid AND + gEfiWatchdogTimerArchProtocolGuid diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec index 6b1296b15a..6d689ecc5d 100644 --- a/OvmfPkg/OvmfPkg.dec +++ b/OvmfPkg/OvmfPkg.dec @@ -400,6 +400,10 @@ ## The Tdx accept page size. 0x1000(4k),0x200000(2M) gUefiOvmfPkgTokenSpaceGuid.PcdTdxAcceptPageSize|0x200000|UINT32|0x65 + ## The QEMU fw_cfg variable that UefiDriverEntryPointFwCfgOverrideLib will + # check to decide whether to abort dispatch of the driver it is linked into. + gUefiOvmfPkgTokenSpaceGuid.PcdEntryPointOverrideFwCfgVarName|""|VOID*|0x68 + [PcdsDynamic, PcdsDynamicEx] gUefiOvmfPkgTokenSpaceGuid.PcdEmuVariableEvent|0|UINT64|2 gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashVariablesEnable|FALSE|BOOLEAN|0x10