From a955e8811bc9e34d7d01ab373aefaecc5fde5a3c Mon Sep 17 00:00:00 2001 From: Mikhail Krichanov Date: Thu, 18 Jul 2024 11:30:45 +0300 Subject: [PATCH] SecurePE: Replaced old PE loader with Secure one. --- ArmPkg/ArmPkg.dsc | 8 +- .../ArmCrashDumpDxe/ArmCrashDumpDxe.dsc | 1 - ArmPkg/Drivers/CpuDxe/CpuDxe.h | 1 - ArmPkg/Drivers/CpuDxe/CpuDxe.inf | 1 - .../ArmDisassemblerLib/ArmDisassemblerLib.inf | 1 - .../DebugAgentSymbolsBaseLib.c | 91 +- .../DebugAgentSymbolsBaseLib.inf | 4 +- .../DebugUefiImageExtraActionLib.c | 141 +++ .../DebugUefiImageExtraActionLib.inf | 33 + .../AArch64/DefaultExceptionHandler.c | 27 +- .../Arm/DefaultExceptionHandler.c | 29 +- .../DefaultExceptionHandlerLib.inf | 1 - .../DefaultExceptionHandlerUefi.c | 10 +- ArmPlatformPkg/ArmPlatformPkg.dsc | 5 +- ArmPlatformPkg/PrePi/PrePi.h | 1 + ArmVirtPkg/ArmVirt.dsc.inc | 10 +- ArmVirtPkg/PrePi/AArch64/ModuleEntryPoint.S | 3 +- ArmVirtPkg/PrePi/Arm/ModuleEntryPoint.S | 3 +- .../PrePi/ArmVirtPrePiUniCoreRelocatable.inf | 2 +- ArmVirtPkg/PrePi/PrePi.c | 33 +- BaseTools/Source/C/GenFv/GenFvInternalLib.c | 217 +++- BaseTools/Source/C/GenFv/GenFvInternalLib.h | 3 +- BaseTools/Source/Python/build/build.py | 23 +- EmbeddedPkg/EmbeddedPkg.dec | 1 - EmbeddedPkg/EmbeddedPkg.dsc | 6 +- EmbeddedPkg/GdbStub/GdbStub.c | 170 +--- EmbeddedPkg/GdbStub/GdbStubInternal.h | 2 +- EmbeddedPkg/Include/Library/PrePiLib.h | 17 +- EmbeddedPkg/Library/PrePiHobLib/Hob.c | 24 +- EmbeddedPkg/Library/PrePiLib/FwVol.c | 32 +- EmbeddedPkg/Library/PrePiLib/PrePi.h | 2 +- EmbeddedPkg/Library/PrePiLib/PrePiLib.c | 71 +- EmbeddedPkg/Library/PrePiLib/PrePiLib.inf | 5 +- EmulatorPkg/EmulatorPkg.dsc | 18 +- EmulatorPkg/Include/Library/EmuMagicPageLib.h | 2 +- EmulatorPkg/Include/Protocol/EmuThunk.h | 17 +- .../DxeEmuPeCoffExtraActionLib.c | 11 +- .../DxeEmuUefiImageExtraActionLib.c | 94 ++ .../DxeEmuUefiImageExtraActionLib.inf | 42 + .../PeiEmuPeCoffExtraActionLib.c | 34 +- .../PeiEmuPeCoffGetEntryPointLib.c | 9 +- .../PeiEmuUefiImageExtraActionLib.c | 101 ++ .../PeiEmuUefiImageExtraActionLib.inf | 43 + EmulatorPkg/Library/SecPeiServicesLib/FwVol.c | 49 + .../SecPeiServicesLib/PeiServicesLib.c | 40 + EmulatorPkg/Sec/Sec.c | 56 +- EmulatorPkg/Sec/Sec.h | 1 - EmulatorPkg/Sec/Sec.inf | 1 - EmulatorPkg/Unix/GdbRun.sh | 2 +- EmulatorPkg/Unix/Host/EmuThunk.c | 6 +- EmulatorPkg/Unix/Host/Gasket.h | 11 +- EmulatorPkg/Unix/Host/Host.c | 337 ++----- EmulatorPkg/Unix/Host/Host.h | 37 +- EmulatorPkg/Unix/Host/Host.inf | 3 +- EmulatorPkg/Unix/Host/Ia32/Gasket.S | 22 +- EmulatorPkg/Unix/Host/X64/Gasket.S | 19 +- EmulatorPkg/Unix/lldbefi.py | 4 +- EmulatorPkg/Win/Host/WinHost.c | 75 +- EmulatorPkg/Win/Host/WinHost.h | 12 +- EmulatorPkg/Win/Host/WinHost.inf | 2 +- EmulatorPkg/Win/Host/WinThunk.c | 6 +- IntelFsp2Pkg/Tools/Tests/QemuFspPkg.dsc | 6 +- .../FspWrapperNotifyDxe.inf | 3 +- .../FspWrapperNotifyDxe/LoadBelow4G.c | 68 +- .../FspmWrapperPeim/FspmWrapperPeim.inf | 4 +- .../FspsWrapperPeim/FspsWrapperPeim.inf | 4 +- IntelFsp2WrapperPkg/IntelFsp2WrapperPkg.dsc | 6 +- LoaderFlow.png | Bin 0 -> 218450 bytes MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.h | 2 +- MdeModulePkg/Core/Dxe/DxeMain.h | 34 +- MdeModulePkg/Core/Dxe/DxeMain.inf | 5 +- MdeModulePkg/Core/Dxe/DxeMain/DxeMain.c | 40 +- MdeModulePkg/Core/Dxe/Image/Image.c | 635 ++++++------ MdeModulePkg/Core/Dxe/Mem/HeapGuard.c | 2 +- .../Core/Dxe/Mem/MemoryProfileRecord.c | 252 +---- MdeModulePkg/Core/Dxe/Misc/DebugImageInfo.c | 72 +- .../Core/Dxe/Misc/MemoryAttributesTable.c | 210 ++-- MdeModulePkg/Core/Dxe/Misc/MemoryProtection.c | 269 +++-- MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c | 120 ++- MdeModulePkg/Core/Pei/FwVol/FwVol.c | 104 +- MdeModulePkg/Core/Pei/FwVol/FwVol.h | 37 + MdeModulePkg/Core/Pei/Image/Image.c | 487 +++------ MdeModulePkg/Core/Pei/PeiMain.h | 45 +- MdeModulePkg/Core/Pei/PeiMain.inf | 3 +- MdeModulePkg/Core/Pei/PeiMain/PeiMain.c | 1 + MdeModulePkg/Core/Pei/Ppi/Ppi.c | 25 +- MdeModulePkg/Core/PiSmmCore/DebugImageInfo.c | 153 +++ MdeModulePkg/Core/PiSmmCore/Dispatcher.c | 329 +++--- .../PiSmmCore/MemoryAllocation.c} | 3 +- .../Core/PiSmmCore/MemoryAttributesTable.c | 255 ++--- MdeModulePkg/Core/PiSmmCore/PiSmmCore.c | 23 +- MdeModulePkg/Core/PiSmmCore/PiSmmCore.h | 62 +- MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf | 7 +- .../Core/PiSmmCore/PiSmmCorePrivateData.h | 4 +- MdeModulePkg/Core/PiSmmCore/PiSmmIpl.c | 189 ++-- MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf | 2 +- .../Core/PiSmmCore/SmiHandlerProfile.c | 20 +- .../Core/PiSmmCore/SmramProfileRecord.c | 273 ++--- MdeModulePkg/Core/RuntimeDxe/Runtime.c | 8 +- MdeModulePkg/Core/RuntimeDxe/Runtime.h | 2 +- MdeModulePkg/Core/RuntimeDxe/RuntimeDxe.inf | 2 +- MdeModulePkg/Include/Guid/MemoryProfile.h | 5 +- .../Library/ImagePropertiesRecordLib.h | 158 +-- .../DxeCorePerformanceLib.c | 9 +- .../DxeCorePerformanceLib.inf | 1 - .../DxeCorePerformanceLibInternal.h | 1 - .../ImagePropertiesRecordLib.c | 810 ++------------- .../ImagePropertiesRecordLib.inf | 2 +- .../PiSmmCoreMemoryAllocationLib.inf | 5 +- .../PiSmmCoreMemoryAllocationProfileLib.inf | 6 +- .../PiSmmCoreMemoryAllocationServices.h | 185 ---- .../SmmCorePerformanceLib.c | 11 +- .../SmmCorePerformanceLib.inf | 1 - .../SmmCorePerformanceLibInternal.h | 1 - .../Library/UefiBootManagerLib/BmLoadOption.c | 103 +- .../Library/UefiBootManagerLib/InternalBm.h | 3 +- .../UefiBootManagerLib/UefiBootManagerLib.inf | 1 - MdeModulePkg/MdeModulePkg.dec | 4 +- MdeModulePkg/MdeModulePkg.dsc | 6 +- .../BootScriptExecutorDxe.inf | 3 +- .../BootScriptExecutorDxe/ScriptExecute.c | 72 +- .../BootScriptExecutorDxe/ScriptExecute.h | 3 +- MdeModulePkg/Universal/CapsulePei/Capsule.h | 5 +- .../Universal/CapsulePei/CapsulePei.inf | 1 - .../Universal/CapsulePei/UefiCapsule.c | 4 +- MdeModulePkg/Universal/EbcDxe/EbcDebugger.inf | 1 - .../Universal/EbcDxe/EbcDebugger/EdbSymbol.c | 117 +-- MdeModulePkg/Universal/EbcDxe/EbcDxe.inf | 1 - MdeModulePkg/Universal/EbcDxe/EbcInt.c | 21 - MdeModulePkg/Universal/EbcDxe/EbcInt.h | 3 +- MdePkg/Include/Guid/DebugImageInfoTable.h | 1 + MdePkg/Include/Guid/WinCertificate.h | 13 +- MdePkg/Include/IndustryStandard/PeImage.h | 72 +- MdePkg/Include/IndustryStandard/PeImage2.h | 761 ++++++++++++++ MdePkg/Include/Library/PeCoffExtraActionLib.h | 4 + MdePkg/Include/Library/PeCoffLib.h | 75 +- MdePkg/Include/Library/PeCoffLib2.h | 597 +++++++++++ MdePkg/Include/Library/PeiServicesLib.h | 26 + .../Include/Library/UefiImageExtraActionLib.h | 47 + MdePkg/Include/Library/UefiImageLib.h | 642 ++++++++++++ MdePkg/Include/Pi/PiPeiCis.h | 35 + MdePkg/Include/Ppi/FirmwareVolume.h | 38 +- MdePkg/Include/Protocol/DebugSupport.h | 14 +- MdePkg/Library/BasePeCoffLib/BasePeCoff.c | 2 +- .../BasePeCoffLib/BasePeCoffLibInternals.h | 31 +- MdePkg/Library/BasePeCoffLib/PeCoffLoad.h | 50 + .../Library/BasePeCoffLib2/BasePeCoffLib2.inf | 47 + .../BasePeCoffLib2/BasePeCoffLib2Internals.h | 55 + .../Library/BasePeCoffLib2/Documentation.md | 40 + MdePkg/Library/BasePeCoffLib2/PeCoffDebug.c | 264 +++++ MdePkg/Library/BasePeCoffLib2/PeCoffHash.c | 487 +++++++++ MdePkg/Library/BasePeCoffLib2/PeCoffHii.c | 286 ++++++ MdePkg/Library/BasePeCoffLib2/PeCoffInfo.c | 152 +++ MdePkg/Library/BasePeCoffLib2/PeCoffInit.c | 896 +++++++++++++++++ MdePkg/Library/BasePeCoffLib2/PeCoffLoad.c | 259 +++++ .../Library/BasePeCoffLib2/PeCoffRelocate.c | 938 ++++++++++++++++++ .../BaseUefiImageExtraActionLibNull.inf | 33 + .../UefiImageExtraActionLib.c | 48 + .../UefiImageExtraActionLibNull.uni | 16 + .../BaseUefiImageLibPeCoff.inf | 40 + .../Library/BaseUefiImageLib/CommonSupport.c | 152 +++ .../BaseUefiImageLib/ExecutionSupport.c | 113 +++ .../Library/BaseUefiImageLib/PeCoffSupport.c | 511 ++++++++++ .../Library/BaseUefiImageLib/PeCoffSupport.h | 37 + .../BaseUefiImageLib/UefiImageLibPeCoff.c | 299 ++++++ .../Library/PeiServicesLib/PeiServicesLib.c | 32 + MdePkg/MdeLibs.dsc.inc | 1 + MdePkg/MdePkg.dec | 67 +- MdePkg/MdePkg.dsc | 6 +- NetworkPkg/NetworkPkg.dsc | 7 +- OvmfPkg/AmdSev/AmdSevX64.dsc | 16 +- OvmfPkg/Bhyve/BhyveX64.dsc | 16 +- .../CompatImageLoaderDxe.c | 1 - .../CompatImageLoaderDxe.inf | 1 - OvmfPkg/IntelTdx/IntelTdxX64.dsc | 35 +- OvmfPkg/IntelTdx/Sec/SecMain.c | 2 - OvmfPkg/IntelTdx/Sec/SecMain.inf | 3 - OvmfPkg/Library/PeilessStartupLib/DxeLoad.c | 12 +- .../PlatformBootManagerLib/BdsPlatform.h | 2 +- .../PlatformBootManagerLibBhyve/BdsPlatform.h | 2 +- OvmfPkg/OvmfPkgIa32.dsc | 35 +- OvmfPkg/OvmfPkgIa32X64.dsc | 53 +- OvmfPkg/OvmfPkgIa32X64.fdf | 2 +- OvmfPkg/OvmfPkgX64.dsc | 33 +- OvmfPkg/OvmfXen.dsc | 16 +- OvmfPkg/Sec/SecMain.c | 60 +- OvmfPkg/Sec/SecMain.inf | 5 +- OvmfPkg/Tcg/TdTcg2Dxe/MeasureBootPeCoff.c | 82 +- OvmfPkg/Tcg/TdTcg2Dxe/TdTcg2Dxe.inf | 2 +- README.md | 71 ++ .../DxeImageVerificationLib.c | 665 +++---------- .../DxeImageVerificationLib.h | 18 +- .../DxeImageVerificationLib.inf | 6 +- .../DxeTpm2MeasureBootLib.c | 93 +- .../DxeTpm2MeasureBootLib.inf | 2 +- .../DxeTpmMeasureBootLib.c | 353 +------ .../DxeTpmMeasureBootLib.inf | 2 +- .../HashInstanceLibSha1/HashInstanceLibSha1.c | 35 +- .../HashInstanceLibSha256.c | 33 +- .../HashInstanceLibSha512.c | 27 +- .../HashInstanceLibSm3/HashInstanceLibSm3.c | 35 +- .../HashLibBaseCryptoRouterDxe.c | 38 +- SecurityPkg/Library/HashLibTpm2/HashLibTpm2.c | 33 +- SecurityPkg/SecurityPkg.dsc | 8 +- SecurityPkg/Tcg/Tcg2Dxe/MeasureBootPeCoff.c | 408 -------- .../Tcg/Tcg2Dxe/MeasureBootUefiImage.c | 96 ++ SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c | 10 +- SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.inf | 4 +- SecurityPkg/Tcg/TcgDxe/TcgDxe.c | 2 +- .../SecureBootConfigDxe.inf | 2 +- .../SecureBootConfigImpl.c | 566 +++-------- .../SecureBootConfigImpl.h | 13 +- .../DynamicCommand/DpDynamicCommand/DpApp.inf | 1 - .../DpDynamicCommand/DpDynamicCommand.inf | 2 +- .../DpDynamicCommand/DpInternal.h | 4 +- .../DynamicCommand/DpDynamicCommand/DpTrace.c | 2 +- .../DpDynamicCommand/DpUtilities.c | 46 +- .../UefiHandleParsingLib.c | 4 +- .../UefiHandleParsingLib.h | 2 +- .../UefiHandleParsingLib.inf | 1 - .../UefiShellDebug1CommandsLib/LoadPciRom.c | 2 +- .../UefiShellDriver1CommandsLib.h | 2 +- .../UefiShellDriver1CommandsLib.inf | 1 - ShellPkg/ShellPkg.dsc | 1 - SignedCapsulePkg/SignedCapsulePkg.dsc | 6 +- .../DebugAgent/DebugAgentCommon/DebugAgent.c | 27 +- .../DebugAgent/DebugAgentCommon/DebugAgent.h | 14 +- .../DxeDebugAgent/DxeDebugAgentLib.c | 2 - .../Library/DebugAgent/DxeDebugAgentLib.inf | 3 +- .../SecPeiDebugAgent/SecPeiDebugAgentLib.c | 8 +- .../DebugAgent/SecPeiDebugAgentLib.inf | 3 +- .../SmmDebugAgent/SmmDebugAgentLib.c | 8 - .../Library/DebugAgent/SmmDebugAgentLib.inf | 3 +- .../Ia32/IntHandler.nasm | 4 + .../PeCoffExtraActionLib.c | 55 +- .../X64/IntHandler.nasm | 4 + .../Ia32/IntHandler.nasm | 22 + .../Ia32/IntHandlerFuncs.c | 93 ++ .../UefiImageExtraActionLib.c | 241 +++++ .../UefiImageExtraActionLib.h | 72 ++ .../UefiImageExtraActionLib.uni | 15 + .../UefiImageExtraActionLibDebug.inf | 50 + .../X64/IntHandler.nasm | 23 + .../X64/IntHandlerFuncs.c | 95 ++ SourceLevelDebugPkg/SourceLevelDebugPkg.dec | 2 +- SourceLevelDebugPkg/SourceLevelDebugPkg.dsc | 6 +- SourceLevelDebugPkg/SourceLevelDebugPkg.uni | 4 +- StandaloneMmPkg/Core/Dispatcher.c | 195 ++-- StandaloneMmPkg/Core/FwVol.c | 8 +- StandaloneMmPkg/Core/StandaloneMmCore.h | 5 +- StandaloneMmPkg/Core/StandaloneMmCore.inf | 12 +- .../Library/Arm/StandaloneMmCoreEntryPoint.h | 56 +- StandaloneMmPkg/Include/Library/FvLib.h | 2 +- .../Library/StandaloneMmProtectionLib.h | 30 + StandaloneMmPkg/Library/FvLib/FvLib.c | 2 +- .../Arm/SetPermissions.c | 323 +----- .../Arm/StandaloneMmCoreEntryPoint.c | 73 +- .../StandaloneMmCoreEntryPoint.inf | 8 +- .../ProtectionAarch64.c | 41 + .../ProtectionNull.c | 49 + .../StandaloneMmProtectionLib.inf | 29 + StandaloneMmPkg/StandaloneMmPkg.dec | 3 + StandaloneMmPkg/StandaloneMmPkg.dsc | 8 +- UefiCpuPkg/CpuDxe/CpuPageTable.c | 2 +- UefiCpuPkg/CpuDxe/CpuPageTable.h | 2 +- .../CpuExceptionCommon.c | 26 +- .../CpuExceptionCommon.h | 12 +- .../DxeCpuExceptionHandlerLib.inf | 4 +- .../CpuExceptionHandlerLib/DxeException.c | 52 + .../CpuExceptionHandlerLib/PeiCpuException.c | 24 + .../PeiCpuExceptionHandlerLib.inf | 2 +- .../SecPeiCpuException.c | 10 + .../SecPeiCpuExceptionHandlerLib.inf | 2 +- .../SmmCpuExceptionHandlerLib.inf | 4 +- .../CpuExceptionHandlerLib/SmmException.c | 76 ++ UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c | 71 +- UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h | 2 +- UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf | 2 +- UefiCpuPkg/SecCore/FindPeiCore.c | 64 +- UefiCpuPkg/SecCore/SecCore.inf | 4 +- UefiCpuPkg/SecCore/SecMain.h | 5 +- UefiCpuPkg/UefiCpuPkg.dec | 2 +- UefiCpuPkg/UefiCpuPkg.dsc | 5 +- .../MemoryAllocation.c | 0 .../UefiPayloadEntryMemoryAllocationLib.inf | 27 + UefiPayloadPkg/UefiPayloadEntry/LoadDxeCore.c | 97 +- .../UefiPayloadEntry/UefiPayloadEntry.h | 7 +- .../UefiPayloadEntry/UefiPayloadEntry.inf | 5 +- .../UefiPayloadEntry/UniversalPayloadEntry.c | 3 +- .../UniversalPayloadEntry.inf | 3 +- UefiPayloadPkg/UefiPayloadPkg.dsc | 9 +- 291 files changed, 12484 insertions(+), 7143 deletions(-) create mode 100644 ArmPkg/Library/DebugUefiImageExtraActionLib/DebugUefiImageExtraActionLib.c create mode 100644 ArmPkg/Library/DebugUefiImageExtraActionLib/DebugUefiImageExtraActionLib.inf mode change 100755 => 100644 ArmVirtPkg/PrePi/PrePi.c create mode 100644 EmulatorPkg/Library/DxeEmuUefiImageExtraActionLib/DxeEmuUefiImageExtraActionLib.c create mode 100644 EmulatorPkg/Library/DxeEmuUefiImageExtraActionLib/DxeEmuUefiImageExtraActionLib.inf create mode 100644 EmulatorPkg/Library/PeiEmuUefiImageExtraActionLib/PeiEmuUefiImageExtraActionLib.c create mode 100644 EmulatorPkg/Library/PeiEmuUefiImageExtraActionLib/PeiEmuUefiImageExtraActionLib.inf mode change 100755 => 100644 EmulatorPkg/Unix/lldbefi.py create mode 100644 LoaderFlow.png create mode 100644 MdeModulePkg/Core/PiSmmCore/DebugImageInfo.c rename MdeModulePkg/{Library/PiSmmCoreMemoryAllocationLib/MemoryAllocationLib.c => Core/PiSmmCore/MemoryAllocation.c} (96%) delete mode 100644 MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/PiSmmCoreMemoryAllocationServices.h create mode 100644 MdePkg/Include/IndustryStandard/PeImage2.h create mode 100644 MdePkg/Include/Library/PeCoffLib2.h create mode 100644 MdePkg/Include/Library/UefiImageExtraActionLib.h create mode 100644 MdePkg/Include/Library/UefiImageLib.h create mode 100644 MdePkg/Library/BasePeCoffLib/PeCoffLoad.h create mode 100644 MdePkg/Library/BasePeCoffLib2/BasePeCoffLib2.inf create mode 100644 MdePkg/Library/BasePeCoffLib2/BasePeCoffLib2Internals.h create mode 100644 MdePkg/Library/BasePeCoffLib2/Documentation.md create mode 100644 MdePkg/Library/BasePeCoffLib2/PeCoffDebug.c create mode 100644 MdePkg/Library/BasePeCoffLib2/PeCoffHash.c create mode 100644 MdePkg/Library/BasePeCoffLib2/PeCoffHii.c create mode 100644 MdePkg/Library/BasePeCoffLib2/PeCoffInfo.c create mode 100644 MdePkg/Library/BasePeCoffLib2/PeCoffInit.c create mode 100644 MdePkg/Library/BasePeCoffLib2/PeCoffLoad.c create mode 100644 MdePkg/Library/BasePeCoffLib2/PeCoffRelocate.c create mode 100644 MdePkg/Library/BaseUefiImageExtraActionLibNull/BaseUefiImageExtraActionLibNull.inf create mode 100644 MdePkg/Library/BaseUefiImageExtraActionLibNull/UefiImageExtraActionLib.c create mode 100644 MdePkg/Library/BaseUefiImageExtraActionLibNull/UefiImageExtraActionLibNull.uni create mode 100644 MdePkg/Library/BaseUefiImageLib/BaseUefiImageLibPeCoff.inf create mode 100644 MdePkg/Library/BaseUefiImageLib/CommonSupport.c create mode 100644 MdePkg/Library/BaseUefiImageLib/ExecutionSupport.c create mode 100644 MdePkg/Library/BaseUefiImageLib/PeCoffSupport.c create mode 100644 MdePkg/Library/BaseUefiImageLib/PeCoffSupport.h create mode 100644 MdePkg/Library/BaseUefiImageLib/UefiImageLibPeCoff.c create mode 100644 README.md delete mode 100644 SecurityPkg/Tcg/Tcg2Dxe/MeasureBootPeCoff.c create mode 100644 SecurityPkg/Tcg/Tcg2Dxe/MeasureBootUefiImage.c create mode 100644 SourceLevelDebugPkg/Library/UefiImageExtraActionLibDebug/Ia32/IntHandler.nasm create mode 100644 SourceLevelDebugPkg/Library/UefiImageExtraActionLibDebug/Ia32/IntHandlerFuncs.c create mode 100644 SourceLevelDebugPkg/Library/UefiImageExtraActionLibDebug/UefiImageExtraActionLib.c create mode 100644 SourceLevelDebugPkg/Library/UefiImageExtraActionLibDebug/UefiImageExtraActionLib.h create mode 100644 SourceLevelDebugPkg/Library/UefiImageExtraActionLibDebug/UefiImageExtraActionLib.uni create mode 100644 SourceLevelDebugPkg/Library/UefiImageExtraActionLibDebug/UefiImageExtraActionLibDebug.inf create mode 100644 SourceLevelDebugPkg/Library/UefiImageExtraActionLibDebug/X64/IntHandler.nasm create mode 100644 SourceLevelDebugPkg/Library/UefiImageExtraActionLibDebug/X64/IntHandlerFuncs.c create mode 100644 StandaloneMmPkg/Include/Library/StandaloneMmProtectionLib.h create mode 100644 StandaloneMmPkg/Library/StandaloneMmProtectionLib/ProtectionAarch64.c create mode 100644 StandaloneMmPkg/Library/StandaloneMmProtectionLib/ProtectionNull.c create mode 100644 StandaloneMmPkg/Library/StandaloneMmProtectionLib/StandaloneMmProtectionLib.inf rename UefiPayloadPkg/{UefiPayloadEntry => Library/UefiPayloadEntryMemoryAllocationLib}/MemoryAllocation.c (100%) create mode 100644 UefiPayloadPkg/Library/UefiPayloadEntryMemoryAllocationLib/UefiPayloadEntryMemoryAllocationLib.inf diff --git a/ArmPkg/ArmPkg.dsc b/ArmPkg/ArmPkg.dsc index 6dd91e6941..93683aa0f1 100644 --- a/ArmPkg/ArmPkg.dsc +++ b/ArmPkg/ArmPkg.dsc @@ -54,9 +54,9 @@ UefiLib|MdePkg/Library/UefiLib/UefiLib.inf DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf - PeCoffLib|MdePkg/Library/BasePeCoffLib/BasePeCoffLib.inf - PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf - PeCoffExtraActionLib|MdePkg/Library/BasePeCoffExtraActionLibNull/BasePeCoffExtraActionLibNull.inf + PeCoffLib2|MdePkg/Library/BasePeCoffLib2/BasePeCoffLib2.inf + UefiImageLib|MdePkg/Library/BaseUefiImageLib/BaseUefiImageLibPeCoff.inf + UefiImageExtraActionLib|MdePkg/Library/BaseUefiImageExtraActionLibNull/BaseUefiImageExtraActionLibNull.inf UefiHiiServicesLib|MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.inf HiiLib|MdeModulePkg/Library/UefiHiiLib/UefiHiiLib.inf @@ -111,7 +111,7 @@ ArmPkg/Library/ArmDisassemblerLib/ArmDisassemblerLib.inf ArmPkg/Library/CompilerIntrinsicsLib/CompilerIntrinsicsLib.inf ArmPkg/Library/DebugAgentSymbolsBaseLib/DebugAgentSymbolsBaseLib.inf - ArmPkg/Library/DebugPeCoffExtraActionLib/DebugPeCoffExtraActionLib.inf + ArmPkg/Library/DebugUefiImageExtraActionLib/DebugUefiImageExtraActionLib.inf ArmPkg/Library/DefaultExceptionHandlerLib/DefaultExceptionHandlerLib.inf ArmPkg/Library/SemiHostingDebugLib/SemiHostingDebugLib.inf ArmPkg/Library/SemiHostingSerialPortLib/SemiHostingSerialPortLib.inf diff --git a/ArmPkg/Drivers/ArmCrashDumpDxe/ArmCrashDumpDxe.dsc b/ArmPkg/Drivers/ArmCrashDumpDxe/ArmCrashDumpDxe.dsc index 2818ce65db..21f66748ef 100644 --- a/ArmPkg/Drivers/ArmCrashDumpDxe/ArmCrashDumpDxe.dsc +++ b/ArmPkg/Drivers/ArmCrashDumpDxe/ArmCrashDumpDxe.dsc @@ -35,7 +35,6 @@ DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf - PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf SerialPortLib|MdePkg/Library/BaseSerialPortLibNull/BaseSerialPortLibNull.inf UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf diff --git a/ArmPkg/Drivers/CpuDxe/CpuDxe.h b/ArmPkg/Drivers/CpuDxe/CpuDxe.h index c6613b939a..8e82ffb9e8 100644 --- a/ArmPkg/Drivers/CpuDxe/CpuDxe.h +++ b/ArmPkg/Drivers/CpuDxe/CpuDxe.h @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include diff --git a/ArmPkg/Drivers/CpuDxe/CpuDxe.inf b/ArmPkg/Drivers/CpuDxe/CpuDxe.inf index 7d8132200e..596644497b 100644 --- a/ArmPkg/Drivers/CpuDxe/CpuDxe.inf +++ b/ArmPkg/Drivers/CpuDxe/CpuDxe.inf @@ -49,7 +49,6 @@ DxeServicesTableLib HobLib MemoryAllocationLib - PeCoffGetEntryPointLib UefiDriverEntryPoint UefiLib diff --git a/ArmPkg/Library/ArmDisassemblerLib/ArmDisassemblerLib.inf b/ArmPkg/Library/ArmDisassemblerLib/ArmDisassemblerLib.inf index 2b8e8d2077..4217f343fb 100644 --- a/ArmPkg/Library/ArmDisassemblerLib/ArmDisassemblerLib.inf +++ b/ArmPkg/Library/ArmDisassemblerLib/ArmDisassemblerLib.inf @@ -32,4 +32,3 @@ BaseLib PrintLib DebugLib - PeCoffGetEntryPointLib diff --git a/ArmPkg/Library/DebugAgentSymbolsBaseLib/DebugAgentSymbolsBaseLib.c b/ArmPkg/Library/DebugAgentSymbolsBaseLib/DebugAgentSymbolsBaseLib.c index 77c92f9ecc..a985f525d3 100644 --- a/ArmPkg/Library/DebugAgentSymbolsBaseLib/DebugAgentSymbolsBaseLib.c +++ b/ArmPkg/Library/DebugAgentSymbolsBaseLib/DebugAgentSymbolsBaseLib.c @@ -13,8 +13,8 @@ #include #include #include -#include -#include +#include +#include #include #include @@ -165,34 +165,39 @@ GetFfsFile ( EFI_STATUS GetImageContext ( - IN EFI_FFS_FILE_HEADER *FfsHeader, - OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext + IN EFI_FFS_FILE_HEADER *FfsHeader, + OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext ) { - EFI_STATUS Status; - UINTN ParsedLength; - UINTN SectionSize; - UINTN SectionLength; - EFI_COMMON_SECTION_HEADER *Section; - VOID *EfiImage; - UINTN ImageAddress; - EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *DebugEntry; - VOID *CodeViewEntryPointer; - - Section = (EFI_COMMON_SECTION_HEADER *)(FfsHeader + 1); - SectionSize = *(UINT32 *)(FfsHeader->Size) & 0x00FFFFFF; - SectionSize -= sizeof (EFI_FFS_FILE_HEADER); - ParsedLength = 0; - EfiImage = NULL; + EFI_STATUS Status; + UINTN ParsedLength; + UINT32 SectionSize; + UINT32 SectionLength; + EFI_COMMON_SECTION_HEADER *Section; + VOID *EfiImage; + + Section = (EFI_COMMON_SECTION_HEADER *)(FfsHeader + 1); + SectionLength = 0; + SectionSize = *(UINT32 *)(FfsHeader->Size) & 0x00FFFFFF; + SectionSize -= sizeof (EFI_FFS_FILE_HEADER); + ParsedLength = 0; + EfiImage = NULL; while (ParsedLength < SectionSize) { + // + // Size is 24 bits wide so mask upper 8 bits. + // + SectionLength = *(UINT32 *)Section->Size & 0x00FFFFFF; + if (SectionLength < sizeof (*Section)) { + return EFI_VOLUME_CORRUPTED; + } + if ((Section->Type == EFI_SECTION_PE32) || (Section->Type == EFI_SECTION_TE)) { - EfiImage = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(Section + 1); + EfiImage = (Section + 1); break; } // - // Size is 24 bits wide so mask upper 8 bits. // SectionLength is adjusted it is 4 byte aligned. // Go to the next section // @@ -208,34 +213,10 @@ GetImageContext ( } // Initialize the Image Context - ZeroMem (ImageContext, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT)); - ImageContext->Handle = EfiImage; - ImageContext->ImageRead = PeCoffLoaderImageReadFromMemory; - - Status = PeCoffLoaderGetImageInfo (ImageContext); - if (!EFI_ERROR (Status) && ((VOID *)(UINTN)ImageContext->DebugDirectoryEntryRva != NULL)) { - ImageAddress = ImageContext->ImageAddress; - if (ImageContext->IsTeImage) { - ImageAddress += sizeof (EFI_TE_IMAGE_HEADER) - ((EFI_TE_IMAGE_HEADER *)EfiImage)->StrippedSize; - } - - DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *)(ImageAddress + ImageContext->DebugDirectoryEntryRva); - if (DebugEntry->Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) { - CodeViewEntryPointer = (VOID *)(ImageAddress + (UINTN)DebugEntry->RVA); - switch (*(UINT32 *)CodeViewEntryPointer) { - case CODEVIEW_SIGNATURE_NB10: - ImageContext->PdbPointer = (CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY); - break; - case CODEVIEW_SIGNATURE_RSDS: - ImageContext->PdbPointer = (CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY); - break; - case CODEVIEW_SIGNATURE_MTOC: - ImageContext->PdbPointer = (CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY); - break; - default: - break; - } - } + // FIXME: Common FFS API with size checks + Status = UefiImageInitializeContext (ImageContext, EfiImage, SectionLength - sizeof (*Section)); + if (!EFI_ERROR(Status)) { + Status = UefiImageLoadImageInplace( ImageContext); } return Status; @@ -271,9 +252,9 @@ InitializeDebugAgent ( IN DEBUG_AGENT_CONTINUE Function OPTIONAL ) { - EFI_STATUS Status; - EFI_FFS_FILE_HEADER *FfsHeader; - PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; + EFI_STATUS Status; + EFI_FFS_FILE_HEADER *FfsHeader; + UEFI_IMAGE_LOADER_IMAGE_CONTEXT ImageContext; // We use InitFlag to know if DebugAgent has been initialized from // Sec (DEBUG_AGENT_INIT_PREMEM_SEC) or PrePi (DEBUG_AGENT_INIT_POSTMEM_SEC) @@ -286,7 +267,7 @@ InitializeDebugAgent ( if (!EFI_ERROR (Status)) { Status = GetImageContext (FfsHeader, &ImageContext); if (!EFI_ERROR (Status)) { - PeCoffLoaderRelocateImageExtraAction (&ImageContext); + UefiImageLoaderRelocateImageExtraAction (&ImageContext); } } } else if (InitFlag == DEBUG_AGENT_INIT_POSTMEM_SEC) { @@ -297,7 +278,7 @@ InitializeDebugAgent ( if (!EFI_ERROR (Status)) { Status = GetImageContext (FfsHeader, &ImageContext); if (!EFI_ERROR (Status)) { - PeCoffLoaderRelocateImageExtraAction (&ImageContext); + UefiImageLoaderRelocateImageExtraAction (&ImageContext); } } @@ -308,7 +289,7 @@ InitializeDebugAgent ( if (!EFI_ERROR (Status)) { Status = GetImageContext (FfsHeader, &ImageContext); if (!EFI_ERROR (Status)) { - PeCoffLoaderRelocateImageExtraAction (&ImageContext); + UefiImageLoaderRelocateImageExtraAction (&ImageContext); } } } diff --git a/ArmPkg/Library/DebugAgentSymbolsBaseLib/DebugAgentSymbolsBaseLib.inf b/ArmPkg/Library/DebugAgentSymbolsBaseLib/DebugAgentSymbolsBaseLib.inf index 2ceeebbdee..03a637346e 100644 --- a/ArmPkg/Library/DebugAgentSymbolsBaseLib/DebugAgentSymbolsBaseLib.inf +++ b/ArmPkg/Library/DebugAgentSymbolsBaseLib/DebugAgentSymbolsBaseLib.inf @@ -24,8 +24,8 @@ [LibraryClasses] DebugLib PcdLib - PeCoffExtraActionLib - PeCoffLib + UefiImageExtraActionLib + UefiImageLib [Pcd] gArmTokenSpaceGuid.PcdSecureFvBaseAddress diff --git a/ArmPkg/Library/DebugUefiImageExtraActionLib/DebugUefiImageExtraActionLib.c b/ArmPkg/Library/DebugUefiImageExtraActionLib/DebugUefiImageExtraActionLib.c new file mode 100644 index 0000000000..db74ff779b --- /dev/null +++ b/ArmPkg/Library/DebugUefiImageExtraActionLib/DebugUefiImageExtraActionLib.c @@ -0,0 +1,141 @@ +/**@file + +Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.
+Portions copyright (c) 2008 - 2010, Apple Inc. All rights reserved.
+Portions copyright (c) 2011 - 2012, ARM Ltd. All rights reserved.
+ +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include + +#include +#include +#include +#include +#include + +/** + If the build is done on cygwin the paths are cygpaths. + /cygdrive/c/tmp.txt vs c:\tmp.txt so we need to convert + them to work with RVD commands + + @param Name Path to convert if needed + +**/ +CONST CHAR8 * +DeCygwinPathIfNeeded ( + IN CONST CHAR8 *Name, + IN CHAR8 *Temp, + IN UINTN Size + ) +{ + CHAR8 *Ptr; + UINTN Index; + UINTN Index2; + + Ptr = AsciiStrStr (Name, "/cygdrive/"); + if (Ptr == NULL) { + return Name; + } + + for (Index = 9, Index2 = 0; (Index < (Size + 9)) && (Ptr[Index] != '\0'); Index++, Index2++) { + Temp[Index2] = Ptr[Index]; + if (Temp[Index2] == '/') { + Temp[Index2] = '\\'; + } + + if (Index2 == 1) { + Temp[Index2 - 1] = Ptr[Index]; + Temp[Index2] = ':'; + } + } + + return Temp; +} + +/** + Performs additional actions after a PE/COFF image has been loaded and relocated. + + If ImageContext is NULL, then ASSERT(). + + @param ImageContext Pointer to the image context structure that describes the + PE/COFF image that has already been loaded and relocated. + +**/ +VOID +EFIAPI +UefiImageLoaderRelocateImageExtraAction ( + IN CONST UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext + ) +{ + RETURN_STATUS Status; + CONST CHAR8 *PdbPath; + UINT32 PdbPathSize; +#if defined (__CC_ARM) || defined (__GNUC__) + CHAR8 Temp[512]; +#endif + + Status = UefiImageGetSymbolsPath (ImageContext, &PdbPath, &PdbPathSize); + + if (!RETURN_ERROR (Status)) { + #ifdef __CC_ARM + #if (__ARMCC_VERSION < 500000) + // Print out the command for the RVD debugger to load symbols for this image + DEBUG ((DEBUG_LOAD | DEBUG_INFO, "load /a /ni /np %a &0x%p\n", DeCygwinPathIfNeeded (PdbPath, Temp, sizeof (Temp)), UefiImageLoaderGetImageAddress (ImageContext))); + #else + // Print out the command for the DS-5 to load symbols for this image + DEBUG ((DEBUG_LOAD | DEBUG_INFO, "add-symbol-file %a -o 0x%p\n", DeCygwinPathIfNeeded (PdbPath, Temp, sizeof (Temp)), UefiImageLoaderGetImageAddress (ImageContext))); + #endif + #elif __GNUC__ + // This may not work correctly if you generate PE/COFF directly as then the Offset would not be required + DEBUG ((DEBUG_LOAD | DEBUG_INFO, "add-symbol-file %a -o 0x%p\n", DeCygwinPathIfNeeded (PdbPath, Temp, sizeof (Temp)), UefiImageLoaderGetImageAddress (ImageContext))); + #else + DEBUG ((DEBUG_LOAD | DEBUG_INFO, "Loading driver at 0x%11p EntryPoint=0x%11p\n", (VOID *)(UINTN)UefiImageLoaderGetImageAddress (ImageContext), FUNCTION_ENTRY_POINT (UefiImageLoaderGetImageEntryPoint (ImageContext)))); + #endif + } else { + DEBUG ((DEBUG_LOAD | DEBUG_INFO, "Loading driver at 0x%11p EntryPoint=0x%11p\n", (VOID *)(UINTN)UefiImageLoaderGetImageAddress (ImageContext), FUNCTION_ENTRY_POINT (UefiImageLoaderGetImageEntryPoint (ImageContext)))); + } +} + +/** + Performs additional actions just before a PE/COFF image is unloaded. Any resources + that were allocated by UefiImageLoaderRelocateImageExtraAction() must be freed. + + If ImageContext is NULL, then ASSERT(). + + @param ImageContext Pointer to the image context structure that describes the + PE/COFF image that is being unloaded. + +**/ +VOID +EFIAPI +UefiImageLoaderUnloadImageExtraAction ( + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext + ) +{ + RETURN_STATUS Status; + CONST CHAR8 *PdbPath; + UINT32 PdbPathSize; +#if defined (__CC_ARM) || defined (__GNUC__) + CHAR8 Temp[512]; +#endif + + Status = UefiImageGetSymbolsPath (ImageContext, &PdbPath, &PdbPathSize); + + if (!RETURN_ERROR (Status)) { + #ifdef __CC_ARM + // Print out the command for the RVD debugger to load symbols for this image + DEBUG ((DEBUG_LOAD | DEBUG_INFO, "unload symbols_only %a\n", DeCygwinPathIfNeeded (PdbPath, Temp, sizeof (Temp)))); + #elif __GNUC__ + // This may not work correctly if you generate PE/COFF directly as then the Offset would not be required + DEBUG ((DEBUG_LOAD | DEBUG_INFO, "remove-symbol-file %a 0x%08x\n", DeCygwinPathIfNeeded (PdbPath, Temp, sizeof (Temp)), (UINTN)UefiImageLoaderGetImageAddress (ImageContext))); + #else + DEBUG ((DEBUG_LOAD | DEBUG_INFO, "Unloading %a\n", PdbPath)); + #endif + } else { + DEBUG ((DEBUG_LOAD | DEBUG_INFO, "Unloading driver at 0x%11p\n", (VOID *)(UINTN)UefiImageLoaderGetImageAddress (ImageContext))); + } +} diff --git a/ArmPkg/Library/DebugUefiImageExtraActionLib/DebugUefiImageExtraActionLib.inf b/ArmPkg/Library/DebugUefiImageExtraActionLib/DebugUefiImageExtraActionLib.inf new file mode 100644 index 0000000000..31728d04d1 --- /dev/null +++ b/ArmPkg/Library/DebugUefiImageExtraActionLib/DebugUefiImageExtraActionLib.inf @@ -0,0 +1,33 @@ +#/** @file +# UEFI Image extra action library for DXE phase that run Unix emulator. +# +# Lib to provide memory journal status code reporting Routines +# Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.
+# Portions copyright (c) 2010, Apple Inc. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = DebugUnixUefiImageExtraActionLib + FILE_GUID = C3E9448E-1726-42fb-9368-41F75B038C0C + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = UefiImageExtraActionLib + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = ARM +# + +[Sources.common] + DebugUefiImageExtraActionLib.c + +[Packages] + MdePkg/MdePkg.dec + +[LibraryClasses] + DebugLib diff --git a/ArmPkg/Library/DefaultExceptionHandlerLib/AArch64/DefaultExceptionHandler.c b/ArmPkg/Library/DefaultExceptionHandlerLib/AArch64/DefaultExceptionHandler.c index 1d3ea61311..d4320ff740 100644 --- a/ArmPkg/Library/DefaultExceptionHandlerLib/AArch64/DefaultExceptionHandler.c +++ b/ArmPkg/Library/DefaultExceptionHandlerLib/AArch64/DefaultExceptionHandler.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -37,11 +36,10 @@ STATIC CHAR8 *gExceptionTypeString[] = { STATIC BOOLEAN mRecursiveException; -CHAR8 * +CONST CHAR8 * GetImageName ( IN UINTN FaultAddress, - OUT UINTN *ImageBase, - OUT UINTN *PeCoffSizeOfHeaders + OUT UINTN *ImageBase ); STATIC @@ -212,14 +210,13 @@ DefaultExceptionHandler ( UnicodeSPrintAsciiFormat (UnicodeBuffer, MAX_PRINT_CHARS, Buffer); DEBUG_CODE_BEGIN (); - CHAR8 *Pdb, *PrevPdb; - UINTN ImageBase; - UINTN PeCoffSizeOfHeader; - UINT64 *Fp; - UINT64 RootFp[2]; - UINTN Idx; - - PrevPdb = Pdb = GetImageName (SystemContext.SystemContextAArch64->ELR, &ImageBase, &PeCoffSizeOfHeader); + CONST CHAR8 *Pdb, *PrevPdb; + UINTN ImageBase; + UINT64 *Fp; + UINT64 RootFp[2]; + UINTN Idx; + + PrevPdb = Pdb = GetImageName (SystemContext.SystemContextAArch64->ELR, &ImageBase); if (Pdb != NULL) { DEBUG (( DEBUG_ERROR, @@ -244,7 +241,7 @@ DefaultExceptionHandler ( } for (Fp = RootFp; Fp[0] != 0; Fp = (UINT64 *)Fp[0]) { - Pdb = GetImageName (Fp[1], &ImageBase, &PeCoffSizeOfHeader); + Pdb = GetImageName (Fp[1], &ImageBase); if (Pdb != NULL) { if (Pdb != PrevPdb) { Idx++; @@ -265,14 +262,14 @@ DefaultExceptionHandler ( } } - PrevPdb = Pdb = GetImageName (SystemContext.SystemContextAArch64->ELR, &ImageBase, &PeCoffSizeOfHeader); + PrevPdb = Pdb = GetImageName (SystemContext.SystemContextAArch64->ELR, &ImageBase); if (Pdb != NULL) { DEBUG ((DEBUG_ERROR, "\n[ 0] %a\n", Pdb)); } Idx = 0; for (Fp = RootFp; Fp[0] != 0; Fp = (UINT64 *)Fp[0]) { - Pdb = GetImageName (Fp[1], &ImageBase, &PeCoffSizeOfHeader); + Pdb = GetImageName (Fp[1], &ImageBase); if ((Pdb != NULL) && (Pdb != PrevPdb)) { DEBUG ((DEBUG_ERROR, "[% 2d] %a\n", ++Idx, Pdb)); PrevPdb = Pdb; diff --git a/ArmPkg/Library/DefaultExceptionHandlerLib/Arm/DefaultExceptionHandler.c b/ArmPkg/Library/DefaultExceptionHandlerLib/Arm/DefaultExceptionHandler.c index accad647d6..a55c38c076 100644 --- a/ArmPkg/Library/DefaultExceptionHandlerLib/Arm/DefaultExceptionHandler.c +++ b/ArmPkg/Library/DefaultExceptionHandlerLib/Arm/DefaultExceptionHandler.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include @@ -54,11 +53,10 @@ STATIC CONST CPSR_CHAR mCpsrChar[] = { { 0, '?' } }; -CHAR8 * +CONST CHAR8 * GetImageName ( IN UINTN FaultAddress, - OUT UINTN *ImageBase, - OUT UINTN *PeCoffSizeOfHeaders + OUT UINTN *ImageBase ); /** @@ -229,20 +227,19 @@ DefaultExceptionHandler ( UnicodeSPrintAsciiFormat (UnicodeBuffer, MAX_PRINT_CHARS, Buffer); DEBUG_CODE_BEGIN (); - CHAR8 *Pdb; - UINT32 ImageBase; - UINT32 PeCoffSizeOfHeader; - UINT32 Offset; - CHAR8 CpsrStr[CPSR_STRING_SIZE]; // char per bit. Lower 5-bits are mode - // that is a 3 char string - CHAR8 Buffer[80]; - UINT8 *DisAsm; - UINT32 ItBlock; + CONST CHAR8 *Pdb; + UINT32 ImageBase; + UINT32 Offset; + CHAR8 CpsrStr[CPSR_STRING_SIZE]; // char per bit. Lower 5-bits are mode + // that is a 3 char string + CHAR8 Buffer[80]; + UINT8 *DisAsm; + UINT32 ItBlock; CpsrString (SystemContext.SystemContextArm->CPSR, CpsrStr); DEBUG ((DEBUG_ERROR, "%a\n", CpsrStr)); - Pdb = GetImageName (SystemContext.SystemContextArm->PC, &ImageBase, &PeCoffSizeOfHeader); + Pdb = GetImageName (SystemContext.SystemContextArm->PC, &ImageBase); Offset = SystemContext.SystemContextArm->PC - ImageBase; if (Pdb != NULL) { DEBUG ((DEBUG_ERROR, "%a\n", Pdb)); @@ -255,7 +252,9 @@ DefaultExceptionHandler ( // you need to subtract out the size of the PE/COFF header to get // get the offset that matches the link map. // - DEBUG ((DEBUG_ERROR, "loaded at 0x%08x (PE/COFF offset) 0x%x (ELF or Mach-O offset) 0x%x", ImageBase, Offset, Offset - PeCoffSizeOfHeader)); + // FIXME: Used to have (ELF or Mach-O offset) 0x%x + // Substitute with .text address (better + may be needed for GDB symbols?) + DEBUG ((EFI_D_ERROR, "loaded at 0x%08x (PE/COFF offset) 0x%x", ImageBase, Offset)); // If we come from an image it is safe to show the instruction. We know it should not fault DisAsm = (UINT8 *)(UINTN)SystemContext.SystemContextArm->PC; diff --git a/ArmPkg/Library/DefaultExceptionHandlerLib/DefaultExceptionHandlerLib.inf b/ArmPkg/Library/DefaultExceptionHandlerLib/DefaultExceptionHandlerLib.inf index c7d31f6408..3475114302 100644 --- a/ArmPkg/Library/DefaultExceptionHandlerLib/DefaultExceptionHandlerLib.inf +++ b/ArmPkg/Library/DefaultExceptionHandlerLib/DefaultExceptionHandlerLib.inf @@ -34,7 +34,6 @@ BaseLib PrintLib DebugLib - PeCoffGetEntryPointLib ArmDisassemblerLib SerialPortLib UefiBootServicesTableLib diff --git a/ArmPkg/Library/DefaultExceptionHandlerLib/DefaultExceptionHandlerUefi.c b/ArmPkg/Library/DefaultExceptionHandlerLib/DefaultExceptionHandlerUefi.c index 752a763f04..290827a99b 100644 --- a/ArmPkg/Library/DefaultExceptionHandlerLib/DefaultExceptionHandlerUefi.c +++ b/ArmPkg/Library/DefaultExceptionHandlerLib/DefaultExceptionHandlerUefi.c @@ -7,7 +7,6 @@ **/ #include -#include #include #include @@ -20,17 +19,15 @@ @param FaultAddress Address to find PE/COFF image for. @param ImageBase Return load address of found image - @param PeCoffSizeOfHeaders Return the size of the PE/COFF header for the image that was found @retval NULL FaultAddress not in a loaded PE/COFF image. @retval Path and file name of PE/COFF image. **/ -CHAR8 * +CONST CHAR8 * GetImageName ( IN UINTN FaultAddress, - OUT UINTN *ImageBase, - OUT UINTN *PeCoffSizeOfHeaders + OUT UINTN *ImageBase ) { EFI_STATUS Status; @@ -59,8 +56,7 @@ GetImageName ( (Address <= ((CHAR8 *)DebugTable->NormalImage->LoadedImageProtocolInstance->ImageBase + DebugTable->NormalImage->LoadedImageProtocolInstance->ImageSize))) { *ImageBase = (UINTN)DebugTable->NormalImage->LoadedImageProtocolInstance->ImageBase; - *PeCoffSizeOfHeaders = PeCoffGetSizeOfHeaders ((VOID *)(UINTN)*ImageBase); - return PeCoffLoaderGetPdbPointer (DebugTable->NormalImage->LoadedImageProtocolInstance->ImageBase); + return DebugTable->NormalImage->PdbPath; } } } diff --git a/ArmPlatformPkg/ArmPlatformPkg.dsc b/ArmPlatformPkg/ArmPlatformPkg.dsc index ddd128f9e6..ab55b557a2 100644 --- a/ArmPlatformPkg/ArmPlatformPkg.dsc +++ b/ArmPlatformPkg/ArmPlatformPkg.dsc @@ -56,8 +56,9 @@ MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf MemoryInitPeiLib|ArmPlatformPkg/MemoryInitPei/MemoryInitPeiLib.inf PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf - PeCoffExtraActionLib|MdePkg/Library/BasePeCoffExtraActionLibNull/BasePeCoffExtraActionLibNull.inf - PeCoffLib|MdePkg/Library/BasePeCoffLib/BasePeCoffLib.inf + UefiImageExtraActionLib|MdePkg/Library/BaseUefiImageExtraActionLibNull/BaseUefiImageExtraActionLibNull.inf + PeCoffLib2|MdePkg/Library/BasePeCoffLib2/BasePeCoffLib2.inf + UefiImageLib|MdePkg/Library/BaseUefiImageLib/BaseUefiImageLibPeCoff.inf PerformanceLib|MdePkg/Library/BasePerformanceLibNull/BasePerformanceLibNull.inf PL011UartClockLib|ArmPlatformPkg/Library/PL011UartClockLib/PL011UartClockLib.inf PL011UartLib|ArmPlatformPkg/Library/PL011UartLib/PL011UartLib.inf diff --git a/ArmPlatformPkg/PrePi/PrePi.h b/ArmPlatformPkg/PrePi/PrePi.h index 1d47ba26be..fa8de425ab 100644 --- a/ArmPlatformPkg/PrePi/PrePi.h +++ b/ArmPlatformPkg/PrePi/PrePi.h @@ -20,6 +20,7 @@ #include #include #include +#include extern UINT64 mSystemMemoryEnd; diff --git a/ArmVirtPkg/ArmVirt.dsc.inc b/ArmVirtPkg/ArmVirt.dsc.inc index 7044790a1e..f07a6edada 100644 --- a/ArmVirtPkg/ArmVirt.dsc.inc +++ b/ArmVirtPkg/ArmVirt.dsc.inc @@ -47,8 +47,8 @@ SynchronizationLib|MdePkg/Library/BaseSynchronizationLib/BaseSynchronizationLib.inf PerformanceLib|MdePkg/Library/BasePerformanceLibNull/BasePerformanceLibNull.inf PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf - PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf - PeCoffLib|MdePkg/Library/BasePeCoffLib/BasePeCoffLib.inf + PeCoffLib2|MdePkg/Library/BasePeCoffLib2/BasePeCoffLib2.inf + UefiImageLib|MdePkg/Library/BaseUefiImageLib/BaseUefiImageLibPeCoff.inf IoLib|MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsicArmVirt.inf UefiDecompressLib|MdePkg/Library/BaseUefiDecompressLib/BaseUefiDecompressLib.inf CpuLib|MdePkg/Library/BaseCpuLib/BaseCpuLib.inf @@ -124,8 +124,8 @@ SerialPortLib|ArmVirtPkg/Library/FdtPL011SerialPortLib/FdtPL011SerialPortLib.inf FdtSerialPortAddressLib|OvmfPkg/Library/FdtSerialPortAddressLib/FdtSerialPortAddressLib.inf - PeCoffExtraActionLib|ArmPkg/Library/DebugPeCoffExtraActionLib/DebugPeCoffExtraActionLib.inf - #PeCoffExtraActionLib|MdePkg/Library/BasePeCoffExtraActionLibNull/BasePeCoffExtraActionLibNull.inf + UefiImageExtraActionLib|ArmPkg/Library/DebugUefiImageExtraActionLib/DebugUefiImageExtraActionLib.inf + #UefiImageExtraActionLib|MdePkg/Library/BaseUefiImageExtraActionLibNull/BaseUefiImageExtraActionLibNull.inf DebugAgentLib|MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.inf DebugAgentTimerLib|EmbeddedPkg/Library/DebugAgentTimerLibNull/DebugAgentTimerLibNull.inf @@ -205,7 +205,6 @@ PeiCoreEntryPoint|MdePkg/Library/PeiCoreEntryPoint/PeiCoreEntryPoint.inf PerformanceLib|MdeModulePkg/Library/PeiPerformanceLib/PeiPerformanceLib.inf OemHookStatusCodeLib|MdeModulePkg/Library/OemHookStatusCodeLibNull/OemHookStatusCodeLibNull.inf - PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf ExtractGuidedSectionLib|MdePkg/Library/PeiExtractGuidedSectionLib/PeiExtractGuidedSectionLib.inf PeiServicesTablePointerLib|ArmPkg/Library/PeiServicesTablePointerLib/PeiServicesTablePointerLib.inf @@ -223,7 +222,6 @@ PeimEntryPoint|MdePkg/Library/PeimEntryPoint/PeimEntryPoint.inf PerformanceLib|MdeModulePkg/Library/PeiPerformanceLib/PeiPerformanceLib.inf OemHookStatusCodeLib|MdeModulePkg/Library/OemHookStatusCodeLibNull/OemHookStatusCodeLibNull.inf - PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf ExtractGuidedSectionLib|MdePkg/Library/PeiExtractGuidedSectionLib/PeiExtractGuidedSectionLib.inf PeiServicesTablePointerLib|ArmPkg/Library/PeiServicesTablePointerLib/PeiServicesTablePointerLib.inf diff --git a/ArmVirtPkg/PrePi/AArch64/ModuleEntryPoint.S b/ArmVirtPkg/PrePi/AArch64/ModuleEntryPoint.S index 01623b6b35..aea976e4f7 100644 --- a/ArmVirtPkg/PrePi/AArch64/ModuleEntryPoint.S +++ b/ArmVirtPkg/PrePi/AArch64/ModuleEntryPoint.S @@ -142,9 +142,8 @@ ASM_PFX(DiscoverDramFromDt): // window at the beginning of the FD image as a temp stack. // mov x0, x7 - adr x1, PeCoffLoaderImageReadFromMemory mov sp, x7 - bl RelocatePeCoffImage + bl RelocateUefiImage // // Discover the memory size and offset from the DTB, and record in the diff --git a/ArmVirtPkg/PrePi/Arm/ModuleEntryPoint.S b/ArmVirtPkg/PrePi/Arm/ModuleEntryPoint.S index f0536c65eb..b22388eeda 100644 --- a/ArmVirtPkg/PrePi/Arm/ModuleEntryPoint.S +++ b/ArmVirtPkg/PrePi/Arm/ModuleEntryPoint.S @@ -146,9 +146,8 @@ ASM_PFX(ArmPlatformPeiBootAction): // window at the beginning of the FD image as a temp stack. // mov r0, r5 - ADRL (r1, PeCoffLoaderImageReadFromMemory) mov sp, r5 - bl RelocatePeCoffImage + bl RelocateUefiImage // // Discover the memory size and offset from the DTB, and record in the diff --git a/ArmVirtPkg/PrePi/ArmVirtPrePiUniCoreRelocatable.inf b/ArmVirtPkg/PrePi/ArmVirtPrePiUniCoreRelocatable.inf index 578ee37e74..e49bd8477e 100755 --- a/ArmVirtPkg/PrePi/ArmVirtPrePiUniCoreRelocatable.inf +++ b/ArmVirtPkg/PrePi/ArmVirtPrePiUniCoreRelocatable.inf @@ -47,7 +47,7 @@ SerialPortLib ExtractGuidedSectionLib LzmaDecompressLib - PeCoffLib + UefiImageLib PrePiLib MemoryAllocationLib HobLib diff --git a/ArmVirtPkg/PrePi/PrePi.c b/ArmVirtPkg/PrePi/PrePi.c old mode 100755 new mode 100644 index f27e0ad3d2..01535ef033 --- a/ArmVirtPkg/PrePi/PrePi.c +++ b/ArmVirtPkg/PrePi/PrePi.c @@ -9,7 +9,7 @@ #include #include -#include +#include #include #include #include @@ -131,15 +131,15 @@ CEntryPoint ( } VOID -RelocatePeCoffImage ( - IN EFI_PEI_FV_HANDLE FwVolHeader, - IN PE_COFF_LOADER_READ_FILE ImageRead +RelocateUefiImage ( + IN EFI_PEI_FV_HANDLE FwVolHeader ) { - EFI_PEI_FILE_HANDLE FileHandle; - VOID *SectionData; - PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; - EFI_STATUS Status; + EFI_PEI_FILE_HANDLE FileHandle; + VOID *SectionData; + UINT32 SectionSize; + UEFI_IMAGE_LOADER_IMAGE_CONTEXT ImageContext; + EFI_STATUS Status; FileHandle = NULL; Status = FfsFindNextFile ( @@ -149,21 +149,16 @@ RelocatePeCoffImage ( ); ASSERT_EFI_ERROR (Status); - Status = FfsFindSectionData (EFI_SECTION_PE32, FileHandle, &SectionData); + Status = FfsFindSectionData (EFI_SECTION_PE32, FileHandle, &SectionData, &SectionSize); if (EFI_ERROR (Status)) { - Status = FfsFindSectionData (EFI_SECTION_TE, FileHandle, &SectionData); + Status = FfsFindSectionData (EFI_SECTION_TE, FileHandle, &SectionData, &SectionSize); } ASSERT_EFI_ERROR (Status); - ZeroMem (&ImageContext, sizeof ImageContext); + Status = UefiImageInitializeContext (&ImageContext, SectionData, SectionSize); + ASSERT_RETURN_ERROR (Status); - ImageContext.Handle = (EFI_HANDLE)SectionData; - ImageContext.ImageRead = ImageRead; - PeCoffLoaderGetImageInfo (&ImageContext); - - if (ImageContext.ImageAddress != (UINTN)SectionData) { - ImageContext.ImageAddress = (UINTN)SectionData; - PeCoffLoaderRelocateImage (&ImageContext); - } + Status = UefiImageRelocateImageInplaceForExecution (&ImageContext); + ASSERT_RETURN_ERROR (Status); } diff --git a/BaseTools/Source/C/GenFv/GenFvInternalLib.c b/BaseTools/Source/C/GenFv/GenFvInternalLib.c index 29c3363a50..ce0345705d 100644 --- a/BaseTools/Source/C/GenFv/GenFvInternalLib.c +++ b/BaseTools/Source/C/GenFv/GenFvInternalLib.c @@ -45,6 +45,10 @@ SPDX-License-Identifier: BSD-2-Clause-Patent (((Imm32) >> 2) & 0x7fffff)) #define ARM_JUMP_TO_THUMB(Offset) _ARM_JUMP_TO_THUMB((Offset) - 8) +#define ALIGN_VALUE_ADDEND(Value, Alignment) (((Alignment) - (Value)) & ((Alignment) - 1U)) +#define ALIGN_VALUE(Value, Alignment) ((Value) + ALIGN_VALUE_ADDEND (Value, Alignment)) +#define IS_ALIGNED(Value, Alignment) (((Value) & ((Alignment) - 1U)) == 0U) + /* * Arm instruction to return from exception (MOVS PC, LR) */ @@ -1299,11 +1303,17 @@ Routine Description: // Rebase the PE or TE image in FileBuffer of FFS file for XIP // Rebase for the debug genfvmap tool // - Status = FfsRebase (FvInfo, FvInfo->FvFiles[Index], (EFI_FFS_FILE_HEADER *) FileBuffer, (UINTN) *VtfFileImage - (UINTN) FvImage->FileImage, FvMapFile); + Status = FfsRebase (FvInfo, FvInfo->FvFiles[Index], (EFI_FFS_FILE_HEADER **)&FileBuffer, &FileSize, (UINTN) *VtfFileImage - (UINTN) FvImage->FileImage, FvMapFile); if (EFI_ERROR (Status)) { Error (NULL, 0, 3000, "Invalid", "Could not rebase %s.", FvInfo->FvFiles[Index]); return Status; } + + if (FileSize > (UINTN) ((UINTN) *VtfFileImage - (UINTN) FvImage->CurrentFilePointer)) { + free (FileBuffer); + Error (NULL, 0, 4002, "Resource", "FV space is full, not enough room to add file %s after ImageBase aligning.", FvInfo->FvFiles[Index]); + return EFI_OUT_OF_RESOURCES; + } // // copy VTF File // @@ -1345,11 +1355,17 @@ Routine Description: // Rebase the PE or TE image in FileBuffer of FFS file for XIP. // Rebase Bs and Rt drivers for the debug genfvmap tool. // - Status = FfsRebase (FvInfo, FvInfo->FvFiles[Index], (EFI_FFS_FILE_HEADER *) FileBuffer, (UINTN) FvImage->CurrentFilePointer - (UINTN) FvImage->FileImage, FvMapFile); - if (EFI_ERROR (Status)) { - Error (NULL, 0, 3000, "Invalid", "Could not rebase %s.", FvInfo->FvFiles[Index]); - return Status; - } + Status = FfsRebase (FvInfo, FvInfo->FvFiles[Index], (EFI_FFS_FILE_HEADER **)&FileBuffer, &FileSize, (UINTN) FvImage->CurrentFilePointer - (UINTN) FvImage->FileImage, FvMapFile); + if (EFI_ERROR (Status)) { + Error (NULL, 0, 3000, "Invalid", "Could not rebase %s.", FvInfo->FvFiles[Index]); + return Status; + } + + if (FileSize > (UINTN) ((UINTN) *VtfFileImage - (UINTN) FvImage->CurrentFilePointer)) { + free (FileBuffer); + Error (NULL, 0, 4002, "Resource", "FV space is full, not enough room to add file %s after ImageBase aligning.", FvInfo->FvFiles[Index]); + return EFI_OUT_OF_RESOURCES; + } // // Copy the file // @@ -3447,11 +3463,109 @@ Routine Description: return EFI_SUCCESS; } +EFI_PHYSICAL_ADDRESS +AddPadSection ( + IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress, + IN UINT32 Alignment, + IN OUT EFI_FFS_FILE_HEADER **FfsFile, + IN OUT UINTN *FileSize, + IN OUT EFI_FILE_SECTION_POINTER *Section + ) +{ + EFI_COMMON_SECTION_HEADER *NewSection; + UINT32 FfsHeaderLength; + UINT32 FfsFileLength; + UINT32 PadSize; + UINTN PadAddress; + UINT8 *FfsPart; + UINT32 PartSize; + UINT32 Offset; + EFI_FFS_INTEGRITY_CHECK *IntegrityCheck; + + PadAddress = ALIGN_VALUE (*BaseAddress + sizeof (EFI_COMMON_SECTION_HEADER), Alignment); + PadSize = PadAddress - *BaseAddress; + + Offset = (UINT32)((UINTN)((*Section).Pe32Section) - (UINTN)(*FfsFile)); + PartSize = GetFfsFileLength (*FfsFile) - Offset; + FfsPart = calloc (1, PartSize); + if (FfsPart == NULL) { + fprintf (stderr, "GenFv: Could not allocate memory for FfsPart\n"); + return EFI_OUT_OF_RESOURCES; + } + + CopyMem (FfsPart, (UINT8 *)(UINTN)((*Section).Pe32Section), PartSize); + + FfsFileLength = GetFfsFileLength (*FfsFile) + PadSize; + *FfsFile = realloc (*FfsFile, FfsFileLength); + if (*FfsFile == NULL) { + fprintf (stderr, "GenFv: Could not reallocate memory for FfsFile\n"); + free (FfsPart); + return EFI_OUT_OF_RESOURCES; + } + *FileSize += PadSize; + + NewSection = (EFI_COMMON_SECTION_HEADER *)((UINTN)(*FfsFile) + Offset); + + NewSection->Size[0] = (UINT8)(PadSize & 0xff); + NewSection->Size[1] = (UINT8)((PadSize & 0xff00) >> 8); + NewSection->Size[2] = (UINT8)((PadSize & 0xff0000) >> 16); + NewSection->Type = EFI_SECTION_RAW; + ++NewSection; + ZeroMem ((VOID *)NewSection, PadSize - sizeof (EFI_COMMON_SECTION_HEADER)); + + *Section = (EFI_FILE_SECTION_POINTER)(EFI_PE32_SECTION *)((UINT8 *)NewSection + PadSize - sizeof (EFI_COMMON_SECTION_HEADER)); + + CopyMem ( + (UINT8 *)((*Section).Pe32Section), + FfsPart, + PartSize + ); + + FfsHeaderLength = GetFfsHeaderLength(*FfsFile); + if (FfsHeaderLength > sizeof(EFI_FFS_FILE_HEADER)) { + ((EFI_FFS_FILE_HEADER2 *)(*FfsFile))->ExtendedSize = FfsFileLength; + } else { + (*FfsFile)->Size[0] = (UINT8)(FfsFileLength & 0x000000FF); + (*FfsFile)->Size[1] = (UINT8)((FfsFileLength & 0x0000FF00) >> 8); + (*FfsFile)->Size[2] = (UINT8)((FfsFileLength & 0x00FF0000) >> 16); + } + + // + // Recalculate the FFS header checksum. Instead of setting Header and State + // both to zero, set Header to (UINT8)(-State) so State preserves its original + // value + // + IntegrityCheck = &(*FfsFile)->IntegrityCheck; + IntegrityCheck->Checksum.Header = (UINT8) (0x100 - (*FfsFile)->State); + IntegrityCheck->Checksum.File = 0; + + IntegrityCheck->Checksum.Header = CalculateChecksum8 ( + (UINT8 *)(*FfsFile), FfsHeaderLength); + + if ((*FfsFile)->Attributes & FFS_ATTRIB_CHECKSUM) { + // + // Ffs header checksum = zero, so only need to calculate ffs body. + // + IntegrityCheck->Checksum.File = CalculateChecksum8 ( + (UINT8 *)(*FfsFile) + FfsHeaderLength, + FfsFileLength - FfsHeaderLength); + } else { + IntegrityCheck->Checksum.File = FFS_FIXED_CHECKSUM; + } + + *BaseAddress = PadAddress; + + free (FfsPart); + + return EFI_SUCCESS; +} + EFI_STATUS FfsRebase ( IN OUT FV_INFO *FvInfo, IN CHAR8 *FileName, - IN OUT EFI_FFS_FILE_HEADER *FfsFile, + IN OUT EFI_FFS_FILE_HEADER **FfsFile, + IN OUT UINTN *FileSize, IN UINTN XipOffset, IN FILE *FvMapFile ) @@ -3524,13 +3638,12 @@ Routine Description: return EFI_SUCCESS; } - XipBase = FvInfo->BaseAddress + XipOffset; // // We only process files potentially containing PE32 sections. // - switch (FfsFile->Type) { + switch ((*FfsFile)->Type) { case EFI_FV_FILETYPE_SECURITY_CORE: case EFI_FV_FILETYPE_PEI_CORE: case EFI_FV_FILETYPE_PEIM: @@ -3542,7 +3655,7 @@ Routine Description: // // Rebase the inside FvImage. // - GetChildFvFromFfs (FvInfo, FfsFile, XipOffset); + GetChildFvFromFfs (FvInfo, *FfsFile, XipOffset); // // Search PE/TE section in FV sectin. @@ -3552,7 +3665,7 @@ Routine Description: return EFI_SUCCESS; } - FfsHeaderSize = GetFfsHeaderLength(FfsFile); + FfsHeaderSize = GetFfsHeaderLength(*FfsFile); // // Rebase each PE32 section // @@ -3566,7 +3679,7 @@ Routine Description: // // Find Pe Image // - Status = GetSectionByType (FfsFile, EFI_SECTION_PE32, Index, &CurrentPe32Section); + Status = GetSectionByType (*FfsFile, EFI_SECTION_PE32, Index, &CurrentPe32Section); if (EFI_ERROR (Status)) { break; } @@ -3615,7 +3728,7 @@ Routine Description: // // Calculate the PE32 base address, based on file type // - switch (FfsFile->Type) { + switch ((*FfsFile)->Type) { case EFI_FV_FILETYPE_SECURITY_CORE: case EFI_FV_FILETYPE_PEI_CORE: case EFI_FV_FILETYPE_PEIM: @@ -3693,7 +3806,7 @@ Routine Description: ImageContext.RelocationsStripped = FALSE; } - NewPe32BaseAddress = XipBase + (UINTN) CurrentPe32Section.Pe32Section + CurSecHdrSize - (UINTN)FfsFile; + NewPe32BaseAddress = XipBase + (UINTN) CurrentPe32Section.Pe32Section + CurSecHdrSize - (UINTN)(*FfsFile); break; case EFI_FV_FILETYPE_DRIVER: @@ -3708,7 +3821,7 @@ Routine Description: Error (NULL, 0, 3000, "Invalid", "PE image Section-Alignment and File-Alignment do not match : %s.", FileName); return EFI_ABORTED; } - NewPe32BaseAddress = XipBase + (UINTN) CurrentPe32Section.Pe32Section + CurSecHdrSize - (UINTN)FfsFile; + NewPe32BaseAddress = XipBase + (UINTN) CurrentPe32Section.Pe32Section + CurSecHdrSize - (UINTN)(*FfsFile); break; default: @@ -3732,15 +3845,28 @@ Routine Description: // // Load and Relocate Image Data // - MemoryImagePointer = (UINT8 *) malloc ((UINTN) ImageContext.ImageSize + ImageContext.SectionAlignment); + MemoryImagePointer = (UINT8 *) calloc (1, (UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment); if (MemoryImagePointer == NULL) { Error (NULL, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName); return EFI_OUT_OF_RESOURCES; } - memset ((VOID *) MemoryImagePointer, 0, (UINTN) ImageContext.ImageSize + ImageContext.SectionAlignment); - ImageContext.ImageAddress = ((UINTN) MemoryImagePointer + ImageContext.SectionAlignment - 1) & (~((UINTN) ImageContext.SectionAlignment - 1)); + ImageContext.ImageAddress = ALIGN_VALUE ((UINTN)MemoryImagePointer, ImageContext.SectionAlignment); - Status = PeCoffLoaderLoadImage (&ImageContext); + if (!(IS_ALIGNED (NewPe32BaseAddress, ImageContext.SectionAlignment))) { + Status = AddPadSection (&NewPe32BaseAddress, ImageContext.SectionAlignment, FfsFile, FileSize, &CurrentPe32Section); + if (EFI_ERROR (Status)) { + free ((VOID *) MemoryImagePointer); + return Status; + } + + CurSecHdrSize = GetSectionHeaderLength (CurrentPe32Section.CommonHeader); + ImageContext.Handle = (VOID *) ((UINTN) CurrentPe32Section.Pe32Section + CurSecHdrSize); + PdbPointer = PeCoffLoaderGetPdbPointer (ImageContext.Handle); + + ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((UINTN) CurrentPe32Section.Pe32Section + CurSecHdrSize + ImageContext.PeCoffHeaderOffset); + } + + Status = PeCoffLoaderLoadImage (&ImageContext); if (EFI_ERROR (Status)) { Error (NULL, 0, 3000, "Invalid", "LocateImage() call failed on rebase of %s", FileName); free ((VOID *) MemoryImagePointer); @@ -3748,7 +3874,8 @@ Routine Description: } ImageContext.DestinationAddress = NewPe32BaseAddress; - Status = PeCoffLoaderRelocateImage (&ImageContext); + + Status = PeCoffLoaderRelocateImage (&ImageContext); if (EFI_ERROR (Status)) { Error (NULL, 0, 3000, "Invalid", "RelocateImage() call failed on rebase of %s Status=%d", FileName, Status); free ((VOID *) MemoryImagePointer); @@ -3798,15 +3925,15 @@ Routine Description: // // Now update file checksum // - if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) { - SavedState = FfsFile->State; - FfsFile->IntegrityCheck.Checksum.File = 0; - FfsFile->State = 0; - FfsFile->IntegrityCheck.Checksum.File = CalculateChecksum8 ( - (UINT8 *) ((UINT8 *)FfsFile + FfsHeaderSize), - GetFfsFileLength (FfsFile) - FfsHeaderSize + if ((*FfsFile)->Attributes & FFS_ATTRIB_CHECKSUM) { + SavedState = (*FfsFile)->State; + (*FfsFile)->IntegrityCheck.Checksum.File = 0; + (*FfsFile)->State = 0; + (*FfsFile)->IntegrityCheck.Checksum.File = CalculateChecksum8 ( + (UINT8 *) ((UINT8 *)(*FfsFile) + FfsHeaderSize), + GetFfsFileLength (*FfsFile) - FfsHeaderSize ); - FfsFile->State = SavedState; + (*FfsFile)->State = SavedState; } // @@ -3820,14 +3947,14 @@ Routine Description: PdbPointer = FileName; } - WriteMapFile (FvMapFile, PdbPointer, FfsFile, NewPe32BaseAddress, &OrigImageContext); + WriteMapFile (FvMapFile, PdbPointer, *FfsFile, NewPe32BaseAddress, &OrigImageContext); } - if (FfsFile->Type != EFI_FV_FILETYPE_SECURITY_CORE && - FfsFile->Type != EFI_FV_FILETYPE_PEI_CORE && - FfsFile->Type != EFI_FV_FILETYPE_PEIM && - FfsFile->Type != EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER && - FfsFile->Type != EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE + if ((*FfsFile)->Type != EFI_FV_FILETYPE_SECURITY_CORE && + (*FfsFile)->Type != EFI_FV_FILETYPE_PEI_CORE && + (*FfsFile)->Type != EFI_FV_FILETYPE_PEIM && + (*FfsFile)->Type != EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER && + (*FfsFile)->Type != EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE ) { // // Only Peim code may have a TE section @@ -3844,7 +3971,7 @@ Routine Description: // // Find Te Image // - Status = GetSectionByType (FfsFile, EFI_SECTION_TE, Index, &CurrentPe32Section); + Status = GetSectionByType (*FfsFile, EFI_SECTION_TE, Index, &CurrentPe32Section); if (EFI_ERROR (Status)) { break; } @@ -3892,7 +4019,7 @@ Routine Description: // Set new rebased address. // NewPe32BaseAddress = XipBase + (UINTN) TEImageHeader + sizeof (EFI_TE_IMAGE_HEADER) \ - - TEImageHeader->StrippedSize - (UINTN) FfsFile; + - TEImageHeader->StrippedSize - (UINTN) (*FfsFile); // // if reloc is stripped, try to get the original efi image to get reloc info. @@ -4035,15 +4162,15 @@ Routine Description: // // Now update file checksum // - if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) { - SavedState = FfsFile->State; - FfsFile->IntegrityCheck.Checksum.File = 0; - FfsFile->State = 0; - FfsFile->IntegrityCheck.Checksum.File = CalculateChecksum8 ( - (UINT8 *)((UINT8 *)FfsFile + FfsHeaderSize), - GetFfsFileLength (FfsFile) - FfsHeaderSize + if ((*FfsFile)->Attributes & FFS_ATTRIB_CHECKSUM) { + SavedState = (*FfsFile)->State; + (*FfsFile)->IntegrityCheck.Checksum.File = 0; + (*FfsFile)->State = 0; + (*FfsFile)->IntegrityCheck.Checksum.File = CalculateChecksum8 ( + (UINT8 *)((UINT8 *)(*FfsFile) + FfsHeaderSize), + GetFfsFileLength (*FfsFile) - FfsHeaderSize ); - FfsFile->State = SavedState; + (*FfsFile)->State = SavedState; } // // Get this module function address from ModulePeMapFile and add them into FvMap file @@ -4059,7 +4186,7 @@ Routine Description: WriteMapFile ( FvMapFile, PdbPointer, - FfsFile, + *FfsFile, NewPe32BaseAddress, &OrigImageContext ); diff --git a/BaseTools/Source/C/GenFv/GenFvInternalLib.h b/BaseTools/Source/C/GenFv/GenFvInternalLib.h index 58dadc3fa9..bf476f2c08 100644 --- a/BaseTools/Source/C/GenFv/GenFvInternalLib.h +++ b/BaseTools/Source/C/GenFv/GenFvInternalLib.h @@ -331,7 +331,8 @@ EFI_STATUS FfsRebase ( IN OUT FV_INFO *FvInfo, IN CHAR8 *FileName, - IN OUT EFI_FFS_FILE_HEADER *FfsFile, + IN OUT EFI_FFS_FILE_HEADER **FfsFile, + IN OUT UINTN *FileSize, IN UINTN XipOffset, IN FILE *FvMapFile ); diff --git a/BaseTools/Source/Python/build/build.py b/BaseTools/Source/Python/build/build.py index 51fb1f433e..1390a62178 100755 --- a/BaseTools/Source/Python/build/build.py +++ b/BaseTools/Source/Python/build/build.py @@ -70,6 +70,24 @@ TemporaryTablePattern = re.compile(r'^_\d+_\d+_[a-fA-F0-9]+$') TmpTableDict = {} +## Return the biggest multiple of alignment that is smaller than or equal to +# value. +# +# @param value The value to align down. +# @param alignment The boundary to align down to. +# +def AlignDown(value, alignment): + return value - (value % alignment) + +## Return the smallest multiple of alignment that is bigger than or equal to +# value. +# +# @param value The value to align up. +# @param alignment The boundary to align up to. +# +def AlignUp(value, alignment): + return AlignDown(value + alignment - 1, alignment) + ## Check environment PATH variable to make sure the specified tool is found # # If the tool is found in the PATH, then True is returned @@ -688,7 +706,7 @@ def __init__(self, BaseName, Guid, Arch, OutputDir, DebugDir, ImageClass): self.OutputDir = OutputDir self.DebugDir = DebugDir self.Image = ImageClass - self.Image.Size = (self.Image.Size // 0x1000 + 1) * 0x1000 + self.Image.Size = AlignUp(self.Image.Size, 0x1000) ## The class implementing the EDK2 build process # @@ -1502,12 +1520,15 @@ def _RebaseModule (self, MapBuffer, BaseAddress, ModuleList, AddrIsOffset = True ## for SMM module in SMRAM, the SMRAM will be allocated from base to top. if not ModeIsSmm: BaseAddress = BaseAddress - ModuleInfo.Image.Size + BaseAddress = AlignDown(BaseAddress, ModuleInfo.Image.SectionAlignment) # # Update Image to new BaseAddress by GenFw tool # LaunchCommand(["GenFw", "--rebase", str(BaseAddress), "-r", ModuleOutputImage], ModuleInfo.OutputDir) LaunchCommand(["GenFw", "--rebase", str(BaseAddress), "-r", ModuleDebugImage], ModuleInfo.DebugDir) + ## for SMM module in SMRAM, the SMRAM will be allocated from base to top. else: + BaseAddress = AlignUp(BaseAddress, ModuleInfo.Image.SectionAlignment) # # Set new address to the section header only for SMM driver. # diff --git a/EmbeddedPkg/EmbeddedPkg.dec b/EmbeddedPkg/EmbeddedPkg.dec index 5dfbbc2933..e3d5be2397 100644 --- a/EmbeddedPkg/EmbeddedPkg.dec +++ b/EmbeddedPkg/EmbeddedPkg.dec @@ -79,7 +79,6 @@ gEmbeddedDeviceGuid = { 0xbf4b9d10, 0x13ec, 0x43dd, { 0x88, 0x80, 0xe9, 0xb, 0x71, 0x8f, 0x27, 0xde } } gEmbeddedExternalDeviceProtocolGuid = { 0x735F8C64, 0xD696, 0x44D0, { 0xBD, 0xF2, 0x44, 0x7F, 0xD0, 0x5A, 0x54, 0x06 }} gEmbeddedGpioProtocolGuid = { 0x17a0a3d7, 0xc0a5, 0x4635, { 0xbb, 0xd5, 0x07, 0x21, 0x87, 0xdf, 0xe2, 0xee }} - gPeCoffLoaderProtocolGuid = { 0xB323179B, 0x97FB, 0x477E, { 0xB0, 0xFE, 0xD8, 0x85, 0x91, 0xFA, 0x11, 0xAB } } gEmbeddedMmcHostProtocolGuid = { 0x3e591c00, 0x9e4a, 0x11df, {0x92, 0x44, 0x00, 0x02, 0xA5, 0xD5, 0xC5, 0x1B }} gAndroidFastbootTransportProtocolGuid = { 0x74bd9fe0, 0x8902, 0x11e3, {0xb9, 0xd3, 0xf7, 0x22, 0x38, 0xfc, 0x9a, 0x31}} gAndroidFastbootPlatformProtocolGuid = { 0x524685a0, 0x89a0, 0x11e3, {0x9d, 0x4d, 0xbf, 0xa9, 0xf6, 0xa4, 0x03, 0x08}} diff --git a/EmbeddedPkg/EmbeddedPkg.dsc b/EmbeddedPkg/EmbeddedPkg.dsc index e9062cacbb..2adc21c255 100644 --- a/EmbeddedPkg/EmbeddedPkg.dsc +++ b/EmbeddedPkg/EmbeddedPkg.dsc @@ -58,9 +58,9 @@ ReportStatusCodeLib|MdeModulePkg/Library/PeiDxeDebugLibReportStatusCode/PeiDxeDebugLibReportStatusCode.inf - PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf - PeCoffLib|MdePkg/Library/BasePeCoffLib/BasePeCoffLib.inf - PeCoffExtraActionLib|MdePkg/Library/BasePeCoffExtraActionLibNull/BasePeCoffExtraActionLibNull.inf + PeCoffLib2|MdePkg/Library/BasePeCoffLib2/BasePeCoffLib2.inf + UefiImageLib|MdePkg/Library/BaseUefiImageLib/BaseUefiImageLibPeCoff.inf + UefiImageExtraActionLib|MdePkg/Library/BaseUefiImageExtraActionLibNull/BaseUefiImageExtraActionLibNull.inf CacheMaintenanceLib|MdePkg/Library/BaseCacheMaintenanceLib/BaseCacheMaintenanceLib.inf PrePiLib|EmbeddedPkg/Library/PrePiLib/PrePiLib.inf diff --git a/EmbeddedPkg/GdbStub/GdbStub.c b/EmbeddedPkg/GdbStub/GdbStub.c index e6e07b87b6..3d317cb05a 100644 --- a/EmbeddedPkg/GdbStub/GdbStub.c +++ b/EmbeddedPkg/GdbStub/GdbStub.c @@ -807,166 +807,6 @@ gXferObjectReadResponse ( return Count; } -/** - Note: This should be a library function. In the Apple case you have to add - the size of the PE/COFF header into the starting address to make things work - right as there is no way to pad the Mach-O for the size of the PE/COFF header. - - - Returns a pointer to the PDB file name for a PE/COFF image that has been - loaded into system memory with the PE/COFF Loader Library functions. - - Returns the PDB file name for the PE/COFF image specified by Pe32Data. If - the PE/COFF image specified by Pe32Data is not a valid, then NULL is - returned. If the PE/COFF image specified by Pe32Data does not contain a - debug directory entry, then NULL is returned. If the debug directory entry - in the PE/COFF image specified by Pe32Data does not contain a PDB file name, - then NULL is returned. - If Pe32Data is NULL, then ASSERT(). - - @param Pe32Data Pointer to the PE/COFF image that is loaded in system - memory. - @param DebugBase Address that the debugger would use as the base of the image - - @return The PDB file name for the PE/COFF image specified by Pe32Data or NULL - if it cannot be retrieved. DebugBase is only valid if PDB file name is - valid. - -**/ -VOID * -EFIAPI -PeCoffLoaderGetDebuggerInfo ( - IN VOID *Pe32Data, - OUT VOID **DebugBase - ) -{ - EFI_IMAGE_DOS_HEADER *DosHdr; - EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr; - EFI_IMAGE_DATA_DIRECTORY *DirectoryEntry; - EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *DebugEntry; - UINTN DirCount; - VOID *CodeViewEntryPointer; - INTN TEImageAdjust; - UINT32 NumberOfRvaAndSizes; - UINT16 Magic; - UINTN SizeOfHeaders; - - ASSERT (Pe32Data != NULL); - - TEImageAdjust = 0; - DirectoryEntry = NULL; - DebugEntry = NULL; - NumberOfRvaAndSizes = 0; - SizeOfHeaders = 0; - - DosHdr = (EFI_IMAGE_DOS_HEADER *)Pe32Data; - if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) { - // - // DOS image header is present, so read the PE header after the DOS image header. - // - Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN)Pe32Data + (UINTN)((DosHdr->e_lfanew) & 0x0ffff)); - } else { - // - // DOS image header is not present, so PE header is at the image base. - // - Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)Pe32Data; - } - - if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) { - if (Hdr.Te->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress != 0) { - DirectoryEntry = &Hdr.Te->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG]; - TEImageAdjust = sizeof (EFI_TE_IMAGE_HEADER) - Hdr.Te->StrippedSize; - DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *)((UINTN)Hdr.Te + - Hdr.Te->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress + - TEImageAdjust); - } - - SizeOfHeaders = sizeof (EFI_TE_IMAGE_HEADER) + (UINTN)Hdr.Te->BaseOfCode - (UINTN)Hdr.Te->StrippedSize; - - // __APPLE__ check this math... - *DebugBase = ((CHAR8 *)Pe32Data) - TEImageAdjust; - } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) { - *DebugBase = Pe32Data; - - // - // NOTE: We use Machine field to identify PE32/PE32+, instead of Magic. - // It is due to backward-compatibility, for some system might - // generate PE32+ image with PE32 Magic. - // - switch (Hdr.Pe32->FileHeader.Machine) { - case EFI_IMAGE_MACHINE_IA32: - // - // Assume PE32 image with IA32 Machine field. - // - Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC; - break; - case EFI_IMAGE_MACHINE_X64: - case EFI_IMAGE_MACHINE_IA64: - // - // Assume PE32+ image with X64 or IPF Machine field - // - Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC; - break; - default: - // - // For unknown Machine field, use Magic in optional Header - // - Magic = Hdr.Pe32->OptionalHeader.Magic; - } - - if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { - // - // Use PE32 offset get Debug Directory Entry - // - SizeOfHeaders = Hdr.Pe32->OptionalHeader.SizeOfHeaders; - NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes; - DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]); - DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *)((UINTN)Pe32Data + DirectoryEntry->VirtualAddress); - } else if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) { - // - // Use PE32+ offset get Debug Directory Entry - // - SizeOfHeaders = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders; - NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes; - DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]); - DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *)((UINTN)Pe32Data + DirectoryEntry->VirtualAddress); - } - - if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) { - DirectoryEntry = NULL; - DebugEntry = NULL; - } - } else { - return NULL; - } - - if ((DebugEntry == NULL) || (DirectoryEntry == NULL)) { - return NULL; - } - - for (DirCount = 0; DirCount < DirectoryEntry->Size; DirCount += sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY), DebugEntry++) { - if (DebugEntry->Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) { - if (DebugEntry->SizeOfData > 0) { - CodeViewEntryPointer = (VOID *)((UINTN)DebugEntry->RVA + ((UINTN)Pe32Data) + (UINTN)TEImageAdjust); - switch (*(UINT32 *)CodeViewEntryPointer) { - case CODEVIEW_SIGNATURE_NB10: - return (VOID *)((CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY)); - case CODEVIEW_SIGNATURE_RSDS: - return (VOID *)((CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY)); - case CODEVIEW_SIGNATURE_MTOC: - *DebugBase = (VOID *)(UINTN)((UINTN)DebugBase - SizeOfHeaders); - return (VOID *)((CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY)); - default: - break; - } - } - } - } - - (void)SizeOfHeaders; - return NULL; -} - /** Process "qXfer:object:read:annex:offset,length" request. @@ -1007,7 +847,7 @@ QxferLibrary ( ) { VOID *LoadAddress; - CHAR8 *Pdb; + CONST CHAR8 *Pdb; UINTN Size; if (Offset != gPacketqXferLibraryOffset) { @@ -1035,12 +875,8 @@ QxferLibrary ( for ( ; gEfiDebugImageTableEntry < gDebugImageTableHeader->TableSize; gEfiDebugImageTableEntry++, gDebugTable++) { if (gDebugTable->NormalImage != NULL) { if ((gDebugTable->NormalImage->ImageInfoType == EFI_DEBUG_IMAGE_INFO_TYPE_NORMAL) && - (gDebugTable->NormalImage->LoadedImageProtocolInstance != NULL)) - { - Pdb = PeCoffLoaderGetDebuggerInfo ( - gDebugTable->NormalImage->LoadedImageProtocolInstance->ImageBase, - &LoadAddress - ); + (gDebugTable->NormalImage->LoadedImageProtocolInstance != NULL)) { + Pdb = gDebugTable->NormalImage->PdbPath; if (Pdb != NULL) { Size = AsciiSPrint ( gXferLibraryBuffer, diff --git a/EmbeddedPkg/GdbStub/GdbStubInternal.h b/EmbeddedPkg/GdbStub/GdbStubInternal.h index 9c3929c812..cc954c0666 100644 --- a/EmbeddedPkg/GdbStub/GdbStubInternal.h +++ b/EmbeddedPkg/GdbStub/GdbStubInternal.h @@ -26,7 +26,7 @@ #include #include #include -#include +#include extern CONST CHAR8 mHexToStr[]; diff --git a/EmbeddedPkg/Include/Library/PrePiLib.h b/EmbeddedPkg/Include/Library/PrePiLib.h index 93a9115eac..a76d4c5686 100644 --- a/EmbeddedPkg/Include/Library/PrePiLib.h +++ b/EmbeddedPkg/Include/Library/PrePiLib.h @@ -71,6 +71,7 @@ EFI_STATUS @param FileHeader A pointer to the file header that contains the set of sections to be searched. @param SectionData A pointer to the discovered section, if successful. + @param SectionSize A pointer to the size of the discovered section, if successful. @retval EFI_SUCCESS The section was found. @retval EFI_NOT_FOUND The section was not found. @@ -82,7 +83,8 @@ FfsFindSectionDataWithHook ( IN EFI_SECTION_TYPE SectionType, IN FFS_CHECK_SECTION_HOOK SectionCheckHook, IN EFI_PEI_FILE_HANDLE FileHandle, - OUT VOID **SectionData + OUT VOID **SectionData, + OUT UINT32 *SectionSize ); /** @@ -92,6 +94,7 @@ FfsFindSectionDataWithHook ( @param FileHandle A pointer to the file header that contains the set of sections to be searched. @param SectionData A pointer to the discovered section, if successful. + @param SectionSize A pointer to the size of the discovered section, if successful. @retval EFI_SUCCESS The section was found. @retval EFI_NOT_FOUND The section was not found. @@ -102,7 +105,8 @@ EFIAPI FfsFindSectionData ( IN EFI_SECTION_TYPE SectionType, IN EFI_PEI_FILE_HANDLE FileHandle, - OUT VOID **SectionData + OUT VOID **SectionData, + OUT UINT32 *SectionSize ); /** @@ -675,7 +679,7 @@ BuildExtractSectionHob ( VOID EFIAPI -BuildPeCoffLoaderHob ( +BuildUefiLoaderHob ( VOID ); @@ -760,10 +764,11 @@ AllocateAlignedPages ( EFI_STATUS EFIAPI -LoadPeCoffImage ( - IN VOID *PeCoffImage, +LoadUefiImage ( + IN VOID *UefiImage, + IN UINT32 UefiImageSize, OUT EFI_PHYSICAL_ADDRESS *ImageAddress, - OUT UINT64 *ImageSize, + OUT UINT32 *ImageSize, OUT EFI_PHYSICAL_ADDRESS *EntryPoint ); diff --git a/EmbeddedPkg/Library/PrePiHobLib/Hob.c b/EmbeddedPkg/Library/PrePiHobLib/Hob.c index cbc35152cc..724c19afee 100644 --- a/EmbeddedPkg/Library/PrePiHobLib/Hob.c +++ b/EmbeddedPkg/Library/PrePiHobLib/Hob.c @@ -12,12 +12,11 @@ #include #include #include -#include +#include #include #include #include -#include #include #include #include @@ -825,27 +824,6 @@ BuildExtractSectionHob ( BuildGuidDataHob (Guid, &Data, sizeof (Data)); } -PE_COFF_LOADER_PROTOCOL gPeCoffProtocol = { - PeCoffLoaderGetImageInfo, - PeCoffLoaderLoadImage, - PeCoffLoaderRelocateImage, - PeCoffLoaderImageReadFromMemory, - PeCoffLoaderRelocateImageForRuntime, - PeCoffLoaderUnloadImage -}; - -VOID -EFIAPI -BuildPeCoffLoaderHob ( - VOID - ) -{ - VOID *Ptr; - - Ptr = &gPeCoffProtocol; - BuildGuidDataHob (&gPeCoffLoaderProtocolGuid, &Ptr, sizeof (VOID *)); -} - // May want to put this into a library so you only need the PCD settings if you are using the feature? VOID BuildMemoryTypeInformationHob ( diff --git a/EmbeddedPkg/Library/PrePiLib/FwVol.c b/EmbeddedPkg/Library/PrePiLib/FwVol.c index 7739a5c8aa..9f9a7190a4 100644 --- a/EmbeddedPkg/Library/PrePiLib/FwVol.c +++ b/EmbeddedPkg/Library/PrePiLib/FwVol.c @@ -278,7 +278,8 @@ FfsProcessSection ( IN FFS_CHECK_SECTION_HOOK SectionCheckHook, IN EFI_COMMON_SECTION_HEADER *Section, IN UINTN SectionSize, - OUT VOID **OutputBuffer + OUT VOID **OutputBuffer, + OUT UINT32 *OutputSize ) { EFI_STATUS Status; @@ -298,6 +299,7 @@ FfsProcessSection ( Found = FALSE; *OutputBuffer = NULL; + *OutputSize = 0; ParsedLength = 0; Status = EFI_NOT_FOUND; while (ParsedLength < SectionSize) { @@ -313,10 +315,13 @@ FfsProcessSection ( } if (Found) { + // FIXME: Use common API with size checks if (IS_SECTION2 (Section)) { *OutputBuffer = (VOID *)((UINT8 *)Section + sizeof (EFI_COMMON_SECTION_HEADER2)); + *OutputSize = SECTION2_SIZE (Section) - sizeof (EFI_COMMON_SECTION_HEADER2); } else { *OutputBuffer = (VOID *)((UINT8 *)Section + sizeof (EFI_COMMON_SECTION_HEADER)); + *OutputSize = SECTION_SIZE (Section) - sizeof (EFI_COMMON_SECTION_HEADER); } return EFI_SUCCESS; @@ -432,7 +437,8 @@ FfsProcessSection ( SectionCheckHook, DstBuffer, DstBufferSize, - OutputBuffer + OutputBuffer, + OutputSize ); } } @@ -466,6 +472,7 @@ FfsProcessSection ( @param FileHandle A pointer to the file header that contains the set of sections to be searched. @param SectionData A pointer to the discovered section, if successful. + @param SectionSize A pointer to the size of the discovered section, if successful. @retval EFI_SUCCESS The section was found. @retval EFI_NOT_FOUND The section was not found. @@ -477,7 +484,8 @@ FfsFindSectionDataWithHook ( IN EFI_SECTION_TYPE SectionType, IN FFS_CHECK_SECTION_HOOK SectionCheckHook, IN EFI_PEI_FILE_HANDLE FileHandle, - OUT VOID **SectionData + OUT VOID **SectionData, + OUT UINT32 *SectionSize ) { EFI_FFS_FILE_HEADER *FfsFileHeader; @@ -500,7 +508,8 @@ FfsFindSectionDataWithHook ( SectionCheckHook, Section, FileSize, - SectionData + SectionData, + SectionSize ); } @@ -511,6 +520,7 @@ FfsFindSectionDataWithHook ( @param FileHandle A pointer to the file header that contains the set of sections to be searched. @param SectionData A pointer to the discovered section, if successful. + @param SectionSize A pointer to the size of the discovered section, if successful. @retval EFI_SUCCESS The section was found. @retval EFI_NOT_FOUND The section was not found. @@ -521,10 +531,11 @@ EFIAPI FfsFindSectionData ( IN EFI_SECTION_TYPE SectionType, IN EFI_PEI_FILE_HANDLE FileHandle, - OUT VOID **SectionData + OUT VOID **SectionData, + OUT UINT32 *SectionSize ) { - return FfsFindSectionDataWithHook (SectionType, NULL, FileHandle, SectionData); + return FfsFindSectionDataWithHook (SectionType, NULL, FileHandle, SectionData, SectionSize); } /** @@ -816,6 +827,7 @@ FfsProcessFvFile ( { EFI_STATUS Status; EFI_PEI_FV_HANDLE FvImageHandle; + UINT32 FvImageHandleSize; EFI_FV_INFO FvImageInfo; UINT32 FvAlignment; VOID *FvBuffer; @@ -842,7 +854,13 @@ FfsProcessFvFile ( // // Find FvImage in FvFile // - Status = FfsFindSectionDataWithHook (EFI_SECTION_FIRMWARE_VOLUME_IMAGE, NULL, FvFileHandle, (VOID **)&FvImageHandle); + Status = FfsFindSectionDataWithHook ( + EFI_SECTION_FIRMWARE_VOLUME_IMAGE, + NULL, + FvFileHandle, + (VOID **)&FvImageHandle, + &FvImageHandleSize + ); if (EFI_ERROR (Status)) { return Status; } diff --git a/EmbeddedPkg/Library/PrePiLib/PrePi.h b/EmbeddedPkg/Library/PrePiLib/PrePi.h index a00c946512..c327081dc1 100644 --- a/EmbeddedPkg/Library/PrePiLib/PrePi.h +++ b/EmbeddedPkg/Library/PrePiLib/PrePi.h @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/EmbeddedPkg/Library/PrePiLib/PrePiLib.c b/EmbeddedPkg/Library/PrePiLib/PrePiLib.c index 3cf866dab2..650d864264 100644 --- a/EmbeddedPkg/Library/PrePiLib/PrePiLib.c +++ b/EmbeddedPkg/Library/PrePiLib/PrePiLib.c @@ -6,6 +6,7 @@ **/ +#include "ProcessorBind.h" #include // @@ -56,54 +57,45 @@ AllocateCodePages ( EFI_STATUS EFIAPI -LoadPeCoffImage ( - IN VOID *PeCoffImage, +LoadUefiImage ( + IN VOID *UefiImage, + IN UINT32 UefiImageSize, OUT EFI_PHYSICAL_ADDRESS *ImageAddress, - OUT UINT64 *ImageSize, + OUT UINT32 *DestinationSize, OUT EFI_PHYSICAL_ADDRESS *EntryPoint ) { - RETURN_STATUS Status; - PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; - VOID *Buffer; - - ZeroMem (&ImageContext, sizeof (ImageContext)); - - ImageContext.Handle = PeCoffImage; - ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory; - - Status = PeCoffLoaderGetImageInfo (&ImageContext); + RETURN_STATUS Status; + UEFI_IMAGE_LOADER_IMAGE_CONTEXT ImageContext; + UINT32 ImageSize; + VOID *Buffer; + UINT32 BufferSize; + UINT32 BufferPages; + UINT32 BufferAlignment; + + Status = UefiImageInitializeContext (&ImageContext, UefiImage, UefiImageSize); ASSERT_EFI_ERROR (Status); + ImageSize = UefiImageGetImageSize (&ImageContext); + BufferPages = EFI_SIZE_TO_PAGES (ImageSize); + BufferSize = EFI_PAGES_TO_SIZE (BufferPages); + BufferAlignment = UefiImageGetSegmentAlignment (&ImageContext); + // // Allocate Memory for the image // - Buffer = AllocateCodePages (EFI_SIZE_TO_PAGES ((UINT32)ImageContext.ImageSize)); + Buffer = AllocateAlignedCodePages (BufferPages, BufferAlignment); ASSERT (Buffer != 0); - ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer; - - // - // Load the image to our new buffer - // - Status = PeCoffLoaderLoadImage (&ImageContext); - ASSERT_EFI_ERROR (Status); - // - // Relocate the image in our new buffer + // Load and relocate the image to our new buffer // - Status = PeCoffLoaderRelocateImage (&ImageContext); + Status = UefiImageLoadImageForExecution (&ImageContext, Buffer, BufferSize, NULL, 0); ASSERT_EFI_ERROR (Status); - *ImageAddress = ImageContext.ImageAddress; - *ImageSize = ImageContext.ImageSize; - *EntryPoint = ImageContext.EntryPoint; - - // - // Flush not needed for all architectures. We could have a processor specific - // function in this library that does the no-op if needed. - // - InvalidateInstructionCacheRange ((VOID *)(UINTN)*ImageAddress, (UINTN)*ImageSize); + *ImageAddress = (UINTN) Buffer; + *DestinationSize = BufferSize; + *EntryPoint = (UINTN) UefiImageLoaderGetImageEntryPoint (&ImageContext); return Status; } @@ -122,22 +114,23 @@ LoadDxeCoreFromFfsFile ( ) { EFI_STATUS Status; - VOID *PeCoffImage; + VOID *UefiImage; + UINT32 UefiImageSize; EFI_PHYSICAL_ADDRESS ImageAddress; - UINT64 ImageSize; + UINT32 DestinationSize; EFI_PHYSICAL_ADDRESS EntryPoint; VOID *BaseOfStack; VOID *TopOfStack; VOID *Hob; EFI_FV_FILE_INFO FvFileInfo; - Status = FfsFindSectionDataWithHook (EFI_SECTION_PE32, NULL, FileHandle, &PeCoffImage); + Status = FfsFindSectionDataWithHook (EFI_SECTION_PE32, NULL, FileHandle, &UefiImage, &UefiImageSize); if (EFI_ERROR (Status)) { return Status; } - Status = LoadPeCoffImage (PeCoffImage, &ImageAddress, &ImageSize, &EntryPoint); - // For NT32 Debug Status = SecWinNtPeiLoadFile (PeCoffImage, &ImageAddress, &ImageSize, &EntryPoint); + Status = LoadUefiImage (UefiImage, UefiImageSize, &ImageAddress, &DestinationSize, &EntryPoint); + // For NT32 Debug Status = SecWinNtPeiLoadFile (UefiImage, &ImageAddress, &ImageSize, &EntryPoint); ASSERT_EFI_ERROR (Status); // @@ -146,7 +139,7 @@ LoadDxeCoreFromFfsFile ( Status = FfsGetFileInfo (FileHandle, &FvFileInfo); ASSERT_EFI_ERROR (Status); - BuildModuleHob (&FvFileInfo.FileName, (EFI_PHYSICAL_ADDRESS)(UINTN)ImageAddress, EFI_SIZE_TO_PAGES ((UINT32)ImageSize) * EFI_PAGE_SIZE, EntryPoint); + BuildModuleHob (&FvFileInfo.FileName, (EFI_PHYSICAL_ADDRESS)(UINTN)ImageAddress, DestinationSize, EntryPoint); DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Loading DxeCore at 0x%10p EntryPoint=0x%10p\n", (VOID *)(UINTN)ImageAddress, (VOID *)(UINTN)EntryPoint)); diff --git a/EmbeddedPkg/Library/PrePiLib/PrePiLib.inf b/EmbeddedPkg/Library/PrePiLib/PrePiLib.inf index 090bfe888f..9b8e6f4c07 100644 --- a/EmbeddedPkg/Library/PrePiLib/PrePiLib.inf +++ b/EmbeddedPkg/Library/PrePiLib/PrePiLib.inf @@ -41,7 +41,7 @@ DebugLib BaseMemoryLib UefiDecompressLib - PeCoffLib + UefiImageLib CacheMaintenanceLib PrintLib SerialPortLib @@ -53,9 +53,6 @@ [Guids] gEfiMemoryTypeInformationGuid -[Protocols] - gPeCoffLoaderProtocolGuid - [FixedPcd.common] gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiACPIReclaimMemory diff --git a/EmulatorPkg/EmulatorPkg.dsc b/EmulatorPkg/EmulatorPkg.dsc index 1c356bc8c7..80e04f11f0 100644 --- a/EmulatorPkg/EmulatorPkg.dsc +++ b/EmulatorPkg/EmulatorPkg.dsc @@ -62,8 +62,8 @@ SynchronizationLib|MdePkg/Library/BaseSynchronizationLib/BaseSynchronizationLib.inf PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf CacheMaintenanceLib|MdePkg/Library/BaseCacheMaintenanceLib/BaseCacheMaintenanceLib.inf - PeCoffLib|MdePkg/Library/BasePeCoffLib/BasePeCoffLib.inf - PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf + PeCoffLib2|MdePkg/Library/BasePeCoffLib2/BasePeCoffLib2.inf + UefiImageLib|MdePkg/Library/BaseUefiImageLib/BaseUefiImageLibPeCoff.inf BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf FrameBufferBltLib|MdeModulePkg/Library/FrameBufferBltLib/FrameBufferBltLib.inf @@ -145,8 +145,7 @@ [LibraryClasses.common.SEC] PeiServicesLib|EmulatorPkg/Library/SecPeiServicesLib/SecPeiServicesLib.inf PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf - PeCoffGetEntryPointLib|EmulatorPkg/Library/PeiEmuPeCoffGetEntryPointLib/PeiEmuPeCoffGetEntryPointLib.inf - PeCoffExtraActionLib|EmulatorPkg/Library/PeiEmuPeCoffExtraActionLib/PeiEmuPeCoffExtraActionLib.inf + UefiImageExtraActionLib|EmulatorPkg/Library/PeiEmuUefiImageExtraActionLib/PeiEmuUefiImageExtraActionLib.inf SerialPortLib|EmulatorPkg/Library/PeiEmuSerialPortLib/PeiEmuSerialPortLib.inf PpiListLib|EmulatorPkg/Library/SecPpiListLib/SecPpiListLib.inf DebugLib|MdePkg/Library/BaseDebugLibSerialPort/BaseDebugLibSerialPort.inf @@ -154,13 +153,13 @@ [LibraryClasses.common.USER_DEFINED, LibraryClasses.common.BASE] DebugLib|MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.inf - PeCoffExtraActionLib|MdePkg/Library/BasePeCoffExtraActionLibNull/BasePeCoffExtraActionLibNull.inf + UefiImageExtraActionLib|MdePkg/Library/BaseUefiImageExtraActionLibNull/BaseUefiImageExtraActionLibNull.inf + HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf MemoryAllocationLib|MdePkg/Library/PeiMemoryAllocationLib/PeiMemoryAllocationLib.inf PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf PpiListLib|EmulatorPkg/Library/SecPpiListLib/SecPpiListLib.inf ThunkPpiList|EmulatorPkg/Library/ThunkPpiList/ThunkPpiList.inf ThunkProtocolList|EmulatorPkg/Library/ThunkProtocolList/ThunkProtocolList.inf - PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf PpiListLib|EmulatorPkg/Library/SecPpiListLib/SecPpiListLib.inf PeiServicesLib|EmulatorPkg/Library/SecPeiServicesLib/SecPeiServicesLib.inf @@ -169,8 +168,7 @@ HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf MemoryAllocationLib|MdePkg/Library/PeiMemoryAllocationLib/PeiMemoryAllocationLib.inf ReportStatusCodeLib|MdeModulePkg/Library/PeiReportStatusCodeLib/PeiReportStatusCodeLib.inf - PeCoffGetEntryPointLib|EmulatorPkg/Library/PeiEmuPeCoffGetEntryPointLib/PeiEmuPeCoffGetEntryPointLib.inf - PeCoffExtraActionLib|EmulatorPkg/Library/PeiEmuPeCoffExtraActionLib/PeiEmuPeCoffExtraActionLib.inf + UefiImageExtraActionLib|EmulatorPkg/Library/PeiEmuUefiImageExtraActionLib/PeiEmuUefiImageExtraActionLib.inf ExtractGuidedSectionLib|MdePkg/Library/PeiExtractGuidedSectionLib/PeiExtractGuidedSectionLib.inf SerialPortLib|EmulatorPkg/Library/PeiEmuSerialPortLib/PeiEmuSerialPortLib.inf ReportStatusCodeLib|MdeModulePkg/Library/PeiReportStatusCodeLib/PeiReportStatusCodeLib.inf @@ -186,7 +184,7 @@ HobLib|MdePkg/Library/DxeCoreHobLib/DxeCoreHobLib.inf MemoryAllocationLib|MdeModulePkg/Library/DxeCoreMemoryAllocationLib/DxeCoreMemoryAllocationLib.inf ReportStatusCodeLib|MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.inf - PeCoffExtraActionLib|EmulatorPkg/Library/DxeEmuPeCoffExtraActionLib/DxeEmuPeCoffExtraActionLib.inf + UefiImageExtraActionLib|EmulatorPkg/Library/DxeEmuUefiImageExtraActionLib/DxeEmuUefiImageExtraActionLib.inf ExtractGuidedSectionLib|MdePkg/Library/DxeExtractGuidedSectionLib/DxeExtractGuidedSectionLib.inf PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf TimerLib|EmulatorPkg/Library/DxeCoreTimerLib/DxeCoreTimerLib.inf @@ -208,7 +206,7 @@ MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf ReportStatusCodeLib|MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.inf EmuThunkLib|EmulatorPkg/Library/DxeEmuLib/DxeEmuLib.inf - PeCoffExtraActionLib|EmulatorPkg/Library/DxeEmuPeCoffExtraActionLib/DxeEmuPeCoffExtraActionLib.inf + UefiImageExtraActionLib|EmulatorPkg/Library/DxeEmuUefiImageExtraActionLib/DxeEmuUefiImageExtraActionLib.inf ReportStatusCodeLib|MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.inf TimerLib|EmulatorPkg/Library/DxeTimerLib/DxeTimerLib.inf diff --git a/EmulatorPkg/Include/Library/EmuMagicPageLib.h b/EmulatorPkg/Include/Library/EmuMagicPageLib.h index d102f1666a..9652a1186e 100644 --- a/EmulatorPkg/Include/Library/EmuMagicPageLib.h +++ b/EmulatorPkg/Include/Library/EmuMagicPageLib.h @@ -23,7 +23,7 @@ typedef struct { // Used by SecPeiServicesLib EFI_PEI_PPI_DESCRIPTOR *PpiList; - // Needed by PEI PEI PeCoffLoaderExtraActionLib + // Needed by PEI PEI UefiImageLoaderExtraActionLib EMU_THUNK_PROTOCOL *Thunk; } EMU_MAGIC_PAGE_LAYOUT; diff --git a/EmulatorPkg/Include/Protocol/EmuThunk.h b/EmulatorPkg/Include/Protocol/EmuThunk.h index bdd57f410b..ae0dbc95c9 100644 --- a/EmulatorPkg/Include/Protocol/EmuThunk.h +++ b/EmulatorPkg/Include/Protocol/EmuThunk.h @@ -17,7 +17,7 @@ // neded for things like EFI_TIME_CAPABILITIES #include -#include +#include #include #include @@ -88,20 +88,21 @@ BOOLEAN typedef EFI_STATUS (EFIAPI *EMU_PE_COFF_GET_ENTRY_POINT)( - IN VOID *Pe32Data, - IN OUT VOID **EntryPoint + IN VOID *Pe32Data, + IN UINT32 Pe32Size, + IN OUT VOID **EntryPoint ); typedef VOID (EFIAPI *EMU_PE_COFF_RELOCATE_EXTRA_ACTION)( - IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext ); typedef VOID (EFIAPI *EMU_PE_COFF_UNLOAD_EXTRA_ACTION)( - IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext ); typedef @@ -217,9 +218,9 @@ struct _EMU_THUNK_PROTOCOL { /// /// PE/COFF loader hooks to get symbols loaded /// - EMU_PE_COFF_GET_ENTRY_POINT PeCoffGetEntryPoint; - EMU_PE_COFF_RELOCATE_EXTRA_ACTION PeCoffRelocateImageExtraAction; - EMU_PE_COFF_UNLOAD_EXTRA_ACTION PeCoffUnloadImageExtraAction; + EMU_PE_COFF_GET_ENTRY_POINT UefiImageGetEntryPoint; + EMU_PE_COFF_RELOCATE_EXTRA_ACTION UefiImageRelocateImageExtraAction; + EMU_PE_COFF_UNLOAD_EXTRA_ACTION UefiImageUnloadImageExtraAction; /// /// DXE Architecture Protocol Services diff --git a/EmulatorPkg/Library/DxeEmuPeCoffExtraActionLib/DxeEmuPeCoffExtraActionLib.c b/EmulatorPkg/Library/DxeEmuPeCoffExtraActionLib/DxeEmuPeCoffExtraActionLib.c index c3c5ae4246..eba37b8755 100644 --- a/EmulatorPkg/Library/DxeEmuPeCoffExtraActionLib/DxeEmuPeCoffExtraActionLib.c +++ b/EmulatorPkg/Library/DxeEmuPeCoffExtraActionLib/DxeEmuPeCoffExtraActionLib.c @@ -1,3 +1,5 @@ +#ifndef DISABLE_NEW_DEPRECATED_INTERFACES + /** @file Provides services to perform additional actions to relocate and unload PE/Coff image for Emu environment specific purpose such as souce level debug. @@ -23,7 +25,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent // // Cache of UnixThunk protocol // -EMU_THUNK_PROTOCOL *mThunk = NULL; +EMU_THUNK_PROTOCOL *mThunk = NULL; + /** The constructor function gets the pointer of the WinNT thunk functions @@ -39,7 +42,7 @@ DxeEmuPeCoffLibExtraActionConstructor ( IN EFI_SYSTEM_TABLE *SystemTable ) { - EFI_HOB_GUID_TYPE *GuidHob; + EFI_HOB_GUID_TYPE *GuidHob; // // Retrieve EmuThunkProtocol from GUID'ed HOB @@ -72,6 +75,8 @@ PeCoffLoaderRelocateImageExtraAction ( } } + + /** Performs additional actions just before a PE/COFF image is unloaded. Any resources that were allocated by PeCoffLoaderRelocateImageExtraAction() must be freed. @@ -92,3 +97,5 @@ PeCoffLoaderUnloadImageExtraAction ( mThunk->PeCoffUnloadImageExtraAction (ImageContext); } } + +#endif // DISABLE_NEW_DEPRECATED_INTERFACES diff --git a/EmulatorPkg/Library/DxeEmuUefiImageExtraActionLib/DxeEmuUefiImageExtraActionLib.c b/EmulatorPkg/Library/DxeEmuUefiImageExtraActionLib/DxeEmuUefiImageExtraActionLib.c new file mode 100644 index 0000000000..246c4d0068 --- /dev/null +++ b/EmulatorPkg/Library/DxeEmuUefiImageExtraActionLib/DxeEmuUefiImageExtraActionLib.c @@ -0,0 +1,94 @@ +/** @file + Provides services to perform additional actions to relocate and unload + PE/Coff image for Emu environment specific purpose such as souce level debug. + This version only works for DXE phase + +Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.
+Portions copyright (c) 2008 - 2011, Apple Inc. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include + +#include + +#include +#include +#include +#include +#include +#include + +// +// Cache of UnixThunk protocol +// +EMU_THUNK_PROTOCOL *mThunk = NULL; + +/** + The constructor function gets the pointer of the WinNT thunk functions + It will ASSERT() if Unix thunk protocol is not installed. + + @retval EFI_SUCCESS Unix thunk protocol is found and cached. + +**/ +EFI_STATUS +EFIAPI +DxeEmuUefiImageLibExtraActionConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_HOB_GUID_TYPE *GuidHob; + + // + // Retrieve EmuThunkProtocol from GUID'ed HOB + // + GuidHob = GetFirstGuidHob (&gEmuThunkProtocolGuid); + ASSERT (GuidHob != NULL); + mThunk = (EMU_THUNK_PROTOCOL *)(*(UINTN *)(GET_GUID_HOB_DATA (GuidHob))); + ASSERT (mThunk != NULL); + + return EFI_SUCCESS; +} + +/** + Performs additional actions after a PE/COFF image has been loaded and relocated. + + If ImageContext is NULL, then ASSERT(). + + @param ImageContext Pointer to the image context structure that describes the + PE/COFF image that has already been loaded and relocated. + +**/ +VOID +EFIAPI +UefiImageLoaderRelocateImageExtraAction ( + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext + ) +{ + if (mThunk != NULL) { + mThunk->UefiImageRelocateImageExtraAction (ImageContext); + } +} + +/** + Performs additional actions just before a PE/COFF image is unloaded. Any resources + that were allocated by UefiImageLoaderRelocateImageExtraAction() must be freed. + + If ImageContext is NULL, then ASSERT(). + + @param ImageContext Pointer to the image context structure that describes the + PE/COFF image that is being unloaded. + +**/ +VOID +EFIAPI +UefiImageLoaderUnloadImageExtraAction ( + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext + ) +{ + if (mThunk != NULL) { + mThunk->UefiImageUnloadImageExtraAction (ImageContext); + } +} diff --git a/EmulatorPkg/Library/DxeEmuUefiImageExtraActionLib/DxeEmuUefiImageExtraActionLib.inf b/EmulatorPkg/Library/DxeEmuUefiImageExtraActionLib/DxeEmuUefiImageExtraActionLib.inf new file mode 100644 index 0000000000..8c7161b573 --- /dev/null +++ b/EmulatorPkg/Library/DxeEmuUefiImageExtraActionLib/DxeEmuUefiImageExtraActionLib.inf @@ -0,0 +1,42 @@ +## @file +# PeCoff extra action libary for DXE phase that run Emu emulator. +# +# Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.
+# Portions copyright (c) 2011, Apple Inc. All rights reserved. +# SPDX-License-Identifier: BSD-2-Clause-Patent + +# +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = DxeEmuUefiImageExtraActionLib + FILE_GUID = 68FCD487-D230-6846-95B1-5E1F2EF942C4 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = UefiImageExtraActionLib|DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER UEFI_DRIVER UEFI_APPLICATION + + CONSTRUCTOR = DxeEmuUefiImageLibExtraActionConstructor + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 +# + +[Sources] + DxeEmuUefiImageExtraActionLib.c + +[Packages] + MdePkg/MdePkg.dec + EmulatorPkg/EmulatorPkg.dec + +[LibraryClasses] + DebugLib + HobLib + BaseMemoryLib + +[Protocols] + gEmuThunkProtocolGuid # PROTOCOL ALWAYS_CONSUMED + diff --git a/EmulatorPkg/Library/PeiEmuPeCoffExtraActionLib/PeiEmuPeCoffExtraActionLib.c b/EmulatorPkg/Library/PeiEmuPeCoffExtraActionLib/PeiEmuPeCoffExtraActionLib.c index 9e1a8be607..f941158b88 100644 --- a/EmulatorPkg/Library/PeiEmuPeCoffExtraActionLib/PeiEmuPeCoffExtraActionLib.c +++ b/EmulatorPkg/Library/PeiEmuPeCoffExtraActionLib/PeiEmuPeCoffExtraActionLib.c @@ -1,3 +1,5 @@ +#ifndef DISABLE_NEW_DEPRECATED_INTERFACES + /** @file Provides services to perform additional actions to relocate and unload PE/Coff image for Emu environment specific purpose such as souce level debug. @@ -22,7 +24,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent // // Cache of UnixThunk protocol // -EMU_THUNK_PROTOCOL *mThunk = NULL; +EMU_THUNK_PROTOCOL *mThunk = NULL; /** The function caches the pointer of the Unix thunk functions @@ -36,21 +38,22 @@ EFIAPI EmuPeCoffGetThunkStucture ( ) { - EMU_THUNK_PPI *ThunkPpi; - EFI_STATUS Status; + EMU_THUNK_PPI *ThunkPpi; + EFI_STATUS Status; + // // Locate Unix ThunkPpi for retrieving standard output handle // Status = PeiServicesLocatePpi ( - &gEmuThunkPpiGuid, - 0, - NULL, - (VOID **)&ThunkPpi - ); + &gEmuThunkPpiGuid, + 0, + NULL, + (VOID **) &ThunkPpi + ); ASSERT_EFI_ERROR (Status); - EMU_MAGIC_PAGE ()->Thunk = (EMU_THUNK_PROTOCOL *)ThunkPpi->Thunk (); + EMU_MAGIC_PAGE()->Thunk = (EMU_THUNK_PROTOCOL *) ThunkPpi->Thunk (); return EFI_SUCCESS; } @@ -70,12 +73,12 @@ PeCoffLoaderRelocateImageExtraAction ( IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext ) { - if (EMU_MAGIC_PAGE ()->Thunk == NULL) { + if (EMU_MAGIC_PAGE()->Thunk == NULL) { EmuPeCoffGetThunkStucture (); } + EMU_MAGIC_PAGE()->Thunk->PeCoffRelocateImageExtraAction (ImageContext); + } - EMU_MAGIC_PAGE ()->Thunk->PeCoffRelocateImageExtraAction (ImageContext); -} /** Performs additional actions just before a PE/COFF image is unloaded. Any resources @@ -93,9 +96,10 @@ PeCoffLoaderUnloadImageExtraAction ( IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext ) { - if (EMU_MAGIC_PAGE ()->Thunk == NULL) { + if (EMU_MAGIC_PAGE()->Thunk == NULL) { EmuPeCoffGetThunkStucture (); } - - EMU_MAGIC_PAGE ()->Thunk->PeCoffUnloadImageExtraAction (ImageContext); + EMU_MAGIC_PAGE()->Thunk->PeCoffUnloadImageExtraAction (ImageContext); } + +#endif // DISABLE_NEW_DEPRECATED_INTERFACES diff --git a/EmulatorPkg/Library/PeiEmuPeCoffGetEntryPointLib/PeiEmuPeCoffGetEntryPointLib.c b/EmulatorPkg/Library/PeiEmuPeCoffGetEntryPointLib/PeiEmuPeCoffGetEntryPointLib.c index a9d28f48cf..e0a6b0f00f 100644 --- a/EmulatorPkg/Library/PeiEmuPeCoffGetEntryPointLib/PeiEmuPeCoffGetEntryPointLib.c +++ b/EmulatorPkg/Library/PeiEmuPeCoffGetEntryPointLib/PeiEmuPeCoffGetEntryPointLib.c @@ -7,7 +7,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include "PiPei.h" -#include +//#include #include #include #include @@ -35,8 +35,9 @@ SPDX-License-Identifier: BSD-2-Clause-Patent RETURN_STATUS EFIAPI PeCoffLoaderGetEntryPoint ( - IN VOID *Pe32Data, - IN OUT VOID **EntryPoint + IN VOID *Pe32Data, + IN UINT32 Pe32Size, + IN OUT VOID **EntryPoint ) { EMU_THUNK_PPI *ThunkPpi; @@ -56,7 +57,7 @@ PeCoffLoaderGetEntryPoint ( Thunk = (EMU_THUNK_PROTOCOL *)ThunkPpi->Thunk (); - return Thunk->PeCoffGetEntryPoint (Pe32Data, EntryPoint); + return Thunk->PeCoffGetEntryPoint (Pe32Data, Pe32Size, EntryPoint); } /** diff --git a/EmulatorPkg/Library/PeiEmuUefiImageExtraActionLib/PeiEmuUefiImageExtraActionLib.c b/EmulatorPkg/Library/PeiEmuUefiImageExtraActionLib/PeiEmuUefiImageExtraActionLib.c new file mode 100644 index 0000000000..ce19922aec --- /dev/null +++ b/EmulatorPkg/Library/PeiEmuUefiImageExtraActionLib/PeiEmuUefiImageExtraActionLib.c @@ -0,0 +1,101 @@ +/** @file + Provides services to perform additional actions to relocate and unload + PE/Coff image for Emu environment specific purpose such as souce level debug. + This version only works for PEI phase + +Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.
+Portions copyright (c) 2008 - 2011, Apple Inc. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +// +// Cache of UnixThunk protocol +// +EMU_THUNK_PROTOCOL *mThunk = NULL; + +/** + The function caches the pointer of the Unix thunk functions + It will ASSERT() if Unix thunk ppi is not installed. + + @retval EFI_SUCCESS WinNT thunk protocol is found and cached. + +**/ +EFI_STATUS +EFIAPI +EmuUefiImageGetThunkStucture ( + ) +{ + EMU_THUNK_PPI *ThunkPpi; + EFI_STATUS Status; + + // + // Locate Unix ThunkPpi for retrieving standard output handle + // + Status = PeiServicesLocatePpi ( + &gEmuThunkPpiGuid, + 0, + NULL, + (VOID **)&ThunkPpi + ); + ASSERT_EFI_ERROR (Status); + + EMU_MAGIC_PAGE ()->Thunk = (EMU_THUNK_PROTOCOL *)ThunkPpi->Thunk (); + + return EFI_SUCCESS; +} + +/** + Performs additional actions after a PE/COFF image has been loaded and relocated. + + If ImageContext is NULL, then ASSERT(). + + @param ImageContext Pointer to the image context structure that describes the + PE/COFF image that has already been loaded and relocated. + +**/ +VOID +EFIAPI +UefiImageLoaderRelocateImageExtraAction ( + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext + ) +{ + if (EMU_MAGIC_PAGE ()->Thunk == NULL) { + EmuUefiImageGetThunkStucture (); + } + + EMU_MAGIC_PAGE ()->Thunk->UefiImageRelocateImageExtraAction (ImageContext); +} + +/** + Performs additional actions just before a PE/COFF image is unloaded. Any resources + that were allocated by UefiImageLoaderRelocateImageExtraAction() must be freed. + + If ImageContext is NULL, then ASSERT(). + + @param ImageContext Pointer to the image context structure that describes the + PE/COFF image that is being unloaded. + +**/ +VOID +EFIAPI +UefiImageLoaderUnloadImageExtraAction ( + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext + ) +{ + if (EMU_MAGIC_PAGE ()->Thunk == NULL) { + EmuUefiImageGetThunkStucture (); + } + + EMU_MAGIC_PAGE ()->Thunk->UefiImageUnloadImageExtraAction (ImageContext); +} diff --git a/EmulatorPkg/Library/PeiEmuUefiImageExtraActionLib/PeiEmuUefiImageExtraActionLib.inf b/EmulatorPkg/Library/PeiEmuUefiImageExtraActionLib/PeiEmuUefiImageExtraActionLib.inf new file mode 100644 index 0000000000..d2b109da86 --- /dev/null +++ b/EmulatorPkg/Library/PeiEmuUefiImageExtraActionLib/PeiEmuUefiImageExtraActionLib.inf @@ -0,0 +1,43 @@ +## @file +# PeCoff extra action libary for Pei phase that run Emu emulator. +# +# Lib to provide memory journal status code reporting Routines +# Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.
+# Portions copyright (c) 2011, Apple Inc. All rights reserved. +# SPDX-License-Identifier: BSD-2-Clause-Patent + +# +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = PeiEmuUefiImageExtraActionLib + FILE_GUID = 79C4E72A-730B-F040-8129-95877B3A97A8 + MODULE_TYPE = PEIM + VERSION_STRING = 1.0 + LIBRARY_CLASS = UefiImageExtraActionLib|PEI_CORE PEIM + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 +# + +[Sources] + PeiEmuUefiImageExtraActionLib.c + +[Packages] + MdePkg/MdePkg.dec + EmulatorPkg/EmulatorPkg.dec + +[LibraryClasses] + BaseLib + PeiServicesLib + DebugLib + +[Ppis] + gEmuThunkPpiGuid # PPI ALWAYS_CONSUMED + +[Pcd] + gEmulatorPkgTokenSpaceGuid.PcdPeiServicesTablePage diff --git a/EmulatorPkg/Library/SecPeiServicesLib/FwVol.c b/EmulatorPkg/Library/SecPeiServicesLib/FwVol.c index e1cc6c6a51..7bb6cd0fe9 100644 --- a/EmulatorPkg/Library/SecPeiServicesLib/FwVol.c +++ b/EmulatorPkg/Library/SecPeiServicesLib/FwVol.c @@ -276,3 +276,52 @@ Routine Description: return EFI_NOT_FOUND; } + +// FIXME: Docs +EFI_STATUS +SecFfsFindSectionData2 ( + IN EFI_SECTION_TYPE SectionType, + IN EFI_FFS_FILE_HEADER *FfsFileHeader, + IN OUT VOID **SectionData, + OUT UINT32 *SectionDataSize + ) +{ + UINT32 FileSize; + EFI_COMMON_SECTION_HEADER *Section; + UINT32 SectionLength; + UINT32 ParsedLength; + + // + // Size is 24 bits wide so mask upper 8 bits. + // Does not include FfsFileHeader header size + // FileSize is adjusted to FileOccupiedSize as it is 8 byte aligned. + // + Section = (EFI_COMMON_SECTION_HEADER *) (FfsFileHeader + 1); + FileSize = *(UINT32 *) (FfsFileHeader->Size) & 0x00FFFFFF; + FileSize -= sizeof (EFI_FFS_FILE_HEADER); + + *SectionData = NULL; + ParsedLength = 0; + while (ParsedLength < FileSize) { + // FIXME: Common API with size checks + // + // Size is 24 bits wide so mask upper 8 bits. + // + SectionLength = *(UINT32 *) Section->Size & 0x00FFFFFF; + if (Section->Type == SectionType) { + *SectionData = (VOID *) (Section + 1); + *SectionDataSize = SectionLength - sizeof (*Section); + return EFI_SUCCESS; + } + // + // SectionLength is adjusted it is 4 byte aligned. + // Go to the next section + // + SectionLength = GET_OCCUPIED_SIZE (SectionLength, 4); + + ParsedLength += SectionLength; + Section = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) Section + SectionLength); + } + + return EFI_NOT_FOUND; +} diff --git a/EmulatorPkg/Library/SecPeiServicesLib/PeiServicesLib.c b/EmulatorPkg/Library/SecPeiServicesLib/PeiServicesLib.c index 9409cbdb66..51bd3f9e1a 100644 --- a/EmulatorPkg/Library/SecPeiServicesLib/PeiServicesLib.c +++ b/EmulatorPkg/Library/SecPeiServicesLib/PeiServicesLib.c @@ -26,6 +26,14 @@ SecFfsFindSectionData ( OUT VOID **SectionData ); +EFI_STATUS +SecFfsFindSectionData2 ( + IN EFI_SECTION_TYPE SectionType, + IN EFI_FFS_FILE_HEADER *FfsFileHeader, + IN OUT VOID **SectionData, + OUT UINT32 *SectionDataSize + ); + /** This service enables a given PEIM to register an interface into the PEI Foundation. @@ -304,6 +312,38 @@ PeiServicesFfsFindSectionData ( return SecFfsFindSectionData (SectionType, FileHandle, SectionData); } +/** + This service enables PEIMs to discover sections of a given instance and type within a valid FFS file. + + @param SectionType The value of the section type to find. + @param SectionInstance Section instance to find. + @param FileHandle A pointer to the file header that contains the set + of sections to be searched. + @param SectionData A pointer to the discovered section, if successful. + @param SectionDataSize The size of the discovered section, if successful. + @param AuthenticationStatus A pointer to the authentication status for this section. + + @retval EFI_SUCCESS The section was found. + @retval EFI_NOT_FOUND The section was not found. + +**/ +EFI_STATUS +EFIAPI +PeiServicesFfsFindSectionData4 ( + IN EFI_SECTION_TYPE SectionType, + IN UINTN SectionInstance, + IN EFI_PEI_FILE_HANDLE FileHandle, + OUT VOID **SectionData, + OUT UINT32 *SectionDataSize, + OUT UINT32 *AuthenticationStatus + ) +{ + ASSERT (SectionInstance == 0); + + *AuthenticationStatus = 0; + return SecFfsFindSectionData2 (SectionType, FileHandle, SectionData, SectionDataSize); +} + /** This service enables PEIMs to register the permanent memory configuration that has been initialized with the PEI Foundation. diff --git a/EmulatorPkg/Sec/Sec.c b/EmulatorPkg/Sec/Sec.c index 3d792adc94..e1d9373b90 100644 --- a/EmulatorPkg/Sec/Sec.c +++ b/EmulatorPkg/Sec/Sec.c @@ -9,6 +9,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include "Sec.h" +#include EFI_PEI_TEMPORARY_RAM_SUPPORT_PPI mSecTemporaryRamSupportPpi = { SecTemporaryRamSupport @@ -22,6 +23,53 @@ EFI_PEI_PPI_DESCRIPTOR gPrivateDispatchTable[] = { } }; +//FIXME: +/** + Retrieves and returns a pointer to the entry point to a PE/COFF image that has been loaded + into system memory with the PE/COFF Loader Library functions. + + Retrieves the entry point to the PE/COFF image specified by Pe32Data and returns this entry + point in EntryPoint. If the entry point could not be retrieved from the PE/COFF image, then + return RETURN_INVALID_PARAMETER. Otherwise return RETURN_SUCCESS. + If Pe32Data is NULL, then ASSERT(). + If EntryPoint is NULL, then ASSERT(). + + @param Pe32Data The pointer to the PE/COFF image that is loaded in system memory. + @param EntryPoint The pointer to entry point to the PE/COFF image to return. + + @retval RETURN_SUCCESS EntryPoint was returned. + @retval RETURN_INVALID_PARAMETER The entry point could not be found in the PE/COFF image. + +**/ +RETURN_STATUS +EFIAPI +UefiImageLoaderGetEntryPoint ( + IN VOID *Pe32Data, + IN UINT32 Pe32Size, + IN OUT VOID **EntryPoint + ) +{ + EMU_THUNK_PPI *ThunkPpi; + EFI_STATUS Status; + EMU_THUNK_PROTOCOL *Thunk; + + // + // Locate EmuThunkPpi for retrieving standard output handle + // + Status = PeiServicesLocatePpi ( + &gEmuThunkPpiGuid, + 0, + NULL, + (VOID **) &ThunkPpi + ); + ASSERT_EFI_ERROR (Status); + + Thunk = (EMU_THUNK_PROTOCOL *)ThunkPpi->Thunk (); + + return Thunk->UefiImageGetEntryPoint (Pe32Data, Pe32Size, EntryPoint); +} + + /** The entry point of PE/COFF Image for the PEI Core, that has been hijacked by this SEC that sits on top of an OS application. So the entry and exit of this module @@ -64,13 +112,15 @@ _ModuleEntryPoint ( EFI_STATUS Status; EFI_PEI_FV_HANDLE VolumeHandle; EFI_PEI_FILE_HANDLE FileHandle; - VOID *PeCoffImage; + VOID *UefiImage; + UINT32 UefiImageSize; EFI_PEI_CORE_ENTRY_POINT EntryPoint; EFI_PEI_PPI_DESCRIPTOR *Ppi; EFI_PEI_PPI_DESCRIPTOR *SecPpiList; UINTN SecReseveredMemorySize; UINTN Index; EFI_PEI_PPI_DESCRIPTOR PpiArray[10]; + UINT32 AuthenticationStatus; EMU_MAGIC_PAGE ()->PpiList = PpiList; ProcessLibraryConstructorList (); @@ -118,10 +168,10 @@ _ModuleEntryPoint ( Status = PeiServicesFfsFindNextFile (EFI_FV_FILETYPE_PEI_CORE, VolumeHandle, &FileHandle); ASSERT_EFI_ERROR (Status); - Status = PeiServicesFfsFindSectionData (EFI_SECTION_PE32, FileHandle, &PeCoffImage); + Status = PeiServicesFfsFindSectionData4 (EFI_SECTION_PE32, 0, FileHandle, &UefiImage, &UefiImageSize, &AuthenticationStatus); ASSERT_EFI_ERROR (Status); - Status = PeCoffLoaderGetEntryPoint (PeCoffImage, (VOID **)&EntryPoint); + Status = UefiImageLoaderGetEntryPoint (UefiImage, UefiImageSize, (VOID **)&EntryPoint); ASSERT_EFI_ERROR (Status); // Transfer control to PEI Core diff --git a/EmulatorPkg/Sec/Sec.h b/EmulatorPkg/Sec/Sec.h index 94689eb41d..e357add14c 100644 --- a/EmulatorPkg/Sec/Sec.h +++ b/EmulatorPkg/Sec/Sec.h @@ -15,7 +15,6 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #include #include #include -#include #include #include diff --git a/EmulatorPkg/Sec/Sec.inf b/EmulatorPkg/Sec/Sec.inf index 7476094f13..8c9441ffa4 100644 --- a/EmulatorPkg/Sec/Sec.inf +++ b/EmulatorPkg/Sec/Sec.inf @@ -36,7 +36,6 @@ [LibraryClasses] DebugLib - PeCoffGetEntryPointLib PeiServicesLib PpiListLib BaseMemoryLib diff --git a/EmulatorPkg/Unix/GdbRun.sh b/EmulatorPkg/Unix/GdbRun.sh index b050ad5e2c..6fea1c9d5b 100644 --- a/EmulatorPkg/Unix/GdbRun.sh +++ b/EmulatorPkg/Unix/GdbRun.sh @@ -41,7 +41,7 @@ set $SymbolFileChangesCount = 0 # define AddFirmwareSymbolFile if $SymbolFileChangesCount < $arg0 - add-symbol-file $arg1 $arg2 + add-symbol-file $arg1 -o $arg2 set $SymbolFileChangesCount = $arg0 end end diff --git a/EmulatorPkg/Unix/Host/EmuThunk.c b/EmulatorPkg/Unix/Host/EmuThunk.c index c57c105a53..bdc6d62035 100644 --- a/EmulatorPkg/Unix/Host/EmuThunk.c +++ b/EmulatorPkg/Unix/Host/EmuThunk.c @@ -415,9 +415,9 @@ EMU_THUNK_PROTOCOL gEmuThunkProtocol = { GasketSecMalloc, GasketSecValloc, GasketSecFree, - GasketSecPeCoffGetEntryPoint, - GasketSecPeCoffRelocateImageExtraAction, - GasketSecPeCoffUnloadImageExtraAction, + GasketSecUefiImageGetEntryPoint, + GasketSecUefiImageRelocateImageExtraAction, + GasketSecUefiImageUnloadImageExtraAction, GasketSecEnableInterrupt, GasketSecDisableInterrupt, GasketQueryPerformanceFrequency, diff --git a/EmulatorPkg/Unix/Host/Gasket.h b/EmulatorPkg/Unix/Host/Gasket.h index 6dafc903cf..6ebac74445 100644 --- a/EmulatorPkg/Unix/Host/Gasket.h +++ b/EmulatorPkg/Unix/Host/Gasket.h @@ -67,21 +67,22 @@ GasketSecFree ( RETURN_STATUS EFIAPI -GasketSecPeCoffGetEntryPoint ( +GasketSecUefiImageGetEntryPoint ( IN VOID *Pe32Data, + IN UINT32 Pe32Size, IN OUT VOID **EntryPoint ); VOID EFIAPI -GasketSecPeCoffRelocateImageExtraAction ( - IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext +GasketSecUefiImageRelocateImageExtraAction ( + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext ); VOID EFIAPI -GasketSecPeCoffUnloadImageExtraAction ( - IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext +GasketSecUefiImageUnloadImageExtraAction ( + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext ); VOID diff --git a/EmulatorPkg/Unix/Host/Host.c b/EmulatorPkg/Unix/Host/Host.c index 1f29dd00a3..134481b617 100644 --- a/EmulatorPkg/Unix/Host/Host.c +++ b/EmulatorPkg/Unix/Host/Host.c @@ -44,9 +44,6 @@ EMU_FD_INFO *gFdInfo; UINTN gSystemMemoryCount = 0; EMU_SYSTEM_MEMORY *gSystemMemory; -UINTN mImageContextModHandleArraySize = 0; -IMAGE_CONTEXT_TO_MOD_HANDLE *mImageContextModHandleArray = NULL; - EFI_PEI_PPI_DESCRIPTOR *gPpiList; int gInXcode = 0; @@ -98,11 +95,13 @@ main ( BOOLEAN Done; EFI_PEI_FILE_HANDLE FileHandle; VOID *SecFile; + UINT32 SecFileSize; CHAR16 *MemorySizeStr; CHAR16 *FirmwareVolumesStr; UINTN *StackPointer; FILE *GdbTempFile; EMU_THUNK_PPI *SecEmuThunkPpi; + UINT32 AuthenticationStatus; // // Xcode does not support sourcing gdb scripts directly, so the Xcode XML @@ -111,8 +110,7 @@ main ( SecGdbConfigBreak (); // - // If dlopen doesn't work, then we build a gdb script to allow the - // symbols to be loaded. + // We build a gdb script to allow the symbols to be loaded. // Index = strlen (*Argv); gGdbWorkingFileName = AllocatePool (Index + strlen (".gdb") + 1); @@ -284,7 +282,14 @@ main ( &FileHandle ); if (!EFI_ERROR (Status)) { - Status = PeiServicesFfsFindSectionData (EFI_SECTION_PE32, FileHandle, &SecFile); + Status = PeiServicesFfsFindSectionData4 ( + EFI_SECTION_PE32, + 0, + FileHandle, + &SecFile, + &SecFileSize, + &AuthenticationStatus + ); if (!EFI_ERROR (Status)) { PeiIndex = Index; printf (" contains SEC Core"); @@ -330,7 +335,7 @@ main ( // // Hand off to SEC // - SecLoadFromCore ((UINTN)InitialStackMemory, (UINTN)InitialStackMemorySize, (UINTN)gFdInfo[0].Address, SecFile); + SecLoadFromCore ((UINTN)InitialStackMemory, (UINTN)InitialStackMemorySize, (UINTN)gFdInfo[0].Address, SecFile, SecFileSize); // // If we get here, then the SEC Core returned. This is an error as SEC should @@ -546,7 +551,8 @@ SecLoadFromCore ( IN UINTN LargestRegion, IN UINTN LargestRegionSize, IN UINTN BootFirmwareVolumeBase, - IN VOID *PeiCorePe32File + IN VOID *PeiCorePe32File, + IN UINT32 PeiCorePe32Size ) { EFI_STATUS Status; @@ -597,7 +603,7 @@ SecLoadFromCore ( // // Find the SEC Core Entry Point // - Status = SecPeCoffGetEntryPoint (PeiCorePe32File, (VOID **)&PeiCoreEntryPoint); + Status = SecUefiImageGetEntryPoint (PeiCorePe32File, PeiCorePe32Size, (VOID **)&PeiCoreEntryPoint); if (EFI_ERROR (Status)) { return; } @@ -731,53 +737,28 @@ SecEmuThunkAddress ( RETURN_STATUS EFIAPI -SecPeCoffGetEntryPoint ( - IN VOID *Pe32Data, - IN OUT VOID **EntryPoint +SecUefiImageGetEntryPoint ( + IN VOID *Pe32Data, + IN UINT32 Pe32Size, + IN OUT VOID **EntryPoint ) { - EFI_STATUS Status; - PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; - - ZeroMem (&ImageContext, sizeof (ImageContext)); - ImageContext.Handle = Pe32Data; - ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE)SecImageRead; + EFI_STATUS Status; + UEFI_IMAGE_LOADER_IMAGE_CONTEXT ImageContext; - Status = PeCoffLoaderGetImageInfo (&ImageContext); + Status = UefiImageInitializeContext (&ImageContext, Pe32Data, Pe32Size); if (EFI_ERROR (Status)) { return Status; } - if (ImageContext.ImageAddress != (UINTN)Pe32Data) { - // - // Relocate image to match the address where it resides - // - ImageContext.ImageAddress = (UINTN)Pe32Data; - Status = PeCoffLoaderLoadImage (&ImageContext); - if (EFI_ERROR (Status)) { - return Status; - } - - Status = PeCoffLoaderRelocateImage (&ImageContext); - if (EFI_ERROR (Status)) { - return Status; - } - } else { - // - // Or just return image entry point - // - ImageContext.PdbPointer = PeCoffLoaderGetPdbPointer (Pe32Data); - Status = PeCoffLoaderGetEntryPoint (Pe32Data, EntryPoint); - if (EFI_ERROR (Status)) { - return Status; - } - - ImageContext.EntryPoint = (UINTN)*EntryPoint; + // FIXME: Why cannot the Image be in-place already? + Status = UefiImageRelocateImageInplaceForExecution (&ImageContext); + if (EFI_ERROR (Status)) { + return Status; } - // On Unix a dlopen is done that will change the entry point - SecPeCoffRelocateImageExtraAction (&ImageContext); - *EntryPoint = (VOID *)(UINTN)ImageContext.EntryPoint; + SecUefiImageRelocateImageExtraAction (&ImageContext); + *EntryPoint = (VOID *) (UefiImageLoaderGetImageEntryPoint (&ImageContext)); return Status; } @@ -900,114 +881,9 @@ Routine Description: return EFI_SUCCESS; } -/*++ - -Routine Description: - Store the ModHandle in an array indexed by the Pdb File name. - The ModHandle is needed to unload the image. - -Arguments: - ImageContext - Input data returned from PE Loader Library. Used to find the - .PDB file name of the PE Image. - ModHandle - Returned from LoadLibraryEx() and stored for call to - FreeLibrary(). - -Returns: - EFI_SUCCESS - ModHandle was stored. - -**/ -EFI_STATUS -AddHandle ( - IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext, - IN VOID *ModHandle - ) -{ - UINTN Index; - IMAGE_CONTEXT_TO_MOD_HANDLE *Array; - UINTN PreviousSize; - - Array = mImageContextModHandleArray; - for (Index = 0; Index < mImageContextModHandleArraySize; Index++, Array++) { - if (Array->ImageContext == NULL) { - // - // Make a copy of the string and store the ModHandle - // - Array->ImageContext = ImageContext; - Array->ModHandle = ModHandle; - return EFI_SUCCESS; - } - } - - // - // No free space in mImageContextModHandleArray so grow it by - // IMAGE_CONTEXT_TO_MOD_HANDLE entires. realloc will - // copy the old values to the new location. But it does - // not zero the new memory area. - // - PreviousSize = mImageContextModHandleArraySize * sizeof (IMAGE_CONTEXT_TO_MOD_HANDLE); - mImageContextModHandleArraySize += MAX_IMAGE_CONTEXT_TO_MOD_HANDLE_ARRAY_SIZE; - - mImageContextModHandleArray = ReallocatePool ( - (mImageContextModHandleArraySize - 1) * sizeof (IMAGE_CONTEXT_TO_MOD_HANDLE), - mImageContextModHandleArraySize * sizeof (IMAGE_CONTEXT_TO_MOD_HANDLE), - mImageContextModHandleArray - ); - if (mImageContextModHandleArray == NULL) { - ASSERT (FALSE); - return EFI_OUT_OF_RESOURCES; - } - - memset (mImageContextModHandleArray + PreviousSize, 0, MAX_IMAGE_CONTEXT_TO_MOD_HANDLE_ARRAY_SIZE * sizeof (IMAGE_CONTEXT_TO_MOD_HANDLE)); - - return AddHandle (ImageContext, ModHandle); -} - -/*++ - -Routine Description: - Return the ModHandle and delete the entry in the array. - -Arguments: - ImageContext - Input data returned from PE Loader Library. Used to find the - .PDB file name of the PE Image. - -Returns: - ModHandle - ModHandle associated with ImageContext is returned - NULL - No ModHandle associated with ImageContext - -**/ -VOID * -RemoveHandle ( - IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext - ) -{ - UINTN Index; - IMAGE_CONTEXT_TO_MOD_HANDLE *Array; - - if (ImageContext->PdbPointer == NULL) { - // - // If no PDB pointer there is no ModHandle so return NULL - // - return NULL; - } - - Array = mImageContextModHandleArray; - for (Index = 0; Index < mImageContextModHandleArraySize; Index++, Array++) { - if (Array->ImageContext == ImageContext) { - // - // If you find a match return it and delete the entry - // - Array->ImageContext = NULL; - return Array->ModHandle; - } - } - - return NULL; -} - BOOLEAN IsPdbFile ( - IN CHAR8 *PdbFileName + IN CONST CHAR8 *PdbFileName ) { UINTN Len; @@ -1035,23 +911,29 @@ IsPdbFile ( void PrintLoadAddress ( - IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext + IN UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext ) { - if (ImageContext->PdbPointer == NULL) { + EFI_STATUS Status; + CONST CHAR8 *PdbPath; + UINT32 PdbPathSize; + + Status = UefiImageGetSymbolsPath (ImageContext, &PdbPath, &PdbPathSize); + + if (EFI_ERROR (Status)) { fprintf ( stderr, "0x%08lx Loading NO DEBUG with entry point 0x%08lx\n", - (unsigned long)(ImageContext->ImageAddress), - (unsigned long)ImageContext->EntryPoint + (unsigned long) UefiImageLoaderGetImageAddress (ImageContext), + (unsigned long) UefiImageLoaderGetImageEntryPoint (ImageContext) ); } else { fprintf ( stderr, "0x%08lx Loading %s with entry point 0x%08lx\n", - (unsigned long)(ImageContext->ImageAddress + ImageContext->SizeOfHeaders), - ImageContext->PdbPointer, - (unsigned long)ImageContext->EntryPoint + (unsigned long) UefiImageLoaderGetImageAddress (ImageContext), + PdbPath, + (unsigned long) UefiImageLoaderGetImageEntryPoint (ImageContext) ); } @@ -1059,71 +941,12 @@ PrintLoadAddress ( fflush (stderr); } -/** - Loads the image using dlopen so symbols will be automatically - loaded by gdb. - - @param ImageContext The PE/COFF image context - - @retval TRUE - The image was successfully loaded - @retval FALSE - The image was successfully loaded - -**/ -BOOLEAN -DlLoadImage ( - IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext - ) -{ - #ifdef __APPLE__ - - return FALSE; - - #else - - void *Handle = NULL; - void *Entry = NULL; - - if (ImageContext->PdbPointer == NULL) { - return FALSE; - } - - if (!IsPdbFile (ImageContext->PdbPointer)) { - return FALSE; - } - - fprintf ( - stderr, - "Loading %s 0x%08lx - entry point 0x%08lx\n", - ImageContext->PdbPointer, - (unsigned long)ImageContext->ImageAddress, - (unsigned long)ImageContext->EntryPoint - ); - - Handle = dlopen (ImageContext->PdbPointer, RTLD_NOW); - if (Handle != NULL) { - Entry = dlsym (Handle, "_ModuleEntryPoint"); - AddHandle (ImageContext, Handle); - } else { - printf ("%s\n", dlerror ()); - } - - if (Entry != NULL) { - ImageContext->EntryPoint = (UINTN)Entry; - printf ("Change %s Entrypoint to :0x%08lx\n", ImageContext->PdbPointer, (unsigned long)Entry); - return TRUE; - } else { - return FALSE; - } - - #endif -} - #ifdef __APPLE__ __attribute__ ((noinline)) #endif VOID SecGdbScriptBreak ( - char *FileName, + const char *FileName, int FileNameLength, long unsigned int LoadAddress, int AddSymbolFlag @@ -1141,28 +964,37 @@ SecGdbScriptBreak ( **/ VOID GdbScriptAddImage ( - IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext ) { + EFI_STATUS Status; + CONST CHAR8 *PdbPath; + UINT32 PdbPathSize; + PrintLoadAddress (ImageContext); - if ((ImageContext->PdbPointer != NULL) && !IsPdbFile (ImageContext->PdbPointer)) { + Status = UefiImageGetSymbolsPath ((ImageContext, &PdbPath,) &PdbPathSize); + if (EFI_ERROR (Status)) { + return; + } + + if (!IsPdbFile (PdbPath)) { FILE *GdbTempFile; if (FeaturePcdGet (PcdEmulatorLazyLoadSymbols)) { GdbTempFile = fopen (gGdbWorkingFileName, "a"); if (GdbTempFile != NULL) { - long unsigned int SymbolsAddr = (long unsigned int)(ImageContext->ImageAddress + ImageContext->SizeOfHeaders); + long unsigned int SymbolsAddr = (long unsigned int)UefiImageLoaderGetImageAddress (ImageContext); mScriptSymbolChangesCount++; fprintf ( GdbTempFile, "AddFirmwareSymbolFile 0x%x %s 0x%08lx\n", mScriptSymbolChangesCount, - ImageContext->PdbPointer, + PdbPath, SymbolsAddr ); fclose (GdbTempFile); // This is for the lldb breakpoint only - SecGdbScriptBreak (ImageContext->PdbPointer, strlen (ImageContext->PdbPointer) + 1, (long unsigned int)(ImageContext->ImageAddress + ImageContext->SizeOfHeaders), 1); + SecGdbScriptBreak (PdbPath, PdbPathSize, (long unsigned int)UefiImageLoaderGetImageAddress (ImageContext), 1); } else { ASSERT (FALSE); } @@ -1171,9 +1003,9 @@ GdbScriptAddImage ( if (GdbTempFile != NULL) { fprintf ( GdbTempFile, - "add-symbol-file %s 0x%08lx\n", - ImageContext->PdbPointer, - (long unsigned int)(ImageContext->ImageAddress + ImageContext->SizeOfHeaders) + "add-symbol-file %s -o 0x%08lx\n", + PdbPath, + (long unsigned int)UefiImageLoaderGetImageAddress (ImageContext) ); fclose (GdbTempFile); @@ -1183,7 +1015,7 @@ GdbScriptAddImage ( // Also used for the lldb breakpoint script. The lldb breakpoint script does // not use the file, it uses the arguments. // - SecGdbScriptBreak (ImageContext->PdbPointer, strlen (ImageContext->PdbPointer) + 1, (long unsigned int)(ImageContext->ImageAddress + ImageContext->SizeOfHeaders), 1); + SecGdbScriptBreak (PdbPath, PdbPathSize, (long unsigned int)UefiImageLoaderGetImageAddress (ImageContext), 1); } else { ASSERT (FALSE); } @@ -1193,13 +1025,11 @@ GdbScriptAddImage ( VOID EFIAPI -SecPeCoffRelocateImageExtraAction ( - IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext +SecUefiImageRelocateImageExtraAction ( + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext ) { - if (!DlLoadImage (ImageContext)) { - GdbScriptAddImage (ImageContext); - } + GdbScriptAddImage (ImageContext); } /** @@ -1211,15 +1041,23 @@ SecPeCoffRelocateImageExtraAction ( **/ VOID GdbScriptRemoveImage ( - IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext ) { - FILE *GdbTempFile; + FILE *GdbTempFile; + EFI_STATUS Status; + CONST CHAR8 *PdbPath; + UINT32 PdbPathSize; + + Status = UefiImageGetSymbolsPath (ImageContext, &PdbPath, &PdbPathSize); + if (EFI_ERROR (Status)) { + return; + } // // Need to skip .PDB files created from VC++ // - if (IsPdbFile (ImageContext->PdbPointer)) { + if (IsPdbFile (PdbPath)) { return; } @@ -1234,24 +1072,24 @@ GdbScriptRemoveImage ( GdbTempFile, "RemoveFirmwareSymbolFile 0x%x %s\n", mScriptSymbolChangesCount, - ImageContext->PdbPointer + PdbPath ); fclose (GdbTempFile); - SecGdbScriptBreak (ImageContext->PdbPointer, strlen (ImageContext->PdbPointer) + 1, 0, 0); + SecGdbScriptBreak (PdbPath, PdbPathSize, 0, 0); } else { ASSERT (FALSE); } } else { GdbTempFile = fopen (gGdbWorkingFileName, "w"); if (GdbTempFile != NULL) { - fprintf (GdbTempFile, "remove-symbol-file %s\n", ImageContext->PdbPointer); + fprintf (GdbTempFile, "remove-symbol-file %s\n", PdbPath); fclose (GdbTempFile); // // Target for gdb breakpoint in a script that uses gGdbWorkingFileName to set a breakpoint. // Hey what can you say scripting in gdb is not that great.... // - SecGdbScriptBreak (ImageContext->PdbPointer, strlen (ImageContext->PdbPointer) + 1, 0, 0); + SecGdbScriptBreak (PdbPath, PdbPathSize, 0, 0); } else { ASSERT (FALSE); } @@ -1260,22 +1098,9 @@ GdbScriptRemoveImage ( VOID EFIAPI -SecPeCoffUnloadImageExtraAction ( - IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext +SecUefiImageUnloadImageExtraAction ( + IN UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext ) { - VOID *Handle; - - // - // Check to see if the image symbols were loaded with gdb script, or dlopen - // - Handle = RemoveHandle (ImageContext); - if (Handle != NULL) { - #ifndef __APPLE__ - dlclose (Handle); - #endif - return; - } - GdbScriptRemoveImage (ImageContext); } diff --git a/EmulatorPkg/Unix/Host/Host.h b/EmulatorPkg/Unix/Host/Host.h index 0c81cdfc01..c3b4214f84 100644 --- a/EmulatorPkg/Unix/Host/Host.h +++ b/EmulatorPkg/Unix/Host/Host.h @@ -85,7 +85,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #include #include -#include +#include #include #include #include @@ -97,7 +97,6 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #include #include #include -#include #include #include @@ -137,7 +136,7 @@ typedef struct { #define MAX_IMAGE_CONTEXT_TO_MOD_HANDLE_ARRAY_SIZE 0x100 typedef struct { - PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext; + UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext; VOID *ModHandle; } IMAGE_CONTEXT_TO_MOD_HANDLE; @@ -162,7 +161,8 @@ SecLoadFromCore ( IN UINTN LargestRegion, IN UINTN LargestRegionSize, IN UINTN BootFirmwareVolumeBase, - IN VOID *PeiCoreFile + IN VOID *PeiCoreFile, + IN UINT32 PeiCorePe32Size ); EFI_STATUS @@ -194,17 +194,11 @@ SecFfsFindSectionData ( ); EFI_STATUS -EFIAPI -SecUnixPeCoffLoaderLoadAsDll ( - IN CHAR8 *PdbFileName, - IN VOID **ImageEntryPoint, - OUT VOID **ModHandle - ); - -EFI_STATUS -EFIAPI -SecUnixPeCoffLoaderFreeLibrary ( - OUT VOID *ModHandle +SecFfsFindSectionData2 ( + IN EFI_SECTION_TYPE SectionType, + IN EFI_FFS_FILE_HEADER *FfsFileHeader, + IN OUT VOID **SectionData, + OUT UINT32 *SectionDataSize ); EFI_STATUS @@ -228,7 +222,7 @@ GasketSecUnixFdAddress ( EFI_STATUS GetImageReadFunction ( - IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext, + IN UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext, IN EFI_PHYSICAL_ADDRESS *TopOfMemory ); @@ -273,21 +267,22 @@ GasketSecTemporaryRamSupport ( RETURN_STATUS EFIAPI -SecPeCoffGetEntryPoint ( +SecUefiImageGetEntryPoint ( IN VOID *Pe32Data, + IN UINT32 Pe32Size, IN OUT VOID **EntryPoint ); VOID EFIAPI -SecPeCoffRelocateImageExtraAction ( - IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext +SecUefiImageRelocateImageExtraAction ( + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext ); VOID EFIAPI -SecPeCoffLoaderUnloadImageExtraAction ( - IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext +SecUefiImageLoaderUnloadImageExtraAction ( + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext ); VOID diff --git a/EmulatorPkg/Unix/Host/Host.inf b/EmulatorPkg/Unix/Host/Host.inf index f5ebbed683..168b17173d 100644 --- a/EmulatorPkg/Unix/Host/Host.inf +++ b/EmulatorPkg/Unix/Host/Host.inf @@ -55,12 +55,11 @@ PrintLib BaseMemoryLib BaseLib - PeCoffLib + UefiImageLib ThunkPpiList ThunkProtocolList PpiListLib PeiServicesLib - PeCoffGetEntryPointLib [Ppis] gEfiPeiStatusCodePpiGuid # PPI ALWAYS_PRODUCED diff --git a/EmulatorPkg/Unix/Host/Ia32/Gasket.S b/EmulatorPkg/Unix/Host/Ia32/Gasket.S index 36197ff260..81c9fd2cc1 100644 --- a/EmulatorPkg/Unix/Host/Ia32/Gasket.S +++ b/EmulatorPkg/Unix/Host/Ia32/Gasket.S @@ -313,24 +313,26 @@ ASM_PFX(GasketSecGetNextProtocol): // PPIs produced by SEC -ASM_GLOBAL ASM_PFX(GasketSecPeCoffGetEntryPoint) -ASM_PFX(GasketSecPeCoffGetEntryPoint): +ASM_GLOBAL ASM_PFX(GasketSecUefiImageGetEntryPoint) +ASM_PFX(GasketSecUefiImageGetEntryPoint): pushl %ebp movl %esp, %ebp - subl $24, %esp // sub extra 16 from the stack for alignment + subl $40, %esp // sub extra 16 from the stack for alignment and $-16, %esp // stack needs to end in 0xFFFFFFF0 before call + movl 16(%ebp), %eax + movl %eax, 8(%esp) movl 12(%ebp), %eax movl %eax, 4(%esp) movl 8(%ebp), %eax movl %eax, (%esp) - call ASM_PFX(SecPeCoffGetEntryPoint) + call ASM_PFX(SecUefiImageGetEntryPoint) leave ret -ASM_GLOBAL ASM_PFX(GasketSecPeCoffRelocateImageExtraAction) -ASM_PFX(GasketSecPeCoffRelocateImageExtraAction): +ASM_GLOBAL ASM_PFX(GasketSecUefiImageRelocateImageExtraAction) +ASM_PFX(GasketSecUefiImageRelocateImageExtraAction): pushl %ebp movl %esp, %ebp subl $24, %esp // sub extra 16 from the stack for alignment @@ -338,13 +340,13 @@ ASM_PFX(GasketSecPeCoffRelocateImageExtraAction): movl 8(%ebp), %eax movl %eax, (%esp) - call ASM_PFX(SecPeCoffRelocateImageExtraAction) + call ASM_PFX(SecUefiImageRelocateImageExtraAction) leave ret -ASM_GLOBAL ASM_PFX(GasketSecPeCoffUnloadImageExtraAction) -ASM_PFX(GasketSecPeCoffUnloadImageExtraAction): +ASM_GLOBAL ASM_PFX(GasketSecUefiImageUnloadImageExtraAction) +ASM_PFX(GasketSecUefiImageUnloadImageExtraAction): pushl %ebp movl %esp, %ebp subl $24, %esp // sub extra 16 from the stack for alignment @@ -352,7 +354,7 @@ ASM_PFX(GasketSecPeCoffUnloadImageExtraAction): movl 8(%ebp), %eax movl %eax, (%esp) - call ASM_PFX(SecPeCoffUnloadImageExtraAction) + call ASM_PFX(SecUefiImageUnloadImageExtraAction) leave ret diff --git a/EmulatorPkg/Unix/Host/X64/Gasket.S b/EmulatorPkg/Unix/Host/X64/Gasket.S index 030faa8e4c..006faa95d0 100644 --- a/EmulatorPkg/Unix/Host/X64/Gasket.S +++ b/EmulatorPkg/Unix/Host/X64/Gasket.S @@ -358,8 +358,8 @@ ASM_PFX(GasketSecGetNextProtocol): // PPIs produced by SEC -ASM_GLOBAL ASM_PFX(GasketSecPeCoffGetEntryPoint) -ASM_PFX(GasketSecPeCoffGetEntryPoint): +ASM_GLOBAL ASM_PFX(GasketSecUefiImageGetEntryPoint) +ASM_PFX(GasketSecUefiImageGetEntryPoint): pushq %rbp // stack frame is for the debugger movq %rsp, %rbp @@ -368,16 +368,17 @@ ASM_PFX(GasketSecPeCoffGetEntryPoint): movq %rcx, %rdi // Swizzle args movq %rdx, %rsi + movq %r8, %rdx - call ASM_PFX(SecPeCoffGetEntryPoint) + call ASM_PFX(SecUefiImageGetEntryPoint) popq %rdi // restore state popq %rsi popq %rbp ret -ASM_GLOBAL ASM_PFX(GasketSecPeCoffRelocateImageExtraAction) -ASM_PFX(GasketSecPeCoffRelocateImageExtraAction): +ASM_GLOBAL ASM_PFX(GasketSecUefiImageRelocateImageExtraAction) +ASM_PFX(GasketSecUefiImageRelocateImageExtraAction): pushq %rbp // stack frame is for the debugger movq %rsp, %rbp @@ -386,15 +387,15 @@ ASM_PFX(GasketSecPeCoffRelocateImageExtraAction): movq %rcx, %rdi // Swizzle args - call ASM_PFX(SecPeCoffRelocateImageExtraAction) + call ASM_PFX(SecUefiImageRelocateImageExtraAction) popq %rdi // restore state popq %rsi popq %rbp ret -ASM_GLOBAL ASM_PFX(GasketSecPeCoffUnloadImageExtraAction) -ASM_PFX(GasketSecPeCoffUnloadImageExtraAction): +ASM_GLOBAL ASM_PFX(GasketSecUefiImageUnloadImageExtraAction) +ASM_PFX(GasketSecUefiImageUnloadImageExtraAction): pushq %rbp // stack frame is for the debugger movq %rsp, %rbp @@ -403,7 +404,7 @@ ASM_PFX(GasketSecPeCoffUnloadImageExtraAction): movq %rcx, %rdi // Swizzle args - call ASM_PFX(SecPeCoffUnloadImageExtraAction) + call ASM_PFX(SecUefiImageUnloadImageExtraAction) popq %rdi // restore state popq %rsi diff --git a/EmulatorPkg/Unix/lldbefi.py b/EmulatorPkg/Unix/lldbefi.py old mode 100755 new mode 100644 index 952f8bf982..85be276d10 --- a/EmulatorPkg/Unix/lldbefi.py +++ b/EmulatorPkg/Unix/lldbefi.py @@ -361,7 +361,7 @@ def LoadEmulatorEfiSymbols(frame, bp_loc , internal_dict): # # VOID # SecGdbScriptBreak ( - # char *FileName, + # const char *FileName, # int FileNameLength, # long unsigned int LoadAddress, # int AddSymbolFlag @@ -394,7 +394,7 @@ def LoadEmulatorEfiSymbols(frame, bp_loc , internal_dict): debugger = frame.thread.process.target.debugger if frame.FindVariable ("AddSymbolFlag").GetValueAsUnsigned() == 1: - LoadAddress = frame.FindVariable ("LoadAddress").GetValueAsUnsigned() - 0x240 + LoadAddress = frame.FindVariable ("LoadAddress").GetValueAsUnsigned() debugger.HandleCommand ("target modules add %s" % FileName) print("target modules load --slid 0x%x %s" % (LoadAddress, FileName)) diff --git a/EmulatorPkg/Win/Host/WinHost.c b/EmulatorPkg/Win/Host/WinHost.c index 193a947fbd..80d44a94ab 100644 --- a/EmulatorPkg/Win/Host/WinHost.c +++ b/EmulatorPkg/Win/Host/WinHost.c @@ -444,6 +444,7 @@ Routine Description: BOOLEAN Done; EFI_PEI_FILE_HANDLE FileHandle; VOID *SecFile; + UINT32 SecFileSize; CHAR16 *MemorySizeStr; CHAR16 *FirmwareVolumesStr; UINTN ProcessAffinityMask; @@ -451,6 +452,7 @@ Routine Description: INT32 LowBit; UINTN ResetJumpCode; EMU_THUNK_PPI *SecEmuThunkPpi; + UINT32 AuthenticationStatus; // // Enable the privilege so that RTC driver can successfully run SetTime() @@ -648,7 +650,14 @@ Routine Description: &FileHandle ); if (!EFI_ERROR (Status)) { - Status = PeiServicesFfsFindSectionData (EFI_SECTION_PE32, FileHandle, &SecFile); + Status = PeiServicesFfsFindSectionData4 ( + EFI_SECTION_PE32, + 0, + FileHandle, + &SecFile, + &SecFileSize, + &AuthenticationStatus + ); if (!EFI_ERROR (Status)) { SecPrint (" contains SEC Core"); } @@ -679,7 +688,7 @@ Routine Description: // // Hand off to SEC Core // - SecLoadSecCore ((UINTN)TemporaryRam, TemporaryRamSize, gFdInfo[0].Address, gFdInfo[0].Size, SecFile); + SecLoadSecCore ((UINTN)TemporaryRam, TemporaryRamSize, gFdInfo[0].Address, gFdInfo[0].Size, SecFile, SecFileSize); // // If we get here, then the SEC Core returned. This is an error as SEC should @@ -695,7 +704,8 @@ SecLoadSecCore ( IN UINTN TemporaryRamSize, IN VOID *BootFirmwareVolumeBase, IN UINTN BootFirmwareVolumeSize, - IN VOID *SecCorePe32File + IN VOID *SecCorePe32File, + IN UINT32 SecCorePe32Size ) /*++ @@ -759,8 +769,9 @@ Routine Description: // // Load the PEI Core from a Firmware Volume // - Status = SecPeCoffGetEntryPoint ( + Status = SecUefiImageGetEntryPoint ( SecCorePe32File, + SecCorePe32Size, &SecCoreEntryPoint ); if (EFI_ERROR (Status)) { @@ -784,40 +795,47 @@ Routine Description: RETURN_STATUS EFIAPI -SecPeCoffGetEntryPoint ( - IN VOID *Pe32Data, - IN OUT VOID **EntryPoint +SecUefiImageGetEntryPoint ( + IN VOID *Pe32Data, + IN UINT32 Pe32Size, + IN OUT VOID **EntryPoint ) { - EFI_STATUS Status; - PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; + EFI_STATUS Status; + UEFI_IMAGE_LOADER_IMAGE_CONTEXT ImageContext; + VOID *Dest; + UINT32 DestSize; - ZeroMem (&ImageContext, sizeof (ImageContext)); - ImageContext.Handle = Pe32Data; - - ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE)SecImageRead; - - Status = PeCoffLoaderGetImageInfo (&ImageContext); + Status = UefiImageInitializeContext (&ImageContext, Pe32Data, Pe32Size); if (EFI_ERROR (Status)) { return Status; } // - // XIP for SEC and PEI_CORE + // Allocate space in NT (not emulator) memory with ReadWrite and Execute attribute. + // Extra space is for alignment // - ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)Pe32Data; + Status = UefiImageLoaderGetDestinationSize(&ImageContext, &DestSize); + if (EFI_ERROR (Status)) { + return Status; + } + + Dest = VirtualAlloc (NULL, (SIZE_T) DestSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE); + if (Dest == NULL) { + return EFI_OUT_OF_RESOURCES; + } - Status = PeCoffLoaderLoadImage (&ImageContext); + Status = UefiImageLoadImage (&ImageContext, Dest, DestSize); if (EFI_ERROR (Status)) { return Status; } - Status = PeCoffLoaderRelocateImage (&ImageContext); + Status = UefiImageRelocateImage (&ImageContext, (UINTN) Dest, NULL, 0); if (EFI_ERROR (Status)) { return Status; } - *EntryPoint = (VOID *)(UINTN)ImageContext.EntryPoint; + *EntryPoint = (VOID *) (UefiImageLoaderGetImageEntryPoint (&ImageContext)); return EFI_SUCCESS; } @@ -951,7 +969,7 @@ Routine Description: --*/ EFI_STATUS AddModHandle ( - IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext, + IN UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext, IN VOID *ModHandle ) @@ -1028,7 +1046,7 @@ AddModHandle ( **/ VOID * RemoveModHandle ( - IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext + IN UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext ) { UINTN Index; @@ -1058,8 +1076,8 @@ RemoveModHandle ( VOID EFIAPI -PeCoffLoaderRelocateImageExtraAction ( - IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext +UefiImageLoaderRelocateImageExtraAction ( + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext ) { EFI_STATUS Status; @@ -1084,7 +1102,7 @@ PeCoffLoaderRelocateImageExtraAction ( // Load the DLL if it's not an EBC image. // if ((ImageContext->PdbPointer != NULL) && - (ImageContext->Machine != EFI_IMAGE_MACHINE_EBC)) + (UefiImageGetMachine (ImageContext) != EFI_IMAGE_MACHINE_EBC)) { // // Convert filename from ASCII to Unicode @@ -1098,7 +1116,7 @@ PeCoffLoaderRelocateImageExtraAction ( free (DllFileName); // - // Never return an error if PeCoffLoaderRelocateImage() succeeded. + // Never return an error if UefiImageRelocateImage() succeeded. // The image will run, but we just can't source level debug. If we // return an error the image will not run. // @@ -1126,6 +1144,7 @@ PeCoffLoaderRelocateImageExtraAction ( // checking as the we can point to the PE32 image loaded by Tiano. This // step is only needed for source level debugging // + // FIXME: Fix ImageBase too DllEntryPoint = (VOID *)(UINTN)GetProcAddress (Library, "InitializeDriver"); } @@ -1154,8 +1173,8 @@ PeCoffLoaderRelocateImageExtraAction ( VOID EFIAPI -PeCoffLoaderUnloadImageExtraAction ( - IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext +UefiImageLoaderUnloadImageExtraAction ( + IN UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext ) { VOID *ModHandle; diff --git a/EmulatorPkg/Win/Host/WinHost.h b/EmulatorPkg/Win/Host/WinHost.h index a9a21007e3..bad2fca5ce 100644 --- a/EmulatorPkg/Win/Host/WinHost.h +++ b/EmulatorPkg/Win/Host/WinHost.h @@ -21,7 +21,7 @@ Module Name: #include "WinInclude.h" #include -#include +#include #include #include #include @@ -35,7 +35,7 @@ Module Name: #include #include -#include +#include #include #include #include @@ -44,7 +44,7 @@ Module Name: #include #include #include -#include +#include #include #define TEMPORARY_RAM_SIZE 0x20000 @@ -61,8 +61,9 @@ typedef struct { RETURN_STATUS EFIAPI -SecPeCoffGetEntryPoint ( +SecUefiImageGetEntryPoint ( IN VOID *Pe32Data, + IN UINT32 Pe32Size, IN OUT VOID **EntryPoint ); @@ -72,7 +73,8 @@ SecLoadSecCore ( IN UINTN TemporaryRamSize, IN VOID *BootFirmwareVolumeBase, IN UINTN BootFirmwareVolumeSize, - IN VOID *SecCorePe32File + IN VOID *SecCorePe32File, + IN UINT32 SecCorePe32Size ) /*++ diff --git a/EmulatorPkg/Win/Host/WinHost.inf b/EmulatorPkg/Win/Host/WinHost.inf index 4dac6e033e..7866a58c7e 100644 --- a/EmulatorPkg/Win/Host/WinHost.inf +++ b/EmulatorPkg/Win/Host/WinHost.inf @@ -49,7 +49,7 @@ PrintLib BaseMemoryLib BaseLib - PeCoffLib + UefiImageLib ThunkPpiList ThunkProtocolList PpiListLib diff --git a/EmulatorPkg/Win/Host/WinThunk.c b/EmulatorPkg/Win/Host/WinThunk.c index 0abe4727e0..a5339a8bd5 100644 --- a/EmulatorPkg/Win/Host/WinThunk.c +++ b/EmulatorPkg/Win/Host/WinThunk.c @@ -581,9 +581,9 @@ EMU_THUNK_PROTOCOL gEmuThunkProtocol = { SecAlloc, NULL, SecFree, - SecPeCoffGetEntryPoint, - PeCoffLoaderRelocateImageExtraAction, - PeCoffLoaderUnloadImageExtraAction, + SecUefiImageGetEntryPoint, + UefiImageLoaderRelocateImageExtraAction, + UefiImageLoaderUnloadImageExtraAction, SecEnableInterrupt, SecDisableInterrupt, SecQueryPerformanceFrequency, diff --git a/IntelFsp2Pkg/Tools/Tests/QemuFspPkg.dsc b/IntelFsp2Pkg/Tools/Tests/QemuFspPkg.dsc index 3155812118..4fbaf8efd0 100644 --- a/IntelFsp2Pkg/Tools/Tests/QemuFspPkg.dsc +++ b/IntelFsp2Pkg/Tools/Tests/QemuFspPkg.dsc @@ -90,11 +90,11 @@ PeiServicesTablePointerLib|MdePkg/Library/PeiServicesTablePointerLibIdt/PeiServicesTablePointerLibIdt.inf PeiServicesLib|MdePkg/Library/PeiServicesLib/PeiServicesLib.inf MemoryAllocationLib|MdePkg/Library/PeiMemoryAllocationLib/PeiMemoryAllocationLib.inf - PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf ReportStatusCodeLib|MdeModulePkg/Library/PeiReportStatusCodeLib/PeiReportStatusCodeLib.inf CacheMaintenanceLib|MdePkg/Library/BaseCacheMaintenanceLib/BaseCacheMaintenanceLib.inf - PeCoffLib|MdePkg/Library/BasePeCoffLib/BasePeCoffLib.inf - PeCoffExtraActionLib|MdePkg/Library/BasePeCoffExtraActionLibNull/BasePeCoffExtraActionLibNull.inf + PeCoffLib2|MdePkg/Library/BasePeCoffLib2/BasePeCoffLib2.inf + UefiImageLib|MdePkg/Library/BaseUefiImageLib/BaseUefiImageLibPeCoff.inf + UefiImageExtraActionLib|MdePkg/Library/BaseUefiImageExtraActionLibNull/BaseUefiImageExtraActionLibNull.inf UefiDecompressLib|MdePkg/Library/BaseUefiDecompressLib/BaseUefiDecompressLib.inf SynchronizationLib|MdePkg/Library/BaseSynchronizationLib/BaseSynchronizationLib.inf CpuLib|MdePkg/Library/BaseCpuLib/BaseCpuLib.inf diff --git a/IntelFsp2WrapperPkg/FspWrapperNotifyDxe/FspWrapperNotifyDxe.inf b/IntelFsp2WrapperPkg/FspWrapperNotifyDxe/FspWrapperNotifyDxe.inf index 4e8b618513..37db0a5a21 100644 --- a/IntelFsp2WrapperPkg/FspWrapperNotifyDxe/FspWrapperNotifyDxe.inf +++ b/IntelFsp2WrapperPkg/FspWrapperNotifyDxe/FspWrapperNotifyDxe.inf @@ -39,12 +39,13 @@ BaseMemoryLib UefiLib FspWrapperApiLib - PeCoffLib + UefiImageLib CacheMaintenanceLib DxeServicesLib PerformanceLib HobLib FspWrapperPlatformLib + MemoryAllocationLib [Protocols] gEfiPciEnumerationCompleteProtocolGuid ## CONSUMES diff --git a/IntelFsp2WrapperPkg/FspWrapperNotifyDxe/LoadBelow4G.c b/IntelFsp2WrapperPkg/FspWrapperNotifyDxe/LoadBelow4G.c index 97723aad65..1a1d052b4d 100644 --- a/IntelFsp2WrapperPkg/FspWrapperNotifyDxe/LoadBelow4G.c +++ b/IntelFsp2WrapperPkg/FspWrapperNotifyDxe/LoadBelow4G.c @@ -11,11 +11,13 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #include #include #include -#include +#include #include #include #include #include +#include +#include /** Relocate this image under 4G memory. @@ -37,9 +39,11 @@ RelocateImageUnder4GIfNeeded ( UINT8 *Buffer; UINTN BufferSize; EFI_HANDLE NewImageHandle; + UINT32 ImageSize; + UINT32 ImageAlignment; UINTN Pages; EFI_PHYSICAL_ADDRESS FfsBuffer; - PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; + UEFI_IMAGE_LOADER_IMAGE_CONTEXT ImageContext; VOID *Interface; // @@ -83,43 +87,34 @@ RelocateImageUnder4GIfNeeded ( &BufferSize ); ASSERT_EFI_ERROR (Status); - ImageContext.Handle = Buffer; - ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory; // // Get information about the image being loaded // - Status = PeCoffLoaderGetImageInfo (&ImageContext); + Status = UefiImageInitializeContext (&ImageContext, Buffer, (UINT32) BufferSize); ASSERT_EFI_ERROR (Status); - if (ImageContext.SectionAlignment > EFI_PAGE_SIZE) { - Pages = EFI_SIZE_TO_PAGES ((UINTN)(ImageContext.ImageSize + ImageContext.SectionAlignment)); - } else { - Pages = EFI_SIZE_TO_PAGES ((UINTN)ImageContext.ImageSize); - } + ImageSize = UefiImageGetImageSize (&ImageContext); + ImageAlignment = UefiImageGetSegmentAlignment (&ImageContext); + Pages = EFI_SIZE_TO_PAGES (ImageSize); FfsBuffer = 0xFFFFFFFF; - Status = gBS->AllocatePages ( - AllocateMaxAddress, - EfiBootServicesCode, - Pages, - &FfsBuffer - ); + Status = AllocateAlignedPagesEx ( + AllocateMaxAddress, + EfiBootServicesCode, + Pages, + ImageAlignment, + &FfsBuffer + ); ASSERT_EFI_ERROR (Status); - ImageContext.ImageAddress = (PHYSICAL_ADDRESS)(UINTN)FfsBuffer; - // - // Align buffer on section boundary - // - ImageContext.ImageAddress += ImageContext.SectionAlignment - 1; - ImageContext.ImageAddress &= ~((EFI_PHYSICAL_ADDRESS)ImageContext.SectionAlignment - 1); // - // Load the image to our new buffer - // - Status = PeCoffLoaderLoadImage (&ImageContext); - ASSERT_EFI_ERROR (Status); - + // Load and relocate the image to our new buffer // - // Relocate the image in our new buffer - // - Status = PeCoffLoaderRelocateImage (&ImageContext); + Status = UefiImageLoadImageForExecution ( + &ImageContext, + (VOID *) (UINTN) FfsBuffer, + ImageSize, + NULL, + 0 + ); ASSERT_EFI_ERROR (Status); // @@ -127,16 +122,11 @@ RelocateImageUnder4GIfNeeded ( // gBS->FreePool (Buffer); - // - // Flush the instruction cache so the image data is written before we execute it - // - InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize); - - DEBUG ((DEBUG_INFO, "Loading driver at 0x%08x EntryPoint=0x%08x\n", (UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.EntryPoint)); - Status = ((EFI_IMAGE_ENTRY_POINT)(UINTN)(ImageContext.EntryPoint))(NewImageHandle, gST); + DEBUG ((DEBUG_INFO, "Loading driver at 0x%08llx EntryPoint=0x%08x\n", FfsBuffer, UefiImageLoaderGetImageEntryPoint (&ImageContext))); + Status = ((EFI_IMAGE_ENTRY_POINT)(UefiImageLoaderGetImageEntryPoint (&ImageContext)))(NewImageHandle, gST); if (EFI_ERROR (Status)) { - DEBUG ((DEBUG_ERROR, "Error: Image at 0x%08x start failed: %r\n", ImageContext.ImageAddress, Status)); - gBS->FreePages (FfsBuffer, Pages); + DEBUG ((DEBUG_ERROR, "Error: Image at 0x%08llx start failed: %r\n", FfsBuffer, Status)); + FreeAlignedPages ((VOID *)(UINTN)FfsBuffer, Pages); } // diff --git a/IntelFsp2WrapperPkg/FspmWrapperPeim/FspmWrapperPeim.inf b/IntelFsp2WrapperPkg/FspmWrapperPeim/FspmWrapperPeim.inf index 0307ce0acc..3176883303 100644 --- a/IntelFsp2WrapperPkg/FspmWrapperPeim/FspmWrapperPeim.inf +++ b/IntelFsp2WrapperPkg/FspmWrapperPeim/FspmWrapperPeim.inf @@ -38,8 +38,8 @@ FspWrapperPlatformLib FspWrapperHobProcessLib CpuLib - PeCoffGetEntryPointLib - PeCoffExtraActionLib + UefiCpuLib + UefiImageExtraActionLib PerformanceLib TimerLib FspWrapperApiLib diff --git a/IntelFsp2WrapperPkg/FspsWrapperPeim/FspsWrapperPeim.inf b/IntelFsp2WrapperPkg/FspsWrapperPeim/FspsWrapperPeim.inf index a7b28e56b5..bc5be2f4cc 100644 --- a/IntelFsp2WrapperPkg/FspsWrapperPeim/FspsWrapperPeim.inf +++ b/IntelFsp2WrapperPkg/FspsWrapperPeim/FspsWrapperPeim.inf @@ -39,8 +39,8 @@ FspWrapperPlatformLib FspWrapperHobProcessLib CpuLib - PeCoffGetEntryPointLib - PeCoffExtraActionLib + UefiCpuLib + UefiImageExtraActionLib PerformanceLib FspWrapperApiLib FspWrapperApiTestLib diff --git a/IntelFsp2WrapperPkg/IntelFsp2WrapperPkg.dsc b/IntelFsp2WrapperPkg/IntelFsp2WrapperPkg.dsc index fe621244a6..04dcd2502c 100644 --- a/IntelFsp2WrapperPkg/IntelFsp2WrapperPkg.dsc +++ b/IntelFsp2WrapperPkg/IntelFsp2WrapperPkg.dsc @@ -27,9 +27,9 @@ DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf PciCf8Lib|MdePkg/Library/BasePciCf8Lib/BasePciCf8Lib.inf IoLib|MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf - PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf - PeCoffExtraActionLib|MdePkg/Library/BasePeCoffExtraActionLibNull/BasePeCoffExtraActionLibNull.inf - PeCoffLib|MdePkg/Library/BasePeCoffLib/BasePeCoffLib.inf + UefiImageExtraActionLib|MdePkg/Library/BaseUefiImageExtraActionLibNull/BaseUefiImageExtraActionLibNull.inf + PeCoffLib2|MdePkg/Library/BasePeCoffLib2/BasePeCoffLib2.inf + UefiImageLib|MdePkg/Library/BaseUefiImageLib/BaseUefiImageLibPeCoff.inf CacheMaintenanceLib|MdePkg/Library/BaseCacheMaintenanceLib/BaseCacheMaintenanceLib.inf PerformanceLib|MdePkg/Library/BasePerformanceLibNull/BasePerformanceLibNull.inf diff --git a/LoaderFlow.png b/LoaderFlow.png new file mode 100644 index 0000000000000000000000000000000000000000..323e1b9aa36ef596509a07b2665d0d7d0c9ba110 GIT binary patch literal 218450 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 literal 0 HcmV?d00001 diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.h b/MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.h index ca5c06204d..e37d34c16d 100644 --- a/MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.h +++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciBus.h @@ -40,7 +40,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #include #include -#include +#include #include typedef struct _PCI_IO_DEVICE PCI_IO_DEVICE; diff --git a/MdeModulePkg/Core/Dxe/DxeMain.h b/MdeModulePkg/Core/Dxe/DxeMain.h index 53e26703f8..aba7b6a03a 100644 --- a/MdeModulePkg/Core/Dxe/DxeMain.h +++ b/MdeModulePkg/Core/Dxe/DxeMain.h @@ -73,11 +73,11 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #include #include #include -#include -#include -#include +#include +#include #include #include +#include #include #include #include @@ -219,10 +219,10 @@ typedef struct { EFI_RUNTIME_IMAGE_ENTRY *RuntimeData; /// Pointer to Loaded Image Device Path Protocol EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath; - /// PeCoffLoader ImageContext - PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; /// Status returned by LoadImage() service. EFI_STATUS LoadImageStatus; + + VOID *HiiData; } LOADED_IMAGE_PRIVATE_DATA; #define LOADED_IMAGE_PRIVATE_DATA_FROM_THIS(a) \ @@ -389,7 +389,8 @@ CoreInitializeEventServices ( **/ EFI_STATUS CoreInitializeImageServices ( - IN VOID *HobStart + IN VOID *HobStart, + OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext ); /** @@ -2384,7 +2385,8 @@ VOID CoreNewDebugImageInfoEntry ( IN UINT32 ImageInfoType, IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage, - IN EFI_HANDLE ImageHandle + IN EFI_HANDLE ImageHandle, + IN UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext ); /** @@ -2573,7 +2575,8 @@ VerifyFvHeaderChecksum ( **/ VOID MemoryProfileInit ( - IN VOID *HobStart + IN VOID *HobStart, + IN UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext ); /** @@ -2599,8 +2602,9 @@ MemoryProfileInstallProtocol ( **/ EFI_STATUS RegisterMemoryProfileImage ( - IN LOADED_IMAGE_PRIVATE_DATA *DriverEntry, - IN EFI_FV_FILETYPE FileType + IN EFI_DEVICE_PATH_PROTOCOL *FilePath, + IN EFI_FV_FILETYPE FileType, + IN UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext ); /** @@ -2616,7 +2620,8 @@ RegisterMemoryProfileImage ( **/ EFI_STATUS UnregisterMemoryProfileImage ( - IN LOADED_IMAGE_PRIVATE_DATA *DriverEntry + EFI_DEVICE_PATH_PROTOCOL *FilePath, + IN EFI_PHYSICAL_ADDRESS ImageAddress ); /** @@ -2703,7 +2708,8 @@ InstallMemoryAttributesTableOnMemoryAllocation ( **/ VOID InsertImageRecord ( - IN EFI_RUNTIME_IMAGE_ENTRY *RuntimeImage + IN LOADED_IMAGE_PRIVATE_DATA *Image, + IN UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext ); /** @@ -2724,8 +2730,8 @@ RemoveImageRecord ( **/ VOID ProtectUefiImage ( - IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage, - IN EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath + IN LOADED_IMAGE_PRIVATE_DATA *Image, + UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext ); /** diff --git a/MdeModulePkg/Core/Dxe/DxeMain.inf b/MdeModulePkg/Core/Dxe/DxeMain.inf index 090970aec6..5f38eb597b 100644 --- a/MdeModulePkg/Core/Dxe/DxeMain.inf +++ b/MdeModulePkg/Core/Dxe/DxeMain.inf @@ -82,9 +82,8 @@ UefiLib DebugLib DxeCoreEntryPoint - PeCoffLib - PeCoffGetEntryPointLib - PeCoffExtraActionLib + UefiImageLib + UefiImageExtraActionLib ExtractGuidedSectionLib MemoryAllocationLib UefiBootServicesTableLib diff --git a/MdeModulePkg/Core/Dxe/DxeMain/DxeMain.c b/MdeModulePkg/Core/Dxe/DxeMain/DxeMain.c index 17d510a287..a24dd8e6a5 100644 --- a/MdeModulePkg/Core/Dxe/DxeMain/DxeMain.c +++ b/MdeModulePkg/Core/Dxe/DxeMain/DxeMain.c @@ -234,15 +234,14 @@ DxeMain ( IN VOID *HobStart ) { - EFI_STATUS Status; - EFI_PHYSICAL_ADDRESS MemoryBaseAddress; - UINT64 MemoryLength; - PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; - UINTN Index; - EFI_HOB_GUID_TYPE *GuidHob; - EFI_VECTOR_HANDOFF_INFO *VectorInfoList; - EFI_VECTOR_HANDOFF_INFO *VectorInfo; - VOID *EntryPoint; + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS MemoryBaseAddress; + UINT64 MemoryLength; + UEFI_IMAGE_LOADER_IMAGE_CONTEXT ImageContext; + UINTN Index; + EFI_HOB_GUID_TYPE *GuidHob; + EFI_VECTOR_HANDOFF_INFO *VectorInfoList; + EFI_VECTOR_HANDOFF_INFO *VectorInfo; // // Setup the default exception handlers @@ -274,14 +273,14 @@ DxeMain ( // CoreInitializeMemoryServices (&HobStart, &MemoryBaseAddress, &MemoryLength); - MemoryProfileInit (HobStart); - // // Start the Image Services. // - Status = CoreInitializeImageServices (HobStart); + Status = CoreInitializeImageServices (HobStart, &ImageContext); ASSERT_EFI_ERROR (Status); + MemoryProfileInit (HobStart, &ImageContext); + // // Initialize the Global Coherency Domain Services // @@ -327,19 +326,9 @@ DxeMain ( // // Report DXE Core image information to the PE/COFF Extra Action Library + // FIXME: This is done by DxeIpl, why is this needed here? Difference PEI/DXE? // - ZeroMem (&ImageContext, sizeof (ImageContext)); - ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)gDxeCoreLoadedImage->ImageBase; - ImageContext.PdbPointer = PeCoffLoaderGetPdbPointer ((VOID *)(UINTN)ImageContext.ImageAddress); - ImageContext.SizeOfHeaders = PeCoffGetSizeOfHeaders ((VOID *)(UINTN)ImageContext.ImageAddress); - Status = PeCoffLoaderGetEntryPoint ((VOID *)(UINTN)ImageContext.ImageAddress, &EntryPoint); - if (Status == EFI_SUCCESS) { - ImageContext.EntryPoint = (EFI_PHYSICAL_ADDRESS)(UINTN)EntryPoint; - } - - ImageContext.Handle = (VOID *)(UINTN)gDxeCoreLoadedImage->ImageBase; - ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory; - PeCoffLoaderRelocateImageExtraAction (&ImageContext); + UefiImageLoaderRelocateImageExtraAction (&ImageContext); // // Install the DXE Services Table into the EFI System Tables's Configuration Table @@ -386,7 +375,8 @@ DxeMain ( CoreNewDebugImageInfoEntry ( EFI_DEBUG_IMAGE_INFO_TYPE_NORMAL, gDxeCoreLoadedImage, - gDxeCoreImageHandle + gDxeCoreImageHandle, + &ImageContext ); DEBUG ((DEBUG_INFO | DEBUG_LOAD, "HOBLIST address in DXE = 0x%p\n", HobStart)); diff --git a/MdeModulePkg/Core/Dxe/Image/Image.c b/MdeModulePkg/Core/Dxe/Image/Image.c index 37fc74d5d1..1df68e22ec 100644 --- a/MdeModulePkg/Core/Dxe/Image/Image.c +++ b/MdeModulePkg/Core/Dxe/Image/Image.c @@ -86,7 +86,20 @@ GLOBAL_REMOVE_IF_UNREFERENCED MACHINE_TYPE_INFO mMachineTypeInfo[] = { { EFI_IMAGE_MACHINE_LOONGARCH64, L"LOONGARCH64" }, }; -UINT16 mDxeCoreImageMachineType = 0; +// FIXME: RISC-V, IA64 +#if defined (MDE_CPU_IA32) + CONST CHAR16 *mDxeCoreImageMachineTypeName = L"IA32"; +#elif defined (MDE_CPU_IPF) + CONST CHAR16 *mDxeCoreImageMachineTypeName = L"IA64"; +#elif defined (MDE_CPU_X64) + CONST CHAR16 *mDxeCoreImageMachineTypeName = L"X64"; +#elif defined (MDE_CPU_ARM) + CONST CHAR16 *mDxeCoreImageMachineTypeName = L"ARM"; +#elif defined (MDE_CPU_AARCH64) + CONST CHAR16 *mDxeCoreImageMachineTypeName = L"AARCH64"; +#else + #error Unkown CPU architecture +#endif /** Return machine type name. @@ -102,7 +115,7 @@ GetMachineTypeName ( { UINTN Index; - for (Index = 0; Index < sizeof (mMachineTypeInfo)/sizeof (mMachineTypeInfo[0]); Index++) { + for (Index = 0; Index < sizeof (mMachineTypeInfo)/sizeof (mMachineTypeInfo[0]); ++Index) { if (mMachineTypeInfo[Index].MachineType == MachineType) { return mMachineTypeInfo[Index].MachineTypeName; } @@ -182,7 +195,8 @@ PeCoffEmuProtocolNotify ( **/ EFI_STATUS CoreInitializeImageServices ( - IN VOID *HobStart + IN VOID *HobStart, + OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext ) { EFI_STATUS Status; @@ -219,6 +233,18 @@ CoreInitializeImageServices ( // Image = &mCorePrivateImage; + Status = UefiImageInitializeContext ( + ImageContext, + (VOID *) (UINTN) DxeCoreImageBaseAddress, + (UINT32) DxeCoreImageLength + ); + ASSERT_EFI_ERROR (Status); + + // FIXME: DxeCore is dynamically loaded by DxeIpl, can't it pass the context? + ImageContext->ImageBuffer = (VOID *) ImageContext->FileBuffer; + + ASSERT ((UINTN) DxeCoreEntryPoint == UefiImageLoaderGetImageEntryPoint (ImageContext)); + Image->EntryPoint = (EFI_IMAGE_ENTRY_POINT)(UINTN)DxeCoreEntryPoint; Image->ImageBasePage = DxeCoreImageBaseAddress; Image->NumberOfPages = (UINTN)(EFI_SIZE_TO_PAGES ((UINTN)(DxeCoreImageLength))); @@ -242,9 +268,8 @@ CoreInitializeImageServices ( // // Fill in DXE globals // - mDxeCoreImageMachineType = PeCoffLoaderGetMachineType (Image->Info.ImageBase); - gDxeCoreImageHandle = Image->Handle; - gDxeCoreLoadedImage = &Image->Info; + gDxeCoreImageHandle = Image->Handle; + gDxeCoreLoadedImage = &Image->Info; // // Create the PE/COFF emulator protocol registration event @@ -270,64 +295,11 @@ CoreInitializeImageServices ( InitializeListHead (&mAvailableEmulators); - ProtectUefiImage (&Image->Info, Image->LoadedImageDevicePath); + ProtectUefiImage (Image, ImageContext); return Status; } -/** - Read image file (specified by UserHandle) into user specified buffer with specified offset - and length. - - @param UserHandle Image file handle - @param Offset Offset to the source file - @param ReadSize For input, pointer of size to read; For output, - pointer of size actually read. - @param Buffer Buffer to write into - - @retval EFI_SUCCESS Successfully read the specified part of file - into buffer. - -**/ -EFI_STATUS -EFIAPI -CoreReadImageFile ( - IN VOID *UserHandle, - IN UINTN Offset, - IN OUT UINTN *ReadSize, - OUT VOID *Buffer - ) -{ - UINTN EndPosition; - IMAGE_FILE_HANDLE *FHand; - - if ((UserHandle == NULL) || (ReadSize == NULL) || (Buffer == NULL)) { - return EFI_INVALID_PARAMETER; - } - - if (MAX_ADDRESS - Offset < *ReadSize) { - return EFI_INVALID_PARAMETER; - } - - FHand = (IMAGE_FILE_HANDLE *)UserHandle; - ASSERT (FHand->Signature == IMAGE_FILE_HANDLE_SIGNATURE); - - // - // Move data from our local copy of the file - // - EndPosition = Offset + *ReadSize; - if (EndPosition > FHand->SourceSize) { - *ReadSize = (UINT32)(FHand->SourceSize - Offset); - } - - if (Offset >= FHand->SourceSize) { - *ReadSize = 0; - } - - CopyMem (Buffer, (CHAR8 *)FHand->Source + Offset, *ReadSize); - return EFI_SUCCESS; -} - /** To check memory usage bit map array to figure out if the memory range the image will be loaded in is available or not. If memory range is available, the function will mark the corresponding bits to 1 which indicates the memory range is used. @@ -378,8 +350,8 @@ CheckAndMarkFixLoadingMemoryUsageBitMap ( // // Test the memory range for loading the image in the DXE code range. // - if ((gLoadModuleAtFixAddressConfigurationTable.DxeCodeTopAddress < ImageBase + ImageSize) || - (DxeCodeBase > ImageBase)) + if ((gLoadModuleAtFixAddressConfigurationTable.DxeCodeTopAddress < ImageBase + ImageSize) || + (DxeCodeBase > ImageBase)) { return EFI_NOT_FOUND; } @@ -389,7 +361,7 @@ CheckAndMarkFixLoadingMemoryUsageBitMap ( // BaseOffsetPageNumber = EFI_SIZE_TO_PAGES ((UINT32)(ImageBase - DxeCodeBase)); TopOffsetPageNumber = EFI_SIZE_TO_PAGES ((UINT32)(ImageBase + ImageSize - DxeCodeBase)); - for (Index = BaseOffsetPageNumber; Index < TopOffsetPageNumber; Index++) { + for (Index = BaseOffsetPageNumber; Index < TopOffsetPageNumber; ++Index) { if ((mDxeCodeMemoryRangeUsageBitMap[Index / 64] & LShiftU64 (1, (Index % 64))) != 0) { // // This page is already used. @@ -401,7 +373,7 @@ CheckAndMarkFixLoadingMemoryUsageBitMap ( // // Being here means the memory range is available. So mark the bits for the memory range // - for (Index = BaseOffsetPageNumber; Index < TopOffsetPageNumber; Index++) { + for (Index = BaseOffsetPageNumber; Index < TopOffsetPageNumber; ++Index) { mDxeCodeMemoryRangeUsageBitMap[Index / 64] |= LShiftU64 (1, (Index % 64)); } @@ -420,88 +392,35 @@ CheckAndMarkFixLoadingMemoryUsageBitMap ( **/ EFI_STATUS -GetPeCoffImageFixLoadingAssignedAddress ( - IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext +GetUefiImageFixLoadingAssignedAddress ( + OUT EFI_PHYSICAL_ADDRESS *LoadAddress, + IN UINT64 ValueInSectionHeader, + IN UINT32 ImageDestSize ) { - UINTN SectionHeaderOffset; - EFI_STATUS Status; - EFI_IMAGE_SECTION_HEADER SectionHeader; - EFI_IMAGE_OPTIONAL_HEADER_UNION *ImgHdr; - UINT16 Index; - UINTN Size; - UINT16 NumberOfSections; - IMAGE_FILE_HANDLE *Handle; - UINT64 ValueInSectionHeader; + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS FixLoadingAddress; - Status = EFI_NOT_FOUND; - - // - // Get PeHeader pointer - // - Handle = (IMAGE_FILE_HANDLE *)ImageContext->Handle; - ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((CHAR8 *)Handle->Source + ImageContext->PeCoffHeaderOffset); - SectionHeaderOffset = ImageContext->PeCoffHeaderOffset + - sizeof (UINT32) + - sizeof (EFI_IMAGE_FILE_HEADER) + - ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader; - NumberOfSections = ImgHdr->Pe32.FileHeader.NumberOfSections; - - // - // Get base address from the first section header that doesn't point to code section. - // - for (Index = 0; Index < NumberOfSections; Index++) { + if ((INT64)PcdGet64(PcdLoadModuleAtFixAddressEnable) > 0) { // - // Read section header from file + // When LMFA feature is configured as Load Module at Fixed Absolute Address mode, PointerToRelocations & PointerToLineNumbers field + // hold the absolute address of image base running in memory // - Size = sizeof (EFI_IMAGE_SECTION_HEADER); - Status = ImageContext->ImageRead ( - ImageContext->Handle, - SectionHeaderOffset, - &Size, - &SectionHeader - ); - if (EFI_ERROR (Status)) { - return Status; - } - - if (Size != sizeof (EFI_IMAGE_SECTION_HEADER)) { - return EFI_NOT_FOUND; - } - - Status = EFI_NOT_FOUND; - - if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_CNT_CODE) == 0) { - // - // Build tool will save the address in PointerToRelocations & PointerToLineNumbers fields in the first section header - // that doesn't point to code section in image header, as well as ImageBase field of image header. And there is an - // assumption that when the feature is enabled, if a module is assigned a loading address by tools, PointerToRelocations - // & PointerToLineNumbers fields should NOT be Zero, or else, these 2 fields should be set to Zero - // - ValueInSectionHeader = ReadUnaligned64 ((UINT64 *)&SectionHeader.PointerToRelocations); - if (ValueInSectionHeader != 0) { - // - // When the feature is configured as load module at fixed absolute address, the ImageAddress field of ImageContext - // hold the specified address. If the feature is configured as load module at fixed offset, ImageAddress hold an offset - // relative to top address - // - if ((INT64)PcdGet64 (PcdLoadModuleAtFixAddressEnable) < 0) { - ImageContext->ImageAddress = gLoadModuleAtFixAddressConfigurationTable.DxeCodeTopAddress + (INT64)(INTN)ImageContext->ImageAddress; - } - - // - // Check if the memory range is available. - // - Status = CheckAndMarkFixLoadingMemoryUsageBitMap (ImageContext->ImageAddress, (UINTN)(ImageContext->ImageSize + ImageContext->SectionAlignment)); - } - - break; - } - - SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER); + FixLoadingAddress = ValueInSectionHeader; + } else { + // + // When LMFA feature is configured as Load Module at Fixed offset mode, PointerToRelocations & PointerToLineNumbers field + // hold the offset relative to a platform-specific top address. + // + FixLoadingAddress = gLoadModuleAtFixAddressConfigurationTable.DxeCodeTopAddress + ValueInSectionHeader; } + // + // Check if the memory range is available. + // + Status = CheckAndMarkFixLoadingMemoryUsageBitMap (FixLoadingAddress, ImageDestSize); + *LoadAddress = FixLoadingAddress; - DEBUG ((DEBUG_INFO|DEBUG_LOAD, "LOADING MODULE FIXED INFO: Loading module at fixed address 0x%11p. Status = %r \n", (VOID *)(UINTN)(ImageContext->ImageAddress), Status)); + DEBUG ((EFI_D_INFO|EFI_D_LOAD, "LOADING MODULE FIXED INFO: Loading module at fixed address 0x%11p. Status = %r \n", (VOID *)(UINTN)FixLoadingAddress, Status)); return Status; } @@ -520,7 +439,8 @@ GetPeCoffImageFixLoadingAssignedAddress ( STATIC BOOLEAN CoreIsImageTypeSupported ( - IN OUT LOADED_IMAGE_PRIVATE_DATA *Image + IN OUT LOADED_IMAGE_PRIVATE_DATA *Image, + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext ) { LIST_ENTRY *Link; @@ -531,13 +451,13 @@ CoreIsImageTypeSupported ( Link = GetNextNode (&mAvailableEmulators, Link)) { Entry = BASE_CR (Link, EMULATOR_ENTRY, Link); - if (Entry->MachineType != Image->ImageContext.Machine) { + if (Entry->MachineType != UefiImageGetMachine (ImageContext)) { continue; } if (Entry->Emulator->IsImageSupported ( Entry->Emulator, - Image->ImageContext.ImageType, + UefiImageGetSubsystem (ImageContext), Image->Info.FilePath )) { @@ -546,8 +466,8 @@ CoreIsImageTypeSupported ( } } - return EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Image->ImageContext.Machine) || - EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED (Image->ImageContext.Machine); + return EFI_IMAGE_MACHINE_TYPE_SUPPORTED (UefiImageGetMachine (ImageContext)) || + EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED (UefiImageGetMachine (ImageContext)); } /** @@ -557,7 +477,6 @@ CoreIsImageTypeSupported ( from the boot manager, and that the boot manager is attempting to load FilePath as a boot selection. - @param Pe32Handle The handle of PE32 image @param Image PE image to be loaded @param DstBuffer The buffer to store the image @param EntryPoint A pointer to the entry point @@ -573,32 +492,30 @@ CoreIsImageTypeSupported ( **/ EFI_STATUS CoreLoadPeImage ( - IN BOOLEAN BootPolicy, - IN VOID *Pe32Handle, - IN LOADED_IMAGE_PRIVATE_DATA *Image, - IN EFI_PHYSICAL_ADDRESS DstBuffer OPTIONAL, - OUT EFI_PHYSICAL_ADDRESS *EntryPoint OPTIONAL, - IN UINT32 Attribute + IN BOOLEAN BootPolicy, + IN LOADED_IMAGE_PRIVATE_DATA *Image, + IN EFI_PHYSICAL_ADDRESS *DstBuffer OPTIONAL, + OUT EFI_PHYSICAL_ADDRESS *EntryPoint OPTIONAL, + IN UINT32 Attribute, + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext ) { - EFI_STATUS Status; - BOOLEAN DstBufAlocated; - UINTN Size; - - ZeroMem (&Image->ImageContext, sizeof (Image->ImageContext)); - - Image->ImageContext.Handle = Pe32Handle; - Image->ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE)CoreReadImageFile; - - // - // Get information about the image being loaded - // - Status = PeCoffLoaderGetImageInfo (&Image->ImageContext); - if (EFI_ERROR (Status)) { - return Status; - } - - if (!CoreIsImageTypeSupported (Image)) { + EFI_STATUS Status; + BOOLEAN DstBufAlocated; + UINT32 ImageSize; + UINT32 ImageAlignment; + UINT64 ValueInSectionHeader; + UINT32 DstBufPages; + UINT32 DstBufSize; + EFI_MEMORY_TYPE ImageCodeMemoryType; + EFI_MEMORY_TYPE ImageDataMemoryType; + UEFI_IMAGE_LOADER_RUNTIME_CONTEXT *RelocationData; + EFI_PHYSICAL_ADDRESS BufferAddress; + UINT32 RelocDataSize; + + RelocationData = NULL; + + if (!CoreIsImageTypeSupported (Image, ImageContext)) { // // The PE/COFF loader can support loading image types that can be executed. // If we loaded an image type that we can not execute return EFI_UNSUPPORTED. @@ -606,50 +523,50 @@ CoreLoadPeImage ( DEBUG (( DEBUG_ERROR, "Image type %s can't be loaded on %s UEFI system.\n", - GetMachineTypeName (Image->ImageContext.Machine), - GetMachineTypeName (mDxeCoreImageMachineType) + GetMachineTypeName (UefiImageGetMachine (ImageContext)), + mDxeCoreImageMachineTypeName )); + return EFI_UNSUPPORTED; } // // Set EFI memory type based on ImageType // - switch (Image->ImageContext.ImageType) { + switch (UefiImageGetSubsystem (ImageContext)) { case EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION: - Image->ImageContext.ImageCodeMemoryType = EfiLoaderCode; - Image->ImageContext.ImageDataMemoryType = EfiLoaderData; + ImageCodeMemoryType = EfiLoaderCode; + ImageDataMemoryType = EfiLoaderData; break; case EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER: - Image->ImageContext.ImageCodeMemoryType = EfiBootServicesCode; - Image->ImageContext.ImageDataMemoryType = EfiBootServicesData; + ImageCodeMemoryType = EfiBootServicesCode; + ImageDataMemoryType = EfiBootServicesData; break; case EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER: case EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER: - Image->ImageContext.ImageCodeMemoryType = EfiRuntimeServicesCode; - Image->ImageContext.ImageDataMemoryType = EfiRuntimeServicesData; + ImageCodeMemoryType = EfiRuntimeServicesCode; + ImageDataMemoryType = EfiRuntimeServicesData; break; - default: - Image->ImageContext.ImageError = IMAGE_ERROR_INVALID_SUBSYSTEM; - return EFI_UNSUPPORTED; + default: + DEBUG ((DEBUG_INFO, "Unsupported type %d\n", UefiImageGetSubsystem (ImageContext))); + return EFI_UNSUPPORTED; } + ImageSize = UefiImageGetImageSize (ImageContext); + DstBufPages = EFI_SIZE_TO_PAGES (ImageSize); + DstBufSize = EFI_PAGES_TO_SIZE (DstBufPages); + ImageAlignment = UefiImageGetSegmentAlignment (ImageContext); + + BufferAddress = 0; // // Allocate memory of the correct memory type aligned on the required image boundary // DstBufAlocated = FALSE; - if (DstBuffer == 0) { + if (*DstBuffer == 0) { // // Allocate Destination Buffer as caller did not pass it in // - - if (Image->ImageContext.SectionAlignment > EFI_PAGE_SIZE) { - Size = (UINTN)Image->ImageContext.ImageSize + Image->ImageContext.SectionAlignment; - } else { - Size = (UINTN)Image->ImageContext.ImageSize; - } - - Image->NumberOfPages = EFI_SIZE_TO_PAGES (Size); + Image->NumberOfPages = DstBufPages; // // If the image relocations have not been stripped, then load at any address. @@ -664,98 +581,105 @@ CoreLoadPeImage ( // a specified address. // if (PcdGet64 (PcdLoadModuleAtFixAddressEnable) != 0 ) { - Status = GetPeCoffImageFixLoadingAssignedAddress (&(Image->ImageContext)); + Status = UefiImageGetFixedAddress (ImageContext, &ValueInSectionHeader); + if (RETURN_ERROR (Status)) { + return Status; + } - if (EFI_ERROR (Status)) { + Status = GetUefiImageFixLoadingAssignedAddress (&BufferAddress, ValueInSectionHeader, DstBufSize); + + if (!EFI_ERROR (Status)) { + if (BufferAddress != UefiImageGetPreferredAddress (ImageContext) && UefiImageGetRelocsStripped (ImageContext)) { + Status = EFI_UNSUPPORTED; + DEBUG ((EFI_D_INFO|EFI_D_LOAD, "LOADING MODULE FIXED ERROR: Loading module at fixed address failed since relocs have been stripped.\n")); + } + } else { // // If the code memory is not ready, invoke CoreAllocatePage with AllocateAnyPages to load the driver. // DEBUG ((DEBUG_INFO|DEBUG_LOAD, "LOADING MODULE FIXED ERROR: Loading module at fixed address failed since specified memory is not available.\n")); - - Status = CoreAllocatePages ( - AllocateAnyPages, - (EFI_MEMORY_TYPE)(Image->ImageContext.ImageCodeMemoryType), - Image->NumberOfPages, - &Image->ImageContext.ImageAddress - ); } - } else { - if ((PcdGetBool (PcdImageLargeAddressLoad) && ((Image->ImageContext.ImageAddress) >= 0x100000)) || - Image->ImageContext.RelocationsStripped) - { - Status = CoreAllocatePages ( + } + if (EFI_ERROR (Status)) { + BufferAddress = UefiImageGetPreferredAddress (ImageContext); + if ((BufferAddress >= 0x100000) || UefiImageGetRelocsStripped (ImageContext)) { + Status = AllocatePagesEx ( AllocateAddress, - (EFI_MEMORY_TYPE)(Image->ImageContext.ImageCodeMemoryType), - Image->NumberOfPages, - &Image->ImageContext.ImageAddress + ImageCodeMemoryType, + DstBufPages, + &BufferAddress ); } - if (EFI_ERROR (Status) && !Image->ImageContext.RelocationsStripped) { - Status = CoreAllocatePages ( + if (EFI_ERROR (Status) && !UefiImageGetRelocsStripped (ImageContext)) { + Status = AllocateAlignedPagesEx ( AllocateAnyPages, - (EFI_MEMORY_TYPE)(Image->ImageContext.ImageCodeMemoryType), - Image->NumberOfPages, - &Image->ImageContext.ImageAddress + ImageCodeMemoryType, + DstBufPages, + ImageAlignment, + &BufferAddress ); } } if (EFI_ERROR (Status)) { + ASSERT (FALSE); return Status; } DstBufAlocated = TRUE; + *DstBuffer = BufferAddress; } else { // // Caller provided the destination buffer // - if (Image->ImageContext.RelocationsStripped && (Image->ImageContext.ImageAddress != DstBuffer)) { + if (UefiImageGetRelocsStripped (ImageContext) && (BufferAddress != *DstBuffer)) { // // If the image relocations were stripped, and the caller provided a // destination buffer address that does not match the address that the // image is linked at, then the image cannot be loaded. // + ASSERT (FALSE); return EFI_INVALID_PARAMETER; } if ((Image->NumberOfPages != 0) && (Image->NumberOfPages < - (EFI_SIZE_TO_PAGES ((UINTN)Image->ImageContext.ImageSize + Image->ImageContext.SectionAlignment)))) + DstBufPages)) { - Image->NumberOfPages = EFI_SIZE_TO_PAGES ((UINTN)Image->ImageContext.ImageSize + Image->ImageContext.SectionAlignment); + Image->NumberOfPages = DstBufPages; + ASSERT (FALSE); return EFI_BUFFER_TOO_SMALL; } - Image->NumberOfPages = EFI_SIZE_TO_PAGES ((UINTN)Image->ImageContext.ImageSize + Image->ImageContext.SectionAlignment); - Image->ImageContext.ImageAddress = DstBuffer; + Image->NumberOfPages = DstBufPages; + BufferAddress = *DstBuffer; } - Image->ImageBasePage = Image->ImageContext.ImageAddress; - if (!Image->ImageContext.IsTeImage) { - Image->ImageContext.ImageAddress = - (Image->ImageContext.ImageAddress + Image->ImageContext.SectionAlignment - 1) & - ~((UINTN)Image->ImageContext.SectionAlignment - 1); - } - - // - // Load the image from the file into the allocated memory - // - Status = PeCoffLoaderLoadImage (&Image->ImageContext); - if (EFI_ERROR (Status)) { - goto Done; - } + Image->ImageBasePage = BufferAddress; // // If this is a Runtime Driver, then allocate memory for the FixupData that // is used to relocate the image when SetVirtualAddressMap() is called. The // relocation is done by the Runtime AP. // + RelocDataSize = 0; if ((Attribute & EFI_LOAD_PE_IMAGE_ATTRIBUTE_RUNTIME_REGISTRATION) != 0) { - if (Image->ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) { - Image->ImageContext.FixupData = AllocateRuntimePool ((UINTN)(Image->ImageContext.FixupDataSize)); - if (Image->ImageContext.FixupData == NULL) { + if (UefiImageGetSubsystem (ImageContext) == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) { + if (UefiImageGetRelocsStripped (ImageContext)) { + ASSERT (FALSE); + Status = RETURN_UNSUPPORTED; + goto Done; + } + Status = UefiImageLoaderGetRuntimeContextSize (ImageContext, &RelocDataSize); + if (EFI_ERROR (Status)) { + ASSERT (FALSE); + goto Done; + } + RelocationData = AllocateRuntimeZeroPool (RelocDataSize); + if (RelocationData == NULL) { + ASSERT (FALSE); Status = EFI_OUT_OF_RESOURCES; goto Done; } @@ -763,38 +687,40 @@ CoreLoadPeImage ( } // - // Relocate the image in memory + // Load the image from the file into the allocated memory // - Status = PeCoffLoaderRelocateImage (&Image->ImageContext); + Status = UefiImageLoadImageForExecution ( + ImageContext, + (VOID *)(UINTN)BufferAddress, + DstBufSize, + RelocationData, + RelocDataSize + ); if (EFI_ERROR (Status)) { + ASSERT (FALSE); goto Done; } - // - // Flush the Instruction Cache - // - InvalidateInstructionCacheRange ((VOID *)(UINTN)Image->ImageContext.ImageAddress, (UINTN)Image->ImageContext.ImageSize); - // // Copy the machine type from the context to the image private data. // - Image->Machine = Image->ImageContext.Machine; + Image->Machine = UefiImageGetMachine (ImageContext); // // Get the image entry point. // - Image->EntryPoint = (EFI_IMAGE_ENTRY_POINT)(UINTN)Image->ImageContext.EntryPoint; + Image->EntryPoint = (EFI_IMAGE_ENTRY_POINT)(UefiImageLoaderGetImageEntryPoint (ImageContext)); // // Fill in the image information for the Loaded Image Protocol // - Image->Type = Image->ImageContext.ImageType; - Image->Info.ImageBase = (VOID *)(UINTN)Image->ImageContext.ImageAddress; - Image->Info.ImageSize = Image->ImageContext.ImageSize; - Image->Info.ImageCodeType = (EFI_MEMORY_TYPE)(Image->ImageContext.ImageCodeMemoryType); - Image->Info.ImageDataType = (EFI_MEMORY_TYPE)(Image->ImageContext.ImageDataMemoryType); + Image->Type = UefiImageGetSubsystem (ImageContext); + Image->Info.ImageBase = (VOID *)(UINTN)BufferAddress; + Image->Info.ImageSize = ImageSize; + Image->Info.ImageCodeType = ImageCodeMemoryType; + Image->Info.ImageDataType = ImageDataMemoryType; if ((Attribute & EFI_LOAD_PE_IMAGE_ATTRIBUTE_RUNTIME_REGISTRATION) != 0) { - if (Image->ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) { + if (UefiImageGetSubsystem (ImageContext) == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) { // // Make a list off all the RT images so we can let the RT AP know about them. // @@ -805,10 +731,10 @@ CoreLoadPeImage ( Image->RuntimeData->ImageBase = Image->Info.ImageBase; Image->RuntimeData->ImageSize = (UINT64)(Image->Info.ImageSize); - Image->RuntimeData->RelocationData = Image->ImageContext.FixupData; + Image->RuntimeData->RelocationData = RelocationData; Image->RuntimeData->Handle = Image->Handle; InsertTailList (&gRuntime->ImageHead, &Image->RuntimeData->Link); - InsertImageRecord (Image->RuntimeData); + InsertImageRecord (Image, ImageContext); } } @@ -816,7 +742,17 @@ CoreLoadPeImage ( // Fill in the entry point of the image if it is available // if (EntryPoint != NULL) { - *EntryPoint = Image->ImageContext.EntryPoint; + *EntryPoint = UefiImageLoaderGetImageEntryPoint (ImageContext); + } + + UINT32 Hiioff; + UINT32 Hiisize; + Status = UefiImageGetHiiDataRva (ImageContext, &Hiioff, &Hiisize); + if (Status != RETURN_NOT_FOUND) { + ASSERT_EFI_ERROR (Status); + } + if (!EFI_ERROR (Status)) { + Image->HiiData = (VOID *)((UINTN)BufferAddress + Hiioff); } // @@ -825,56 +761,25 @@ CoreLoadPeImage ( DEBUG_CODE_BEGIN (); - UINTN Index; - UINTN StartIndex; - CHAR8 EfiFileName[256]; + CHAR8 EfiFileName[256]; - DEBUG (( - DEBUG_INFO | DEBUG_LOAD, - "Loading driver at 0x%11p EntryPoint=0x%11p ", - (VOID *)(UINTN)Image->ImageContext.ImageAddress, - FUNCTION_ENTRY_POINT (Image->ImageContext.EntryPoint) - )); + DEBUG ((DEBUG_INFO | DEBUG_LOAD, + "Loading driver at 0x%11p EntryPoint=0x%11p \n", + (VOID *)(UINTN)BufferAddress, + FUNCTION_ENTRY_POINT (UefiImageLoaderGetImageEntryPoint (ImageContext)))); + + Status = UefiImageGetModuleNameFromSymbolsPath ( + ImageContext, + EfiFileName, + sizeof (EfiFileName) + ); // // Print Module Name by Pdb file path. - // Windows and Unix style file path are all trimmed correctly. // - if (Image->ImageContext.PdbPointer != NULL) { - StartIndex = 0; - for (Index = 0; Image->ImageContext.PdbPointer[Index] != 0; Index++) { - if ((Image->ImageContext.PdbPointer[Index] == '\\') || (Image->ImageContext.PdbPointer[Index] == '/')) { - StartIndex = Index + 1; - } - } - - // - // Copy the PDB file name to our temporary string, and replace .pdb with .efi - // The PDB file name is limited in the range of 0~255. - // If the length is bigger than 255, trim the redudant characters to avoid overflow in array boundary. - // - for (Index = 0; Index < sizeof (EfiFileName) - 4; Index++) { - EfiFileName[Index] = Image->ImageContext.PdbPointer[Index + StartIndex]; - if (EfiFileName[Index] == 0) { - EfiFileName[Index] = '.'; - } - - if (EfiFileName[Index] == '.') { - EfiFileName[Index + 1] = 'e'; - EfiFileName[Index + 2] = 'f'; - EfiFileName[Index + 3] = 'i'; - EfiFileName[Index + 4] = 0; - break; - } - } - - if (Index == sizeof (EfiFileName) - 4) { - EfiFileName[Index] = 0; - } - - DEBUG ((DEBUG_INFO | DEBUG_LOAD, "%a", EfiFileName)); // &Image->ImageContext.PdbPointer[StartIndex])); + if (!EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO | DEBUG_LOAD, "%a", EfiFileName)); } - DEBUG ((DEBUG_INFO | DEBUG_LOAD, "\n")); DEBUG_CODE_END (); @@ -888,13 +793,13 @@ CoreLoadPeImage ( // if (DstBufAlocated) { - CoreFreePages (Image->ImageContext.ImageAddress, Image->NumberOfPages); - Image->ImageContext.ImageAddress = 0; + ZeroMem ((VOID *)(UINTN)BufferAddress, EFI_PAGES_TO_SIZE (Image->NumberOfPages)); + FreeAlignedPages ((VOID *)(UINTN)BufferAddress, Image->NumberOfPages); Image->ImageBasePage = 0; } - if (Image->ImageContext.FixupData != NULL) { - CoreFreePool (Image->ImageContext.FixupData); + if (RelocationData != NULL) { + CoreFreePool (RelocationData); } return Status; @@ -959,23 +864,20 @@ CoreUnloadAndCloseImage ( HandleBuffer = NULL; ProtocolGuidArray = NULL; - if (Image->Started) { - UnregisterMemoryProfileImage (Image); - } - - UnprotectUefiImage (&Image->Info, Image->LoadedImageDevicePath); + UnregisterMemoryProfileImage (Image->Info.FilePath, Image->ImageBasePage); if (Image->PeCoffEmu != NULL) { // // If the PE/COFF Emulator protocol exists we must unregister the image. // - Image->PeCoffEmu->UnregisterImage (Image->PeCoffEmu, Image->ImageBasePage); + Image->PeCoffEmu->UnregisterImage (Image->PeCoffEmu, (UINTN) Image->Info.ImageBase); } // // Unload image, free Image->ImageContext->ModHandle // - PeCoffLoaderUnloadImage (&Image->ImageContext); + // FIXME: + //PeCoffUnloadImage (&Image->ImageContext); // // Free our references to the image handle @@ -989,14 +891,14 @@ CoreUnloadAndCloseImage ( &HandleBuffer ); if (!EFI_ERROR (Status)) { - for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) { + for (HandleIndex = 0; HandleIndex < HandleCount; ++HandleIndex) { Status = CoreProtocolsPerHandle ( HandleBuffer[HandleIndex], &ProtocolGuidArray, &ArrayCount ); if (!EFI_ERROR (Status)) { - for (ProtocolIndex = 0; ProtocolIndex < ArrayCount; ProtocolIndex++) { + for (ProtocolIndex = 0; ProtocolIndex < ArrayCount; ++ProtocolIndex) { Status = CoreOpenProtocolInformation ( HandleBuffer[HandleIndex], ProtocolGuidArray[ProtocolIndex], @@ -1004,7 +906,7 @@ CoreUnloadAndCloseImage ( &OpenInfoCount ); if (!EFI_ERROR (Status)) { - for (OpenInfoIndex = 0; OpenInfoIndex < OpenInfoCount; OpenInfoIndex++) { + for (OpenInfoIndex = 0; OpenInfoIndex < OpenInfoCount; ++OpenInfoIndex) { if (OpenInfo[OpenInfoIndex].AgentHandle == Image->Handle) { Status = CoreCloseProtocol ( HandleBuffer[HandleIndex], @@ -1046,11 +948,11 @@ CoreUnloadAndCloseImage ( &Image->Info ); - if (Image->ImageContext.HiiResourceData != 0) { + if (Image->HiiData != NULL) { Status = CoreUninstallProtocolInterface ( Image->Handle, &gEfiHiiPackageListProtocolGuid, - (VOID *)(UINTN)Image->ImageContext.HiiResourceData + Image->HiiData ); } } @@ -1067,16 +969,23 @@ CoreUnloadAndCloseImage ( CoreFreePool (Image->RuntimeData); } + // + // Done with the Image structure + // + if (Image->FixupData != NULL) { + CoreFreePool (Image->FixupData); + } + // // Free the Image from memory // if ((Image->ImageBasePage != 0) && FreePage) { + UnprotectUefiImage (&Image->Info, Image->LoadedImageDevicePath); + // FIXME: SecureZeroMem; instruction pattern to trap? + ZeroMem ((VOID *)(UINTN)Image->ImageBasePage, EFI_PAGES_TO_SIZE (Image->NumberOfPages)); CoreFreePages (Image->ImageBasePage, Image->NumberOfPages); } - // - // Done with the Image structure - // if (Image->Info.FilePath != NULL) { CoreFreePool (Image->Info.FilePath); } @@ -1085,10 +994,6 @@ CoreUnloadAndCloseImage ( CoreFreePool (Image->LoadedImageDevicePath); } - if (Image->FixupData != NULL) { - CoreFreePool (Image->FixupData); - } - CoreFreePool (Image); } @@ -1150,20 +1055,21 @@ CoreLoadImageCommon ( IN UINT32 Attribute ) { - LOADED_IMAGE_PRIVATE_DATA *Image; - LOADED_IMAGE_PRIVATE_DATA *ParentImage; - IMAGE_FILE_HANDLE FHand; - EFI_STATUS Status; - EFI_STATUS SecurityStatus; - EFI_HANDLE DeviceHandle; - UINT32 AuthenticationStatus; - EFI_DEVICE_PATH_PROTOCOL *OriginalFilePath; - EFI_DEVICE_PATH_PROTOCOL *HandleFilePath; - EFI_DEVICE_PATH_PROTOCOL *InputFilePath; - EFI_DEVICE_PATH_PROTOCOL *Node; - UINTN FilePathSize; - BOOLEAN ImageIsFromFv; - BOOLEAN ImageIsFromLoadFile; + LOADED_IMAGE_PRIVATE_DATA *Image; + LOADED_IMAGE_PRIVATE_DATA *ParentImage; + IMAGE_FILE_HANDLE FHand; + EFI_STATUS Status; + EFI_STATUS SecurityStatus; + EFI_HANDLE DeviceHandle; + UINT32 AuthenticationStatus; + EFI_DEVICE_PATH_PROTOCOL *OriginalFilePath; + EFI_DEVICE_PATH_PROTOCOL *HandleFilePath; + EFI_DEVICE_PATH_PROTOCOL *InputFilePath; + EFI_DEVICE_PATH_PROTOCOL *Node; + UINTN FilePathSize; + BOOLEAN ImageIsFromFv; + BOOLEAN ImageIsFromLoadFile; + UEFI_IMAGE_LOADER_IMAGE_CONTEXT ImageContext; SecurityStatus = EFI_SUCCESS; @@ -1206,6 +1112,18 @@ CoreLoadImageCommon ( } if (SourceSize > 0) { + if (DeviceHandle != NULL) { + Status = CoreOpenProtocol ( + DeviceHandle, + &gEfiFirmwareVolume2ProtocolGuid, + NULL, + NULL, + NULL, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL + ); + ImageIsFromFv = !EFI_ERROR (Status); + } + Status = EFI_SUCCESS; } else { Status = EFI_LOAD_ERROR; @@ -1269,6 +1187,16 @@ CoreLoadImageCommon ( goto Done; } + // + // Get information about the image being loaded + // + Status = UefiImageInitializeContextPreHash (&ImageContext, FHand.Source, (UINT32) FHand.SourceSize); + if (EFI_ERROR (Status)) { + ASSERT (FALSE); + return Status; + } + + // FIXME: Context if (gSecurity2 != NULL) { // // Verify File Authentication through the Security2 Architectural Protocol @@ -1276,8 +1204,8 @@ CoreLoadImageCommon ( SecurityStatus = gSecurity2->FileAuthentication ( gSecurity2, OriginalFilePath, - FHand.Source, - FHand.SourceSize, + &ImageContext, + sizeof (ImageContext), BootPolicy ); if (!EFI_ERROR (SecurityStatus) && ImageIsFromFv) { @@ -1324,6 +1252,11 @@ CoreLoadImageCommon ( goto Done; } + Status = UefiImageInitializeContextPostHash (&ImageContext); + if (RETURN_ERROR (Status)) { + goto Done; + } + // // Allocate a new image structure // @@ -1379,7 +1312,8 @@ CoreLoadImageCommon ( // // Load the image. If EntryPoint is Null, it will not be set. // - Status = CoreLoadPeImage (BootPolicy, &FHand, Image, DstBuffer, EntryPoint, Attribute); + EFI_PHYSICAL_ADDRESS LoadAddress = DstBuffer; + Status = CoreLoadPeImage (BootPolicy, Image, &LoadAddress, EntryPoint, Attribute, &ImageContext); if (EFI_ERROR (Status)) { if ((Status == EFI_BUFFER_TOO_SMALL) || (Status == EFI_OUT_OF_RESOURCES)) { if (NumberOfPages != NULL) { @@ -1398,7 +1332,7 @@ CoreLoadImageCommon ( // Register the image in the Debug Image Info Table if the attribute is set // if ((Attribute & EFI_LOAD_PE_IMAGE_ATTRIBUTE_DEBUG_IMAGE_INFO_TABLE_REGISTRATION) != 0) { - CoreNewDebugImageInfoEntry (EFI_DEBUG_IMAGE_INFO_TYPE_NORMAL, &Image->Info, Image->Handle); + CoreNewDebugImageInfoEntry (EFI_DEBUG_IMAGE_INFO_TYPE_NORMAL, &Image->Info, Image->Handle, &ImageContext); } // @@ -1445,22 +1379,26 @@ CoreLoadImageCommon ( goto Done; } - // - // Install HII Package List Protocol onto the image handle - // - if (Image->ImageContext.HiiResourceData != 0) { + if (Image->HiiData != NULL) { Status = CoreInstallProtocolInterface ( &Image->Handle, &gEfiHiiPackageListProtocolGuid, EFI_NATIVE_INTERFACE, - (VOID *)(UINTN)Image->ImageContext.HiiResourceData + Image->HiiData ); if (EFI_ERROR (Status)) { goto Done; } } - ProtectUefiImage (&Image->Info, Image->LoadedImageDevicePath); + Status = EFI_SUCCESS; + ProtectUefiImage (Image, &ImageContext); + + RegisterMemoryProfileImage ( + Image->LoadedImageDevicePath, + (UefiImageGetSubsystem (&ImageContext) == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION ? EFI_FV_FILETYPE_APPLICATION : EFI_FV_FILETYPE_DRIVER), + &ImageContext + ); // // Success. Return the image handle @@ -1623,6 +1561,8 @@ CoreStartImage ( return Image->LoadImageStatus; } + DEBUG ((DEBUG_WARN, "Starting driver at %lu\n", Image->Info.ImageBase)); + // // The image to be started must have the machine type supported by DxeCore. // @@ -1633,16 +1573,16 @@ CoreStartImage ( // Do not ASSERT here, because image might be loaded via EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED // But it can not be started. // - DEBUG ((DEBUG_ERROR, "Image type %s can't be started ", GetMachineTypeName (Image->Machine))); - DEBUG ((DEBUG_ERROR, "on %s UEFI system.\n", GetMachineTypeName (mDxeCoreImageMachineType))); + DEBUG ((EFI_D_ERROR, "Image type %s can't be started ", GetMachineTypeName(Image->Machine))); + DEBUG ((EFI_D_ERROR, "on %s UEFI system.\n", mDxeCoreImageMachineTypeName)); return EFI_UNSUPPORTED; } if (Image->PeCoffEmu != NULL) { Status = Image->PeCoffEmu->RegisterImage ( Image->PeCoffEmu, - Image->ImageBasePage, - EFI_PAGES_TO_SIZE (Image->NumberOfPages), + (UINTN) Image->Info.ImageBase, + Image->Info.ImageSize, &Image->EntryPoint ); if (EFI_ERROR (Status)) { @@ -1696,7 +1636,6 @@ CoreStartImage ( // Subsequent calls to LongJump() cause a non-zero value to be returned by SetJump(). // if (SetJumpFlag == 0) { - RegisterMemoryProfileImage (Image, (Image->ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION ? EFI_FV_FILETYPE_APPLICATION : EFI_FV_FILETYPE_DRIVER)); // // Call the image's entry point // diff --git a/MdeModulePkg/Core/Dxe/Mem/HeapGuard.c b/MdeModulePkg/Core/Dxe/Mem/HeapGuard.c index 0c0ca61872..6457741683 100644 --- a/MdeModulePkg/Core/Dxe/Mem/HeapGuard.c +++ b/MdeModulePkg/Core/Dxe/Mem/HeapGuard.c @@ -1528,7 +1528,7 @@ PromoteGuardedFreePages ( OUT EFI_PHYSICAL_ADDRESS *EndAddress ) { - EFI_STATUS Status; + EFI_STATUS Status; UINTN AvailablePages; UINT64 Bitmap; EFI_PHYSICAL_ADDRESS Start; diff --git a/MdeModulePkg/Core/Dxe/Mem/MemoryProfileRecord.c b/MdeModulePkg/Core/Dxe/Mem/MemoryProfileRecord.c index 00e33b707d..b67596f48e 100644 --- a/MdeModulePkg/Core/Dxe/Mem/MemoryProfileRecord.c +++ b/MdeModulePkg/Core/Dxe/Mem/MemoryProfileRecord.c @@ -8,6 +8,10 @@ #include "DxeMain.h" #include "Imem.h" +#include "Library/UefiImageLib.h" +#include "ProcessorBind.h" +#include "Protocol/LoadedImage.h" +#include "Uefi/UefiBaseType.h" #define IS_UEFI_MEMORY_PROFILE_ENABLED ((PcdGet8 (PcdMemoryProfilePropertyMask) & BIT0) != 0) @@ -104,8 +108,7 @@ EFIAPI ProfileProtocolRegisterImage ( IN EDKII_MEMORY_PROFILE_PROTOCOL *This, IN EFI_DEVICE_PATH_PROTOCOL *FilePath, - IN PHYSICAL_ADDRESS ImageBase, - IN UINT64 ImageSize, + IN UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext, IN EFI_FV_FILETYPE FileType ); @@ -247,110 +250,6 @@ GetMemoryProfileContext ( return mMemoryProfileContextPtr; } -/** - Retrieves and returns the Subsystem of a PE/COFF image that has been loaded into system memory. - If Pe32Data is NULL, then ASSERT(). - - @param Pe32Data The pointer to the PE/COFF image that is loaded in system memory. - - @return The Subsystem of the PE/COFF image. - -**/ -UINT16 -InternalPeCoffGetSubsystem ( - IN VOID *Pe32Data - ) -{ - EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr; - EFI_IMAGE_DOS_HEADER *DosHdr; - UINT16 Magic; - - ASSERT (Pe32Data != NULL); - - DosHdr = (EFI_IMAGE_DOS_HEADER *)Pe32Data; - if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) { - // - // DOS image header is present, so read the PE header after the DOS image header. - // - Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN)Pe32Data + (UINTN)((DosHdr->e_lfanew) & 0x0ffff)); - } else { - // - // DOS image header is not present, so PE header is at the image base. - // - Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)Pe32Data; - } - - if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) { - return Hdr.Te->Subsystem; - } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) { - Magic = Hdr.Pe32->OptionalHeader.Magic; - if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { - return Hdr.Pe32->OptionalHeader.Subsystem; - } else if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) { - return Hdr.Pe32Plus->OptionalHeader.Subsystem; - } - } - - return 0x0000; -} - -/** - Retrieves and returns a pointer to the entry point to a PE/COFF image that has been loaded - into system memory with the PE/COFF Loader Library functions. - - Retrieves the entry point to the PE/COFF image specified by Pe32Data and returns this entry - point in EntryPoint. If the entry point could not be retrieved from the PE/COFF image, then - return RETURN_INVALID_PARAMETER. Otherwise return RETURN_SUCCESS. - If Pe32Data is NULL, then ASSERT(). - If EntryPoint is NULL, then ASSERT(). - - @param Pe32Data The pointer to the PE/COFF image that is loaded in system memory. - @param EntryPoint The pointer to entry point to the PE/COFF image to return. - - @retval RETURN_SUCCESS EntryPoint was returned. - @retval RETURN_INVALID_PARAMETER The entry point could not be found in the PE/COFF image. - -**/ -RETURN_STATUS -InternalPeCoffGetEntryPoint ( - IN VOID *Pe32Data, - OUT VOID **EntryPoint - ) -{ - EFI_IMAGE_DOS_HEADER *DosHdr; - EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr; - - ASSERT (Pe32Data != NULL); - ASSERT (EntryPoint != NULL); - - DosHdr = (EFI_IMAGE_DOS_HEADER *)Pe32Data; - if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) { - // - // DOS image header is present, so read the PE header after the DOS image header. - // - Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN)Pe32Data + (UINTN)((DosHdr->e_lfanew) & 0x0ffff)); - } else { - // - // DOS image header is not present, so PE header is at the image base. - // - Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)Pe32Data; - } - - // - // Calculate the entry point relative to the start of the image. - // AddressOfEntryPoint is common for PE32 & PE32+ - // - if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) { - *EntryPoint = (VOID *)((UINTN)Pe32Data + (UINTN)(Hdr.Te->AddressOfEntryPoint & 0x0ffffffff) + sizeof (EFI_TE_IMAGE_HEADER) - Hdr.Te->StrippedSize); - return RETURN_SUCCESS; - } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) { - *EntryPoint = (VOID *)((UINTN)Pe32Data + (UINTN)(Hdr.Pe32->OptionalHeader.AddressOfEntryPoint & 0x0ffffffff)); - return RETURN_SUCCESS; - } - - return RETURN_UNSUPPORTED; -} - /** Build driver info. @@ -367,32 +266,27 @@ InternalPeCoffGetEntryPoint ( **/ MEMORY_PROFILE_DRIVER_INFO_DATA * BuildDriverInfo ( - IN MEMORY_PROFILE_CONTEXT_DATA *ContextData, - IN EFI_GUID *FileName, - IN PHYSICAL_ADDRESS ImageBase, - IN UINT64 ImageSize, - IN PHYSICAL_ADDRESS EntryPoint, - IN UINT16 ImageSubsystem, - IN EFI_FV_FILETYPE FileType + IN MEMORY_PROFILE_CONTEXT_DATA *ContextData, + IN EFI_GUID *FileName, + IN UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext, + IN EFI_FV_FILETYPE FileType ) { + RETURN_STATUS PdbStatus; EFI_STATUS Status; MEMORY_PROFILE_DRIVER_INFO *DriverInfo; MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData; - VOID *EntryPointInImage; - CHAR8 *PdbString; - UINTN PdbSize; + CONST CHAR8 *PdbString; + UINT32 PdbSize; UINTN PdbOccupiedSize; - PdbSize = 0; PdbOccupiedSize = 0; - PdbString = NULL; - if (ImageBase != 0) { - PdbString = PeCoffLoaderGetPdbPointer ((VOID *)(UINTN)ImageBase); - if (PdbString != NULL) { - PdbSize = AsciiStrSize (PdbString); - PdbOccupiedSize = GET_OCCUPIED_SIZE (PdbSize, sizeof (UINT64)); - } + + ASSERT (UefiImageLoaderGetImageAddress (ImageContext) != 0); + + PdbStatus = UefiImageGetSymbolsPath (ImageContext, &PdbString, &PdbSize); + if (!EFI_ERROR (PdbStatus)) { + PdbOccupiedSize = GET_OCCUPIED_SIZE (PdbSize, sizeof (UINT64)); } // @@ -420,19 +314,10 @@ BuildDriverInfo ( CopyMem (&DriverInfo->FileName, FileName, sizeof (EFI_GUID)); } - DriverInfo->ImageBase = ImageBase; - DriverInfo->ImageSize = ImageSize; - DriverInfo->EntryPoint = EntryPoint; - DriverInfo->ImageSubsystem = ImageSubsystem; - if ((EntryPoint != 0) && ((EntryPoint < ImageBase) || (EntryPoint >= (ImageBase + ImageSize)))) { - // - // If the EntryPoint is not in the range of image buffer, it should come from emulation environment. - // So patch ImageBuffer here to align the EntryPoint. - // - Status = InternalPeCoffGetEntryPoint ((VOID *)(UINTN)ImageBase, &EntryPointInImage); - ASSERT_EFI_ERROR (Status); - DriverInfo->ImageBase = ImageBase + EntryPoint - (PHYSICAL_ADDRESS)(UINTN)EntryPointInImage; - } + DriverInfo->ImageBase = UefiImageLoaderGetImageAddress (ImageContext); + DriverInfo->ImageSize = UefiImageGetImageSize (ImageContext); + DriverInfo->EntryPoint = UefiImageLoaderGetImageEntryPoint (ImageContext); + DriverInfo->ImageSubsystem = UefiImageGetSubsystem (ImageContext); DriverInfo->FileType = FileType; DriverInfoData->AllocInfoList = (LIST_ENTRY *)(DriverInfoData + 1); @@ -440,7 +325,7 @@ BuildDriverInfo ( DriverInfo->CurrentUsage = 0; DriverInfo->PeakUsage = 0; DriverInfo->AllocRecordCount = 0; - if (PdbSize != 0) { + if (!RETURN_ERROR (PdbStatus)) { DriverInfo->PdbStringOffset = (UINT16)sizeof (MEMORY_PROFILE_DRIVER_INFO); DriverInfoData->PdbString = (CHAR8 *)(DriverInfoData->AllocInfoList + 1); CopyMem (DriverInfoData->PdbString, PdbString, PdbSize); @@ -528,13 +413,13 @@ NeedRecordThisDriver ( **/ BOOLEAN RegisterDxeCore ( - IN VOID *HobStart, - IN MEMORY_PROFILE_CONTEXT_DATA *ContextData + IN VOID *HobStart, + IN UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext, + IN MEMORY_PROFILE_CONTEXT_DATA *ContextData ) { EFI_PEI_HOB_POINTERS DxeCoreHob; MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData; - PHYSICAL_ADDRESS ImageBase; UINT8 TempBuffer[sizeof (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH) + sizeof (EFI_DEVICE_PATH_PROTOCOL)]; MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FilePath; @@ -565,14 +450,10 @@ RegisterDxeCore ( return FALSE; } - ImageBase = DxeCoreHob.MemoryAllocationModule->MemoryAllocationHeader.MemoryBaseAddress; DriverInfoData = BuildDriverInfo ( ContextData, &DxeCoreHob.MemoryAllocationModule->ModuleName, - ImageBase, - DxeCoreHob.MemoryAllocationModule->MemoryAllocationHeader.MemoryLength, - DxeCoreHob.MemoryAllocationModule->EntryPoint, - InternalPeCoffGetSubsystem ((VOID *)(UINTN)ImageBase), + ImageContext, EFI_FV_FILETYPE_DXE_CORE ); if (DriverInfoData == NULL) { @@ -590,7 +471,8 @@ RegisterDxeCore ( **/ VOID MemoryProfileInit ( - IN VOID *HobStart + IN VOID *HobStart, + IN UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext ) { MEMORY_PROFILE_CONTEXT_DATA *ContextData; @@ -615,7 +497,7 @@ MemoryProfileInit ( mMemoryProfileDriverPath = AllocateCopyPool (mMemoryProfileDriverPathSize, PcdGetPtr (PcdMemoryProfileDriverPath)); mMemoryProfileContextPtr = &mMemoryProfileContext; - RegisterDxeCore (HobStart, &mMemoryProfileContext); + RegisterDxeCore (HobStart, ImageContext, &mMemoryProfileContext); DEBUG ((DEBUG_INFO, "MemoryProfileInit MemoryProfileContext - 0x%x\n", &mMemoryProfileContext)); } @@ -692,8 +574,9 @@ GetFileNameFromFilePath ( **/ EFI_STATUS RegisterMemoryProfileImage ( - IN LOADED_IMAGE_PRIVATE_DATA *DriverEntry, - IN EFI_FV_FILETYPE FileType + IN EFI_DEVICE_PATH_PROTOCOL *FilePath, + IN EFI_FV_FILETYPE FileType, + IN UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext ) { MEMORY_PROFILE_CONTEXT_DATA *ContextData; @@ -703,7 +586,7 @@ RegisterMemoryProfileImage ( return EFI_UNSUPPORTED; } - if (!NeedRecordThisDriver (DriverEntry->Info.FilePath)) { + if (!NeedRecordThisDriver (FilePath)) { return EFI_UNSUPPORTED; } @@ -714,11 +597,8 @@ RegisterMemoryProfileImage ( DriverInfoData = BuildDriverInfo ( ContextData, - GetFileNameFromFilePath (DriverEntry->Info.FilePath), - DriverEntry->ImageContext.ImageAddress, - DriverEntry->ImageContext.ImageSize, - DriverEntry->ImageContext.EntryPoint, - DriverEntry->ImageContext.ImageType, + GetFileNameFromFilePath (FilePath), + ImageContext, FileType ); if (DriverInfoData == NULL) { @@ -831,21 +711,21 @@ GetMemoryProfileDriverInfoFromAddress ( **/ EFI_STATUS UnregisterMemoryProfileImage ( - IN LOADED_IMAGE_PRIVATE_DATA *DriverEntry + EFI_DEVICE_PATH_PROTOCOL *FilePath, + IN EFI_PHYSICAL_ADDRESS ImageAddress ) { - EFI_STATUS Status; + //EFI_STATUS Status; MEMORY_PROFILE_CONTEXT_DATA *ContextData; MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData; EFI_GUID *FileName; - PHYSICAL_ADDRESS ImageAddress; - VOID *EntryPointInImage; + //VOID *EntryPointInImage; if (!IS_UEFI_MEMORY_PROFILE_ENABLED) { return EFI_UNSUPPORTED; } - if (!NeedRecordThisDriver (DriverEntry->Info.FilePath)) { + if (!NeedRecordThisDriver (FilePath)) { return EFI_UNSUPPORTED; } @@ -855,17 +735,7 @@ UnregisterMemoryProfileImage ( } DriverInfoData = NULL; - FileName = GetFileNameFromFilePath (DriverEntry->Info.FilePath); - ImageAddress = DriverEntry->ImageContext.ImageAddress; - if ((DriverEntry->ImageContext.EntryPoint < ImageAddress) || (DriverEntry->ImageContext.EntryPoint >= (ImageAddress + DriverEntry->ImageContext.ImageSize))) { - // - // If the EntryPoint is not in the range of image buffer, it should come from emulation environment. - // So patch ImageAddress here to align the EntryPoint. - // - Status = InternalPeCoffGetEntryPoint ((VOID *)(UINTN)ImageAddress, &EntryPointInImage); - ASSERT_EFI_ERROR (Status); - ImageAddress = ImageAddress + (UINTN)DriverEntry->ImageContext.EntryPoint - (UINTN)EntryPointInImage; - } + FileName = GetFileNameFromFilePath (FilePath); if (FileName != NULL) { DriverInfoData = GetMemoryProfileDriverInfoByFileNameAndAddress (ContextData, FileName, ImageAddress); @@ -1629,27 +1499,13 @@ ProfileProtocolGetData ( EFI_STATUS EFIAPI ProfileProtocolRegisterImage ( - IN EDKII_MEMORY_PROFILE_PROTOCOL *This, - IN EFI_DEVICE_PATH_PROTOCOL *FilePath, - IN PHYSICAL_ADDRESS ImageBase, - IN UINT64 ImageSize, - IN EFI_FV_FILETYPE FileType + IN EDKII_MEMORY_PROFILE_PROTOCOL *This, + IN EFI_DEVICE_PATH_PROTOCOL *FilePath, + IN UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext, + IN EFI_FV_FILETYPE FileType ) { - EFI_STATUS Status; - LOADED_IMAGE_PRIVATE_DATA DriverEntry; - VOID *EntryPointInImage; - - ZeroMem (&DriverEntry, sizeof (DriverEntry)); - DriverEntry.Info.FilePath = FilePath; - DriverEntry.ImageContext.ImageAddress = ImageBase; - DriverEntry.ImageContext.ImageSize = ImageSize; - Status = InternalPeCoffGetEntryPoint ((VOID *)(UINTN)ImageBase, &EntryPointInImage); - ASSERT_EFI_ERROR (Status); - DriverEntry.ImageContext.EntryPoint = (PHYSICAL_ADDRESS)(UINTN)EntryPointInImage; - DriverEntry.ImageContext.ImageType = InternalPeCoffGetSubsystem ((VOID *)(UINTN)ImageBase); - - return RegisterMemoryProfileImage (&DriverEntry, FileType); + return RegisterMemoryProfileImage (FilePath, FileType, ImageContext); } /** @@ -1675,19 +1531,7 @@ ProfileProtocolUnregisterImage ( IN UINT64 ImageSize ) { - EFI_STATUS Status; - LOADED_IMAGE_PRIVATE_DATA DriverEntry; - VOID *EntryPointInImage; - - ZeroMem (&DriverEntry, sizeof (DriverEntry)); - DriverEntry.Info.FilePath = FilePath; - DriverEntry.ImageContext.ImageAddress = ImageBase; - DriverEntry.ImageContext.ImageSize = ImageSize; - Status = InternalPeCoffGetEntryPoint ((VOID *)(UINTN)ImageBase, &EntryPointInImage); - ASSERT_EFI_ERROR (Status); - DriverEntry.ImageContext.EntryPoint = (PHYSICAL_ADDRESS)(UINTN)EntryPointInImage; - - return UnregisterMemoryProfileImage (&DriverEntry); + return UnregisterMemoryProfileImage (FilePath, ImageBase); } /** diff --git a/MdeModulePkg/Core/Dxe/Misc/DebugImageInfo.c b/MdeModulePkg/Core/Dxe/Misc/DebugImageInfo.c index eeb18f6e47..d6e732e021 100644 --- a/MdeModulePkg/Core/Dxe/Misc/DebugImageInfo.c +++ b/MdeModulePkg/Core/Dxe/Misc/DebugImageInfo.c @@ -160,15 +160,20 @@ CoreUpdateDebugTableCrc32 ( **/ VOID CoreNewDebugImageInfoEntry ( - IN UINT32 ImageInfoType, - IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage, - IN EFI_HANDLE ImageHandle + IN UINT32 ImageInfoType, + IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage, + IN EFI_HANDLE ImageHandle, + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext ) { - EFI_DEBUG_IMAGE_INFO *Table; - EFI_DEBUG_IMAGE_INFO *NewTable; - UINTN Index; - UINTN TableSize; + EFI_DEBUG_IMAGE_INFO *Table; + EFI_DEBUG_IMAGE_INFO *NewTable; + UINTN Index; + UINTN TableSize; + EFI_DEBUG_IMAGE_INFO_NORMAL *NormalImage; + RETURN_STATUS Status; + CONST CHAR8 *PdbPath; + UINT32 PdbPathSize; // // Set the flag indicating that we're in the process of updating the table. @@ -205,6 +210,15 @@ CoreNewDebugImageInfoEntry ( // Copy the old table into the new one // CopyMem (NewTable, Table, TableSize); + mDebugInfoTableHeader.EfiDebugImageInfoTable = NewTable; + // + // Set the first empty entry index to be the original max table entries. + // + Index = mMaxTableEntries; + // + // Enlarge the max table entries. + // + mMaxTableEntries += EFI_PAGE_SIZE / EFI_DEBUG_TABLE_ENTRY_SIZE; // // Free the old table // @@ -212,32 +226,31 @@ CoreNewDebugImageInfoEntry ( // // Update the table header // - Table = NewTable; - mDebugInfoTableHeader.EfiDebugImageInfoTable = NewTable; - // - // Enlarge the max table entries and set the first empty entry index to - // be the original max table entries. - // - Index = mMaxTableEntries; - mMaxTableEntries += EFI_PAGE_SIZE / EFI_DEBUG_TABLE_ENTRY_SIZE; + Table = NewTable; } // // Allocate data for new entry // - Table[Index].NormalImage = AllocateZeroPool (sizeof (EFI_DEBUG_IMAGE_INFO_NORMAL)); - if (Table[Index].NormalImage != NULL) { + NormalImage = AllocateZeroPool (sizeof (EFI_DEBUG_IMAGE_INFO_NORMAL)); + if (NormalImage != NULL) { // // Update the entry // - Table[Index].NormalImage->ImageInfoType = (UINT32)ImageInfoType; - Table[Index].NormalImage->LoadedImageProtocolInstance = LoadedImage; - Table[Index].NormalImage->ImageHandle = ImageHandle; + NormalImage->ImageInfoType = (UINT32)ImageInfoType; + NormalImage->LoadedImageProtocolInstance = LoadedImage; + NormalImage->ImageHandle = ImageHandle; + + Status = UefiImageGetSymbolsPath (ImageContext, &PdbPath, &PdbPathSize); + if (!RETURN_ERROR (Status)) { + NormalImage->PdbPath = AllocateCopyPool (PdbPathSize, PdbPath); + } // // Increase the number of EFI_DEBUG_IMAGE_INFO elements and set the mDebugInfoTable in modified status. // - mDebugInfoTableHeader.TableSize++; mDebugInfoTableHeader.UpdateStatus |= EFI_DEBUG_IMAGE_INFO_TABLE_MODIFIED; + Table[Index].NormalImage = NormalImage; + mDebugInfoTableHeader.TableSize++; } mDebugInfoTableHeader.UpdateStatus &= ~EFI_DEBUG_IMAGE_INFO_UPDATE_IN_PROGRESS; @@ -254,8 +267,9 @@ CoreRemoveDebugImageInfoEntry ( EFI_HANDLE ImageHandle ) { - EFI_DEBUG_IMAGE_INFO *Table; - UINTN Index; + EFI_DEBUG_IMAGE_INFO *Table; + UINTN Index; + EFI_DEBUG_IMAGE_INFO_NORMAL *NormalImage; mDebugInfoTableHeader.UpdateStatus |= EFI_DEBUG_IMAGE_INFO_UPDATE_IN_PROGRESS; @@ -267,13 +281,19 @@ CoreRemoveDebugImageInfoEntry ( // Found a match. Free up the record, then NULL the pointer to indicate the slot // is free. // - CoreFreePool (Table[Index].NormalImage); - Table[Index].NormalImage = NULL; + NormalImage = Table[Index].NormalImage; // // Decrease the number of EFI_DEBUG_IMAGE_INFO elements and set the mDebugInfoTable in modified status. // - mDebugInfoTableHeader.TableSize--; mDebugInfoTableHeader.UpdateStatus |= EFI_DEBUG_IMAGE_INFO_TABLE_MODIFIED; + mDebugInfoTableHeader.TableSize--; + Table[Index].NormalImage = NULL; + + if (NormalImage->PdbPath != NULL) { + FreePool (NormalImage->PdbPath); + } + + CoreFreePool (NormalImage); break; } } diff --git a/MdeModulePkg/Core/Dxe/Misc/MemoryAttributesTable.c b/MdeModulePkg/Core/Dxe/Misc/MemoryAttributesTable.c index e9343a2c4e..047982812d 100644 --- a/MdeModulePkg/Core/Dxe/Misc/MemoryAttributesTable.c +++ b/MdeModulePkg/Core/Dxe/Misc/MemoryAttributesTable.c @@ -22,6 +22,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #include "DxeMain.h" #include "HeapGuard.h" +#include "IndustryStandard/PeImage2.h" +#include "ProcessorBind.h" /** This function for GetMemoryMap() with properties table capability. @@ -73,7 +75,7 @@ CoreGetMemoryMapWithSeparatedImageSection ( typedef struct { UINT32 Signature; UINTN ImageRecordCount; - UINTN CodeSegmentCountMax; + UINTN SectionCountMax; LIST_ENTRY ImageRecordList; } IMAGE_PROPERTIES_PRIVATE_DATA; @@ -201,7 +203,7 @@ InstallMemoryAttributesTable ( case EfiRuntimeServicesCode: case EfiRuntimeServicesData: CopyMem (MemoryAttributesEntry, MemoryMap, DescriptorSize); - MemoryAttributesEntry->Attribute &= (EFI_MEMORY_RO|EFI_MEMORY_XP|EFI_MEMORY_RUNTIME); + MemoryAttributesEntry->Attribute &= EFI_MEMORY_ACCESS_MASK | EFI_MEMORY_RUNTIME; DEBUG ((DEBUG_VERBOSE, "Entry (0x%x)\n", MemoryAttributesEntry)); DEBUG ((DEBUG_VERBOSE, " Type - 0x%x\n", MemoryAttributesEntry->Type)); DEBUG ((DEBUG_VERBOSE, " PhysicalStart - 0x%016lx\n", MemoryAttributesEntry->PhysicalStart)); @@ -284,15 +286,6 @@ InstallMemoryAttributesTableOnEndOfDxe ( { mMemoryAttributesTableEndOfDxe = TRUE; InstallMemoryAttributesTable (); - - DEBUG_CODE_BEGIN (); - if ( mImagePropertiesPrivateData.ImageRecordCount > 0) { - DEBUG ((DEBUG_INFO, "DXE - Total Runtime Image Count: 0x%x\n", mImagePropertiesPrivateData.ImageRecordCount)); - DEBUG ((DEBUG_INFO, "DXE - Dump Runtime Image Records:\n")); - DumpImageRecords (&mImagePropertiesPrivateData.ImageRecordList); - } - - DEBUG_CODE_END (); } /** @@ -526,7 +519,11 @@ CoreGetMemoryMapWithSeparatedImageSection ( CoreAcquiremMemoryAttributesTableLock (); - AdditionalRecordCount = (2 * mImagePropertiesPrivateData.CodeSegmentCountMax + 3) * mImagePropertiesPrivateData.ImageRecordCount; + // + // Per image, there may be one additional trailer. There may be prefixed data + // (counted as the original entry). + // + AdditionalRecordCount = (mImagePropertiesPrivateData.SectionCountMax + 1) * mImagePropertiesPrivateData.ImageRecordCount; OldMemoryMapSize = *MemoryMapSize; Status = CoreGetMemoryMap (MemoryMapSize, MemoryMap, MapKey, DescriptorSize, DescriptorVersion); @@ -566,6 +563,68 @@ CoreGetMemoryMapWithSeparatedImageSection ( // Below functions are for ImageRecord // +/** + Set MemoryAttributesTable according to PE/COFF image section alignment. + + @param SectionAlignment PE/COFF section alignment +**/ +STATIC +VOID +SetMemoryAttributesTableSectionAlignment ( + IN UINT32 SectionAlignment + ) +{ + if (((SectionAlignment & (RUNTIME_PAGE_ALLOCATION_GRANULARITY - 1)) != 0) && + mMemoryAttributesTableEnable) + { + DEBUG ((DEBUG_VERBOSE, "SetMemoryAttributesTableSectionAlignment - Clear\n")); + mMemoryAttributesTableEnable = FALSE; + } +} + +/** + Sort image record based upon the ImageBase from low to high. +**/ +STATIC +VOID +InsertSortImageRecord ( + IN UEFI_IMAGE_RECORD *NewImageRecord + ) +{ + UEFI_IMAGE_RECORD *ImageRecord; + LIST_ENTRY *PrevImageRecordLink; + LIST_ENTRY *ImageRecordLink; + LIST_ENTRY *ImageRecordList; + + ImageRecordList = &mImagePropertiesPrivateData.ImageRecordList; + + PrevImageRecordLink = ImageRecordList; + for ( + ImageRecordLink = GetFirstNode (ImageRecordList); + !IsNull (ImageRecordLink, ImageRecordList); + ImageRecordLink = GetNextNode (ImageRecordList, PrevImageRecordLink) + ) { + ImageRecord = CR ( + ImageRecordLink, + UEFI_IMAGE_RECORD, + Link, + UEFI_IMAGE_RECORD_SIGNATURE + ); + if (NewImageRecord->StartAddress < ImageRecord->StartAddress) { + break; + } + + PrevImageRecordLink = ImageRecordLink; + } + + InsertHeadList (PrevImageRecordLink, &NewImageRecord->Link); + mImagePropertiesPrivateData.ImageRecordCount++; + + if (mImagePropertiesPrivateData.SectionCountMax < NewImageRecord->NumSegments) { + mImagePropertiesPrivateData.SectionCountMax = NewImageRecord->NumSegments; + } +} + /** Insert image record. @@ -573,13 +632,18 @@ CoreGetMemoryMapWithSeparatedImageSection ( **/ VOID InsertImageRecord ( - IN EFI_RUNTIME_IMAGE_ENTRY *RuntimeImage + IN LOADED_IMAGE_PRIVATE_DATA *Image, + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext ) { - EFI_STATUS Status; - IMAGE_PROPERTIES_RECORD *ImageRecord; - CHAR8 *PdbPointer; - UINT32 RequiredAlignment; + RETURN_STATUS PdbStatus; + EFI_RUNTIME_IMAGE_ENTRY *RuntimeImage; + UINT32 SectionAlignment; + UEFI_IMAGE_RECORD *ImageRecord; + CONST CHAR8 *PdbPointer; + UINT32 PdbSize; + + RuntimeImage = Image->RuntimeData; DEBUG ((DEBUG_VERBOSE, "InsertImageRecord - 0x%x\n", RuntimeImage)); @@ -588,71 +652,85 @@ InsertImageRecord ( return; } - ImageRecord = AllocatePool (sizeof (*ImageRecord)); - if (ImageRecord == NULL) { - return; - } - - InitializeListHead (&ImageRecord->Link); - InitializeListHead (&ImageRecord->CodeSegmentList); + DEBUG ((DEBUG_VERBOSE, "ImageRecordCount - 0x%x\n", mImagePropertiesPrivateData.ImageRecordCount)); - PdbPointer = PeCoffLoaderGetPdbPointer ((VOID *)(UINTN)RuntimeImage->ImageBase); - if (PdbPointer != NULL) { + PdbStatus = UefiImageGetSymbolsPath (ImageContext, &PdbPointer, &PdbSize); + if (!EFI_ERROR (PdbStatus)) { DEBUG ((DEBUG_VERBOSE, " Image - %a\n", PdbPointer)); } - RequiredAlignment = RUNTIME_PAGE_ALLOCATION_GRANULARITY; - Status = CreateImagePropertiesRecord ( - RuntimeImage->ImageBase, - RuntimeImage->ImageSize, - &RequiredAlignment, - ImageRecord - ); - - if (EFI_ERROR (Status)) { - if (Status == EFI_ABORTED) { - mMemoryAttributesTableEnable = FALSE; + // + // Get SectionAlignment + // + SectionAlignment = UefiImageGetSegmentAlignment (ImageContext); + + SetMemoryAttributesTableSectionAlignment (SectionAlignment); + if ((SectionAlignment & (RUNTIME_PAGE_ALLOCATION_GRANULARITY - 1)) != 0) { + DEBUG (( + DEBUG_WARN, + "!!!!!!!! InsertImageRecord - Section Alignment(0x%x) is not %dK !!!!!!!!\n", + SectionAlignment, RUNTIME_PAGE_ALLOCATION_GRANULARITY >> 10)); + if (!EFI_ERROR (PdbStatus)) { + DEBUG ((DEBUG_WARN, "!!!!!!!! Image - %a !!!!!!!!\n", PdbPointer)); } - Status = EFI_ABORTED; - goto Finish; + return; } - if (ImageRecord->CodeSegmentCount == 0) { - mMemoryAttributesTableEnable = FALSE; - DEBUG ((DEBUG_ERROR, "!!!!!!!! InsertImageRecord - CodeSegmentCount is 0 !!!!!!!!\n")); - if (PdbPointer != NULL) { - DEBUG ((DEBUG_ERROR, "!!!!!!!! Image - %a !!!!!!!!\n", PdbPointer)); - } - - Status = EFI_ABORTED; - goto Finish; + ImageRecord = UefiImageLoaderGetImageRecord (ImageContext); + if (ImageRecord == NULL) { + return ; } + UefiImageDebugPrintSegments (ImageContext); + UefiImageDebugPrintImageRecord (ImageRecord); + // - // Check overlap all section in ImageBase/Size + // Section order is guaranteed by the PE specification. + // Section validity (e.g. no overlap) is guaranteed by the PE specification. // - if (!IsImageRecordCodeSectionValid (ImageRecord)) { - DEBUG ((DEBUG_ERROR, "IsImageRecordCodeSectionValid - FAIL\n")); - Status = EFI_ABORTED; - goto Finish; - } - InsertTailList (&mImagePropertiesPrivateData.ImageRecordList, &ImageRecord->Link); - mImagePropertiesPrivateData.ImageRecordCount++; + InsertSortImageRecord (ImageRecord); +} - if (mImagePropertiesPrivateData.CodeSegmentCountMax < ImageRecord->CodeSegmentCount) { - mImagePropertiesPrivateData.CodeSegmentCountMax = ImageRecord->CodeSegmentCount; - } +/** + Find image record according to image base and size. - SortImageRecord (&mImagePropertiesPrivateData.ImageRecordList); + @param ImageBase Base of PE image + @param ImageSize Size of PE image -Finish: - if (EFI_ERROR (Status) && (ImageRecord != NULL)) { - DeleteImagePropertiesRecord (ImageRecord); + @return image record +**/ +STATIC +UEFI_IMAGE_RECORD * +FindImageRecord ( + IN EFI_PHYSICAL_ADDRESS ImageBase + ) +{ + UEFI_IMAGE_RECORD *ImageRecord; + LIST_ENTRY *ImageRecordLink; + LIST_ENTRY *ImageRecordList; + + ImageRecordList = &mImagePropertiesPrivateData.ImageRecordList; + + for (ImageRecordLink = ImageRecordList->ForwardLink; + ImageRecordLink != ImageRecordList; + ImageRecordLink = ImageRecordLink->ForwardLink) + { + ImageRecord = CR ( + ImageRecordLink, + UEFI_IMAGE_RECORD, + Link, + UEFI_IMAGE_RECORD_SIGNATURE + ); + + if (ImageBase == ImageRecord->StartAddress) + { + return ImageRecord; + } } - return; + return NULL; } /** @@ -665,7 +743,7 @@ RemoveImageRecord ( IN EFI_RUNTIME_IMAGE_ENTRY *RuntimeImage ) { - IMAGE_PROPERTIES_RECORD *ImageRecord; + UEFI_IMAGE_RECORD *ImageRecord; DEBUG ((DEBUG_VERBOSE, "RemoveImageRecord - 0x%x\n", RuntimeImage)); DEBUG ((DEBUG_VERBOSE, "RemoveImageRecord - 0x%016lx - 0x%016lx\n", (EFI_PHYSICAL_ADDRESS)(UINTN)RuntimeImage->ImageBase, RuntimeImage->ImageSize)); @@ -675,7 +753,7 @@ RemoveImageRecord ( return; } - ImageRecord = FindImageRecord ((EFI_PHYSICAL_ADDRESS)(UINTN)RuntimeImage->ImageBase, RuntimeImage->ImageSize, &mImagePropertiesPrivateData.ImageRecordList); + ImageRecord = FindImageRecord ((EFI_PHYSICAL_ADDRESS)(UINTN)RuntimeImage->ImageBase); if (ImageRecord == NULL) { DEBUG ((DEBUG_ERROR, "!!!!!!!! ImageRecord not found !!!!!!!!\n")); return; diff --git a/MdeModulePkg/Core/Dxe/Misc/MemoryProtection.c b/MdeModulePkg/Core/Dxe/Misc/MemoryProtection.c index 2c069cc12c..2d568b2463 100644 --- a/MdeModulePkg/Core/Dxe/Misc/MemoryProtection.c +++ b/MdeModulePkg/Core/Dxe/Misc/MemoryProtection.c @@ -40,8 +40,12 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #include #include +#include "Base.h" #include "DxeMain.h" +#include "Library/UefiImageLib.h" #include "Mem/HeapGuard.h" +#include "ProcessorBind.h" +#include "Uefi/UefiMultiPhase.h" // // Image type definitions @@ -213,113 +217,73 @@ SetUefiImageMemoryAttributes ( **/ VOID SetUefiImageProtectionAttributes ( - IN IMAGE_PROPERTIES_RECORD *ImageRecord + IN UEFI_IMAGE_RECORD *ImageRecord ) { - IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection; - LIST_ENTRY *ImageRecordCodeSectionLink; - LIST_ENTRY *ImageRecordCodeSectionEndLink; - LIST_ENTRY *ImageRecordCodeSectionList; - UINT64 CurrentBase; - UINT64 ImageEnd; - - ImageRecordCodeSectionList = &ImageRecord->CodeSegmentList; - - CurrentBase = ImageRecord->ImageBase; - ImageEnd = ImageRecord->ImageBase + ImageRecord->ImageSize; - - ImageRecordCodeSectionLink = ImageRecordCodeSectionList->ForwardLink; - ImageRecordCodeSectionEndLink = ImageRecordCodeSectionList; - while (ImageRecordCodeSectionLink != ImageRecordCodeSectionEndLink) { - ImageRecordCodeSection = CR ( - ImageRecordCodeSectionLink, - IMAGE_PROPERTIES_RECORD_CODE_SECTION, - Link, - IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE - ); - ImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink; - - ASSERT (CurrentBase <= ImageRecordCodeSection->CodeSegmentBase); - if (CurrentBase < ImageRecordCodeSection->CodeSegmentBase) { - // - // DATA - // - SetUefiImageMemoryAttributes ( - CurrentBase, - ImageRecordCodeSection->CodeSegmentBase - CurrentBase, - EFI_MEMORY_XP - ); - } + UEFI_IMAGE_RECORD_SEGMENT *ImageRecordSegment; + UINTN SectionAddress; + UINT32 Index; - // - // CODE - // + SectionAddress = ImageRecord->StartAddress; + for (Index = 0; Index < ImageRecord->NumSegments; Index++) { + ImageRecordSegment = &ImageRecord->Segments[Index]; SetUefiImageMemoryAttributes ( - ImageRecordCodeSection->CodeSegmentBase, - ImageRecordCodeSection->CodeSegmentSize, - EFI_MEMORY_RO + SectionAddress, + ImageRecordSegment->Size, + ImageRecordSegment->Attributes ); - CurrentBase = ImageRecordCodeSection->CodeSegmentBase + ImageRecordCodeSection->CodeSegmentSize; - } - // - // Last DATA - // - ASSERT (CurrentBase <= ImageEnd); - if (CurrentBase < ImageEnd) { - // - // DATA - // - SetUefiImageMemoryAttributes ( - CurrentBase, - ImageEnd - CurrentBase, - EFI_MEMORY_XP - ); + SectionAddress += ImageRecordSegment->Size; } - - return; } /** - Return the section alignment requirement for the PE image section type. - - @param[in] MemoryType PE/COFF image memory type + Return if the PE image section is aligned. - @retval The required section alignment for this memory type + @param[in] SectionAlignment PE/COFF section alignment + @param[in] MemoryType PE/COFF image memory type + @retval TRUE The PE image section is aligned. + @retval FALSE The PE image section is not aligned. **/ STATIC -UINT32 -GetMemoryProtectionSectionAlignment ( +BOOLEAN +IsMemoryProtectionSectionAligned ( + IN UINT32 SectionAlignment, IN EFI_MEMORY_TYPE MemoryType ) { - UINT32 SectionAlignment; + UINT32 PageAlignment; switch (MemoryType) { case EfiRuntimeServicesCode: case EfiACPIMemoryNVS: case EfiReservedMemoryType: - SectionAlignment = RUNTIME_PAGE_ALLOCATION_GRANULARITY; + PageAlignment = RUNTIME_PAGE_ALLOCATION_GRANULARITY; break; case EfiRuntimeServicesData: ASSERT (FALSE); - SectionAlignment = RUNTIME_PAGE_ALLOCATION_GRANULARITY; + PageAlignment = RUNTIME_PAGE_ALLOCATION_GRANULARITY; break; case EfiBootServicesCode: case EfiLoaderCode: - SectionAlignment = EFI_PAGE_SIZE; + PageAlignment = EFI_PAGE_SIZE; break; case EfiACPIReclaimMemory: default: ASSERT (FALSE); - SectionAlignment = EFI_PAGE_SIZE; + PageAlignment = EFI_PAGE_SIZE; break; } - return SectionAlignment; + if ((SectionAlignment & (PageAlignment - 1)) != 0) { + return FALSE; + } else { + return TRUE; + } } +// FIXME: Deduplicate /** Protect UEFI PE/COFF image. @@ -328,22 +292,26 @@ GetMemoryProtectionSectionAlignment ( **/ VOID ProtectUefiImage ( - IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage, - IN EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath + IN LOADED_IMAGE_PRIVATE_DATA *Image, + UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext ) { - IMAGE_PROPERTIES_RECORD *ImageRecord; - UINT32 ProtectionPolicy; - EFI_STATUS Status; - UINT32 RequiredAlignment; + RETURN_STATUS PdbStatus; + EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; + EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath; + UINT32 SectionAlignment; + UEFI_IMAGE_RECORD *ImageRecord; + CONST CHAR8 *PdbPointer; + UINT32 PdbSize; + BOOLEAN IsAligned; + UINT32 ProtectionPolicy; + + LoadedImage = &Image->Info; + LoadedImageDevicePath = Image->LoadedImageDevicePath; DEBUG ((DEBUG_INFO, "ProtectUefiImageCommon - 0x%x\n", LoadedImage)); DEBUG ((DEBUG_INFO, " - 0x%016lx - 0x%016lx\n", (EFI_PHYSICAL_ADDRESS)(UINTN)LoadedImage->ImageBase, LoadedImage->ImageSize)); - if (gCpu == NULL) { - return; - } - ProtectionPolicy = GetUefiImageProtectionPolicy (LoadedImage, LoadedImageDevicePath); switch (ProtectionPolicy) { case DO_NOT_PROTECT: @@ -355,36 +323,49 @@ ProtectUefiImage ( return; } - ImageRecord = AllocateZeroPool (sizeof (*ImageRecord)); - if (ImageRecord == NULL) { - return; + PdbStatus = UefiImageGetSymbolsPath (ImageContext, &PdbPointer, &PdbSize); + if (!RETURN_ERROR (PdbStatus)) { + DEBUG ((DEBUG_VERBOSE, " Image - %a\n", PdbPointer)); } - RequiredAlignment = GetMemoryProtectionSectionAlignment (LoadedImage->ImageCodeType); + // + // Get SectionAlignment + // + SectionAlignment = UefiImageGetSegmentAlignment (ImageContext); - Status = CreateImagePropertiesRecord ( - LoadedImage->ImageBase, - LoadedImage->ImageSize, - &RequiredAlignment, - ImageRecord - ); + IsAligned = IsMemoryProtectionSectionAligned (SectionAlignment, LoadedImage->ImageCodeType); + if (!IsAligned) { + DEBUG (( + DEBUG_VERBOSE, + "!!!!!!!! ProtectUefiImageCommon - Section Alignment(0x%x) is incorrect !!!!!!!!\n", + SectionAlignment)); + if (!RETURN_ERROR (PdbStatus)) { + DEBUG ((DEBUG_VERBOSE, "!!!!!!!! Image - %a !!!!!!!!\n", PdbPointer)); + } - if (EFI_ERROR (Status)) { - DEBUG ((DEBUG_ERROR, "%a failed to create image properties record\n", __func__)); - FreePool (ImageRecord); goto Finish; } - // - // CPU ARCH present. Update memory attribute directly. - // - SetUefiImageProtectionAttributes (ImageRecord); + ImageRecord = UefiImageLoaderGetImageRecord (ImageContext); + if (ImageRecord == NULL) { + return ; + } + + UefiImageDebugPrintSegments (ImageContext); + UefiImageDebugPrintImageRecord (ImageRecord); // // Record the image record in the list so we can undo the protections later // InsertTailList (&mProtectedImageRecordList, &ImageRecord->Link); + if (gCpu != NULL) { + // + // CPU ARCH present. Update memory attribute directly. + // + SetUefiImageProtectionAttributes (ImageRecord); + } + Finish: return; } @@ -401,30 +382,31 @@ UnprotectUefiImage ( IN EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath ) { - IMAGE_PROPERTIES_RECORD *ImageRecord; - LIST_ENTRY *ImageRecordLink; - - if (PcdGet32 (PcdImageProtectionPolicy) != 0) { - for (ImageRecordLink = mProtectedImageRecordList.ForwardLink; - ImageRecordLink != &mProtectedImageRecordList; - ImageRecordLink = ImageRecordLink->ForwardLink) - { - ImageRecord = CR ( - ImageRecordLink, - IMAGE_PROPERTIES_RECORD, - Link, - IMAGE_PROPERTIES_RECORD_SIGNATURE - ); - - if (ImageRecord->ImageBase == (EFI_PHYSICAL_ADDRESS)(UINTN)LoadedImage->ImageBase) { + UEFI_IMAGE_RECORD *ImageRecord; + LIST_ENTRY *ImageRecordLink; + + for (ImageRecordLink = mProtectedImageRecordList.ForwardLink; + ImageRecordLink != &mProtectedImageRecordList; + ImageRecordLink = ImageRecordLink->ForwardLink) { + ImageRecord = CR ( + ImageRecordLink, + UEFI_IMAGE_RECORD, + Link, + UEFI_IMAGE_RECORD_SIGNATURE + ); + + if (ImageRecord->StartAddress == (EFI_PHYSICAL_ADDRESS)(UINTN)LoadedImage->ImageBase) { + // TODO: Revise for removal (e.g. CpuDxe integration) + if (gCpu != NULL) { SetUefiImageMemoryAttributes ( - ImageRecord->ImageBase, - ImageRecord->ImageSize, + ImageRecord->StartAddress, + ImageRecord->EndAddress - ImageRecord->StartAddress, 0 ); - DeleteImagePropertiesRecord (ImageRecord); - return; } + RemoveEntryList (&ImageRecord->Link); + FreePool (ImageRecord); + return; } } } @@ -567,7 +549,6 @@ MergeMemoryMapForProtectionPolicy ( Remove exec permissions from all regions whose type is identified by PcdDxeNxMemoryProtectionPolicy. **/ -STATIC VOID InitializeDxeNxMemoryProtectionPolicy ( VOID @@ -775,12 +756,9 @@ MemoryProtectionCpuArchProtocolNotify ( IN VOID *Context ) { - EFI_STATUS Status; - EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; - EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath; - UINTN NoHandles; - EFI_HANDLE *HandleBuffer; - UINTN Index; + EFI_STATUS Status; + LIST_ENTRY *ImageRecordLink; + UEFI_IMAGE_RECORD *ImageRecord; DEBUG ((DEBUG_INFO, "MemoryProtectionCpuArchProtocolNotify:\n")); Status = CoreLocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&gCpu); @@ -804,41 +782,22 @@ MemoryProtectionCpuArchProtocolNotify ( goto Done; } - Status = gBS->LocateHandleBuffer ( - ByProtocol, - &gEfiLoadedImageProtocolGuid, - NULL, - &NoHandles, - &HandleBuffer - ); - if (EFI_ERROR (Status) && (NoHandles == 0)) { - goto Done; - } - - for (Index = 0; Index < NoHandles; Index++) { - Status = gBS->HandleProtocol ( - HandleBuffer[Index], - &gEfiLoadedImageProtocolGuid, - (VOID **)&LoadedImage - ); - if (EFI_ERROR (Status)) { - continue; - } - - Status = gBS->HandleProtocol ( - HandleBuffer[Index], - &gEfiLoadedImageDevicePathProtocolGuid, - (VOID **)&LoadedImageDevicePath + for (ImageRecordLink = mProtectedImageRecordList.ForwardLink; + ImageRecordLink != &mProtectedImageRecordList; + ImageRecordLink = ImageRecordLink->ForwardLink) { + ImageRecord = CR ( + ImageRecordLink, + UEFI_IMAGE_RECORD, + Link, + UEFI_IMAGE_RECORD_SIGNATURE ); - if (EFI_ERROR (Status)) { - LoadedImageDevicePath = NULL; - } - ProtectUefiImage (LoadedImage, LoadedImageDevicePath); + // + // CPU ARCH present. Update memory attribute directly. + // + SetUefiImageProtectionAttributes (ImageRecord); } - FreePool (HandleBuffer); - Done: CoreCloseEvent (Event); } diff --git a/MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c b/MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c index ca37bde482..24b7d6f953 100644 --- a/MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c +++ b/MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c @@ -8,6 +8,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include "PeiMain.h" +#include "ProcessorBind.h" /** @@ -1009,8 +1010,7 @@ MigratePeim ( EFI_FFS_FILE_HEADER *FileHeader; VOID *Pe32Data; VOID *ImageAddress; - CHAR8 *AsciiString; - UINTN Index; + UINT32 ImageSize; Status = EFI_SUCCESS; @@ -1018,24 +1018,10 @@ MigratePeim ( ASSERT (!IS_FFS_FILE2 (FileHeader)); ImageAddress = NULL; - PeiGetPe32Data (MigratedFileHandle, &ImageAddress); + PeiGetPe32Data (MigratedFileHandle, &ImageAddress, &ImageSize); if (ImageAddress != NULL) { - DEBUG_CODE_BEGIN (); - AsciiString = PeCoffLoaderGetPdbPointer (ImageAddress); - for (Index = 0; AsciiString[Index] != 0; Index++) { - if ((AsciiString[Index] == '\\') || (AsciiString[Index] == '/')) { - AsciiString = AsciiString + Index + 1; - Index = 0; - } else if (AsciiString[Index] == '.') { - AsciiString[Index] = 0; - } - } - - DEBUG ((DEBUG_VERBOSE, "%a", AsciiString)); - DEBUG_CODE_END (); - Pe32Data = (VOID *)((UINTN)ImageAddress - (UINTN)MigratedFileHandle + (UINTN)FileHandle); - Status = LoadAndRelocatePeCoffImageInPlace (Pe32Data, ImageAddress); + Status = LoadAndRelocateUefiImageInPlace (Pe32Data, ImageAddress, ImageSize); ASSERT_EFI_ERROR (Status); } @@ -1097,6 +1083,104 @@ ConvertStatusCodeCallbacks ( } } +/** + Migrates SEC modules in the given firmware volume. + + Migrating SECURITY_CORE files requires special treatment since they are not tracked for PEI dispatch. + + This functioun should be called after the FV has been copied to its post-memory location and the PEI Core FV list has + been updated. + + @param Private Pointer to the PeiCore's private data structure. + @param FvIndex The firmware volume index to migrate. + @param OrgFvHandle The handle to the firmware volume in temporary memory. + + @retval EFI_SUCCESS SEC modules were migrated successfully + @retval EFI_INVALID_PARAMETER The Private pointer is NULL or FvCount is invalid. + @retval EFI_NOT_FOUND Can't find valid FFS header. + +**/ +EFI_STATUS +EFIAPI +MigrateSecModulesInFv ( + IN PEI_CORE_INSTANCE *Private, + IN UINTN FvIndex, + IN UINTN OrgFvHandle + ) +{ + EFI_STATUS Status; + EFI_STATUS FindFileStatus; + EFI_PEI_FILE_HANDLE MigratedFileHandle; + EFI_PEI_FILE_HANDLE FileHandle; + UINT32 SectionAuthenticationStatus; + UINT32 FileSize; + VOID *OrgPe32SectionData; + VOID *Pe32SectionData; + UINT32 Pe32SectionDataSize; + EFI_FFS_FILE_HEADER *FfsFileHeader; + EFI_COMMON_SECTION_HEADER *Section; + BOOLEAN IsFfs3Fv; + UINTN SectionInstance; + + if (Private == NULL || FvIndex >= Private->FvCount) { + return EFI_INVALID_PARAMETER; + } + + do { + FindFileStatus = PeiFfsFindNextFile ( + GetPeiServicesTablePointer (), + EFI_FV_FILETYPE_SECURITY_CORE, + Private->Fv[FvIndex].FvHandle, + &MigratedFileHandle + ); + if (!EFI_ERROR (FindFileStatus ) && MigratedFileHandle != NULL) { + FileHandle = (EFI_PEI_FILE_HANDLE) ((UINTN) MigratedFileHandle - (UINTN) Private->Fv[FvIndex].FvHandle + OrgFvHandle); + FfsFileHeader = (EFI_FFS_FILE_HEADER *) MigratedFileHandle; + + DEBUG ((DEBUG_VERBOSE, " Migrating SEC_CORE MigratedFileHandle at 0x%x.\n", (UINTN) MigratedFileHandle)); + DEBUG ((DEBUG_VERBOSE, " FileHandle at 0x%x.\n", (UINTN) FileHandle)); + + IsFfs3Fv = CompareGuid (&Private->Fv[FvIndex].FvHeader->FileSystemGuid, &gEfiFirmwareFileSystem3Guid); + if (IS_FFS_FILE2 (FfsFileHeader)) { + ASSERT (FFS_FILE2_SIZE (FfsFileHeader) > 0x00FFFFFF); + if (!IsFfs3Fv) { + DEBUG ((DEBUG_ERROR, "It is a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &FfsFileHeader->Name)); + return EFI_NOT_FOUND; + } + Section = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) FfsFileHeader + sizeof (EFI_FFS_FILE_HEADER2)); + FileSize = FFS_FILE2_SIZE (FfsFileHeader) - sizeof (EFI_FFS_FILE_HEADER2); + } else { + Section = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) FfsFileHeader + sizeof (EFI_FFS_FILE_HEADER)); + FileSize = FFS_FILE_SIZE (FfsFileHeader) - sizeof (EFI_FFS_FILE_HEADER); + } + + SectionInstance = 1; + SectionAuthenticationStatus = 0; + Status = ProcessSection ( + GetPeiServicesTablePointer (), + EFI_SECTION_PE32, + &SectionInstance, + Section, + FileSize, + &Pe32SectionData, + &Pe32SectionDataSize, + &SectionAuthenticationStatus, + IsFfs3Fv + ); + + if (!EFI_ERROR (Status)) { + OrgPe32SectionData = (VOID *) ((UINTN) Pe32SectionData - (UINTN) MigratedFileHandle + (UINTN) FileHandle); + DEBUG ((DEBUG_VERBOSE, " PE32 section in migrated file at 0x%x.\n", (UINTN) Pe32SectionData)); + DEBUG ((DEBUG_VERBOSE, " PE32 section in original file at 0x%x.\n", (UINTN) OrgPe32SectionData)); + Status = LoadAndRelocateUefiImageInPlace (OrgPe32SectionData, Pe32SectionData, Pe32SectionDataSize); + ASSERT_EFI_ERROR (Status); + } + } + } while (!EFI_ERROR (FindFileStatus)); + + return EFI_SUCCESS; +} + /** Migrates PEIMs in the given firmware volume. diff --git a/MdeModulePkg/Core/Pei/FwVol/FwVol.c b/MdeModulePkg/Core/Pei/FwVol/FwVol.c index f7cc94c6eb..763920ce3d 100644 --- a/MdeModulePkg/Core/Pei/FwVol/FwVol.c +++ b/MdeModulePkg/Core/Pei/FwVol/FwVol.c @@ -35,7 +35,8 @@ PEI_FW_VOL_INSTANCE mPeiFfs2FwVol = { PeiFfsFvPpiGetFileInfo2, PeiFfsFvPpiFindSectionByType2, EFI_PEI_FIRMWARE_VOLUME_PPI_SIGNATURE, - EFI_PEI_FIRMWARE_VOLUME_PPI_REVISION + EFI_PEI_FIRMWARE_VOLUME_PPI_REVISION, + PeiFfsFvPpiFindSectionByType3 } }; @@ -52,7 +53,8 @@ PEI_FW_VOL_INSTANCE mPeiFfs3FwVol = { PeiFfsFvPpiGetFileInfo2, PeiFfsFvPpiFindSectionByType2, EFI_PEI_FIRMWARE_VOLUME_PPI_SIGNATURE, - EFI_PEI_FIRMWARE_VOLUME_PPI_REVISION + EFI_PEI_FIRMWARE_VOLUME_PPI_REVISION, + PeiFfsFvPpiFindSectionByType3 } }; @@ -771,6 +773,8 @@ VerifyGuidedSectionGuid ( @param SectionSize The file size to search. @param OutputBuffer A pointer to the discovered section, if successful. NULL if section not found + @param OutputSize The size of the discovered section, if successful. + 0 if section not found @param AuthenticationStatus Updated upon return to point to the authentication status for this section. @param IsFfs3Fv Indicates the FV format. @@ -786,6 +790,7 @@ ProcessSection ( IN EFI_COMMON_SECTION_HEADER *Section, IN UINTN SectionSize, OUT VOID **OutputBuffer, + OUT UINT32 *OutputSize, OUT UINT32 *AuthenticationStatus, IN BOOLEAN IsFfs3Fv ) @@ -803,11 +808,13 @@ ProcessSection ( EFI_GUID *SectionDefinitionGuid; BOOLEAN SectionCached; VOID *TempOutputBuffer; + UINT32 TempOutputSize; UINT32 TempAuthenticationStatus; UINT16 GuidedSectionAttributes; PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices); *OutputBuffer = NULL; + *OutputSize = 0; ParsedLength = 0; Index = 0; Status = EFI_NOT_FOUND; @@ -840,10 +847,13 @@ ProcessSection ( // // Got it! // + // FIXME: Size checks if (IS_SECTION2 (Section)) { *OutputBuffer = (VOID *)((UINT8 *)Section + sizeof (EFI_COMMON_SECTION_HEADER2)); + *OutputSize = SECTION2_SIZE (Section) - sizeof (EFI_COMMON_SECTION_HEADER2); } else { *OutputBuffer = (VOID *)((UINT8 *)Section + sizeof (EFI_COMMON_SECTION_HEADER)); + *OutputSize = SECTION_SIZE (Section) - sizeof (EFI_COMMON_SECTION_HEADER); } return EFI_SUCCESS; @@ -886,11 +896,13 @@ ProcessSection ( PpiOutput, PpiOutputSize, &TempOutputBuffer, + &TempOutputSize, &TempAuthenticationStatus, IsFfs3Fv ); if (!EFI_ERROR (Status)) { *OutputBuffer = TempOutputBuffer; + *OutputSize = TempOutputSize; *AuthenticationStatus = TempAuthenticationStatus | Authentication; return EFI_SUCCESS; } @@ -973,11 +985,13 @@ ProcessSection ( PpiOutput, PpiOutputSize, &TempOutputBuffer, + &TempOutputSize, &TempAuthenticationStatus, IsFfs3Fv ); if (!EFI_ERROR (Status)) { *OutputBuffer = TempOutputBuffer; + *OutputSize = TempOutputSize; *AuthenticationStatus = TempAuthenticationStatus | Authentication; return EFI_SUCCESS; } @@ -1060,6 +1074,38 @@ PeiFfsFindSectionData3 ( OUT VOID **SectionData, OUT UINT32 *AuthenticationStatus ) +{ + UINT32 SectionDataSize; + + return PeiFfsFindSectionData4 (PeiServices, SectionType, SectionInstance, FileHandle, SectionData, &SectionDataSize, AuthenticationStatus); +} + +/** + Searches for the next matching section within the specified file. + + @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation. + @param SectionType The value of the section type to find. + @param SectionInstance Section instance to find. + @param FileHandle Handle of the firmware file to search. + @param SectionData A pointer to the discovered section, if successful. + @param SectionDataSize The size of the discovered section, if successful. + @param AuthenticationStatus A pointer to the authentication status for this section. + + @retval EFI_SUCCESS The section was found. + @retval EFI_NOT_FOUND The section was not found. + +**/ +EFI_STATUS +EFIAPI +PeiFfsFindSectionData4 ( + IN CONST EFI_PEI_SERVICES **PeiServices, + IN EFI_SECTION_TYPE SectionType, + IN UINTN SectionInstance, + IN EFI_PEI_FILE_HANDLE FileHandle, + OUT VOID **SectionData, + OUT UINT32 *SectionDataSize, + OUT UINT32 *AuthenticationStatus + ) { PEI_CORE_FV_HANDLE *CoreFvHandle; @@ -1071,7 +1117,7 @@ PeiFfsFindSectionData3 ( if ((CoreFvHandle->FvPpi->Signature == EFI_PEI_FIRMWARE_VOLUME_PPI_SIGNATURE) && (CoreFvHandle->FvPpi->Revision == EFI_PEI_FIRMWARE_VOLUME_PPI_REVISION)) { - return CoreFvHandle->FvPpi->FindSectionByType2 (CoreFvHandle->FvPpi, SectionType, SectionInstance, FileHandle, SectionData, AuthenticationStatus); + return CoreFvHandle->FvPpi->FindSectionByType3 (CoreFvHandle->FvPpi, SectionType, SectionInstance, FileHandle, SectionData, SectionDataSize, AuthenticationStatus); } // @@ -2028,6 +2074,57 @@ PeiFfsFvPpiFindSectionByType2 ( OUT VOID **SectionData, OUT UINT32 *AuthenticationStatus ) +{ + UINT32 SectionDataSize; + + // FIXME: Deprecate + return PeiFfsFvPpiFindSectionByType3 ( + This, + SearchType, + SearchInstance, + FileHandle, + SectionData, + &SectionDataSize, + AuthenticationStatus + ); +} + +/** + Find the next matching section in the firmware file. + + This service enables PEI modules to discover sections + of a given instance and type within a valid file. + + @param This Points to this instance of the + EFI_PEI_FIRMWARE_VOLUME_PPI. + @param SearchType A filter to find only sections of this + type. + @param SearchInstance A filter to find the specific instance + of sections. + @param FileHandle Handle of firmware file in which to + search. + @param SectionData Updated upon return to point to the + section found. + @param SectionDataSize Updated upon return to point to the + section size found. + @param AuthenticationStatus Updated upon return to point to the + authentication status for this section. + + @retval EFI_SUCCESS Section was found. + @retval EFI_NOT_FOUND Section of the specified type was not + found. SectionData contains NULL. +**/ +EFI_STATUS +EFIAPI +PeiFfsFvPpiFindSectionByType3 ( + IN CONST EFI_PEI_FIRMWARE_VOLUME_PPI *This, + IN EFI_SECTION_TYPE SearchType, + IN UINTN SearchInstance, + IN EFI_PEI_FILE_HANDLE FileHandle, + OUT VOID **SectionData, + OUT UINT32 *SectionDataSize, + OUT UINT32 *AuthenticationStatus + ) { EFI_STATUS Status; EFI_FFS_FILE_HEADER *FfsFileHeader; @@ -2077,6 +2174,7 @@ PeiFfsFvPpiFindSectionByType2 ( Section, FileSize, SectionData, + SectionDataSize, &ExtractedAuthenticationStatus, FwVolInstance->IsFfs3Fv ); diff --git a/MdeModulePkg/Core/Pei/FwVol/FwVol.h b/MdeModulePkg/Core/Pei/FwVol/FwVol.h index 7d1dc9cba1..02a732845e 100644 --- a/MdeModulePkg/Core/Pei/FwVol/FwVol.h +++ b/MdeModulePkg/Core/Pei/FwVol/FwVol.h @@ -185,6 +185,43 @@ PeiFfsFvPpiFindSectionByType2 ( OUT UINT32 *AuthenticationStatus ); +/** + Find the next matching section in the firmware file. + + This service enables PEI modules to discover sections + of a given instance and type within a valid file. + + @param This Points to this instance of the + EFI_PEI_FIRMWARE_VOLUME_PPI. + @param SearchType A filter to find only sections of this + type. + @param SearchInstance A filter to find the specific instance + of sections. + @param FileHandle Handle of firmware file in which to + search. + @param SectionData Updated upon return to point to the + section found. + @param SectionDataSize Updated upon return to point to the + section size found. + @param AuthenticationStatus Updated upon return to point to the + authentication status for this section. + + @retval EFI_SUCCESS Section was found. + @retval EFI_NOT_FOUND Section of the specified type was not + found. SectionData contains NULL. +**/ +EFI_STATUS +EFIAPI +PeiFfsFvPpiFindSectionByType3 ( + IN CONST EFI_PEI_FIRMWARE_VOLUME_PPI *This, + IN EFI_SECTION_TYPE SearchType, + IN UINTN SearchInstance, + IN EFI_PEI_FILE_HANDLE FileHandle, + OUT VOID **SectionData, + OUT UINT32 *SectionDataSize, + OUT UINT32 *AuthenticationStatus + ); + /** Returns information about a specific file. diff --git a/MdeModulePkg/Core/Pei/Image/Image.c b/MdeModulePkg/Core/Pei/Image/Image.c index cee9f09c6e..ca57bfaefc 100644 --- a/MdeModulePkg/Core/Pei/Image/Image.c +++ b/MdeModulePkg/Core/Pei/Image/Image.c @@ -18,40 +18,6 @@ EFI_PEI_PPI_DESCRIPTOR gPpiLoadFilePpiList = { &mPeiLoadImagePpi }; -/** - - Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file. - The function is used for XIP code to have optimized memory copy. - - @param FileHandle - The handle to the PE/COFF file - @param FileOffset - The offset, in bytes, into the file to read - @param ReadSize - The number of bytes to read from the file starting at FileOffset - @param Buffer - A pointer to the buffer to read the data into. - - @return EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset - -**/ -EFI_STATUS -EFIAPI -PeiImageRead ( - IN VOID *FileHandle, - IN UINTN FileOffset, - IN UINTN *ReadSize, - OUT VOID *Buffer - ) -{ - CHAR8 *Destination8; - CHAR8 *Source8; - - Destination8 = Buffer; - Source8 = (CHAR8 *)((UINTN)FileHandle + FileOffset); - if (Destination8 != Source8) { - CopyMem (Destination8, Source8, *ReadSize); - } - - return EFI_SUCCESS; -} - /** To check memory usage bit map array to figure out if the memory range the image will be loaded in is available or not. If memory range is available, the function will mark the corresponding bits to 1 which indicates the memory range is used. @@ -135,111 +101,36 @@ CheckAndMarkFixLoadingMemoryUsageBitMap ( **/ EFI_STATUS -GetPeCoffImageFixLoadingAssignedAddress ( - IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext, - IN PEI_CORE_INSTANCE *Private +GetUefiImageFixLoadingAssignedAddress ( + OUT EFI_PHYSICAL_ADDRESS *LoadAddress, + IN UINT64 ValueInSectionHeader, + IN UINT32 ImageDestSize, + IN PEI_CORE_INSTANCE *Private ) { - UINTN SectionHeaderOffset; - EFI_STATUS Status; - EFI_IMAGE_SECTION_HEADER SectionHeader; - EFI_IMAGE_OPTIONAL_HEADER_UNION *ImgHdr; - EFI_PHYSICAL_ADDRESS FixLoadingAddress; - UINT16 Index; - UINTN Size; - UINT16 NumberOfSections; - UINT64 ValueInSectionHeader; + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS FixLoadingAddress; - FixLoadingAddress = 0; - Status = EFI_NOT_FOUND; - - // - // Get PeHeader pointer - // - ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((CHAR8 *)ImageContext->Handle + ImageContext->PeCoffHeaderOffset); - if (ImageContext->IsTeImage) { + if ((INT64)PcdGet64(PcdLoadModuleAtFixAddressEnable) > 0) { // - // for TE image, the fix loading address is saved in first section header that doesn't point - // to code section. + // When LMFA feature is configured as Load Module at Fixed Absolute Address mode, PointerToRelocations & PointerToLineNumbers field + // hold the absolute address of image base running in memory // - SectionHeaderOffset = sizeof (EFI_TE_IMAGE_HEADER); - NumberOfSections = ImgHdr->Te.NumberOfSections; + FixLoadingAddress = ValueInSectionHeader; } else { - SectionHeaderOffset = ImageContext->PeCoffHeaderOffset + - sizeof (UINT32) + - sizeof (EFI_IMAGE_FILE_HEADER) + - ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader; - NumberOfSections = ImgHdr->Pe32.FileHeader.NumberOfSections; - } - - // - // Get base address from the first section header that doesn't point to code section. - // - for (Index = 0; Index < NumberOfSections; Index++) { // - // Read section header from file + // When LMFA feature is configured as Load Module at Fixed offset mode, PointerToRelocations & PointerToLineNumbers field + // hold the offset relative to a platform-specific top address. // - Size = sizeof (EFI_IMAGE_SECTION_HEADER); - Status = ImageContext->ImageRead ( - ImageContext->Handle, - SectionHeaderOffset, - &Size, - &SectionHeader - ); - if (EFI_ERROR (Status)) { - return Status; - } - - Status = EFI_NOT_FOUND; - - if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_CNT_CODE) == 0) { - // - // Build tool will save the address in PointerToRelocations & PointerToLineNumbers fields in the first section header - // that doesn't point to code section in image header, as well as ImageBase field of image header. A notable thing is - // that for PEIM, the value in ImageBase field may not be equal to the value in PointerToRelocations & PointerToLineNumbers because - // for XIP PEIM, ImageBase field holds the image base address running on the Flash. And PointerToRelocations & PointerToLineNumbers - // hold the image base address when it is shadow to the memory. And there is an assumption that when the feature is enabled, if a - // module is assigned a loading address by tools, PointerToRelocations & PointerToLineNumbers fields should NOT be Zero, or - // else, these 2 fields should be set to Zero - // - ValueInSectionHeader = ReadUnaligned64 ((UINT64 *)&SectionHeader.PointerToRelocations); - if (ValueInSectionHeader != 0) { - // - // Found first section header that doesn't point to code section. - // - if ((INT64)PcdGet64 (PcdLoadModuleAtFixAddressEnable) > 0) { - // - // When LMFA feature is configured as Load Module at Fixed Absolute Address mode, PointerToRelocations & PointerToLineNumbers field - // hold the absolute address of image base running in memory - // - FixLoadingAddress = ValueInSectionHeader; - } else { - // - // When LMFA feature is configured as Load Module at Fixed offset mode, PointerToRelocations & PointerToLineNumbers field - // hold the offset relative to a platform-specific top address. - // - FixLoadingAddress = (EFI_PHYSICAL_ADDRESS)(Private->LoadModuleAtFixAddressTopAddress + (INT64)ValueInSectionHeader); - } - - // - // Check if the memory range is available. - // - Status = CheckAndMarkFixLoadingMemoryUsageBitMap (Private, FixLoadingAddress, (UINT32)ImageContext->ImageSize); - if (!EFI_ERROR (Status)) { - // - // The assigned address is valid. Return the specified loading address - // - ImageContext->ImageAddress = FixLoadingAddress; - } - } - - break; - } - - SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER); + FixLoadingAddress = (EFI_PHYSICAL_ADDRESS)(Private->LoadModuleAtFixAddressTopAddress + ValueInSectionHeader); } + // + // Check if the memory range is available. + // + Status = CheckAndMarkFixLoadingMemoryUsageBitMap (Private, FixLoadingAddress, ImageDestSize); + *LoadAddress = FixLoadingAddress; - DEBUG ((DEBUG_INFO|DEBUG_LOAD, "LOADING MODULE FIXED INFO: Loading module at fixed address 0x%11p. Status= %r \n", (VOID *)(UINTN)FixLoadingAddress, Status)); + DEBUG ((EFI_D_INFO|EFI_D_LOAD, "LOADING MODULE FIXED INFO: Loading module at fixed address 0x%11p. Status= %r \n", (VOID *)(UINTN)FixLoadingAddress, Status)); return Status; } @@ -262,38 +153,49 @@ GetPeCoffImageFixLoadingAssignedAddress ( **/ EFI_STATUS -LoadAndRelocatePeCoffImage ( +LoadAndRelocateUefiImage ( IN EFI_PEI_FILE_HANDLE FileHandle, IN VOID *Pe32Data, - OUT EFI_PHYSICAL_ADDRESS *ImageAddress, - OUT UINT64 *ImageSize, - OUT EFI_PHYSICAL_ADDRESS *EntryPoint + IN UINT32 Pe32DataSize, + OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext, + OUT EFI_PHYSICAL_ADDRESS *ImageAddress ) { EFI_STATUS Status; - PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; + BOOLEAN Success; PEI_CORE_INSTANCE *Private; - UINT64 AlignImageSize; + UINT32 ImageSize; + UINT32 ImageAlignment; + UINT64 ValueInSectionHeader; BOOLEAN IsXipImage; EFI_STATUS ReturnStatus; BOOLEAN IsS3Boot; BOOLEAN IsPeiModule; BOOLEAN IsRegisterForShadow; EFI_FV_FILE_INFO FileInfo; + UINT32 DestinationPages; + UINT32 DestinationSize; + EFI_PHYSICAL_ADDRESS Destination; + UINT16 Machine; + BOOLEAN LoadDynamically; Private = PEI_CORE_INSTANCE_FROM_PS_THIS (GetPeiServicesTablePointer ()); ReturnStatus = EFI_SUCCESS; - IsXipImage = FALSE; - ZeroMem (&ImageContext, sizeof (ImageContext)); - ImageContext.Handle = Pe32Data; - ImageContext.ImageRead = PeiImageRead; - Status = PeCoffLoaderGetImageInfo (&ImageContext); + Status = UefiImageInitializeContext (ImageContext, Pe32Data, Pe32DataSize); if (EFI_ERROR (Status)) { return Status; } + Machine = UefiImageGetMachine (ImageContext); + + if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Machine)) { + if (!EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED (Machine)) { + return EFI_UNSUPPORTED; + } + } + // // Initialize local IsS3Boot and IsRegisterForShadow variable // @@ -312,9 +214,7 @@ LoadAndRelocatePeCoffImage ( // // XIP image that ImageAddress is same to Image handle. // - if (ImageContext.ImageAddress == (EFI_PHYSICAL_ADDRESS)(UINTN)Pe32Data) { - IsXipImage = TRUE; - } + IsXipImage = UefiImageImageIsInplace (ImageContext); // // Get file type first @@ -336,7 +236,7 @@ LoadAndRelocatePeCoffImage ( // // When Image has no reloc section, it can't be relocated into memory. // - if (ImageContext.RelocationsStripped && (Private->PeiMemoryInstalled) && + if (UefiImageGetRelocsStripped (ImageContext) && (Private->PeiMemoryInstalled) && ((!IsPeiModule) || PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes) || (!IsS3Boot && (PcdGetBool (PcdShadowPeimOnBoot) || IsRegisterForShadow)) || (IsS3Boot && PcdGetBool (PcdShadowPeimOnS3Boot))) @@ -345,125 +245,95 @@ LoadAndRelocatePeCoffImage ( DEBUG ((DEBUG_INFO|DEBUG_LOAD, "The image at 0x%08x without reloc section can't be loaded into memory\n", (UINTN)Pe32Data)); } - // - // Set default base address to current image address. - // - ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)Pe32Data; + LoadDynamically = FALSE; + ImageSize = UefiImageGetImageSize (ImageContext); + DestinationPages = EFI_SIZE_TO_PAGES (ImageSize); + DestinationSize = EFI_PAGES_TO_SIZE (DestinationPages); // // Allocate Memory for the image when memory is ready, and image is relocatable. // On normal boot, PcdShadowPeimOnBoot decides whether load PEIM or PeiCore into memory. // On S3 boot, PcdShadowPeimOnS3Boot decides whether load PEIM or PeiCore into memory. // - if ((!ImageContext.RelocationsStripped) && (Private->PeiMemoryInstalled) && + if ((!UefiImageGetRelocsStripped (ImageContext)) && (Private->PeiMemoryInstalled) && ((!IsPeiModule) || PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes) || (!IsS3Boot && (PcdGetBool (PcdShadowPeimOnBoot) || IsRegisterForShadow)) || (IsS3Boot && PcdGetBool (PcdShadowPeimOnS3Boot))) ) { - // - // Allocate more buffer to avoid buffer overflow. - // - if (ImageContext.IsTeImage) { - AlignImageSize = ImageContext.ImageSize + ((EFI_TE_IMAGE_HEADER *)Pe32Data)->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER); - } else { - AlignImageSize = ImageContext.ImageSize; - } + Success = FALSE; - if (ImageContext.SectionAlignment > EFI_PAGE_SIZE) { - AlignImageSize += ImageContext.SectionAlignment; - } + if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0 && (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME)) { + Status = UefiImageGetFixedAddress (ImageContext, &ValueInSectionHeader); + if (!RETURN_ERROR (Status)) { + Status = GetUefiImageFixLoadingAssignedAddress(&Destination, ValueInSectionHeader, DestinationSize, Private); + } - if ((PcdGet64 (PcdLoadModuleAtFixAddressEnable) != 0) && (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME)) { - Status = GetPeCoffImageFixLoadingAssignedAddress (&ImageContext, Private); - if (EFI_ERROR (Status)) { - DEBUG ((DEBUG_INFO|DEBUG_LOAD, "LOADING MODULE FIXED ERROR: Failed to load module at fixed address. \n")); - // - // The PEIM is not assigned valid address, try to allocate page to load it. - // - Status = PeiServicesAllocatePages ( - EfiBootServicesCode, - EFI_SIZE_TO_PAGES ((UINT32)AlignImageSize), - &ImageContext.ImageAddress - ); + if (!EFI_ERROR (Status)){ + Success = Destination == UefiImageGetPreferredAddress (ImageContext); + + if (!Success) { + DEBUG ((DEBUG_INFO|DEBUG_LOAD, "LOADING MODULE FIXED ERROR: Loading module at fixed address failed since relocs have been stripped.\n")); + } + } else { + DEBUG ((EFI_D_INFO|EFI_D_LOAD, "LOADING MODULE FIXED ERROR: Failed to load module at fixed address. \n")); } - } else { - Status = PeiServicesAllocatePages ( - EfiBootServicesCode, - EFI_SIZE_TO_PAGES ((UINT32)AlignImageSize), - &ImageContext.ImageAddress - ); } - if (!EFI_ERROR (Status)) { + if (!Success) { // - // Adjust the Image Address to make sure it is section alignment. + // Allocate more buffer to avoid buffer overflow. // - if (ImageContext.SectionAlignment > EFI_PAGE_SIZE) { - ImageContext.ImageAddress = - (ImageContext.ImageAddress + ImageContext.SectionAlignment - 1) & - ~((UINTN)ImageContext.SectionAlignment - 1); - } + ImageAlignment = UefiImageGetSegmentAlignment (ImageContext); + + Destination = (UINTN)AllocateAlignedCodePages ( + DestinationPages, + ImageAlignment + ); + Success = Destination != 0; + } + if (Success) { + LoadDynamically = TRUE; // - // Fix alignment requirement when Load IPF TeImage into memory. - // Skip the reserved space for the stripped PeHeader when load TeImage into memory. + // Load the image to our new buffer // - if (ImageContext.IsTeImage) { - ImageContext.ImageAddress = ImageContext.ImageAddress + - ((EFI_TE_IMAGE_HEADER *)Pe32Data)->StrippedSize - - sizeof (EFI_TE_IMAGE_HEADER); + Status = UefiImageLoadImageForExecution ( + ImageContext, + (VOID *) (UINTN)Destination, + DestinationSize, + NULL, + 0 + ); + if (EFI_ERROR (Status)) { + return Status; } } else { // // No enough memory resource. // - if (IsXipImage) { - // - // XIP image can still be invoked. - // - ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)Pe32Data; - ReturnStatus = EFI_WARN_BUFFER_TOO_SMALL; - } else { + if (!IsXipImage) { // // Non XIP image can't be loaded because no enough memory is allocated. // ASSERT (FALSE); return EFI_OUT_OF_RESOURCES; } + // + // XIP image can still be invoked. + // + ReturnStatus = EFI_WARN_BUFFER_TOO_SMALL; } } - // - // Load the image to our new buffer - // - Status = PeCoffLoaderLoadImage (&ImageContext); - if (EFI_ERROR (Status)) { - if (ImageContext.ImageError == IMAGE_ERROR_INVALID_SECTION_ALIGNMENT) { - DEBUG ((DEBUG_ERROR, "PEIM Image Address 0x%11p doesn't meet with section alignment 0x%x.\n", (VOID *)(UINTN)ImageContext.ImageAddress, ImageContext.SectionAlignment)); + if (!LoadDynamically) { + Status = UefiImageLoadImageInplace (ImageContext); + if (EFI_ERROR (Status)) { + return Status; } - - return Status; } - // - // Relocate the image in our new buffer - // - Status = PeCoffLoaderRelocateImage (&ImageContext); - if (EFI_ERROR (Status)) { - return Status; - } - - // - // Flush the instruction cache so the image data is written before we execute it - // - if (ImageContext.ImageAddress != (EFI_PHYSICAL_ADDRESS)(UINTN)Pe32Data) { - InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize); - } - - *ImageAddress = ImageContext.ImageAddress; - *ImageSize = ImageContext.ImageSize; - *EntryPoint = ImageContext.EntryPoint; + *ImageAddress = UefiImageLoaderGetImageAddress (ImageContext); return ReturnStatus; } @@ -479,50 +349,30 @@ LoadAndRelocatePeCoffImage ( **/ EFI_STATUS -LoadAndRelocatePeCoffImageInPlace ( +LoadAndRelocateUefiImageInPlace ( IN VOID *Pe32Data, - IN VOID *ImageAddress + IN VOID *ImageAddress, + IN UINT32 ImageSize ) { EFI_STATUS Status; - PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; + UEFI_IMAGE_LOADER_IMAGE_CONTEXT ImageContext; - ZeroMem (&ImageContext, sizeof (ImageContext)); - ImageContext.Handle = Pe32Data; - ImageContext.ImageRead = PeiImageRead; + ASSERT (Pe32Data != ImageAddress); - Status = PeCoffLoaderGetImageInfo (&ImageContext); - if (EFI_ERROR (Status)) { - ASSERT_EFI_ERROR (Status); - return Status; - } - - ImageContext.ImageAddress = (PHYSICAL_ADDRESS)(UINTN)ImageAddress; - - // - // Load the image in place - // - Status = PeCoffLoaderLoadImage (&ImageContext); - if (EFI_ERROR (Status)) { - ASSERT_EFI_ERROR (Status); - return Status; - } + CopyMem (ImageAddress, Pe32Data, ImageSize); - // - // Relocate the image in place - // - Status = PeCoffLoaderRelocateImage (&ImageContext); + Status = UefiImageInitializeContext (&ImageContext, ImageAddress, ImageSize); if (EFI_ERROR (Status)) { ASSERT_EFI_ERROR (Status); return Status; } // - // Flush the instruction cache so the image data is written before we execute it + // Load the image in place // - if (ImageContext.ImageAddress != (EFI_PHYSICAL_ADDRESS)(UINTN)Pe32Data) { - InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize); - } + Status = UefiImageRelocateImageInplaceForExecution (&ImageContext); + ASSERT_EFI_ERROR (Status); return Status; } @@ -540,7 +390,8 @@ LoadAndRelocatePeCoffImageInPlace ( EFI_STATUS PeiGetPe32Data ( IN EFI_PEI_FILE_HANDLE FileHandle, - OUT VOID **Pe32Data + OUT VOID **Pe32Data, + OUT UINT32 *Pe32DataSize ) { EFI_STATUS Status; @@ -562,22 +413,24 @@ PeiGetPe32Data ( // Try to find a first exe section (if PcdPeiCoreImageLoaderSearchTeSectionFirst // is true, TE will be searched first). // - Status = PeiServicesFfsFindSectionData3 ( + Status = PeiServicesFfsFindSectionData4 ( SearchType1, 0, FileHandle, Pe32Data, + Pe32DataSize, &AuthenticationState ); // // If we didn't find a first exe section, try to find the second exe section. // if (EFI_ERROR (Status)) { - Status = PeiServicesFfsFindSectionData3 ( + Status = PeiServicesFfsFindSectionData4 ( SearchType2, 0, FileHandle, Pe32Data, + Pe32DataSize, &AuthenticationState ); } @@ -617,15 +470,13 @@ PeiLoadImageLoadImage ( { EFI_STATUS Status; VOID *Pe32Data; + UINT32 Pe32DataSize; EFI_PHYSICAL_ADDRESS ImageAddress; - UINT64 ImageSize; - EFI_PHYSICAL_ADDRESS ImageEntryPoint; - UINT16 Machine; EFI_SECTION_TYPE SearchType1; EFI_SECTION_TYPE SearchType2; + UEFI_IMAGE_LOADER_IMAGE_CONTEXT ImageContext; *EntryPoint = 0; - ImageSize = 0; *AuthenticationState = 0; if (FeaturePcdGet (PcdPeiCoreImageLoaderSearchTeSectionFirst)) { @@ -640,22 +491,24 @@ PeiLoadImageLoadImage ( // Try to find a first exe section (if PcdPeiCoreImageLoaderSearchTeSectionFirst // is true, TE will be searched first). // - Status = PeiServicesFfsFindSectionData3 ( + Status = PeiServicesFfsFindSectionData4 ( SearchType1, 0, FileHandle, &Pe32Data, + &Pe32DataSize, AuthenticationState ); // // If we didn't find a first exe section, try to find the second exe section. // if (EFI_ERROR (Status)) { - Status = PeiServicesFfsFindSectionData3 ( + Status = PeiServicesFfsFindSectionData4 ( SearchType2, 0, FileHandle, &Pe32Data, + &Pe32DataSize, AuthenticationState ); if (EFI_ERROR (Status)) { @@ -672,12 +525,12 @@ PeiLoadImageLoadImage ( // // If memory is installed, perform the shadow operations // - Status = LoadAndRelocatePeCoffImage ( + Status = LoadAndRelocateUefiImage ( FileHandle, Pe32Data, - &ImageAddress, - &ImageSize, - &ImageEntryPoint + Pe32DataSize, + &ImageContext, + &ImageAddress ); if (EFI_ERROR (Status)) { @@ -687,83 +540,47 @@ PeiLoadImageLoadImage ( // // Got the entry point from the loaded Pe32Data // - Pe32Data = (VOID *)((UINTN)ImageAddress); - *EntryPoint = ImageEntryPoint; - - Machine = PeCoffLoaderGetMachineType (Pe32Data); - - if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Machine)) { - if (!EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED (Machine)) { - return EFI_UNSUPPORTED; - } - } + *EntryPoint = UefiImageLoaderGetImageEntryPoint (&ImageContext); if (ImageAddressArg != NULL) { *ImageAddressArg = ImageAddress; } if (ImageSizeArg != NULL) { - *ImageSizeArg = ImageSize; + *ImageSizeArg =UefiImageGetImageSize (&ImageContext); } DEBUG_CODE_BEGIN (); - CHAR8 *AsciiString; - CHAR8 EfiFileName[512]; - INT32 Index; - INT32 StartIndex; + CHAR8 EfiFileName[512]; + UINT16 Machine; + + Machine = UefiImageGetMachine (&ImageContext); - // - // Print debug message: Loading PEIM at 0x12345678 EntryPoint=0x12345688 Driver.efi - // - if (Machine != EFI_IMAGE_MACHINE_IA64) { - DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Loading PEIM at 0x%11p EntryPoint=0x%11p ", (VOID *)(UINTN)ImageAddress, (VOID *)(UINTN)*EntryPoint)); - } else { // - // For IPF Image, the real entry point should be print. + // Print debug message: Loading PEIM at 0x12345678 EntryPoint=0x12345688 Driver.efi // - DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Loading PEIM at 0x%11p EntryPoint=0x%11p ", (VOID *)(UINTN)ImageAddress, (VOID *)(UINTN)(*(UINT64 *)(UINTN)*EntryPoint))); - } - - // - // Print Module Name by PeImage PDB file name. - // - AsciiString = PeCoffLoaderGetPdbPointer (Pe32Data); - - if (AsciiString != NULL) { - StartIndex = 0; - for (Index = 0; AsciiString[Index] != 0; Index++) { - if ((AsciiString[Index] == '\\') || (AsciiString[Index] == '/')) { - StartIndex = Index + 1; - } + if (Machine != EFI_IMAGE_MACHINE_IA64) { + DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Loading PEIM at 0x%11p EntryPoint=0x%11p ", (VOID *)(UINTN)ImageAddress, (VOID *)(UINTN)*EntryPoint)); + } else { + // + // For IPF Image, the real entry point should be print. + // + DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Loading PEIM at 0x%11p EntryPoint=0x%11p ", (VOID *)(UINTN)ImageAddress, (VOID *)(UINTN)(*(UINT64 *)(UINTN)*EntryPoint))); } // - // Copy the PDB file name to our temporary string, and replace .pdb with .efi - // The PDB file name is limited in the range of 0~511. - // If the length is bigger than 511, trim the redundant characters to avoid overflow in array boundary. + // Print Module Name by PeImage PDB file name. // - for (Index = 0; Index < sizeof (EfiFileName) - 4; Index++) { - EfiFileName[Index] = AsciiString[Index + StartIndex]; - if (EfiFileName[Index] == 0) { - EfiFileName[Index] = '.'; - } - - if (EfiFileName[Index] == '.') { - EfiFileName[Index + 1] = 'e'; - EfiFileName[Index + 2] = 'f'; - EfiFileName[Index + 3] = 'i'; - EfiFileName[Index + 4] = 0; - break; - } - } + Status = UefiImageGetModuleNameFromSymbolsPath ( + &ImageContext, + EfiFileName, + sizeof (EfiFileName) + ); - if (Index == sizeof (EfiFileName) - 4) { - EfiFileName[Index] = 0; + if (!RETURN_ERROR (Status)) { + DEBUG ((DEBUG_INFO | DEBUG_LOAD, "%a", EfiFileName)); } - DEBUG ((DEBUG_INFO | DEBUG_LOAD, "%a", EfiFileName)); - } - DEBUG_CODE_END (); DEBUG ((DEBUG_INFO | DEBUG_LOAD, "\n")); @@ -814,7 +631,7 @@ PeiLoadImageLoadImageWrapper ( @retval FALSE Relocation is not stripped. **/ -BOOLEAN +/*BOOLEAN RelocationIsStrip ( IN VOID *Pe32Data ) @@ -863,7 +680,7 @@ RelocationIsStrip ( } return FALSE; -} +}*/ /** Routine to load image file for subsequent execution by LoadFile Ppi. @@ -896,9 +713,9 @@ PeiLoadImage ( EFI_PEI_LOAD_FILE_PPI *LoadFile; EFI_PHYSICAL_ADDRESS ImageAddress; UINT64 ImageSize; - BOOLEAN IsStrip; + //BOOLEAN IsStrip; - IsStrip = FALSE; + //IsStrip = FALSE; // // If any instances of PEI_LOAD_FILE_PPI are installed, they are called. // one at a time, until one reports EFI_SUCCESS. @@ -924,7 +741,9 @@ PeiLoadImage ( // // The shadowed PEIM must be relocatable. // - if (PeimState == PEIM_STATE_REGISTER_FOR_SHADOW) { + // FIXME: + /*if (PeimState == PEIM_STATE_REGISTER_FOR_SHADOW) { + // FIXME: Assumes headers were loaded into the image memory IsStrip = RelocationIsStrip ((VOID *)(UINTN)ImageAddress); ASSERT (!IsStrip); if (IsStrip) { @@ -935,10 +754,10 @@ PeiLoadImage ( // // The image to be started must have the machine type supported by PeiCore. // - ASSERT (EFI_IMAGE_MACHINE_TYPE_SUPPORTED (PeCoffLoaderGetMachineType ((VOID *)(UINTN)ImageAddress))); - if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (PeCoffLoaderGetMachineType ((VOID *)(UINTN)ImageAddress))) { + ASSERT (EFI_IMAGE_MACHINE_TYPE_SUPPORTED (UefiImageLoaderGetMachineType ((VOID *)(UINTN)ImageAddress))); + if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (UefiImageLoaderGetMachineType ((VOID *)(UINTN)ImageAddress))) { return EFI_UNSUPPORTED; - } + }*/ return EFI_SUCCESS; } diff --git a/MdeModulePkg/Core/Pei/PeiMain.h b/MdeModulePkg/Core/Pei/PeiMain.h index 46b6c23014..36ab6bf322 100644 --- a/MdeModulePkg/Core/Pei/PeiMain.h +++ b/MdeModulePkg/Core/Pei/PeiMain.h @@ -33,12 +33,11 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #include #include #include -#include -#include +#include #include #include #include -#include +#include #include #include #include @@ -289,7 +288,7 @@ struct _PEI_CORE_INSTANCE { // // This field points to the shadowed image read function // - PE_COFF_LOADER_READ_FILE ShadowedImageRead; + VOID *ShadowedImageRead; UINTN TempPeimCount; @@ -903,6 +902,8 @@ PeiFfsFindNextFile ( @param SectionSize The file size to search. @param OutputBuffer A pointer to the discovered section, if successful. NULL if section not found. + @param OutputSize The size of the discovered section, if successful. + 0 if section not found @param AuthenticationStatus Updated upon return to point to the authentication status for this section. @param IsFfs3Fv Indicates the FV format. @@ -918,6 +919,7 @@ ProcessSection ( IN EFI_COMMON_SECTION_HEADER *Section, IN UINTN SectionSize, OUT VOID **OutputBuffer, + OUT UINT32 *OutputSize, OUT UINT32 *AuthenticationStatus, IN BOOLEAN IsFfs3Fv ); @@ -969,6 +971,33 @@ PeiFfsFindSectionData3 ( OUT UINT32 *AuthenticationStatus ); +/** + Searches for the next matching section within the specified file. + + @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation. + @param SectionType The value of the section type to find. + @param SectionInstance Section instance to find. + @param FileHandle Handle of the firmware file to search. + @param SectionData A pointer to the discovered section, if successful. + @param SectionDataSize The size of the discovered section, if successful. + @param AuthenticationStatus A pointer to the authentication status for this section. + + @retval EFI_SUCCESS The section was found. + @retval EFI_NOT_FOUND The section was not found. + +**/ +EFI_STATUS +EFIAPI +PeiFfsFindSectionData4 ( + IN CONST EFI_PEI_SERVICES **PeiServices, + IN EFI_SECTION_TYPE SectionType, + IN UINTN SectionInstance, + IN EFI_PEI_FILE_HANDLE FileHandle, + OUT VOID **SectionData, + OUT UINT32 *SectionDataSize, + OUT UINT32 *AuthenticationStatus + ); + /** Search the firmware volumes by index @@ -1391,9 +1420,10 @@ InitializeImageServices ( **/ EFI_STATUS -LoadAndRelocatePeCoffImageInPlace ( +LoadAndRelocateUefiImageInPlace ( IN VOID *Pe32Data, - IN VOID *ImageAddress + IN VOID *ImageAddress, + IN UINT32 ImageSize ); /** @@ -1409,7 +1439,8 @@ LoadAndRelocatePeCoffImageInPlace ( EFI_STATUS PeiGetPe32Data ( IN EFI_PEI_FILE_HANDLE FileHandle, - OUT VOID **Pe32Data + OUT VOID **Pe32Data, + OUT UINT32 *Pe32DataSize ); /** diff --git a/MdeModulePkg/Core/Pei/PeiMain.inf b/MdeModulePkg/Core/Pei/PeiMain.inf index 893bdc0527..c5c19664e5 100644 --- a/MdeModulePkg/Core/Pei/PeiMain.inf +++ b/MdeModulePkg/Core/Pei/PeiMain.inf @@ -53,7 +53,6 @@ [LibraryClasses] BaseMemoryLib - PeCoffGetEntryPointLib ReportStatusCodeLib PeiServicesLib PerformanceLib @@ -63,7 +62,7 @@ DebugLib MemoryAllocationLib CacheMaintenanceLib - PeCoffLib + UefiImageLib PeiServicesTablePointerLib PcdLib diff --git a/MdeModulePkg/Core/Pei/PeiMain/PeiMain.c b/MdeModulePkg/Core/Pei/PeiMain/PeiMain.c index bf1719d794..e9aa65c92f 100644 --- a/MdeModulePkg/Core/Pei/PeiMain/PeiMain.c +++ b/MdeModulePkg/Core/Pei/PeiMain/PeiMain.c @@ -60,6 +60,7 @@ EFI_PEI_SERVICES gPs = { PeiFfsGetFileInfo2, PeiResetSystem2, PeiFreePages, + PeiFfsFindSectionData4 }; /** diff --git a/MdeModulePkg/Core/Pei/Ppi/Ppi.c b/MdeModulePkg/Core/Pei/Ppi/Ppi.c index 0e85264ddb..0184f206b9 100644 --- a/MdeModulePkg/Core/Pei/Ppi/Ppi.c +++ b/MdeModulePkg/Core/Pei/Ppi/Ppi.c @@ -1082,14 +1082,16 @@ ConvertPeiCorePpiPointers ( IN PEI_CORE_FV_HANDLE *CoreFvHandle ) { - EFI_FV_FILE_INFO FileInfo; - EFI_PHYSICAL_ADDRESS OrgImageBase; - EFI_PHYSICAL_ADDRESS MigratedImageBase; - UINTN PeiCoreModuleSize; - EFI_PEI_FILE_HANDLE PeiCoreFileHandle; - VOID *PeiCoreImageBase; - VOID *PeiCoreEntryPoint; - EFI_STATUS Status; + EFI_FV_FILE_INFO FileInfo; + EFI_PHYSICAL_ADDRESS OrgImageBase; + EFI_PHYSICAL_ADDRESS MigratedImageBase; + UINTN PeiCoreModuleSize; + EFI_PEI_FILE_HANDLE PeiCoreFileHandle; + VOID *PeiCoreImageBase; + UINT32 PeiCoreImageSize; + //VOID *PeiCoreEntryPoint; + EFI_STATUS Status; + UEFI_IMAGE_LOADER_IMAGE_CONTEXT ImageContext; PeiCoreFileHandle = NULL; @@ -1108,17 +1110,18 @@ ConvertPeiCorePpiPointers ( Status = CoreFvHandle->FvPpi->GetFileInfo (CoreFvHandle->FvPpi, PeiCoreFileHandle, &FileInfo); ASSERT_EFI_ERROR (Status); - Status = PeiGetPe32Data (PeiCoreFileHandle, &PeiCoreImageBase); + Status = PeiGetPe32Data (PeiCoreFileHandle, &PeiCoreImageBase, &PeiCoreImageSize); ASSERT_EFI_ERROR (Status); // // Find PEI Core EntryPoint in the BFV in temporary memory. // - Status = PeCoffLoaderGetEntryPoint ((VOID *)(UINTN)PeiCoreImageBase, &PeiCoreEntryPoint); + // FIXME: "Assume" sanity and skip full initialisation? + Status = UefiImageInitializeContext (&ImageContext, (VOID *) (UINTN) PeiCoreImageBase, PeiCoreImageSize); ASSERT_EFI_ERROR (Status); OrgImageBase = (UINTN)PeiCoreImageBase; - MigratedImageBase = (UINTN)_ModuleEntryPoint - ((UINTN)PeiCoreEntryPoint - (UINTN)PeiCoreImageBase); + MigratedImageBase = (UINTN)_ModuleEntryPoint - UefiImageGetEntryPointAddress (&ImageContext); // // Size of loaded PEI_CORE in permanent memory. diff --git a/MdeModulePkg/Core/PiSmmCore/DebugImageInfo.c b/MdeModulePkg/Core/PiSmmCore/DebugImageInfo.c new file mode 100644 index 0000000000..1812eacc2d --- /dev/null +++ b/MdeModulePkg/Core/PiSmmCore/DebugImageInfo.c @@ -0,0 +1,153 @@ +/** @file + Support functions for managing debug image info table when loading and unloading + images. + +Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "PiSmmCore.h" + +// FIXME: Unify with DXE + +EFI_DEBUG_IMAGE_INFO_TABLE_HEADER mDebugInfoTableHeader = { + 0, // volatile UINT32 UpdateStatus; + 0, // UINT32 TableSize; + NULL // EFI_DEBUG_IMAGE_INFO *EfiDebugImageInfoTable; +}; + +UINTN mMaxTableEntries = 0; + +#define EFI_DEBUG_TABLE_ENTRY_SIZE (sizeof (VOID *)) + +/** + Creates and initializes the DebugImageInfo Table. Also creates the configuration + table and registers it into the system table. + +**/ +VOID +SmmInitializeDebugImageInfoTable ( + VOID + ) +{ + EFI_STATUS Status; + + // + // Install the EFI_SYSTEM_TABLE_POINTER structure in the EFI System + // Configuration Table + // + Status = SmmInstallConfigurationTable ( + gSmst, + &gEfiDebugImageInfoTableGuid, + &mDebugInfoTableHeader, + sizeof (mDebugInfoTableHeader) + ); + ASSERT_EFI_ERROR (Status); +} + + +/** + Adds a new DebugImageInfo structure to the DebugImageInfo Table. Re-Allocates + the table if it's not large enough to accomidate another entry. + + @param ImageInfoType type of debug image information + @param LoadedImage pointer to the loaded image protocol for the image being + loaded + @param ImageHandle image handle for the image being loaded + +**/ +VOID +SmmNewDebugImageInfoEntry ( + IN UINT32 ImageInfoType, + IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage, + IN EFI_HANDLE ImageHandle, + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext + ) +{ + EFI_DEBUG_IMAGE_INFO *Table; + EFI_DEBUG_IMAGE_INFO *NewTable; + UINTN Index; + UINTN TableSize; + EFI_DEBUG_IMAGE_INFO_NORMAL *NormalImage; + RETURN_STATUS Status; + CONST CHAR8 *PdbPath; + UINT32 PdbPathSize; + + // + // Set the flag indicating that we're in the process of updating the table. + // + mDebugInfoTableHeader.UpdateStatus |= EFI_DEBUG_IMAGE_INFO_UPDATE_IN_PROGRESS; + + Table = mDebugInfoTableHeader.EfiDebugImageInfoTable; + + if (mDebugInfoTableHeader.TableSize < mMaxTableEntries) { + // + // We still have empty entires in the Table, find the first empty entry. + // + Index = 0; + while (Table[Index].NormalImage != NULL) { + Index++; + } + // + // There must be an empty entry in the in the table. + // + ASSERT (Index < mMaxTableEntries); + } else { + // + // Table is full, so re-allocate another page for a larger table... + // + TableSize = mMaxTableEntries * EFI_DEBUG_TABLE_ENTRY_SIZE; + NewTable = AllocateZeroPool (TableSize + EFI_PAGE_SIZE); + if (NewTable == NULL) { + mDebugInfoTableHeader.UpdateStatus &= ~EFI_DEBUG_IMAGE_INFO_UPDATE_IN_PROGRESS; + return; + } + // + // Copy the old table into the new one + // + CopyMem (NewTable, Table, TableSize); + mDebugInfoTableHeader.EfiDebugImageInfoTable = NewTable; + // + // Enlarge the max table entries. + // + mMaxTableEntries += EFI_PAGE_SIZE / EFI_DEBUG_TABLE_ENTRY_SIZE; + // + // Free the old table + // + SmmFreePool (Table); + // + // Update the table header + // + Table = NewTable; + // + // Set the first empty entry index to be the original max table entries. + // + Index = mMaxTableEntries; + } + + // + // Allocate data for new entry + // + NormalImage = AllocateZeroPool (sizeof (EFI_DEBUG_IMAGE_INFO_NORMAL)); + if (NormalImage != NULL) { + // + // Update the entry + // + NormalImage->ImageInfoType = (UINT32) ImageInfoType; + NormalImage->LoadedImageProtocolInstance = LoadedImage; + NormalImage->ImageHandle = ImageHandle; + + Status = UefiImageGetSymbolsPath (ImageContext, &PdbPath, &PdbPathSize); + if (!RETURN_ERROR (Status)) { + NormalImage->PdbPath = AllocateCopyPool (PdbPathSize, PdbPath); + } + // + // Increase the number of EFI_DEBUG_IMAGE_INFO elements and set the mDebugInfoTable in modified status. + // + mDebugInfoTableHeader.UpdateStatus |= EFI_DEBUG_IMAGE_INFO_TABLE_MODIFIED; + Table[Index].NormalImage = NormalImage; + mDebugInfoTableHeader.TableSize++; + } + mDebugInfoTableHeader.UpdateStatus &= ~EFI_DEBUG_IMAGE_INFO_UPDATE_IN_PROGRESS; +} diff --git a/MdeModulePkg/Core/PiSmmCore/Dispatcher.c b/MdeModulePkg/Core/PiSmmCore/Dispatcher.c index bb789e5890..dc22b9a7a5 100644 --- a/MdeModulePkg/Core/PiSmmCore/Dispatcher.c +++ b/MdeModulePkg/Core/PiSmmCore/Dispatcher.c @@ -33,7 +33,9 @@ **/ +#include "Library/UefiImageLib.h" #include "PiSmmCore.h" +#include "Uefi/UefiBaseType.h" // // SMM Dispatcher Data structures @@ -213,84 +215,18 @@ CheckAndMarkFixLoadingMemoryUsageBitMap ( **/ EFI_STATUS -GetPeCoffImageFixLoadingAssignedAddress ( - IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext +GetUefiImageFixLoadingAssignedAddress ( + OUT EFI_PHYSICAL_ADDRESS *LoadAddress, + IN UINT64 ValueInSectionHeader, + IN UINT32 ImageDestSize ) { - UINTN SectionHeaderOffset; - EFI_STATUS Status; - EFI_IMAGE_SECTION_HEADER SectionHeader; - EFI_IMAGE_OPTIONAL_HEADER_UNION *ImgHdr; - EFI_PHYSICAL_ADDRESS FixLoadingAddress; - UINT16 Index; - UINTN Size; - UINT16 NumberOfSections; - UINT64 ValueInSectionHeader; + RETURN_STATUS Status; + EFI_PHYSICAL_ADDRESS FixLoadingAddress; - FixLoadingAddress = 0; - Status = EFI_NOT_FOUND; - - // - // Get PeHeader pointer - // - ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((CHAR8 *)ImageContext->Handle + ImageContext->PeCoffHeaderOffset); - SectionHeaderOffset = ImageContext->PeCoffHeaderOffset + - sizeof (UINT32) + - sizeof (EFI_IMAGE_FILE_HEADER) + - ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader; - NumberOfSections = ImgHdr->Pe32.FileHeader.NumberOfSections; - - // - // Get base address from the first section header that doesn't point to code section. - // - for (Index = 0; Index < NumberOfSections; Index++) { - // - // Read section header from file - // - Size = sizeof (EFI_IMAGE_SECTION_HEADER); - Status = ImageContext->ImageRead ( - ImageContext->Handle, - SectionHeaderOffset, - &Size, - &SectionHeader - ); - if (EFI_ERROR (Status)) { - return Status; - } - - Status = EFI_NOT_FOUND; - - if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_CNT_CODE) == 0) { - // - // Build tool will save the address in PointerToRelocations & PointerToLineNumbers fields in the first section header - // that doesn't point to code section in image header.So there is an assumption that when the feature is enabled, - // if a module with a loading address assigned by tools, the PointerToRelocations & PointerToLineNumbers fields - // should not be Zero, or else, these 2 fields should be set to Zero - // - ValueInSectionHeader = ReadUnaligned64 ((UINT64 *)&SectionHeader.PointerToRelocations); - if (ValueInSectionHeader != 0) { - // - // Found first section header that doesn't point to code section in which build tool saves the - // offset to SMRAM base as image base in PointerToRelocations & PointerToLineNumbers fields - // - FixLoadingAddress = (EFI_PHYSICAL_ADDRESS)(gLoadModuleAtFixAddressSmramBase + (INT64)ValueInSectionHeader); - // - // Check if the memory range is available. - // - Status = CheckAndMarkFixLoadingMemoryUsageBitMap (FixLoadingAddress, (UINTN)(ImageContext->ImageSize + ImageContext->SectionAlignment)); - if (!EFI_ERROR (Status)) { - // - // The assigned address is valid. Return the specified loading address - // - ImageContext->ImageAddress = FixLoadingAddress; - } - } - - break; - } - - SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER); - } + FixLoadingAddress = (EFI_PHYSICAL_ADDRESS)(gLoadModuleAtFixAddressSmramBase + ValueInSectionHeader); + Status = CheckAndMarkFixLoadingMemoryUsageBitMap (FixLoadingAddress, ImageDestSize); + *LoadAddress = FixLoadingAddress; DEBUG ((DEBUG_INFO|DEBUG_LOAD, "LOADING MODULE FIXED INFO: Loading module at fixed address %x, Status = %r\n", FixLoadingAddress, Status)); return Status; @@ -307,24 +243,29 @@ GetPeCoffImageFixLoadingAssignedAddress ( EFI_STATUS EFIAPI SmmLoadImage ( - IN OUT EFI_SMM_DRIVER_ENTRY *DriverEntry + IN OUT EFI_SMM_DRIVER_ENTRY *DriverEntry, + OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext ) { UINT32 AuthenticationStatus; UINTN FilePathSize; VOID *Buffer; UINTN Size; - UINTN PageCount; + UINT32 DstBufferPages; EFI_GUID *NameGuid; EFI_STATUS Status; EFI_STATUS SecurityStatus; EFI_HANDLE DeviceHandle; - EFI_PHYSICAL_ADDRESS DstBuffer; + UINT32 ImageSize; + UINT32 ImageAlignment; + UINT64 ValueInSectionHeader; + VOID *DstBuffer; + UINT32 DstBufferSize; EFI_DEVICE_PATH_PROTOCOL *FilePath; EFI_DEVICE_PATH_PROTOCOL *OriginalFilePath; EFI_DEVICE_PATH_PROTOCOL *HandleFilePath; EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv; - PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; + EFI_PHYSICAL_ADDRESS LoadAddress; PERF_LOAD_IMAGE_BEGIN (DriverEntry->ImageHandle); @@ -413,6 +354,18 @@ SmmLoadImage ( return Status; } + // + // Get information about the image being loaded + // + Status = UefiImageInitializeContextPreHash (ImageContext, Buffer, (UINT32) Size); + if (EFI_ERROR (Status)) { + if (Buffer != NULL) { + gBS->FreePool (Buffer); + } + return Status; + } + + // FIXME: Context? // // Verify File Authentication through the Security2 Architectural Protocol // @@ -420,8 +373,8 @@ SmmLoadImage ( SecurityStatus = mSecurity2->FileAuthentication ( mSecurity2, OriginalFilePath, - Buffer, - Size, + ImageContext, + sizeof (*ImageContext), FALSE ); } @@ -444,24 +397,23 @@ SmmLoadImage ( return Status; } - // - // Initialize ImageContext - // - ImageContext.Handle = Buffer; - ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory; + Status = UefiImageInitializeContextPostHash (ImageContext); + if (RETURN_ERROR (Status)) { + return Status; + } // - // Get information about the image being loaded + // Stripped relocations are not supported for both fixed-address and dynamic + // loading. // - Status = PeCoffLoaderGetImageInfo (&ImageContext); - if (EFI_ERROR (Status)) { - if (Buffer != NULL) { - gBS->FreePool (Buffer); - } - - return Status; + if (UefiImageGetRelocsStripped (ImageContext)) { + return EFI_UNSUPPORTED; } + ImageSize = UefiImageGetImageSize (ImageContext); + DstBufferPages = EFI_SIZE_TO_PAGES (ImageSize); + DstBufferSize = EFI_PAGES_TO_SIZE (DstBufferPages); + ImageAlignment = UefiImageGetSegmentAlignment (ImageContext); // // if Loading module at Fixed Address feature is enabled, then cut out a memory range started from TESG BASE // to hold the Smm driver code @@ -470,102 +422,68 @@ SmmLoadImage ( // // Get the fixed loading address assigned by Build tool // - Status = GetPeCoffImageFixLoadingAssignedAddress (&ImageContext); + Status = UefiImageGetFixedAddress (ImageContext, &ValueInSectionHeader); + if (!RETURN_ERROR (Status)) { + Status = GetUefiImageFixLoadingAssignedAddress (&LoadAddress, ValueInSectionHeader, DstBufferSize); + } + if (!EFI_ERROR (Status)) { // // Since the memory range to load Smm core already been cut out, so no need to allocate and free this range // following statements is to bypass SmmFreePages // - PageCount = 0; - DstBuffer = (UINTN)gLoadModuleAtFixAddressSmramBase; + DstBufferPages = 0; + DstBuffer = (VOID *)(UINTN)LoadAddress; } else { DEBUG ((DEBUG_INFO|DEBUG_LOAD, "LOADING MODULE FIXED ERROR: Failed to load module at fixed address. \n")); // // allocate the memory to load the SMM driver // - PageCount = (UINTN)EFI_SIZE_TO_PAGES ((UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment); - DstBuffer = (UINTN)(-1); - - Status = SmmAllocatePages ( - AllocateMaxAddress, - EfiRuntimeServicesCode, - PageCount, - &DstBuffer - ); - if (EFI_ERROR (Status)) { + DstBuffer = AllocateAlignedCodePages (DstBufferPages, ImageAlignment); + if (DstBuffer == NULL) { if (Buffer != NULL) { gBS->FreePool (Buffer); } - return Status; - } - - ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)DstBuffer; + return EFI_OUT_OF_RESOURCES; + } } } else { - PageCount = (UINTN)EFI_SIZE_TO_PAGES ((UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment); - DstBuffer = (UINTN)(-1); - - Status = SmmAllocatePages ( - AllocateMaxAddress, - EfiRuntimeServicesCode, - PageCount, - &DstBuffer - ); - if (EFI_ERROR (Status)) { + DstBuffer = AllocateAlignedCodePages (DstBufferPages, ImageAlignment); + if (DstBuffer == NULL) { if (Buffer != NULL) { gBS->FreePool (Buffer); } - return Status; + return EFI_OUT_OF_RESOURCES; } - - ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)DstBuffer; } - // - // Align buffer on section boundary - // - ImageContext.ImageAddress += ImageContext.SectionAlignment - 1; - ImageContext.ImageAddress &= ~((EFI_PHYSICAL_ADDRESS)ImageContext.SectionAlignment - 1); - // // Load the image to our new buffer // - Status = PeCoffLoaderLoadImage (&ImageContext); - if (EFI_ERROR (Status)) { - if (Buffer != NULL) { - gBS->FreePool (Buffer); - } - - SmmFreePages (DstBuffer, PageCount); - return Status; - } - - // - // Relocate the image in our new buffer - // - Status = PeCoffLoaderRelocateImage (&ImageContext); + Status = UefiImageLoadImageForExecution ( + ImageContext, + DstBuffer, + DstBufferSize, + NULL, + 0 + ); if (EFI_ERROR (Status)) { if (Buffer != NULL) { gBS->FreePool (Buffer); } - SmmFreePages (DstBuffer, PageCount); + FreeAlignedPages (DstBuffer, DstBufferPages); return Status; } - // - // Flush the instruction cache so the image data are written before we execute it - // - InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize); - // // Save Image EntryPoint in DriverEntry // - DriverEntry->ImageEntryPoint = ImageContext.EntryPoint; - DriverEntry->ImageBuffer = DstBuffer; - DriverEntry->NumberOfPage = PageCount; + DriverEntry->ImageEntryPoint = UefiImageLoaderGetImageEntryPoint (ImageContext); + DriverEntry->ImageBuffer = (UINTN)DstBuffer; + DriverEntry->NumberOfPage = DstBufferPages; // // Allocate a Loaded Image Protocol in EfiBootServicesData @@ -576,7 +494,7 @@ SmmLoadImage ( gBS->FreePool (Buffer); } - SmmFreePages (DstBuffer, PageCount); + FreeAlignedPages (DstBuffer, DstBufferPages); return Status; } @@ -604,14 +522,14 @@ SmmLoadImage ( gBS->FreePool (Buffer); } - SmmFreePages (DstBuffer, PageCount); + FreeAlignedPages (DstBuffer, DstBufferPages); return Status; } CopyMem (DriverEntry->LoadedImage->FilePath, FilePath, GetDevicePathSize (FilePath)); - DriverEntry->LoadedImage->ImageBase = (VOID *)(UINTN)ImageContext.ImageAddress; - DriverEntry->LoadedImage->ImageSize = ImageContext.ImageSize; + DriverEntry->LoadedImage->ImageBase = DstBuffer; + DriverEntry->LoadedImage->ImageSize = ImageSize; DriverEntry->LoadedImage->ImageCodeType = EfiRuntimeServicesCode; DriverEntry->LoadedImage->ImageDataType = EfiRuntimeServicesData; @@ -625,14 +543,14 @@ SmmLoadImage ( } gBS->FreePool (DriverEntry->LoadedImage->FilePath); - SmmFreePages (DstBuffer, PageCount); + FreeAlignedPages (DstBuffer, DstBufferPages); return Status; } - CopyMem (DriverEntry->SmmLoadedImage.FilePath, FilePath, GetDevicePathSize (FilePath)); + CopyMem (DriverEntry->SmmLoadedImage.FilePath, FilePath, GetDevicePathSize(FilePath)); - DriverEntry->SmmLoadedImage.ImageBase = (VOID *)(UINTN)ImageContext.ImageAddress; - DriverEntry->SmmLoadedImage.ImageSize = ImageContext.ImageSize; + DriverEntry->SmmLoadedImage.ImageBase = DstBuffer; + DriverEntry->SmmLoadedImage.ImageSize = ImageSize; DriverEntry->SmmLoadedImage.ImageCodeType = EfiRuntimeServicesCode; DriverEntry->SmmLoadedImage.ImageDataType = EfiRuntimeServicesData; @@ -660,60 +578,42 @@ SmmLoadImage ( PERF_LOAD_IMAGE_END (DriverEntry->ImageHandle); + SmmInsertImageRecord (&DriverEntry->SmmLoadedImage, ImageContext); + + // + // Register the image in the Debug Image Info Table if the attribute is set + // + SmmNewDebugImageInfoEntry ( + EFI_DEBUG_IMAGE_INFO_TYPE_NORMAL, + &DriverEntry->SmmLoadedImage, + DriverEntry->SmmImageHandle, + ImageContext + ); + // // Print the load address and the PDB file name if it is available // DEBUG_CODE_BEGIN (); - UINTN Index; - UINTN StartIndex; - CHAR8 EfiFileName[256]; + CHAR8 EfiFileName[256]; - DEBUG (( - DEBUG_INFO | DEBUG_LOAD, - "Loading SMM driver at 0x%11p EntryPoint=0x%11p ", - (VOID *)(UINTN)ImageContext.ImageAddress, - FUNCTION_ENTRY_POINT (ImageContext.EntryPoint) - )); + DEBUG ((DEBUG_INFO | DEBUG_LOAD, + "Loading SMM driver at 0x%11p EntryPoint=0x%11p ", + DstBuffer, + FUNCTION_ENTRY_POINT (UefiImageLoaderGetImageEntryPoint (ImageContext)))); // // Print Module Name by Pdb file path. // Windows and Unix style file path are all trimmed correctly. // - if (ImageContext.PdbPointer != NULL) { - StartIndex = 0; - for (Index = 0; ImageContext.PdbPointer[Index] != 0; Index++) { - if ((ImageContext.PdbPointer[Index] == '\\') || (ImageContext.PdbPointer[Index] == '/')) { - StartIndex = Index + 1; - } - } - - // - // Copy the PDB file name to our temporary string, and replace .pdb with .efi - // The PDB file name is limited in the range of 0~255. - // If the length is bigger than 255, trim the redundant characters to avoid overflow in array boundary. - // - for (Index = 0; Index < sizeof (EfiFileName) - 4; Index++) { - EfiFileName[Index] = ImageContext.PdbPointer[Index + StartIndex]; - if (EfiFileName[Index] == 0) { - EfiFileName[Index] = '.'; - } - - if (EfiFileName[Index] == '.') { - EfiFileName[Index + 1] = 'e'; - EfiFileName[Index + 2] = 'f'; - EfiFileName[Index + 3] = 'i'; - EfiFileName[Index + 4] = 0; - break; - } - } - - if (Index == sizeof (EfiFileName) - 4) { - EfiFileName[Index] = 0; - } - - DEBUG ((DEBUG_INFO | DEBUG_LOAD, "%a", EfiFileName)); // &Image->ImageContext.PdbPointer[StartIndex])); + Status = UefiImageGetModuleNameFromSymbolsPath ( + ImageContext, + EfiFileName, + sizeof (EfiFileName) + ); + if (!EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO | DEBUG_LOAD, "%a", EfiFileName)); } DEBUG ((DEBUG_INFO | DEBUG_LOAD, "\n")); @@ -852,11 +752,12 @@ SmmDispatcher ( VOID ) { - EFI_STATUS Status; - LIST_ENTRY *Link; - EFI_SMM_DRIVER_ENTRY *DriverEntry; - BOOLEAN ReadyToRun; - BOOLEAN PreviousSmmEntryPointRegistered; + EFI_STATUS Status; + LIST_ENTRY *Link; + EFI_SMM_DRIVER_ENTRY *DriverEntry; + BOOLEAN ReadyToRun; + BOOLEAN PreviousSmmEntryPointRegistered; + UEFI_IMAGE_LOADER_IMAGE_CONTEXT ImageContext; if (!gRequestDispatch) { return EFI_NOT_FOUND; @@ -889,8 +790,7 @@ SmmDispatcher ( // skip the LoadImage // if (DriverEntry->ImageHandle == NULL) { - Status = SmmLoadImage (DriverEntry); - + Status = SmmLoadImage (DriverEntry, &ImageContext); // // Update the driver state to reflect that it's been loaded // @@ -929,7 +829,7 @@ SmmDispatcher ( // // For each SMM driver, pass NULL as ImageHandle // - RegisterSmramProfileImage (DriverEntry, TRUE); + RegisterSmramProfileImage (&DriverEntry->FileName, TRUE, &ImageContext); PERF_START_IMAGE_BEGIN (DriverEntry->ImageHandle); Status = ((EFI_IMAGE_ENTRY_POINT)(UINTN)DriverEntry->ImageEntryPoint)(DriverEntry->ImageHandle, gST); PERF_START_IMAGE_END (DriverEntry->ImageHandle); @@ -940,7 +840,12 @@ SmmDispatcher ( DriverEntry->SmmLoadedImage.ImageBase, Status )); - UnregisterSmramProfileImage (DriverEntry, TRUE); + UnregisterSmramProfileImage ( + &DriverEntry->FileName, + (UINTN) DriverEntry->LoadedImage->ImageBase, + DriverEntry->LoadedImage->ImageSize, + TRUE + ); SmmFreePages (DriverEntry->ImageBuffer, DriverEntry->NumberOfPage); // // Uninstall LoadedImage diff --git a/MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/MemoryAllocationLib.c b/MdeModulePkg/Core/PiSmmCore/MemoryAllocation.c similarity index 96% rename from MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/MemoryAllocationLib.c rename to MdeModulePkg/Core/PiSmmCore/MemoryAllocation.c index 9a4d5b8cac..b81d637aef 100644 --- a/MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/MemoryAllocationLib.c +++ b/MdeModulePkg/Core/PiSmmCore/MemoryAllocation.c @@ -22,7 +22,8 @@ #include #include #include -#include "PiSmmCoreMemoryAllocationServices.h" +#include "PiSmmCore.h" +#include "PiSmmCorePrivateData.h" #include diff --git a/MdeModulePkg/Core/PiSmmCore/MemoryAttributesTable.c b/MdeModulePkg/Core/PiSmmCore/MemoryAttributesTable.c index 28fe74ecc4..c06bb409d4 100644 --- a/MdeModulePkg/Core/PiSmmCore/MemoryAttributesTable.c +++ b/MdeModulePkg/Core/PiSmmCore/MemoryAttributesTable.c @@ -16,12 +16,12 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #include #include -#include -#include +#include #include #include "PiSmmCore.h" +#include "ProcessorBind.h" #define PREVIOUS_MEMORY_DESCRIPTOR(MemoryDescriptor, Size) \ ((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)(MemoryDescriptor) - (Size))) @@ -31,7 +31,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent typedef struct { UINT32 Signature; UINTN ImageRecordCount; - UINTN CodeSegmentCountMax; + UINT32 NumberOfSectionsMax; LIST_ENTRY ImageRecordList; } IMAGE_PROPERTIES_PRIVATE_DATA; @@ -212,7 +212,10 @@ SmmCoreGetMemoryMapMemoryAttributesTable ( return EFI_INVALID_PARAMETER; } - AdditionalRecordCount = (2 * mImagePropertiesPrivateData.CodeSegmentCountMax + 3) * mImagePropertiesPrivateData.ImageRecordCount; + // + // Per image, they may be one trailer. There may be prefixed data. + // + AdditionalRecordCount = (mImagePropertiesPrivateData.NumberOfSectionsMax + 1) * mImagePropertiesPrivateData.ImageRecordCount + 1; OldMemoryMapSize = *MemoryMapSize; Status = SmmCoreGetMemoryMap (MemoryMapSize, MemoryMap, MapKey, DescriptorSize, DescriptorVersion); @@ -252,88 +255,158 @@ SmmCoreGetMemoryMapMemoryAttributesTable ( // /** - Insert image record. + Set MemoryProtectionAttribute according to PE/COFF image section alignment. - @param[in] DriverEntry Driver information + @param[in] SectionAlignment PE/COFF section alignment **/ +STATIC VOID -SmmInsertImageRecord ( - IN EFI_SMM_DRIVER_ENTRY *DriverEntry +SetMemoryAttributesTableSectionAlignment ( + IN UINT32 SectionAlignment ) { - EFI_STATUS Status; - IMAGE_PROPERTIES_RECORD *ImageRecord; - CHAR8 *PdbPointer; - UINT32 RequiredAlignment; + if (((SectionAlignment & (RUNTIME_PAGE_ALLOCATION_GRANULARITY - 1)) != 0) && + ((mMemoryProtectionAttribute & EFI_MEMORY_ATTRIBUTES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA) != 0)) + { + DEBUG ((DEBUG_VERBOSE, "SMM SetMemoryAttributesTableSectionAlignment - Clear\n")); + mMemoryProtectionAttribute &= ~((UINT64)EFI_MEMORY_ATTRIBUTES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA); + } +} - DEBUG ((DEBUG_VERBOSE, "SMM InsertImageRecord - 0x%x\n", DriverEntry)); +/** + Sort image record based upon the ImageBase from low to high. +**/ +STATIC +VOID +InsertSortImageRecord ( + IN UEFI_IMAGE_RECORD *NewImageRecord + ) +{ + UEFI_IMAGE_RECORD *ImageRecord; + LIST_ENTRY *PrevImageRecordLink; + LIST_ENTRY *ImageRecordLink; + LIST_ENTRY *ImageRecordList; + + ImageRecordList = &mImagePropertiesPrivateData.ImageRecordList; + + PrevImageRecordLink = ImageRecordList; + for ( + ImageRecordLink = GetFirstNode (ImageRecordList); + !IsNull (ImageRecordLink, ImageRecordList); + ImageRecordLink = GetNextNode (ImageRecordList, PrevImageRecordLink) + ) { + ImageRecord = CR ( + ImageRecordLink, + UEFI_IMAGE_RECORD, + Link, + UEFI_IMAGE_RECORD_SIGNATURE + ); + if (NewImageRecord->StartAddress < ImageRecord->StartAddress) { + break; + } - ImageRecord = AllocatePool (sizeof (*ImageRecord)); - if (ImageRecord == NULL) { - return; + PrevImageRecordLink = ImageRecordLink; } - InitializeListHead (&ImageRecord->Link); - InitializeListHead (&ImageRecord->CodeSegmentList); + InsertHeadList (PrevImageRecordLink, &NewImageRecord->Link); + mImagePropertiesPrivateData.ImageRecordCount++; - PdbPointer = PeCoffLoaderGetPdbPointer ((VOID *)(UINTN)DriverEntry->ImageBuffer); - if (PdbPointer != NULL) { - DEBUG ((DEBUG_VERBOSE, "SMM Image - %a\n", PdbPointer)); + if (mImagePropertiesPrivateData.NumberOfSectionsMax < NewImageRecord->NumSegments) { + mImagePropertiesPrivateData.NumberOfSectionsMax = NewImageRecord->NumSegments; } +} - RequiredAlignment = RUNTIME_PAGE_ALLOCATION_GRANULARITY; - Status = CreateImagePropertiesRecord ( - (VOID *)(UINTN)DriverEntry->ImageBuffer, - LShiftU64 (DriverEntry->NumberOfPage, EFI_PAGE_SHIFT), - &RequiredAlignment, - ImageRecord - ); - - if (EFI_ERROR (Status)) { - if (Status == EFI_ABORTED) { - mMemoryProtectionAttribute &= - ~((UINT64)EFI_MEMORY_ATTRIBUTES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA); - } - - goto Finish; +/** + Dump image record. +**/ +STATIC +VOID +DumpImageRecord ( + VOID + ) +{ + UEFI_IMAGE_RECORD *ImageRecord; + LIST_ENTRY *ImageRecordLink; + LIST_ENTRY *ImageRecordList; + UINTN Index; + + ImageRecordList = &mImagePropertiesPrivateData.ImageRecordList; + + for (ImageRecordLink = ImageRecordList->ForwardLink, Index = 0; + ImageRecordLink != ImageRecordList; + ImageRecordLink = ImageRecordLink->ForwardLink, Index++) + { + ImageRecord = CR ( + ImageRecordLink, + UEFI_IMAGE_RECORD, + Link, + UEFI_IMAGE_RECORD_SIGNATURE + ); + DEBUG ((DEBUG_VERBOSE, "SMM Image[%d]: 0x%016lx - 0x%016lx\n", Index, ImageRecord->StartAddress, ImageRecord->EndAddress - ImageRecord->StartAddress)); } +} - if (ImageRecord->CodeSegmentCount == 0) { - mMemoryProtectionAttribute &= - ~((UINT64)EFI_MEMORY_ATTRIBUTES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA); - DEBUG ((DEBUG_ERROR, "SMM !!!!!!!! InsertImageRecord - CodeSegmentCount is 0 !!!!!!!!\n")); - if (PdbPointer != NULL) { - DEBUG ((DEBUG_ERROR, "SMM !!!!!!!! Image - %a !!!!!!!!\n", PdbPointer)); - } +/** + Insert image record. - Status = EFI_ABORTED; - goto Finish; + @param[in] DriverEntry Driver information +**/ +VOID +SmmInsertImageRecord ( + IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage, + IN UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext + ) +{ + RETURN_STATUS PdbStatus; + PHYSICAL_ADDRESS ImageBuffer; + UINTN NumberOfPage; + UINT32 SectionAlignment; + UEFI_IMAGE_RECORD *ImageRecord; + CONST CHAR8 *PdbPointer; + UINT32 PdbSize; + + ImageBuffer = (UINTN)LoadedImage->ImageBase; + NumberOfPage = EFI_SIZE_TO_PAGES((UINTN)LoadedImage->ImageSize); + + DEBUG ((DEBUG_VERBOSE, "SMM InsertImageRecord - 0x%016lx - 0x%08x\n", ImageBuffer, NumberOfPage)); + + DEBUG ((DEBUG_VERBOSE, "SMM ImageRecordCount - 0x%x\n", mImagePropertiesPrivateData.ImageRecordCount)); + + PdbStatus = UefiImageGetSymbolsPath (ImageContext, &PdbPointer, &PdbSize); + if (!RETURN_ERROR (PdbStatus)) { + DEBUG ((DEBUG_VERBOSE, "SMM Image - %a\n", PdbPointer)); } // - // Check overlap all section in ImageBase/Size + // Get SectionAlignment // - if (!IsImageRecordCodeSectionValid (ImageRecord)) { - DEBUG ((DEBUG_ERROR, "SMM IsImageRecordCodeSectionValid - FAIL\n")); - Status = EFI_ABORTED; - goto Finish; - } - - InsertTailList (&mImagePropertiesPrivateData.ImageRecordList, &ImageRecord->Link); - mImagePropertiesPrivateData.ImageRecordCount++; + SectionAlignment = UefiImageGetSegmentAlignment (ImageContext); + + SetMemoryAttributesTableSectionAlignment (SectionAlignment); + if ((SectionAlignment & (RUNTIME_PAGE_ALLOCATION_GRANULARITY - 1)) != 0) { + DEBUG (( + DEBUG_WARN, + "SMM !!!!!!!! InsertImageRecord - Section Alignment(0x%x) is not %dK !!!!!!!!\n", + SectionAlignment, RUNTIME_PAGE_ALLOCATION_GRANULARITY >> 10)); + if (!RETURN_ERROR (PdbStatus)) { + DEBUG ((DEBUG_WARN, "SMM !!!!!!!! Image - %a !!!!!!!!\n", PdbPointer)); + } - if (mImagePropertiesPrivateData.CodeSegmentCountMax < ImageRecord->CodeSegmentCount) { - mImagePropertiesPrivateData.CodeSegmentCountMax = ImageRecord->CodeSegmentCount; + return; } - SortImageRecord (&mImagePropertiesPrivateData.ImageRecordList); - -Finish: - if (EFI_ERROR (Status) && (ImageRecord != NULL)) { - DeleteImagePropertiesRecord (ImageRecord); + // + // The image headers are not recorded among the sections, allocate one more. + // + ImageRecord = UefiImageLoaderGetImageRecord (ImageContext); + if (ImageRecord == NULL) { + return; } - return; + UefiImageDebugPrintSegments (ImageContext); + UefiImageDebugPrintImageRecord (ImageRecord); + + InsertSortImageRecord (ImageRecord); } /** @@ -418,60 +491,6 @@ PublishMemoryAttributesTable ( ASSERT_EFI_ERROR (Status); } -/** - This function installs all SMM image record information. -**/ -VOID -SmmInstallImageRecord ( - VOID - ) -{ - EFI_STATUS Status; - UINTN NoHandles; - EFI_HANDLE *HandleBuffer; - EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; - UINTN Index; - EFI_SMM_DRIVER_ENTRY DriverEntry; - - Status = SmmLocateHandleBuffer ( - ByProtocol, - &gEfiLoadedImageProtocolGuid, - NULL, - &NoHandles, - &HandleBuffer - ); - if (EFI_ERROR (Status)) { - return; - } - - for (Index = 0; Index < NoHandles; Index++) { - Status = gSmst->SmmHandleProtocol ( - HandleBuffer[Index], - &gEfiLoadedImageProtocolGuid, - (VOID **)&LoadedImage - ); - if (EFI_ERROR (Status)) { - continue; - } - - DEBUG ((DEBUG_VERBOSE, "LoadedImage - 0x%x 0x%x ", LoadedImage->ImageBase, LoadedImage->ImageSize)); - { - VOID *PdbPointer; - PdbPointer = PeCoffLoaderGetPdbPointer (LoadedImage->ImageBase); - if (PdbPointer != NULL) { - DEBUG ((DEBUG_VERBOSE, "(%a) ", PdbPointer)); - } - } - DEBUG ((DEBUG_VERBOSE, "\n")); - ZeroMem (&DriverEntry, sizeof (DriverEntry)); - DriverEntry.ImageBuffer = (UINTN)LoadedImage->ImageBase; - DriverEntry.NumberOfPage = EFI_SIZE_TO_PAGES ((UINTN)LoadedImage->ImageSize); - SmmInsertImageRecord (&DriverEntry); - } - - FreePool (HandleBuffer); -} - /** Install MemoryAttributesTable. @@ -489,8 +508,6 @@ SmmInstallMemoryAttributesTable ( IN EFI_HANDLE Handle ) { - SmmInstallImageRecord (); - DEBUG ((DEBUG_VERBOSE, "SMM MemoryProtectionAttribute - 0x%016lx\n", mMemoryProtectionAttribute)); if ((mMemoryProtectionAttribute & EFI_MEMORY_ATTRIBUTES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA) == 0) { return EFI_SUCCESS; @@ -500,7 +517,7 @@ SmmInstallMemoryAttributesTable ( if ( mImagePropertiesPrivateData.ImageRecordCount > 0) { DEBUG ((DEBUG_INFO, "SMM - Total Runtime Image Count - 0x%x\n", mImagePropertiesPrivateData.ImageRecordCount)); DEBUG ((DEBUG_INFO, "SMM - Dump Runtime Image Records:\n")); - DumpImageRecords (&mImagePropertiesPrivateData.ImageRecordList); + DumpImageRecord (); } DEBUG_CODE_END (); diff --git a/MdeModulePkg/Core/PiSmmCore/PiSmmCore.c b/MdeModulePkg/Core/PiSmmCore/PiSmmCore.c index e957cb67f8..9f3e9392e8 100644 --- a/MdeModulePkg/Core/PiSmmCore/PiSmmCore.c +++ b/MdeModulePkg/Core/PiSmmCore/PiSmmCore.c @@ -815,7 +815,7 @@ SmmCoreInstallLoadedImage ( mSmmCoreLoadedImage->SystemTable = gST; mSmmCoreLoadedImage->ImageBase = (VOID *)(UINTN)gSmmCorePrivate->PiSmmCoreImageBase; - mSmmCoreLoadedImage->ImageSize = gSmmCorePrivate->PiSmmCoreImageSize; + mSmmCoreLoadedImage->ImageSize = UefiImageGetImageSize (&gSmmCorePrivate->PiSmmCoreImageContext); mSmmCoreLoadedImage->ImageCodeType = EfiRuntimeServicesCode; mSmmCoreLoadedImage->ImageDataType = EfiRuntimeServicesData; @@ -847,13 +847,13 @@ SmmCoreInstallLoadedImage ( mSmmCoreDriverEntry->SmmLoadedImage.SystemTable = gST; mSmmCoreDriverEntry->SmmLoadedImage.ImageBase = (VOID *)(UINTN)gSmmCorePrivate->PiSmmCoreImageBase; - mSmmCoreDriverEntry->SmmLoadedImage.ImageSize = gSmmCorePrivate->PiSmmCoreImageSize; + mSmmCoreDriverEntry->SmmLoadedImage.ImageSize = UefiImageGetImageSize (&gSmmCorePrivate->PiSmmCoreImageContext); mSmmCoreDriverEntry->SmmLoadedImage.ImageCodeType = EfiRuntimeServicesCode; mSmmCoreDriverEntry->SmmLoadedImage.ImageDataType = EfiRuntimeServicesData; - mSmmCoreDriverEntry->ImageEntryPoint = gSmmCorePrivate->PiSmmCoreEntryPoint; + mSmmCoreDriverEntry->ImageEntryPoint = UefiImageLoaderGetImageEntryPoint (&gSmmCorePrivate->PiSmmCoreImageContext); mSmmCoreDriverEntry->ImageBuffer = gSmmCorePrivate->PiSmmCoreImageBase; - mSmmCoreDriverEntry->NumberOfPage = EFI_SIZE_TO_PAGES ((UINTN)gSmmCorePrivate->PiSmmCoreImageSize); + mSmmCoreDriverEntry->NumberOfPage = EFI_SIZE_TO_PAGES ((UINTN)UefiImageGetImageSize (&gSmmCorePrivate->PiSmmCoreImageContext)); // // Create a new image handle in the SMM handle database for the SMM Driver @@ -867,6 +867,21 @@ SmmCoreInstallLoadedImage ( ); ASSERT_EFI_ERROR (Status); + SmmInsertImageRecord (&mSmmCoreDriverEntry->SmmLoadedImage, &gSmmCorePrivate->PiSmmCoreImageContext); + + // + // Create the aligned system table pointer structure that is used by external + // debuggers to locate the system table... Also, install debug image info + // configuration table. + // + SmmInitializeDebugImageInfoTable (); + SmmNewDebugImageInfoEntry ( + EFI_DEBUG_IMAGE_INFO_TYPE_NORMAL, + &mSmmCoreDriverEntry->SmmLoadedImage, + mSmmCoreDriverEntry->SmmImageHandle, + &gSmmCorePrivate->PiSmmCoreImageContext + ); + return; } diff --git a/MdeModulePkg/Core/PiSmmCore/PiSmmCore.h b/MdeModulePkg/Core/PiSmmCore/PiSmmCore.h index 60073c78b4..6b33a9d34a 100644 --- a/MdeModulePkg/Core/PiSmmCore/PiSmmCore.h +++ b/MdeModulePkg/Core/PiSmmCore/PiSmmCore.h @@ -37,11 +37,11 @@ #include #include #include +#include #include #include -#include -#include +#include #include #include #include @@ -55,6 +55,7 @@ #include #include #include +#include #include "PiSmmCorePrivateData.h" #include "HeapGuard.h" @@ -1020,8 +1021,9 @@ SmramProfileInstallProtocol ( **/ EFI_STATUS RegisterSmramProfileImage ( - IN EFI_SMM_DRIVER_ENTRY *DriverEntry, - IN BOOLEAN RegisterToDxe + IN EFI_GUID *FileName, + IN BOOLEAN RegisterToDxe, + IN UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext ); /** @@ -1038,8 +1040,10 @@ RegisterSmramProfileImage ( **/ EFI_STATUS UnregisterSmramProfileImage ( - IN EFI_SMM_DRIVER_ENTRY *DriverEntry, - IN BOOLEAN UnregisterToDxe + IN EFI_GUID *FileName, + IN PHYSICAL_ADDRESS ImageBase, + IN UINT64 ImageSize, + IN BOOLEAN UnregisterFromDxe ); /** @@ -1352,4 +1356,50 @@ SmmEntryPointMemoryManagementHook ( VOID ); +/** + Creates and initializes the DebugImageInfo Table. Also creates the configuration + table and registers it into the system table. + + Note: + This function allocates memory, frees it, and then allocates memory at an + address within the initial allocation. Since this function is called early + in DXE core initialization (before drivers are dispatched), this should not + be a problem. + +**/ +VOID +SmmInitializeDebugImageInfoTable ( + VOID + ); + + +/** + Adds a new DebugImageInfo structure to the DebugImageInfo Table. Re-Allocates + the table if it's not large enough to accomidate another entry. + + @param ImageInfoType type of debug image information + @param LoadedImage pointer to the loaded image protocol for the image being + loaded + @param ImageHandle image handle for the image being loaded + +**/ +VOID +SmmNewDebugImageInfoEntry ( + IN UINT32 ImageInfoType, + IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage, + IN EFI_HANDLE ImageHandle, + IN UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext + ); + +/** + Insert image record. + + @param[in] DriverEntry Driver information +**/ +VOID +SmmInsertImageRecord ( + IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage, + IN UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext + ); + #endif diff --git a/MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf b/MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf index 75a5934f0c..d14f76b65f 100644 --- a/MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf +++ b/MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf @@ -37,6 +37,8 @@ SmiHandlerProfile.c HeapGuard.c HeapGuard.h + MemoryAllocation.c + DebugImageInfo.c [Packages] MdePkg/MdePkg.dec @@ -46,8 +48,7 @@ UefiDriverEntryPoint BaseLib BaseMemoryLib - PeCoffLib - PeCoffGetEntryPointLib + UefiImageLib CacheMaintenanceLib DebugLib ReportStatusCodeLib @@ -99,6 +100,7 @@ gEfiMdeModulePkgTokenSpaceGuid.PcdHeapGuardPoolType ## CONSUMES gEfiMdeModulePkgTokenSpaceGuid.PcdHeapGuardPropertyMask ## CONSUMES gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiS3Enable ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdMaxEfiSystemTablePointerAddress ## CONSUMES [Guids] gAprioriGuid ## SOMETIMES_CONSUMES ## File @@ -120,6 +122,7 @@ gSmiHandlerProfileGuid gEdkiiEndOfS3ResumeGuid ## SOMETIMES_PRODUCES ## GUID # Install protocol gEdkiiS3SmmInitDoneGuid ## SOMETIMES_PRODUCES ## GUID # Install protocol + gEfiDebugImageInfoTableGuid ## PRODUCES ## SystemTable [UserExtensions.TianoCore."ExtraFiles"] PiSmmCoreExtra.uni diff --git a/MdeModulePkg/Core/PiSmmCore/PiSmmCorePrivateData.h b/MdeModulePkg/Core/PiSmmCore/PiSmmCorePrivateData.h index d8fe2dd9b9..301b9b4656 100644 --- a/MdeModulePkg/Core/PiSmmCore/PiSmmCorePrivateData.h +++ b/MdeModulePkg/Core/PiSmmCore/PiSmmCorePrivateData.h @@ -22,6 +22,7 @@ /// the SMM Entry Point enabling the use of SMM Mode. In this case, the SMM Core /// should be notified again to dispatch more SMM Drivers using SMM Mode. /// +#include "Library/UefiImageLib.h" #define COMM_BUFFER_SMM_DISPATCH_ERROR 0x00 #define COMM_BUFFER_SMM_DISPATCH_SUCCESS 0x01 #define COMM_BUFFER_SMM_DISPATCH_RESTART 0x02 @@ -112,8 +113,7 @@ typedef struct { EFI_STATUS ReturnStatus; EFI_PHYSICAL_ADDRESS PiSmmCoreImageBase; - UINT64 PiSmmCoreImageSize; - EFI_PHYSICAL_ADDRESS PiSmmCoreEntryPoint; + UEFI_IMAGE_LOADER_IMAGE_CONTEXT PiSmmCoreImageContext; } SMM_CORE_PRIVATE_DATA; #endif diff --git a/MdeModulePkg/Core/PiSmmCore/PiSmmIpl.c b/MdeModulePkg/Core/PiSmmCore/PiSmmIpl.c index fbba868fd0..524a74bdc4 100644 --- a/MdeModulePkg/Core/PiSmmCore/PiSmmIpl.c +++ b/MdeModulePkg/Core/PiSmmCore/PiSmmIpl.c @@ -23,7 +23,7 @@ #include #include -#include +#include #include #include #include @@ -36,6 +36,8 @@ #include #include "PiSmmCorePrivateData.h" #include +#include "ProcessorBind.h" +#include "Uefi/UefiBaseType.h" #define SMRAM_CAPABILITIES (EFI_MEMORY_WB | EFI_MEMORY_UC) @@ -913,91 +915,41 @@ SmmIplSetVirtualAddressNotify ( @retval EFI_NOT_FOUND The image has no assigned fixed loading address. **/ EFI_STATUS -GetPeCoffImageFixLoadingAssignedAddress ( - IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext +GetUefiImageFixLoadingAssignedAddress ( + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext, + OUT EFI_PHYSICAL_ADDRESS *LoadAddress ) { - UINTN SectionHeaderOffset; - EFI_STATUS Status; - EFI_IMAGE_SECTION_HEADER SectionHeader; - EFI_IMAGE_OPTIONAL_HEADER_UNION *ImgHdr; - EFI_PHYSICAL_ADDRESS FixLoadingAddress; - UINT16 Index; - UINTN Size; - UINT16 NumberOfSections; - EFI_PHYSICAL_ADDRESS SmramBase; - UINT64 SmmCodeSize; - UINT64 ValueInSectionHeader; - + EFI_STATUS Status; + UINT64 ValueInSectionHeader; + EFI_PHYSICAL_ADDRESS FixLoadingAddress; + UINT32 SizeOfImage; + EFI_PHYSICAL_ADDRESS SmramBase; + UINT64 SmmCodeSize; + + Status = UefiImageGetFixedAddress (ImageContext, &ValueInSectionHeader); + if (RETURN_ERROR (Status)) { + return Status; + } // // Build tool will calculate the smm code size and then patch the PcdLoadFixAddressSmmCodePageNumber // - SmmCodeSize = EFI_PAGES_TO_SIZE (PcdGet32 (PcdLoadFixAddressSmmCodePageNumber)); + SmmCodeSize = EFI_PAGES_TO_SIZE (PcdGet32(PcdLoadFixAddressSmmCodePageNumber)); + SmramBase = mLMFAConfigurationTable->SmramBase; - FixLoadingAddress = 0; - Status = EFI_NOT_FOUND; - SmramBase = mLMFAConfigurationTable->SmramBase; - // - // Get PeHeader pointer - // - ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((CHAR8 *)ImageContext->Handle + ImageContext->PeCoffHeaderOffset); - SectionHeaderOffset = ImageContext->PeCoffHeaderOffset + - sizeof (UINT32) + - sizeof (EFI_IMAGE_FILE_HEADER) + - ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader; - NumberOfSections = ImgHdr->Pe32.FileHeader.NumberOfSections; + FixLoadingAddress = SmramBase + ValueInSectionHeader; + SizeOfImage = UefiImageGetImageSize (ImageContext); - // - // Get base address from the first section header that doesn't point to code section. - // - for (Index = 0; Index < NumberOfSections; Index++) { + if (SmramBase + SmmCodeSize >= FixLoadingAddress + SizeOfImage + && SmramBase <= FixLoadingAddress) { // - // Read section header from file + // The assigned address is valid. Return the specified loading address // - Size = sizeof (EFI_IMAGE_SECTION_HEADER); - Status = ImageContext->ImageRead ( - ImageContext->Handle, - SectionHeaderOffset, - &Size, - &SectionHeader - ); - if (EFI_ERROR (Status)) { - return Status; - } - - Status = EFI_NOT_FOUND; - - if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_CNT_CODE) == 0) { - // - // Build tool saves the offset to SMRAM base as image base in PointerToRelocations & PointerToLineNumbers fields in the - // first section header that doesn't point to code section in image header. And there is an assumption that when the - // feature is enabled, if a module is assigned a loading address by tools, PointerToRelocations & PointerToLineNumbers - // fields should NOT be Zero, or else, these 2 fields should be set to Zero - // - ValueInSectionHeader = ReadUnaligned64 ((UINT64 *)&SectionHeader.PointerToRelocations); - if (ValueInSectionHeader != 0) { - // - // Found first section header that doesn't point to code section in which build tool saves the - // offset to SMRAM base as image base in PointerToRelocations & PointerToLineNumbers fields - // - FixLoadingAddress = (EFI_PHYSICAL_ADDRESS)(SmramBase + (INT64)ValueInSectionHeader); - - if ((SmramBase + SmmCodeSize > FixLoadingAddress) && (SmramBase <= FixLoadingAddress)) { - // - // The assigned address is valid. Return the specified loading address - // - ImageContext->ImageAddress = FixLoadingAddress; - Status = EFI_SUCCESS; - } - } - - break; - } - - SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER); + *LoadAddress = FixLoadingAddress; + Status = EFI_SUCCESS; } - DEBUG ((DEBUG_INFO|DEBUG_LOAD, "LOADING MODULE FIXED INFO: Loading module at fixed address %x, Status = %r \n", FixLoadingAddress, Status)); + DEBUG ((EFI_D_INFO|EFI_D_LOAD, "LOADING MODULE FIXED INFO: Loading module at fixed address %x, Status = %r \n", FixLoadingAddress, Status)); return Status; } @@ -1024,9 +976,14 @@ ExecuteSmmCoreFromSmram ( EFI_STATUS Status; VOID *SourceBuffer; UINTN SourceSize; - PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; + UINT32 ImageSize; + UINT32 ImageAlignment; + UINT32 DestinationPages; + UINT32 DestinationSize; + UINT32 AlignSubtrahend; UINTN PageCount; EFI_IMAGE_ENTRY_POINT EntryPoint; + EFI_PHYSICAL_ADDRESS LoadAddress; // // Search all Firmware Volumes for a PE/COFF image in a file of type SMM_CORE @@ -1043,20 +1000,26 @@ ExecuteSmmCoreFromSmram ( return Status; } - // - // Initialize ImageContext - // - ImageContext.Handle = SourceBuffer; - ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory; - // // Get information about the image being loaded // - Status = PeCoffLoaderGetImageInfo (&ImageContext); + Status = UefiImageInitializeContext (&gSmmCorePrivate->PiSmmCoreImageContext, SourceBuffer, (UINT32) SourceSize); if (EFI_ERROR (Status)) { return Status; } + // + // Stripped relocations are not supported for both fixed-address and dynamic + // loading. + // + if (UefiImageGetRelocsStripped (&gSmmCorePrivate->PiSmmCoreImageContext)) { + return EFI_UNSUPPORTED; + } + + ImageSize = UefiImageGetImageSize (&gSmmCorePrivate->PiSmmCoreImageContext); + DestinationPages = EFI_SIZE_TO_PAGES (ImageSize); + DestinationSize = EFI_PAGES_TO_SIZE (DestinationPages); + ImageAlignment = UefiImageGetSegmentAlignment (&gSmmCorePrivate->PiSmmCoreImageContext); // // if Loading module at Fixed Address feature is enabled, the SMM core driver will be loaded to // the address assigned by build tool. @@ -1065,7 +1028,7 @@ ExecuteSmmCoreFromSmram ( // // Get the fixed loading address assigned by Build tool // - Status = GetPeCoffImageFixLoadingAssignedAddress (&ImageContext); + Status = GetUefiImageFixLoadingAssignedAddress (&gSmmCorePrivate->PiSmmCoreImageContext, &LoadAddress); if (!EFI_ERROR (Status)) { // // Since the memory range to load SMM CORE will be cut out in SMM core, so no need to allocate and free this range @@ -1081,7 +1044,11 @@ ExecuteSmmCoreFromSmram ( // Allocate memory for the image being loaded from the EFI_SRAM_DESCRIPTOR // specified by SmramRange // - PageCount = (UINTN)EFI_SIZE_TO_PAGES ((UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment); + AlignSubtrahend = ALIGN_VALUE_SUBTRAHEND ( + SmramRange->CpuStart + SmramRange->PhysicalSize, + ImageAlignment + ); + PageCount = (UINTN)DestinationPages + (UINTN)EFI_SIZE_TO_PAGES ((UINTN)AlignSubtrahend); ASSERT ((SmramRange->PhysicalSize & EFI_PAGE_MASK) == 0); ASSERT (SmramRange->PhysicalSize > EFI_PAGES_TO_SIZE (PageCount)); @@ -1095,14 +1062,18 @@ ExecuteSmmCoreFromSmram ( // // Align buffer on section boundary // - ImageContext.ImageAddress = SmramRangeSmmCore->CpuStart; + LoadAddress = SmramRangeSmmCore->CpuStart; } } else { // // Allocate memory for the image being loaded from the EFI_SRAM_DESCRIPTOR // specified by SmramRange // - PageCount = (UINTN)EFI_SIZE_TO_PAGES ((UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment); + AlignSubtrahend = ALIGN_VALUE_SUBTRAHEND ( + SmramRange->CpuStart + SmramRange->PhysicalSize, + ImageAlignment + ); + PageCount = (UINTN)DestinationPages + (UINTN)EFI_SIZE_TO_PAGES ((UINTN)AlignSubtrahend); ASSERT ((SmramRange->PhysicalSize & EFI_PAGE_MASK) == 0); ASSERT (SmramRange->PhysicalSize > EFI_PAGES_TO_SIZE (PageCount)); @@ -1116,50 +1087,34 @@ ExecuteSmmCoreFromSmram ( // // Align buffer on section boundary // - ImageContext.ImageAddress = SmramRangeSmmCore->CpuStart; + LoadAddress = SmramRangeSmmCore->CpuStart; } - ImageContext.ImageAddress += ImageContext.SectionAlignment - 1; - ImageContext.ImageAddress &= ~((EFI_PHYSICAL_ADDRESS)ImageContext.SectionAlignment - 1); - // // Print debug message showing SMM Core load address. // - DEBUG ((DEBUG_INFO, "SMM IPL loading SMM Core at SMRAM address %p\n", (VOID *)(UINTN)ImageContext.ImageAddress)); + DEBUG ((DEBUG_INFO, "SMM IPL loading SMM Core at SMRAM destination %p\n", (VOID *)(UINTN)LoadAddress)); // // Load the image to our new buffer // - Status = PeCoffLoaderLoadImage (&ImageContext); + Status = UefiImageLoadImageForExecution (&gSmmCorePrivate->PiSmmCoreImageContext, (VOID *)(UINTN)LoadAddress, DestinationSize, NULL, 0); if (!EFI_ERROR (Status)) { + LoadAddress = UefiImageLoaderGetImageAddress (&gSmmCorePrivate->PiSmmCoreImageContext); // - // Relocate the image in our new buffer + // Print debug message showing SMM Core entry point address. // - Status = PeCoffLoaderRelocateImage (&ImageContext); - if (!EFI_ERROR (Status)) { - // - // Flush the instruction cache so the image data are written before we execute it - // - InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize); - - // - // Print debug message showing SMM Core entry point address. - // - DEBUG ((DEBUG_INFO, "SMM IPL calling SMM Core at SMRAM address %p\n", (VOID *)(UINTN)ImageContext.EntryPoint)); - - gSmmCorePrivate->PiSmmCoreImageBase = ImageContext.ImageAddress; - gSmmCorePrivate->PiSmmCoreImageSize = ImageContext.ImageSize; - DEBUG ((DEBUG_INFO, "PiSmmCoreImageBase - 0x%016lx\n", gSmmCorePrivate->PiSmmCoreImageBase)); - DEBUG ((DEBUG_INFO, "PiSmmCoreImageSize - 0x%016lx\n", gSmmCorePrivate->PiSmmCoreImageSize)); + DEBUG ((DEBUG_INFO, "SMM IPL calling SMM Core at SMRAM address %p\n", (VOID *)(UINTN)(UefiImageLoaderGetImageEntryPoint (&gSmmCorePrivate->PiSmmCoreImageContext)))); - gSmmCorePrivate->PiSmmCoreEntryPoint = ImageContext.EntryPoint; + gSmmCorePrivate->PiSmmCoreImageBase = LoadAddress; + DEBUG ((DEBUG_INFO, "PiSmmCoreImageBase - 0x%016lx\n", gSmmCorePrivate->PiSmmCoreImageBase)); + DEBUG ((DEBUG_INFO, "PiSmmCoreImageSize - 0x%016lx\n", UefiImageGetImageSize (&gSmmCorePrivate->PiSmmCoreImageContext))); - // - // Execute image - // - EntryPoint = (EFI_IMAGE_ENTRY_POINT)(UINTN)ImageContext.EntryPoint; - Status = EntryPoint ((EFI_HANDLE)Context, gST); - } + // + // Execute image + // + EntryPoint = (EFI_IMAGE_ENTRY_POINT)(UINTN)(UefiImageLoaderGetImageEntryPoint (&gSmmCorePrivate->PiSmmCoreImageContext)); + Status = EntryPoint ((EFI_HANDLE)Context, gST); } // diff --git a/MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf b/MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf index ddeb39cee2..60d14cd59c 100644 --- a/MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf +++ b/MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf @@ -35,7 +35,7 @@ UefiDriverEntryPoint BaseLib BaseMemoryLib - PeCoffLib + UefiImageLib CacheMaintenanceLib MemoryAllocationLib DebugLib diff --git a/MdeModulePkg/Core/PiSmmCore/SmiHandlerProfile.c b/MdeModulePkg/Core/PiSmmCore/SmiHandlerProfile.c index 27da2898dd..c2bf7c6299 100644 --- a/MdeModulePkg/Core/PiSmmCore/SmiHandlerProfile.c +++ b/MdeModulePkg/Core/PiSmmCore/SmiHandlerProfile.c @@ -16,7 +16,6 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #include #include #include -#include #include #include #include @@ -65,7 +64,7 @@ RegisterSmiHandlerProfileHandler ( **/ RETURN_STATUS -InternalPeCoffGetEntryPoint ( +InternalUefiImageGetEntryPoint ( IN VOID *Pe32Data, OUT VOID **EntryPoint ); @@ -255,7 +254,6 @@ GetSmmLoadedImage ( CHAR16 *PathStr; EFI_SMM_DRIVER_ENTRY *LoadedImagePrivate; PHYSICAL_ADDRESS EntryPoint; - VOID *EntryPointInImage; EFI_GUID Guid; CHAR8 *PdbString; PHYSICAL_ADDRESS RealImageBase; @@ -315,15 +313,6 @@ GetSmmLoadedImage ( RealImageBase = (UINTN)LoadedImage->ImageBase; if (LoadedImagePrivate->Signature == EFI_SMM_DRIVER_ENTRY_SIGNATURE) { EntryPoint = LoadedImagePrivate->ImageEntryPoint; - if ((EntryPoint != 0) && ((EntryPoint < (UINTN)LoadedImage->ImageBase) || (EntryPoint >= ((UINTN)LoadedImage->ImageBase + LoadedImage->ImageSize)))) { - // - // If the EntryPoint is not in the range of image buffer, it should come from emulation environment. - // So patch ImageBuffer here to align the EntryPoint. - // - Status = InternalPeCoffGetEntryPoint (LoadedImage->ImageBase, &EntryPointInImage); - ASSERT_EFI_ERROR (Status); - RealImageBase = (UINTN)LoadedImage->ImageBase + EntryPoint - (UINTN)EntryPointInImage; - } } DEBUG ((DEBUG_INFO, "(0x%lx - 0x%lx", RealImageBase, LoadedImage->ImageSize)); @@ -333,10 +322,11 @@ GetSmmLoadedImage ( DEBUG ((DEBUG_INFO, ")\n")); - if (RealImageBase != 0) { - PdbString = PeCoffLoaderGetPdbPointer ((VOID *)(UINTN)RealImageBase); + // FIXME: + /*if (RealImageBase != 0) { + PdbString = UefiImageLoaderGetPdbPointer ((VOID *)(UINTN)RealImageBase); DEBUG ((DEBUG_INFO, " pdb - %a\n", PdbString)); - } else { + } else*/ { PdbString = NULL; } diff --git a/MdeModulePkg/Core/PiSmmCore/SmramProfileRecord.c b/MdeModulePkg/Core/PiSmmCore/SmramProfileRecord.c index b437e4c433..1fa33efbbe 100644 --- a/MdeModulePkg/Core/PiSmmCore/SmramProfileRecord.c +++ b/MdeModulePkg/Core/PiSmmCore/SmramProfileRecord.c @@ -128,8 +128,7 @@ EFIAPI SmramProfileProtocolRegisterImage ( IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL *This, IN EFI_DEVICE_PATH_PROTOCOL *FilePath, - IN PHYSICAL_ADDRESS ImageBase, - IN UINT64 ImageSize, + IN UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext, IN EFI_FV_FILETYPE FileType ); @@ -249,110 +248,6 @@ GetSmramProfileContext ( return mSmramProfileContextPtr; } -/** - Retrieves and returns the Subsystem of a PE/COFF image that has been loaded into system memory. - If Pe32Data is NULL, then ASSERT(). - - @param Pe32Data The pointer to the PE/COFF image that is loaded in system memory. - - @return The Subsystem of the PE/COFF image. - -**/ -UINT16 -InternalPeCoffGetSubsystem ( - IN VOID *Pe32Data - ) -{ - EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr; - EFI_IMAGE_DOS_HEADER *DosHdr; - UINT16 Magic; - - ASSERT (Pe32Data != NULL); - - DosHdr = (EFI_IMAGE_DOS_HEADER *)Pe32Data; - if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) { - // - // DOS image header is present, so read the PE header after the DOS image header. - // - Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN)Pe32Data + (UINTN)((DosHdr->e_lfanew) & 0x0ffff)); - } else { - // - // DOS image header is not present, so PE header is at the image base. - // - Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)Pe32Data; - } - - if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) { - return Hdr.Te->Subsystem; - } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) { - Magic = Hdr.Pe32->OptionalHeader.Magic; - if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { - return Hdr.Pe32->OptionalHeader.Subsystem; - } else if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) { - return Hdr.Pe32Plus->OptionalHeader.Subsystem; - } - } - - return 0x0000; -} - -/** - Retrieves and returns a pointer to the entry point to a PE/COFF image that has been loaded - into system memory with the PE/COFF Loader Library functions. - - Retrieves the entry point to the PE/COFF image specified by Pe32Data and returns this entry - point in EntryPoint. If the entry point could not be retrieved from the PE/COFF image, then - return RETURN_INVALID_PARAMETER. Otherwise return RETURN_SUCCESS. - If Pe32Data is NULL, then ASSERT(). - If EntryPoint is NULL, then ASSERT(). - - @param Pe32Data The pointer to the PE/COFF image that is loaded in system memory. - @param EntryPoint The pointer to entry point to the PE/COFF image to return. - - @retval RETURN_SUCCESS EntryPoint was returned. - @retval RETURN_INVALID_PARAMETER The entry point could not be found in the PE/COFF image. - -**/ -RETURN_STATUS -InternalPeCoffGetEntryPoint ( - IN VOID *Pe32Data, - OUT VOID **EntryPoint - ) -{ - EFI_IMAGE_DOS_HEADER *DosHdr; - EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr; - - ASSERT (Pe32Data != NULL); - ASSERT (EntryPoint != NULL); - - DosHdr = (EFI_IMAGE_DOS_HEADER *)Pe32Data; - if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) { - // - // DOS image header is present, so read the PE header after the DOS image header. - // - Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN)Pe32Data + (UINTN)((DosHdr->e_lfanew) & 0x0ffff)); - } else { - // - // DOS image header is not present, so PE header is at the image base. - // - Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)Pe32Data; - } - - // - // Calculate the entry point relative to the start of the image. - // AddressOfEntryPoint is common for PE32 & PE32+ - // - if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) { - *EntryPoint = (VOID *)((UINTN)Pe32Data + (UINTN)(Hdr.Te->AddressOfEntryPoint & 0x0ffffffff) + sizeof (EFI_TE_IMAGE_HEADER) - Hdr.Te->StrippedSize); - return RETURN_SUCCESS; - } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) { - *EntryPoint = (VOID *)((UINTN)Pe32Data + (UINTN)(Hdr.Pe32->OptionalHeader.AddressOfEntryPoint & 0x0ffffffff)); - return RETURN_SUCCESS; - } - - return RETURN_UNSUPPORTED; -} - /** Build driver info. @@ -371,30 +266,26 @@ MEMORY_PROFILE_DRIVER_INFO_DATA * BuildDriverInfo ( IN MEMORY_PROFILE_CONTEXT_DATA *ContextData, IN EFI_GUID *FileName, - IN PHYSICAL_ADDRESS ImageBase, - IN UINT64 ImageSize, - IN PHYSICAL_ADDRESS EntryPoint, - IN UINT16 ImageSubsystem, + IN UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext, + IN EFI_PHYSICAL_ADDRESS LoadAddress, IN EFI_FV_FILETYPE FileType ) { + RETURN_STATUS PdbStatus; EFI_STATUS Status; MEMORY_PROFILE_DRIVER_INFO *DriverInfo; - MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData; - VOID *EntryPointInImage; - CHAR8 *PdbString; - UINTN PdbSize; - UINTN PdbOccupiedSize; + MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData; + CONST CHAR8 *PdbString; + UINT32 PdbSize; + UINTN PdbOccupiedSize; - PdbSize = 0; PdbOccupiedSize = 0; - PdbString = NULL; - if (ImageBase != 0) { - PdbString = PeCoffLoaderGetPdbPointer ((VOID *)(UINTN)ImageBase); - if (PdbString != NULL) { - PdbSize = AsciiStrSize (PdbString); - PdbOccupiedSize = GET_OCCUPIED_SIZE (PdbSize, sizeof (UINT64)); - } + + ASSERT (UefiImageLoaderGetImageAddress (ImageContext) != 0); + + PdbStatus = UefiImageGetSymbolsPath (ImageContext, &PdbString, &PdbSize); + if (!EFI_ERROR (PdbStatus)) { + PdbOccupiedSize = GET_OCCUPIED_SIZE (PdbSize, sizeof (UINT64)); } // @@ -422,19 +313,10 @@ BuildDriverInfo ( CopyMem (&DriverInfo->FileName, FileName, sizeof (EFI_GUID)); } - DriverInfo->ImageBase = ImageBase; - DriverInfo->ImageSize = ImageSize; - DriverInfo->EntryPoint = EntryPoint; - DriverInfo->ImageSubsystem = ImageSubsystem; - if ((EntryPoint != 0) && ((EntryPoint < ImageBase) || (EntryPoint >= (ImageBase + ImageSize)))) { - // - // If the EntryPoint is not in the range of image buffer, it should come from emulation environment. - // So patch ImageBuffer here to align the EntryPoint. - // - Status = InternalPeCoffGetEntryPoint ((VOID *)(UINTN)ImageBase, &EntryPointInImage); - ASSERT_EFI_ERROR (Status); - DriverInfo->ImageBase = ImageBase + EntryPoint - (PHYSICAL_ADDRESS)(UINTN)EntryPointInImage; - } + DriverInfo->ImageBase = LoadAddress; + DriverInfo->ImageSize = UefiImageGetImageSize (ImageContext); + DriverInfo->EntryPoint = UefiImageLoaderGetImageEntryPoint (ImageContext); + DriverInfo->ImageSubsystem = UefiImageGetSubsystem (ImageContext); DriverInfo->FileType = FileType; DriverInfoData->AllocInfoList = (LIST_ENTRY *)(DriverInfoData + 1); @@ -442,7 +324,7 @@ BuildDriverInfo ( DriverInfo->CurrentUsage = 0; DriverInfo->PeakUsage = 0; DriverInfo->AllocRecordCount = 0; - if (PdbSize != 0) { + if (!RETURN_ERROR (PdbStatus)) { DriverInfo->PdbStringOffset = (UINT16)sizeof (MEMORY_PROFILE_DRIVER_INFO); DriverInfoData->PdbString = (CHAR8 *)(DriverInfoData->AllocInfoList + 1); CopyMem (DriverInfoData->PdbString, PdbString, PdbSize); @@ -470,8 +352,7 @@ BuildDriverInfo ( VOID RegisterImageToDxe ( IN EFI_GUID *FileName, - IN PHYSICAL_ADDRESS ImageBase, - IN UINT64 ImageSize, + IN UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext, IN EFI_FV_FILETYPE FileType ) { @@ -490,8 +371,7 @@ RegisterImageToDxe ( Status = ProfileProtocol->RegisterImage ( ProfileProtocol, (EFI_DEVICE_PATH_PROTOCOL *)FilePath, - ImageBase, - ImageSize, + ImageContext, FileType ); } @@ -610,7 +490,6 @@ RegisterSmmCore ( ) { MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData; - PHYSICAL_ADDRESS ImageBase; UINT8 TempBuffer[sizeof (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH) + sizeof (EFI_DEVICE_PATH_PROTOCOL)]; MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FilePath; @@ -622,14 +501,11 @@ RegisterSmmCore ( return FALSE; } - ImageBase = gSmmCorePrivate->PiSmmCoreImageBase; DriverInfoData = BuildDriverInfo ( ContextData, &gEfiCallerIdGuid, - ImageBase, - gSmmCorePrivate->PiSmmCoreImageSize, - gSmmCorePrivate->PiSmmCoreEntryPoint, - InternalPeCoffGetSubsystem ((VOID *)(UINTN)ImageBase), + &gSmmCorePrivate->PiSmmCoreImageContext, + gSmmCorePrivate->PiSmmCoreImageBase, EFI_FV_FILETYPE_SMM_CORE ); if (DriverInfoData == NULL) { @@ -652,8 +528,7 @@ SmramProfileInit ( RegisterImageToDxe ( &gEfiCallerIdGuid, - gSmmCorePrivate->PiSmmCoreImageBase, - gSmmCorePrivate->PiSmmCoreImageSize, + &gSmmCorePrivate->PiSmmCoreImageContext, EFI_FV_FILETYPE_SMM_CORE ); @@ -754,8 +629,9 @@ GetFileNameFromFilePath ( **/ EFI_STATUS RegisterSmramProfileImage ( - IN EFI_SMM_DRIVER_ENTRY *DriverEntry, - IN BOOLEAN RegisterToDxe + IN EFI_GUID *FileName, + IN BOOLEAN RegisterToDxe, + IN UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext ) { MEMORY_PROFILE_CONTEXT_DATA *ContextData; @@ -765,9 +641,8 @@ RegisterSmramProfileImage ( if (RegisterToDxe) { RegisterImageToDxe ( - &DriverEntry->FileName, - DriverEntry->ImageBuffer, - EFI_PAGES_TO_SIZE (DriverEntry->NumberOfPage), + FileName, + ImageContext, EFI_FV_FILETYPE_SMM ); } @@ -777,7 +652,7 @@ RegisterSmramProfileImage ( } FilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)TempBuffer; - EfiInitializeFwVolDevicepathNode (FilePath, &DriverEntry->FileName); + EfiInitializeFwVolDevicepathNode (FilePath, FileName); SetDevicePathEndNode (FilePath + 1); if (!NeedRecordThisDriver ((EFI_DEVICE_PATH_PROTOCOL *)FilePath)) { @@ -791,11 +666,9 @@ RegisterSmramProfileImage ( DriverInfoData = BuildDriverInfo ( ContextData, - &DriverEntry->FileName, - DriverEntry->ImageBuffer, - EFI_PAGES_TO_SIZE (DriverEntry->NumberOfPage), - DriverEntry->ImageEntryPoint, - InternalPeCoffGetSubsystem ((VOID *)(UINTN)DriverEntry->ImageBuffer), + FileName, + ImageContext, + UefiImageLoaderGetImageAddress (ImageContext), EFI_FV_FILETYPE_SMM ); if (DriverInfoData == NULL) { @@ -909,24 +782,22 @@ GetMemoryProfileDriverInfoFromAddress ( **/ EFI_STATUS UnregisterSmramProfileImage ( - IN EFI_SMM_DRIVER_ENTRY *DriverEntry, - IN BOOLEAN UnregisterFromDxe + IN EFI_GUID *FileName, + IN PHYSICAL_ADDRESS ImageBase, + IN UINT64 ImageSize, + IN BOOLEAN UnregisterFromDxe ) { - EFI_STATUS Status; MEMORY_PROFILE_CONTEXT_DATA *ContextData; MEMORY_PROFILE_DRIVER_INFO_DATA *DriverInfoData; - EFI_GUID *FileName; - PHYSICAL_ADDRESS ImageAddress; - VOID *EntryPointInImage; UINT8 TempBuffer[sizeof (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH) + sizeof (EFI_DEVICE_PATH_PROTOCOL)]; MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FilePath; if (UnregisterFromDxe) { UnregisterImageFromDxe ( - &DriverEntry->FileName, - DriverEntry->ImageBuffer, - EFI_PAGES_TO_SIZE (DriverEntry->NumberOfPage) + FileName, + ImageBase, + ImageSize ); } @@ -935,7 +806,7 @@ UnregisterSmramProfileImage ( } FilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)TempBuffer; - EfiInitializeFwVolDevicepathNode (FilePath, &DriverEntry->FileName); + EfiInitializeFwVolDevicepathNode (FilePath, FileName); SetDevicePathEndNode (FilePath + 1); if (!NeedRecordThisDriver ((EFI_DEVICE_PATH_PROTOCOL *)FilePath)) { @@ -948,24 +819,13 @@ UnregisterSmramProfileImage ( } DriverInfoData = NULL; - FileName = &DriverEntry->FileName; - ImageAddress = DriverEntry->ImageBuffer; - if ((DriverEntry->ImageEntryPoint < ImageAddress) || (DriverEntry->ImageEntryPoint >= (ImageAddress + EFI_PAGES_TO_SIZE (DriverEntry->NumberOfPage)))) { - // - // If the EntryPoint is not in the range of image buffer, it should come from emulation environment. - // So patch ImageAddress here to align the EntryPoint. - // - Status = InternalPeCoffGetEntryPoint ((VOID *)(UINTN)ImageAddress, &EntryPointInImage); - ASSERT_EFI_ERROR (Status); - ImageAddress = ImageAddress + (UINTN)DriverEntry->ImageEntryPoint - (UINTN)EntryPointInImage; - } if (FileName != NULL) { - DriverInfoData = GetMemoryProfileDriverInfoByFileNameAndAddress (ContextData, FileName, ImageAddress); + DriverInfoData = GetMemoryProfileDriverInfoByFileNameAndAddress (ContextData, FileName, ImageBase); } if (DriverInfoData == NULL) { - DriverInfoData = GetMemoryProfileDriverInfoFromAddress (ContextData, ImageAddress); + DriverInfoData = GetMemoryProfileDriverInfoFromAddress (ContextData, ImageBase); } if (DriverInfoData == NULL) { @@ -1989,29 +1849,20 @@ EFIAPI SmramProfileProtocolRegisterImage ( IN EDKII_SMM_MEMORY_PROFILE_PROTOCOL *This, IN EFI_DEVICE_PATH_PROTOCOL *FilePath, - IN PHYSICAL_ADDRESS ImageBase, - IN UINT64 ImageSize, + IN UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext, IN EFI_FV_FILETYPE FileType ) { - EFI_STATUS Status; - EFI_SMM_DRIVER_ENTRY DriverEntry; - VOID *EntryPointInImage; - EFI_GUID *Name; + EFI_GUID *FileName; + EFI_GUID ZeroGuid; - ZeroMem (&DriverEntry, sizeof (DriverEntry)); - Name = GetFileNameFromFilePath (FilePath); - if (Name != NULL) { - CopyMem (&DriverEntry.FileName, Name, sizeof (EFI_GUID)); + FileName = GetFileNameFromFilePath (FilePath); + if (FileName == NULL) { + ZeroMem (&ZeroGuid, sizeof (ZeroGuid)); + FileName = &ZeroGuid; } - DriverEntry.ImageBuffer = ImageBase; - DriverEntry.NumberOfPage = EFI_SIZE_TO_PAGES ((UINTN)ImageSize); - Status = InternalPeCoffGetEntryPoint ((VOID *)(UINTN)DriverEntry.ImageBuffer, &EntryPointInImage); - ASSERT_EFI_ERROR (Status); - DriverEntry.ImageEntryPoint = (PHYSICAL_ADDRESS)(UINTN)EntryPointInImage; - - return RegisterSmramProfileImage (&DriverEntry, FALSE); + return RegisterSmramProfileImage (FileName, FALSE, ImageContext); } /** @@ -2037,24 +1888,16 @@ SmramProfileProtocolUnregisterImage ( IN UINT64 ImageSize ) { - EFI_STATUS Status; - EFI_SMM_DRIVER_ENTRY DriverEntry; - VOID *EntryPointInImage; - EFI_GUID *Name; + EFI_GUID *FileName; + EFI_GUID ZeroGuid; - ZeroMem (&DriverEntry, sizeof (DriverEntry)); - Name = GetFileNameFromFilePath (FilePath); - if (Name != NULL) { - CopyMem (&DriverEntry.FileName, Name, sizeof (EFI_GUID)); + FileName = GetFileNameFromFilePath (FilePath); + if (FileName == NULL) { + ZeroMem (&ZeroGuid, sizeof (ZeroGuid)); + FileName = &ZeroGuid; } - DriverEntry.ImageBuffer = ImageBase; - DriverEntry.NumberOfPage = EFI_SIZE_TO_PAGES ((UINTN)ImageSize); - Status = InternalPeCoffGetEntryPoint ((VOID *)(UINTN)DriverEntry.ImageBuffer, &EntryPointInImage); - ASSERT_EFI_ERROR (Status); - DriverEntry.ImageEntryPoint = (PHYSICAL_ADDRESS)(UINTN)EntryPointInImage; - - return UnregisterSmramProfileImage (&DriverEntry, FALSE); + return UnregisterSmramProfileImage (FileName, ImageBase, ImageSize, FALSE); } /** diff --git a/MdeModulePkg/Core/RuntimeDxe/Runtime.c b/MdeModulePkg/Core/RuntimeDxe/Runtime.c index c66ed71e35..314a424e14 100644 --- a/MdeModulePkg/Core/RuntimeDxe/Runtime.c +++ b/MdeModulePkg/Core/RuntimeDxe/Runtime.c @@ -325,14 +325,12 @@ RuntimeDriverSetVirtualAddressMap ( Status = RuntimeDriverConvertPointer (0, (VOID **)&VirtImageBase); ASSERT_EFI_ERROR (Status); - PeCoffLoaderRelocateImageForRuntime ( - (EFI_PHYSICAL_ADDRESS)(UINTN)RuntimeImage->ImageBase, + UefiImageRuntimeRelocateImageForExecution ( + (VOID *)(UINTN)RuntimeImage->ImageBase, + (UINT32)RuntimeImage->ImageSize, VirtImageBase, - (UINTN)RuntimeImage->ImageSize, RuntimeImage->RelocationData ); - - InvalidateInstructionCacheRange (RuntimeImage->ImageBase, (UINTN)RuntimeImage->ImageSize); } } diff --git a/MdeModulePkg/Core/RuntimeDxe/Runtime.h b/MdeModulePkg/Core/RuntimeDxe/Runtime.h index 1e28b98d78..00ac1fe08d 100644 --- a/MdeModulePkg/Core/RuntimeDxe/Runtime.h +++ b/MdeModulePkg/Core/RuntimeDxe/Runtime.h @@ -22,7 +22,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #include #include #include -#include +#include // // Function Prototypes diff --git a/MdeModulePkg/Core/RuntimeDxe/RuntimeDxe.inf b/MdeModulePkg/Core/RuntimeDxe/RuntimeDxe.inf index 694c7690fa..36d282d69a 100644 --- a/MdeModulePkg/Core/RuntimeDxe/RuntimeDxe.inf +++ b/MdeModulePkg/Core/RuntimeDxe/RuntimeDxe.inf @@ -39,7 +39,7 @@ MdePkg/MdePkg.dec [LibraryClasses] - PeCoffLib + UefiImageLib CacheMaintenanceLib UefiBootServicesTableLib UefiLib diff --git a/MdeModulePkg/Include/Guid/MemoryProfile.h b/MdeModulePkg/Include/Guid/MemoryProfile.h index 8194b06330..33a033bb00 100644 --- a/MdeModulePkg/Include/Guid/MemoryProfile.h +++ b/MdeModulePkg/Include/Guid/MemoryProfile.h @@ -11,6 +11,8 @@ #include +#include + // // For BIOS MemoryType (0 ~ EfiMaxMemoryType - 1), it is recorded in UsageByType[MemoryType]. (Each valid entry has one entry) // For OS MemoryType (0x80000000 ~ 0xFFFFFFFF), it is recorded in UsageByType[EfiMaxMemoryType]. (All types are combined into one entry) @@ -242,8 +244,7 @@ EFI_STATUS (EFIAPI *EDKII_MEMORY_PROFILE_REGISTER_IMAGE)( IN EDKII_MEMORY_PROFILE_PROTOCOL *This, IN EFI_DEVICE_PATH_PROTOCOL *FilePath, - IN PHYSICAL_ADDRESS ImageBase, - IN UINT64 ImageSize, + IN UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext, IN EFI_FV_FILETYPE FileType ); diff --git a/MdeModulePkg/Include/Library/ImagePropertiesRecordLib.h b/MdeModulePkg/Include/Library/ImagePropertiesRecordLib.h index 87c94c7237..7207e9f763 100644 --- a/MdeModulePkg/Include/Library/ImagePropertiesRecordLib.h +++ b/MdeModulePkg/Include/Library/ImagePropertiesRecordLib.h @@ -11,25 +11,7 @@ #ifndef IMAGE_PROPERTIES_RECORD_SUPPORT_LIB_H_ #define IMAGE_PROPERTIES_RECORD_SUPPORT_LIB_H_ -#define IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE SIGNATURE_32 ('I','P','R','C') - -typedef struct { - UINT32 Signature; - LIST_ENTRY Link; - EFI_PHYSICAL_ADDRESS CodeSegmentBase; - UINT64 CodeSegmentSize; -} IMAGE_PROPERTIES_RECORD_CODE_SECTION; - -#define IMAGE_PROPERTIES_RECORD_SIGNATURE SIGNATURE_32 ('I','P','R','D') - -typedef struct { - UINT32 Signature; - LIST_ENTRY Link; - EFI_PHYSICAL_ADDRESS ImageBase; - UINT64 ImageSize; - UINTN CodeSegmentCount; - LIST_ENTRY CodeSegmentList; -} IMAGE_PROPERTIES_RECORD; +#include /** Split the original memory map and add more entries to describe PE code @@ -82,142 +64,6 @@ SplitTable ( IN UINTN NumberOfAdditionalDescriptors ); -/** - Sort the code sections in the input ImageRecord based upon CodeSegmentBase from low to high. - - @param[in] ImageRecord IMAGE_PROPERTIES_RECORD to be sorted - - @retval EFI_SUCCESS The code sections in the input ImageRecord were sorted successfully - @retval EFI_ABORTED An error occurred while sorting the code sections in the input ImageRecord - @retval EFI_INVALID_PARAMETER ImageRecord is NULL -**/ -EFI_STATUS -EFIAPI -SortImageRecordCodeSection ( - IN IMAGE_PROPERTIES_RECORD *ImageRecord - ); - -/** - Check if the code sections in the input ImageRecord are valid. - The code sections are valid if they don't overlap, are contained - within the the ImageRecord's ImageBase and ImageSize, and are - contained within the MAX_ADDRESS. - - @param[in] ImageRecord IMAGE_PROPERTIES_RECORD to be checked - - @retval TRUE The code sections in the input ImageRecord are valid - @retval FALSE The code sections in the input ImageRecord are invalid -**/ -BOOLEAN -EFIAPI -IsImageRecordCodeSectionValid ( - IN IMAGE_PROPERTIES_RECORD *ImageRecord - ); - -/** - Sort the input ImageRecordList based upon the ImageBase from low to high. - - @param[in] ImageRecordList Image record list to be sorted - - @retval EFI_SUCCESS The image record list was sorted successfully - @retval EFI_ABORTED An error occurred while sorting the image record list - @retval EFI_INVALID_PARAMETER ImageRecordList is NULL -**/ -EFI_STATUS -EFIAPI -SortImageRecord ( - IN LIST_ENTRY *ImageRecordList - ); - -/** - Swap two image records. - - @param[in] FirstImageRecord The first image record. - @param[in] SecondImageRecord The second image record. - - @retval EFI_SUCCESS The image records were swapped successfully - @retval EFI_INVALID_PARAMETER FirstImageRecord or SecondImageRecord is NULL -**/ -EFI_STATUS -EFIAPI -SwapImageRecord ( - IN IMAGE_PROPERTIES_RECORD *FirstImageRecord, - IN IMAGE_PROPERTIES_RECORD *SecondImageRecord - ); - -/** - Swap two code sections in a single IMAGE_PROPERTIES_RECORD. - - @param[in] FirstImageRecordCodeSection The first code section - @param[in] SecondImageRecordCodeSection The second code section - - @retval EFI_SUCCESS The code sections were swapped successfully - @retval EFI_INVALID_PARAMETER FirstImageRecordCodeSection or SecondImageRecordCodeSection is NULL -**/ -EFI_STATUS -EFIAPI -SwapImageRecordCodeSection ( - IN IMAGE_PROPERTIES_RECORD_CODE_SECTION *FirstImageRecordCodeSection, - IN IMAGE_PROPERTIES_RECORD_CODE_SECTION *SecondImageRecordCodeSection - ); - -/** - Find image properties record according to image base and size in the - input ImageRecordList. - - @param[in] ImageBase Base of PE image - @param[in] ImageSize Size of PE image - @param[in] ImageRecordList Image record list to be searched - - @retval NULL No IMAGE_PROPERTIES_RECORD matches ImageBase - and ImageSize in the input ImageRecordList - @retval Other The found IMAGE_PROPERTIES_RECORD -**/ -IMAGE_PROPERTIES_RECORD * -EFIAPI -FindImageRecord ( - IN EFI_PHYSICAL_ADDRESS ImageBase, - IN UINT64 ImageSize, - IN LIST_ENTRY *ImageRecordList - ); - -/** - Debug dumps the input list of IMAGE_PROPERTIES_RECORD structs. - - @param[in] ImageRecordList Head of the IMAGE_PROPERTIES_RECORD list -**/ -VOID -EFIAPI -DumpImageRecords ( - IN LIST_ENTRY *ImageRecordList - ); - -/** - Creates an IMAGE_PROPERTIES_RECORD from a loaded PE image. The PE/COFF header will be found - and parsed to determine the number of code segments and their base addresses and sizes. - - @param[in] ImageBase Base of the PE image - @param[in] ImageSize Size of the PE image - @param[in] RequiredAlignment If non-NULL, the alignment specified in the PE/COFF header - will be compared against this value. - @param[out] ImageRecord On out, a populated image properties record - - @retval EFI_INVALID_PARAMETER This function ImageBase or ImageRecord was NULL, or the - image located at ImageBase was not a valid PE/COFF image - @retval EFI_OUT_OF_RESOURCES Failure to Allocate() - @retval EFI_ABORTED The input Alignment was non-NULL and did not match the - alignment specified in the PE/COFF header - @retval EFI_SUCCESS The image properties record was successfully created -**/ -EFI_STATUS -EFIAPI -CreateImagePropertiesRecord ( - IN CONST VOID *ImageBase, - IN CONST UINT64 ImageSize, - IN CONST UINT32 *Alignment OPTIONAL, - OUT IMAGE_PROPERTIES_RECORD *ImageRecord - ); - /** Deleted an image properties record. The function will also call RemoveEntryList() on each code segment and the input ImageRecord before @@ -228,7 +74,7 @@ CreateImagePropertiesRecord ( VOID EFIAPI DeleteImagePropertiesRecord ( - IN IMAGE_PROPERTIES_RECORD *ImageRecord + IN UEFI_IMAGE_RECORD *ImageRecord ); #endif diff --git a/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.c b/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.c index ef32771561..9825fdaeab 100644 --- a/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.c +++ b/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.c @@ -462,9 +462,9 @@ GetModuleInfoFromHandle ( EFI_STATUS Status; EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; EFI_DRIVER_BINDING_PROTOCOL *DriverBinding; - CHAR8 *PdbFileName; + //CHAR8 *PdbFileName; EFI_GUID *TempGuid; - UINTN StartIndex; + //UINTN StartIndex; UINTN Index; INTN Count; BOOLEAN ModuleGuidIsGet; @@ -558,7 +558,8 @@ GetModuleInfoFromHandle ( // // Method 1 Get Module Name from PDB string. // - PdbFileName = PeCoffLoaderGetPdbPointer (LoadedImage->ImageBase); + // FIXME: + /*PdbFileName = UefiImageLoaderGetPdbPointer (LoadedImage->ImageBase); if ((PdbFileName != NULL) && (BufferSize > 0)) { StartIndex = 0; for (Index = 0; PdbFileName[Index] != 0; Index++) { @@ -587,7 +588,7 @@ GetModuleInfoFromHandle ( // Module Name is got. // goto Done; - } + }*/ } // diff --git a/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.inf b/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.inf index 599d4dea66..0a36591c63 100644 --- a/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.inf +++ b/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.inf @@ -54,7 +54,6 @@ UefiLib ReportStatusCodeLib DxeServicesLib - PeCoffGetEntryPointLib DevicePathLib [Protocols] diff --git a/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLibInternal.h b/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLibInternal.h index 8f32018c06..155e71555a 100644 --- a/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLibInternal.h +++ b/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLibInternal.h @@ -42,7 +42,6 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #include #include #include -#include /** Create performance record with event description and a timestamp. diff --git a/MdeModulePkg/Library/ImagePropertiesRecordLib/ImagePropertiesRecordLib.c b/MdeModulePkg/Library/ImagePropertiesRecordLib/ImagePropertiesRecordLib.c index 3ac043f980..22a1a7cc5a 100644 --- a/MdeModulePkg/Library/ImagePropertiesRecordLib/ImagePropertiesRecordLib.c +++ b/MdeModulePkg/Library/ImagePropertiesRecordLib/ImagePropertiesRecordLib.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #define PREVIOUS_MEMORY_DESCRIPTOR(MemoryDescriptor, Size) \ @@ -60,39 +59,6 @@ EfiSizeToPages ( return RShiftU64 (Size, EFI_PAGE_SHIFT) + ((((UINTN)Size) & EFI_PAGE_MASK) ? 1 : 0); } -/** - Frees the memory for each ImageRecordCodeSection within an ImageRecord - and removes the entries from the list. It does not free the ImageRecord - itself. - - @param[in] ImageRecord The ImageRecord in which to free code sections -**/ -STATIC -VOID -FreeImageRecordCodeSections ( - IMAGE_PROPERTIES_RECORD *ImageRecord - ) -{ - LIST_ENTRY *CodeSegmentListHead; - IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection; - - if (ImageRecord == NULL) { - return; - } - - CodeSegmentListHead = &ImageRecord->CodeSegmentList; - while (!IsListEmpty (CodeSegmentListHead)) { - ImageRecordCodeSection = CR ( - CodeSegmentListHead->ForwardLink, - IMAGE_PROPERTIES_RECORD_CODE_SECTION, - Link, - IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE - ); - RemoveEntryList (&ImageRecordCodeSection->Link); - FreePool (ImageRecordCodeSection); - } -} - /** Sort memory map entries based upon PhysicalStart from low to high. @@ -146,15 +112,15 @@ SortMemoryMap ( @retval The first image record covered by [Buffer, Length] **/ STATIC -IMAGE_PROPERTIES_RECORD * +UEFI_IMAGE_RECORD * GetImageRecordByAddress ( IN EFI_PHYSICAL_ADDRESS Buffer, IN UINT64 Length, IN LIST_ENTRY *ImageRecordList ) { - IMAGE_PROPERTIES_RECORD *ImageRecord; - LIST_ENTRY *ImageRecordLink; + UEFI_IMAGE_RECORD *ImageRecord; + LIST_ENTRY *ImageRecordLink; for (ImageRecordLink = ImageRecordList->ForwardLink; ImageRecordLink != ImageRecordList; @@ -162,13 +128,13 @@ GetImageRecordByAddress ( { ImageRecord = CR ( ImageRecordLink, - IMAGE_PROPERTIES_RECORD, + UEFI_IMAGE_RECORD, Link, - IMAGE_PROPERTIES_RECORD_SIGNATURE + UEFI_IMAGE_RECORD_SIGNATURE ); - if ((Buffer <= ImageRecord->ImageBase) && - (Buffer + Length >= ImageRecord->ImageBase + ImageRecord->ImageSize)) + if ((Buffer <= ImageRecord->StartAddress) && + (Buffer + Length >= ImageRecord->EndAddress)) { return ImageRecord; } @@ -195,88 +161,48 @@ GetImageRecordByAddress ( STATIC UINTN SetNewRecord ( - IN IMAGE_PROPERTIES_RECORD *ImageRecord, + IN UEFI_IMAGE_RECORD *ImageRecord, IN OUT EFI_MEMORY_DESCRIPTOR *NewRecord, IN EFI_MEMORY_DESCRIPTOR *OldRecord, IN UINTN DescriptorSize ) { - EFI_MEMORY_DESCRIPTOR TempRecord; - IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection; - LIST_ENTRY *ImageRecordCodeSectionLink; - LIST_ENTRY *ImageRecordCodeSectionEndLink; - LIST_ENTRY *ImageRecordCodeSectionList; - UINTN NewRecordCount; - UINT64 PhysicalEnd; - UINT64 ImageEnd; + EFI_MEMORY_DESCRIPTOR TempRecord; + UEFI_IMAGE_RECORD_SEGMENT *ImageRecordSegment; + UINTN SectionAddress; + UINT32 Index; + UINT32 NewRecordCount; CopyMem (&TempRecord, OldRecord, sizeof (EFI_MEMORY_DESCRIPTOR)); - PhysicalEnd = TempRecord.PhysicalStart + EfiPagesToSize (TempRecord.NumberOfPages); + // + // Always create a new entry for non-PE image record + // NewRecordCount = 0; - - ImageRecordCodeSectionList = &ImageRecord->CodeSegmentList; - - ImageRecordCodeSectionLink = ImageRecordCodeSectionList->ForwardLink; - ImageRecordCodeSectionEndLink = ImageRecordCodeSectionList; - while (ImageRecordCodeSectionLink != ImageRecordCodeSectionEndLink) { - ImageRecordCodeSection = CR ( - ImageRecordCodeSectionLink, - IMAGE_PROPERTIES_RECORD_CODE_SECTION, - Link, - IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE - ); - ImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink; - - if (TempRecord.PhysicalStart <= ImageRecordCodeSection->CodeSegmentBase) { - // - // DATA - // - NewRecord->Type = TempRecord.Type; - NewRecord->PhysicalStart = TempRecord.PhysicalStart; - NewRecord->VirtualStart = 0; - NewRecord->NumberOfPages = EfiSizeToPages (ImageRecordCodeSection->CodeSegmentBase - NewRecord->PhysicalStart); - NewRecord->Attribute = TempRecord.Attribute | EFI_MEMORY_XP; - if (NewRecord->NumberOfPages != 0) { - NewRecord = NEXT_MEMORY_DESCRIPTOR (NewRecord, DescriptorSize); - NewRecordCount++; - } - - // - // CODE - // - NewRecord->Type = TempRecord.Type; - NewRecord->PhysicalStart = ImageRecordCodeSection->CodeSegmentBase; - NewRecord->VirtualStart = 0; - NewRecord->NumberOfPages = EfiSizeToPages (ImageRecordCodeSection->CodeSegmentSize); - NewRecord->Attribute = (TempRecord.Attribute & (~EFI_MEMORY_XP)) | EFI_MEMORY_RO; - if (NewRecord->NumberOfPages != 0) { - NewRecord = NEXT_MEMORY_DESCRIPTOR (NewRecord, DescriptorSize); - NewRecordCount++; - } - - TempRecord.PhysicalStart = ImageRecordCodeSection->CodeSegmentBase + EfiPagesToSize (EfiSizeToPages (ImageRecordCodeSection->CodeSegmentSize)); - TempRecord.NumberOfPages = EfiSizeToPages (PhysicalEnd - TempRecord.PhysicalStart); - if (TempRecord.NumberOfPages == 0) { - break; - } - } + if (ImageRecord->StartAddress > TempRecord.PhysicalStart) { + NewRecord->Type = TempRecord.Type; + NewRecord->PhysicalStart = TempRecord.PhysicalStart; + NewRecord->VirtualStart = 0; + NewRecord->NumberOfPages = EfiSizeToPages (ImageRecord->StartAddress - TempRecord.PhysicalStart); + NewRecord->Attribute = TempRecord.Attribute; + NewRecord = NEXT_MEMORY_DESCRIPTOR (NewRecord, DescriptorSize); + ++NewRecordCount; } - ImageEnd = ImageRecord->ImageBase + ImageRecord->ImageSize; + SectionAddress = ImageRecord->StartAddress; + for (Index = 0; Index < ImageRecord->NumSegments; ++Index) { + ImageRecordSegment = &ImageRecord->Segments[Index]; - // - // Final DATA - // - if (TempRecord.PhysicalStart < ImageEnd) { NewRecord->Type = TempRecord.Type; - NewRecord->PhysicalStart = TempRecord.PhysicalStart; + NewRecord->PhysicalStart = SectionAddress; NewRecord->VirtualStart = 0; - NewRecord->NumberOfPages = EfiSizeToPages (ImageEnd - TempRecord.PhysicalStart); - NewRecord->Attribute = TempRecord.Attribute | EFI_MEMORY_XP; - NewRecordCount++; + NewRecord->NumberOfPages = EfiSizeToPages (ImageRecordSegment->Size); + NewRecord->Attribute = (TempRecord.Attribute & ~(UINT64) EFI_MEMORY_ACCESS_MASK) | ImageRecordSegment->Attributes; + NewRecord = NEXT_MEMORY_DESCRIPTOR (NewRecord, DescriptorSize); + + SectionAddress += ImageRecordSegment->Size; } - return NewRecordCount; + return NewRecordCount + ImageRecord->NumSegments; } /** @@ -298,29 +224,32 @@ GetMaxSplitRecordCount ( IN LIST_ENTRY *ImageRecordList ) { - IMAGE_PROPERTIES_RECORD *ImageRecord; - UINTN SplitRecordCount; - UINT64 PhysicalStart; - UINT64 PhysicalEnd; - + UEFI_IMAGE_RECORD *ImageRecord; + UINTN SplitRecordCount; + UINT64 PhysicalStart; + UINT64 PhysicalEnd; + // + // Per region, there may be one prefix, but the return value is the amount of + // new records in addition to the original one. + // SplitRecordCount = 0; PhysicalStart = OldRecord->PhysicalStart; PhysicalEnd = OldRecord->PhysicalStart + EfiPagesToSize (OldRecord->NumberOfPages); do { + // FIXME: Inline iteration to not always start anew? ImageRecord = GetImageRecordByAddress (PhysicalStart, PhysicalEnd - PhysicalStart, ImageRecordList); if (ImageRecord == NULL) { break; } - SplitRecordCount += (2 * ImageRecord->CodeSegmentCount + 3); - PhysicalStart = ImageRecord->ImageBase + ImageRecord->ImageSize; + // + // Per image, they may be one trailer. + // + SplitRecordCount += ImageRecord->NumSegments + 1; + PhysicalStart = ImageRecord->EndAddress; } while ((ImageRecord != NULL) && (PhysicalStart < PhysicalEnd)); - if (SplitRecordCount != 0) { - SplitRecordCount--; - } - return SplitRecordCount; } @@ -350,13 +279,13 @@ SplitRecord ( IN LIST_ENTRY *ImageRecordList ) { - EFI_MEMORY_DESCRIPTOR TempRecord; - IMAGE_PROPERTIES_RECORD *ImageRecord; - IMAGE_PROPERTIES_RECORD *NewImageRecord; - UINT64 PhysicalStart; - UINT64 PhysicalEnd; - UINTN NewRecordCount; - UINTN TotalNewRecordCount; + EFI_MEMORY_DESCRIPTOR TempRecord; + UEFI_IMAGE_RECORD *ImageRecord; + UEFI_IMAGE_RECORD *NewImageRecord; + UINT64 PhysicalStart; + UINT64 PhysicalEnd; + UINTN NewRecordCount; + UINTN TotalNewRecordCount; if (MaxSplitRecordCount == 0) { CopyMem (NewRecord, OldRecord, DescriptorSize); @@ -397,15 +326,15 @@ SplitRecord ( // // Update PhysicalStart to exclude the portion before the image buffer // - if (TempRecord.PhysicalStart < ImageRecord->ImageBase) { + if (TempRecord.PhysicalStart < ImageRecord->StartAddress) { NewRecord->Type = TempRecord.Type; NewRecord->PhysicalStart = TempRecord.PhysicalStart; NewRecord->VirtualStart = 0; - NewRecord->NumberOfPages = EfiSizeToPages (ImageRecord->ImageBase - TempRecord.PhysicalStart); + NewRecord->NumberOfPages = EfiSizeToPages (ImageRecord->StartAddress - TempRecord.PhysicalStart); NewRecord->Attribute = TempRecord.Attribute; TotalNewRecordCount++; - PhysicalStart = ImageRecord->ImageBase; + PhysicalStart = ImageRecord->StartAddress; TempRecord.PhysicalStart = PhysicalStart; TempRecord.NumberOfPages = EfiSizeToPages (PhysicalEnd - PhysicalStart); @@ -422,7 +351,7 @@ SplitRecord ( // // Update PhysicalStart, in order to exclude the image buffer already splitted. // - PhysicalStart = ImageRecord->ImageBase + ImageRecord->ImageSize; + PhysicalStart = ImageRecord->EndAddress; TempRecord.PhysicalStart = PhysicalStart; TempRecord.NumberOfPages = EfiSizeToPages (PhysicalEnd - PhysicalStart); } while ((ImageRecord != NULL) && (PhysicalStart < PhysicalEnd)); @@ -550,623 +479,6 @@ SplitTable ( return EFI_SUCCESS; } -/** - Swap two code sections in a single IMAGE_PROPERTIES_RECORD. - - @param[in] FirstImageRecordCodeSection The first code section - @param[in] SecondImageRecordCodeSection The second code section - - @retval EFI_SUCCESS The code sections were swapped successfully - @retval EFI_INVALID_PARAMETER FirstImageRecordCodeSection or SecondImageRecordCodeSection is NULL -**/ -EFI_STATUS -EFIAPI -SwapImageRecordCodeSection ( - IN IMAGE_PROPERTIES_RECORD_CODE_SECTION *FirstImageRecordCodeSection, - IN IMAGE_PROPERTIES_RECORD_CODE_SECTION *SecondImageRecordCodeSection - ) -{ - IMAGE_PROPERTIES_RECORD_CODE_SECTION TempImageRecordCodeSection; - - if ((FirstImageRecordCodeSection == NULL) || (SecondImageRecordCodeSection == NULL)) { - return EFI_INVALID_PARAMETER; - } - - TempImageRecordCodeSection.CodeSegmentBase = FirstImageRecordCodeSection->CodeSegmentBase; - TempImageRecordCodeSection.CodeSegmentSize = FirstImageRecordCodeSection->CodeSegmentSize; - - FirstImageRecordCodeSection->CodeSegmentBase = SecondImageRecordCodeSection->CodeSegmentBase; - FirstImageRecordCodeSection->CodeSegmentSize = SecondImageRecordCodeSection->CodeSegmentSize; - - SecondImageRecordCodeSection->CodeSegmentBase = TempImageRecordCodeSection.CodeSegmentBase; - SecondImageRecordCodeSection->CodeSegmentSize = TempImageRecordCodeSection.CodeSegmentSize; - - return EFI_SUCCESS; -} - -/** - Sort the code sections in the input ImageRecord based upon CodeSegmentBase from low to high. - - @param[in] ImageRecord IMAGE_PROPERTIES_RECORD to be sorted - - @retval EFI_SUCCESS The code sections in the input ImageRecord were sorted successfully - @retval EFI_ABORTED An error occurred while sorting the code sections in the input ImageRecord - @retval EFI_INVALID_PARAMETER ImageRecord is NULL -**/ -EFI_STATUS -EFIAPI -SortImageRecordCodeSection ( - IN IMAGE_PROPERTIES_RECORD *ImageRecord - ) -{ - EFI_STATUS Status; - IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection; - IMAGE_PROPERTIES_RECORD_CODE_SECTION *NextImageRecordCodeSection; - LIST_ENTRY *ImageRecordCodeSectionLink; - LIST_ENTRY *NextImageRecordCodeSectionLink; - LIST_ENTRY *ImageRecordCodeSectionEndLink; - LIST_ENTRY *ImageRecordCodeSectionList; - - if (ImageRecord == NULL) { - return EFI_INVALID_PARAMETER; - } - - ImageRecordCodeSectionList = &ImageRecord->CodeSegmentList; - - ImageRecordCodeSectionLink = ImageRecordCodeSectionList->ForwardLink; - NextImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink; - ImageRecordCodeSectionEndLink = ImageRecordCodeSectionList; - while (ImageRecordCodeSectionLink != ImageRecordCodeSectionEndLink) { - ImageRecordCodeSection = CR ( - ImageRecordCodeSectionLink, - IMAGE_PROPERTIES_RECORD_CODE_SECTION, - Link, - IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE - ); - while (NextImageRecordCodeSectionLink != ImageRecordCodeSectionEndLink) { - NextImageRecordCodeSection = CR ( - NextImageRecordCodeSectionLink, - IMAGE_PROPERTIES_RECORD_CODE_SECTION, - Link, - IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE - ); - if (ImageRecordCodeSection->CodeSegmentBase > NextImageRecordCodeSection->CodeSegmentBase) { - Status = SwapImageRecordCodeSection (ImageRecordCodeSection, NextImageRecordCodeSection); - if (EFI_ERROR (Status)) { - ASSERT_EFI_ERROR (Status); - return EFI_ABORTED; - } - } - - NextImageRecordCodeSectionLink = NextImageRecordCodeSectionLink->ForwardLink; - } - - ImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink; - NextImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink; - } - - return EFI_SUCCESS; -} - -/** - Check if the code sections in the input ImageRecord are valid. - The code sections are valid if they don't overlap, are contained - within the the ImageRecord's ImageBase and ImageSize, and are - contained within the MAX_ADDRESS. - - @param[in] ImageRecord IMAGE_PROPERTIES_RECORD to be checked - - @retval TRUE The code sections in the input ImageRecord are valid - @retval FALSE The code sections in the input ImageRecord are invalid -**/ -BOOLEAN -EFIAPI -IsImageRecordCodeSectionValid ( - IN IMAGE_PROPERTIES_RECORD *ImageRecord - ) -{ - IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection; - IMAGE_PROPERTIES_RECORD_CODE_SECTION *LastImageRecordCodeSection; - LIST_ENTRY *ImageRecordCodeSectionLink; - LIST_ENTRY *ImageRecordCodeSectionEndLink; - LIST_ENTRY *ImageRecordCodeSectionList; - - if (ImageRecord == NULL) { - return FALSE; - } - - DEBUG ((DEBUG_VERBOSE, "ImageCode SegmentCount - 0x%x\n", ImageRecord->CodeSegmentCount)); - - ImageRecordCodeSectionList = &ImageRecord->CodeSegmentList; - - ImageRecordCodeSectionLink = ImageRecordCodeSectionList->ForwardLink; - ImageRecordCodeSectionEndLink = ImageRecordCodeSectionList; - LastImageRecordCodeSection = NULL; - while (ImageRecordCodeSectionLink != ImageRecordCodeSectionEndLink) { - ImageRecordCodeSection = CR ( - ImageRecordCodeSectionLink, - IMAGE_PROPERTIES_RECORD_CODE_SECTION, - Link, - IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE - ); - if (ImageRecordCodeSection->CodeSegmentSize == 0) { - return FALSE; - } - - if (ImageRecordCodeSection->CodeSegmentBase < ImageRecord->ImageBase) { - return FALSE; - } - - if (ImageRecordCodeSection->CodeSegmentBase >= MAX_ADDRESS - ImageRecordCodeSection->CodeSegmentSize) { - return FALSE; - } - - if ((ImageRecordCodeSection->CodeSegmentBase + ImageRecordCodeSection->CodeSegmentSize) > (ImageRecord->ImageBase + ImageRecord->ImageSize)) { - return FALSE; - } - - if (LastImageRecordCodeSection != NULL) { - if ((LastImageRecordCodeSection->CodeSegmentBase + LastImageRecordCodeSection->CodeSegmentSize) > ImageRecordCodeSection->CodeSegmentBase) { - return FALSE; - } - } - - LastImageRecordCodeSection = ImageRecordCodeSection; - ImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink; - } - - return TRUE; -} - -/** - Swap two image records. - - @param[in] FirstImageRecord The first image record. - @param[in] SecondImageRecord The second image record. - - @retval EFI_SUCCESS The image records were swapped successfully - @retval EFI_INVALID_PARAMETER FirstImageRecord or SecondImageRecord is NULL -**/ -EFI_STATUS -EFIAPI -SwapImageRecord ( - IN IMAGE_PROPERTIES_RECORD *FirstImageRecord, - IN IMAGE_PROPERTIES_RECORD *SecondImageRecord - ) -{ - IMAGE_PROPERTIES_RECORD TempImageRecord; - - if ((FirstImageRecord == NULL) || (SecondImageRecord == NULL)) { - return EFI_INVALID_PARAMETER; - } - - TempImageRecord.ImageBase = FirstImageRecord->ImageBase; - TempImageRecord.ImageSize = FirstImageRecord->ImageSize; - TempImageRecord.CodeSegmentCount = FirstImageRecord->CodeSegmentCount; - - FirstImageRecord->ImageBase = SecondImageRecord->ImageBase; - FirstImageRecord->ImageSize = SecondImageRecord->ImageSize; - FirstImageRecord->CodeSegmentCount = SecondImageRecord->CodeSegmentCount; - - SecondImageRecord->ImageBase = TempImageRecord.ImageBase; - SecondImageRecord->ImageSize = TempImageRecord.ImageSize; - SecondImageRecord->CodeSegmentCount = TempImageRecord.CodeSegmentCount; - - SwapListEntries (&FirstImageRecord->CodeSegmentList, &SecondImageRecord->CodeSegmentList); - return EFI_SUCCESS; -} - -/** - Sort the input ImageRecordList based upon the ImageBase from low to high. - - @param[in] ImageRecordList Image record list to be sorted - - @retval EFI_SUCCESS The image record list was sorted successfully - @retval EFI_ABORTED An error occurred while sorting the image record list - @retval EFI_INVALID_PARAMETER ImageRecordList is NULL -**/ -EFI_STATUS -EFIAPI -SortImageRecord ( - IN LIST_ENTRY *ImageRecordList - ) -{ - IMAGE_PROPERTIES_RECORD *ImageRecord; - IMAGE_PROPERTIES_RECORD *NextImageRecord; - LIST_ENTRY *ImageRecordLink; - LIST_ENTRY *NextImageRecordLink; - LIST_ENTRY *ImageRecordEndLink; - EFI_STATUS Status; - - if (ImageRecordList == NULL) { - return EFI_INVALID_PARAMETER; - } - - ImageRecordLink = ImageRecordList->ForwardLink; - NextImageRecordLink = ImageRecordLink->ForwardLink; - ImageRecordEndLink = ImageRecordList; - while (ImageRecordLink != ImageRecordEndLink) { - ImageRecord = CR ( - ImageRecordLink, - IMAGE_PROPERTIES_RECORD, - Link, - IMAGE_PROPERTIES_RECORD_SIGNATURE - ); - while (NextImageRecordLink != ImageRecordEndLink) { - NextImageRecord = CR ( - NextImageRecordLink, - IMAGE_PROPERTIES_RECORD, - Link, - IMAGE_PROPERTIES_RECORD_SIGNATURE - - ); - if (ImageRecord->ImageBase > NextImageRecord->ImageBase) { - Status = SwapImageRecord (ImageRecord, NextImageRecord); - if (EFI_ERROR (Status)) { - ASSERT_EFI_ERROR (Status); - return EFI_ABORTED; - } - } - - NextImageRecordLink = NextImageRecordLink->ForwardLink; - } - - ImageRecordLink = ImageRecordLink->ForwardLink; - NextImageRecordLink = ImageRecordLink->ForwardLink; - } - - return EFI_SUCCESS; -} - -/** - Extract the .efi filename out of the input PDB. - - @param[in] PdbPointer Pointer to the PDB file path. - @param[out] EfiFileName Pointer to the .efi filename. - @param[in] EfiFileNameSize Size of the .efi filename buffer. -**/ -STATIC -VOID -GetFilename ( - IN CHAR8 *PdbPointer, - OUT CHAR8 *EfiFileName, - IN UINTN EfiFileNameSize - ) -{ - UINTN Index; - UINTN StartIndex; - - if ((PdbPointer == NULL) || (EfiFileNameSize < 5)) { - return; - } - - // Print Module Name by Pdb file path. - StartIndex = 0; - for (Index = 0; PdbPointer[Index] != 0; Index++) { - if ((PdbPointer[Index] == '\\') || (PdbPointer[Index] == '/')) { - StartIndex = Index + 1; - } - } - - // Copy the PDB file name to EfiFileName and replace .pdb with .efi - for (Index = 0; Index < EfiFileNameSize - 4; Index++) { - EfiFileName[Index] = PdbPointer[Index + StartIndex]; - if (EfiFileName[Index] == 0) { - EfiFileName[Index] = '.'; - } - - if (EfiFileName[Index] == '.') { - EfiFileName[Index + 1] = 'e'; - EfiFileName[Index + 2] = 'f'; - EfiFileName[Index + 3] = 'i'; - EfiFileName[Index + 4] = 0; - break; - } - } - - if (Index == sizeof (EfiFileName) - 4) { - EfiFileName[Index] = 0; - } -} - -/** - Debug dumps the input list of IMAGE_PROPERTIES_RECORD structs. - - @param[in] ImageRecordList Head of the IMAGE_PROPERTIES_RECORD list -**/ -VOID -EFIAPI -DumpImageRecords ( - IN LIST_ENTRY *ImageRecordList - ) -{ - LIST_ENTRY *ImageRecordLink; - IMAGE_PROPERTIES_RECORD *CurrentImageRecord; - LIST_ENTRY *CodeSectionLink; - IMAGE_PROPERTIES_RECORD_CODE_SECTION *CurrentCodeSection; - CHAR8 *PdbPointer; - CHAR8 EfiFileName[256]; - - if (ImageRecordList == NULL) { - return; - } - - ImageRecordLink = ImageRecordList->ForwardLink; - - while (ImageRecordLink != ImageRecordList) { - CurrentImageRecord = CR ( - ImageRecordLink, - IMAGE_PROPERTIES_RECORD, - Link, - IMAGE_PROPERTIES_RECORD_SIGNATURE - ); - - PdbPointer = PeCoffLoaderGetPdbPointer ((VOID *)(UINTN)CurrentImageRecord->ImageBase); - if (PdbPointer != NULL) { - GetFilename (PdbPointer, EfiFileName, sizeof (EfiFileName)); - DEBUG (( - DEBUG_INFO, - "%a: 0x%llx - 0x%llx\n", - EfiFileName, - CurrentImageRecord->ImageBase, - CurrentImageRecord->ImageBase + CurrentImageRecord->ImageSize - )); - } else { - DEBUG (( - DEBUG_INFO, - "Unknown Image: 0x%llx - 0x%llx\n", - CurrentImageRecord->ImageBase, - CurrentImageRecord->ImageBase + CurrentImageRecord->ImageSize - )); - } - - CodeSectionLink = CurrentImageRecord->CodeSegmentList.ForwardLink; - - while (CodeSectionLink != &CurrentImageRecord->CodeSegmentList) { - CurrentCodeSection = CR ( - CodeSectionLink, - IMAGE_PROPERTIES_RECORD_CODE_SECTION, - Link, - IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE - ); - - DEBUG (( - DEBUG_INFO, - " Code Section: 0x%llx - 0x%llx\n", - CurrentCodeSection->CodeSegmentBase, - CurrentCodeSection->CodeSegmentBase + CurrentCodeSection->CodeSegmentSize - )); - - CodeSectionLink = CodeSectionLink->ForwardLink; - } - - ImageRecordLink = ImageRecordLink->ForwardLink; - } -} - -/** - Find image record according to image base and size. - - @param[in] ImageBase Base of PE image - @param[in] ImageSize Size of PE image - @param[in] ImageRecordList Image record list to be searched - - @retval NULL No IMAGE_PROPERTIES_RECORD matches ImageBase - and ImageSize in the input ImageRecordList - @retval Other The found IMAGE_PROPERTIES_RECORD -**/ -IMAGE_PROPERTIES_RECORD * -EFIAPI -FindImageRecord ( - IN EFI_PHYSICAL_ADDRESS ImageBase, - IN UINT64 ImageSize, - IN LIST_ENTRY *ImageRecordList - ) -{ - IMAGE_PROPERTIES_RECORD *ImageRecord; - LIST_ENTRY *ImageRecordLink; - - if (ImageRecordList == NULL) { - return NULL; - } - - for (ImageRecordLink = ImageRecordList->ForwardLink; - ImageRecordLink != ImageRecordList; - ImageRecordLink = ImageRecordLink->ForwardLink) - { - ImageRecord = CR ( - ImageRecordLink, - IMAGE_PROPERTIES_RECORD, - Link, - IMAGE_PROPERTIES_RECORD_SIGNATURE - ); - - if ((ImageBase == ImageRecord->ImageBase) && - (ImageSize == ImageRecord->ImageSize)) - { - return ImageRecord; - } - } - - return NULL; -} - -/** - Creates an IMAGE_PROPERTIES_RECORD from a loaded PE image. The PE/COFF header will be found - and parsed to determine the number of code segments and their base addresses and sizes. - - @param[in] ImageBase Base of the PE image - @param[in] ImageSize Size of the PE image - @param[in] RequiredAlignment If non-NULL, the alignment specified in the PE/COFF header - will be compared against this value. - @param[out] ImageRecord On out, a populated image properties record - - @retval EFI_INVALID_PARAMETER This function ImageBase or ImageRecord was NULL, or the - image located at ImageBase was not a valid PE/COFF image - @retval EFI_OUT_OF_RESOURCES Failure to Allocate() - @retval EFI_ABORTED The input Alignment was non-NULL and did not match the - alignment specified in the PE/COFF header - @retval EFI_SUCCESS The image properties record was successfully created -**/ -EFI_STATUS -EFIAPI -CreateImagePropertiesRecord ( - IN CONST VOID *ImageBase, - IN CONST UINT64 ImageSize, - IN CONST UINT32 *RequiredAlignment OPTIONAL, - OUT IMAGE_PROPERTIES_RECORD *ImageRecord - ) -{ - EFI_STATUS Status; - EFI_IMAGE_DOS_HEADER *DosHdr; - EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr; - EFI_IMAGE_SECTION_HEADER *Section; - IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection; - UINTN Index; - UINT8 *Name; - UINT32 SectionAlignment; - UINT32 PeCoffHeaderOffset; - CHAR8 *PdbPointer; - - if ((ImageRecord == NULL) || (ImageBase == NULL)) { - return EFI_INVALID_PARAMETER; - } - - DEBUG (( - DEBUG_VERBOSE, - "Creating Image Properties Record: 0x%016lx - 0x%016lx\n", - (EFI_PHYSICAL_ADDRESS)(UINTN)ImageBase, - ImageSize - )); - - // - // Step 1: record whole region - // - Status = EFI_SUCCESS; - ImageRecord->Signature = IMAGE_PROPERTIES_RECORD_SIGNATURE; - ImageRecord->ImageBase = (EFI_PHYSICAL_ADDRESS)(UINTN)ImageBase; - ImageRecord->ImageSize = ImageSize; - ImageRecord->CodeSegmentCount = 0; - InitializeListHead (&ImageRecord->Link); - InitializeListHead (&ImageRecord->CodeSegmentList); - - PdbPointer = PeCoffLoaderGetPdbPointer ((VOID *)(UINTN)ImageBase); - if (PdbPointer != NULL) { - DEBUG ((DEBUG_ERROR, " Image - %a\n", PdbPointer)); - } - - // Check PE/COFF image - DosHdr = (EFI_IMAGE_DOS_HEADER *)(UINTN)ImageBase; - PeCoffHeaderOffset = 0; - if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) { - PeCoffHeaderOffset = DosHdr->e_lfanew; - } - - Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINT8 *)(UINTN)ImageBase + PeCoffHeaderOffset); - if (Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) { - DEBUG ((DEBUG_VERBOSE, "Hdr.Pe32->Signature invalid - 0x%x\n", Hdr.Pe32->Signature)); - return EFI_INVALID_PARAMETER; - } - - // Get SectionAlignment - if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { - SectionAlignment = Hdr.Pe32->OptionalHeader.SectionAlignment; - } else { - SectionAlignment = Hdr.Pe32Plus->OptionalHeader.SectionAlignment; - } - - // Check RequiredAlignment - if ((RequiredAlignment != NULL) && ((SectionAlignment & (*RequiredAlignment - 1)) != 0)) { - DEBUG (( - DEBUG_WARN, - "!!!!!!!! Image Section Alignment(0x%x) does not match Required Alignment (0x%x) !!!!!!!!\n", - SectionAlignment, - *RequiredAlignment - )); - - return EFI_ABORTED; - } - - Section = (EFI_IMAGE_SECTION_HEADER *)( - (UINT8 *)(UINTN)ImageBase + - PeCoffHeaderOffset + - sizeof (UINT32) + - sizeof (EFI_IMAGE_FILE_HEADER) + - Hdr.Pe32->FileHeader.SizeOfOptionalHeader - ); - for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) { - Name = Section[Index].Name; - DEBUG (( - DEBUG_VERBOSE, - " Section - '%c%c%c%c%c%c%c%c'\n", - Name[0], - Name[1], - Name[2], - Name[3], - Name[4], - Name[5], - Name[6], - Name[7] - )); - - if ((Section[Index].Characteristics & EFI_IMAGE_SCN_CNT_CODE) != 0) { - DEBUG ((DEBUG_VERBOSE, " VirtualSize - 0x%08x\n", Section[Index].Misc.VirtualSize)); - DEBUG ((DEBUG_VERBOSE, " VirtualAddress - 0x%08x\n", Section[Index].VirtualAddress)); - DEBUG ((DEBUG_VERBOSE, " SizeOfRawData - 0x%08x\n", Section[Index].SizeOfRawData)); - DEBUG ((DEBUG_VERBOSE, " PointerToRawData - 0x%08x\n", Section[Index].PointerToRawData)); - DEBUG ((DEBUG_VERBOSE, " PointerToRelocations - 0x%08x\n", Section[Index].PointerToRelocations)); - DEBUG ((DEBUG_VERBOSE, " PointerToLinenumbers - 0x%08x\n", Section[Index].PointerToLinenumbers)); - DEBUG ((DEBUG_VERBOSE, " NumberOfRelocations - 0x%08x\n", Section[Index].NumberOfRelocations)); - DEBUG ((DEBUG_VERBOSE, " NumberOfLinenumbers - 0x%08x\n", Section[Index].NumberOfLinenumbers)); - DEBUG ((DEBUG_VERBOSE, " Characteristics - 0x%08x\n", Section[Index].Characteristics)); - - // Record code section(s) - ImageRecordCodeSection = AllocatePool (sizeof (*ImageRecordCodeSection)); - if (ImageRecordCodeSection == NULL) { - Status = EFI_OUT_OF_RESOURCES; - goto CreateImagePropertiesRecordEnd; - } - - ImageRecordCodeSection->Signature = IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE; - - ImageRecordCodeSection->CodeSegmentBase = (UINTN)ImageBase + Section[Index].VirtualAddress; - // We still need to align the VirtualSize to the SectionAlignment because MSVC does not do - // this when creating a PE image. It expects the loader to do this. - ImageRecordCodeSection->CodeSegmentSize = ALIGN_VALUE (Section[Index].Misc.VirtualSize, SectionAlignment); - - InsertTailList (&ImageRecord->CodeSegmentList, &ImageRecordCodeSection->Link); - ImageRecord->CodeSegmentCount++; - } - } - - if (ImageRecord->CodeSegmentCount > 0) { - SortImageRecordCodeSection (ImageRecord); - } - - // - // Check overlap all section in ImageBase/Size - // - if (!IsImageRecordCodeSectionValid (ImageRecord)) { - DEBUG ((DEBUG_ERROR, "IsImageRecordCodeSectionValid - FAIL\n")); - Status = EFI_INVALID_PARAMETER; - goto CreateImagePropertiesRecordEnd; - } - - // - // Round up the ImageSize, some CPU arch may return EFI_UNSUPPORTED if ImageSize is not aligned. - // Given that the loader always allocates full pages, we know the space after the image is not used. - // - ImageRecord->ImageSize = ALIGN_VALUE (ImageRecord->ImageSize, EFI_PAGE_SIZE); - -CreateImagePropertiesRecordEnd: - if (EFI_ERROR (Status)) { - // we failed to create a valid record, free the section memory that was allocated - FreeImageRecordCodeSections (ImageRecord); - } - - return Status; -} - /** Deleted an image properties record. The function will also call RemoveEntryList() on each code segment and the input ImageRecord before @@ -1177,11 +489,9 @@ CreateImagePropertiesRecord ( VOID EFIAPI DeleteImagePropertiesRecord ( - IN IMAGE_PROPERTIES_RECORD *ImageRecord + IN UEFI_IMAGE_RECORD *ImageRecord ) { - FreeImageRecordCodeSections (ImageRecord); - if (!IsListEmpty (&ImageRecord->Link)) { RemoveEntryList (&ImageRecord->Link); } diff --git a/MdeModulePkg/Library/ImagePropertiesRecordLib/ImagePropertiesRecordLib.inf b/MdeModulePkg/Library/ImagePropertiesRecordLib/ImagePropertiesRecordLib.inf index 1f82cc3e46..43310f5553 100644 --- a/MdeModulePkg/Library/ImagePropertiesRecordLib/ImagePropertiesRecordLib.inf +++ b/MdeModulePkg/Library/ImagePropertiesRecordLib/ImagePropertiesRecordLib.inf @@ -24,7 +24,7 @@ BaseMemoryLib DebugLib MemoryAllocationLib - PeCoffGetEntryPointLib + UefiImageLib [Packages] MdePkg/MdePkg.dec diff --git a/MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/PiSmmCoreMemoryAllocationLib.inf b/MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/PiSmmCoreMemoryAllocationLib.inf index 5c51c48b0b..8812c96041 100644 --- a/MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/PiSmmCoreMemoryAllocationLib.inf +++ b/MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/PiSmmCoreMemoryAllocationLib.inf @@ -19,6 +19,9 @@ VERSION_STRING = 1.0 PI_SPECIFICATION_VERSION = 0x0001000A LIBRARY_CLASS = MemoryAllocationLib|SMM_CORE + # + # This function is defined in PiSmmCore. + # CONSTRUCTOR = PiSmmCoreMemoryAllocationLibConstructor # @@ -28,8 +31,6 @@ # [Sources] - MemoryAllocationLib.c - PiSmmCoreMemoryAllocationServices.h PiSmmCoreMemoryProfileLibNull.c [Packages] diff --git a/MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/PiSmmCoreMemoryAllocationProfileLib.inf b/MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/PiSmmCoreMemoryAllocationProfileLib.inf index 89658c0f6c..c3b8a4fdce 100644 --- a/MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/PiSmmCoreMemoryAllocationProfileLib.inf +++ b/MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/PiSmmCoreMemoryAllocationProfileLib.inf @@ -19,6 +19,9 @@ VERSION_STRING = 1.0 PI_SPECIFICATION_VERSION = 0x0001000A LIBRARY_CLASS = MemoryAllocationLib|SMM_CORE + # + # This function is defined in PiSmmCore. + # CONSTRUCTOR = PiSmmCoreMemoryAllocationLibConstructor LIBRARY_CLASS = MemoryProfileLib|SMM_CORE CONSTRUCTOR = PiSmmCoreMemoryProfileLibConstructor @@ -30,8 +33,6 @@ # [Sources] - MemoryAllocationLib.c - PiSmmCoreMemoryAllocationServices.h PiSmmCoreMemoryProfileLib.c PiSmmCoreMemoryProfileServices.h @@ -43,6 +44,7 @@ DebugLib BaseMemoryLib UefiBootServicesTableLib + MemoryAllocationLib [Guids] gEdkiiMemoryProfileGuid ## SOMETIMES_CONSUMES ## GUID # Locate protocol diff --git a/MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/PiSmmCoreMemoryAllocationServices.h b/MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/PiSmmCoreMemoryAllocationServices.h deleted file mode 100644 index 64429e028a..0000000000 --- a/MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/PiSmmCoreMemoryAllocationServices.h +++ /dev/null @@ -1,185 +0,0 @@ -/** @file - Contains function prototypes for Memory Services in the SMM Core. - - This header file borrows the PiSmmCore Memory Allocation services as the primitive - for memory allocation. - - Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.
- SPDX-License-Identifier: BSD-2-Clause-Patent - -**/ - -#ifndef _PI_SMM_CORE_MEMORY_ALLOCATION_SERVICES_H_ -#define _PI_SMM_CORE_MEMORY_ALLOCATION_SERVICES_H_ - -// -// It should be aligned with the definition in PiSmmCore. -// -typedef struct { - UINTN Signature; - - /// - /// The ImageHandle passed into the entry point of the SMM IPL. This ImageHandle - /// is used by the SMM Core to fill in the ParentImageHandle field of the Loaded - /// Image Protocol for each SMM Driver that is dispatched by the SMM Core. - /// - EFI_HANDLE SmmIplImageHandle; - - /// - /// The number of SMRAM ranges passed from the SMM IPL to the SMM Core. The SMM - /// Core uses these ranges of SMRAM to initialize the SMM Core memory manager. - /// - UINTN SmramRangeCount; - - /// - /// A table of SMRAM ranges passed from the SMM IPL to the SMM Core. The SMM - /// Core uses these ranges of SMRAM to initialize the SMM Core memory manager. - /// - EFI_SMRAM_DESCRIPTOR *SmramRanges; - - /// - /// The SMM Foundation Entry Point. The SMM Core fills in this field when the - /// SMM Core is initialized. The SMM IPL is responsbile for registering this entry - /// point with the SMM Configuration Protocol. The SMM Configuration Protocol may - /// not be available at the time the SMM IPL and SMM Core are started, so the SMM IPL - /// sets up a protocol notification on the SMM Configuration Protocol and registers - /// the SMM Foundation Entry Point as soon as the SMM Configuration Protocol is - /// available. - /// - EFI_SMM_ENTRY_POINT SmmEntryPoint; - - /// - /// Boolean flag set to TRUE while an SMI is being processed by the SMM Core. - /// - BOOLEAN SmmEntryPointRegistered; - - /// - /// Boolean flag set to TRUE while an SMI is being processed by the SMM Core. - /// - BOOLEAN InSmm; - - /// - /// This field is set by the SMM Core then the SMM Core is initialized. This field is - /// used by the SMM Base 2 Protocol and SMM Communication Protocol implementations in - /// the SMM IPL. - /// - EFI_SMM_SYSTEM_TABLE2 *Smst; - - /// - /// This field is used by the SMM Communicatioon Protocol to pass a buffer into - /// a software SMI handler and for the software SMI handler to pass a buffer back to - /// the caller of the SMM Communication Protocol. - /// - VOID *CommunicationBuffer; - - /// - /// This field is used by the SMM Communicatioon Protocol to pass the size of a buffer, - /// in bytes, into a software SMI handler and for the software SMI handler to pass the - /// size, in bytes, of a buffer back to the caller of the SMM Communication Protocol. - /// - UINTN BufferSize; - - /// - /// This field is used by the SMM Communication Protocol to pass the return status from - /// a software SMI handler back to the caller of the SMM Communication Protocol. - /// - EFI_STATUS ReturnStatus; - - EFI_PHYSICAL_ADDRESS PiSmmCoreImageBase; - UINT64 PiSmmCoreImageSize; - EFI_PHYSICAL_ADDRESS PiSmmCoreEntryPoint; -} SMM_CORE_PRIVATE_DATA; - -/** - Called to initialize the memory service. - - @param SmramRangeCount Number of SMRAM Regions - @param SmramRanges Pointer to SMRAM Descriptors - -**/ -VOID -SmmInitializeMemoryServices ( - IN UINTN SmramRangeCount, - IN EFI_SMRAM_DESCRIPTOR *SmramRanges - ); - -/** - Allocates pages from the memory map. - - @param Type The type of allocation to perform - @param MemoryType The type of memory to turn the allocated pages - into - @param NumberOfPages The number of pages to allocate - @param Memory A pointer to receive the base allocated memory - address - - @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in spec. - @retval EFI_NOT_FOUND Could not allocate pages match the requirement. - @retval EFI_OUT_OF_RESOURCES No enough pages to allocate. - @retval EFI_SUCCESS Pages successfully allocated. - -**/ -EFI_STATUS -EFIAPI -SmmAllocatePages ( - IN EFI_ALLOCATE_TYPE Type, - IN EFI_MEMORY_TYPE MemoryType, - IN UINTN NumberOfPages, - OUT EFI_PHYSICAL_ADDRESS *Memory - ); - -/** - Frees previous allocated pages. - - @param Memory Base address of memory being freed - @param NumberOfPages The number of pages to free - - @retval EFI_NOT_FOUND Could not find the entry that covers the range - @retval EFI_INVALID_PARAMETER Address not aligned - @return EFI_SUCCESS Pages successfully freed. - -**/ -EFI_STATUS -EFIAPI -SmmFreePages ( - IN EFI_PHYSICAL_ADDRESS Memory, - IN UINTN NumberOfPages - ); - -/** - Allocate pool of a particular type. - - @param PoolType Type of pool to allocate - @param Size The amount of pool to allocate - @param Buffer The address to return a pointer to the allocated - pool - - @retval EFI_INVALID_PARAMETER PoolType not valid - @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed. - @retval EFI_SUCCESS Pool successfully allocated. - -**/ -EFI_STATUS -EFIAPI -SmmAllocatePool ( - IN EFI_MEMORY_TYPE PoolType, - IN UINTN Size, - OUT VOID **Buffer - ); - -/** - Frees pool. - - @param Buffer The allocated pool entry to free - - @retval EFI_INVALID_PARAMETER Buffer is not a valid value. - @retval EFI_SUCCESS Pool successfully freed. - -**/ -EFI_STATUS -EFIAPI -SmmFreePool ( - IN VOID *Buffer - ); - -#endif diff --git a/MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLib.c b/MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLib.c index 2700f5adbc..2b6cd76d7f 100644 --- a/MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLib.c +++ b/MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLib.c @@ -272,9 +272,9 @@ GetModuleInfoFromHandle ( EFI_STATUS Status; EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; EFI_DRIVER_BINDING_PROTOCOL *DriverBinding; - CHAR8 *PdbFileName; + //CHAR8 *PdbFileName; EFI_GUID *TempGuid; - UINTN StartIndex; + //UINTN StartIndex; UINTN Index; INTN Count; BOOLEAN ModuleGuidIsGet; @@ -367,7 +367,8 @@ GetModuleInfoFromHandle ( // // Method 1 Get Module Name from PDB string. // - PdbFileName = PeCoffLoaderGetPdbPointer (LoadedImage->ImageBase); + // FIXME: + /*PdbFileName = UefiImageLoaderGetPdbPointer (LoadedImage->ImageBase); if ((PdbFileName != NULL) && (BufferSize > 0)) { StartIndex = 0; for (Index = 0; PdbFileName[Index] != 0; Index++) { @@ -396,7 +397,7 @@ GetModuleInfoFromHandle ( // Module Name is got. // goto Done; - } + }*/ } if (ModuleGuidIsGet) { @@ -426,7 +427,7 @@ GetModuleInfoFromHandle ( } } -Done: +//Done: // // Copy Module Guid // diff --git a/MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLib.inf b/MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLib.inf index 9a7e14e80c..cb8ab4897e 100644 --- a/MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLib.inf +++ b/MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLib.inf @@ -53,7 +53,6 @@ SmmMemLib UefiLib ReportStatusCodeLib - PeCoffGetEntryPointLib DxeServicesLib [Protocols] diff --git a/MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLibInternal.h b/MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLibInternal.h index 62b496484c..2f24117069 100644 --- a/MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLibInternal.h +++ b/MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLibInternal.h @@ -33,7 +33,6 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #include #include #include -#include #include #include diff --git a/MdeModulePkg/Library/UefiBootManagerLib/BmLoadOption.c b/MdeModulePkg/Library/UefiBootManagerLib/BmLoadOption.c index 83a2f893e4..0e8154ae07 100644 --- a/MdeModulePkg/Library/UefiBootManagerLib/BmLoadOption.c +++ b/MdeModulePkg/Library/UefiBootManagerLib/BmLoadOption.c @@ -1213,82 +1213,6 @@ EfiBootManagerFreeLoadOptions ( return EFI_SUCCESS; } -/** - Return whether the PE header of the load option is valid or not. - - @param[in] Type The load option type. - It's used to check whether the load option is valid. - When it's LoadOptionTypeMax, the routine only guarantees - the load option is a valid PE image but doesn't guarantee - the PE's subsystem type is valid. - @param[in] FileBuffer The PE file buffer of the load option. - @param[in] FileSize The size of the load option file. - - @retval TRUE The PE header of the load option is valid. - @retval FALSE The PE header of the load option is not valid. -**/ -BOOLEAN -BmIsLoadOptionPeHeaderValid ( - IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE Type, - IN VOID *FileBuffer, - IN UINTN FileSize - ) -{ - EFI_IMAGE_DOS_HEADER *DosHeader; - EFI_IMAGE_OPTIONAL_HEADER_UNION *PeHeader; - EFI_IMAGE_OPTIONAL_HEADER32 *OptionalHeader; - UINT16 Subsystem; - - if ((FileBuffer == NULL) || (FileSize == 0)) { - return FALSE; - } - - // - // Read dos header - // - DosHeader = (EFI_IMAGE_DOS_HEADER *)FileBuffer; - if ((FileSize >= sizeof (EFI_IMAGE_DOS_HEADER)) && - (FileSize > DosHeader->e_lfanew) && (DosHeader->e_magic == EFI_IMAGE_DOS_SIGNATURE) - ) - { - // - // Read and check PE signature - // - PeHeader = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((UINT8 *)FileBuffer + DosHeader->e_lfanew); - if ((FileSize >= DosHeader->e_lfanew + sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION)) && - (PeHeader->Pe32.Signature == EFI_IMAGE_NT_SIGNATURE) - ) - { - // - // Check PE32 or PE32+ magic, and machine type - // - OptionalHeader = (EFI_IMAGE_OPTIONAL_HEADER32 *)&PeHeader->Pe32.OptionalHeader; - if ((OptionalHeader->Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) || - (OptionalHeader->Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC)) - { - // - // Check the Subsystem: - // Driver#### must be of type BootServiceDriver or RuntimeDriver - // SysPrep####, Boot####, OsRecovery####, PlatformRecovery#### must be of type Application - // - Subsystem = OptionalHeader->Subsystem; - if ((Type == LoadOptionTypeMax) || - ((Type == LoadOptionTypeDriver) && (Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER)) || - ((Type == LoadOptionTypeDriver) && (Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER)) || - ((Type == LoadOptionTypeSysPrep) && (Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION)) || - ((Type == LoadOptionTypeBoot) && (Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION)) || - ((Type == LoadOptionTypePlatformRecovery) && (Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION)) - ) - { - return TRUE; - } - } - } - } - - return FALSE; -} - /** Return the next matched load option buffer. The routine keeps calling BmGetNextLoadOptionDevicePath() until a valid @@ -1322,7 +1246,6 @@ BmGetNextLoadOptionBuffer ( EFI_DEVICE_PATH_PROTOCOL *CurFullPath; UINTN LocalFileSize; UINT32 AuthenticationStatus; - EFI_DEVICE_PATH_PROTOCOL *RamDiskDevicePath; LocalFileSize = 0; FileBuffer = NULL; @@ -1342,22 +1265,6 @@ BmGetNextLoadOptionBuffer ( } FileBuffer = GetFileBufferByFilePath (TRUE, CurFullPath, &LocalFileSize, &AuthenticationStatus); - if ((FileBuffer != NULL) && !BmIsLoadOptionPeHeaderValid (Type, FileBuffer, LocalFileSize)) { - // - // Free the RAM disk file system if the load option is invalid. - // - RamDiskDevicePath = BmGetRamDiskDevicePath (FilePath); - if (RamDiskDevicePath != NULL) { - BmDestroyRamDisk (RamDiskDevicePath); - FreePool (RamDiskDevicePath); - } - - // - // Free the invalid load option buffer. - // - FreePool (FileBuffer); - FileBuffer = NULL; - } } while (FileBuffer == NULL); if (FileBuffer == NULL) { @@ -1399,6 +1306,7 @@ EfiBootManagerProcessLoadOption ( EFI_LOADED_IMAGE_PROTOCOL *ImageInfo; VOID *FileBuffer; UINTN FileSize; + EFI_DEVICE_PATH_PROTOCOL *RamDiskDevicePath; if ((UINT32)LoadOption->OptionType >= LoadOptionTypeMax) { return EFI_INVALID_PARAMETER; @@ -1476,6 +1384,15 @@ EfiBootManagerProcessLoadOption ( if (Status == EFI_SECURITY_VIOLATION) { gBS->UnloadImage (ImageHandle); } + + // + // Free the RAM disk file system if the load option is invalid. + // + RamDiskDevicePath = BmGetRamDiskDevicePath (LoadOption->FilePath); + if (RamDiskDevicePath != NULL) { + BmDestroyRamDisk (RamDiskDevicePath); + FreePool (RamDiskDevicePath); + } } else { Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **)&ImageInfo); ASSERT_EFI_ERROR (Status); diff --git a/MdeModulePkg/Library/UefiBootManagerLib/InternalBm.h b/MdeModulePkg/Library/UefiBootManagerLib/InternalBm.h index b7dfe2a7e0..4bb01664e1 100644 --- a/MdeModulePkg/Library/UefiBootManagerLib/InternalBm.h +++ b/MdeModulePkg/Library/UefiBootManagerLib/InternalBm.h @@ -14,7 +14,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #include #include -#include +#include #include #include #include @@ -62,7 +62,6 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #include #include #include -#include #include #include #include diff --git a/MdeModulePkg/Library/UefiBootManagerLib/UefiBootManagerLib.inf b/MdeModulePkg/Library/UefiBootManagerLib/UefiBootManagerLib.inf index 2fc0a80a4e..6a32f5128d 100644 --- a/MdeModulePkg/Library/UefiBootManagerLib/UefiBootManagerLib.inf +++ b/MdeModulePkg/Library/UefiBootManagerLib/UefiBootManagerLib.inf @@ -52,7 +52,6 @@ BaseMemoryLib DevicePathLib PerformanceLib - PeCoffGetEntryPointLib UefiBootServicesTableLib UefiRuntimeServicesTableLib DxeServicesTableLib diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec index f7339f0aec..b4c9ad73c7 100644 --- a/MdeModulePkg/MdeModulePkg.dec +++ b/MdeModulePkg/MdeModulePkg.dec @@ -555,7 +555,7 @@ ## Load File protocol provides capability to load and unload EFI image into memory and execute it. # Include/Protocol/LoadPe32Image.h # This protocol is deprecated. Native EDKII module should NOT use this protocol to load/unload image. - # If developer need implement such functionality, they should use BasePeCoffLib. + # If developer need implement such functionality, they should use BasePeCoffLib2. gEfiLoadPeImageProtocolGuid = { 0x5CB5C776, 0x60D5, 0x45EE, { 0x88, 0x3C, 0x45, 0x27, 0x08, 0xCD, 0x74, 0x3F }} ## Print protocols define basic print functions to print the format unicode and ascii string. @@ -1468,7 +1468,7 @@ # e.g. 0x7BD4 can be used for all memory except Code and ACPINVS/Reserved.
# # @Prompt Set DXE memory protection policy. - gEfiMdeModulePkgTokenSpaceGuid.PcdDxeNxMemoryProtectionPolicy|0x0000000|UINT64|0x00001048 + gEfiMdeModulePkgTokenSpaceGuid.PcdDxeNxMemoryProtectionPolicy|0xFFFFFFFFFFFFFFD5|UINT64|0x00001048 ## PCI Serial Device Info. It is an array of Device, Function, and Power Management # information that describes the path that contains zero or more PCI to PCI bridges diff --git a/MdeModulePkg/MdeModulePkg.dsc b/MdeModulePkg/MdeModulePkg.dsc index a1c8e2f905..4f445bf8d2 100644 --- a/MdeModulePkg/MdeModulePkg.dsc +++ b/MdeModulePkg/MdeModulePkg.dsc @@ -43,8 +43,8 @@ PciCf8Lib|MdePkg/Library/BasePciCf8Lib/BasePciCf8Lib.inf PciSegmentLib|MdePkg/Library/BasePciSegmentLibPci/BasePciSegmentLibPci.inf CacheMaintenanceLib|MdePkg/Library/BaseCacheMaintenanceLib/BaseCacheMaintenanceLib.inf - PeCoffLib|MdePkg/Library/BasePeCoffLib/BasePeCoffLib.inf - PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf + PeCoffLib2|MdePkg/Library/BasePeCoffLib2/BasePeCoffLib2.inf + UefiImageLib|MdePkg/Library/BaseUefiImageLib/BaseUefiImageLibPeCoff.inf SortLib|MdeModulePkg/Library/BaseSortLib/BaseSortLib.inf # # UEFI & PI @@ -81,7 +81,7 @@ DebugLib|MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.inf DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf ReportStatusCodeLib|MdePkg/Library/BaseReportStatusCodeLibNull/BaseReportStatusCodeLibNull.inf - PeCoffExtraActionLib|MdePkg/Library/BasePeCoffExtraActionLibNull/BasePeCoffExtraActionLibNull.inf + UefiImageExtraActionLib|MdePkg/Library/BaseUefiImageExtraActionLibNull/BaseUefiImageExtraActionLibNull.inf PerformanceLib|MdePkg/Library/BasePerformanceLibNull/BasePerformanceLibNull.inf DebugAgentLib|MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.inf PlatformHookLib|MdeModulePkg/Library/BasePlatformHookLibNull/BasePlatformHookLibNull.inf diff --git a/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/BootScriptExecutorDxe.inf b/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/BootScriptExecutorDxe.inf index fb149c2f02..22a28df8e6 100644 --- a/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/BootScriptExecutorDxe.inf +++ b/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/BootScriptExecutorDxe.inf @@ -49,7 +49,7 @@ UefiDriverEntryPoint BaseLib S3BootScriptLib - PeCoffLib + UefiImageLib DxeServicesLib UefiBootServicesTableLib CacheMaintenanceLib @@ -59,6 +59,7 @@ CpuExceptionHandlerLib DevicePathLib DxeServicesTableLib + MemoryAllocationLib [Guids] gEfiBootScriptExecutorVariableGuid ## PRODUCES ## UNDEFINED # SaveLockBox diff --git a/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/ScriptExecute.c b/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/ScriptExecute.c index 98c5abecf8..4599425859 100644 --- a/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/ScriptExecute.c +++ b/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/ScriptExecute.c @@ -227,8 +227,7 @@ S3BootScriptExecutorEntryFunction ( VOID RegisterMemoryProfileImage ( IN EFI_GUID *FileName, - IN PHYSICAL_ADDRESS ImageBase, - IN UINT64 ImageSize, + IN UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext, IN EFI_FV_FILETYPE FileType ) { @@ -247,8 +246,7 @@ RegisterMemoryProfileImage ( Status = ProfileProtocol->RegisterImage ( ProfileProtocol, (EFI_DEVICE_PATH_PROTOCOL *)FilePath, - ImageBase, - ImageSize, + ImageContext, FileType ); } @@ -275,9 +273,11 @@ ReadyToLockEventNotify ( UINTN BufferSize; EFI_HANDLE NewImageHandle; UINTN Pages; - EFI_PHYSICAL_ADDRESS FfsBuffer; - PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; + UEFI_IMAGE_LOADER_IMAGE_CONTEXT ImageContext; + UINT32 ImageSize; + UINT32 ImageAlignment; EFI_GCD_MEMORY_SPACE_DESCRIPTOR MemDesc; + EFI_PHYSICAL_ADDRESS LoadAddress; Status = gBS->LocateProtocol (&gEfiDxeSmmReadyToLockProtocolGuid, NULL, &Interface); if (EFI_ERROR (Status)) { @@ -307,56 +307,40 @@ ReadyToLockEventNotify ( &BufferSize ); ASSERT_EFI_ERROR (Status); - ImageContext.Handle = Buffer; - ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory; // // Get information about the image being loaded // - Status = PeCoffLoaderGetImageInfo (&ImageContext); + Status = UefiImageInitializeContext (&ImageContext, Buffer, (UINT32) BufferSize); ASSERT_EFI_ERROR (Status); - if (ImageContext.SectionAlignment > EFI_PAGE_SIZE) { - Pages = EFI_SIZE_TO_PAGES ((UINTN)(ImageContext.ImageSize + ImageContext.SectionAlignment)); - } else { - Pages = EFI_SIZE_TO_PAGES ((UINTN)ImageContext.ImageSize); - } - - FfsBuffer = 0xFFFFFFFF; - Status = gBS->AllocatePages ( - AllocateMaxAddress, - EfiReservedMemoryType, - Pages, - &FfsBuffer - ); + ImageSize = UefiImageGetImageSize (&ImageContext); + ImageAlignment = UefiImageGetSegmentAlignment (&ImageContext); + Pages = EFI_SIZE_TO_PAGES (ImageSize); + LoadAddress = 0xFFFFFFFF; + Status = AllocateAlignedPagesEx ( + AllocateMaxAddress, + EfiReservedMemoryType, + Pages, + ImageAlignment, + &LoadAddress + ); ASSERT_EFI_ERROR (Status); // // Make sure that the buffer can be used to store code. // - Status = gDS->GetMemorySpaceDescriptor (FfsBuffer, &MemDesc); + Status = gDS->GetMemorySpaceDescriptor (LoadAddress, &MemDesc); if (!EFI_ERROR (Status) && ((MemDesc.Attributes & EFI_MEMORY_XP) != 0)) { gDS->SetMemorySpaceAttributes ( - FfsBuffer, + LoadAddress, EFI_PAGES_TO_SIZE (Pages), MemDesc.Attributes & (~EFI_MEMORY_XP) ); } - ImageContext.ImageAddress = (PHYSICAL_ADDRESS)(UINTN)FfsBuffer; - // - // Align buffer on section boundary - // - ImageContext.ImageAddress += ImageContext.SectionAlignment - 1; - ImageContext.ImageAddress &= ~((EFI_PHYSICAL_ADDRESS)ImageContext.SectionAlignment - 1); // // Load the image to our new buffer // - Status = PeCoffLoaderLoadImage (&ImageContext); - ASSERT_EFI_ERROR (Status); - - // - // Relocate the image in our new buffer - // - Status = PeCoffLoaderRelocateImage (&ImageContext); + Status = UefiImageLoadImageForExecution (&ImageContext, (VOID *)(UINTN)LoadAddress, ImageSize, NULL, 0); ASSERT_EFI_ERROR (Status); // @@ -364,19 +348,13 @@ ReadyToLockEventNotify ( // gBS->FreePool (Buffer); - // - // Flush the instruction cache so the image data is written before we execute it - // - InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize); - RegisterMemoryProfileImage ( &gEfiCallerIdGuid, - ImageContext.ImageAddress, - ImageContext.ImageSize, + &ImageContext, EFI_FV_FILETYPE_DRIVER ); - Status = ((EFI_IMAGE_ENTRY_POINT)(UINTN)(ImageContext.EntryPoint))(NewImageHandle, gST); + Status = ((EFI_IMAGE_ENTRY_POINT)(UINTN)(UefiImageLoaderGetImageEntryPoint (&ImageContext)))(NewImageHandle, gST); ASSERT_EFI_ERROR (Status); // @@ -385,8 +363,8 @@ ReadyToLockEventNotify ( // Status = SaveLockBox ( &mBootScriptExecutorImageGuid, - (VOID *)(UINTN)ImageContext.ImageAddress, - (UINTN)ImageContext.ImageSize + (VOID *)(UINTN)LoadAddress, + (UINTN)UefiImageGetImageSize (&ImageContext) ); ASSERT_EFI_ERROR (Status); diff --git a/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/ScriptExecute.h b/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/ScriptExecute.h index 0ea38223d7..c18e6ed551 100644 --- a/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/ScriptExecute.h +++ b/MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/ScriptExecute.h @@ -21,7 +21,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #include #include #include -#include +#include #include #include #include @@ -34,6 +34,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #include #include #include +#include #include #include diff --git a/MdeModulePkg/Universal/CapsulePei/Capsule.h b/MdeModulePkg/Universal/CapsulePei/Capsule.h index c16f83a07a..7e3ee64d5f 100644 --- a/MdeModulePkg/Universal/CapsulePei/Capsule.h +++ b/MdeModulePkg/Universal/CapsulePei/Capsule.h @@ -25,13 +25,12 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #include #include #include -#include -#include +#include #include #include #include #include -#include +#include #include "Common/CommonHeader.h" #ifdef MDE_CPU_IA32 diff --git a/MdeModulePkg/Universal/CapsulePei/CapsulePei.inf b/MdeModulePkg/Universal/CapsulePei/CapsulePei.inf index e5078c7986..832f97683a 100644 --- a/MdeModulePkg/Universal/CapsulePei/CapsulePei.inf +++ b/MdeModulePkg/Universal/CapsulePei/CapsulePei.inf @@ -53,7 +53,6 @@ ReportStatusCodeLib [LibraryClasses.IA32] - PeCoffGetEntryPointLib PcdLib DebugAgentLib diff --git a/MdeModulePkg/Universal/CapsulePei/UefiCapsule.c b/MdeModulePkg/Universal/CapsulePei/UefiCapsule.c index 8e26a7d795..a155078ed8 100644 --- a/MdeModulePkg/Universal/CapsulePei/UefiCapsule.c +++ b/MdeModulePkg/Universal/CapsulePei/UefiCapsule.c @@ -542,7 +542,9 @@ FindCapsuleCoalesceImage ( return Status; } - *CoalesceImageMachineType = PeCoffLoaderGetMachineType ((VOID *)(UINTN)CoalesceImageAddress); + *CoalesceImageMachineType = EFI_IMAGE_MACHINE_X64; + // FIXME: Get machine type from context once PPI is adapted + //*CoalesceImageMachineType = UefiImageLoaderGetMachineType ((VOID *)(UINTN)CoalesceImageAddress); break; } else { continue; diff --git a/MdeModulePkg/Universal/EbcDxe/EbcDebugger.inf b/MdeModulePkg/Universal/EbcDxe/EbcDebugger.inf index e942317603..ef0ed4936c 100644 --- a/MdeModulePkg/Universal/EbcDxe/EbcDebugger.inf +++ b/MdeModulePkg/Universal/EbcDxe/EbcDebugger.inf @@ -85,7 +85,6 @@ DebugLib BaseLib CacheMaintenanceLib - PeCoffLib [Protocols] gEfiDebugSupportProtocolGuid ## PRODUCES diff --git a/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbSymbol.c b/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbSymbol.c index 834c90e32a..cf8ff3d371 100644 --- a/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbSymbol.c +++ b/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbSymbol.c @@ -759,107 +759,6 @@ EdbLoadSymbol ( return EFI_SUCCESS; } -/** - - Located PDB path name in PE image. - - @param ImageBase - base of PE to search - - @return Pointer into image at offset of PDB file name if PDB file name is found, - Otherwise a pointer to an empty string. - -**/ -CHAR8 * -GetPdbPath ( - VOID *ImageBase - ) -{ - CHAR8 *PdbPath; - UINT32 DirCount; - EFI_IMAGE_DOS_HEADER *DosHdr; - EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr; - EFI_IMAGE_OPTIONAL_HEADER32 *OptionalHdr32; - EFI_IMAGE_OPTIONAL_HEADER64 *OptionalHdr64; - EFI_IMAGE_DATA_DIRECTORY *DirectoryEntry; - EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *DebugEntry; - VOID *CodeViewEntryPointer; - - // - // Init value - // - CodeViewEntryPointer = NULL; - PdbPath = NULL; - DosHdr = ImageBase; - - // - // Check magic - // - if (DosHdr->e_magic != EFI_IMAGE_DOS_SIGNATURE) { - return NULL; - } - - NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((UINT8 *)DosHdr + DosHdr->e_lfanew); - // - // Check Machine, filter for EBC - // - if (NtHdr->Pe32.FileHeader.Machine != EFI_IMAGE_MACHINE_EBC) { - // - // If not EBC, return NULL - // - return NULL; - } - - // - // Get DirectoryEntry - // EBC spec says PE32+, but implementation uses PE32. So check dynamically here. - // - if (NtHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { - OptionalHdr32 = (VOID *)&NtHdr->Pe32.OptionalHeader; - DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(OptionalHdr32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]); - } else if (NtHdr->Pe32Plus.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) { - OptionalHdr64 = (VOID *)&NtHdr->Pe32Plus.OptionalHeader; - DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(OptionalHdr64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]); - } else { - return NULL; - } - - if (DirectoryEntry->VirtualAddress == 0) { - return NULL; - } - - // - // Go through DirectoryEntry - // - for (DirCount = 0; - (DirCount < DirectoryEntry->Size / sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY)) && CodeViewEntryPointer == NULL; - DirCount++ - ) - { - DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *)(DirectoryEntry->VirtualAddress + (UINTN)ImageBase + DirCount * sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY)); - if (DebugEntry->Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) { - // - // Match DebugEntry, only CODEVIEW_SIGNATURE_NB10 and CODEVIEW_SIGNATURE_RSDS are supported. - // - CodeViewEntryPointer = (VOID *)((UINTN)DebugEntry->RVA + (UINTN)ImageBase); - switch (*(UINT32 *)CodeViewEntryPointer) { - case CODEVIEW_SIGNATURE_NB10: - PdbPath = (CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY); - break; - case CODEVIEW_SIGNATURE_RSDS: - PdbPath = (CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY); - break; - default: - break; - } - } - } - - // - // Done successfully - // - return PdbPath; -} - /** Check whether PDB file and MAP file have same name. @@ -873,14 +772,14 @@ GetPdbPath ( **/ BOOLEAN MatchPdbAndMap ( - IN CHAR8 *PdbFileName, - IN CHAR16 *MapFileName + IN CONST CHAR8 *PdbFileName, + IN CONST CHAR16 *MapFileName ) { - UINTN PdbNameSize; - UINTN MapNameSize; - CHAR8 *PurePdbFileName; - UINTN Index; + UINTN PdbNameSize; + UINTN MapNameSize; + CONST CHAR8 *PurePdbFileName; + UINTN Index; // // remove dir name @@ -1003,7 +902,7 @@ EdbPatchSymbolRVA ( EFI_STATUS Status; UINTN ImageNumber; EFI_DEBUG_IMAGE_INFO *ImageTable; - CHAR8 *PdbPath; + CONST CHAR8 *PdbPath; VOID *ImageBase; VOID *CandidateImageBase; EFI_DEBUGGER_SYMBOL_OBJECT *Object; @@ -1058,7 +957,7 @@ EdbPatchSymbolRVA ( // // Get PDB path // - PdbPath = GetPdbPath (ImageBase); + PdbPath = ImageTable[ImageNumber].NormalImage->PdbPath; if (PdbPath == NULL) { continue; } diff --git a/MdeModulePkg/Universal/EbcDxe/EbcDxe.inf b/MdeModulePkg/Universal/EbcDxe/EbcDxe.inf index 8f5fcbeb82..9ca18d8ec6 100644 --- a/MdeModulePkg/Universal/EbcDxe/EbcDxe.inf +++ b/MdeModulePkg/Universal/EbcDxe/EbcDxe.inf @@ -53,7 +53,6 @@ [LibraryClasses] CacheMaintenanceLib MemoryAllocationLib - PeCoffLib UefiBootServicesTableLib BaseMemoryLib UefiDriverEntryPoint diff --git a/MdeModulePkg/Universal/EbcDxe/EbcInt.c b/MdeModulePkg/Universal/EbcDxe/EbcInt.c index d2254c2765..46c4020102 100644 --- a/MdeModulePkg/Universal/EbcDxe/EbcInt.c +++ b/MdeModulePkg/Universal/EbcDxe/EbcInt.c @@ -405,27 +405,6 @@ EbcRegisterImage ( IN OUT EFI_IMAGE_ENTRY_POINT *EntryPoint ) { - DEBUG_CODE_BEGIN (); - PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; - EFI_STATUS Status; - - ZeroMem (&ImageContext, sizeof (ImageContext)); - - ImageContext.Handle = (VOID *)(UINTN)ImageBase; - ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory; - - Status = PeCoffLoaderGetImageInfo (&ImageContext); - if (EFI_ERROR (Status)) { - return Status; - } - - ASSERT (ImageContext.Machine == EFI_IMAGE_MACHINE_EBC); - ASSERT ( - ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION || - ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER - ); - DEBUG_CODE_END (); - EbcRegisterICacheFlush ( NULL, (EBC_ICACHE_FLUSH)InvalidateInstructionCacheRange diff --git a/MdeModulePkg/Universal/EbcDxe/EbcInt.h b/MdeModulePkg/Universal/EbcDxe/EbcInt.h index 646e3a613b..df3f11b1d4 100644 --- a/MdeModulePkg/Universal/EbcDxe/EbcInt.h +++ b/MdeModulePkg/Universal/EbcDxe/EbcInt.h @@ -12,6 +12,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #include +#include + #include #include #include @@ -21,7 +23,6 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #include #include #include -#include #include #include #include diff --git a/MdePkg/Include/Guid/DebugImageInfoTable.h b/MdePkg/Include/Guid/DebugImageInfoTable.h index 6661c4dd6a..82f337f67e 100644 --- a/MdePkg/Include/Guid/DebugImageInfoTable.h +++ b/MdePkg/Include/Guid/DebugImageInfoTable.h @@ -47,6 +47,7 @@ typedef struct { /// Indicates the image handle of the associated image. /// EFI_HANDLE ImageHandle; + CHAR8 *PdbPath; } EFI_DEBUG_IMAGE_INFO_NORMAL; typedef union { diff --git a/MdePkg/Include/Guid/WinCertificate.h b/MdePkg/Include/Guid/WinCertificate.h index 3b81a8a769..d29dc0ed17 100644 --- a/MdePkg/Include/Guid/WinCertificate.h +++ b/MdePkg/Include/Guid/WinCertificate.h @@ -56,7 +56,7 @@ typedef struct { /// WIN_CERTIFICATE_UEFI_GUID.CertData /// typedef struct { - EFI_GUID HashType; + GUID HashType; UINT8 PublicKey[256]; UINT8 Signature[256]; } EFI_CERT_BLOCK_RSA_2048_SHA256; @@ -74,14 +74,14 @@ typedef struct { /// This is the unique id which determines the /// format of the CertData. . /// - EFI_GUID CertType; + GUID CertType; /// /// The following is the certificate data. The format of /// the data is determined by the CertType. /// If CertType is EFI_CERT_TYPE_RSA2048_SHA256_GUID, /// the CertData will be EFI_CERT_BLOCK_RSA_2048_SHA256 structure. /// - UINT8 CertData[1]; + UINT8 CertData[]; } WIN_CERTIFICATE_UEFI_GUID; /// @@ -102,7 +102,7 @@ typedef struct { /// This is the hashing algorithm which was performed on the /// UEFI executable when creating the digital signature. /// - EFI_GUID HashAlgorithm; + GUID HashAlgorithm; /// /// The following is the actual digital signature. The /// size of the signature is the same size as the key @@ -111,10 +111,9 @@ typedef struct { /// from the total length of the certificate as found in /// Hdr.dwLength. /// - /// UINT8 Signature[]; - /// + UINT8 Signature[]; } WIN_CERTIFICATE_EFI_PKCS1_15; -extern EFI_GUID gEfiCertTypeRsa2048Sha256Guid; +extern GUID gEfiCertTypeRsa2048Sha256Guid; #endif diff --git a/MdePkg/Include/IndustryStandard/PeImage.h b/MdePkg/Include/IndustryStandard/PeImage.h index 596c2fc3cd..cfcabad63f 100644 --- a/MdePkg/Include/IndustryStandard/PeImage.h +++ b/MdePkg/Include/IndustryStandard/PeImage.h @@ -1,3 +1,5 @@ +#ifndef DISABLE_NEW_DEPRECATED_INTERFACES + /** @file EFI image format for PE32, PE32+ and TE. Please note some data structures are different for PE32 and PE32+. EFI_IMAGE_NT_HEADERS32 is for PE32 and @@ -25,7 +27,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #define EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION 10 #define EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER 11 #define EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER 12 -#define EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER 13///< defined PI Specification, 1.0 +#define EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER 13 ///< defined PI Specification, 1.0 // // PE32+ Machine type for EFI images @@ -191,7 +193,7 @@ typedef struct { /// EFI_IMAGE_OPTIONAL_HEADER64 must be used. The data structures only vary /// after NT additional fields. /// -#define EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b +#define EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b /// /// Optional Header Standard Fields for PE32+. @@ -232,32 +234,33 @@ typedef struct { UINT64 SizeOfHeapCommit; UINT32 LoaderFlags; UINT32 NumberOfRvaAndSizes; - EFI_IMAGE_DATA_DIRECTORY DataDirectory[EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES]; + EFI_IMAGE_DATA_DIRECTORY DataDirectory[EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES]; } EFI_IMAGE_OPTIONAL_HEADER64; + /// /// @attention /// EFI_IMAGE_NT_HEADERS32 is for use ONLY by tools. /// typedef struct { - UINT32 Signature; - EFI_IMAGE_FILE_HEADER FileHeader; - EFI_IMAGE_OPTIONAL_HEADER32 OptionalHeader; + UINT32 Signature; + EFI_IMAGE_FILE_HEADER FileHeader; + EFI_IMAGE_OPTIONAL_HEADER32 OptionalHeader; } EFI_IMAGE_NT_HEADERS32; -#define EFI_IMAGE_SIZEOF_NT_OPTIONAL32_HEADER sizeof (EFI_IMAGE_NT_HEADERS32) +#define EFI_IMAGE_SIZEOF_NT_OPTIONAL32_HEADER sizeof (EFI_IMAGE_NT_HEADERS32) /// /// @attention /// EFI_IMAGE_HEADERS64 is for use ONLY by tools. /// typedef struct { - UINT32 Signature; - EFI_IMAGE_FILE_HEADER FileHeader; - EFI_IMAGE_OPTIONAL_HEADER64 OptionalHeader; + UINT32 Signature; + EFI_IMAGE_FILE_HEADER FileHeader; + EFI_IMAGE_OPTIONAL_HEADER64 OptionalHeader; } EFI_IMAGE_NT_HEADERS64; -#define EFI_IMAGE_SIZEOF_NT_OPTIONAL64_HEADER sizeof (EFI_IMAGE_NT_HEADERS64) +#define EFI_IMAGE_SIZEOF_NT_OPTIONAL64_HEADER sizeof (EFI_IMAGE_NT_HEADERS64) // // Other Windows Subsystem Values @@ -293,10 +296,10 @@ typedef struct { /// Section Table. This table immediately follows the optional header. /// typedef struct { - UINT8 Name[EFI_IMAGE_SIZEOF_SHORT_NAME]; + UINT8 Name[EFI_IMAGE_SIZEOF_SHORT_NAME]; union { - UINT32 PhysicalAddress; - UINT32 VirtualSize; + UINT32 PhysicalAddress; + UINT32 VirtualSize; } Misc; UINT32 VirtualAddress; UINT32 SizeOfRawData; @@ -311,7 +314,7 @@ typedef struct { /// /// Size of EFI_IMAGE_SECTION_HEADER. /// -#define EFI_IMAGE_SIZEOF_SECTION_HEADER 40 +#define EFI_IMAGE_SIZEOF_SECTION_HEADER 40 // // Section Flags Values @@ -518,9 +521,9 @@ typedef struct { /// /// Relocation types of RISC-V processor. /// -#define EFI_IMAGE_REL_BASED_RISCV_HI20 5 -#define EFI_IMAGE_REL_BASED_RISCV_LOW12I 7 -#define EFI_IMAGE_REL_BASED_RISCV_LOW12S 8 +#define EFI_IMAGE_REL_BASED_RISCV_HI20 5 +#define EFI_IMAGE_REL_BASED_RISCV_LOW12I 7 +#define EFI_IMAGE_REL_BASED_RISCV_LOW12S 8 // // Relocation types of LoongArch processor. @@ -572,6 +575,7 @@ typedef struct { /// #define EFI_IMAGE_SIZEOF_ARCHIVE_MEMBER_HDR 60 + // // DLL Support // @@ -634,6 +638,7 @@ typedef struct { EFI_IMAGE_THUNK_DATA *FirstThunk; } EFI_IMAGE_IMPORT_DESCRIPTOR; + /// /// Debug Directory Format. /// @@ -681,6 +686,7 @@ typedef struct { // } EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY; + /// /// Debug Data Structure defined by Apple Mach-O to Coff utility. /// @@ -725,12 +731,12 @@ typedef struct { /// Resource format. /// typedef struct { - UINT32 Characteristics; - UINT32 TimeDateStamp; - UINT16 MajorVersion; - UINT16 MinorVersion; - UINT16 NumberOfNamedEntries; - UINT16 NumberOfIdEntries; + UINT32 Characteristics; + UINT32 TimeDateStamp; + UINT16 MajorVersion; + UINT16 MinorVersion; + UINT16 NumberOfNamedEntries; + UINT16 NumberOfIdEntries; // // Array of EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY entries goes here. // @@ -789,6 +795,7 @@ typedef struct { EFI_IMAGE_DATA_DIRECTORY DataDirectory[2]; ///< Only base relocation and debug directory. } EFI_TE_IMAGE_HEADER; + #define EFI_TE_IMAGE_HEADER_SIGNATURE SIGNATURE_16('V', 'Z') // @@ -797,20 +804,23 @@ typedef struct { #define EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC 0 #define EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG 1 + /// /// Union of PE32, PE32+, and TE headers. /// typedef union { - EFI_IMAGE_NT_HEADERS32 Pe32; - EFI_IMAGE_NT_HEADERS64 Pe32Plus; - EFI_TE_IMAGE_HEADER Te; + EFI_IMAGE_NT_HEADERS32 Pe32; + EFI_IMAGE_NT_HEADERS64 Pe32Plus; + EFI_TE_IMAGE_HEADER Te; } EFI_IMAGE_OPTIONAL_HEADER_UNION; typedef union { - EFI_IMAGE_NT_HEADERS32 *Pe32; - EFI_IMAGE_NT_HEADERS64 *Pe32Plus; - EFI_TE_IMAGE_HEADER *Te; - EFI_IMAGE_OPTIONAL_HEADER_UNION *Union; + EFI_IMAGE_NT_HEADERS32 *Pe32; + EFI_IMAGE_NT_HEADERS64 *Pe32Plus; + EFI_TE_IMAGE_HEADER *Te; + EFI_IMAGE_OPTIONAL_HEADER_UNION *Union; } EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION; #endif + +#endif // DISABLE_NEW_DEPRECATED_INTERFACES diff --git a/MdePkg/Include/IndustryStandard/PeImage2.h b/MdePkg/Include/IndustryStandard/PeImage2.h new file mode 100644 index 0000000000..d5a69f7886 --- /dev/null +++ b/MdePkg/Include/IndustryStandard/PeImage2.h @@ -0,0 +1,761 @@ +/** @file + EFI image format for PE32, PE32+ and TE. Please note some data structures are + different for PE32 and PE32+. EFI_IMAGE_NT_HEADERS32 is for PE32 and + EFI_IMAGE_NT_HEADERS64 is for PE32+. + This file is coded to the Visual Studio, Microsoft Portable Executable and + Common Object File Format Specification, Revision 8.3 - February 6, 2013. + This file also includes some definitions in PI Specification, Revision 1.0. + + Copyright (c) 2020, Marvin Häuser. All rights reserved.
+ Copyright (c) 2020, Vitaly Cheptsov. All rights reserved.
+ Copyright (c) 2020, ISP RAS. All rights reserved.
+ Portions copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.
+ Portions copyright (c) 2008 - 2010, Apple Inc. All rights reserved.
+ Portions Copyright (c) 2020, Hewlett Packard Enterprise Development LP. All rights reserved.
+ + SPDX-License-Identifier: BSD-3-Clause +**/ + +#ifndef PE_COFF_IMAGE2_H_ +#define PE_COFF_IMAGE2_H_ + +// +// PE32+ Subsystem type for EFI images +// +#define EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION 10 +#define EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER 11 +#define EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER 12 +#define EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER 13 ///< defined PI Specification, 1.0 + + +// +// PE32+ Machine type for EFI images +// +#define IMAGE_FILE_MACHINE_I386 0x014c +#define IMAGE_FILE_MACHINE_IA64 0x0200 +#define IMAGE_FILE_MACHINE_EBC 0x0EBC +#define IMAGE_FILE_MACHINE_X64 0x8664 +#define IMAGE_FILE_MACHINE_ARMTHUMB_MIXED 0x01c2 +#define IMAGE_FILE_MACHINE_ARM64 0xAA64 +#define IMAGE_FILE_MACHINE_RISCV32 0x5032 +#define IMAGE_FILE_MACHINE_RISCV64 0x5064 +#define IMAGE_FILE_MACHINE_RISCV128 0x5128 + +// +// EXE file formats +// +#define EFI_IMAGE_DOS_SIGNATURE SIGNATURE_16('M', 'Z') +#define EFI_IMAGE_OS2_SIGNATURE SIGNATURE_16('N', 'E') +#define EFI_IMAGE_OS2_SIGNATURE_LE SIGNATURE_16('L', 'E') +#define EFI_IMAGE_NT_SIGNATURE SIGNATURE_32('P', 'E', '\0', '\0') + +/// +/// PE images can start with an optional DOS header, so if an image is run +/// under DOS it can print an error message. +/// +typedef struct { + UINT16 e_magic; ///< Magic number. + UINT16 e_cblp; ///< Bytes on last page of file. + UINT16 e_cp; ///< Pages in file. + UINT16 e_crlc; ///< Relocations. + UINT16 e_cparhdr; ///< Size of header in paragraphs. + UINT16 e_minalloc; ///< Minimum extra paragraphs needed. + UINT16 e_maxalloc; ///< Maximum extra paragraphs needed. + UINT16 e_ss; ///< Initial (relative) SS value. + UINT16 e_sp; ///< Initial SP value. + UINT16 e_csum; ///< Checksum. + UINT16 e_ip; ///< Initial IP value. + UINT16 e_cs; ///< Initial (relative) CS value. + UINT16 e_lfarlc; ///< File address of relocation table. + UINT16 e_ovno; ///< Overlay number. + UINT16 e_res[4]; ///< Reserved words. + UINT16 e_oemid; ///< OEM identifier (for e_oeminfo). + UINT16 e_oeminfo; ///< OEM information; e_oemid specific. + UINT16 e_res2[10]; ///< Reserved words. + UINT32 e_lfanew; ///< File address of new exe header. +} EFI_IMAGE_DOS_HEADER; + +/// +/// COFF File Header (Object and Image). +/// +typedef struct { + UINT16 Machine; + UINT16 NumberOfSections; + UINT32 TimeDateStamp; + UINT32 PointerToSymbolTable; + UINT32 NumberOfSymbols; + UINT16 SizeOfOptionalHeader; + UINT16 Characteristics; +} EFI_IMAGE_FILE_HEADER; + +/// +/// Size of EFI_IMAGE_FILE_HEADER. +/// +#define EFI_IMAGE_SIZEOF_FILE_HEADER 20 + +// +// Characteristics +// +#define EFI_IMAGE_FILE_RELOCS_STRIPPED BIT0 ///< 0x0001 Relocation info stripped from file. +#define EFI_IMAGE_FILE_EXECUTABLE_IMAGE BIT1 ///< 0x0002 File is executable (i.e. no unresolved externel references). +#define EFI_IMAGE_FILE_LINE_NUMS_STRIPPED BIT2 ///< 0x0004 Line numbers stripped from file. +#define EFI_IMAGE_FILE_LOCAL_SYMS_STRIPPED BIT3 ///< 0x0008 Local symbols stripped from file. +#define EFI_IMAGE_FILE_LARGE_ADDRESS_AWARE BIT5 ///< 0x0020 Supports addresses > 2-GB +#define EFI_IMAGE_FILE_BYTES_REVERSED_LO BIT7 ///< 0x0080 Bytes of machine word are reversed. +#define EFI_IMAGE_FILE_32BIT_MACHINE BIT8 ///< 0x0100 32 bit word machine. +#define EFI_IMAGE_FILE_DEBUG_STRIPPED BIT9 ///< 0x0200 Debugging info stripped from file in .DBG file. +#define EFI_IMAGE_FILE_SYSTEM BIT12 ///< 0x1000 System File. +#define EFI_IMAGE_FILE_DLL BIT13 ///< 0x2000 File is a DLL. +#define EFI_IMAGE_FILE_BYTES_REVERSED_HI BIT15 ///< 0x8000 Bytes of machine word are reversed. + +/// +/// Header Data Directories. +/// +typedef struct { + UINT32 VirtualAddress; + UINT32 Size; +} EFI_IMAGE_DATA_DIRECTORY; + +// +// Directory Entries +// +#define EFI_IMAGE_DIRECTORY_ENTRY_EXPORT 0 +#define EFI_IMAGE_DIRECTORY_ENTRY_IMPORT 1 +#define EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE 2 +#define EFI_IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 +#define EFI_IMAGE_DIRECTORY_ENTRY_SECURITY 4 +#define EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC 5 +#define EFI_IMAGE_DIRECTORY_ENTRY_DEBUG 6 +#define EFI_IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7 +#define EFI_IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 +#define EFI_IMAGE_DIRECTORY_ENTRY_TLS 9 +#define EFI_IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 + +#define EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES 16 + +/// +/// @attention +/// EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC means PE32 and +/// EFI_IMAGE_OPTIONAL_HEADER32 must be used. The data structures only vary +/// after NT additional fields. +/// +#define EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b + +/// +/// @attention +/// EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC means PE32+ and +/// EFI_IMAGE_OPTIONAL_HEADER64 must be used. The data structures only vary +/// after NT additional fields. +/// +#define EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b + + +/// +/// @attention +/// EFI_IMAGE_NT_HEADERS32 is for use ONLY by tools. +/// +typedef struct { + UINT32 Signature; + EFI_IMAGE_FILE_HEADER FileHeader; +} EFI_IMAGE_NT_HEADERS_COMMON_HDR; + +STATIC_ASSERT ( + sizeof (EFI_IMAGE_NT_HEADERS_COMMON_HDR) == sizeof (UINT32) + sizeof (EFI_IMAGE_FILE_HEADER), + "Unsupported padding." + ); + +/// +/// @attention +/// EFI_IMAGE_NT_HEADERS32 is for use ONLY by tools. +/// +typedef struct { + EFI_IMAGE_NT_HEADERS_COMMON_HDR CommonHeader; + /// + /// Standard fields. + /// + UINT16 Magic; + UINT8 MajorLinkerVersion; + UINT8 MinorLinkerVersion; + UINT32 SizeOfCode; + UINT32 SizeOfInitializedData; + UINT32 SizeOfUninitializedData; + UINT32 AddressOfEntryPoint; + UINT32 BaseOfCode; + UINT32 BaseOfData; ///< PE32 contains this additional field, which is absent in PE32+. + /// + /// Optional Header Windows-Specific Fields. + /// + UINT32 ImageBase; + UINT32 SectionAlignment; + UINT32 FileAlignment; + UINT16 MajorOperatingSystemVersion; + UINT16 MinorOperatingSystemVersion; + UINT16 MajorImageVersion; + UINT16 MinorImageVersion; + UINT16 MajorSubsystemVersion; + UINT16 MinorSubsystemVersion; + UINT32 Win32VersionValue; + UINT32 SizeOfImage; + UINT32 SizeOfHeaders; + UINT32 CheckSum; + UINT16 Subsystem; + UINT16 DllCharacteristics; + UINT32 SizeOfStackReserve; + UINT32 SizeOfStackCommit; + UINT32 SizeOfHeapReserve; + UINT32 SizeOfHeapCommit; + UINT32 LoaderFlags; + UINT32 NumberOfRvaAndSizes; + EFI_IMAGE_DATA_DIRECTORY DataDirectory[]; +} EFI_IMAGE_NT_HEADERS32; + +/// +/// @attention +/// EFI_IMAGE_HEADERS64 is for use ONLY by tools. +/// +typedef struct { + EFI_IMAGE_NT_HEADERS_COMMON_HDR CommonHeader; + /// + /// Standard fields. + /// + UINT16 Magic; + UINT8 MajorLinkerVersion; + UINT8 MinorLinkerVersion; + UINT32 SizeOfCode; + UINT32 SizeOfInitializedData; + UINT32 SizeOfUninitializedData; + UINT32 AddressOfEntryPoint; + UINT32 BaseOfCode; + /// + /// Optional Header Windows-Specific Fields. + /// + UINT64 ImageBase; + UINT32 SectionAlignment; + UINT32 FileAlignment; + UINT16 MajorOperatingSystemVersion; + UINT16 MinorOperatingSystemVersion; + UINT16 MajorImageVersion; + UINT16 MinorImageVersion; + UINT16 MajorSubsystemVersion; + UINT16 MinorSubsystemVersion; + UINT32 Win32VersionValue; + UINT32 SizeOfImage; + UINT32 SizeOfHeaders; + UINT32 CheckSum; + UINT16 Subsystem; + UINT16 DllCharacteristics; + UINT64 SizeOfStackReserve; + UINT64 SizeOfStackCommit; + UINT64 SizeOfHeapReserve; + UINT64 SizeOfHeapCommit; + UINT32 LoaderFlags; + UINT32 NumberOfRvaAndSizes; + EFI_IMAGE_DATA_DIRECTORY DataDirectory[]; +} EFI_IMAGE_NT_HEADERS64; + +// +// Other Windows Subsystem Values +// +#define EFI_IMAGE_SUBSYSTEM_UNKNOWN 0 +#define EFI_IMAGE_SUBSYSTEM_NATIVE 1 +#define EFI_IMAGE_SUBSYSTEM_WINDOWS_GUI 2 +#define EFI_IMAGE_SUBSYSTEM_WINDOWS_CUI 3 +#define EFI_IMAGE_SUBSYSTEM_OS2_CUI 5 +#define EFI_IMAGE_SUBSYSTEM_POSIX_CUI 7 + +/// +/// Length of ShortName. +/// +#define EFI_IMAGE_SIZEOF_SHORT_NAME 8 + +/// +/// Section Table. This table immediately follows the optional header. +/// +typedef struct { + UINT8 Name[EFI_IMAGE_SIZEOF_SHORT_NAME]; + UINT32 VirtualSize; + UINT32 VirtualAddress; + UINT32 SizeOfRawData; + UINT32 PointerToRawData; + UINT32 PointerToRelocations; + UINT32 PointerToLinenumbers; + UINT16 NumberOfRelocations; + UINT16 NumberOfLinenumbers; + UINT32 Characteristics; +} EFI_IMAGE_SECTION_HEADER; + +// +// Section Flags Values +// +#define EFI_IMAGE_SCN_TYPE_NO_PAD BIT3 ///< 0x00000008 ///< Reserved. +#define EFI_IMAGE_SCN_CNT_CODE BIT5 ///< 0x00000020 +#define EFI_IMAGE_SCN_CNT_INITIALIZED_DATA BIT6 ///< 0x00000040 +#define EFI_IMAGE_SCN_CNT_UNINITIALIZED_DATA BIT7 ///< 0x00000080 + +#define EFI_IMAGE_SCN_LNK_OTHER BIT8 ///< 0x00000100 ///< Reserved. +#define EFI_IMAGE_SCN_LNK_INFO BIT9 ///< 0x00000200 ///< Section contains comments or some other type of information. +#define EFI_IMAGE_SCN_LNK_REMOVE BIT11 ///< 0x00000800 ///< Section contents will not become part of image. +#define EFI_IMAGE_SCN_LNK_COMDAT BIT12 ///< 0x00001000 + +#define EFI_IMAGE_SCN_ALIGN_1BYTES BIT20 ///< 0x00100000 +#define EFI_IMAGE_SCN_ALIGN_2BYTES BIT21 ///< 0x00200000 +#define EFI_IMAGE_SCN_ALIGN_4BYTES (BIT20|BIT21) ///< 0x00300000 +#define EFI_IMAGE_SCN_ALIGN_8BYTES BIT22 ///< 0x00400000 +#define EFI_IMAGE_SCN_ALIGN_16BYTES (BIT20|BIT22) ///< 0x00500000 +#define EFI_IMAGE_SCN_ALIGN_32BYTES (BIT21|BIT22) ///< 0x00600000 +#define EFI_IMAGE_SCN_ALIGN_64BYTES (BIT20|BIT21|BIT22) ///< 0x00700000 + +#define EFI_IMAGE_SCN_MEM_DISCARDABLE BIT25 ///< 0x02000000 +#define EFI_IMAGE_SCN_MEM_NOT_CACHED BIT26 ///< 0x04000000 +#define EFI_IMAGE_SCN_MEM_NOT_PAGED BIT27 ///< 0x08000000 +#define EFI_IMAGE_SCN_MEM_SHARED BIT28 ///< 0x10000000 +#define EFI_IMAGE_SCN_MEM_EXECUTE BIT29 ///< 0x20000000 +#define EFI_IMAGE_SCN_MEM_READ BIT30 ///< 0x40000000 +#define EFI_IMAGE_SCN_MEM_WRITE BIT31 ///< 0x80000000 + +/// +/// Size of a Symbol Table Record. +/// +#define EFI_IMAGE_SIZEOF_SYMBOL 18 + +// +// Symbols have a section number of the section in which they are +// defined. Otherwise, section numbers have the following meanings: +// +#define EFI_IMAGE_SYM_UNDEFINED (UINT16) 0 ///< Symbol is undefined or is common. +#define EFI_IMAGE_SYM_ABSOLUTE (UINT16) -1 ///< Symbol is an absolute value. +#define EFI_IMAGE_SYM_DEBUG (UINT16) -2 ///< Symbol is a special debug item. + +// +// Symbol Type (fundamental) values. +// +#define EFI_IMAGE_SYM_TYPE_NULL 0 ///< no type. +#define EFI_IMAGE_SYM_TYPE_VOID 1 ///< no valid type. +#define EFI_IMAGE_SYM_TYPE_CHAR 2 ///< type character. +#define EFI_IMAGE_SYM_TYPE_SHORT 3 ///< type short integer. +#define EFI_IMAGE_SYM_TYPE_INT 4 +#define EFI_IMAGE_SYM_TYPE_LONG 5 +#define EFI_IMAGE_SYM_TYPE_FLOAT 6 +#define EFI_IMAGE_SYM_TYPE_DOUBLE 7 +#define EFI_IMAGE_SYM_TYPE_STRUCT 8 +#define EFI_IMAGE_SYM_TYPE_UNION 9 +#define EFI_IMAGE_SYM_TYPE_ENUM 10 ///< enumeration. +#define EFI_IMAGE_SYM_TYPE_MOE 11 ///< member of enumeration. +#define EFI_IMAGE_SYM_TYPE_BYTE 12 +#define EFI_IMAGE_SYM_TYPE_WORD 13 +#define EFI_IMAGE_SYM_TYPE_UINT 14 +#define EFI_IMAGE_SYM_TYPE_DWORD 15 + +// +// Symbol Type (derived) values. +// +#define EFI_IMAGE_SYM_DTYPE_NULL 0 ///< no derived type. +#define EFI_IMAGE_SYM_DTYPE_POINTER 1 +#define EFI_IMAGE_SYM_DTYPE_FUNCTION 2 +#define EFI_IMAGE_SYM_DTYPE_ARRAY 3 + +// +// Storage classes. +// +#define EFI_IMAGE_SYM_CLASS_END_OF_FUNCTION ((UINT8) -1) +#define EFI_IMAGE_SYM_CLASS_NULL 0 +#define EFI_IMAGE_SYM_CLASS_AUTOMATIC 1 +#define EFI_IMAGE_SYM_CLASS_EXTERNAL 2 +#define EFI_IMAGE_SYM_CLASS_STATIC 3 +#define EFI_IMAGE_SYM_CLASS_REGISTER 4 +#define EFI_IMAGE_SYM_CLASS_EXTERNAL_DEF 5 +#define EFI_IMAGE_SYM_CLASS_LABEL 6 +#define EFI_IMAGE_SYM_CLASS_UNDEFINED_LABEL 7 +#define EFI_IMAGE_SYM_CLASS_MEMBER_OF_STRUCT 8 +#define EFI_IMAGE_SYM_CLASS_ARGUMENT 9 +#define EFI_IMAGE_SYM_CLASS_STRUCT_TAG 10 +#define EFI_IMAGE_SYM_CLASS_MEMBER_OF_UNION 11 +#define EFI_IMAGE_SYM_CLASS_UNION_TAG 12 +#define EFI_IMAGE_SYM_CLASS_TYPE_DEFINITION 13 +#define EFI_IMAGE_SYM_CLASS_UNDEFINED_STATIC 14 +#define EFI_IMAGE_SYM_CLASS_ENUM_TAG 15 +#define EFI_IMAGE_SYM_CLASS_MEMBER_OF_ENUM 16 +#define EFI_IMAGE_SYM_CLASS_REGISTER_PARAM 17 +#define EFI_IMAGE_SYM_CLASS_BIT_FIELD 18 +#define EFI_IMAGE_SYM_CLASS_BLOCK 100 +#define EFI_IMAGE_SYM_CLASS_FUNCTION 101 +#define EFI_IMAGE_SYM_CLASS_END_OF_STRUCT 102 +#define EFI_IMAGE_SYM_CLASS_FILE 103 +#define EFI_IMAGE_SYM_CLASS_SECTION 104 +#define EFI_IMAGE_SYM_CLASS_WEAK_EXTERNAL 105 + +// +// type packing constants +// +#define EFI_IMAGE_N_BTMASK 017 +#define EFI_IMAGE_N_TMASK 060 +#define EFI_IMAGE_N_TMASK1 0300 +#define EFI_IMAGE_N_TMASK2 0360 +#define EFI_IMAGE_N_BTSHFT 4 +#define EFI_IMAGE_N_TSHIFT 2 + +// +// Communal selection types. +// +#define EFI_IMAGE_COMDAT_SELECT_NODUPLICATES 1 +#define EFI_IMAGE_COMDAT_SELECT_ANY 2 +#define EFI_IMAGE_COMDAT_SELECT_SAME_SIZE 3 +#define EFI_IMAGE_COMDAT_SELECT_EXACT_MATCH 4 +#define EFI_IMAGE_COMDAT_SELECT_ASSOCIATIVE 5 + +// +// the following values only be referred in PeCoff, not defined in PECOFF. +// +#define EFI_IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY 1 +#define EFI_IMAGE_WEAK_EXTERN_SEARCH_LIBRARY 2 +#define EFI_IMAGE_WEAK_EXTERN_SEARCH_ALIAS 3 + +/// +/// Relocation format. +/// +typedef struct { + UINT32 VirtualAddress; + UINT32 SymbolTableIndex; + UINT16 Type; +} EFI_IMAGE_RELOCATION; + +/// +/// Size of EFI_IMAGE_RELOCATION +/// +#define EFI_IMAGE_SIZEOF_RELOCATION 10 + +// +// I386 relocation types. +// +#define EFI_IMAGE_REL_I386_ABSOLUTE 0x0000 ///< Reference is absolute, no relocation is necessary. +#define EFI_IMAGE_REL_I386_DIR16 0x0001 ///< Direct 16-bit reference to the symbols virtual address. +#define EFI_IMAGE_REL_I386_REL16 0x0002 ///< PC-relative 16-bit reference to the symbols virtual address. +#define EFI_IMAGE_REL_I386_DIR32 0x0006 ///< Direct 32-bit reference to the symbols virtual address. +#define EFI_IMAGE_REL_I386_DIR32NB 0x0007 ///< Direct 32-bit reference to the symbols virtual address, base not included. +#define EFI_IMAGE_REL_I386_SEG12 0x0009 ///< Direct 16-bit reference to the segment-selector bits of a 32-bit virtual address. +#define EFI_IMAGE_REL_I386_SECTION 0x000A +#define EFI_IMAGE_REL_I386_SECREL 0x000B +#define EFI_IMAGE_REL_I386_REL32 0x0014 ///< PC-relative 32-bit reference to the symbols virtual address. + +// +// x64 processor relocation types. +// +#define IMAGE_REL_AMD64_ABSOLUTE 0x0000 +#define IMAGE_REL_AMD64_ADDR64 0x0001 +#define IMAGE_REL_AMD64_ADDR32 0x0002 +#define IMAGE_REL_AMD64_ADDR32NB 0x0003 +#define IMAGE_REL_AMD64_REL32 0x0004 +#define IMAGE_REL_AMD64_REL32_1 0x0005 +#define IMAGE_REL_AMD64_REL32_2 0x0006 +#define IMAGE_REL_AMD64_REL32_3 0x0007 +#define IMAGE_REL_AMD64_REL32_4 0x0008 +#define IMAGE_REL_AMD64_REL32_5 0x0009 +#define IMAGE_REL_AMD64_SECTION 0x000A +#define IMAGE_REL_AMD64_SECREL 0x000B +#define IMAGE_REL_AMD64_SECREL7 0x000C +#define IMAGE_REL_AMD64_TOKEN 0x000D +#define IMAGE_REL_AMD64_SREL32 0x000E +#define IMAGE_REL_AMD64_PAIR 0x000F +#define IMAGE_REL_AMD64_SSPAN32 0x0010 + +/** + Returns the type of a Base Relocation. + + @param[in] Relocation The composite Base Relocation value. +**/ +#define IMAGE_RELOC_TYPE(Relocation) ((Relocation) >> 12U) + +/** + Returns the target offset of a Base Relocation. + + @param[in] Relocation The composite Base Relocation value. +**/ +#define IMAGE_RELOC_OFFSET(Relocation) ((Relocation) & 0x0FFFU) + +/// +/// Based relocation format. +/// +typedef struct { + UINT32 VirtualAddress; + UINT32 SizeOfBlock; + UINT16 Relocations[]; +} EFI_IMAGE_BASE_RELOCATION_BLOCK; + +// +// Based relocation types. +// +#define EFI_IMAGE_REL_BASED_ABSOLUTE 0 +#define EFI_IMAGE_REL_BASED_HIGH 1 +#define EFI_IMAGE_REL_BASED_LOW 2 +#define EFI_IMAGE_REL_BASED_HIGHLOW 3 +#define EFI_IMAGE_REL_BASED_HIGHADJ 4 +#define EFI_IMAGE_REL_BASED_MIPS_JMPADDR 5 +#define EFI_IMAGE_REL_BASED_ARM_MOV32A 5 +#define EFI_IMAGE_REL_BASED_ARM_MOV32T 7 +#define EFI_IMAGE_REL_BASED_IA64_IMM64 9 +#define EFI_IMAGE_REL_BASED_MIPS_JMPADDR16 9 +#define EFI_IMAGE_REL_BASED_DIR64 10 + +/// +/// Relocation types of RISC-V processor. +/// +#define EFI_IMAGE_REL_BASED_RISCV_HI20 5 +#define EFI_IMAGE_REL_BASED_RISCV_LOW12I 7 +#define EFI_IMAGE_REL_BASED_RISCV_LOW12S 8 + +/// +/// Line number format. +/// +typedef struct { + union { + UINT32 SymbolTableIndex; ///< Symbol table index of function name if Linenumber is 0. + UINT32 VirtualAddress; ///< Virtual address of line number. + } Type; + UINT16 Linenumber; ///< Line number. +} EFI_IMAGE_LINENUMBER; + +/// +/// Size of EFI_IMAGE_LINENUMBER. +/// +#define EFI_IMAGE_SIZEOF_LINENUMBER 6 + +// +// Archive format. +// +#define EFI_IMAGE_ARCHIVE_START_SIZE 8 +#define EFI_IMAGE_ARCHIVE_START "!\n" +#define EFI_IMAGE_ARCHIVE_END "`\n" +#define EFI_IMAGE_ARCHIVE_PAD "\n" +#define EFI_IMAGE_ARCHIVE_LINKER_MEMBER "/ " +#define EFI_IMAGE_ARCHIVE_LONGNAMES_MEMBER "// " + +/// +/// Archive Member Headers +/// +typedef struct { + UINT8 Name[16]; ///< File member name - `/' terminated. + UINT8 Date[12]; ///< File member date - decimal. + UINT8 UserID[6]; ///< File member user id - decimal. + UINT8 GroupID[6]; ///< File member group id - decimal. + UINT8 Mode[8]; ///< File member mode - octal. + UINT8 Size[10]; ///< File member size - decimal. + UINT8 EndHeader[2]; ///< String to end header. (0x60 0x0A). +} EFI_IMAGE_ARCHIVE_MEMBER_HEADER; + +/// +/// Size of EFI_IMAGE_ARCHIVE_MEMBER_HEADER. +/// +#define EFI_IMAGE_SIZEOF_ARCHIVE_MEMBER_HDR 60 + + +// +// DLL Support +// + +/// +/// Export Directory Table. +/// +typedef struct { + UINT32 Characteristics; + UINT32 TimeDateStamp; + UINT16 MajorVersion; + UINT16 MinorVersion; + UINT32 Name; + UINT32 Base; + UINT32 NumberOfFunctions; + UINT32 NumberOfNames; + UINT32 AddressOfFunctions; + UINT32 AddressOfNames; + UINT32 AddressOfNameOrdinals; +} EFI_IMAGE_EXPORT_DIRECTORY; + +/// +/// Hint/Name Table. +/// +typedef struct { + UINT16 Hint; + UINT8 Name[1]; +} EFI_IMAGE_IMPORT_BY_NAME; + +/// +/// Import Address Table RVA (Thunk Table). +/// +typedef struct { + union { + UINT32 Function; + UINT32 Ordinal; + EFI_IMAGE_IMPORT_BY_NAME *AddressOfData; + } u1; +} EFI_IMAGE_THUNK_DATA; + +#define EFI_IMAGE_ORDINAL_FLAG BIT31 ///< Flag for PE32. +#define EFI_IMAGE_SNAP_BY_ORDINAL(Ordinal) ((Ordinal & EFI_IMAGE_ORDINAL_FLAG) != 0) +#define EFI_IMAGE_ORDINAL(Ordinal) (Ordinal & 0xffff) + +/// +/// Import Directory Table +/// +typedef struct { + UINT32 Characteristics; + UINT32 TimeDateStamp; + UINT32 ForwarderChain; + UINT32 Name; + EFI_IMAGE_THUNK_DATA *FirstThunk; +} EFI_IMAGE_IMPORT_DESCRIPTOR; + + +/// +/// Debug Directory Format. +/// +typedef struct { + UINT32 Characteristics; + UINT32 TimeDateStamp; + UINT16 MajorVersion; + UINT16 MinorVersion; + UINT32 Type; + UINT32 SizeOfData; + UINT32 RVA; ///< The address of the debug data when loaded, relative to the image base. + UINT32 FileOffset; ///< The file pointer to the debug data. +} EFI_IMAGE_DEBUG_DIRECTORY_ENTRY; + +#define EFI_IMAGE_DEBUG_TYPE_CODEVIEW 2 ///< The Visual C++ debug information. + +/// +/// Debug Data Structure defined in Microsoft C++. +/// +#define CODEVIEW_SIGNATURE_NB10 SIGNATURE_32('N', 'B', '1', '0') +typedef struct { + UINT32 Signature; ///< "NB10" + UINT32 Unknown; + UINT32 Unknown2; + UINT32 Unknown3; + // + // Filename of .PDB goes here + // +} EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY; + +/// +/// Debug Data Structure defined in Microsoft C++. +/// FIXME: +/// Documentation available at: https://github.com/dotnet/runtime/blob/main/docs/design/specs/PE-COFF.md +/// +#define CODEVIEW_SIGNATURE_RSDS SIGNATURE_32('R', 'S', 'D', 'S') +typedef struct { + // + // 0x52 0x53 0x44 0x53 (ASCII string: "RSDS") + // + UINT32 Signature; ///< "RSDS". + // + // GUID (Globally Unique Identifier) of the associated PDB. + // + UINT8 Guid[16]; + // + // Iteration of the PDB. The first iteration is 1. The iteration is + // incremented each time the PDB content is augmented. + // + UINT32 Age; + // + // UTF-8 NUL-terminated path to the associated .pdb file + // +} EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY; + + +/// +/// Debug Data Structure defined by Apple Mach-O to Coff utility. +/// +#define CODEVIEW_SIGNATURE_MTOC SIGNATURE_32('M', 'T', 'O', 'C') +typedef struct { + UINT32 Signature; ///< "MTOC". + UINT8 Uuid[16]; + // + // Filename of .DLL (Mach-O with debug info) goes here + // +} EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY; + +/// +/// Resource directory entry format. +/// +typedef struct { + union { + struct { + UINT32 NameOffset:31; + UINT32 NameIsString:1; + } s; + UINT32 Id; + } u1; + union { + UINT32 OffsetToData; + struct { + UINT32 OffsetToDirectory:31; + UINT32 DataIsDirectory:1; + } s; + } u2; +} EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY; + +/// +/// Resource format. +/// +typedef struct { + UINT32 Characteristics; + UINT32 TimeDateStamp; + UINT16 MajorVersion; + UINT16 MinorVersion; + UINT16 NumberOfNamedEntries; + UINT16 NumberOfIdEntries; + EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY Entries[]; +} EFI_IMAGE_RESOURCE_DIRECTORY; + +/// +/// Resource directory entry for string. +/// +typedef struct { + UINT16 Length; + CHAR16 String[]; +} EFI_IMAGE_RESOURCE_DIRECTORY_STRING; + +/// +/// Resource directory entry for data array. +/// +typedef struct { + UINT32 OffsetToData; + UINT32 Size; + UINT32 CodePage; + UINT32 Reserved; +} EFI_IMAGE_RESOURCE_DATA_ENTRY; + +/// +/// Header format for TE images, defined in the PI Specification, 1.0. +/// +typedef struct { + UINT16 Signature; ///< The signature for TE format = "VZ". + UINT16 Machine; ///< From the original file header. + UINT8 NumberOfSections; ///< From the original file header. + UINT8 Subsystem; ///< From original optional header. + UINT16 StrippedSize; ///< Number of bytes we removed from the header. + UINT32 AddressOfEntryPoint; ///< Offset to entry point -- from original optional header. + UINT32 BaseOfCode; ///< From original image -- required for ITP debug. + UINT64 ImageBase; ///< From original file header. + EFI_IMAGE_DATA_DIRECTORY DataDirectory[2]; ///< Only base relocation and debug directory. +} EFI_TE_IMAGE_HEADER; + + +#define EFI_TE_IMAGE_HEADER_SIGNATURE SIGNATURE_16('V', 'Z') + +// +// Data directory indexes in our TE image header +// +#define EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC 0 +#define EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG 1 + + +/// +/// Union of PE32, PE32+, and TE headers. +/// +typedef union { + EFI_IMAGE_NT_HEADERS_COMMON_HDR PeCommon; + EFI_IMAGE_NT_HEADERS32 Pe32; + EFI_IMAGE_NT_HEADERS64 Pe32Plus; + EFI_TE_IMAGE_HEADER Te; +} EFI_IMAGE_OPTIONAL_HEADER_UNION; + +#endif // PE_COFF_IMAGE2_H_ diff --git a/MdePkg/Include/Library/PeCoffExtraActionLib.h b/MdePkg/Include/Library/PeCoffExtraActionLib.h index efe5133922..8950f1a604 100644 --- a/MdePkg/Include/Library/PeCoffExtraActionLib.h +++ b/MdePkg/Include/Library/PeCoffExtraActionLib.h @@ -1,3 +1,5 @@ +#ifndef DISABLE_NEW_DEPRECATED_INTERFACES + /** @file Provides services to perform additional actions when a PE/COFF image is loaded or unloaded. This is useful for environment where symbols need to be loaded @@ -45,3 +47,5 @@ PeCoffLoaderUnloadImageExtraAction ( ); #endif + +#endif // DISABLE_NEW_DEPRECATED_INTERFACES diff --git a/MdePkg/Include/Library/PeCoffLib.h b/MdePkg/Include/Library/PeCoffLib.h index 74cceb37bf..f644fdeddc 100644 --- a/MdePkg/Include/Library/PeCoffLib.h +++ b/MdePkg/Include/Library/PeCoffLib.h @@ -1,3 +1,5 @@ +#ifndef DISABLE_NEW_DEPRECATED_INTERFACES + /** @file Provides services to load and relocate a PE/COFF image. @@ -76,127 +78,127 @@ typedef struct { /// /// Set by PeCoffLoaderGetImageInfo() to the ImageBase in the PE/COFF header. /// - PHYSICAL_ADDRESS ImageAddress; + PHYSICAL_ADDRESS ImageAddress; /// /// Set by PeCoffLoaderGetImageInfo() to the SizeOfImage in the PE/COFF header. /// Image size includes the size of Debug Entry if it is present. /// - UINT64 ImageSize; + UINT64 ImageSize; /// /// Is set to zero by PeCoffLoaderGetImageInfo(). If DestinationAddress is non-zero, /// PeCoffLoaderRelocateImage() will relocate the image using this base address. /// If the DestinationAddress is zero, the ImageAddress will be used as the base /// address of relocation. /// - PHYSICAL_ADDRESS DestinationAddress; + PHYSICAL_ADDRESS DestinationAddress; /// /// PeCoffLoaderLoadImage() sets EntryPoint to to the entry point of the PE/COFF image. /// - PHYSICAL_ADDRESS EntryPoint; + PHYSICAL_ADDRESS EntryPoint; /// /// Passed in by the caller to PeCoffLoaderGetImageInfo() and PeCoffLoaderLoadImage() /// to abstract accessing the image from the library. /// - PE_COFF_LOADER_READ_FILE ImageRead; + PE_COFF_LOADER_READ_FILE ImageRead; /// /// Used as the FileHandle passed into the ImageRead function when it's called. /// - VOID *Handle; + VOID *Handle; /// /// Caller allocated buffer of size FixupDataSize that can be optionally allocated /// prior to calling PeCoffLoaderRelocateImage(). /// This buffer is filled with the information used to fix up the image. /// The fixups have been applied to the image and this entry is just for information. /// - VOID *FixupData; + VOID *FixupData; /// /// Set by PeCoffLoaderGetImageInfo() to the Section Alignment in the PE/COFF header. /// If the image is a TE image, then this field is set to 0. /// - UINT32 SectionAlignment; + UINT32 SectionAlignment; /// /// Set by PeCoffLoaderGetImageInfo() to offset to the PE/COFF header. /// If the PE/COFF image does not start with a DOS header, this value is zero. /// Otherwise, it's the offset to the PE/COFF header. /// - UINT32 PeCoffHeaderOffset; + UINT32 PeCoffHeaderOffset; /// /// Set by PeCoffLoaderGetImageInfo() to the Relative Virtual Address of the debug directory, /// if it exists in the image /// - UINT32 DebugDirectoryEntryRva; + UINT32 DebugDirectoryEntryRva; /// /// Set by PeCoffLoaderLoadImage() to CodeView area of the PE/COFF Debug directory. /// - VOID *CodeView; + VOID *CodeView; /// /// Set by PeCoffLoaderLoadImage() to point to the PDB entry contained in the CodeView area. /// The PdbPointer points to the filename of the PDB file used for source-level debug of /// the image by a debugger. /// - CHAR8 *PdbPointer; + CHAR8 *PdbPointer; /// /// Is set by PeCoffLoaderGetImageInfo() to the Section Alignment in the PE/COFF header. /// - UINTN SizeOfHeaders; + UINTN SizeOfHeaders; /// /// Not used by this library class. Other library classes that layer on top of this library /// class fill in this value as part of their GetImageInfo call. /// This allows the caller of the library to know what type of memory needs to be allocated /// to load and relocate the image. /// - UINT32 ImageCodeMemoryType; + UINT32 ImageCodeMemoryType; /// /// Not used by this library class. Other library classes that layer on top of this library /// class fill in this value as part of their GetImageInfo call. /// This allows the caller of the library to know what type of memory needs to be allocated /// to load and relocate the image. /// - UINT32 ImageDataMemoryType; + UINT32 ImageDataMemoryType; /// /// Set by any of the library functions if they encounter an error. /// - UINT32 ImageError; + UINT32 ImageError; /// /// Set by PeCoffLoaderLoadImage() to indicate the size of FixupData that the caller must /// allocate before calling PeCoffLoaderRelocateImage(). /// - UINTN FixupDataSize; + UINTN FixupDataSize; /// /// Set by PeCoffLoaderGetImageInfo() to the machine type stored in the PE/COFF header. /// - UINT16 Machine; + UINT16 Machine; /// /// Set by PeCoffLoaderGetImageInfo() to the subsystem type stored in the PE/COFF header. /// - UINT16 ImageType; + UINT16 ImageType; /// /// Set by PeCoffLoaderGetImageInfo() to the DLL flags stored in the PE/COFF header and /// in the DllCharacteristicsEx debug table. /// - UINT16 DllCharacteristics; - UINT32 DllCharacteristicsEx; + UINT16 DllCharacteristics; + UINT32 DllCharacteristicsEx; /// /// Set by PeCoffLoaderGetImageInfo() to TRUE if the PE/COFF image does not contain /// relocation information. /// - BOOLEAN RelocationsStripped; + BOOLEAN RelocationsStripped; /// /// Set by PeCoffLoaderGetImageInfo() to TRUE if the image is a TE image. /// For a definition of the TE Image format, see the Platform Initialization Pre-EFI /// Initialization Core Interface Specification. /// - BOOLEAN IsTeImage; + BOOLEAN IsTeImage; /// /// Set by PeCoffLoaderLoadImage() to the HII resource offset /// if the image contains a custom PE/COFF resource with the type 'HII'. /// Otherwise, the entry remains to be 0. /// - PHYSICAL_ADDRESS HiiResourceData; + PHYSICAL_ADDRESS HiiResourceData; /// /// Private storage for implementation specific data. /// - UINT64 Context; + UINT64 Context; } PE_COFF_LOADER_IMAGE_CONTEXT; /** @@ -302,6 +304,7 @@ PeCoffLoaderLoadImage ( IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext ); + /** Reads contents of a PE/COFF image from a buffer in system memory. @@ -328,12 +331,13 @@ PeCoffLoaderLoadImage ( RETURN_STATUS EFIAPI PeCoffLoaderImageReadFromMemory ( - IN VOID *FileHandle, - IN UINTN FileOffset, - IN OUT UINTN *ReadSize, - OUT VOID *Buffer + IN VOID *FileHandle, + IN UINTN FileOffset, + IN OUT UINTN *ReadSize, + OUT VOID *Buffer ); + /** Reapply fixups on a fixed up PE32/PE32+ image to allow virtual calling at EFI runtime. @@ -359,11 +363,11 @@ PeCoffLoaderImageReadFromMemory ( **/ VOID EFIAPI -PeCoffLoaderRelocateImageForRuntime ( - IN PHYSICAL_ADDRESS ImageBase, - IN PHYSICAL_ADDRESS VirtImageBase, - IN UINTN ImageSize, - IN VOID *RelocationData +PeCoffLoaderRuntimeRelocateImage ( + IN PHYSICAL_ADDRESS ImageBase, + IN PHYSICAL_ADDRESS VirtImageBase, + IN UINTN ImageSize, + IN VOID *RelocationData ); /** @@ -387,5 +391,6 @@ EFIAPI PeCoffLoaderUnloadImage ( IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext ); - #endif + +#endif // DISABLE_NEW_DEPRECATED_INTERFACES diff --git a/MdePkg/Include/Library/PeCoffLib2.h b/MdePkg/Include/Library/PeCoffLib2.h new file mode 100644 index 0000000000..0985a0bc1e --- /dev/null +++ b/MdePkg/Include/Library/PeCoffLib2.h @@ -0,0 +1,597 @@ +/** @file + Provides APIs to inspect, load, and relocate PE/COFF Images. + + No implementation of this library may use global variable pointers, as this + may cause the emission of Image relocations for this address. This is + incompatible with the concept of Image self-relocation, where the Image is + loaded in a similar fashion to XIP Images into the memory at an address + unknown at compile-time. As such, Image relocation must be safe to perform + without any Image relocations applied earlier. + + Copyright (c) 2020 - 2021, Marvin Häuser. All rights reserved.
+ Copyright (c) 2020, Vitaly Cheptsov. All rights reserved.
+ Copyright (c) 2020, ISP RAS. All rights reserved.
+ + SPDX-License-Identifier: BSD-3-Clause +**/ + +#ifndef PE_COFF_LIB2_H_ +#define PE_COFF_LIB2_H_ + +#include + +#include + +// FIXME: Where to put this? +// +// PcdImageLoaderAlignmentPolicy bits. +// + +/// +/// If set, unaligned Image sections are permitted. +/// +#define PCD_ALIGNMENT_POLICY_CONTIGUOUS_SECTIONS BIT0 +/// +/// If set, unaligned Image Relocation Block sizes are permitted. +/// +#define PCD_ALIGNMENT_POLICY_RELOCATION_BLOCK_SIZES BIT1 +/// +/// If set, unaligned Image certificate sizes are permitted. +/// +#define PCD_ALIGNMENT_POLICY_CERTIFICATE_SIZES BIT2 + +// FIXME: Rework docs to consider Inplace dependencies + +/** + Returns whether the Image targets the UEFI Subsystem. + + @param[in] Subsystem The Subsystem value from the Image Headers. +**/ +#define IMAGE_IS_EFI_SUBYSYSTEM(Subsystem) \ + ((Subsystem) >= EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION && \ + (Subsystem) <= EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER) + +/// +/// Image type enumeration for Image format identification from the context. +/// +typedef enum { + PeCoffLoaderTypeTe, + PeCoffLoaderTypePe32, + PeCoffLoaderTypePe32Plus, + PeCoffLoaderTypeMax +} PE_COFF_LOADER_IMAGE_TYPE; + +/// +/// Image context structure used for abstraction and bookkeeping. +/// This structure is publicly exposed for memory allocation reasons and must +/// not be accessed directly outside of the library implementation. +/// +typedef struct { + /// + /// The preferred load address of the Image. + /// + UINT64 ImageBase; + /// + /// A pointer to the Image raw file buffer. + /// + CONST VOID *FileBuffer; + /// + /// The size, in Bytes, of FileBuffer. + /// + UINT32 FileSize; + /// + /// A pointer to the loaded Image destination. + /// + VOID *ImageBuffer; + /// + /// The offset of the Section Headers from the beginning of the raw file. + /// + UINT32 SectionsOffset; + /// + /// The number of Sections in the Image. + /// + UINT16 NumberOfSections; + /// + /// The size, in Bytes, required to load the Image. + /// + UINT32 SizeOfImage; + /// + /// The alignment, in Bytes, of Image Sections virtual addresses. + /// + UINT32 SectionAlignment; + /// + /// The offset of the Image Header from the beginning of the raw file. + /// + UINT32 ExeHdrOffset; + /// + /// The combined size, in Bytes, of all Image Headers. + /// + UINT32 SizeOfHeaders; + /// + /// The RVA of the Image entry point. + /// + UINT32 AddressOfEntryPoint; + /// + /// Indicates whether relocation information has been stripped from the Image. + /// + BOOLEAN RelocsStripped; + /// + /// The file format of the Image raw file, refer to PE_COFF_LOADER_IMAGE_TYPE. + /// + UINT8 ImageType; + /// + /// The Subsystem value from the Image Header. + /// + UINT16 Subsystem; + /// + /// The Machine value from the Image Header. + /// + UINT16 Machine; + /// + /// The size, in Bytes, stripped from the beginning of the Image raw file + /// during TE file generation. Always 0 for PE Images. + /// + UINT16 TeStrippedOffset; + /// + /// The RVA of the Relocation Directory. + /// + UINT32 RelocDirRva; + /// + /// The size, in Bytes, of the Relocation Directory. + /// + UINT32 RelocDirSize; + /// + /// The RVA of the Security Directory. + /// + UINT32 SecDirOffset; + /// + /// The size, in Bytes, of the Security Directory. + /// + UINT32 SecDirSize; +} PE_COFF_LOADER_IMAGE_CONTEXT; + +/// +/// Image runtime context used to relocate the Image during runtime. +/// +typedef struct PE_COFF_LOADER_RUNTIME_CONTEXT_ PE_COFF_LOADER_RUNTIME_CONTEXT; + +/** + Adds the digest of Data to HashContext. This function can be called multiple + times to compute the digest of discontinuous data. + + @param[in,out] HashContext The context of the current hash. + @param[in] Data The data to be hashed. + @param[in] DataSize The size, in Bytes, of Data. + + @returns Whether hashing has been successful. +**/ +typedef +BOOLEAN +(EFIAPI *PE_COFF_LOADER_HASH_UPDATE)( + IN OUT VOID *HashContext, + IN CONST VOID *Data, + IN UINTN DataSize + ); + +/** + Verify the TE, PE32, or PE32+ Image and initialise Context. + + Used offsets and ranges must be aligned and in the bounds of the raw file. + Image Section Headers and basic Relocation information must be well-formed. + + FileBuffer must remain valid for the entire lifetime of Context. + + @param[out] Context The context describing the Image. + @param[in] FileBuffer The file data to parse as TE or PE Image. + @param[in] FileSize The size, in Bytes, of FileBuffer. + + @retval RETURN_SUCCESS The Image context has been initialised successfully. + @retval other The file data is malformed. +**/ +RETURN_STATUS +PeCoffInitializeContext ( + OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context, + IN CONST VOID *FileBuffer, + IN UINT32 FileSize + ); + +/** + Hashes the Image using the Authenticode (PE/COFF Specification 8.1 Appendix A) + algorithm. + + @param[in,out] Context The context describing the Image. Must have been + initialised by PeCoffInitializeContext(). + @param[in,out] HashContext The context of the current hash. Must have been + initialised for usage with the HashUpdate + function. + @param[in] HashUpdate The data hashing function. + + @returns Whether hashing has been successful. +**/ +BOOLEAN +PeCoffHashImageAuthenticode ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context, + IN OUT VOID *HashContext, + IN PE_COFF_LOADER_HASH_UPDATE HashUpdate + ); + +/** + Load the Image into the destination memory space. + + @param[in,out] Context The context describing the Image. Must have + been initialised by PeCoffInitializeContext(). + @param[out] Destination The Image destination memory. Must be + allocated from page memory. + @param[in] DestinationSize The size, in Bytes, of Destination. Must be + sufficent to load the Image with regards to + its Image section alignment. + + @retval RETURN_SUCCESS The Image was loaded successfully. + @retval other The Image could not be loaded successfully. +**/ +RETURN_STATUS +PeCoffLoadImage ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context, + OUT VOID *Destination, + IN UINT32 DestinationSize + ); + +// FIXME: Docs +BOOLEAN +PeCoffImageIsInplace ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context + ); + +/** + Equivalent to the PeCoffLoadImage() function for inplace-loading. Ensures that + all important raw file offsets match the respective RVAs. + + @param[in,out] Context The context describing the Image. Must have been + initialised by PeCoffInitializeContext(). + + @retval RETURN_SUCCESS The Image has been inplace-loaded successfully. + @retval other The Image is not suitable for inplace-loading. +**/ +RETURN_STATUS +PeCoffLoadImageInplace ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context + ); + +// FIXME: Docs +RETURN_STATUS +PeCoffRelocateImageInplace ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context + ); + +/** + Retrieves the size required to bookkeep Image runtime relocation information. + + May only be called when PeCoffGetRelocsStripped() returns FALSE. + + @param[in,out] Context The context describing the Image. Must have been + loaded by PeCoffLoadImage(). + @param[out] Size On output, the size, in Bytes, required for the + bookkeeping buffer. + + @retval RETURN_SUCCESS The Image runtime context size for the Image was + retrieved successfully. + @retval other The Image runtime context size for the Image could not + be retrieved successfully. +**/ +RETURN_STATUS +PeCoffLoaderGetRuntimeContextSize ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context, + OUT UINT32 *Size + ); + +/** + Relocate the Image for boot-time usage. + + May only be called when PeCoffGetRelocsStripped() returns FALSE, or with + BaseAddress == PeCoffGetImageBase(). + + @param[in,out] Context The context describing the Image. Must have + been loaded by PeCoffLoadImage(). + @param[in] BaseAddress The address to relocate the Image to. + @param[out] RuntimeContext If not NULL, on output, a bookkeeping data + required for Image runtime relocation. + @param[in] RuntimeContextSize The size, in Bytes, of RuntimeContext. Must + be at least as big as the size returned by + PeCoffLoaderGetRuntimeContextSize(). + + @retval RETURN_SUCCESS The Image has been relocated successfully. + @retval other The Image Relocation Directory is malformed. +**/ +RETURN_STATUS +PeCoffRelocateImage ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context, + IN UINT64 BaseAddress, + OUT PE_COFF_LOADER_RUNTIME_CONTEXT *RuntimeContext OPTIONAL, + IN UINT32 RuntimeContextSize + ); + +/** + Relocate Image for Runtime usage. + + May only be called when PeCoffGetRelocsStripped() returns FALSE, or with + BaseAddress == PeCoffGetImageBase(). + + @param[in,out] Image The Image destination memory. Must have been + relocated by PeCoffRelocateImage(). + @param[in] ImageSize The size, in Bytes, of Image. + @param[in] BaseAddress The address to relocate the Image to. + @param[in] RuntimeContext The Relocation context obtained by + PeCoffRelocateImage(). + + @retval RETURN_SUCCESS The Image has been relocated successfully. + @retval other The Image could not be relocated successfully. +**/ +RETURN_STATUS +PeCoffRuntimeRelocateImage ( + IN OUT VOID *Image, + IN UINT32 ImageSize, + IN UINT64 BaseAddress, + IN CONST PE_COFF_LOADER_RUNTIME_CONTEXT *RuntimeContext + ); + +/** + Discards optional Image Sections to disguise sensitive data. + + This may destruct the Image Relocation Directory and as such, no function that + performs Image relocation may be called after this function has been invoked. + + @param[in,out] Context The context describing the Image. Must have been + loaded by PeCoffLoadImage(). +**/ +VOID +PeCoffDiscardSections ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context + ); + +/** + Retrieves the Image PDB path. + + @param[in,out] Context The context describing the Image. Must have been + initialised by PeCoffInitializeContext(). + @param[out] PdbPath On output, a pointer to the Image PDB path. + @param[out] PdbPathSize On output, the size, in Bytes, of *PdbPath. + + @retval RETURN_SUCCESS The Image PDB path was retrieved successfully. + @retval other The Image PDB path could not be retrieved + successfully. +**/ +RETURN_STATUS +PeCoffGetPdbPath ( + IN CONST PE_COFF_LOADER_IMAGE_CONTEXT *Context, + OUT CONST CHAR8 **PdbPath, + OUT UINT32 *PdbPathSize + ); + +/** + Retrieves the first certificate from the Image Certificate Directory. + + @param[in,out] Context The context describing the Image. Must have been + initialised by PeCoffInitializeContext(). + @param[out] Certificate On output, the first certificate of the Image. + + @retval RETURN_SUCCESS The certificate has been retrieved successfully. + @retval RETURN_NOT_FOUND There is no such certificate. + @retval other The Image Certificate Directory is malformed. +**/ +RETURN_STATUS +PeCoffGetFirstCertificate ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context, + OUT CONST WIN_CERTIFICATE **Certificate + ); + +/** + Retrieves the next certificate from the Image Certificate Directory. + + @param[in,out] Context The context describing the Image. Must have been + initialised by PeCoffInitializeContext(). + @param[out] Certificate On input, the current certificate of the Image. + Must have been retrieved by + PeCoffGetFirstCertificate(). + On output, the next certificate of the Image. + + @retval RETURN_SUCCESS The certificate has been retrieved successfully. + @retval RETURN_NOT_FOUND There is no such certificate. + @retval other The Image Certificate Directory is malformed. +**/ +RETURN_STATUS +PeCoffGetNextCertificate ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context, + IN OUT CONST WIN_CERTIFICATE **Certificate + ); + +/** + Retrieves the Image Section Table. + + @param[in,out] Context The context describing the Image. Must have been + initialised by PeCoffInitializeContext(). + @param[out] Sections On output, points to the Image Section Table. + + @returns The number of sections in the Image Section Table. +**/ +UINT16 +PeCoffGetSectionTable ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context, + OUT CONST EFI_IMAGE_SECTION_HEADER **Sections + ); + +/** + Retrieves the Image HII data RVA. + + @param[in,out] Context The context describing the Image. Must have been + initialised by PeCoffInitializeContext(). + @param[out] HiiRva On output, the RVA of the HII resource data. + @param[out] HiiSize On output, the size, in Bytes, of HiiRva. + + @retval RETURN_SUCCESS The Image HII data has been retrieved successfully. + @retval RETURN_NOT_FOUND The Image HII data could not be found. + @retval other The Image Resource Directory is malformed. +**/ +RETURN_STATUS +PeCoffGetHiiDataRva ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context, + OUT UINT32 *HiiRva, + OUT UINT32 *HiiSize + ); + +/** + Retrieve the Image entry point RVA. + + @param[in,out] Context The context describing the Image. Must have been + initialised by PeCoffInitializeContext(). + + @returns The Image entry point RVA. +**/ +UINT32 +PeCoffGetAddressOfEntryPoint ( + IN CONST PE_COFF_LOADER_IMAGE_CONTEXT *Context + ); + +/** + Retrieves the Image machine type. + + @param[in,out] Context The context describing the Image. Must have been + initialised by PeCoffInitializeContext(). + + @returns The Image machine type. +**/ +UINT16 +PeCoffGetMachine ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context + ); + +/** + Retrieves the Image subsystem type. + + @param[in,out] Context The context describing the Image. Must have been + initialised by PeCoffInitializeContext(). + + @returns The Image subsystem type. +**/ +UINT16 +PeCoffGetSubsystem ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context + ); + +/** + Retrieves the Image section alignment. + + @param[in,out] Context The context describing the Image. Must have been + initialised by PeCoffInitializeContext(). + + @returns The Image section alignment. +**/ +UINT32 +PeCoffGetSectionAlignment ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context + ); + +/** + Retrieves the size, in Bytes, of the Image memory space. + + @param[in,out] Context The context describing the Image. Must have been + initialised by PeCoffInitializeContext(). + + @returns The size of the Image memory space. +**/ +UINT32 +PeCoffGetSizeOfImage ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context + ); + +/** + Retrieves the size, in Bytes, of the Image memory space for in-place loading. + + @param[in,out] Context The context describing the Image. Must have been + initialised by PeCoffInitializeContext(). + + @returns The size of the Image memory space for in-place loading. +**/ +UINT32 +PeCoffGetSizeOfImageInplace ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context + ); + +/** + Retrieves the Image preferred load address. + + @param[in,out] Context The context describing the Image. Must have been + initialised by PeCoffInitializeContext(). + + @returns The Image preferred load address. +**/ +UINT64 +PeCoffGetImageBase ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context + ); + +/** + Retrieves the size, in Bytes, of the Image Headers. + + @param[in,out] Context The context describing the Image. Must have been + initialised by PeCoffInitializeContext(). + + @returns The size of the Image Headers. +**/ +UINT32 +PeCoffGetSizeOfHeaders ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context + ); + +/** + Returns whether the Image relocations have been stripped. + + @param[in,out] Context The context describing the Image. Must have been + initialised by PeCoffInitializeContext(). + + @returns Whether the Image relocations have been stripped. +**/ +BOOLEAN +PeCoffGetRelocsStripped ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context + ); + +/** + Retrieves the Image load address PeCoffLoadImage() has loaded the Image to. + + May be called only after PeCoffLoadImage() has succeeded. + + @param[in,out] Context The context describing the Image. Must have been + initialised by PeCoffInitializeContext(). + + @returns The Image load address. +**/ +UINTN +PeCoffLoaderGetImageAddress ( + IN CONST PE_COFF_LOADER_IMAGE_CONTEXT *Context + ); + +/** + Retrieve the immediate data encoded in an ARM MOVW/MOVT instruciton pair. + + @param[in] Instructions Pointer to an ARM MOVW/MOVT insturction pair. + + @returns The Immediate address encoded in the instructions. +**/ +UINT32 +PeCoffThumbMovwMovtImmediateAddress ( + IN CONST VOID *Instructions + ); + +/** + Relocate an ARM MOVW/MOVT immediate instruction instruction pair. + + @param[in,out] Instructions Pointer to ARM MOVW/MOVT instruction pair. + @param[in] Adjust The delta to add to the addresses. +**/ +VOID +PeCoffThumbMovwMovtImmediateFixup ( + IN OUT VOID *Instructions, + IN UINT64 Adjust + ); + +#endif // PE_COFF_LIB2_H_ diff --git a/MdePkg/Include/Library/PeiServicesLib.h b/MdePkg/Include/Library/PeiServicesLib.h index 0ca032e411..3ed1fd72f7 100644 --- a/MdePkg/Include/Library/PeiServicesLib.h +++ b/MdePkg/Include/Library/PeiServicesLib.h @@ -238,6 +238,32 @@ PeiServicesFfsFindSectionData3 ( OUT UINT32 *AuthenticationStatus ); +/** + This service enables PEIMs to discover sections of a given instance and type within a valid FFS file. + + @param SectionType The value of the section type to find. + @param SectionInstance Section instance to find. + @param FileHandle A pointer to the file header that contains the set + of sections to be searched. + @param SectionData A pointer to the discovered section, if successful. + @param SectionDataSize The size of the discovered section, if successful. + @param AuthenticationStatus A pointer to the authentication status for this section. + + @retval EFI_SUCCESS The section was found. + @retval EFI_NOT_FOUND The section was not found. + +**/ +EFI_STATUS +EFIAPI +PeiServicesFfsFindSectionData4 ( + IN EFI_SECTION_TYPE SectionType, + IN UINTN SectionInstance, + IN EFI_PEI_FILE_HANDLE FileHandle, + OUT VOID **SectionData, + OUT UINT32 *SectionDataSize, + OUT UINT32 *AuthenticationStatus + ); + /** This service enables PEIMs to register the permanent memory configuration that has been initialized with the PEI Foundation. diff --git a/MdePkg/Include/Library/UefiImageExtraActionLib.h b/MdePkg/Include/Library/UefiImageExtraActionLib.h new file mode 100644 index 0000000000..4aa7193527 --- /dev/null +++ b/MdePkg/Include/Library/UefiImageExtraActionLib.h @@ -0,0 +1,47 @@ +/** @file + Provides services to perform additional actions when an UEFI image is loaded + or unloaded. This is useful for environment where symbols need to be loaded + and unloaded to support source level debugging. + + Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __UEFI_IMAGE_EXTRA_ACTION_LIB_H__ +#define __UEFI_IMAGE_EXTRA_ACTION_LIB_H__ + +#include + +/** + Performs additional actions after a UEFI image has been loaded and relocated. + + If ImageContext is NULL, then ASSERT(). + + @param ImageContext Pointer to the image context structure that describes the + UEFI image that has already been loaded and relocated. + +**/ +VOID +EFIAPI +UefiImageLoaderRelocateImageExtraAction ( + IN CONST UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext + ); + +/** + Performs additional actions just before a UEFI image is unloaded. Any resources + that were allocated by UefiImageLoaderRelocateImageExtraAction() must be freed. + + If ImageContext is NULL, then ASSERT(). + + @param ImageContext Pointer to the image context structure that describes the + UEFI image that is being unloaded. + +**/ +VOID +EFIAPI +UefiImageLoaderUnloadImageExtraAction ( + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext + ); + +#endif diff --git a/MdePkg/Include/Library/UefiImageLib.h b/MdePkg/Include/Library/UefiImageLib.h new file mode 100644 index 0000000000..b0de4b317c --- /dev/null +++ b/MdePkg/Include/Library/UefiImageLib.h @@ -0,0 +1,642 @@ +// FIXME: Docs +#ifndef UEFI_IMAGE_LIB_H_ +#define UEFI_IMAGE_LIB_H_ + +// FIXME: Work on reasonable abstraction +#ifndef UEFI_IMAGE_LOADER_IMAGE_CONTEXT + #include + + #define UEFI_IMAGE_LOADER_IMAGE_CONTEXT PE_COFF_LOADER_IMAGE_CONTEXT + #define UEFI_IMAGE_LOADER_RUNTIME_CONTEXT PE_COFF_LOADER_RUNTIME_CONTEXT +#endif + +/// +/// Image record segment that desribes the UEFI memory permission configuration +/// for one segment of the Image. +/// +typedef struct { + /// + /// The size, in Bytes, of the Image record segment. + /// + UINT32 Size; + /// + /// The UEFI memory permission attributes corresponding to this Image record + /// segment. + /// + UINT32 Attributes; +} UEFI_IMAGE_RECORD_SEGMENT; + +/// +/// The 32-bit signature that identifies a UEFI_IMAGE_RECORD structure. +/// +#define UEFI_IMAGE_RECORD_SIGNATURE SIGNATURE_32 ('U','I','I','R') + +/// +/// Image record that describes the UEFI memory permission configuration for +/// every segment of the Image. +/// +typedef struct { + /// + /// The signature of the Image record structure. Must be set to + /// UEFI_IMAGE_RECORD_SIGNATURE. + /// + UINT32 Signature; + /// + /// The number of Image records. Must be at least 1. + /// + UINT32 NumSegments; + /// + /// A link to allow insertion of the Image record into a doubly-linked list. + /// + LIST_ENTRY Link; + /// + /// The start address of the Image memory space. + /// + UINTN StartAddress; + /// + /// The end address of the Image memory space. Must be equal to StartAddress + /// plus the sum of Segments[i].Size for 0 <= i < NumSegments. + /// + UINTN EndAddress; + /// + /// The Image record segments with their corresponding memory permission + /// attributes. All Image record segments are contiguous and cover the entire + /// Image memory space. The address of an Image record segment can be + /// determined by adding the sum of all previous sizes to StartAddress. + /// + UEFI_IMAGE_RECORD_SEGMENT Segments[]; +} UEFI_IMAGE_RECORD; + +/** + Adds the digest of Data to HashContext. This function can be called multiple + times to compute the digest of discontinuous data. + + @param[in,out] HashContext The context of the current hash. + @param[in] Data The data to be hashed. + @param[in] DataSize The size, in Bytes, of Data. + + @returns Whether hashing has been successful. +**/ +typedef +BOOLEAN +(EFIAPI *UEFI_IMAGE_LOADER_HASH_UPDATE)( + IN OUT VOID *HashContext, + IN CONST VOID *Data, + IN UINTN DataSize + ); + +// FIXME: Docs +RETURN_STATUS +UefiImageInitializeContextPreHash ( + OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context, + IN CONST VOID *FileBuffer, + IN UINT32 FileSize + ); + +RETURN_STATUS +UefiImageInitializeContextPostHash ( + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context + ); + +/** + Verify the UEFI Image and initialise Context. + + Used offsets and ranges must be aligned and in the bounds of the raw file. + Image headers and basic Relocation information must be well-formed. + + FileBuffer must remain valid for the entire lifetime of Context. + + @param[out] Context The context describing the Image. + @param[in] FileBuffer The file data to parse as UEFI Image. + @param[in] FileSize The size, in Bytes, of FileBuffer. + + @retval RETURN_SUCCESS The Image context has been initialised successfully. + @retval other The file data is malformed. +**/ +RETURN_STATUS +UefiImageInitializeContext ( + OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context, + IN CONST VOID *FileBuffer, + IN UINT32 FileSize + ); + +/** + Retrieves the UefiImageLib Image format identifier. + + @param[out] Context The context describing the Image. + + @returns The UefiImageLib format identifier. +**/ +UINT8 +UefiImageGetFormat ( + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context + ); + +/** + Hashes the Image using the format's default hashing algorithm. + + @param[in,out] Context The context describing the Image. Must have been + initialised by UefiImageInitializeContext(). + @param[in,out] HashContext The context of the current hash. Must have been + initialised for usage with the HashUpdate + function. + @param[in] HashUpdate The data hashing function. + + @returns Whether hashing has been successful. +**/ +BOOLEAN +UefiImageHashImageDefault ( + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context, + IN OUT VOID *HashContext, + IN UEFI_IMAGE_LOADER_HASH_UPDATE HashUpdate + ); + +/** + Load the Image into the destination memory space. + + @param[in,out] Context The context describing the Image. Must have been + initialised by UefiImageInitializeContext(). + @param[out] Destination The Image destination memory. Must be allocated + from page memory. + @param[in] DestinationSize The size, in Bytes, of Destination. Must be at + least as large as the size returned by + UefiImageGetImageSize(). + + @retval RETURN_SUCCESS The Image was loaded successfully. + @retval other The Image could not be loaded successfully. +**/ +RETURN_STATUS +UefiImageLoadImage ( + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context, + OUT VOID *Destination, + IN UINT32 DestinationSize + ); + +// FIXME: Docs +BOOLEAN +UefiImageImageIsInplace ( + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context + ); + +/** + Equivalent to the UefiImageLoadImage() function for inplace-loading. Ensures that + all important raw file offsets match the respective RVAs. + + @param[in,out] Context The context describing the Image. Must have been + initialised by UefiImageInitializeContext(). + + @retval RETURN_SUCCESS The Image has been inplace-loaded successfully. + @retval other The Image is not suitable for inplace-loading. +**/ +RETURN_STATUS +UefiImageLoadImageInplace ( + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context + ); + +// FIXME: Docs +RETURN_STATUS +UefiImageRelocateImageInplace ( + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context + ); + +// FIXME: +RETURN_STATUS +UefiImageRelocateImageInplaceForExecution ( + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context + ); + +/** + Retrieves the size required to bookkeep Image runtime relocation information. + + May only be called when UefiImageGetRelocsStripped() returns FALSE. + + @param[in,out] Context The context describing the Image. Must have been + loaded by UefiImageLoadImage(). + @param[out] Size On output, the size, in Bytes, required for the + bookkeeping buffer. + + @retval RETURN_SUCCESS The Image runtime context size for the Image was + retrieved successfully. + @retval other The Image runtime context size for the Image could not + be retrieved successfully. +**/ +RETURN_STATUS +UefiImageLoaderGetRuntimeContextSize ( + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context, + OUT UINT32 *Size + ); + +/** + Relocate the Image for boot-time usage. + + May only be called when UefiImageGetRelocsStripped() returns FALSE, or with + BaseAddress == UefiImageGetPreferredAddress(). + + @param[in,out] Context The context describing the Image. Must have + been loaded by UefiImageLoadImage(). + @param[in] BaseAddress The address to relocate the Image to. + @param[out] RuntimeContext If not NULL, on output, a bookkeeping data + required for Image runtime relocation. + @param[in] RuntimeContextSize The size, in Bytes, of RuntimeContext. Must + be at least as big as the size returned by + UefiImageLoaderGetRuntimeContextSize(). + + @retval RETURN_SUCCESS The Image has been relocated successfully. + @retval other The Image Relocation Directory is malformed. +**/ +RETURN_STATUS +UefiImageRelocateImage ( + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context, + IN UINT64 BaseAddress, + OUT UEFI_IMAGE_LOADER_RUNTIME_CONTEXT *RuntimeContext OPTIONAL, + IN UINT32 RuntimeContextSize + ); + +/** + Load the Image into the destination memory space, relocate Image for boot-time + usage, and perform environment-specific actions required to execute code from + the Image. + + May only be called when UefiImageGetRelocsStripped() returns FALSE, or with + BaseAddress == UefiImageGetPreferredAddress(). + + @param[in,out] Context The context describing the Image. Must have + been initialised by + UefiImageInitializeContext(). + @param[out] Destination The Image destination memory. Must be + allocated from page memory. + @param[in] DestinationSize The size, in Bytes, of Destination. Must be + at least as large as the size returned by + UefiImageGetImageSize(). + @param[out] RuntimeContext If not NULL, on output, a buffer + bookkeeping data required for Image runtime + relocation. + @param[in] RuntimeContextSize The size, in Bytes, of RuntimeContext. Must + be at least as big as the size returned by + UefiImageLoaderGetRuntimeContextSize(). + + @retval RETURN_SUCCESS The Image was loaded successfully. + @retval other The Image could not be loaded successfully. +**/ +RETURN_STATUS +UefiImageLoadImageForExecution ( + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context, + OUT VOID *Destination, + IN UINT32 DestinationSize, + OUT UEFI_IMAGE_LOADER_RUNTIME_CONTEXT *RuntimeContext OPTIONAL, + IN UINT32 RuntimeContextSize + ); + +/** + Relocate Image for Runtime usage. + + May only be called when UefiImageGetRelocsStripped() returns FALSE, or with + BaseAddress == UefiImageGetPreferredAddress(). + + @param[in,out] Image The Image destination memory. Must have been + relocated by UefiImageRelocateImage(). + @param[in] ImageSize The size, in Bytes, of Image. + @param[in] BaseAddress The address to relocate the Image to. + @param[in] RuntimeContext The Relocation context obtained by + UefiImageRelocateImage(). + + @retval RETURN_SUCCESS The Image has been relocated successfully. + @retval other The Image could not be relocated successfully. +**/ +RETURN_STATUS +UefiImageRuntimeRelocateImage ( + IN OUT VOID *Image, + IN UINT32 ImageSize, + IN UINT64 BaseAddress, + IN CONST UEFI_IMAGE_LOADER_RUNTIME_CONTEXT *RuntimeContext + ); + +/** + Relocate Image for Runtime usage, and perform environment-specific actions + required to execute code from the Image. + + May only be called when UefiImageGetRelocsStripped() returns FALSE, or with + BaseAddress == UefiImageGetPreferredAddress(). + + @param[in,out] Image The Image destination memory. Must have been + relocated by UefiImageRelocateImage(). + @param[in] ImageSize The size, in Bytes, of Image. + @param[in] BaseAddress The address to relocate the Image to. + @param[in] RuntimeContext The Relocation context obtained by + UefiImageRelocateImage(). + + @retval RETURN_SUCCESS The Image has been relocated successfully. + @retval other The Image could not be relocated successfully. +**/ +RETURN_STATUS +UefiImageRuntimeRelocateImageForExecution ( + IN OUT VOID *Image, + IN UINT32 ImageSize, + IN UINT64 BaseAddress, + IN CONST UEFI_IMAGE_LOADER_RUNTIME_CONTEXT *RuntimeContext + ); + +/** + Discards optional Image segments to disguise sensitive data. + + This may destruct the Image Relocation Directory and as such, no function that + performs Image relocation may be called after this function has been invoked. + + @param[in,out] Context The context describing the Image. Must have been + loaded by UefiImageLoadImage(). +**/ +VOID +UefiImageDiscardSegments ( + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context + ); + +/** + Retrieves the Image symbols path. + + @param[in,out] Context The context describing the Image. Must have + been initialised by + UefiImageInitializeContext(). + @param[out] SymbolsPath On output, a pointer to the Image symbols + path. + @param[out] SymbolsPathSize On output, the size, in Bytes, of * + SymbolsPath. + + @retval RETURN_SUCCESS The Image symbols path was retrieved successfully. + @retval other The Image symbols path could not be retrieved + successfully. +**/ +RETURN_STATUS +UefiImageGetSymbolsPath ( + IN CONST UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context, + OUT CONST CHAR8 **SymbolsPath, + OUT UINT32 *SymbolsPathSize + ); + +/** + Retrieves the Image module name from the Image symbols path. + + @param[in,out] Context The context describing the Image. Must have + been initialised by + UefiImageInitializeContext(). + @param[out] ModuleName Buffer the Image module name is written into. + If the name exceeds ModuleNameSize, it will be + truncated. + @param[out] ModuleNameSize The size, in Bytes, of ModuleName. + + @retval RETURN_SUCCESS The Image module name was retrieved successfully. + @retval other The Image module name could not be retrieved + successfully. +**/ +RETURN_STATUS +UefiImageGetModuleNameFromSymbolsPath ( + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context, + OUT CHAR8 *ModuleName, + IN UINT32 ModuleNameSize + ); + +// FIXME: Abstract certificates somehow? +/** + Retrieves the first certificate from the Image Certificate Directory. + + @param[in,out] Context The context describing the Image. Must have been + initialised by UefiImageInitializeContext(). + @param[out] Certificate On output, the first certificate of the Image. + + @retval RETURN_SUCCESS The certificate has been retrieved successfully. + @retval RETURN_NOT_FOUND There is no such certificate. + @retval other The Image Certificate Directory is malformed. +**/ +RETURN_STATUS +UefiImageGetFirstCertificate ( + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context, + OUT CONST WIN_CERTIFICATE **Certificate + ); + +/** + Retrieves the next certificate from the Image Certificate Directory. + + @param[in,out] Context The context describing the Image. Must have been + initialised by UefiImageInitializeContext(). + @param[out] Certificate On input, the current certificate of the Image. + Must have been retrieved by + UefiImageGetFirstCertificate(). + On output, the next certificate of the Image. + + @retval RETURN_SUCCESS The certificate has been retrieved successfully. + @retval RETURN_NOT_FOUND There is no such certificate. + @retval other The Image Certificate Directory is malformed. +**/ +RETURN_STATUS +UefiImageGetNextCertificate ( + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context, + IN OUT CONST WIN_CERTIFICATE **Certificate + ); + +/** + Retrieves the Image HII data RVA. + + @param[in,out] Context The context describing the Image. Must have been + initialised by UefiImageInitializeContext(). + @param[out] HiiRva On output, the RVA of the HII resource data. + @param[out] HiiSize On output, the size, in Bytes, of HiiRva. + + @retval RETURN_SUCCESS The Image HII data has been retrieved successfully. + @retval RETURN_NOT_FOUND The Image HII data could not be found. + @retval other The Image Resource Directory is malformed. +**/ +RETURN_STATUS +UefiImageGetHiiDataRva ( + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context, + OUT UINT32 *HiiRva, + OUT UINT32 *HiiSize + ); + +/** + Retrieve the Image entry point RVA. + + @param[in,out] Context The context describing the Image. Must have been + initialised by UefiImageInitializeContext(). + + @returns The Image entry point RVA. +**/ +UINT32 +UefiImageGetEntryPointAddress ( + IN CONST UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context + ); + +/** + Retrieves the Image machine type. + + @param[in,out] Context The context describing the Image. Must have been + initialised by UefiImageInitializeContext(). + + @returns The Image machine type. +**/ +UINT16 +UefiImageGetMachine ( + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context + ); + +/** + Retrieves the Image subsystem type. + + @param[in,out] Context The context describing the Image. Must have been + initialised by UefiImageInitializeContext(). + + @returns The Image subsystem type. +**/ +UINT16 +UefiImageGetSubsystem ( + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context + ); + +/** + Retrieves the Image segment alignment. + + @param[in,out] Context The context describing the Image. Must have been + initialised by UefiImageInitializeContext(). + + @returns The Image segment alignment. +**/ +UINT32 +UefiImageGetSegmentAlignment ( + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context + ); + +/** + Retrieves the size, in Bytes, of the Image memory space. + + @param[in,out] Context The context describing the Image. Must have been + initialised by UefiImageInitializeContext(). + + @returns The size of the Image memory space. +**/ +UINT32 +UefiImageGetImageSize ( + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context + ); + +// FIXME: Docs +UINT32 +UefiImageGetImageSizeInplace ( + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context + ); + +/** + Retrieves the Image preferred load address. + + @param[in,out] Context The context describing the Image. Must have been + initialised by UefiImageInitializeContext(). + + @returns The Image preferred load address. +**/ +UINT64 +UefiImageGetPreferredAddress ( + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context + ); + +/** + Returns whether the Image relocations have been stripped. + + @param[in,out] Context The context describing the Image. Must have been + initialised by UefiImageInitializeContext(). + + @returns Whether the Image relocations have been stripped. +**/ +BOOLEAN +UefiImageGetRelocsStripped ( + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context + ); + +/** + Retrieves the Image load address UefiImageLoadImage() has loaded the Image to. + + May be called only after UefiImageLoadImage() has succeeded. + + @param[in,out] Context The context describing the Image. Must have been + initialised by UefiImageInitializeContext(). + + @returns The Image load address. +**/ +UINTN +UefiImageLoaderGetImageAddress ( + IN CONST UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context + ); + +/** + Retrieve the Image entry point address. + + May be called only after UefiImageLoadImage() has succeeded. + + @param[in,out] Context The context describing the Image. Must have been + initialised by UefiImageInitializeContext(). + + @returns The Image entry point addres. +**/ +UINTN +UefiImageLoaderGetImageEntryPoint ( + IN CONST UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context + ); + +/** + Constructs an Image record from the Image. Any headers, gaps, or trailers are + described as read-only data. + + May be called only after UefiImageLoadImage() has succeeded. + + @param[in,out] Context The context describing the Image. Must have been + initialised by UefiImageInitializeContext(). + + @retval NULL The Image record could not constructed successfully. + @retval other The Image record was constructed successfully and is returned. + It is allocated using the AllocatePool() API and is + caller-owned as soon as this function returns. +**/ +UEFI_IMAGE_RECORD * +UefiImageLoaderGetImageRecord ( + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context + ); + +// FIXME: Docs +RETURN_STATUS +UefiImageDebugLocateImage ( + OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context, + IN UINTN Address + ); + +/** + Retrieve the Image fixed loading address. + + This function is only guaranteed to function correctly if the Image was built + by a tool with this feature enabled. + + @param[in,out] Context The context describing the Image. Must have been + initialised by UefiImageInitializeContext(). + @param[out] Address On output, the fixed loading address of the Image. + *Address is guaranteed to by aligned by the Image + segment alignment, and thus the size returned by + UefiImageGetImageSize is sufficient to hold the + Image. + + @retval RETURN_SUCCESS The Image has a fixed loading address. + @retval RETURN_NOT_FOUND The Image does not have a fixed loading address. + @retval RETURN_UNSUPPORTED The Image fixed loading address is unaligned. +**/ +RETURN_STATUS +UefiImageGetFixedAddress ( + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context, + OUT UINT64 *Address + ); + +// FIXME: Docs +VOID +UefiImageDebugPrintSegments ( + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context + ); + +VOID +UefiImageDebugPrintImageRecord ( + IN CONST UEFI_IMAGE_RECORD *ImageRecord + ); + +#endif // UEFI_IMAGE_LIB_H_ diff --git a/MdePkg/Include/Pi/PiPeiCis.h b/MdePkg/Include/Pi/PiPeiCis.h index 69eec2c473..be66e5dc72 100644 --- a/MdePkg/Include/Pi/PiPeiCis.h +++ b/MdePkg/Include/Pi/PiPeiCis.h @@ -419,6 +419,40 @@ EFI_STATUS OUT UINT32 *AuthenticationStatus ); +/** + Searches for the next matching section within the specified file. + + This service enables PEI modules to discover the section of a given type within a valid file. + This service will search within encapsulation sections (compression and GUIDed) as well. It will + search inside of a GUIDed section or a compressed section, but may not, for example, search a + GUIDed section inside a GUIDes section. + This service will not search within compression sections or GUIDed sections that require + extraction if memory is not present. + + @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation. + @param SectionType The value of the section type to find. + @param SectionInstance Section instance to find. + @param FileHandle Handle of the firmware file to search. + @param SectionData A pointer to the discovered section, if successful. + @param SectionDataSize The size of the discovered section, if successful. + @param AuthenticationStatus A pointer to the authentication status for this section. + + @retval EFI_SUCCESS The section was found. + @retval EFI_NOT_FOUND The section was not found. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PEI_FFS_FIND_SECTION_DATA4)( + IN CONST EFI_PEI_SERVICES **PeiServices, + IN EFI_SECTION_TYPE SectionType, + IN UINTN SectionInstance, + IN EFI_PEI_FILE_HANDLE FileHandle, + OUT VOID **SectionData, + OUT UINT32 *SectionDataSize, + OUT UINT32 *AuthenticationStatus + ); + /** This function registers the found memory configuration with the PEI Foundation. @@ -944,6 +978,7 @@ struct _EFI_PEI_SERVICES { EFI_PEI_FFS_GET_FILE_INFO2 FfsGetFileInfo2; EFI_PEI_RESET2_SYSTEM ResetSystem2; EFI_PEI_FREE_PAGES FreePages; + EFI_PEI_FFS_FIND_SECTION_DATA4 FindSectionData4; }; /// diff --git a/MdePkg/Include/Ppi/FirmwareVolume.h b/MdePkg/Include/Ppi/FirmwareVolume.h index e789970edb..0b7a2727c6 100644 --- a/MdePkg/Include/Ppi/FirmwareVolume.h +++ b/MdePkg/Include/Ppi/FirmwareVolume.h @@ -255,8 +255,43 @@ EFI_STATUS OUT UINT32 *AuthenticationStatus ); +/** + Find the next matching section in the firmware file. + + This service enables PEI modules to discover sections + of a given instance and type within a valid file. + + @param This Points to this instance of the + EFI_PEI_FIRMWARE_VOLUME_PPI. + @param SearchType A filter to find only sections of this + type. + @param SearchInstance A filter to find the specific instance + of sections. + @param FileHandle Handle of firmware file in which to + search. + @param SectionData Updated upon return to point to the + section found. + @param AuthenticationStatus Updated upon return to point to the + authentication status for this section. + + @retval EFI_SUCCESS Section was found. + @retval EFI_NOT_FOUND Section of the specified type was not + found. SectionData contains NULL. +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PEI_FV_FIND_SECTION3)( + IN CONST EFI_PEI_FIRMWARE_VOLUME_PPI *This, + IN EFI_SECTION_TYPE SearchType, + IN UINTN SearchInstance, + IN EFI_PEI_FILE_HANDLE FileHandle, + OUT VOID **SectionData, + OUT UINT32 *SectionDataSize, + OUT UINT32 *AuthenticationStatus +); + #define EFI_PEI_FIRMWARE_VOLUME_PPI_SIGNATURE SIGNATURE_32 ('P', 'F', 'V', 'P') -#define EFI_PEI_FIRMWARE_VOLUME_PPI_REVISION 0x00010030 +#define EFI_PEI_FIRMWARE_VOLUME_PPI_REVISION 0x00010031 /// /// This PPI provides functions for accessing a memory-mapped firmware volume of a specific format. @@ -278,6 +313,7 @@ struct _EFI_PEI_FIRMWARE_VOLUME_PPI { /// Revision for further extension. /// UINT32 Revision; + EFI_PEI_FV_FIND_SECTION3 FindSectionByType3; }; extern EFI_GUID gEfiPeiFirmwareVolumePpiGuid; diff --git a/MdePkg/Include/Protocol/DebugSupport.h b/MdePkg/Include/Protocol/DebugSupport.h index 06f99ba7f7..005f89b85c 100644 --- a/MdePkg/Include/Protocol/DebugSupport.h +++ b/MdePkg/Include/Protocol/DebugSupport.h @@ -16,8 +16,6 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #ifndef __DEBUG_SUPPORT_H__ #define __DEBUG_SUPPORT_H__ -#include - typedef struct _EFI_DEBUG_SUPPORT_PROTOCOL EFI_DEBUG_SUPPORT_PROTOCOL; /// @@ -834,12 +832,12 @@ VOID /// Machine type definition /// typedef enum { - IsaIa32 = IMAGE_FILE_MACHINE_I386, ///< 0x014C - IsaX64 = IMAGE_FILE_MACHINE_X64, ///< 0x8664 - IsaIpf = IMAGE_FILE_MACHINE_IA64, ///< 0x0200 - IsaEbc = IMAGE_FILE_MACHINE_EBC, ///< 0x0EBC - IsaArm = IMAGE_FILE_MACHINE_ARMTHUMB_MIXED, ///< 0x01c2 - IsaAArch64 = IMAGE_FILE_MACHINE_ARM64 ///< 0xAA64 + IsaIa32 = EFI_IMAGE_MACHINE_IA32, ///< 0x014C + IsaX64 = EFI_IMAGE_MACHINE_X64, ///< 0x8664 + IsaIpf = EFI_IMAGE_MACHINE_IA64, ///< 0x0200 + IsaEbc = EFI_IMAGE_MACHINE_EBC, ///< 0x0EBC + IsaArm = EFI_IMAGE_MACHINE_ARMTHUMB_MIXED, ///< 0x01c2 + IsaAArch64 = EFI_IMAGE_MACHINE_AARCH64 ///< 0xAA64 } EFI_INSTRUCTION_SET_ARCHITECTURE; // diff --git a/MdePkg/Library/BasePeCoffLib/BasePeCoff.c b/MdePkg/Library/BasePeCoffLib/BasePeCoff.c index 86ff2e769b..b73b405a6d 100644 --- a/MdePkg/Library/BasePeCoffLib/BasePeCoff.c +++ b/MdePkg/Library/BasePeCoffLib/BasePeCoff.c @@ -1739,7 +1739,7 @@ PeCoffLoaderLoadImage ( **/ VOID EFIAPI -PeCoffLoaderRelocateImageForRuntime ( +PeCoffLoaderRuntimeRelocateImage ( IN PHYSICAL_ADDRESS ImageBase, IN PHYSICAL_ADDRESS VirtImageBase, IN UINTN ImageSize, diff --git a/MdePkg/Library/BasePeCoffLib/BasePeCoffLibInternals.h b/MdePkg/Library/BasePeCoffLib/BasePeCoffLibInternals.h index aa86a54850..3ee56e0e5f 100644 --- a/MdePkg/Library/BasePeCoffLib/BasePeCoffLibInternals.h +++ b/MdePkg/Library/BasePeCoffLib/BasePeCoffLibInternals.h @@ -20,12 +20,13 @@ // // Macro definitions for RISC-V architecture. // -#define RV_X(x, s, n) (((x) >> (s)) & ((1<<(n))-1)) -#define RISCV_IMM_BITS 12 -#define RISCV_IMM_REACH (1LL<> (s)) & ((1<<(n))-1)) +#define RISCV_IMM_BITS 12 +#define RISCV_IMM_REACH (1LL< + Copyright (c) 2020, Vitaly Cheptsov. All rights reserved.
+ Copyright (c) 2020, ISP RAS. All rights reserved.
+ SPDX-License-Identifier: BSD-3-Clause +**/ + +#ifndef PE_COFF_LOAD_H_ +#define PE_COFF_LOAD_H_ + +/** + Load the Image into the destination memory space. + + @param[in] Context The context describing the Image. Must have been + initialised by PeCoffInitializeContext(). + @param[out] Destination The Image destination memory. Must be allocated + from page memory. + @param[in] DestinationSize The size, in bytes, of Destination. + Must be at least + Context->SizeOfImage + + Context->SizeOfImageDebugAdd. If the Section + Alignment exceeds 4 KB, must be at least + Context->SizeOfImage + + Context->SizeOfImageDebugAdd + Context->SectionAlignment. + + @retval RETURN_SUCCESS The Image was loaded successfully. + @retval other The Image could not be loaded successfully. +**/ +RETURN_STATUS +PeCoffLoadImage ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context, + OUT VOID *Destination, + IN UINT32 DestinationSize + ); + +/** + Discards optional Image Sections to disguise sensitive data. + + @param[in] Context The context describing the Image. Must have been loaded by + PeCoffLoadImage(). +**/ +VOID +PeCoffDiscardSections ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context + ); + +#endif // PE_COFF_LOAD_H_ diff --git a/MdePkg/Library/BasePeCoffLib2/BasePeCoffLib2.inf b/MdePkg/Library/BasePeCoffLib2/BasePeCoffLib2.inf new file mode 100644 index 0000000000..4d375e2506 --- /dev/null +++ b/MdePkg/Library/BasePeCoffLib2/BasePeCoffLib2.inf @@ -0,0 +1,47 @@ +## @file +# PE/COFF Loader Library implementation. +# +# Copyright (c) 2020 - 2021, Marvin Häuser. All rights reserved.
+# Copyright (c) 2020, Vitaly Cheptsov. All rights reserved.
+# Copyright (c) 2020, ISP RAS. All rights reserved.
+# +# SPDX-License-Identifier: BSD-3-Clause +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = BasePeCoffLib2 + FILE_GUID = 454A346E-3064-464E-8285-99DF1E220E0F + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = PeCoffLib2 + +[Sources] + PeCoffDebug.c + PeCoffHash.c + PeCoffHii.c + PeCoffInfo.c + PeCoffInit.c + PeCoffLoad.c + PeCoffRelocate.c + +[Packages] + MdePkg/MdePkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + BaseOverflowLib + DebugLib + MemoryAllocationLib + +[FixedPcd] + gEfiMdePkgTokenSpaceGuid.PcdImageLoaderRtRelocAllowTargetMismatch + gEfiMdePkgTokenSpaceGuid.PcdImageLoaderHashProhibitOverlap + gEfiMdePkgTokenSpaceGuid.PcdImageLoaderLoadHeader + gEfiMdePkgTokenSpaceGuid.PcdImageLoaderRelocTypePolicy + gEfiMdePkgTokenSpaceGuid.PcdImageLoaderAlignmentPolicy + gEfiMdePkgTokenSpaceGuid.PcdImageLoaderWXorX + gEfiMdePkgTokenSpaceGuid.PcdImageLoaderDebugSupport + gEfiMdePkgTokenSpaceGuid.PcdImageLoaderProhibitTe + gEfiMdePkgTokenSpaceGuid.PcdImageLoaderAllowMisalignedOffset diff --git a/MdePkg/Library/BasePeCoffLib2/BasePeCoffLib2Internals.h b/MdePkg/Library/BasePeCoffLib2/BasePeCoffLib2Internals.h new file mode 100644 index 0000000000..97f2d4b5c8 --- /dev/null +++ b/MdePkg/Library/BasePeCoffLib2/BasePeCoffLib2Internals.h @@ -0,0 +1,55 @@ +/** @file + Provides shared private definitions across this library. + + Copyright (c) 2020 - 2021, Marvin Häuser. All rights reserved.
+ Copyright (c) 2020, Vitaly Cheptsov. All rights reserved.
+ Copyright (c) 2020, ISP RAS. All rights reserved.
+ + SPDX-License-Identifier: BSD-3-Clause +**/ + +#ifndef BASE_PE_COFF_LIB2_INTERNALS_H_ +#define BASE_PE_COFF_LIB2_INTERNALS_H_ + +// +// PcdImageLoaderRelocTypePolicy bits. +// + +/// +/// If set, ARM Thumb Image relocations are supported. +/// +#define PCD_RELOC_TYPE_POLICY_ARM BIT0 + +/// +/// Denotes the alignment requirement for Image certificate sizes. +/// +#define IMAGE_CERTIFICATE_ALIGN 8U + +// +// The PE/COFF specification guarantees an 8 Byte alignment for certificate +// sizes. This is larger than the alignment requirement for WIN_CERTIFICATE +// implied by the UEFI ABI. ASSERT this holds. +// +STATIC_ASSERT ( + ALIGNOF (WIN_CERTIFICATE) <= IMAGE_CERTIFICATE_ALIGN, + "The PE/COFF specification guarantee does not suffice." + ); + +// +// The 4 Byte alignment guaranteed by the PE/COFF specification has been +// replaced with ALIGNOF (EFI_IMAGE_BASE_RELOCATION_BLOCK) for proof simplicity. +// This obviously was the original intention of the specification. ASSERT in +// case the equality is not given. +// +STATIC_ASSERT ( + sizeof (UINT32) == ALIGNOF (EFI_IMAGE_BASE_RELOCATION_BLOCK), + "The current model violates the PE/COFF specification" + ); + +// FIXME: +RETURN_STATUS +PeCoffLoadImageInplaceNoBase ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context + ); + +#endif // BASE_PE_COFF_LIB_INTERNALS_H_ diff --git a/MdePkg/Library/BasePeCoffLib2/Documentation.md b/MdePkg/Library/BasePeCoffLib2/Documentation.md new file mode 100644 index 0000000000..0c8ef63e07 --- /dev/null +++ b/MdePkg/Library/BasePeCoffLib2/Documentation.md @@ -0,0 +1,40 @@ +# EDK II Image Loader documentation + +**Please note that this is an early work-in-progress. Correctness and completeness are not guaranteed.** + +## 1. Image Section Table well-formedness +An Image Section Table is considered well-formed if and only if: +1. The Image Section Table is sorted by Image section RVA in ascending order. +2. All Image sections are disjoint in the Image memory space. +3. For PE/COFF Images, all Image sections are in bounds of the Image memory space defined by the Image headers. + * For TE Images, the Image memory space is implicitly defined by the Image Section Table. +4. All Image sections are in bounds of the raw file. + +Additionally, based on PCD policy values, the following constraints may be added: + +5. All Image sections are aligned by the Image section alignment. +6. The first Image section is adjacent to the aligned Image headers, or it is the start of the Image memory space. +7. All Image sections are pairwise adjacent (considering aligned size) in the Image memory space. +8. All Image sections are not executable and writable at the same time. + +### 1.2. Rationales + +|| Origin | Rationale | Known violations | +|---|---|---|---| +|1 | PE | Allows for efficient verification of constraint 2. | None | +|2 | PE | Mitigates accidental Image corruption and ensures the same deterministic Image memory space contents invariant of Image section load order. | None | +|3 | PE | Provides hardening against (otherwise potentially incorrect) assumptions regarding the Image header information. | None | +|4 | PE | Mitigates out-of-bounds accesses. | None | +|5 | PE | Ensures data is aligned at their optimal boundary and provides hardening against (otherwise potentially incorrect) assumptions regarding the Image header information. | Old Apple Mac OS X bootloaders, old iPXE OPROMs | +|6 | EDK II | Allows both the Image Headers to be or to not be loaded. Loading the Image Headers is the default behaviour for all common PE/COFF Image loaders, however it is not required, and the data may be used to more easily identify locations within the Image memory space. | See 5 | +|7 | PE | Provides hardening against unintentional gaps in the Image memory space that may be handled incorrectly. | See 5 | +|8 | EDK II | Provides hardening against accidental and malicious code modifications. The concept is well-known as W^X. | None | + +## 2. Image memory permissions +The Image memory space is protected as follows: +1. Image Headers are protected as read-only data. +2. Image sections are protected according to their defined permissions. +3. Any gaps between Image sections are protected as read-only data. +4. The Image trailer is protected as read-only data. + +Due to the explicit handling of Image Headers, gaps, and Image trailer, the full Image memory space has well-defined permissions. To embrace the W^X pattern, and to mitigate attacks (e.g. format string exploits), the tightest permissions are chosen for all Image memory permission segments. diff --git a/MdePkg/Library/BasePeCoffLib2/PeCoffDebug.c b/MdePkg/Library/BasePeCoffLib2/PeCoffDebug.c new file mode 100644 index 0000000000..8109b65f57 --- /dev/null +++ b/MdePkg/Library/BasePeCoffLib2/PeCoffDebug.c @@ -0,0 +1,264 @@ +/** @file + Implements APIs to load PE/COFF debug information. + + Copyright (c) 2020 - 2021, Marvin Häuser. All rights reserved.
+ Copyright (c) 2020, Vitaly Cheptsov. All rights reserved.
+ Copyright (c) 2020, ISP RAS. All rights reserved.
+ Portions copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.
+ Portions copyright (c) 2008 - 2010, Apple Inc. All rights reserved.
+ Portions copyright (c) 2020, Hewlett Packard Enterprise Development LP. All rights reserved.
+ + SPDX-License-Identifier: BSD-3-Clause +**/ + +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include "BasePeCoffLib2Internals.h" + +RETURN_STATUS +PeCoffGetPdbPath ( + IN CONST PE_COFF_LOADER_IMAGE_CONTEXT *Context, + OUT CONST CHAR8 **PdbPath, + OUT UINT32 *PdbPathSize + ) +{ + BOOLEAN Overflow; + + CONST EFI_IMAGE_DATA_DIRECTORY *DebugDir; + CONST EFI_TE_IMAGE_HEADER *TeHdr; + CONST EFI_IMAGE_NT_HEADERS32 *Pe32Hdr; + CONST EFI_IMAGE_NT_HEADERS64 *Pe32PlusHdr; + + CONST EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *DebugEntries; + UINT32 NumDebugEntries; + UINT32 DebugIndex; + CONST EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *CodeViewEntry; + + UINT32 DebugDirTop; + UINT32 DebugEntryFileOffset; + UINT32 DebugEntryFileOffsetTop; + + CONST CHAR8 *CodeView; + UINT32 PdbOffset; + CONST CHAR8 *PdbName; + UINT32 PdbNameSize; + + ASSERT (Context != NULL); + ASSERT (PdbPath != NULL); + ASSERT (PdbPathSize != NULL); + + if (!PcdGetBool (PcdImageLoaderDebugSupport)) { + return RETURN_NOT_FOUND; + } + // + // Retrieve the Debug Directory of the Image. + // + switch (Context->ImageType) { + case PeCoffLoaderTypeTe: + if (PcdGetBool (PcdImageLoaderProhibitTe)) { + ASSERT (FALSE); + return RETURN_UNSUPPORTED; + } + + TeHdr = (CONST EFI_TE_IMAGE_HEADER *) (CONST VOID *) ( + (CONST CHAR8 *) Context->FileBuffer + ); + + DebugDir = &TeHdr->DataDirectory[1]; + break; + + case PeCoffLoaderTypePe32: + Pe32Hdr = (CONST EFI_IMAGE_NT_HEADERS32 *) (CONST VOID *) ( + (CONST CHAR8 *) Context->FileBuffer + Context->ExeHdrOffset + ); + + if (Pe32Hdr->NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) { + return RETURN_NOT_FOUND; + } + + DebugDir = Pe32Hdr->DataDirectory + EFI_IMAGE_DIRECTORY_ENTRY_DEBUG; + break; + + case PeCoffLoaderTypePe32Plus: + Pe32PlusHdr = (CONST EFI_IMAGE_NT_HEADERS64 *) (CONST VOID *) ( + (CONST CHAR8 *) Context->FileBuffer + Context->ExeHdrOffset + ); + + if (Pe32PlusHdr->NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) { + return RETURN_NOT_FOUND; + } + + DebugDir = Pe32PlusHdr->DataDirectory + EFI_IMAGE_DIRECTORY_ENTRY_DEBUG; + break; + + default: + ASSERT (FALSE); + return RETURN_VOLUME_CORRUPTED; + } + // + // Verify the Debug Directory is not empty. + // + if (DebugDir->Size == 0) { + return RETURN_NOT_FOUND; + } + // + // Verify the Debug Directory has a well-formed size. + // + if (DebugDir->Size % sizeof (*DebugEntries) != 0) { + // + // Some Apple-made images contain a sum of EFI_IMAGE_DEBUG_DIRECTORY_ENTRY + // and EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY sizes in DebugDir size. + // Since this violates the spec and nobody but Apple has access + // to the DEBUG symbols, just ignore this debug information. + // + return RETURN_VOLUME_CORRUPTED; + } + // + // Verify the Debug Directory is in bounds of the Image buffer. + // + Overflow = BaseOverflowAddU32 ( + DebugDir->VirtualAddress, + DebugDir->Size, + &DebugDirTop + ); + if (Overflow || DebugDirTop > Context->SizeOfImage) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + // + // Verify the Debug Directory Image address is sufficiently aligned. + // + if (!IS_ALIGNED (DebugDir->VirtualAddress, ALIGNOF (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY))) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + + DebugEntries = (CONST EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *) (CONST VOID *) ( + (CONST CHAR8 *) Context->ImageBuffer + DebugDir->VirtualAddress + ); + + NumDebugEntries = DebugDir->Size / sizeof (*DebugEntries); + + for (DebugIndex = 0; DebugIndex < NumDebugEntries; ++DebugIndex) { + if (DebugEntries[DebugIndex].Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) { + break; + } + } + // + // Verify the CodeView entry has been found in the Debug Directory. + // + if (DebugIndex == NumDebugEntries) { + return RETURN_NOT_FOUND; + } + // + // Verify the CodeView entry has sufficient space for the signature. + // + CodeViewEntry = &DebugEntries[DebugIndex]; + + if (CodeViewEntry->SizeOfData < sizeof (UINT32)) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + + DebugEntryFileOffset = CodeViewEntry->FileOffset; + + if (!PcdGetBool (PcdImageLoaderProhibitTe)) { + Overflow = BaseOverflowSubU32 ( + DebugEntryFileOffset, + Context->TeStrippedOffset, + &DebugEntryFileOffset + ); + if (Overflow) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + } else { + ASSERT (Context->TeStrippedOffset == 0); + } + // + // Verify the CodeView entry is in bounds of the raw file, and the + // CodeView entry raw file offset is sufficiently aligned. + // + Overflow = BaseOverflowAddU32 ( + DebugEntryFileOffset, + CodeViewEntry->SizeOfData, + &DebugEntryFileOffsetTop + ); + if (Overflow || DebugEntryFileOffsetTop > Context->FileSize + || !IS_ALIGNED (DebugEntryFileOffset, ALIGNOF (UINT32))) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + + CodeView = (CONST CHAR8 *) Context->FileBuffer + DebugEntryFileOffset; + // + // This memory access is safe because we know that + // 1) IS_ALIGNED (DebugEntryFileOffset, ALIGNOF (UINT32)) + // 2) sizeof (UINT32) <= CodeViewEntry->SizeOfData. + // + switch (*(CONST UINT32 *) (CONST VOID *) CodeView) { + case CODEVIEW_SIGNATURE_NB10: + PdbOffset = sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY); + + STATIC_ASSERT ( + ALIGNOF (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY) <= ALIGNOF (UINT32), + "The structure may be misalignedd." + ); + break; + + case CODEVIEW_SIGNATURE_RSDS: + PdbOffset = sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY); + + STATIC_ASSERT ( + ALIGNOF (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY) <= ALIGNOF (UINT32), + "The structure may be misalignedd." + ); + break; + + case CODEVIEW_SIGNATURE_MTOC: + PdbOffset = sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY); + + STATIC_ASSERT ( + ALIGNOF (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY) <= ALIGNOF (UINT32), + "The structure may be misalignedd." + ); + break; + + default: + return RETURN_UNSUPPORTED; + } + // + // Verify the PDB path exists and is in bounds of the Image buffer. + // + Overflow = BaseOverflowSubU32 ( + CodeViewEntry->SizeOfData, + PdbOffset, + &PdbNameSize + ); + if (Overflow || PdbNameSize == 0) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + // + // Verify the PDB path is correctly terminated. + // + PdbName = CodeView + PdbOffset; + if (PdbName[PdbNameSize - 1] != 0) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + + *PdbPath = PdbName; + *PdbPathSize = PdbNameSize; + + return RETURN_SUCCESS; +} diff --git a/MdePkg/Library/BasePeCoffLib2/PeCoffHash.c b/MdePkg/Library/BasePeCoffLib2/PeCoffHash.c new file mode 100644 index 0000000000..12a9495d05 --- /dev/null +++ b/MdePkg/Library/BasePeCoffLib2/PeCoffHash.c @@ -0,0 +1,487 @@ +/** @file + Implements APIs to verify the Authenticode Signature of PE/COFF Images. + + Copyright (c) 2020 - 2021, Marvin Häuser. All rights reserved.
+ Copyright (c) 2020, Vitaly Cheptsov. All rights reserved.
+ Copyright (c) 2020, ISP RAS. All rights reserved.
+ Portions copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.
+ Portions copyright (c) 2016, Hewlett Packard Enterprise Development LP. All rights reserved.
+ + SPDX-License-Identifier: BSD-3-Clause +**/ + +#include + +#include + +#include + +#include +#include +#include +#include +#include + +#include "BasePeCoffLib2Internals.h" + +/** + Hashes the Image section data in ascending order of raw file appearance. + + @param[in] Context The context describing the Image. Must have been + initialised by PeCoffInitializeContext(). + @param[in] HashUpdate The data hashing function. + @param[in,out] HashContext The context of the current hash. + + @returns Whether hashing has been successful. +**/ +STATIC +BOOLEAN +InternalHashSections ( + IN CONST PE_COFF_LOADER_IMAGE_CONTEXT *Context, + IN OUT VOID *HashContext, + IN PE_COFF_LOADER_HASH_UPDATE HashUpdate, + IN OUT UINT32 *SumBytesHashed + ) +{ + BOOLEAN Result; + BOOLEAN Overflow; + + CONST EFI_IMAGE_SECTION_HEADER *Sections; + CONST EFI_IMAGE_SECTION_HEADER **SortedSections; + UINT16 SectionIndex; + UINT16 SectionPos; + UINT32 SectionTop; + UINT32 CurHashSize; + // + // 9. Build a temporary table of pointers to all of the section headers in the + // image. The NumberOfSections field of COFF File Header indicates how big + // the table should be. Do not include any section headers in the table + // whose SizeOfRawData field is zero. + // + SortedSections = AllocatePool ( + (UINT32) Context->NumberOfSections * sizeof (*SortedSections) + ); + if (SortedSections == NULL) { + return FALSE; + } + + Sections = (CONST EFI_IMAGE_SECTION_HEADER *) (CONST VOID *) ( + (CONST CHAR8 *) Context->FileBuffer + Context->SectionsOffset + ); + // + // 10. Using the PointerToRawData field (offset 20) in the referenced + // SectionHeader structure as a key, arrange the table's elements in + // ascending order. In other words, sort the section headers in ascending + // order according to the disk-file offset of the sections. + // + SortedSections[0] = Sections; + // + // Perform Insertion Sort to order the Sections by their raw file offset. + // + for (SectionIndex = 1; SectionIndex < Context->NumberOfSections; ++SectionIndex) { + for (SectionPos = SectionIndex; + 0 < SectionPos + && SortedSections[SectionPos - 1]->PointerToRawData > Sections[SectionIndex].PointerToRawData; + --SectionPos) { + SortedSections[SectionPos] = SortedSections[SectionPos - 1]; + } + + SortedSections[SectionPos] = Sections + SectionIndex; + } + + Result = TRUE; + SectionTop = 0; + CurHashSize = 0; + // + // 13. Repeat steps 11 and 12 for all of the sections in the sorted table. + // + ASSERT (Context->TeStrippedOffset == 0); + for (SectionIndex = 0; SectionIndex < Context->NumberOfSections; ++SectionIndex) { + // + // Verify the Image section does not overlap with the previous one if the + // policy demands it. Overlapping Sections could dramatically increase the + // hashing time. + // FIXME: Move to init, along with a trailing data policy. + // + if (PcdGetBool (PcdImageLoaderHashProhibitOverlap)) { + if (SectionTop > SortedSections[SectionIndex]->PointerToRawData) { + Result = FALSE; + break; + } + + SectionTop = SortedSections[SectionIndex]->PointerToRawData + SortedSections[SectionIndex]->SizeOfRawData; + } + // + // Skip Sections that contain no data. + // + if (SortedSections[SectionIndex]->SizeOfRawData > 0) { + // + // 11. Walk through the sorted table, load the corresponding section into + // memory, and hash the entire section. Use the SizeOfRawData field in the + // SectionHeader structure to determine the amount of data to hash. + // + Result = HashUpdate ( + HashContext, + (CONST CHAR8 *) Context->FileBuffer + SortedSections[SectionIndex]->PointerToRawData, + SortedSections[SectionIndex]->SizeOfRawData + ); + if (!Result) { + break; + } + // + // 12. Add the section’s SizeOfRawData value to SUM_OF_BYTES_HASHED. + // + // If and only if the Sections do not overlap, we know their sizes are at + // most MAX_UINT32 in sum because the file size is at most MAX_UINT32. + // + if (PcdGetBool (PcdImageLoaderHashProhibitOverlap)) { + CurHashSize += SortedSections[SectionIndex]->SizeOfRawData; + } else { + // + // Verify the hash size does not overflow. + // + Overflow = BaseOverflowAddU32 ( + CurHashSize, + SortedSections[SectionIndex]->SizeOfRawData, + &CurHashSize + ); + if (Overflow) { + Result = FALSE; + break; + } + } + } + } + + *SumBytesHashed = CurHashSize; + FreePool ((VOID *) SortedSections); + + return Result; +} + +BOOLEAN +PeCoffHashImageAuthenticode ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context, + IN OUT VOID *HashContext, + IN PE_COFF_LOADER_HASH_UPDATE HashUpdate + ) +{ + BOOLEAN Result; + BOOLEAN Overflow; + UINT32 NumberOfRvaAndSizes; + UINT32 ChecksumOffset; + UINT32 SecurityDirOffset; + UINT32 SecurityDirSize; + UINT32 CurrentOffset; + UINT32 HashSize; + CONST EFI_IMAGE_NT_HEADERS32 *Pe32; + CONST EFI_IMAGE_NT_HEADERS64 *Pe32Plus; + UINT32 SumBytesHashed; + UINT32 FileSize; + + // + // These conditions must be met by the caller prior to calling this function. + // + // 1. Load the image header into memory. + // 2. Initialize a hash algorithm context. + // + + // + // This step can be moved here because steps 1 to 5 do not modify the Image. + // + // 6. Get the Attribute Certificate Table address and size from the + // Certificate Table entry. For details, see section 5.7 of the PE/COFF + // specification. + // + // Additionally, retrieve important offsets for later steps. + // + switch (Context->ImageType) { + case PeCoffLoaderTypeTe: + if (PcdGetBool (PcdImageLoaderProhibitTe)) { + ASSERT (FALSE); + return FALSE; + } + // + // Authenticode does not define a hashing algorithm for TE Images. + // + DEBUG_RAISE (); + return FALSE; + + case PeCoffLoaderTypePe32: + Pe32 = (CONST EFI_IMAGE_NT_HEADERS32 *) (CONST VOID *) ( + (CONST CHAR8 *) Context->FileBuffer + Context->ExeHdrOffset + ); + ChecksumOffset = Context->ExeHdrOffset + (UINT32) OFFSET_OF (EFI_IMAGE_NT_HEADERS32, CheckSum); + SecurityDirOffset = Context->ExeHdrOffset + (UINT32) OFFSET_OF (EFI_IMAGE_NT_HEADERS32, DataDirectory) + (UINT32) (EFI_IMAGE_DIRECTORY_ENTRY_SECURITY * sizeof (EFI_IMAGE_DATA_DIRECTORY)); + NumberOfRvaAndSizes = Pe32->NumberOfRvaAndSizes; + // + // Retrieve the Security Directory size depending on existence. + // + if (EFI_IMAGE_DIRECTORY_ENTRY_SECURITY < NumberOfRvaAndSizes) { + SecurityDirSize = Pe32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size; + } else { + SecurityDirSize = 0; + } + + break; + + case PeCoffLoaderTypePe32Plus: + Pe32Plus = (CONST EFI_IMAGE_NT_HEADERS64 *) (CONST VOID *) ( + (CONST CHAR8 *) Context->FileBuffer + Context->ExeHdrOffset + ); + ChecksumOffset = Context->ExeHdrOffset + (UINT32) OFFSET_OF (EFI_IMAGE_NT_HEADERS64, CheckSum); + SecurityDirOffset = Context->ExeHdrOffset + (UINT32) OFFSET_OF (EFI_IMAGE_NT_HEADERS64, DataDirectory) + (UINT32) (EFI_IMAGE_DIRECTORY_ENTRY_SECURITY * sizeof (EFI_IMAGE_DATA_DIRECTORY)); + NumberOfRvaAndSizes = Pe32Plus->NumberOfRvaAndSizes; + // + // Retrieve the Security Directory size depending on existence. + // + if (EFI_IMAGE_DIRECTORY_ENTRY_SECURITY < NumberOfRvaAndSizes) { + SecurityDirSize = Pe32Plus->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size; + } else { + SecurityDirSize = 0; + } + + break; + + default: + ASSERT (FALSE); + return FALSE; + } + // + // 3. Hash the image header from its base to immediately before the start of + // the checksum address, as specified in Optional Header Windows-Specific + // Fields. + // + Result = HashUpdate (HashContext, Context->FileBuffer, ChecksumOffset); + if (!Result) { + DEBUG_RAISE (); + return FALSE; + } + // + // 4. Skip over the checksum, which is a 4-byte field. + // + CurrentOffset = ChecksumOffset + sizeof (UINT32); + // + // 5. Hash everything from the end of the checksum field to immediately before + // the start of the Certificate Table entry, as specified in Optional + // Header Data Directories. + // + if (EFI_IMAGE_DIRECTORY_ENTRY_SECURITY < NumberOfRvaAndSizes) { + HashSize = SecurityDirOffset - CurrentOffset; + Result = HashUpdate ( + HashContext, + (CONST CHAR8 *) Context->FileBuffer + CurrentOffset, + HashSize + ); + if (!Result) { + DEBUG_RAISE (); + return FALSE; + } + // + // Skip over the Security Directory. + // + CurrentOffset = SecurityDirOffset + sizeof (EFI_IMAGE_DATA_DIRECTORY); + } + // + // 7. Exclude the Certificate Table entry from the calculation and hash + // everything from the end of the Certificate Table entry to the end of + // image header, including Section Table (headers).The Certificate Table + // entry is 8 Bytes long, as specified in Optional Header Data Directories. + // + HashSize = Context->SizeOfHeaders - CurrentOffset; + Result = HashUpdate ( + HashContext, + (CONST CHAR8 *) Context->FileBuffer + CurrentOffset, + HashSize + ); + if (!Result) { + DEBUG_RAISE (); + return FALSE; + } + // + // Perform the Section-related steps of the algorithm. + // + Result = InternalHashSections ( + Context, + HashContext, + HashUpdate, + &SumBytesHashed + ); + if (!Result) { + DEBUG_RAISE (); + return FALSE; + } + // + // 8. Create a counter called SUM_OF_BYTES_HASHED, which is not part of the + // signature. Set this counter to the SizeOfHeaders field, as specified in + // Optional Header Windows-Specific Field. + // + Overflow = BaseOverflowAddU32 ( + SumBytesHashed, + Context->SizeOfHeaders, + &SumBytesHashed + ); + if (Overflow) { + DEBUG_RAISE (); + return FALSE; + } + // + // 14. Create a value called FILE_SIZE, which is not part of the signature. + // Set this value to the image’s file size, acquired from the underlying + // file system. If FILE_SIZE is greater than SUM_OF_BYTES_HASHED, the file + // contains extra data that must be added to the hash. This data begins at + // the SUM_OF_BYTES_HASHED file offset, and its length is: + // (File Size) - ((Size of AttributeCertificateTable) + SUM_OF_BYTES_HASHED) + // + // Note: The size of Attribute Certificate Table is specified in the + // second ULONG value in the Certificate Table entry (32 bit: offset 132, + // 64 bit: offset 148) in Optional Header Data Directories. + // + FileSize = Context->FileSize - SecurityDirSize; + if (SumBytesHashed < FileSize) { + Result = HashUpdate ( + HashContext, + (CONST CHAR8 *) Context->FileBuffer + SumBytesHashed, + FileSize - SumBytesHashed + ); + } + // + // This step must be performed by the caller after this function succeeded. + // + // 15. Finalize the hash algorithm context. + // + return Result; +} + +RETURN_STATUS +PeCoffGetFirstCertificate ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context, + OUT CONST WIN_CERTIFICATE **Certificate + ) +{ + CONST WIN_CERTIFICATE *WinCertificate; + // + // These conditions are verified by PeCoffInitializeContext(). + // + ASSERT (Context->SecDirOffset % ALIGNOF (WIN_CERTIFICATE)); + ASSERT (Context->SecDirSize == 0 || sizeof (WIN_CERTIFICATE) <= Context->SecDirSize); + // + // Verify the Security Directory is not empty. + // + if (Context->SecDirSize == 0) { + return RETURN_NOT_FOUND; + } + // + // Verify the certificate size is well-formed and that it is in bounds of the + // Security Directory. + // + WinCertificate = (CONST WIN_CERTIFICATE *) (CONST VOID *) ( + (CONST UINT8 *) Context->FileBuffer + Context->SecDirOffset + ); + if (WinCertificate->dwLength < sizeof (WIN_CERTIFICATE) + || WinCertificate->dwLength > Context->SecDirSize) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + // + // Verify the certificate size is sufficiently aligned, if the policy demands + // it. This has been observed to not be the case with images signed with + // pesign, such as GRUB. + // + if ((PcdGet32 (PcdImageLoaderAlignmentPolicy) & PCD_ALIGNMENT_POLICY_CERTIFICATE_SIZES) == 0) { + if (!IS_ALIGNED (WinCertificate->dwLength, IMAGE_CERTIFICATE_ALIGN)) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + } + + *Certificate = WinCertificate; + + return RETURN_SUCCESS; +} + +RETURN_STATUS +PeCoffGetNextCertificate ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context, + IN OUT CONST WIN_CERTIFICATE **Certificate + ) +{ + BOOLEAN Overflow; + UINT32 CertOffset; + UINT32 CertSize; + UINT32 CertEnd; + CONST WIN_CERTIFICATE *WinCertificate; + // + // This condition is verified by PeCoffInitializeContext(). + // + ASSERT (IS_ALIGNED (Context->SecDirSize, IMAGE_CERTIFICATE_ALIGN)); + // + // Retrieve the current certificate. + // + WinCertificate = *Certificate; + CertOffset = (UINT32) ((UINTN) WinCertificate - ((UINTN) Context->FileBuffer + Context->SecDirOffset)); + // + // Retrieve the offset of the next certificate. + // + if ((PcdGet32 (PcdImageLoaderAlignmentPolicy) & PCD_ALIGNMENT_POLICY_CERTIFICATE_SIZES) == 0) { + CertSize = WinCertificate->dwLength; + } else { + CertSize = ALIGN_VALUE (WinCertificate->dwLength, IMAGE_CERTIFICATE_ALIGN); + } + + CertOffset += CertSize; + // + // This invariant is ensured by the certificate iteration functions. + // + ASSERT (CertOffset <= Context->SecDirSize); + // + // If the next offset is the end of the Directory, signal it's the end of + // the certificate list. + // + if (CertOffset == Context->SecDirSize) { + return RETURN_NOT_FOUND; + } + // + // Verify the Directory fits another certificate. + // + if (Context->SecDirSize - CertOffset < sizeof (WIN_CERTIFICATE)) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + // + // Verify the certificate has a well-formed size. + // + WinCertificate = (CONST WIN_CERTIFICATE *) (CONST VOID *) ( + (CONST UINT8 *) Context->FileBuffer + Context->SecDirOffset + CertOffset + ); + if (WinCertificate->dwLength < sizeof (WIN_CERTIFICATE)) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + // + // Verify the certificate size is sufficiently aligned, if the policy demands + // it. + // + if ((PcdGet32 (PcdImageLoaderAlignmentPolicy) & PCD_ALIGNMENT_POLICY_CERTIFICATE_SIZES) == 0) { + if (!IS_ALIGNED (WinCertificate->dwLength, IMAGE_CERTIFICATE_ALIGN)) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + } + // + // Verify the certificate is in bounds of the Security Directory. + // + Overflow = BaseOverflowAddU32 ( + CertOffset, + WinCertificate->dwLength, + &CertEnd + ); + if (Overflow || CertEnd > Context->SecDirSize) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + + *Certificate = WinCertificate; + + return RETURN_SUCCESS; +} diff --git a/MdePkg/Library/BasePeCoffLib2/PeCoffHii.c b/MdePkg/Library/BasePeCoffLib2/PeCoffHii.c new file mode 100644 index 0000000000..a877031ca9 --- /dev/null +++ b/MdePkg/Library/BasePeCoffLib2/PeCoffHii.c @@ -0,0 +1,286 @@ +/** @file + Implements APIs to retrieve UEFI HII data from PE/COFF Images. + + Copyright (c) 2020 - 2021, Marvin Häuser. All rights reserved.
+ Copyright (c) 2020, Vitaly Cheptsov. All rights reserved.
+ Copyright (c) 2020, ISP RAS. All rights reserved.
+ Portions copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.
+ Portions copyright (c) 2008 - 2010, Apple Inc. All rights reserved.
+ Portions copyright (c) 2020, Hewlett Packard Enterprise Development LP. All rights reserved.
+ + SPDX-License-Identifier: BSD-3-Clause +**/ + +#include + +#include + +#include +#include +#include +#include + +#include "BasePeCoffLib2Internals.h" + +RETURN_STATUS +PeCoffGetHiiDataRva ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context, + OUT UINT32 *HiiRva, + OUT UINT32 *HiiSize + ) +{ + UINT16 Index; + CONST EFI_IMAGE_NT_HEADERS32 *Pe32Hdr; + CONST EFI_IMAGE_NT_HEADERS64 *Pe32PlusHdr; + CONST EFI_IMAGE_DATA_DIRECTORY *ResDirTable; + CONST EFI_IMAGE_RESOURCE_DIRECTORY *ResourceDir; + CONST EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *ResourceDirEntry; + CONST EFI_IMAGE_RESOURCE_DIRECTORY_STRING *ResourceDirString; + CONST EFI_IMAGE_RESOURCE_DATA_ENTRY *ResourceDataEntry; + BOOLEAN Overflow; + UINT32 Offset; + UINT32 TopOffset; + UINT8 ResourceLevel; + UINT32 HiiRvaEnd; + + ASSERT (Context != NULL); + ASSERT (HiiRva != NULL); + ASSERT (HiiSize != NULL); + // + // Retrieve the Image's Resource Directory Table. + // + switch (Context->ImageType) { + case PeCoffLoaderTypeTe: + if (PcdGetBool (PcdImageLoaderProhibitTe)) { + ASSERT (FALSE); + return RETURN_UNSUPPORTED; + } + // + // TE Images do not contain a Resource Directory Table. + // + return RETURN_NOT_FOUND; + + case PeCoffLoaderTypePe32: + Pe32Hdr = (CONST EFI_IMAGE_NT_HEADERS32 *) (CONST VOID *) ( + (CONST CHAR8 *) Context->FileBuffer + Context->ExeHdrOffset + ); + if (Pe32Hdr->NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE) { + return RETURN_NOT_FOUND; + } + + ResDirTable = &Pe32Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE]; + break; + + case PeCoffLoaderTypePe32Plus: + Pe32PlusHdr = (CONST EFI_IMAGE_NT_HEADERS64 *) (CONST VOID *) ( + (CONST CHAR8 *) Context->FileBuffer + Context->ExeHdrOffset + ); + if (Pe32PlusHdr->NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE) { + return RETURN_NOT_FOUND; + } + + ResDirTable = &Pe32PlusHdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE]; + break; + + default: + ASSERT (FALSE); + return RETURN_UNSUPPORTED; + } + // + // Verify the Resource Directory Table contains at least one entry. + // + if (ResDirTable->Size < sizeof (EFI_IMAGE_RESOURCE_DIRECTORY) + sizeof (*ResourceDir->Entries)) { + return RETURN_NOT_FOUND; + } + // + // Verify the start of the Resource Directory Table is sufficiently aligned. + // + if (!IS_ALIGNED (ResDirTable->VirtualAddress, ALIGNOF (EFI_IMAGE_RESOURCE_DIRECTORY))) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + // FIXME: Verify against first Image section / Headers due to XIP TE. + // + // Verify the Resource Directory Table is in bounds of the Image buffer. + // + Overflow = BaseOverflowAddU32 ( + ResDirTable->VirtualAddress, + ResDirTable->Size, + &TopOffset + ); + if (Overflow || TopOffset > Context->SizeOfImage) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + + ResourceDir = (CONST EFI_IMAGE_RESOURCE_DIRECTORY *) (CONST VOID *) ( + (CONST CHAR8 *) Context->ImageBuffer + ResDirTable->VirtualAddress + ); + // + // Verify the Resource Directory Table can hold all of its entries. + // + STATIC_ASSERT ( + sizeof (*ResourceDirEntry) * MAX_UINT16 <= ((UINT64) MAX_UINT32 + 1U) / 2 - sizeof (EFI_IMAGE_RESOURCE_DIRECTORY), + "The following arithmetic may overflow." + ); + TopOffset = sizeof (EFI_IMAGE_RESOURCE_DIRECTORY) + sizeof (*ResourceDirEntry) * + ((UINT32) ResourceDir->NumberOfNamedEntries + ResourceDir->NumberOfIdEntries); + if (TopOffset > ResDirTable->Size) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + // + // Try to locate the "HII" Resource entry. + // + for (Index = 0; Index < ResourceDir->NumberOfNamedEntries; ++Index) { + ResourceDirEntry = &ResourceDir->Entries[Index]; + // + // Filter entries with a non-Unicode name entry. + // + if (ResourceDirEntry->u1.s.NameIsString == 0) { + continue; + } + // + // Verify the Resource Directory String header is in bounds of the Resource + // Directory Table. + // + Overflow = BaseOverflowAddU32 ( + ResourceDirEntry->u1.s.NameOffset, + sizeof (*ResourceDirString), + &TopOffset + ); + if (Overflow || TopOffset > ResDirTable->Size) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + // + // Verify the Resource Directory String offset is sufficiently aligned. + // + Offset = ResDirTable->VirtualAddress + ResourceDirEntry->u1.s.NameOffset; + if (!IS_ALIGNED (Offset, ALIGNOF (EFI_IMAGE_RESOURCE_DIRECTORY_STRING))) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + + ResourceDirString = (CONST EFI_IMAGE_RESOURCE_DIRECTORY_STRING *) (CONST VOID *) ( + (CONST CHAR8 *) Context->ImageBuffer + Offset + ); + // + // Verify the Resource Directory String is in bounds of the Resource + // Directory Table. + // + Overflow = BaseOverflowAddU32 ( + TopOffset, + (UINT32) ResourceDirString->Length * sizeof (CHAR16), + &TopOffset + ); + if (Overflow || TopOffset > ResDirTable->Size) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + // + // Verify the type name matches "HII". + // + if (ResourceDirString->Length == 3 + && ResourceDirString->String[0] == L'H' + && ResourceDirString->String[1] == L'I' + && ResourceDirString->String[2] == L'I') { + break; + } + } + // + // Verify the "HII" Type Resource Directory Entry exists. + // + if (Index == ResourceDir->NumberOfNamedEntries) { + return RETURN_NOT_FOUND; + } + // + // Walk down the conventional "Name" and "Language" levels to reach the + // data directory. + // + for (ResourceLevel = 0; ResourceLevel < 2; ++ResourceLevel) { + // + // Succeed early if one of the levels is omitted. + // + if (ResourceDirEntry->u2.s.DataIsDirectory == 0) { + break; + } + // + // Verify the Resource Directory Table fits at least the Resource Directory + // with and one Relocation Directory Entry. + // + if (ResourceDirEntry->u2.s.OffsetToDirectory > ResDirTable->Size - sizeof (EFI_IMAGE_RESOURCE_DIRECTORY) + sizeof (*ResourceDir->Entries)) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + // + // Verify the next Relocation Directory offset is sufficiently aligned. + // + Offset = ResDirTable->VirtualAddress + ResourceDirEntry->u2.s.OffsetToDirectory; + if (!IS_ALIGNED (Offset, ALIGNOF (EFI_IMAGE_RESOURCE_DIRECTORY))) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + // + // Verify the Resource Directory has at least one entry. + // + ResourceDir = (CONST EFI_IMAGE_RESOURCE_DIRECTORY *) (CONST VOID *) ( + (CONST CHAR8 *) Context->ImageBuffer + Offset + ); + if ((UINT32) ResourceDir->NumberOfIdEntries + ResourceDir->NumberOfNamedEntries == 0) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + // + // Always take the first entry for simplicity. + // + ResourceDirEntry = &ResourceDir->Entries[0]; + } + // + // Verify the final Resource Directory Entry is of a data type. + // + if (ResourceDirEntry->u2.s.DataIsDirectory != 0) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + // + // Verify the Resource Directory Table fits at least the Resource Directory. + // + STATIC_ASSERT ( + sizeof (EFI_IMAGE_RESOURCE_DATA_ENTRY) <= sizeof (EFI_IMAGE_RESOURCE_DIRECTORY), + "The following arithmetic may overflow." + ); + if (ResourceDirEntry->u2.OffsetToData > ResDirTable->Size - sizeof (EFI_IMAGE_RESOURCE_DATA_ENTRY)) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + // + // Verify the Relocation Directory Entry offset is sufficiently aligned. + // + Offset = ResDirTable->VirtualAddress + ResourceDirEntry->u2.OffsetToData; + if (!IS_ALIGNED (Offset, ALIGNOF (EFI_IMAGE_RESOURCE_DATA_ENTRY))) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + + ResourceDataEntry = (CONST EFI_IMAGE_RESOURCE_DATA_ENTRY *) (CONST VOID *) ( + (CONST CHAR8 *) Context->ImageBuffer + Offset + ); + // + // Verify the "HII" data is in bounds of the Image buffer. + // + Overflow = BaseOverflowAddU32 ( + ResourceDataEntry->OffsetToData, + ResourceDataEntry->Size, + &HiiRvaEnd + ); + if (Overflow || HiiRvaEnd > Context->SizeOfImage) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + + *HiiRva = ResourceDataEntry->OffsetToData; + *HiiSize = ResourceDataEntry->Size; + + return RETURN_SUCCESS; +} diff --git a/MdePkg/Library/BasePeCoffLib2/PeCoffInfo.c b/MdePkg/Library/BasePeCoffLib2/PeCoffInfo.c new file mode 100644 index 0000000000..38211f1c89 --- /dev/null +++ b/MdePkg/Library/BasePeCoffLib2/PeCoffInfo.c @@ -0,0 +1,152 @@ +/** @file + Implements APIs to retrieve general information about PE/COFF Images. + + Copyright (c) 2020 - 2021, Marvin Häuser. All rights reserved.
+ Copyright (c) 2020, Vitaly Cheptsov. All rights reserved.
+ Copyright (c) 2020, ISP RAS. All rights reserved.
+ + SPDX-License-Identifier: BSD-3-Clause +**/ + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "BasePeCoffLib2Internals.h" + +UINT32 +PeCoffGetAddressOfEntryPoint ( + IN CONST PE_COFF_LOADER_IMAGE_CONTEXT *Context + ) +{ + ASSERT (Context != NULL); + + return Context->AddressOfEntryPoint; +} + +UINT16 +PeCoffGetMachine ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context + ) +{ + ASSERT (Context != NULL); + + return Context->Machine; +} + +UINT16 +PeCoffGetSubsystem ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context + ) +{ + ASSERT (Context != NULL); + + return Context->Subsystem; +} + +UINT32 +PeCoffGetSectionAlignment ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context + ) +{ + ASSERT (Context != NULL); + + return Context->SectionAlignment; +} + +UINT32 +PeCoffGetSizeOfImage ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context + ) +{ + ASSERT (Context != NULL); + + return Context->SizeOfImage; +} + +UINT32 +PeCoffGetSizeOfImageInplace ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context + ) +{ + UINT32 SizeOfImage; + + ASSERT (Context != NULL); + + SizeOfImage = Context->SizeOfImage; + // + // SizeOfImage is defined with the full Image header size pre-stripping. As + // XIP TE Images always have a stripped Image header, subtract the difference. + // + if (!PcdGetBool (PcdImageLoaderProhibitTe)) { + ASSERT (Context->TeStrippedOffset < SizeOfImage); + SizeOfImage -= Context->TeStrippedOffset; + } else { + ASSERT (Context->TeStrippedOffset == 0); + } + + return SizeOfImage; +} + +UINT64 +PeCoffGetImageBase ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context + ) +{ + ASSERT (Context != NULL); + + return Context->ImageBase; +} + +UINT32 +PeCoffGetSizeOfHeaders ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context + ) +{ + ASSERT (Context != NULL); + + return Context->SizeOfHeaders; +} + +UINT16 +PeCoffGetSectionTable ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context, + OUT CONST EFI_IMAGE_SECTION_HEADER **Sections + ) +{ + ASSERT (Context != NULL); + ASSERT (Sections != NULL); + + *Sections = (CONST EFI_IMAGE_SECTION_HEADER *) (CONST VOID *) ( + (CONST CHAR8 *) Context->FileBuffer + Context->SectionsOffset + ); + return Context->NumberOfSections; +} + +BOOLEAN +PeCoffGetRelocsStripped ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context + ) +{ + ASSERT (Context != NULL); + + return Context->RelocsStripped; +} + +// FIXME: Distinguish between base and buffer (XIP TE) +UINTN +PeCoffLoaderGetImageAddress ( + IN CONST PE_COFF_LOADER_IMAGE_CONTEXT *Context + ) +{ + ASSERT (Context != NULL); + ASSERT (Context->ImageBuffer != NULL); + + return (UINTN) Context->ImageBuffer; +} diff --git a/MdePkg/Library/BasePeCoffLib2/PeCoffInit.c b/MdePkg/Library/BasePeCoffLib2/PeCoffInit.c new file mode 100644 index 0000000000..11b8237599 --- /dev/null +++ b/MdePkg/Library/BasePeCoffLib2/PeCoffInit.c @@ -0,0 +1,896 @@ +/** @file + Implements APIs to verify PE/COFF Images for further processing. + + Copyright (c) 2020 - 2021, Marvin Häuser. All rights reserved.
+ Copyright (c) 2020, Vitaly Cheptsov. All rights reserved.
+ Copyright (c) 2020, ISP RAS. All rights reserved.
+ Portions copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.
+ Portions copyright (c) 2008 - 2010, Apple Inc. All rights reserved.
+ Portions copyright (c) 2020, Hewlett Packard Enterprise Development LP. All rights reserved.
+ + SPDX-License-Identifier: BSD-3-Clause +**/ + +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include + +#include "BasePeCoffLib2Internals.h" + +// +// FIXME: Provide an API to destruct the context? +// + +/** + Verify the Image section Headers and initialise the Image memory space size. + + The first Image section must be the beginning of the memory space, or be + contiguous to the aligned Image Headers. + Sections must be disjoint and, depending on the policy, contiguous in the + memory space space. + The section data must be in bounds bounds of the file buffer. + + @param[in,out] Context The context describing the Image. Must have been + initialised by PeCoffInitializeContext(). + @param[in] FileSize The size, in Bytes, of Context->FileBuffer. + @param[out] StartAddress On output, the RVA of the first Image section. + + @retval RETURN_SUCCESS The Image section Headers are well-formed. + @retval other The Image section Headers are malformed. +**/ +STATIC +RETURN_STATUS +InternalVerifySections ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context, + IN UINT32 FileSize, + OUT UINT32 *StartAddress + ) +{ + BOOLEAN Overflow; + UINT32 NextSectRva; + UINT32 SectRawEnd; + UINT32 EffectiveSectRawEnd; + UINT16 SectionIndex; + CONST EFI_IMAGE_SECTION_HEADER *Sections; + + ASSERT (Context != NULL); + ASSERT (Context->TeStrippedOffset <= Context->SizeOfHeaders); + ASSERT (IS_POW2 (Context->SectionAlignment)); + ASSERT (StartAddress != NULL); + // + // Images without Sections have no usable data, disallow them. + // + if (Context->NumberOfSections == 0) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + + Sections = (CONST EFI_IMAGE_SECTION_HEADER *) (CONST VOID *) ( + (CONST CHAR8 *) Context->FileBuffer + Context->SectionsOffset + ); + // + // The first Image section must begin the Image memory space, or it must be + // adjacent to the Image Headers. + // + if (Sections[0].VirtualAddress == 0) { + // FIXME: Add PCD to disallow. + // + // TE Images cannot support loading the Image Headers as part of the first + // Image section due to its StrippedSize sematics. + // + if (!PcdGetBool (PcdImageLoaderProhibitTe)) { + if (Context->ImageType == PeCoffLoaderTypeTe) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + } else { + ASSERT (Context->ImageType != PeCoffLoaderTypeTe); + } + + NextSectRva = 0; + } else { + // + // Choose the raw or aligned Image Headers size depending on whether loading + // unaligned Sections is allowed. + // + if ((PcdGet32 (PcdImageLoaderAlignmentPolicy) & PCD_ALIGNMENT_POLICY_CONTIGUOUS_SECTIONS) == 0) { + Overflow = BaseOverflowAlignUpU32 ( + Context->SizeOfHeaders, + Context->SectionAlignment, + &NextSectRva + ); + if (Overflow) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + } else { + NextSectRva = Context->SizeOfHeaders; + } + } + + *StartAddress = NextSectRva; + // + // Verify all Image sections are valid. + // + for (SectionIndex = 0; SectionIndex < Context->NumberOfSections; ++SectionIndex) { + // + // Verify the Image section adheres to the W^X principle, if the policy + // demands it. + // + if (PcdGetBool (PcdImageLoaderWXorX)) { + if ((Sections[SectionIndex].Characteristics & (EFI_IMAGE_SCN_MEM_EXECUTE | EFI_IMAGE_SCN_MEM_WRITE)) == (EFI_IMAGE_SCN_MEM_EXECUTE | EFI_IMAGE_SCN_MEM_WRITE)) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + } + // + // Verify the Image sections are disjoint (relaxed) or adjacent (strict) + // depending on whether unaligned Image sections may be loaded or not. + // Unaligned Image sections have been observed with iPXE Option ROMs and old + // Apple Mac OS X bootloaders. + // + if ((PcdGet32 (PcdImageLoaderAlignmentPolicy) & PCD_ALIGNMENT_POLICY_CONTIGUOUS_SECTIONS) == 0) { + if (Sections[SectionIndex].VirtualAddress != NextSectRva) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + } else { + if (Sections[SectionIndex].VirtualAddress < NextSectRva) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + // + // If the Image section address is not aligned by the Image section + // alignment, fall back to important architecture-specific page sizes if + // possible, to ensure the Image can have memory protection applied. + // Otherwise, report no alignment for the Image. + // + if (!IS_ALIGNED (Sections[SectionIndex].VirtualAddress, Context->SectionAlignment)) { + STATIC_ASSERT ( + DEFAULT_PAGE_ALLOCATION_GRANULARITY <= RUNTIME_PAGE_ALLOCATION_GRANULARITY, + "This code must be adapted to consider the reversed order." + ); + + if (IS_ALIGNED (Sections[SectionIndex].VirtualAddress, RUNTIME_PAGE_ALLOCATION_GRANULARITY)) { + Context->SectionAlignment = RUNTIME_PAGE_ALLOCATION_GRANULARITY; + } else if (DEFAULT_PAGE_ALLOCATION_GRANULARITY < RUNTIME_PAGE_ALLOCATION_GRANULARITY + && IS_ALIGNED (Sections[SectionIndex].VirtualAddress, DEFAULT_PAGE_ALLOCATION_GRANULARITY)) { + Context->SectionAlignment = DEFAULT_PAGE_ALLOCATION_GRANULARITY; + } else { + Context->SectionAlignment = 1; + } + } + } + // + // Verify the Image sections with data are in bounds of the file buffer. + // + if (Sections[SectionIndex].SizeOfRawData > 0) { + if (!PcdGetBool (PcdImageLoaderProhibitTe)) { + if (Context->TeStrippedOffset > Sections[SectionIndex].PointerToRawData) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + } else { + ASSERT (Context->TeStrippedOffset == 0); + } + + Overflow = BaseOverflowAddU32 ( + Sections[SectionIndex].PointerToRawData, + Sections[SectionIndex].SizeOfRawData, + &SectRawEnd + ); + if (Overflow) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + + if (!PcdGetBool (PcdImageLoaderProhibitTe)) { + EffectiveSectRawEnd = SectRawEnd - Context->TeStrippedOffset; + } else { + ASSERT (Context->TeStrippedOffset == 0); + EffectiveSectRawEnd = SectRawEnd; + } + + if (EffectiveSectRawEnd > FileSize) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + } + // + // Determine the end of the current Image section. + // + Overflow = BaseOverflowAddU32 ( + Sections[SectionIndex].VirtualAddress, + Sections[SectionIndex].VirtualSize, + &NextSectRva + ); + if (Overflow) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + // + // VirtualSize does not need to be aligned, so align the result if needed. + // + if ((PcdGet32 (PcdImageLoaderAlignmentPolicy) & PCD_ALIGNMENT_POLICY_CONTIGUOUS_SECTIONS) == 0) { + Overflow = BaseOverflowAlignUpU32 ( + NextSectRva, + Context->SectionAlignment, + &NextSectRva + ); + if (Overflow) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + } + } + // + // Set SizeOfImage to the aligned end address of the last ImageSection. + // + if ((PcdGet32 (PcdImageLoaderAlignmentPolicy) & PCD_ALIGNMENT_POLICY_CONTIGUOUS_SECTIONS) == 0) { + Context->SizeOfImage = NextSectRva; + } else { + // + // Because VirtualAddress is aligned by SectionAlignment for all Image + // sections, and they are disjoint and ordered by VirtualAddress, + // VirtualAddress + VirtualSize must be safe to align by SectionAlignment for + // all but the last Image section. + // Determine the strictest common alignment that the last section's end is + // safe to align to. + // + Overflow = BaseOverflowAlignUpU32 ( + NextSectRva, + Context->SectionAlignment, + &Context->SizeOfImage + ); + if (Overflow) { + Context->SectionAlignment = RUNTIME_PAGE_ALLOCATION_GRANULARITY; + Overflow = BaseOverflowAlignUpU32 ( + NextSectRva, + Context->SectionAlignment, + &Context->SizeOfImage + ); + if (DEFAULT_PAGE_ALLOCATION_GRANULARITY < RUNTIME_PAGE_ALLOCATION_GRANULARITY + && Overflow) { + Context->SectionAlignment = DEFAULT_PAGE_ALLOCATION_GRANULARITY; + Overflow = BaseOverflowAlignUpU32 ( + NextSectRva, + Context->SectionAlignment, + &Context->SizeOfImage + ); + } + + if (Overflow) { + Context->SectionAlignment = 1; + } + } + } + + return RETURN_SUCCESS; +} + +/** + Verify the basic Image Relocation information. + + The preferred Image load address must be aligned by the section alignment. + The Relocation Directory must be contained within the Image section memory. + The Relocation Directory must be sufficiently aligned in memory. + + @param[in] Context The context describing the Image. Must have been + initialised by PeCoffInitializeContext(). + @param[in] StartAddress The RVA of the first Image section. + + @retval RETURN_SUCCESS The basic Image Relocation information is well-formed. + @retval other The basic Image Relocation information is malformed. +**/ +STATIC +RETURN_STATUS +InternalValidateRelocInfo ( + IN CONST PE_COFF_LOADER_IMAGE_CONTEXT *Context, + IN UINT32 StartAddress + ) +{ + BOOLEAN Overflow; + UINT32 SectRvaEnd; + + ASSERT (Context != NULL); + ASSERT (!Context->RelocsStripped || Context->RelocDirSize == 0); + // + // If the Base Relocations have not been stripped, verify their Directory. + // + if (Context->RelocDirSize != 0) { + // + // Verify the Relocation Directory is not empty. + // + if (sizeof (EFI_IMAGE_BASE_RELOCATION_BLOCK) > Context->RelocDirSize) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + // + // Verify the Relocation Directory does not overlap with the Image Headers. + // + if (StartAddress > Context->RelocDirRva) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + // + // Verify the Relocation Directory is contained in the Image memory space. + // + Overflow = BaseOverflowAddU32 ( + Context->RelocDirRva, + Context->RelocDirSize, + &SectRvaEnd + ); + if (Overflow || SectRvaEnd > Context->SizeOfImage) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + // + // Verify the Relocation Directory start is sufficiently aligned. + // + if (!IS_ALIGNED (Context->RelocDirRva, ALIGNOF (EFI_IMAGE_BASE_RELOCATION_BLOCK))) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + } + // + // Verify the preferred Image load address is sufficiently aligned. + // + // FIXME: Only with force-aligned sections? What to do with XIP? + if (!IS_ALIGNED (Context->ImageBase, (UINT64) Context->SectionAlignment)) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + + return RETURN_SUCCESS; +} + +/** + Verify the TE Image and initialise Context. + + Used offsets and ranges must be aligned and in the bounds of the raw file. + Image section Headers and basic Relocation information must be well-formed. + + @param[in,out] Context The context describing the Image. Must have been + initialised by PeCoffInitializeContext(). + @param[in] FileSize The size, in Bytes, of Context->FileBuffer. + + @retval RETURN_SUCCESS The TE Image is well-formed. + @retval other The TE Image is malformed. +**/ +STATIC +RETURN_STATUS +InternalInitializeTe ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context, + IN UINT32 FileSize + ) +{ + RETURN_STATUS Status; + BOOLEAN Overflow; + CONST EFI_TE_IMAGE_HEADER *TeHdr; + UINT32 StartAddress; + + ASSERT (Context != NULL); + ASSERT (Context->ExeHdrOffset == 0); + ASSERT (sizeof (EFI_TE_IMAGE_HEADER) <= FileSize); + + if (PcdGetBool (PcdImageLoaderProhibitTe)) { + ASSERT (FALSE); + return RETURN_UNSUPPORTED; + } + + TeHdr = (CONST EFI_TE_IMAGE_HEADER *) (CONST VOID *) ( + (CONST CHAR8 *) Context->FileBuffer + ); + + Context->ImageType = PeCoffLoaderTypeTe; + // + // Calculate the size, in Bytes, stripped from the Image Headers. + // + Overflow = BaseOverflowSubU16 ( + TeHdr->StrippedSize, + sizeof (*TeHdr), + &Context->TeStrippedOffset + ); + if (Overflow) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + + STATIC_ASSERT ( + MAX_UINT8 * sizeof (EFI_IMAGE_SECTION_HEADER) <= MAX_UINT32 - MAX_UINT16, + "The following arithmetic may overflow." + ); + // + // Calculate SizeOfHeaders in a way that is equivalent to what the size would + // be if this was the original (unstripped) PE32 binary. As the TE image + // creation doesn't fix fields up, values work the same way as for PE32. + // When referencing raw data however, the TE stripped size must be subracted. + // + Context->SizeOfHeaders = (UINT32) TeHdr->StrippedSize + (UINT32) TeHdr->NumberOfSections * sizeof (EFI_IMAGE_SECTION_HEADER); + // + // Verify that the Image Headers are in bounds of the file buffer. + // + if (Context->SizeOfHeaders - Context->TeStrippedOffset > FileSize) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + + STATIC_ASSERT ( + IS_ALIGNED (sizeof (*TeHdr), ALIGNOF (EFI_IMAGE_SECTION_HEADER)), + "The Image section alignment requirements are violated." + ); + // + // TE Image sections start right after the Image Headers. + // + Context->SectionsOffset = sizeof (EFI_TE_IMAGE_HEADER); + // + // TE Images do not store their section alignment. Assume the UEFI Page size + // by default, as it is the minimum to guarantee memory permission support. + // + Context->SectionAlignment = EFI_PAGE_SIZE; + Context->NumberOfSections = TeHdr->NumberOfSections; + // + // Validate the sections. + // TE images do not have a field to explicitly describe the image size. + // Set it to the top of the Image's memory space. + // + Status = InternalVerifySections ( + Context, + FileSize, + &StartAddress + ); + if (Status != RETURN_SUCCESS) { + DEBUG_RAISE (); + return Status; + } + // + // Verify the Image entry point is in bounds of the Image buffer. + // + if (TeHdr->AddressOfEntryPoint >= Context->SizeOfImage) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + + Context->Machine = TeHdr->Machine; + Context->Subsystem = TeHdr->Subsystem; + Context->ImageBase = TeHdr->ImageBase; + Context->AddressOfEntryPoint = TeHdr->AddressOfEntryPoint; + Context->RelocDirRva = TeHdr->DataDirectory[0].VirtualAddress; + Context->RelocDirSize = TeHdr->DataDirectory[0].Size; + // + // TE Images do not explicitly store whether their Relocations have been + // stripped. Relocations have been stripped if and only if both the RVA and + // size of the Relocation Directory are zero. + // + Context->RelocsStripped = TeHdr->DataDirectory[0].VirtualAddress == 0 && TeHdr->DataDirectory[0].Size == 0; + // + // Verify basic sanity of the Relocation Directory. + // + return InternalValidateRelocInfo (Context, StartAddress); +} + +/** + Verify the PE32 or PE32+ Image and initialise Context. + + Used offsets and ranges must be aligned and in the bounds of the raw file. + Image section Headers and basic Relocation information must be Well-formed. + + @param[in,out] Context The context describing the Image. Must have been + initialised by PeCoffInitializeContext(). + @param[in] FileSize The size, in Bytes, of Context->FileBuffer. + + @retval RETURN_SUCCESS The PE Image is Well-formed. + @retval other The PE Image is malformed. +**/ +STATIC +RETURN_STATUS +InternalInitializePe ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context, + IN UINT32 FileSize + ) +{ + BOOLEAN Overflow; + CONST EFI_IMAGE_NT_HEADERS_COMMON_HDR *PeCommon; + CONST EFI_IMAGE_NT_HEADERS32 *Pe32; + CONST EFI_IMAGE_NT_HEADERS64 *Pe32Plus; + CONST CHAR8 *OptHdrPtr; + UINT32 HdrSizeWithoutDataDir; + UINT32 MinSizeOfOptionalHeader; + UINT32 MinSizeOfHeaders; + CONST EFI_IMAGE_DATA_DIRECTORY *RelocDir; + CONST EFI_IMAGE_DATA_DIRECTORY *SecDir; + UINT32 SecDirEnd; + UINT32 NumberOfRvaAndSizes; + RETURN_STATUS Status; + UINT32 StartAddress; + + ASSERT (Context != NULL); + ASSERT (sizeof (EFI_IMAGE_NT_HEADERS_COMMON_HDR) + sizeof (UINT16) <= FileSize - Context->ExeHdrOffset); + if (!PcdGetBool (PcdImageLoaderAllowMisalignedOffset)) { + ASSERT (IS_ALIGNED (Context->ExeHdrOffset, ALIGNOF (EFI_IMAGE_NT_HEADERS_COMMON_HDR))); + } + // + // Locate the PE Optional Header. + // + OptHdrPtr = (CONST CHAR8 *) Context->FileBuffer + Context->ExeHdrOffset; + OptHdrPtr += sizeof (EFI_IMAGE_NT_HEADERS_COMMON_HDR); + + STATIC_ASSERT ( + IS_ALIGNED (ALIGNOF (EFI_IMAGE_NT_HEADERS_COMMON_HDR), ALIGNOF (UINT16)) + && IS_ALIGNED (sizeof (EFI_IMAGE_NT_HEADERS_COMMON_HDR), ALIGNOF (UINT16)), + "The following operation might be an unaligned access." + ); + // + // Determine the type of and retrieve data from the PE Optional Header. + // Do not retrieve SizeOfImage as the value usually does not follow the + // specification. Even if the value is large enough to hold the last Image + // section, it may not be aligned, or it may be too large. No data can + // possibly be loaded past the last Image section anyway. + // + switch (*(CONST UINT16 *) (CONST VOID *) OptHdrPtr) { + case EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC: + // + // Verify the PE32 header is in bounds of the file buffer. + // + if (sizeof (*Pe32) > FileSize - Context->ExeHdrOffset) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + // + // The PE32 header offset is always sufficiently aligned. + // + STATIC_ASSERT ( + ALIGNOF (EFI_IMAGE_NT_HEADERS32) <= ALIGNOF (EFI_IMAGE_NT_HEADERS_COMMON_HDR), + "The following operations may be unaligned." + ); + // + // Populate the common data with information from the Optional Header. + // + Pe32 = (CONST EFI_IMAGE_NT_HEADERS32 *) (CONST VOID *) ( + (CONST CHAR8 *) Context->FileBuffer + Context->ExeHdrOffset + ); + + Context->ImageType = PeCoffLoaderTypePe32; + Context->Subsystem = Pe32->Subsystem; + Context->SizeOfHeaders = Pe32->SizeOfHeaders; + Context->ImageBase = Pe32->ImageBase; + Context->AddressOfEntryPoint = Pe32->AddressOfEntryPoint; + Context->SectionAlignment = Pe32->SectionAlignment; + + RelocDir = Pe32->DataDirectory + EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC; + SecDir = Pe32->DataDirectory + EFI_IMAGE_DIRECTORY_ENTRY_SECURITY; + + PeCommon = &Pe32->CommonHeader; + NumberOfRvaAndSizes = Pe32->NumberOfRvaAndSizes; + HdrSizeWithoutDataDir = sizeof (EFI_IMAGE_NT_HEADERS32) - sizeof (EFI_IMAGE_NT_HEADERS_COMMON_HDR); + + break; + + case EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC: + // + // Verify the PE32+ header is in bounds of the file buffer. + // + if (sizeof (*Pe32Plus) > FileSize - Context->ExeHdrOffset) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + // + // Verify the PE32+ header offset is sufficiently aligned. + // + if (!PcdGetBool (PcdImageLoaderAllowMisalignedOffset) + && !IS_ALIGNED (Context->ExeHdrOffset, ALIGNOF (EFI_IMAGE_NT_HEADERS64))) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + // + // Populate the common data with information from the Optional Header. + // + Pe32Plus = (CONST EFI_IMAGE_NT_HEADERS64 *) (CONST VOID *) ( + (CONST CHAR8 *) Context->FileBuffer + Context->ExeHdrOffset + ); + + Context->ImageType = PeCoffLoaderTypePe32Plus; + Context->Subsystem = Pe32Plus->Subsystem; + Context->SizeOfHeaders = Pe32Plus->SizeOfHeaders; + Context->ImageBase = Pe32Plus->ImageBase; + Context->AddressOfEntryPoint = Pe32Plus->AddressOfEntryPoint; + Context->SectionAlignment = Pe32Plus->SectionAlignment; + + RelocDir = Pe32Plus->DataDirectory + EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC; + SecDir = Pe32Plus->DataDirectory + EFI_IMAGE_DIRECTORY_ENTRY_SECURITY; + + PeCommon = &Pe32Plus->CommonHeader; + NumberOfRvaAndSizes = Pe32Plus->NumberOfRvaAndSizes; + HdrSizeWithoutDataDir = sizeof (EFI_IMAGE_NT_HEADERS64) - sizeof (EFI_IMAGE_NT_HEADERS_COMMON_HDR); + + break; + + default: + // + // Disallow Images with unknown PE Optional Header signatures. + // + DEBUG_RAISE (); + return RETURN_UNSUPPORTED; + } + // + // Disallow Images with unknown directories. + // + if (NumberOfRvaAndSizes > EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + // + // Verify the Image alignment is a power of 2. + // + if (!IS_POW2 (Context->SectionAlignment)) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + + STATIC_ASSERT ( + sizeof (EFI_IMAGE_DATA_DIRECTORY) <= MAX_UINT32 / EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES, + "The following arithmetic may overflow." + ); + // + // Calculate the offset of the Image sections. + // + // Context->ExeHdrOffset + sizeof (EFI_IMAGE_NT_HEADERS_COMMON_HDR) cannot overflow because + // * ExeFileSize > sizeof (EFI_IMAGE_NT_HEADERS_COMMON_HDR) and + // * Context->ExeHdrOffset + ExeFileSize = FileSize + // + Overflow = BaseOverflowAddU32 ( + Context->ExeHdrOffset + sizeof (*PeCommon), + PeCommon->FileHeader.SizeOfOptionalHeader, + &Context->SectionsOffset + ); + if (Overflow) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + // + // Verify the Section Headers offset is sufficiently aligned. + // + if (!PcdGetBool (PcdImageLoaderAllowMisalignedOffset) + && !IS_ALIGNED (Context->SectionsOffset, ALIGNOF (EFI_IMAGE_SECTION_HEADER))) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + // + // This arithmetic cannot overflow because all values are sufficiently + // bounded. + // + MinSizeOfOptionalHeader = HdrSizeWithoutDataDir + + NumberOfRvaAndSizes * sizeof (EFI_IMAGE_DATA_DIRECTORY); + + ASSERT (MinSizeOfOptionalHeader >= HdrSizeWithoutDataDir); + + STATIC_ASSERT ( + sizeof (EFI_IMAGE_SECTION_HEADER) <= (MAX_UINT32 + 1ULL) / (MAX_UINT16 + 1ULL), + "The following arithmetic may overflow." + ); + // + // Calculate the minimum size of the Image Headers. + // + Overflow = BaseOverflowAddU32 ( + Context->SectionsOffset, + (UINT32) PeCommon->FileHeader.NumberOfSections * sizeof (EFI_IMAGE_SECTION_HEADER), + &MinSizeOfHeaders + ); + if (Overflow) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + // + // Verify the Image Header sizes are sane. SizeOfHeaders contains all header + // components (DOS, PE Common and Optional Header). + // + if (MinSizeOfOptionalHeader > PeCommon->FileHeader.SizeOfOptionalHeader) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + + if (MinSizeOfHeaders > Context->SizeOfHeaders) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + // + // Verify the Image Headers are in bounds of the file buffer. + // + if (Context->SizeOfHeaders > FileSize) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + // + // Populate the Image context with information from the Common Header. + // + Context->NumberOfSections = PeCommon->FileHeader.NumberOfSections; + Context->Machine = PeCommon->FileHeader.Machine; + Context->RelocsStripped = + ( + PeCommon->FileHeader.Characteristics & EFI_IMAGE_FILE_RELOCS_STRIPPED + ) != 0; + + if (EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC < NumberOfRvaAndSizes) { + Context->RelocDirRva = RelocDir->VirtualAddress; + Context->RelocDirSize = RelocDir->Size; + + if (Context->RelocsStripped && Context->RelocDirSize != 0) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + } else { + ASSERT (Context->RelocDirRva == 0); + ASSERT (Context->RelocDirSize == 0); + } + + if (EFI_IMAGE_DIRECTORY_ENTRY_SECURITY < NumberOfRvaAndSizes) { + Context->SecDirOffset = SecDir->VirtualAddress; + Context->SecDirSize = SecDir->Size; + // + // Verify the Security Directory is in bounds of the Image buffer. + // + Overflow = BaseOverflowAddU32 ( + Context->SecDirOffset, + Context->SecDirSize, + &SecDirEnd + ); + if (Overflow || SecDirEnd > FileSize) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + // + // Verify the Security Directory is sufficiently aligned. + // + if (!IS_ALIGNED (Context->SecDirOffset, IMAGE_CERTIFICATE_ALIGN)) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + // + // Verify the Security Directory size is sufficiently aligned, and that if + // it is not empty, it can fit at least one certificate. + // + if (Context->SecDirSize != 0 + && (!IS_ALIGNED (Context->SecDirSize, IMAGE_CERTIFICATE_ALIGN) + || Context->SecDirSize < sizeof (WIN_CERTIFICATE))) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + } else { + // + // The Image context is zero'd on allocation. + // + ASSERT (Context->SecDirOffset == 0); + ASSERT (Context->SecDirSize == 0); + } + + ASSERT (Context->TeStrippedOffset == 0); + // + // Verify the Image sections are Well-formed. + // + Status = InternalVerifySections ( + Context, + FileSize, + &StartAddress + ); + if (Status != RETURN_SUCCESS) { + DEBUG_RAISE (); + return Status; + } + // + // Verify the entry point is in bounds of the Image buffer. + // + if (Context->AddressOfEntryPoint >= Context->SizeOfImage) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + // + // Verify the basic Relocation information is well-formed. + // + Status = InternalValidateRelocInfo (Context, StartAddress); + if (Status != RETURN_SUCCESS) { + DEBUG_RAISE (); + } + + return Status; +} + +RETURN_STATUS +PeCoffInitializeContext ( + OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context, + IN CONST VOID *FileBuffer, + IN UINT32 FileSize + ) +{ + RETURN_STATUS Status; + CONST EFI_IMAGE_DOS_HEADER *DosHdr; + + ASSERT (Context != NULL); + ASSERT (FileBuffer != NULL || FileSize == 0); + // + // Initialise the Image context with 0-values. + // + ZeroMem (Context, sizeof (*Context)); + + Context->FileBuffer = FileBuffer; + Context->FileSize = FileSize; + // + // Check whether the DOS Image Header is present. + // + if (sizeof (*DosHdr) <= FileSize + && *(CONST UINT16 *) (CONST VOID *) FileBuffer == EFI_IMAGE_DOS_SIGNATURE) { + DosHdr = (CONST EFI_IMAGE_DOS_HEADER *) (CONST VOID *) ( + (CONST CHAR8 *) FileBuffer + ); + // + // Verify the DOS Image Header and the Executable Header are in bounds of + // the file buffer, and that they are disjoint. + // + if (sizeof (EFI_IMAGE_DOS_HEADER) > DosHdr->e_lfanew + || DosHdr->e_lfanew > FileSize) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + + Context->ExeHdrOffset = DosHdr->e_lfanew; + // + // Verify the Execution Header offset is sufficiently aligned. + // + if (!PcdGetBool (PcdImageLoaderAllowMisalignedOffset) + && !IS_ALIGNED (Context->ExeHdrOffset, ALIGNOF (EFI_IMAGE_NT_HEADERS_COMMON_HDR))) { + return RETURN_UNSUPPORTED; + } + } else if (!PcdGetBool (PcdImageLoaderProhibitTe)) { + // + // Assume the Image starts with the Executable Header, determine whether it + // is a TE Image. + // + if (sizeof (EFI_TE_IMAGE_HEADER) <= FileSize + && *(CONST UINT16 *) (CONST VOID *) FileBuffer == EFI_TE_IMAGE_HEADER_SIGNATURE) { + // + // Verify the TE Image Header is well-formed. + // + Status = InternalInitializeTe (Context, FileSize); + if (Status != RETURN_SUCCESS) { + DEBUG_RAISE (); + return Status; + } + + return RETURN_SUCCESS; + } + } + // + // Verify the file buffer can hold a PE Common Header. + // + if (FileSize - Context->ExeHdrOffset < sizeof (EFI_IMAGE_NT_HEADERS_COMMON_HDR) + sizeof (UINT16)) { + return RETURN_UNSUPPORTED; + } + + STATIC_ASSERT ( + ALIGNOF (UINT32) <= ALIGNOF (EFI_IMAGE_NT_HEADERS_COMMON_HDR), + "The following access may be performed unaligned" + ); + // + // Verify the Image Executable Header has a PE signature. + // + if (*(CONST UINT32 *) (CONST VOID *) ((CONST CHAR8 *) FileBuffer + Context->ExeHdrOffset) != EFI_IMAGE_NT_SIGNATURE) { + return RETURN_UNSUPPORTED; + } + // + // Verify the PE Image Header is well-formed. + // + Status = InternalInitializePe (Context, FileSize); + if (Status != RETURN_SUCCESS) { + return Status; + } + + return RETURN_SUCCESS; +} diff --git a/MdePkg/Library/BasePeCoffLib2/PeCoffLoad.c b/MdePkg/Library/BasePeCoffLib2/PeCoffLoad.c new file mode 100644 index 0000000000..6aa1acb38f --- /dev/null +++ b/MdePkg/Library/BasePeCoffLib2/PeCoffLoad.c @@ -0,0 +1,259 @@ +/** @file + Implements APIs to load PE/COFF Images. + + Copyright (c) 2020 - 2021, Marvin Häuser. All rights reserved.
+ Copyright (c) 2020, Vitaly Cheptsov. All rights reserved.
+ Copyright (c) 2020, ISP RAS. All rights reserved.
+ Portions copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.
+ Portions copyright (c) 2008 - 2010, Apple Inc. All rights reserved.
+ Portions copyright (c) 2020, Hewlett Packard Enterprise Development LP. All rights reserved.
+ + SPDX-License-Identifier: BSD-3-Clause +**/ + +#include + +#include + +#include +#include +#include +#include + +#include "BasePeCoffLib2Internals.h" + +/** + Loads the Image sections into the memory space and initialises any padding + with zeros. + + @param[in] Context The context describing the Image. Must have been + initialised by PeCoffInitializeContext(). + @param[in] LoadedHeaderSize The size, in Bytes, of the loaded Image Headers. + @param[in] DestinationSize The size, in Bytes, of Destination. Must be + sufficent to load the Image with regards to its + Image section alignment. +**/ +STATIC +VOID +InternalLoadSections ( + IN CONST PE_COFF_LOADER_IMAGE_CONTEXT *Context, + IN UINT32 LoadedHeaderSize, + IN UINT32 DestinationSize + ) +{ + CONST EFI_IMAGE_SECTION_HEADER *Sections; + UINT16 SectionIndex; + UINT32 EffectivePointerToRawData; + UINT32 DataSize; + UINT32 PreviousTopRva; + + Sections = (CONST EFI_IMAGE_SECTION_HEADER *) (CONST VOID *) ( + (CONST CHAR8 *) Context->FileBuffer + Context->SectionsOffset + ); + // + // As the loop zero's the data from the end of the previous section, start + // with the size of the loaded Image Headers to zero their trailing data. + // + PreviousTopRva = LoadedHeaderSize; + + for (SectionIndex = 0; SectionIndex < Context->NumberOfSections; ++SectionIndex) { + // + // Zero from the end of the previous section to the start of this section. + // + ZeroMem ( + (CHAR8 *) Context->ImageBuffer + PreviousTopRva, + Sections[SectionIndex].VirtualAddress - PreviousTopRva + ); + // + // Copy the maximum amount of data that fits both sizes. + // + if (Sections[SectionIndex].SizeOfRawData <= Sections[SectionIndex].VirtualSize) { + DataSize = Sections[SectionIndex].SizeOfRawData; + } else { + DataSize = Sections[SectionIndex].VirtualSize; + } + // + // Load the current Image section into the memory space. + // + if (!PcdGetBool (PcdImageLoaderProhibitTe)) { + EffectivePointerToRawData = Sections[SectionIndex].PointerToRawData - Context->TeStrippedOffset; + } else { + ASSERT (Context->TeStrippedOffset == 0); + EffectivePointerToRawData = Sections[SectionIndex].PointerToRawData; + } + + CopyMem ( + (CHAR8 *) Context->ImageBuffer + Sections[SectionIndex].VirtualAddress, + (CONST CHAR8 *) Context->FileBuffer + EffectivePointerToRawData, + DataSize + ); + + PreviousTopRva = Sections[SectionIndex].VirtualAddress + DataSize; + } + // + // Zero the trailing data after the last Image section. + // + ZeroMem ( + (CHAR8 *) Context->ImageBuffer + PreviousTopRva, + DestinationSize - PreviousTopRva + ); +} + +RETURN_STATUS +PeCoffLoadImage ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context, + OUT VOID *Destination, + IN UINT32 DestinationSize + ) +{ + UINT32 LoadedHeaderSize; + CONST EFI_IMAGE_SECTION_HEADER *Sections; + + ASSERT (Context != NULL); + ASSERT (Destination != NULL); + ASSERT (ADDRESS_IS_ALIGNED (Destination, Context->SectionAlignment)); + ASSERT (Context->SizeOfImage <= DestinationSize); + + Context->ImageBuffer = Destination; + // + // Load the Image Headers into the memory space, if the policy demands it. + // + Sections = (CONST EFI_IMAGE_SECTION_HEADER *) (CONST VOID *) ( + (CONST CHAR8 *) Context->FileBuffer + Context->SectionsOffset + ); + if (PcdGetBool (PcdImageLoaderLoadHeader) && Sections[0].VirtualAddress != 0) { + LoadedHeaderSize = Context->SizeOfHeaders - Context->TeStrippedOffset; + CopyMem (Context->ImageBuffer, Context->FileBuffer, LoadedHeaderSize); + } else { + LoadedHeaderSize = 0; + } + // + // Load all Image sections into the memory space. + // + InternalLoadSections (Context, LoadedHeaderSize, DestinationSize); + + return RETURN_SUCCESS; +} + +RETURN_STATUS +PeCoffLoadImageInplaceNoBase ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context + ) +{ + UINT32 NumberOfSections; + CONST EFI_IMAGE_SECTION_HEADER *Sections; + UINT32 AlignedSize; + UINT16 SectionIndex; + CHAR8 *ImageBuffer; + + ASSERT (Context != NULL); + + NumberOfSections = PeCoffGetSectionTable (Context, &Sections); + // + // Verify all RVAs and raw file offsets are identical for XIP Images. + // + for (SectionIndex = 0; SectionIndex < NumberOfSections; ++SectionIndex) { + AlignedSize = ALIGN_VALUE ( + Sections[SectionIndex].VirtualSize, + Context->SectionAlignment + ); + if (Sections[SectionIndex].PointerToRawData != Sections[SectionIndex].VirtualAddress + || Sections[SectionIndex].SizeOfRawData != AlignedSize) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + } + + ImageBuffer = (CHAR8 *) Context->FileBuffer; + if (!PcdGetBool (PcdImageLoaderProhibitTe)) { + // FIXME: Abstract all accesses to ImageBuffer for safety? + // + // TE XIP Images are padded to be aligned such that their Image sections + // are correctly aligned. ImageBuffer is used exclusively to accesses RVAs, + // which for TE XIP Images are always off by Context->TeStrippedOffset. + // There is no other way but to treat the data in front of the TE Image + // Header as a part of the TE Image Header. + // + ImageBuffer -= Context->TeStrippedOffset; + } else { + ASSERT (Context->ImageType != PeCoffLoaderTypeTe); + } + + Context->ImageBuffer = ImageBuffer; + + return RETURN_SUCCESS; +} + +BOOLEAN +PeCoffImageIsInplace ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context + ) +{ + UINT64 ImageBase; + + ASSERT (Context != NULL); + + ImageBase = PeCoffGetImageBase (Context); + + if (!PcdGetBool (PcdImageLoaderProhibitTe)) { + ImageBase += Context->TeStrippedOffset; + } else { + ASSERT (Context->TeStrippedOffset == 0); + } + // + // Verify the Image is located at its preferred load address. + // + return ImageBase == (UINTN) Context->FileBuffer; +} + +RETURN_STATUS +PeCoffLoadImageInplace ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context + ) +{ + BOOLEAN Result; + + ASSERT (Context != NULL); + + Result = PeCoffImageIsInplace (Context); + if (!Result) { + DEBUG_RAISE (); + return RETURN_UNSUPPORTED; + } + + return PeCoffLoadImageInplaceNoBase (Context); +} + +// +// FIXME: Provide a runtime version of this API as well. +// +VOID +PeCoffDiscardSections ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context + ) +{ + CONST EFI_IMAGE_SECTION_HEADER *Sections; + UINT32 SectionIndex; + + ASSERT (Context != NULL); + // + // By the PE/COFF specification, the .reloc section is supposed to be + // discardable, so we must assume it is no longer valid. + // + Context->RelocDirRva = 0; + Context->RelocDirSize = 0; + // + // Zero all Image sections that are flagged as discardable. + // + Sections = (CONST EFI_IMAGE_SECTION_HEADER *) (CONST VOID *) ( + (CONST CHAR8 *) Context->FileBuffer + Context->SectionsOffset + ); + for (SectionIndex = 0; SectionIndex < Context->NumberOfSections; ++SectionIndex) { + if ((Sections[SectionIndex].Characteristics & EFI_IMAGE_SCN_MEM_DISCARDABLE) != 0) { + ZeroMem ( + (CHAR8 *) Context->ImageBuffer + Sections[SectionIndex].VirtualAddress, + Sections[SectionIndex].VirtualSize + ); + } + } +} diff --git a/MdePkg/Library/BasePeCoffLib2/PeCoffRelocate.c b/MdePkg/Library/BasePeCoffLib2/PeCoffRelocate.c new file mode 100644 index 0000000000..78527b0ac3 --- /dev/null +++ b/MdePkg/Library/BasePeCoffLib2/PeCoffRelocate.c @@ -0,0 +1,938 @@ +/** @file + Implements APIs to relocate PE/COFF Images. + + Copyright (c) 2020 - 2021, Marvin Häuser. All rights reserved.
+ Copyright (c) 2020, Vitaly Cheptsov. All rights reserved.
+ Copyright (c) 2020, ISP RAS. All rights reserved.
+ Portions copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.
+ Portions copyright (c) 2008 - 2010, Apple Inc. All rights reserved.
+ Portions copyright (c) 2020, Hewlett Packard Enterprise Development LP. All rights reserved.
+ + SPDX-License-Identifier: BSD-3-Clause +**/ + +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include "BasePeCoffLib2Internals.h" + +struct PE_COFF_LOADER_RUNTIME_CONTEXT_ { + /// + /// The RVA of the Relocation Directory. + /// + UINT32 RelocDirRva; + /// + /// The size, in Bytes, of the Relocation Directory. + /// + UINT32 RelocDirSize; + /// + /// Information bookkept during the initial Image relocation. + /// + UINT64 FixupData[]; +}; + +// FIXME: Add RISC-V support. +/** + Returns whether the Base Relocation type is supported by this loader. + + @param[in] Type The type of the Base Relocation. +**/ +#define IMAGE_RELOC_TYPE_SUPPORTED(Type) \ + (((Type) == EFI_IMAGE_REL_BASED_ABSOLUTE) || \ + ((Type) == EFI_IMAGE_REL_BASED_HIGHLOW) || \ + ((Type) == EFI_IMAGE_REL_BASED_DIR64) || \ + ((PcdGet32 (PcdImageLoaderRelocTypePolicy) & PCD_RELOC_TYPE_POLICY_ARM) != 0 && (Type) == EFI_IMAGE_REL_BASED_ARM_MOV32T)) + +/** + Returns whether the Base Relocation is supported by this loader. + + @param[in] Relocation The composite Base Relocation value. +**/ +#define IMAGE_RELOC_SUPPORTED(Relocation) \ + IMAGE_RELOC_TYPE_SUPPORTED (IMAGE_RELOC_TYPE (Reloc)) + +/** + Retrieve the immediate data encoded in an ARM MOVT or MOVW immediate + instruciton. + + @param[in] Instruction Pointer to an ARM MOVT or MOVW immediate instruction. + + @returns The Immediate address encoded in the instruction. +**/ +STATIC +UINT16 +ThumbMovtImmediateAddress ( + IN CONST VOID *Instruction + ) +{ + UINT32 Movt; + UINT16 Movt1; + UINT16 Movt2; + UINT16 Address; + // + // Thumb2 is two separate 16-bit instructions working together, e.g. + // MOVT R0, #0 is 0x0000f2c0 or 0xf2c0 0x0000 + // + Movt1 = *(CONST UINT16 *) (CONST VOID *) Instruction; + Movt2 = *(CONST UINT16 *) (CONST VOID *) ((CONST CHAR8 *) Instruction + sizeof (UINT16)); + Movt = ((UINT32) Movt1 << 16U) | (UINT32) Movt2; + // + // imm16 = imm4:i:imm3:imm8 + // imm4 -> Bit19:Bit16 + // i -> Bit26 + // imm3 -> Bit14:Bit12 + // imm8 -> Bit7:Bit0 + // + Address = (UINT16) (Movt & 0x000000FFU); // imm8 + Address |= (UINT16) ((Movt >> 4U) & 0x0000F700U); // imm4 imm3 + Address |= (UINT16) ((Movt & BIT26) >> 15U); // i, Bit26->11 + + return Address; +} + +/** + Update an ARM MOVT or MOVW immediate instruction immediate data. + + @param[in,out] Instruction Pointer to an ARM MOVT or MOVW immediate + instruction. + @param[in] Address New address to patch into the instruction. +**/ +STATIC +VOID +ThumbMovtImmediatePatch ( + IN OUT VOID *Instruction, + IN UINT16 Address + ) +{ + UINT16 Patch; + UINT16 PatchedInstruction; + // + // First 16-bit chunk of instruction. + // + Patch = (Address & 0xF000U) >> 12U; // imm4 + Patch |= (Address & BIT11) >> 1U; // i, Bit11->10 + // + // Mask out instruction bits and or in address. + // + PatchedInstruction = *(CONST UINT16 *) (CONST VOID *) Instruction; + *(UINT16 *) (VOID *) Instruction = (PatchedInstruction & ~(UINT16) 0x040FU) | Patch; + // + // Second 16-bit chunk of instruction. + // + Patch = Address & 0x000000FFU; // imm8 + Patch |= ((UINT32) Address << 4U) & 0x00007000U; // imm3 + // + // Mask out instruction bits and or in address. + // + PatchedInstruction = *(CONST UINT16 *) (CONST VOID *) ((CHAR8 *) Instruction + sizeof (UINT16)); + *(UINT16 *) (VOID *) ((CHAR8 *) Instruction + sizeof (UINT16)) = + (PatchedInstruction & ~(UINT16) 0x70FFU) | Patch; +} + +UINT32 +PeCoffThumbMovwMovtImmediateAddress ( + IN CONST VOID *Instructions + ) +{ + CONST CHAR8 *Word; + CONST CHAR8 *Top; + // + // Calculate the encoded address of the instruction pair. + // + Word = Instructions; // MOVW + Top = (CONST CHAR8 *) Instructions + 2 * sizeof (UINT16); // MOVT + + return (UINT32) (((UINT32) ThumbMovtImmediateAddress (Top) << 16U) | ThumbMovtImmediateAddress (Word)); +} + +/** + Update an ARM MOVW/MOVT immediate instruction instruction pair. + + @param[in,out] Instructions Pointer to ARM MOVW/MOVT instruction pair. + @param[in] Address New address to patch into the instructions. +**/ +STATIC +VOID +ThumbMovwMovtImmediatePatch ( + IN OUT VOID *Instructions, + IN UINT32 Address + ) +{ + CHAR8 *Word; + CHAR8 *Top; + // + // Patch the instruction pair's encoded address. + // + Word = Instructions; // MOVW + Top = (CHAR8 *) Instructions + 2 * sizeof (UINT16); // MOVT + + ThumbMovtImmediatePatch (Word, (UINT16) (Address & 0x0000FFFFU)); + ThumbMovtImmediatePatch (Top, (UINT16) ((Address & 0xFFFF0000U) >> 16U)); +} + +/** + Relocate an ARM MOVW/MOVT immediate instruction instruction pair. + + @param[in,out] Instructions Pointer to ARM MOVW/MOVT instruction pair. + @param[in] Adjust The delta to add to the addresses. +**/ +VOID +PeCoffThumbMovwMovtImmediateFixup ( + IN OUT VOID *Instructions, + IN UINT64 Adjust + ) +{ + UINT32 Fixup32; + // + // Relocate the instruction pair. + // + Fixup32 = PeCoffThumbMovwMovtImmediateAddress (Instructions) + (UINT32) Adjust; + ThumbMovwMovtImmediatePatch (Instructions, Fixup32); +} + +/** + Apply an Image Base Relocation. + + Only a subset of the PE/COFF Base Relocation types are permited. + The Base Relocation target must be in bounds, aligned, and must not overlap + with the Relocation Directory. + + @param[in] Context The context describing the Image. Must have been + loaded by PeCoffLoadImage(). + @param[in] RelocBlock The Base Relocation Block to apply from. + @param[in] RelocIndex The index of the Base Relocation to apply. + @param[in] Adjust The delta to add to the addresses. + @param[out] FixupData On input, a pointer to a bookkeeping value or NULL. + On output, a value to preserve for Image runtime + relocation. + + @retval RETURN_SUCCESS The Base Relocation has been applied successfully. + @retval other The Base Relocation could not be applied successfully. +**/ +STATIC +RETURN_STATUS +InternalApplyRelocation ( + IN CONST PE_COFF_LOADER_IMAGE_CONTEXT *Context, + IN CONST EFI_IMAGE_BASE_RELOCATION_BLOCK *RelocBlock, + IN UINT32 RelocIndex, + IN UINT64 Adjust, + OUT UINT64 *FixupData OPTIONAL + ) +{ + BOOLEAN Overflow; + + UINT16 RelocType; + UINT16 RelocOffset; + UINT32 RelocTargetRva; + UINT32 RemRelocTargetSize; + + CHAR8 *Fixup; + UINT32 Fixup32; + UINT64 Fixup64; + + RelocType = IMAGE_RELOC_TYPE (RelocBlock->Relocations[RelocIndex]); + RelocOffset = IMAGE_RELOC_OFFSET (RelocBlock->Relocations[RelocIndex]); + // + // Absolute Base Relocations are used for padding any must be skipped. + // + if (RelocType == EFI_IMAGE_REL_BASED_ABSOLUTE) { + if (FixupData != NULL) { + FixupData[RelocIndex] = 0; + } + + return RETURN_SUCCESS; + } + // + // Verify the Base Relocation target address is in bounds of the Image buffer. + // + Overflow = BaseOverflowAddU32 ( + RelocBlock->VirtualAddress, + RelocOffset, + &RelocTargetRva + ); + if (Overflow) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + + Overflow = BaseOverflowSubU32 ( + Context->SizeOfImage, + RelocTargetRva, + &RemRelocTargetSize + ); + if (Overflow) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + + Fixup = (CHAR8 *) Context->ImageBuffer + RelocTargetRva; + // + // Apply the Base Relocation fixup per type. + // If RuntimeContext is not NULL, store the current value of the fixup + // target to determine whether it has been changed during runtime + // execution. + // + // It is not clear how EFI_IMAGE_REL_BASED_HIGH and + // EFI_IMAGE_REL_BASED_LOW are supposed to be handled. While the PE + // specification suggests to just add the high or low part of the + // displacement, there are concerns about how it's supposed to deal with + // wraparounds. As they are virtually non-existent, they are unsupported for + // the time being. + // + switch (RelocType) { + case EFI_IMAGE_REL_BASED_HIGHLOW: + // + // Verify the Base Relocation target is in bounds of the Image buffer. + // + if (sizeof (UINT32) > RemRelocTargetSize) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + // + // Verify the Image Base Relocation does not target the Image Relocation + // Directory. + // + if (RelocTargetRva + sizeof (UINT32) > Context->RelocDirRva + && Context->RelocDirRva + Context->RelocDirSize > RelocTargetRva) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + // + // Relocate the target instruction. + // + Fixup32 = ReadUnaligned32 ((CONST VOID *) Fixup); + Fixup32 += (UINT32) Adjust; + WriteUnaligned32 ((VOID *) Fixup, Fixup32); + // + // Record the relocated value for Image runtime relocation. + // + if (FixupData != NULL) { + FixupData[RelocIndex] = Fixup32; + } + + break; + + case EFI_IMAGE_REL_BASED_DIR64: + // + // Verify the Image Base Relocation target is in bounds of the Image + // buffer. + // + if (sizeof (UINT64) > RemRelocTargetSize) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + // + // Verify the Image Base Relocation does not target the Image Relocation + // Directory. + // + if (RelocTargetRva + sizeof (UINT64) > Context->RelocDirRva + && Context->RelocDirRva + Context->RelocDirSize > RelocTargetRva) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + // + // Relocate target the instruction. + // + Fixup64 = ReadUnaligned64 ((CONST VOID *) Fixup); + Fixup64 += Adjust; + WriteUnaligned64 ((VOID *) Fixup, Fixup64); + // + // Record the relocated value for Image runtime relocation. + // + if (FixupData != NULL) { + FixupData[RelocIndex] = Fixup64; + } + + break; + + case EFI_IMAGE_REL_BASED_ARM_MOV32T: + // + // Verify ARM Thumb mode Base Relocations are supported. + // + if ((PcdGet32 (PcdImageLoaderRelocTypePolicy) & PCD_RELOC_TYPE_POLICY_ARM) == 0) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + // + // Verify the Base Relocation target is in bounds of the Image buffer. + // + if (sizeof (UINT64) > RemRelocTargetSize) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + // + // Verify the Base Relocation target is sufficiently aligned. + // The ARM Thumb instruction pair must start on a 16-bit boundary. + // + if (!IS_ALIGNED (RelocTargetRva, ALIGNOF (UINT16))) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + // + // Verify the Base Relocation does not target the Relocation Directory. + // + if (RelocTargetRva + sizeof (UINT64) > Context->RelocDirRva + && Context->RelocDirRva + Context->RelocDirSize > RelocTargetRva) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + // + // Relocate the target instruction. + // + PeCoffThumbMovwMovtImmediateFixup (Fixup, Adjust); + // + // Record the relocated value for Image runtime relocation. + // + if (FixupData != NULL) { + FixupData[RelocIndex] = ReadUnaligned64 ((CONST VOID *) Fixup); + } + + break; + + default: + // + // The Image Base Relocation type is unknown, disallow the Image. + // + DEBUG_RAISE (); + return RETURN_UNSUPPORTED; + } + + return RETURN_SUCCESS; +} + +RETURN_STATUS +PeCoffRelocateImage ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context, + IN UINT64 BaseAddress, + OUT PE_COFF_LOADER_RUNTIME_CONTEXT *RuntimeContext OPTIONAL, + IN UINT32 RuntimeContextSize + ) +{ + RETURN_STATUS Status; + BOOLEAN Overflow; + + UINT64 Adjust; + + UINT32 RelocBlockOffsetMax; + UINT32 TopOfRelocDir; + + UINT32 RelocBlockOffset; + CONST EFI_IMAGE_BASE_RELOCATION_BLOCK *RelocBlock; + UINT32 RelocBlockSize; + UINT32 SizeOfRelocs; + UINT32 NumRelocs; + UINT32 RelocIndex; + UINT32 FixupDataIndex; + UINT64 *CurrentFixupData; + + ASSERT (Context != NULL); + ASSERT (!Context->RelocsStripped || BaseAddress == Context->ImageBase); + ASSERT (RuntimeContext != NULL || RuntimeContextSize == 0); + ASSERT (RuntimeContext == NULL || RuntimeContextSize >= sizeof (PE_COFF_LOADER_RUNTIME_CONTEXT) + Context->RelocDirSize * (sizeof (UINT64) / sizeof (UINT16))); + // + // Initialise the Image runtime context header. + // + if (RuntimeContext != NULL) { + RuntimeContext->RelocDirRva = Context->RelocDirRva; + RuntimeContext->RelocDirSize = Context->RelocDirSize; + } + // + // Verify the Relocation Directory is not empty. + // + if (Context->RelocDirSize == 0) { + return RETURN_SUCCESS; + } + // + // Calculate the Image displacement from its prefered load address. + // + Adjust = BaseAddress - Context->ImageBase; + // + // Runtime drivers should unconditionally go through the full Relocation + // procedure early to eliminate the possibility of errors later at runtime. + // Runtime drivers don't have their Base Relocations stripped, this is + // verified during context creation. + // Skip explicit Relocation when the Image is already loaded at its + // prefered location. + // + if (RuntimeContext == NULL && Adjust == 0) { + return RETURN_SUCCESS; + } + + RelocBlockOffset = Context->RelocDirRva; + TopOfRelocDir = Context->RelocDirRva + Context->RelocDirSize; + RelocBlockOffsetMax = TopOfRelocDir - sizeof (EFI_IMAGE_BASE_RELOCATION_BLOCK); + FixupDataIndex = 0; + // + // Align TopOfRelocDir because, if the policy does not demand Relocation Block + // sizes to be aligned, the code below will manually align them. Thus, the + // end offset of the last Relocation Block must be compared to a manually + // aligned Relocation Directoriy end offset. + // + if ((PcdGet32 (PcdImageLoaderAlignmentPolicy) & PCD_ALIGNMENT_POLICY_RELOCATION_BLOCK_SIZES) != 0) { + Overflow = BaseOverflowAlignUpU32 ( + TopOfRelocDir, + ALIGNOF (EFI_IMAGE_BASE_RELOCATION_BLOCK), + &TopOfRelocDir + ); + if (Overflow) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + } + // + // Apply all Base Relocations of the Image. + // + while (RelocBlockOffset <= RelocBlockOffsetMax) { + RelocBlock = (CONST EFI_IMAGE_BASE_RELOCATION_BLOCK *) (CONST VOID *) ( + (CONST CHAR8 *) Context->ImageBuffer + RelocBlockOffset + ); + // + // Verify the Base Relocation Block size is well-formed. + // + Overflow = BaseOverflowSubU32 ( + RelocBlock->SizeOfBlock, + sizeof (EFI_IMAGE_BASE_RELOCATION_BLOCK), + &SizeOfRelocs + ); + if (Overflow) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + // + // Verify the Base Relocation Block is in bounds of the Relocation + // Directory. + // + if (SizeOfRelocs > RelocBlockOffsetMax - RelocBlockOffset) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + // + // Advance to the next Base Relocation Block offset based on the alignment + // policy. + // + if ((PcdGet32 (PcdImageLoaderAlignmentPolicy) & PCD_ALIGNMENT_POLICY_RELOCATION_BLOCK_SIZES) == 0) { + RelocBlockSize = RelocBlock->SizeOfBlock; + // + // Verify the next Base Relocation Block offset is sufficiently aligned. + // + if (!IS_ALIGNED (RelocBlockSize, ALIGNOF (EFI_IMAGE_BASE_RELOCATION_BLOCK))) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + } else { + // + // This arithmetic cannot overflow because we know + // 1) RelocBlock->SizeOfBlock <= RelocMax <= TopOfRelocDir + // 2) IS_ALIGNED (TopOfRelocDir, ALIGNOF (EFI_IMAGE_BASE_RELOCATION_BLOCK)). + // + RelocBlockSize = ALIGN_VALUE ( + RelocBlock->SizeOfBlock, + ALIGNOF (EFI_IMAGE_BASE_RELOCATION_BLOCK) + ); + } + // + // This division is safe due to the guarantee made above. + // + NumRelocs = SizeOfRelocs / sizeof (*RelocBlock->Relocations); + + if (RuntimeContext != NULL) { + CurrentFixupData = &RuntimeContext->FixupData[FixupDataIndex]; + // + // This arithmetic cannot overflow because The number of Image Base + // Relocations cannot exceed the size of their Image Relocation Block, and + // latter has been verified to be in bounds of the Image buffer. The Image + // buffer size and RelocDataIndex are both bound by MAX_UINT32. + // + FixupDataIndex += NumRelocs; + } else { + CurrentFixupData = NULL; + } + // + // Process all Base Relocations of the current Block. + // + for (RelocIndex = 0; RelocIndex < NumRelocs; ++RelocIndex) { + // + // Apply the Image Base Relocation fixup. + // If RuntimeContext is not NULL, store the current value of the fixup + // target to determine whether it has been changed during runtime + // execution. + // + // It is not clear how EFI_IMAGE_REL_BASED_HIGH and + // EFI_IMAGE_REL_BASED_LOW are supposed to be handled. While PE reference + // suggests to just add the high or low part of the displacement, there + // are concerns about how it's supposed to deal with wraparounds. + // As no known linker emits them, omit support. + // + Status = InternalApplyRelocation ( + Context, + RelocBlock, + RelocIndex, + Adjust, + CurrentFixupData + ); + if (Status != RETURN_SUCCESS) { + DEBUG_RAISE (); + return Status; + } + } + // + // This arithmetic cannot overflow because it has been checked that the + // Image Base Relocation Block is in bounds of the Image buffer. + // + RelocBlockOffset += RelocBlockSize; + } + // + // Verify the Relocation Directory size matches the contained data. + // + if (RelocBlockOffset != TopOfRelocDir) { + DEBUG_RAISE (); + return RETURN_VOLUME_CORRUPTED; + } + // + // Initialise the remaining uninitialised portion of the Image runtime + // context. + // + if (RuntimeContext != NULL) { + // + // This arithmetic cannot overflow due to the guarantee given by + // PeCoffLoaderGetRuntimeContextSize(). + // + ZeroMem ( + &RuntimeContext->FixupData[FixupDataIndex], + RuntimeContextSize - sizeof (PE_COFF_LOADER_RUNTIME_CONTEXT) - FixupDataIndex * sizeof (UINT64) + ); + } + + return RETURN_SUCCESS; +} + +/** + Apply an Image Base Relocation for Image runtime relocation. + + Well-formedness has been verified by PeCoffRelocateImage() previously. + Fails if the Relocation target value has changed since PeCoffRelocateImage(). + + @param[in] Image The Image destination memory. Must have been relocated + by PeCoffRelocateImage(). + @param[in] RelocBlock The Base Relocation Block to apply from. + @param[in] RelocIndex The index of the Base Relocation to apply. + @param[in] Adjust The delta to add to the addresses. + @param[out] FixupData The bookkeeping value. + + @retval RETURN_SUCCESS The Base Relocation has been applied successfully. + @retval other The Base Relocation could not be applied successfully. +**/ +STATIC +RETURN_STATUS +InternalApplyRelocationRuntime ( + IN OUT VOID *Fixup, + IN UINT16 RelocType, + IN UINT64 Adjust, + IN UINT64 FixupData + ) +{ + UINT32 Fixup32; + UINT64 Fixup64; + + ASSERT (Fixup != NULL); + ASSERT (IMAGE_RELOC_TYPE_SUPPORTED (RelocType) + && RelocType != EFI_IMAGE_REL_BASED_ABSOLUTE); + // + // Apply the Image Base Relocation fixup per type. + // + // If the Image relocation target value has changes since the initial + // Image relocation, skip or abort based on the policy. The fixup cannot + // be applies safely as the value might not reference an address within + // the Image memory space, e.g. when a global variable pointer to another + // variable is changed during runtime. + // + switch (RelocType) { + case EFI_IMAGE_REL_BASED_HIGHLOW: + Fixup32 = ReadUnaligned32 ((CONST VOID *) Fixup); + // + // If the Image relocation target value mismatches, skip or abort. + // + if (FixupData != Fixup32) { + if (PcdGetBool (PcdImageLoaderRtRelocAllowTargetMismatch)) { + return RETURN_SUCCESS; + } + + return RETURN_VOLUME_CORRUPTED; + } + + Fixup32 += (UINT32) Adjust; + WriteUnaligned32 (Fixup, Fixup32); + + break; + + case EFI_IMAGE_REL_BASED_DIR64: + Fixup64 = ReadUnaligned64 (Fixup); + // + // If the Image relocation target value mismatches, skip or abort. + // + if (FixupData != Fixup64) { + if (PcdGetBool (PcdImageLoaderRtRelocAllowTargetMismatch)) { + return RETURN_SUCCESS; + } + + return RETURN_VOLUME_CORRUPTED; + } + + Fixup64 += Adjust; + WriteUnaligned64 (Fixup, Fixup64); + + break; + + case EFI_IMAGE_REL_BASED_ARM_MOV32T: + ASSERT ((PcdGet32 (PcdImageLoaderRelocTypePolicy) & PCD_RELOC_TYPE_POLICY_ARM) != 0); + + Fixup64 = ReadUnaligned64 (Fixup); + // + // If the Image relocation target value mismatches, skip or abort. + // + if (FixupData != Fixup64) { + if (PcdGetBool (PcdImageLoaderRtRelocAllowTargetMismatch)) { + return RETURN_SUCCESS; + } + + return RETURN_VOLUME_CORRUPTED; + } + + PeCoffThumbMovwMovtImmediateFixup (Fixup, Adjust); + + break; + + default: + // + // Invalid Base Relocation types would have caused the Image to not be + // loaded relocated successfully earlier. + // + ASSERT (FALSE); + } + + return RETURN_SUCCESS; +} + +RETURN_STATUS +PeCoffLoaderGetRuntimeContextSize ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context, + OUT UINT32 *Size + ) +{ + BOOLEAN Overflow; + UINT32 FixupDataSize; + + ASSERT (Context != NULL); + ASSERT (!Context->RelocsStripped); + ASSERT (Size != NULL); + + // + // Because the ImageBase Relocations have not been stripped, + // PeCoffInitializeContext() has verified the Relocation Directory exists and + // is valid. + // + + // + // Request 64-bit of source value per 16-bit Base Relocation. + // This allocates too many Bytes because it assumes that every Base Relocation + // refers to a 64-bit target and does not account for Base Relocation Block + // headers. + // + Overflow = BaseOverflowMulU32 ( + Context->RelocDirSize, + sizeof (UINT64) / sizeof (UINT16), + &FixupDataSize + ); + if (Overflow) { + return RETURN_UNSUPPORTED; + } + + Overflow = BaseOverflowAddU32 ( + FixupDataSize, + sizeof (PE_COFF_LOADER_RUNTIME_CONTEXT), + Size + ); + if (Overflow) { + return RETURN_UNSUPPORTED; + } + + return RETURN_SUCCESS; +} + +RETURN_STATUS +PeCoffRuntimeRelocateImage ( + IN OUT VOID *Image, + IN UINT32 ImageSize, + IN UINT64 BaseAddress, + IN CONST PE_COFF_LOADER_RUNTIME_CONTEXT *RuntimeContext + ) +{ + RETURN_STATUS Status; + + UINTN ImageAddress; + UINT32 FixupDataIndex; + CONST EFI_IMAGE_BASE_RELOCATION_BLOCK *RelocBlock; + UINT64 Adjust; + + UINT32 TopOfRelocDir; + UINT32 RelocBlockOffset; + UINT32 SizeOfRelocs; + UINT32 NumRelocs; + UINT32 RelocIndex; + UINT32 RelocTarget; + UINT32 RelocOffset; + UINT32 RelocBlockSize; + + (VOID) ImageSize; + + ASSERT (Image != NULL); + ASSERT (BaseAddress != 0); + ASSERT (RuntimeContext != NULL); + // + // If the relocation directory is empty, skip relocation. + // + if (RuntimeContext->RelocDirSize == 0) { + return RETURN_SUCCESS; + } + + // + // The arithmetics in this function generally cannot overflow due to the + // guarantees given by PeCoffRelocateImage(). + // + + ImageAddress = (UINTN) Image; + Adjust = BaseAddress - ImageAddress; + // + // If the Image remains at the current address, skip relocation. + // + if (Adjust == 0) { + return RETURN_SUCCESS; + } + // + // Apply all Base Relocations of the Image. + // + RelocBlockOffset = RuntimeContext->RelocDirRva; + TopOfRelocDir = RuntimeContext->RelocDirRva + RuntimeContext->RelocDirSize; + FixupDataIndex = 0; + while (RelocBlockOffset < TopOfRelocDir) { + ASSERT (IS_ALIGNED (RelocBlockOffset, ALIGNOF (EFI_IMAGE_BASE_RELOCATION_BLOCK))); + + RelocBlock = (CONST EFI_IMAGE_BASE_RELOCATION_BLOCK *) (CONST VOID *) ( + (CONST CHAR8 *) Image + RelocBlockOffset + ); + + STATIC_ASSERT ( + (sizeof (UINT32) % ALIGNOF (EFI_IMAGE_BASE_RELOCATION_BLOCK)) == 0, + "The following accesses must be performed unaligned." + ); + + ASSERT (sizeof (EFI_IMAGE_BASE_RELOCATION_BLOCK) <= RelocBlock->SizeOfBlock); + // + // Determine the number of Image Base Relocations in this Block. + // + SizeOfRelocs = RelocBlock->SizeOfBlock - sizeof (EFI_IMAGE_BASE_RELOCATION_BLOCK); + NumRelocs = SizeOfRelocs / sizeof (*RelocBlock->Relocations); + // + // Apply all Image Base Relocation fixups of the current Image Base + // Relocation Block. + // + for (RelocIndex = 0; RelocIndex < NumRelocs; ++RelocIndex) { + // + // Skip Absolute Image Base Relocations. + // + if (IMAGE_RELOC_TYPE (RelocBlock->Relocations[RelocIndex]) == EFI_IMAGE_REL_BASED_ABSOLUTE) { + ++FixupDataIndex; + continue; + } + // + // Determine the Image Base Relocation target address. + // + RelocOffset = IMAGE_RELOC_OFFSET (RelocBlock->Relocations[RelocIndex]); + ASSERT (RelocOffset <= RelocBlock->VirtualAddress + RelocOffset); + // + // Apply the Image Base Relocation fixup. + // + RelocTarget = RelocBlock->VirtualAddress + RelocOffset; + Status = InternalApplyRelocationRuntime ( + (CHAR8 *) Image + RelocTarget, + IMAGE_RELOC_TYPE (RelocBlock->Relocations[RelocIndex]), + Adjust, + RuntimeContext->FixupData[FixupDataIndex] + ); + // + // If the original Image Relocation target value mismatches the expected + // value, and the policy demands it, report an error. + // + if (!PcdGetBool (PcdImageLoaderRtRelocAllowTargetMismatch)) { + if (Status != RETURN_SUCCESS) { + return Status; + } + } else { + ASSERT (Status == RETURN_SUCCESS); + } + + ++FixupDataIndex; + } + // + // Advance to the next Base Relocation Block based on the alignment policy. + // + if ((PcdGet32 (PcdImageLoaderAlignmentPolicy) & PCD_ALIGNMENT_POLICY_RELOCATION_BLOCK_SIZES) == 0) { + RelocBlockSize = RelocBlock->SizeOfBlock; + ASSERT (IS_ALIGNED (RelocBlockSize, ALIGNOF (EFI_IMAGE_BASE_RELOCATION_BLOCK))); + } else { + RelocBlockSize = ALIGN_VALUE ( + RelocBlock->SizeOfBlock, + ALIGNOF (EFI_IMAGE_BASE_RELOCATION_BLOCK) + ); + } + + RelocBlockOffset += RelocBlockSize; + } + // + // Align TopOfRelocDir because, if the policy does not demand Relocation Block + // sizes to be aligned, the code below will manually align them. Thus, the + // end offset of the last Relocation Block must be compared to a manually + // aligned Relocation Directoriy end offset. + // + if ((PcdGet32 (PcdImageLoaderAlignmentPolicy) & PCD_ALIGNMENT_POLICY_RELOCATION_BLOCK_SIZES) != 0) { + TopOfRelocDir = ALIGN_VALUE (TopOfRelocDir, ALIGNOF (EFI_IMAGE_BASE_RELOCATION_BLOCK)); + } + // + // This condition is verified by PeCoffRelocateImage(). + // + ASSERT (RelocBlockOffset == TopOfRelocDir); + + return RETURN_SUCCESS; +} + +RETURN_STATUS +PeCoffRelocateImageInplace ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context + ) +{ + RETURN_STATUS Status; + UINTN NewBase; + + Status = PeCoffLoadImageInplaceNoBase (Context); + if (RETURN_ERROR (Status)) { + DEBUG_RAISE (); + return Status; + } + + NewBase = PeCoffLoaderGetImageAddress (Context); + + Status = PeCoffRelocateImage (Context, NewBase, NULL, 0); + if (RETURN_ERROR (Status)) { + DEBUG_RAISE (); + } + + return Status; +} diff --git a/MdePkg/Library/BaseUefiImageExtraActionLibNull/BaseUefiImageExtraActionLibNull.inf b/MdePkg/Library/BaseUefiImageExtraActionLibNull/BaseUefiImageExtraActionLibNull.inf new file mode 100644 index 0000000000..125733a234 --- /dev/null +++ b/MdePkg/Library/BaseUefiImageExtraActionLibNull/BaseUefiImageExtraActionLibNull.inf @@ -0,0 +1,33 @@ +## @file +# Null PE/Coff Extra Action library instances with empty functions. +# +# Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = UefiImageExtraActionLibNull + MODULE_UNI_FILE = UefiImageExtraActionLibNull.uni + FILE_GUID = 0EB84DA1-267A-40b4-8347-1F48694C8B47 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = UefiImageExtraActionLib + + +# +# VALID_ARCHITECTURES = IA32 X64 EBC +# + +[Sources] + UefiImageExtraActionLib.c + +[Packages] + MdePkg/MdePkg.dec + +[LibraryClasses] + DebugLib + diff --git a/MdePkg/Library/BaseUefiImageExtraActionLibNull/UefiImageExtraActionLib.c b/MdePkg/Library/BaseUefiImageExtraActionLibNull/UefiImageExtraActionLib.c new file mode 100644 index 0000000000..d134a48810 --- /dev/null +++ b/MdePkg/Library/BaseUefiImageExtraActionLibNull/UefiImageExtraActionLib.c @@ -0,0 +1,48 @@ +/** @file + Null PE/Coff Extra Action library instances with empty functions. + + Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include + +/** + Performs additional actions after a PE/COFF image has been loaded and relocated. + + If ImageContext is NULL, then ASSERT(). + + @param ImageContext The pointer to the image context structure that describes the + PE/COFF image that has already been loaded and relocated. + +**/ +VOID +EFIAPI +UefiImageLoaderRelocateImageExtraAction ( + IN CONST UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext + ) +{ + ASSERT (ImageContext != NULL); +} + +/** + Performs additional actions just before a PE/COFF image is unloaded. Any resources + that were allocated by UefiImageLoaderRelocateImageExtraAction() must be freed. + + If ImageContext is NULL, then ASSERT(). + + @param ImageContext The pointer to the image context structure that describes the + PE/COFF image that is being unloaded. + +**/ +VOID +EFIAPI +UefiImageLoaderUnloadImageExtraAction ( + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext + ) +{ + ASSERT (ImageContext != NULL); +} diff --git a/MdePkg/Library/BaseUefiImageExtraActionLibNull/UefiImageExtraActionLibNull.uni b/MdePkg/Library/BaseUefiImageExtraActionLibNull/UefiImageExtraActionLibNull.uni new file mode 100644 index 0000000000..2ed84d48b8 --- /dev/null +++ b/MdePkg/Library/BaseUefiImageExtraActionLibNull/UefiImageExtraActionLibNull.uni @@ -0,0 +1,16 @@ +// /** @file +// Null PE/Coff Extra Action library instances with empty functions. +// +// Null PE/Coff Extra Action library instances with empty functions. +// +// Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.
+// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + + +#string STR_MODULE_ABSTRACT #language en-US "Null PE/Coff Extra Action library instances with empty functions" + +#string STR_MODULE_DESCRIPTION #language en-US "Null PE/Coff Extra Action library instances with empty functions." + diff --git a/MdePkg/Library/BaseUefiImageLib/BaseUefiImageLibPeCoff.inf b/MdePkg/Library/BaseUefiImageLib/BaseUefiImageLibPeCoff.inf new file mode 100644 index 0000000000..bfe7296e0d --- /dev/null +++ b/MdePkg/Library/BaseUefiImageLib/BaseUefiImageLibPeCoff.inf @@ -0,0 +1,40 @@ +## @file +# UEFI Image Loader library implementation for PE/COFF and TE Images. +# +# Copyright (c) 2021, Marvin Häuser. All rights reserved.
+# +# SPDX-License-Identifier: BSD-3-Clause +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = BaseUefiImageLibPeCoff + FILE_GUID = 357AD87E-8D6B-468A-B3FA-0D9CC4C725CD + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = UefiImageLib + +[Sources] + CommonSupport.c + ExecutionSupport.c + PeCoffSupport.h + PeCoffSupport.c + UefiImageLibPeCoff.c + +[Packages] + MdePkg/MdePkg.dec + +[LibraryClasses] + BaseLib + BaseOverflowLib + BaseMemoryLib + CacheMaintenanceLib + DebugLib + MemoryAllocationLib + PeCoffLib2 + UefiImageExtraActionLib + +[FixedPcd] + gEfiMdePkgTokenSpaceGuid.PcdImageLoaderAlignmentPolicy + gEfiMdePkgTokenSpaceGuid.PcdImageLoaderLoadHeader + gEfiMdePkgTokenSpaceGuid.PcdImageLoaderProhibitTe diff --git a/MdePkg/Library/BaseUefiImageLib/CommonSupport.c b/MdePkg/Library/BaseUefiImageLib/CommonSupport.c new file mode 100644 index 0000000000..70a191c2af --- /dev/null +++ b/MdePkg/Library/BaseUefiImageLib/CommonSupport.c @@ -0,0 +1,152 @@ +/** @file + Support for functions common to all Image formats. + + Copyright (c) 2021, Marvin Häuser. All rights reserved.
+ + SPDX-License-Identifier: BSD-3-Clause +**/ + +#include +#include +#include + +#include +#include +#include + +RETURN_STATUS +UefiImageInitializeContext ( + OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context, + IN CONST VOID *FileBuffer, + IN UINT32 FileSize + ) +{ + RETURN_STATUS Status; + + Status = UefiImageInitializeContextPreHash (Context, FileBuffer, FileSize); + if (RETURN_ERROR (Status)) { + return Status; + } + + return UefiImageInitializeContextPostHash (Context); +} + +UINTN +UefiImageLoaderGetImageEntryPoint ( + IN CONST UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context + ) +{ + UINTN ImageAddress; + UINT32 EntryPointAddress; + + ASSERT (Context != NULL); + + ImageAddress = UefiImageLoaderGetImageAddress (Context); + EntryPointAddress = UefiImageGetEntryPointAddress (Context); + + return ImageAddress + EntryPointAddress; +} + +// FIXME: Some image prints use this and some don't. Is this really needed? +RETURN_STATUS +UefiImageGetModuleNameFromSymbolsPath ( + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context, + OUT CHAR8 *ModuleName, + IN UINT32 ModuleNameSize + ) +{ + RETURN_STATUS Status; + CONST CHAR8 *SymbolsPath; + UINT32 SymbolsPathSize; + UINTN Index; + UINTN StartIndex; + + ASSERT (Context != NULL); + ASSERT (ModuleName != NULL); + ASSERT (3 <= ModuleNameSize); + + Status = UefiImageGetSymbolsPath ( + Context, + &SymbolsPath, + &SymbolsPathSize + ); + if (RETURN_ERROR (Status)) { + return Status; + } + // + // Find the last component of the symbols path, which is the file containing + // the debug symbols for the Image. + // + StartIndex = 0; + for ( + Index = 0; + Index < SymbolsPathSize && SymbolsPath[Index] != '\0'; + ++Index + ) { + if (SymbolsPath[Index] == '\\' || SymbolsPath[Index] == '/') { + StartIndex = Index + 1; + } + } + // + // Extract the module name from the debug symbols file and ensure the correct + // file extensions. + // + for ( + Index = 0; + Index < MIN (ModuleNameSize, SymbolsPathSize); + ++Index + ) { + ModuleName[Index] = SymbolsPath[Index + StartIndex]; + if (ModuleName[Index] == '\0') { + ModuleName[Index] = '.'; + } + if (ModuleName[Index] == '.') { + if (Index > ModuleNameSize - 3) { + break; + } + + ModuleName[Index + 1] = 'e'; + ModuleName[Index + 2] = 'f'; + ModuleName[Index + 3] = 'i'; + Index += 4; + break; + } + } + // + // Terminate the newly created module name string. + // + ModuleName[Index] = '\0'; + + return RETURN_SUCCESS; +} + +VOID +UefiImageDebugPrintImageRecord ( + IN CONST UEFI_IMAGE_RECORD *ImageRecord + ) +{ + UINT16 SegmentIndex; + UINTN SegmentAddress; + + ASSERT (ImageRecord != NULL); + + SegmentAddress = ImageRecord->StartAddress; + for ( + SegmentIndex = 0; + SegmentIndex < ImageRecord->NumSegments; + ++SegmentIndex + ) { + DEBUG (( + DEBUG_VERBOSE, + " RecordSegment\n" + " Address - 0x%016llx\n" + " Size - 0x%08x\n" + " Attributes - 0x%08x\n", + (UINT64) SegmentAddress, + ImageRecord->Segments[SegmentIndex].Size, + ImageRecord->Segments[SegmentIndex].Attributes + )); + + SegmentAddress += ImageRecord->Segments[SegmentIndex].Size; + } +} diff --git a/MdePkg/Library/BaseUefiImageLib/ExecutionSupport.c b/MdePkg/Library/BaseUefiImageLib/ExecutionSupport.c new file mode 100644 index 0000000000..63f5b00466 --- /dev/null +++ b/MdePkg/Library/BaseUefiImageLib/ExecutionSupport.c @@ -0,0 +1,113 @@ +/** @file + Support for functions common to all Image formats. + + Copyright (c) 2021, Marvin Häuser. All rights reserved.
+ + SPDX-License-Identifier: BSD-3-Clause +**/ + +#include +#include +#include + +#include +#include +#include +#include + +RETURN_STATUS +UefiImageRelocateImageInplaceForExecution ( + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context + ) +{ + RETURN_STATUS Status; + UINTN ImageAddress; + UINTN ImageSize; + + Status = UefiImageRelocateImageInplace (Context); + if (RETURN_ERROR (Status)) { + return Status; + } + + ImageAddress = UefiImageLoaderGetImageAddress (Context); + ImageSize = UefiImageGetImageSizeInplace (Context); + // + // Flush the instruction cache so the image data is written before + // execution. + // + InvalidateInstructionCacheRange ((VOID *) ImageAddress, ImageSize); + + return RETURN_SUCCESS; +} + +// FIXME: Check Subsystem here +RETURN_STATUS +UefiImageLoadImageForExecution ( + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context, + OUT VOID *Destination, + IN UINT32 DestinationSize, + OUT UEFI_IMAGE_LOADER_RUNTIME_CONTEXT *RuntimeContext OPTIONAL, + IN UINT32 RuntimeContextSize + ) +{ + RETURN_STATUS Status; + UINTN BaseAddress; + UINTN SizeOfImage; + // + // Load the Image into the memory space. + // + Status = UefiImageLoadImage (Context, Destination, DestinationSize); + if (RETURN_ERROR (Status)) { + return Status; + } + // + // Relocate the Image to the address it has been loaded to. + // + BaseAddress = UefiImageLoaderGetImageAddress (Context); + Status = UefiImageRelocateImage ( + Context, + BaseAddress, + RuntimeContext, + RuntimeContextSize + ); + if (RETURN_ERROR (Status)) { + return Status; + } + + SizeOfImage = UefiImageGetImageSize (Context); + // + // Flush the instruction cache so the image data is written before execution. + // + InvalidateInstructionCacheRange ((VOID *) BaseAddress, SizeOfImage); + + return RETURN_SUCCESS; +} + +RETURN_STATUS +UefiImageRuntimeRelocateImageForExecution ( + IN OUT VOID *Image, + IN UINT32 ImageSize, + IN UINT64 BaseAddress, + IN CONST UEFI_IMAGE_LOADER_RUNTIME_CONTEXT *RuntimeContext + ) +{ + RETURN_STATUS Status; + // + // Relocate the Image to the new address. + // + Status = UefiImageRuntimeRelocateImage ( + Image, + ImageSize, + BaseAddress, + RuntimeContext + ); + if (RETURN_ERROR (Status)) { + return Status; + } + // + // Flush the instruction cache so the image data is written before execution. + // + InvalidateInstructionCacheRange (Image, ImageSize); + + return RETURN_SUCCESS; +} diff --git a/MdePkg/Library/BaseUefiImageLib/PeCoffSupport.c b/MdePkg/Library/BaseUefiImageLib/PeCoffSupport.c new file mode 100644 index 0000000000..678c6b2b5a --- /dev/null +++ b/MdePkg/Library/BaseUefiImageLib/PeCoffSupport.c @@ -0,0 +1,511 @@ +/** @file + UEFI Image Loader library implementation for PE/COFF and TE Images. + + Copyright (c) 2021, Marvin Häuser. All rights reserved.
+ + SPDX-License-Identifier: BSD-3-Clause +**/ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + Retrieves the memory protection attributes corresponding to PE/COFF Image + section permissions. + + @param[in] Characteristics The PE/COFF Image section permissions + + @returns The memory protection attributes corresponding to the PE/COFF Image + section permissions. +**/ +STATIC +UINT32 +InternalCharacteristicsToAttributes ( + IN UINT32 Characteristics + ) +{ + UINT32 Attributes; + + Attributes = 0; + if ((Characteristics & EFI_IMAGE_SCN_MEM_READ) == 0) { + Attributes |= EFI_MEMORY_RP; + } + if ((Characteristics & EFI_IMAGE_SCN_MEM_EXECUTE) == 0) { + Attributes |= EFI_MEMORY_XP; + } + if ((Characteristics & EFI_IMAGE_SCN_MEM_WRITE) == 0) { + Attributes |= EFI_MEMORY_RO; + } + + return Attributes; +} + +/** + Index the read-only padding following an Image record section, if existent. + + @param[in,out] RecordSegment The Image record section for the current memory + protection range. May be extended if it is of + the same type as the adjacent padding. At least + one more record section must be reserved after + it in order to index the read-only padding. + @param[in] NextAddress The start address of the next memory permission + range. This may be the end address of the Image + in order to cover the Image trailer. + @param[in] EndAddress The end address of the current memory permission + range. This also denotes the start of the added + read-only padding. + @param[in] Attributes The memory protection attributes of the current + memory permission range. + + @returns The amount of Image record sections that have been appended. +**/ +STATIC +UINT8 +InternalInsertImageRecordSegmentPadding ( + IN OUT UEFI_IMAGE_RECORD_SEGMENT *RecordSegment, + IN UINT32 EndAddress, + IN UINT32 NextAddress, + IN UINT32 Attributes + ) +{ + ASSERT (RecordSegment != NULL); + ASSERT (EndAddress <= NextAddress); + + if (NextAddress == EndAddress) { + return 0; + } + // + // Add a new Image record section or expand the previous one depending on + // the the permissions of the previous Image record section. + // + if (Attributes == (EFI_MEMORY_XP | EFI_MEMORY_RO)) { + RecordSegment->Size += NextAddress - EndAddress; + + return 0; + } + + ++RecordSegment; + RecordSegment->Size = NextAddress - EndAddress; + RecordSegment->Attributes = EFI_MEMORY_XP | EFI_MEMORY_RO; + + return 1; +} + +UEFI_IMAGE_RECORD * +UefiImageLoaderGetImageRecordPeCoff ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context + ) +{ + UEFI_IMAGE_RECORD *ImageRecord; + UINT32 MaxNumRecordSegments; + UINT32 NumRecordSegments; + UEFI_IMAGE_RECORD_SEGMENT *RecordSegment; + UINTN ImageAddress; + UINT32 SizeOfImage; + UINT32 SectionAlignment; + CONST EFI_IMAGE_SECTION_HEADER *Sections; + UINT16 NumberOfSections; + UINT16 SectionIndex; + CONST EFI_IMAGE_SECTION_HEADER *Section; + UINT32 SectionAddress; + UINT32 SectionSize; + UINT32 SectionCharacteristics; + UINT32 StartAddress; + UINT32 EndAddress; + UINT32 Characteristics; + UINT32 Attributes; + + ASSERT (Context != NULL); + // + // Determine the maximum amount of Image record sections and allocate the + // Image record. + // + NumberOfSections = PeCoffGetSectionTable (Context, &Sections); + + STATIC_ASSERT ( + MAX_UINT16 <= MAX_UINT32 / 2 - 1, + "The following arithmetic may overflow." + ); + + if ((PcdGet32 (PcdImageLoaderAlignmentPolicy) & PCD_ALIGNMENT_POLICY_CONTIGUOUS_SECTIONS) == 0) { + // + // In case of contiguous Image sections, there can be two additional record + // sections (Image Headers and trailer, e.g. debug information). + // + MaxNumRecordSegments = (UINT32) NumberOfSections + 2; + } else { + // + // In case of possibly non-contiguous Image sections, there can be a trailer + // per Image section (the last Image section's trailer is the same as the + // Image trailer), as well as additionally the Image Headers. + // + MaxNumRecordSegments = (UINT32) NumberOfSections * 2 + 1; + } + + ImageRecord = AllocatePool ( + sizeof (*ImageRecord) + + MaxNumRecordSegments * sizeof (*ImageRecord->Segments) + ); + if (ImageRecord == NULL) { + DEBUG_RAISE (); + return NULL; + } + + ImageRecord->Signature = UEFI_IMAGE_RECORD_SIGNATURE; + InitializeListHead (&ImageRecord->Link); + + SectionAlignment = PeCoffGetSectionAlignment (Context); + // + // Map the Image Headers as read-only data. If the first Image section is + // loaded at the start of the Image memory space, the condition + // SectionAddress != StartAddress does not hold and these definitions will be + // ignored. + // + StartAddress = 0; + EndAddress = PeCoffGetSizeOfHeaders (Context); + Characteristics = EFI_IMAGE_SCN_MEM_READ; + Attributes = EFI_MEMORY_XP | EFI_MEMORY_RO; + ASSERT (Attributes == InternalCharacteristicsToAttributes (Characteristics)); + // + // Create an Image record section for every permission-distinct range of the + // Image. The current range [StartAddress, EndAddress) shares the memory + // permissions Charactersitics/Attributes and is extended till a new + // memory permission configuration is required. Headers and trailers treated + // as read-only data. + // + NumRecordSegments = 0; + for (SectionIndex = 0; SectionIndex < NumberOfSections; ++SectionIndex) { + Section = Sections + SectionIndex; + // + // Skip empty Image sections to avoid unnecessary splitting. + // + if (Section->VirtualSize == 0) { + continue; + } + // + // These arithmetics are safe as guaranteed by PeCoffInitializeContext(). + // + SectionAddress = Section->VirtualAddress; + SectionSize = ALIGN_VALUE (Section->VirtualSize, SectionAlignment); + SectionCharacteristics = Section->Characteristics & (EFI_IMAGE_SCN_MEM_EXECUTE | EFI_IMAGE_SCN_MEM_READ | EFI_IMAGE_SCN_MEM_WRITE); + // + // Skip Image sections with the same memory permissions as the current range + // as they can be merged. For this, the Image sections must be adjacent, or + // the range must have the same memory permissions as the padding inbetween + // (read-only). + // + if ((PcdGet32 (PcdImageLoaderAlignmentPolicy) & PCD_ALIGNMENT_POLICY_CONTIGUOUS_SECTIONS) == 0 + || SectionAddress == EndAddress + || Characteristics == EFI_IMAGE_SCN_MEM_READ) { + if (SectionCharacteristics == Characteristics) { + EndAddress = SectionAddress + SectionSize; + continue; + } + } + // + // Only create an entry if the range is not empty, otherwise discard it and + // start a new one. Even with skipping empty Image sections, this can still + // happen for the Image Headers when the first Image section starts at 0. + // + if (SectionAddress != StartAddress) { + // + // Create an Image record section for the current memory permission range. + // + RecordSegment = &ImageRecord->Segments[NumRecordSegments]; + RecordSegment->Size = EndAddress - StartAddress; + RecordSegment->Attributes = Attributes; + ++NumRecordSegments; + // + // If the previous range is not adjacent to the current Image section, + // report the padding as read-only data. + // + if ((PcdGet32 (PcdImageLoaderAlignmentPolicy) & PCD_ALIGNMENT_POLICY_CONTIGUOUS_SECTIONS) != 0) { + NumRecordSegments += InternalInsertImageRecordSegmentPadding ( + RecordSegment, + EndAddress, + SectionAddress, + Attributes + ); + } + + StartAddress = SectionAddress; + } + // + // Start a Image record section with the current Image section. + // + EndAddress = SectionAddress + SectionSize; + Characteristics = SectionCharacteristics; + Attributes = InternalCharacteristicsToAttributes (Characteristics); + } + // + // Image Record sections are only created once a non-empty Image section is + // encountered that requests a different memory permission configuration. + // As such, the last memory permission range is never converted in the loop. + // If the loop never produced such, this is true for the Image Headers, which + // cannot be empty. + // + ASSERT (StartAddress < EndAddress); + // + // Create an Image record section for the last Image memory permission range. + // + RecordSegment = &ImageRecord->Segments[NumRecordSegments]; + RecordSegment->Size = EndAddress - StartAddress; + RecordSegment->Attributes = Attributes; + ++NumRecordSegments; + + ImageAddress = PeCoffLoaderGetImageAddress (Context); + SizeOfImage = PeCoffGetSizeOfImage (Context); + // + // The Image trailer, if existent, is treated as padding and as such is + // reported as read-only data, as intended. Because it is not part of the + // original Image memory space, this needs to happen whether Image sections + // are guaranteed to be contiguously form the entire Image memory space or + // not. + // + NumRecordSegments += InternalInsertImageRecordSegmentPadding ( + RecordSegment, + EndAddress, + SizeOfImage, + Attributes + ); + + ImageRecord->NumSegments = NumRecordSegments; + ImageRecord->StartAddress = ImageAddress; + ImageRecord->EndAddress = ImageAddress + SizeOfImage; + // + // Zero the remaining array entries to avoid uninitialised data. + // + ZeroMem ( + ImageRecord->Segments + NumRecordSegments, + (MaxNumRecordSegments - NumRecordSegments) * sizeof (*ImageRecord->Segments) + ); + + return ImageRecord; +} + +// FIXME: Docs +STATIC +RETURN_STATUS +InternalDebugLocateImage ( + OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context, + IN CHAR8 *Buffer, + IN UINTN Address, + IN BOOLEAN Recurse + ) +{ + RETURN_STATUS Status; + RETURN_STATUS DosStatus; + PE_COFF_LOADER_IMAGE_CONTEXT DosContext; + + ASSERT (((UINTN) Buffer & 3U) == 0); + // + // Align the search buffer to a 4 Byte boundary. + // + // Search for the Image Header in 4 Byte steps. All dynamically loaded + // Images start at a page boundary to allow for Image section protection, + // but XIP Images may not. As all Image Headers are at least 4 Byte aligned + // due to natural alignment, even XIP TE Image Headers should start at a + // 4 Byte boundary. + // + // Do not attempt to access memory of the first page as it may be protected as + // part of NULL dereference detection. + // + for (; EFI_PAGE_SIZE <= (UINTN) Buffer; Buffer -= 4) { + // + // Try to parse the current memory as PE/COFF or TE Image. Pass MAX_UINT32 + // as the file size as there isn't any more information available. Only the + // Image Header memory will be accessed as part of initialisation. + // + Status = PeCoffInitializeContext ( + Context, + Buffer, + MAX_UINT32 + ); + if (RETURN_ERROR (Status)) { + continue; + } + + if (!Recurse) { + // + // For PE/COFF Images, the PE/COFF Image Header may be discovered while + // there may still be a preceeding DOS Image Header. All RVAs are relatvie + // to the start of the Image memory space, of which the DOS Image Header + // is a part of, if existent. Allow one level of recursion to find a lower + // Image Base including the DOS Image Header. + // + if ((PcdGetBool (PcdImageLoaderProhibitTe) + || Context->ImageType != PeCoffLoaderTypeTe) + && Context->ExeHdrOffset == 0) { + ASSERT (Context->ImageType != PeCoffLoaderTypeTe); + + DosStatus = InternalDebugLocateImage ( + &DosContext, + Buffer - 4, + Address, + TRUE + ); + if (!RETURN_ERROR (DosStatus)) { + Buffer = DosContext.ImageBuffer; + CopyMem (Context, &DosContext, sizeof (*Context)); + } + } + } + // + // We know that (UINTN) Buffer <= Address from the initialisation. + // + // FIXME: Set to non-stripped base for XIP TE Images. + if (Address < (UINTN) Buffer + PeCoffGetSizeOfImage (Context)) { + Context->ImageBuffer = Buffer; + // + // Zero the raw file information as we are initialising from a potentially + // non-XIP in-memory Image. + // + Context->FileBuffer = NULL; + Context->FileSize = 0; + + return RETURN_SUCCESS; + } + // + // Continue for the unlikely case that a PE/COFF or TE Image embeds another + // one within its data, the outer Image may still follow. + // + } + + return RETURN_NOT_FOUND; +} + +RETURN_STATUS +UefiImageDebugLocateImagePeCoff ( + OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context, + IN UINTN Address + ) +{ + RETURN_STATUS Status; + + Status = RETURN_NOT_FOUND; + // + // As this function is intrinsically unsafe, do not allow its usage outside of + // DEBUG-enabled code. + // + DEBUG_CODE_BEGIN (); + + // + // If the Image Headers are not loaded explicitly, only XIP Images and Images + // that embed the Image Header in the first Image section can be located. As + // this is not the case for the majority of Images, don't attempt to locate + // the Image base to not access too much (potentially protected) memory. + // + if (!PcdGetBool (PcdImageLoaderLoadHeader)) { + DEBUG_RAISE (); + return RETURN_NOT_FOUND; + } + // + // Align the search buffer to a 4 Byte boundary. + // + Status = InternalDebugLocateImage ( + Context, + (CHAR8 *) (Address & ~(UINTN) 3U), + Address, + FALSE + ); + + DEBUG_CODE_END (); + + return Status; +} + +RETURN_STATUS +UefiImageGetFixedAddressPeCoff ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context, + OUT UINT64 *Address + ) +{ + CONST EFI_IMAGE_SECTION_HEADER *Sections; + UINT16 NumberOfSections; + UINT16 SectionIndex; + UINT64 FixedAddress; + + ASSERT (Address != NULL); + // + // If this feature is enabled, the build tool will save the address in the + // PointerToRelocations and PointerToLineNumbers fields of the first Image + // section header that doesn't hold code. The 64-bit value across those fields + // will be non-zero if and only if the module has been assigned an address. + // + NumberOfSections = PeCoffGetSectionTable (Context, &Sections); + for (SectionIndex = 0; SectionIndex < NumberOfSections; ++SectionIndex) { + if ((Sections[SectionIndex].Characteristics & EFI_IMAGE_SCN_CNT_CODE) != 0) { + continue; + } + + FixedAddress = ReadUnaligned64 ( + (CONST VOID *) &Sections[SectionIndex].PointerToRelocations + ); + if (FixedAddress != 0) { + if (!IS_ALIGNED (FixedAddress, Context->SectionAlignment)) { + return RETURN_UNSUPPORTED; + } + + *Address = FixedAddress; + return RETURN_SUCCESS; + } + + break; + } + + return RETURN_NOT_FOUND; +} + +VOID +UefiImageDebugPrintSegmentsPeCoff ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context + ) +{ + CONST EFI_IMAGE_SECTION_HEADER *Sections; + UINT16 NumberOfSections; + UINT16 SectionIndex; + CONST UINT8 *Name; + + NumberOfSections = PeCoffGetSectionTable (Context, &Sections); + + for (SectionIndex = 0; SectionIndex < NumberOfSections; ++SectionIndex) { + Name = Sections[SectionIndex].Name; + DEBUG (( + DEBUG_VERBOSE, + " Section - '%c%c%c%c%c%c%c%c'\n" + " VirtualSize - 0x%08x\n" + " VirtualAddress - 0x%08x\n" + " SizeOfRawData - 0x%08x\n" + " PointerToRawData - 0x%08x\n", + Name[0], Name[1], Name[2], Name[3], Name[4], Name[5], Name[6], Name[7], + Sections[SectionIndex].VirtualSize, + Sections[SectionIndex].VirtualAddress, + Sections[SectionIndex].SizeOfRawData, + Sections[SectionIndex].PointerToRawData + )); + DEBUG (( + DEBUG_VERBOSE, + " PointerToRelocations - 0x%08x\n" + " PointerToLinenumbers - 0x%08x\n" + " NumberOfRelocations - 0x%08x\n" + " NumberOfLinenumbers - 0x%08x\n" + " Characteristics - 0x%08x\n", + Sections[SectionIndex].PointerToRelocations, + Sections[SectionIndex].PointerToLinenumbers, + Sections[SectionIndex].NumberOfRelocations, + Sections[SectionIndex].NumberOfLinenumbers, + Sections[SectionIndex].Characteristics + )); + } +} diff --git a/MdePkg/Library/BaseUefiImageLib/PeCoffSupport.h b/MdePkg/Library/BaseUefiImageLib/PeCoffSupport.h new file mode 100644 index 0000000000..102e09375f --- /dev/null +++ b/MdePkg/Library/BaseUefiImageLib/PeCoffSupport.h @@ -0,0 +1,37 @@ +/** @file + UEFI Image Loader library implementation for PE/COFF and TE Images. + + Copyright (c) 2021, Marvin Häuser. All rights reserved.
+ + SPDX-License-Identifier: BSD-3-Clause +**/ + +#ifndef PE_COFF_SUPPORT_H_ +#define PE_COFF_SUPPORT_H_ + +#include +#include + +UEFI_IMAGE_RECORD * +UefiImageLoaderGetImageRecordPeCoff ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context + ); + +RETURN_STATUS +UefiImageDebugLocateImagePeCoff ( + OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context, + IN UINTN Address + ); + +RETURN_STATUS +UefiImageGetFixedAddressPeCoff ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context, + OUT UINT64 *Address + ); + +VOID +UefiImageDebugPrintSegmentsPeCoff ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *Context + ); + +#endif // PE_COFF_SUPPORT_H_ diff --git a/MdePkg/Library/BaseUefiImageLib/UefiImageLibPeCoff.c b/MdePkg/Library/BaseUefiImageLib/UefiImageLibPeCoff.c new file mode 100644 index 0000000000..76b43f228a --- /dev/null +++ b/MdePkg/Library/BaseUefiImageLib/UefiImageLibPeCoff.c @@ -0,0 +1,299 @@ +/** @file + UEFI Image Loader library implementation for PE/COFF and TE Images. + + Copyright (c) 2021, Marvin Häuser. All rights reserved.
+ + SPDX-License-Identifier: BSD-3-Clause +**/ + +#define UEFI_IMAGE_LOADER_IMAGE_CONTEXT PE_COFF_LOADER_IMAGE_CONTEXT +#define UEFI_IMAGE_LOADER_RUNTIME_CONTEXT PE_COFF_LOADER_RUNTIME_CONTEXT + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "PeCoffSupport.h" + +RETURN_STATUS +UefiImageInitializeContextPreHash ( + OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context, + IN CONST VOID *FileBuffer, + IN UINT32 FileSize + ) +{ + return PeCoffInitializeContext (Context, FileBuffer, FileSize); +} + +RETURN_STATUS +UefiImageInitializeContextPostHash ( + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context + ) +{ + ASSERT (Context != NULL); + + return RETURN_SUCCESS; +} + +UINT8 +UefiImageGetFormat ( + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context + ) +{ + return UefiImageFormatPe; +} + +BOOLEAN +UefiImageHashImageDefault ( + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context, + IN OUT VOID *HashContext, + IN UEFI_IMAGE_LOADER_HASH_UPDATE HashUpdate + ) +{ + return PeCoffHashImageAuthenticode (Context, HashContext, HashUpdate); +} + +RETURN_STATUS +UefiImageLoadImage ( + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context, + OUT VOID *Destination, + IN UINT32 DestinationSize + ) +{ + return PeCoffLoadImage (Context, Destination, DestinationSize); +} + +BOOLEAN +UefiImageImageIsInplace ( + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context + ) +{ + return PeCoffImageIsInplace (Context); +} + +RETURN_STATUS +UefiImageLoadImageInplace ( + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context + ) +{ + return PeCoffLoadImageInplace (Context); +} + +RETURN_STATUS +UefiImageRelocateImageInplace ( + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context + ) +{ + return PeCoffRelocateImageInplace (Context); +} + +RETURN_STATUS +UefiImageLoaderGetRuntimeContextSize ( + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context, + OUT UINT32 *Size + ) +{ + return PeCoffLoaderGetRuntimeContextSize (Context, Size); +} + +RETURN_STATUS +UefiImageRelocateImage ( + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context, + IN UINT64 BaseAddress, + OUT UEFI_IMAGE_LOADER_RUNTIME_CONTEXT *RuntimeContext OPTIONAL, + IN UINT32 RuntimeContextSize + ) +{ + RETURN_STATUS Status; + + Status = PeCoffRelocateImage ( + Context, + BaseAddress, + RuntimeContext, + RuntimeContextSize + ); + if (!RETURN_ERROR (Status)) { + UefiImageLoaderRelocateImageExtraAction (Context); + } + + return Status; +} + +RETURN_STATUS +UefiImageRuntimeRelocateImage ( + IN OUT VOID *Image, + IN UINT32 ImageSize, + IN UINT64 BaseAddress, + IN CONST UEFI_IMAGE_LOADER_RUNTIME_CONTEXT *RuntimeContext + ) +{ + return PeCoffRuntimeRelocateImage ( + Image, + ImageSize, + BaseAddress, + RuntimeContext + ); +} + +VOID +UefiImageDiscardSegments ( + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context + ) +{ + PeCoffDiscardSections (Context); +} + +RETURN_STATUS +UefiImageGetSymbolsPath ( + IN CONST UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context, + OUT CONST CHAR8 **SymbolsPath, + OUT UINT32 *SymbolsPathSize + ) +{ + return PeCoffGetPdbPath (Context, SymbolsPath, SymbolsPathSize); +} + +RETURN_STATUS +UefiImageGetFirstCertificate ( + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context, + OUT CONST WIN_CERTIFICATE **Certificate + ) +{ + return PeCoffGetFirstCertificate (Context, Certificate); +} + +RETURN_STATUS +UefiImageGetNextCertificate ( + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context, + IN OUT CONST WIN_CERTIFICATE **Certificate + ) +{ + return PeCoffGetNextCertificate (Context, Certificate); +} + +RETURN_STATUS +UefiImageGetHiiDataRva ( + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context, + OUT UINT32 *HiiRva, + OUT UINT32 *HiiSize + ) +{ + return PeCoffGetHiiDataRva (Context, HiiRva, HiiSize); +} + +UINT32 +UefiImageGetEntryPointAddress ( + IN CONST UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context + ) +{ + return PeCoffGetAddressOfEntryPoint (Context); +} + +UINT16 +UefiImageGetMachine ( + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context + ) +{ + return PeCoffGetMachine (Context); +} + +UINT16 +UefiImageGetSubsystem ( + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context + ) +{ + return PeCoffGetSubsystem (Context); +} + +UINT32 +UefiImageGetSegmentAlignment ( + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context + ) +{ + return PeCoffGetSectionAlignment (Context); +} + +UINT32 +UefiImageGetImageSize ( + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context + ) +{ + return PeCoffGetSizeOfImage (Context); +} + +UINT32 +UefiImageGetImageSizeInplace ( + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context + ) +{ + return PeCoffGetSizeOfImageInplace (Context); +} + +UINT64 +UefiImageGetPreferredAddress ( + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context + ) +{ + return PeCoffGetImageBase (Context); +} + +BOOLEAN +UefiImageGetRelocsStripped ( + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context + ) +{ + return PeCoffGetRelocsStripped (Context); +} + +UINTN +UefiImageLoaderGetImageAddress ( + IN CONST UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context + ) +{ + return PeCoffLoaderGetImageAddress (Context); +} + +UEFI_IMAGE_RECORD * +UefiImageLoaderGetImageRecord ( + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context + ) +{ + return UefiImageLoaderGetImageRecordPeCoff (Context); +} + +RETURN_STATUS +UefiImageDebugLocateImage ( + OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context, + IN UINTN Address + ) +{ + return UefiImageDebugLocateImagePeCoff (Context, Address); +} + +RETURN_STATUS +UefiImageGetFixedAddress ( + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context, + OUT UINT64 *Address + ) +{ + return UefiImageGetFixedAddressPeCoff (Context, Address); +} + +VOID +UefiImageDebugPrintSegments ( + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context + ) +{ + UefiImageDebugPrintSegmentsPeCoff (Context); +} diff --git a/MdePkg/Library/PeiServicesLib/PeiServicesLib.c b/MdePkg/Library/PeiServicesLib/PeiServicesLib.c index 98cc69c3a2..727541ce75 100644 --- a/MdePkg/Library/PeiServicesLib/PeiServicesLib.c +++ b/MdePkg/Library/PeiServicesLib/PeiServicesLib.c @@ -324,6 +324,38 @@ PeiServicesFfsFindSectionData3 ( return (*PeiServices)->FindSectionData3 (PeiServices, SectionType, SectionInstance, FileHandle, SectionData, AuthenticationStatus); } +/** + This service enables PEIMs to discover sections of a given instance and type within a valid FFS file. + + @param SectionType The value of the section type to find. + @param SectionInstance Section instance to find. + @param FileHandle A pointer to the file header that contains the set + of sections to be searched. + @param SectionData A pointer to the discovered section, if successful. + @param SectionDataSize The size of the discovered section, if successful. + @param AuthenticationStatus A pointer to the authentication status for this section. + + @retval EFI_SUCCESS The section was found. + @retval EFI_NOT_FOUND The section was not found. + +**/ +EFI_STATUS +EFIAPI +PeiServicesFfsFindSectionData4 ( + IN EFI_SECTION_TYPE SectionType, + IN UINTN SectionInstance, + IN EFI_PEI_FILE_HANDLE FileHandle, + OUT VOID **SectionData, + OUT UINT32 *SectionDataSize, + OUT UINT32 *AuthenticationStatus + ) +{ + CONST EFI_PEI_SERVICES **PeiServices; + + PeiServices = GetPeiServicesTablePointer (); + return (*PeiServices)->FindSectionData4 (PeiServices, SectionType, SectionInstance, FileHandle, SectionData, SectionDataSize, AuthenticationStatus); +} + /** This service enables PEIMs to register the permanent memory configuration that has been initialized with the PEI Foundation. diff --git a/MdePkg/MdeLibs.dsc.inc b/MdePkg/MdeLibs.dsc.inc index ddd27115f5..9dca700c5b 100644 --- a/MdePkg/MdeLibs.dsc.inc +++ b/MdePkg/MdeLibs.dsc.inc @@ -19,3 +19,4 @@ SafeIntLib|MdePkg/Library/BaseSafeIntLib/BaseSafeIntLib.inf SynchronizationLib|MdePkg/Library/BaseSynchronizationLib/BaseSynchronizationLib.inf MmUnblockMemoryLib|MdePkg/Library/MmUnblockMemoryLib/MmUnblockMemoryLibNull.inf + BaseOverflowLib|MdePkg/Library/BaseOverflowLib/BaseOverflowLib.inf diff --git a/MdePkg/MdePkg.dec b/MdePkg/MdePkg.dec index bf94549cbf..be3c5900b5 100644 --- a/MdePkg/MdePkg.dec +++ b/MdePkg/MdePkg.dec @@ -131,9 +131,15 @@ ## @libraryclass Provides extra action services for unloading and relocating a PE/COFF image on some specific platform such ## as NT32 emulator. PeCoffExtraActionLib|Include/Library/PeCoffExtraActionLib.h + # FIXME: Docs + ## @libraryclass Provides services to load and relocate a PE/COFF image. + PeCoffLib2|Include/Library/PeCoffLib2.h + ## @libraryclass Provides extra action services for unloading and relocating a PE/COFF image on some specific platform such + ## as NT32 emulator. + UefiImageExtraActionLib|Include/Library/UefiImageExtraActionLib.h ## @libraryclass Provides a service to retrieve the PE/COFF entry point from a PE/COFF image. - PeCoffGetEntryPointLib|Include/Library/PeCoffGetEntryPointLib.h + UefiImageGetEntryPointLib|Include/Library/UefiImageGetEntryPointLib.h ## @libraryclass Provides services to return the PCI segment information. PciSegmentInfoLib|Include/Library/PciSegmentInfoLib.h @@ -2229,7 +2235,7 @@ # BIT0 - SMM CET Shadow Stack is enabled.
# Other - reserved # @Prompt Enable control flow enforcement. - gEfiMdePkgTokenSpaceGuid.PcdControlFlowEnforcementPropertyMask|0x0|UINT32|0x30001017 + gEfiMdePkgTokenSpaceGuid.PcdControlFlowEnforcementPropertyMask|0|UINT32|0x30001017 ## Indicates the type of instruction sequence to use for a speculation # barrier. The default instruction sequence is LFENCE.

@@ -2240,6 +2246,63 @@ # @Prompt Speculation Barrier Type. gEfiMdePkgTokenSpaceGuid.PcdSpeculationBarrierType|0x01|UINT8|0x30001018 + ## Indicates whether Image Relocation target values at Runtime may mismatch + # the values assigned during initial load.

+ # TRUE - Image relocation target values may mismatch the expected values.
+ # FALSE - Image relocation target values must match the expected values.
+ # @Prompt Allow Runtime Relocation Target Mismatch. + gEfiMdePkgTokenSpaceGuid.PcdImageLoaderRtRelocAllowTargetMismatch|FALSE|BOOLEAN|0x40001018 + + ## Indicates whether Image section may overlap with the previous one. + # Overlapping Sections could dramatically increase the hashing time.

+ # TRUE - Image section must not overlap with the previous one.
+ # FALSE - Image section may overlap with the previous one.
+ # @Prompt Prohibit Overlapping Sections. + gEfiMdePkgTokenSpaceGuid.PcdImageLoaderHashProhibitOverlap|TRUE|BOOLEAN|0x40001019 + + ## Indicates whether Image Headers must be loaded into the memory space.

+ # TRUE - Image Headers will be loaded into the memory space.
+ # FALSE - Image Headers will not be loaded into the memory space.
+ # @Prompt Load Image Headers. + gEfiMdePkgTokenSpaceGuid.PcdImageLoaderLoadHeader|TRUE|BOOLEAN|0x4000101A + + ## This flag is used to control the set of supported relocations' types.

+ # BIT0 - If set, ARM Thumb Image relocations are supported.
+ # @Prompt Image Relocations Policy. + gEfiMdePkgTokenSpaceGuid.PcdImageLoaderRelocTypePolicy|0xFFFFFFFF|UINT32|0x4000101B + + ## Indicates whether Image sections must adhere to the W^X principle.

+ # TRUE - Image sections must adhere to the W^X principle.
+ # FALSE - Image sections may not adhere to the W^X principle.
+ # @Prompt Enforce W^X principle. + gEfiMdePkgTokenSpaceGuid.PcdImageLoaderWXorX|TRUE|BOOLEAN|0x4000101C + + ## Indicates whether Debug information can be retrieved + # from the Debug Directory of the Image.

+ # TRUE - Debug Directory will be scaned for Debug Information.
+ # FALSE - Debug Directory will not be scaned.
+ # @Prompt Support Debug Information. + gEfiMdePkgTokenSpaceGuid.PcdImageLoaderDebugSupport|TRUE|BOOLEAN|0x4000101D + + ## This flag is used to control Image Loader alignment policy.

+ # BIT0 - If set, unaligned Image sections are permitted.
+ # BIT1 - If set, unaligned Image Relocation Block sizes are permitted.
+ # BIT2 - If set, unaligned Image certificate sizes are permitted.
+ # @Prompt Image Loader Alignment Policy. + gEfiMdePkgTokenSpaceGuid.PcdImageLoaderAlignmentPolicy|0xFFFFFFFF|UINT32|0x4000101E + + ## Indicates whether TE Images are allowed.

+ # TRUE - TE Images are forbidden.
+ # FALSE - TE Images are allowed.
+ # @Prompt Prohibit TE Images Loading. + gEfiMdePkgTokenSpaceGuid.PcdImageLoaderProhibitTe|FALSE|BOOLEAN|0x4000101F + + ## Indicates whether PE32+ header offset is sufficiently aligned.

+ # TRUE - Execution Header offset may be not aligned.
+ # FALSE - Execution Header offset must be sufficiently aligned.
+ # @Prompt Allow Misaligned Offset. + gEfiMdePkgTokenSpaceGuid.PcdImageLoaderAllowMisalignedOffset|FALSE|BOOLEAN|0x40001020 + [PcdsFixedAtBuild,PcdsPatchableInModule] ## Indicates the maximum length of unicode string used in the following # BaseLib functions: StrLen(), StrSize(), StrCmp(), StrnCmp(), StrCpy(), StrnCpy()

diff --git a/MdePkg/MdePkg.dsc b/MdePkg/MdePkg.dsc index 109224c527..bc8cfc9406 100644 --- a/MdePkg/MdePkg.dsc +++ b/MdePkg/MdePkg.dsc @@ -58,9 +58,9 @@ MdePkg/Library/PciSegmentLibSegmentInfo/DxeRuntimePciSegmentLibSegmentInfo.inf MdePkg/Library/BaseS3PciSegmentLib/BaseS3PciSegmentLib.inf MdePkg/Library/BaseArmTrngLibNull/BaseArmTrngLibNull.inf - MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf - MdePkg/Library/BasePeCoffLib/BasePeCoffLib.inf - MdePkg/Library/BasePeCoffExtraActionLibNull/BasePeCoffExtraActionLibNull.inf + MdePkg/Library/BasePeCoffLib2/BasePeCoffLib2.inf + MdePkg/Library/BaseUefiImageLib/BaseUefiImageLibPeCoff.inf + MdePkg/Library/BaseUefiImageExtraActionLibNull/BaseUefiImageExtraActionLibNull.inf MdePkg/Library/BasePerformanceLibNull/BasePerformanceLibNull.inf MdePkg/Library/BasePostCodeLibDebug/BasePostCodeLibDebug.inf MdePkg/Library/BasePostCodeLibPort80/BasePostCodeLibPort80.inf diff --git a/NetworkPkg/NetworkPkg.dsc b/NetworkPkg/NetworkPkg.dsc index 808c6bffce..486782fa8f 100644 --- a/NetworkPkg/NetworkPkg.dsc +++ b/NetworkPkg/NetworkPkg.dsc @@ -41,12 +41,15 @@ UefiBootManagerLib|MdeModulePkg/Library/UefiBootManagerLib/UefiBootManagerLib.inf TimerLib|MdePkg/Library/BaseTimerLibNullTemplate/BaseTimerLibNullTemplate.inf PerformanceLib|MdePkg/Library/BasePerformanceLibNull/BasePerformanceLibNull.inf - PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf DxeServicesLib|MdePkg/Library/DxeServicesLib/DxeServicesLib.inf DxeServicesTableLib|MdePkg/Library/DxeServicesTableLib/DxeServicesTableLib.inf SafeIntLib|MdePkg/Library/BaseSafeIntLib/BaseSafeIntLib.inf RngLib|MdePkg/Library/BaseRngLib/BaseRngLib.inf VariablePolicyHelperLib|MdeModulePkg/Library/VariablePolicyHelperLib/VariablePolicyHelperLib.inf + PeCoffLib2|MdePkg/Library/BasePeCoffLib2/BasePeCoffLib2.inf + UefiImageLib|MdePkg/Library/BaseUefiImageLib/BaseUefiImageLibPeCoff.inf + CacheMaintenanceLib|MdePkg/Library/BaseCacheMaintenanceLib/BaseCacheMaintenanceLib.inf + UefiImageExtraActionLib|MdePkg/Library/BaseUefiImageExtraActionLibNull/BaseUefiImageExtraActionLibNull.inf !ifdef CONTINUOUS_INTEGRATION BaseCryptLib|CryptoPkg/Library/BaseCryptLibNull/BaseCryptLibNull.inf @@ -128,7 +131,7 @@ NetworkPkg/Library/DxeTcpIoLib/DxeTcpIoLib.inf NetworkPkg/Library/DxeUdpIoLib/DxeUdpIoLib.inf - !include NetworkPkg/Network.dsc.inc +!include NetworkPkg/Network.dsc.inc [BuildOptions] *_*_*_CC_FLAGS = -D DISABLE_NEW_DEPRECATED_INTERFACES diff --git a/OvmfPkg/AmdSev/AmdSevX64.dsc b/OvmfPkg/AmdSev/AmdSevX64.dsc index 8eb6f4f24f..8e323bdefd 100644 --- a/OvmfPkg/AmdSev/AmdSevX64.dsc +++ b/OvmfPkg/AmdSev/AmdSevX64.dsc @@ -122,7 +122,8 @@ SynchronizationLib|MdePkg/Library/BaseSynchronizationLib/BaseSynchronizationLib.inf CpuLib|MdePkg/Library/BaseCpuLib/BaseCpuLib.inf PerformanceLib|MdePkg/Library/BasePerformanceLibNull/BasePerformanceLibNull.inf - PeCoffLib|MdePkg/Library/BasePeCoffLib/BasePeCoffLib.inf + PeCoffLib2|MdePkg/Library/BasePeCoffLib2/BasePeCoffLib2.inf + UefiImageLib|MdePkg/Library/BaseUefiImageLib/BaseUefiImageLibPeCoff.inf CacheMaintenanceLib|MdePkg/Library/BaseCacheMaintenanceLib/BaseCacheMaintenanceLib.inf UefiDecompressLib|MdePkg/Library/BaseUefiDecompressLib/BaseUefiDecompressLib.inf UefiHiiServicesLib|MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.inf @@ -134,7 +135,6 @@ CapsuleLib|MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.inf DxeServicesLib|MdePkg/Library/DxeServicesLib/DxeServicesLib.inf DxeServicesTableLib|MdePkg/Library/DxeServicesTableLib/DxeServicesTableLib.inf - PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf PciCf8Lib|MdePkg/Library/BasePciCf8Lib/BasePciCf8Lib.inf PciExpressLib|MdePkg/Library/BasePciExpressLib/BasePciExpressLib.inf PciLib|MdePkg/Library/BasePciLibCf8/BasePciLibCf8.inf @@ -175,10 +175,10 @@ ImagePropertiesRecordLib|MdeModulePkg/Library/ImagePropertiesRecordLib/ImagePropertiesRecordLib.inf !if $(SOURCE_DEBUG_ENABLE) == TRUE - PeCoffExtraActionLib|SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLibDebug.inf + UefiImageExtraActionLib|SourceLevelDebugPkg/Library/UefiImageExtraActionLibDebug/UefiImageExtraActionLibDebug.inf DebugCommunicationLib|SourceLevelDebugPkg/Library/DebugCommunicationLibSerialPort/DebugCommunicationLibSerialPort.inf !else - PeCoffExtraActionLib|MdePkg/Library/BasePeCoffExtraActionLibNull/BasePeCoffExtraActionLibNull.inf + UefiImageExtraActionLib|MdePkg/Library/BaseUefiImageExtraActionLibNull/BaseUefiImageExtraActionLibNull.inf DebugAgentLib|MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.inf !endif @@ -240,13 +240,13 @@ PeiCoreEntryPoint|MdePkg/Library/PeiCoreEntryPoint/PeiCoreEntryPoint.inf ReportStatusCodeLib|MdeModulePkg/Library/PeiReportStatusCodeLib/PeiReportStatusCodeLib.inf OemHookStatusCodeLib|MdeModulePkg/Library/OemHookStatusCodeLibNull/OemHookStatusCodeLibNull.inf - PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf !ifdef $(DEBUG_ON_SERIAL_PORT) DebugLib|MdePkg/Library/BaseDebugLibSerialPort/BaseDebugLibSerialPort.inf !else DebugLib|OvmfPkg/Library/PlatformDebugLibIoPort/PlatformRomDebugLibIoPort.inf !endif - PeCoffLib|MdePkg/Library/BasePeCoffLib/BasePeCoffLib.inf + PeCoffLib2|MdePkg/Library/BasePeCoffLib2/BasePeCoffLib2.inf + UefiImageLib|MdePkg/Library/BaseUefiImageLib/BaseUefiImageLibPeCoff.inf [LibraryClasses.common.PEIM] HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf @@ -256,13 +256,13 @@ PeimEntryPoint|MdePkg/Library/PeimEntryPoint/PeimEntryPoint.inf ReportStatusCodeLib|MdeModulePkg/Library/PeiReportStatusCodeLib/PeiReportStatusCodeLib.inf OemHookStatusCodeLib|MdeModulePkg/Library/OemHookStatusCodeLibNull/OemHookStatusCodeLibNull.inf - PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf !ifdef $(DEBUG_ON_SERIAL_PORT) DebugLib|MdePkg/Library/BaseDebugLibSerialPort/BaseDebugLibSerialPort.inf !else DebugLib|OvmfPkg/Library/PlatformDebugLibIoPort/PlatformRomDebugLibIoPort.inf !endif - PeCoffLib|MdePkg/Library/BasePeCoffLib/BasePeCoffLib.inf + PeCoffLib2|MdePkg/Library/BasePeCoffLib2/BasePeCoffLib2.inf + UefiImageLib|MdePkg/Library/BaseUefiImageLib/BaseUefiImageLibPeCoff.inf ResourcePublicationLib|MdePkg/Library/PeiResourcePublicationLib/PeiResourcePublicationLib.inf ExtractGuidedSectionLib|MdePkg/Library/PeiExtractGuidedSectionLib/PeiExtractGuidedSectionLib.inf !if $(SOURCE_DEBUG_ENABLE) == TRUE diff --git a/OvmfPkg/Bhyve/BhyveX64.dsc b/OvmfPkg/Bhyve/BhyveX64.dsc index 78050959f8..bd307efac7 100644 --- a/OvmfPkg/Bhyve/BhyveX64.dsc +++ b/OvmfPkg/Bhyve/BhyveX64.dsc @@ -128,7 +128,8 @@ SynchronizationLib|MdePkg/Library/BaseSynchronizationLib/BaseSynchronizationLib.inf CpuLib|MdePkg/Library/BaseCpuLib/BaseCpuLib.inf PerformanceLib|MdePkg/Library/BasePerformanceLibNull/BasePerformanceLibNull.inf - PeCoffLib|MdePkg/Library/BasePeCoffLib/BasePeCoffLib.inf + PeCoffLib2|MdePkg/Library/BasePeCoffLib2/BasePeCoffLib2.inf + UefiImageLib|MdePkg/Library/BaseUefiImageLib/BaseUefiImageLibPeCoff.inf CacheMaintenanceLib|MdePkg/Library/BaseCacheMaintenanceLib/BaseCacheMaintenanceLib.inf UefiDecompressLib|MdePkg/Library/BaseUefiDecompressLib/BaseUefiDecompressLib.inf UefiHiiServicesLib|MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.inf @@ -140,7 +141,6 @@ CapsuleLib|MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.inf DxeServicesLib|MdePkg/Library/DxeServicesLib/DxeServicesLib.inf DxeServicesTableLib|MdePkg/Library/DxeServicesTableLib/DxeServicesTableLib.inf - PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf PciCf8Lib|MdePkg/Library/BasePciCf8Lib/BasePciCf8Lib.inf PciExpressLib|MdePkg/Library/BasePciExpressLib/BasePciExpressLib.inf PciLib|MdePkg/Library/BasePciLibCf8/BasePciLibCf8.inf @@ -180,10 +180,10 @@ FrameBufferBltLib|MdeModulePkg/Library/FrameBufferBltLib/FrameBufferBltLib.inf !if $(SOURCE_DEBUG_ENABLE) == TRUE - PeCoffExtraActionLib|SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLibDebug.inf + UefiImageExtraActionLib|SourceLevelDebugPkg/Library/UefiImageExtraActionLibDebug/UefiImageExtraActionLibDebug.inf DebugCommunicationLib|SourceLevelDebugPkg/Library/DebugCommunicationLibSerialPort/DebugCommunicationLibSerialPort.inf !else - PeCoffExtraActionLib|MdePkg/Library/BasePeCoffExtraActionLibNull/BasePeCoffExtraActionLibNull.inf + UefiImageExtraActionLib|MdePkg/Library/BaseUefiImageExtraActionLibNull/BaseUefiImageExtraActionLibNull.inf DebugAgentLib|MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.inf !endif @@ -264,13 +264,13 @@ PeiCoreEntryPoint|MdePkg/Library/PeiCoreEntryPoint/PeiCoreEntryPoint.inf ReportStatusCodeLib|MdeModulePkg/Library/PeiReportStatusCodeLib/PeiReportStatusCodeLib.inf OemHookStatusCodeLib|MdeModulePkg/Library/OemHookStatusCodeLibNull/OemHookStatusCodeLibNull.inf - PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf !ifdef $(DEBUG_ON_SERIAL_PORT) DebugLib|MdePkg/Library/BaseDebugLibSerialPort/BaseDebugLibSerialPort.inf !else DebugLib|OvmfPkg/Library/PlatformDebugLibIoPort/PlatformRomDebugLibIoPort.inf !endif - PeCoffLib|MdePkg/Library/BasePeCoffLib/BasePeCoffLib.inf + PeCoffLib2|MdePkg/Library/BasePeCoffLib2/BasePeCoffLib2.inf + UefiImageLib|MdePkg/Library/BaseUefiImageLib/BaseUefiImageLibPeCoff.inf [LibraryClasses.common.PEIM] HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf @@ -280,13 +280,13 @@ PeimEntryPoint|MdePkg/Library/PeimEntryPoint/PeimEntryPoint.inf ReportStatusCodeLib|MdeModulePkg/Library/PeiReportStatusCodeLib/PeiReportStatusCodeLib.inf OemHookStatusCodeLib|MdeModulePkg/Library/OemHookStatusCodeLibNull/OemHookStatusCodeLibNull.inf - PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf !ifdef $(DEBUG_ON_SERIAL_PORT) DebugLib|MdePkg/Library/BaseDebugLibSerialPort/BaseDebugLibSerialPort.inf !else DebugLib|OvmfPkg/Library/PlatformDebugLibIoPort/PlatformRomDebugLibIoPort.inf !endif - PeCoffLib|MdePkg/Library/BasePeCoffLib/BasePeCoffLib.inf + PeCoffLib2|MdePkg/Library/BasePeCoffLib2/BasePeCoffLib2.inf + UefiImageLib|MdePkg/Library/BaseUefiImageLib/BaseUefiImageLibPeCoff.inf ResourcePublicationLib|MdePkg/Library/PeiResourcePublicationLib/PeiResourcePublicationLib.inf ExtractGuidedSectionLib|MdePkg/Library/PeiExtractGuidedSectionLib/PeiExtractGuidedSectionLib.inf !if $(SOURCE_DEBUG_ENABLE) == TRUE diff --git a/OvmfPkg/CompatImageLoaderDxe/CompatImageLoaderDxe.c b/OvmfPkg/CompatImageLoaderDxe/CompatImageLoaderDxe.c index c4416494a9..c4ae25fe2e 100644 --- a/OvmfPkg/CompatImageLoaderDxe/CompatImageLoaderDxe.c +++ b/OvmfPkg/CompatImageLoaderDxe/CompatImageLoaderDxe.c @@ -12,7 +12,6 @@ #include #include -#include #include #include diff --git a/OvmfPkg/CompatImageLoaderDxe/CompatImageLoaderDxe.inf b/OvmfPkg/CompatImageLoaderDxe/CompatImageLoaderDxe.inf index 74f06c64bf..c9fbbe0591 100644 --- a/OvmfPkg/CompatImageLoaderDxe/CompatImageLoaderDxe.inf +++ b/OvmfPkg/CompatImageLoaderDxe/CompatImageLoaderDxe.inf @@ -26,7 +26,6 @@ [LibraryClasses] BaseMemoryLib DebugLib - PeCoffLib UefiBootServicesTableLib UefiDriverEntryPoint diff --git a/OvmfPkg/IntelTdx/IntelTdxX64.dsc b/OvmfPkg/IntelTdx/IntelTdxX64.dsc index 0931ce061a..69beae7649 100644 --- a/OvmfPkg/IntelTdx/IntelTdxX64.dsc +++ b/OvmfPkg/IntelTdx/IntelTdxX64.dsc @@ -36,6 +36,9 @@ # DEFINE BUILD_SHELL = TRUE + DEFINE LEGACY_WINDOWS_LOADER = FALSE + DEFINE LINUX_LOADER = FALSE + # # Device drivers # @@ -90,12 +93,6 @@ INTEL:*_*_*_CC_FLAGS = /D TDX_PEI_LESS_BOOT GCC:*_*_*_CC_FLAGS = -D TDX_PEI_LESS_BOOT -[BuildOptions.common.EDKII.DXE_RUNTIME_DRIVER] - GCC:*_*_*_DLINK_FLAGS = -z common-page-size=0x1000 - XCODE:*_*_*_DLINK_FLAGS = -seg1addr 0x1000 -segalign 0x1000 - XCODE:*_*_*_MTOC_FLAGS = -align 0x1000 - CLANGPDB:*_*_*_DLINK_FLAGS = /ALIGN:4096 - ################################################################################ # # SKU Identification section - list of all SKU IDs supported by this Platform. @@ -125,7 +122,8 @@ SynchronizationLib|MdePkg/Library/BaseSynchronizationLib/BaseSynchronizationLib.inf CpuLib|MdePkg/Library/BaseCpuLib/BaseCpuLib.inf PerformanceLib|MdePkg/Library/BasePerformanceLibNull/BasePerformanceLibNull.inf - PeCoffLib|MdePkg/Library/BasePeCoffLib/BasePeCoffLib.inf + PeCoffLib2|MdePkg/Library/BasePeCoffLib2/BasePeCoffLib2.inf + UefiImageLib|MdePkg/Library/BaseUefiImageLib/BaseUefiImageLibPeCoff.inf CacheMaintenanceLib|MdePkg/Library/BaseCacheMaintenanceLib/BaseCacheMaintenanceLib.inf UefiDecompressLib|MdePkg/Library/BaseUefiDecompressLib/BaseUefiDecompressLib.inf UefiHiiServicesLib|MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.inf @@ -137,7 +135,6 @@ CapsuleLib|MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.inf DxeServicesLib|MdePkg/Library/DxeServicesLib/DxeServicesLib.inf DxeServicesTableLib|MdePkg/Library/DxeServicesTableLib/DxeServicesTableLib.inf - PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf PciCf8Lib|MdePkg/Library/BasePciCf8Lib/BasePciCf8Lib.inf PciExpressLib|MdePkg/Library/BasePciExpressLib/BasePciExpressLib.inf PciLib|MdePkg/Library/BasePciLibCf8/BasePciLibCf8.inf @@ -177,9 +174,14 @@ CustomizedDisplayLib|MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.inf FrameBufferBltLib|MdeModulePkg/Library/FrameBufferBltLib/FrameBufferBltLib.inf - PeCoffExtraActionLib|MdePkg/Library/BasePeCoffExtraActionLibNull/BasePeCoffExtraActionLibNull.inf DebugAgentLib|MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.inf +!if $(SOURCE_DEBUG_ENABLE) == TRUE + UefiImageExtraActionLib|SourceLevelDebugPkg/Library/UefiImageExtraActionLibDebug/UefiImageExtraActionLibDebug.inf +!else + UefiImageExtraActionLib|MdePkg/Library/BaseUefiImageExtraActionLibNull/BaseUefiImageExtraActionLibNull.inf +!endif + LocalApicLib|UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.inf DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf @@ -466,6 +468,21 @@ # gUefiCpuPkgTokenSpaceGuid.PcdFirstTimeWakeUpAPsBySipi|FALSE + # + # Security measures for memory protection. + # + !if $(LEGACY_WINDOWS_LOADER) == TRUE + # Allow execution of EfiLoaderData memory regions. + gEfiMdeModulePkgTokenSpaceGuid.PcdDxeNxMemoryProtectionPolicy|0xFFFFFFFFFFFFFFD1 + !elseif $(LINUX_LOADER) == TRUE + # Allow execution of EfiReservedMemoryType, EfiConventionalMemory, EfiBootServicesData and EfiLoaderData memory regions. + gEfiMdeModulePkgTokenSpaceGuid.PcdDxeNxMemoryProtectionPolicy|0xFFFFFFFFFFFFFF40 + gEfiMdePkgTokenSpaceGuid.PcdImageLoaderAllowMisalignedOffset|TRUE + !else + # Allow execution of EfiConventionalMemory and EfiBootServicesData memory regions. + gEfiMdeModulePkgTokenSpaceGuid.PcdDxeNxMemoryProtectionPolicy|0xFFFFFFFFFFFFFF45 + !endif + ################################################################################ # # Pcd Dynamic Section - list of all EDK II PCD Entries defined by this Platform diff --git a/OvmfPkg/IntelTdx/Sec/SecMain.c b/OvmfPkg/IntelTdx/Sec/SecMain.c index 4e750755bf..828a19d475 100644 --- a/OvmfPkg/IntelTdx/Sec/SecMain.c +++ b/OvmfPkg/IntelTdx/Sec/SecMain.c @@ -18,8 +18,6 @@ #include #include #include -#include -#include #include #include #include diff --git a/OvmfPkg/IntelTdx/Sec/SecMain.inf b/OvmfPkg/IntelTdx/Sec/SecMain.inf index cf95284f02..db7140ae46 100644 --- a/OvmfPkg/IntelTdx/Sec/SecMain.inf +++ b/OvmfPkg/IntelTdx/Sec/SecMain.inf @@ -40,9 +40,6 @@ CpuLib DebugAgentLib IoLib - PeCoffLib - PeCoffGetEntryPointLib - PeCoffExtraActionLib ExtractGuidedSectionLib LocalApicLib MemEncryptSevLib diff --git a/OvmfPkg/Library/PeilessStartupLib/DxeLoad.c b/OvmfPkg/Library/PeilessStartupLib/DxeLoad.c index d34690eb8a..f2f0acff3a 100644 --- a/OvmfPkg/Library/PeilessStartupLib/DxeLoad.c +++ b/OvmfPkg/Library/PeilessStartupLib/DxeLoad.c @@ -194,6 +194,7 @@ FindDxeNonCc ( EFI_FV_INFO FvImageInfo; UINT32 FvAlignment; VOID *FvBuffer; + UINT32 FvImageSize; FileHandle = NULL; @@ -209,7 +210,7 @@ FindDxeNonCc ( // // Find FvImage in FvFile // - Status = FfsFindSectionDataWithHook (EFI_SECTION_FIRMWARE_VOLUME_IMAGE, CheckSectionHookForDxeNonCc, FileHandle, (VOID **)&FvImageHandle); + Status = FfsFindSectionDataWithHook (EFI_SECTION_FIRMWARE_VOLUME_IMAGE, CheckSectionHookForDxeNonCc, FileHandle, (VOID **)&FvImageHandle, &FvImageSize); if (EFI_ERROR (Status)) { return Status; } @@ -281,10 +282,11 @@ DxeLoadCore ( EFI_STATUS Status; EFI_FV_FILE_INFO DxeCoreFileInfo; EFI_PHYSICAL_ADDRESS DxeCoreAddress; - UINT64 DxeCoreSize; + UINT32 DxeCoreSize; EFI_PHYSICAL_ADDRESS DxeCoreEntryPoint; EFI_PEI_FILE_HANDLE FileHandle; - VOID *PeCoffImage; + VOID *UefiImage; + UINT32 UefiImageSize; // // Look in all the FVs present and find the DXE Core FileHandle @@ -303,12 +305,12 @@ DxeLoadCore ( // // Load the DXE Core from a Firmware Volume. // - Status = FfsFindSectionDataWithHook (EFI_SECTION_PE32, NULL, FileHandle, &PeCoffImage); + Status = FfsFindSectionDataWithHook (EFI_SECTION_PE32, NULL, FileHandle, &UefiImage, &UefiImageSize); if (EFI_ERROR (Status)) { return Status; } - Status = LoadPeCoffImage (PeCoffImage, &DxeCoreAddress, &DxeCoreSize, &DxeCoreEntryPoint); + Status = LoadUefiImage (UefiImage, UefiImageSize, &DxeCoreAddress, &DxeCoreSize, &DxeCoreEntryPoint); ASSERT_EFI_ERROR (Status); // diff --git a/OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.h b/OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.h index 18b3deb9db..9c172d56a7 100644 --- a/OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.h +++ b/OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.h @@ -22,7 +22,7 @@ Module Name: #include #include #include -#include +#include #include #include diff --git a/OvmfPkg/Library/PlatformBootManagerLibBhyve/BdsPlatform.h b/OvmfPkg/Library/PlatformBootManagerLibBhyve/BdsPlatform.h index 9be184cb64..af26b3bac7 100644 --- a/OvmfPkg/Library/PlatformBootManagerLibBhyve/BdsPlatform.h +++ b/OvmfPkg/Library/PlatformBootManagerLibBhyve/BdsPlatform.h @@ -23,7 +23,7 @@ Module Name: #include #include #include -#include +#include #include #include diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc index 2ca005d768..8200d85c01 100644 --- a/OvmfPkg/OvmfPkgIa32.dsc +++ b/OvmfPkg/OvmfPkgIa32.dsc @@ -52,6 +52,10 @@ !include NetworkPkg/NetworkDefines.dsc.inc + DEFINE LEGACY_WINDOWS_LOADER = FALSE + DEFINE LINUX_LOADER = FALSE + DEFINE WINDOWS_10_IA32 = FALSE + # # Device drivers # @@ -142,7 +146,8 @@ SynchronizationLib|MdePkg/Library/BaseSynchronizationLib/BaseSynchronizationLib.inf CpuLib|MdePkg/Library/BaseCpuLib/BaseCpuLib.inf PerformanceLib|MdePkg/Library/BasePerformanceLibNull/BasePerformanceLibNull.inf - PeCoffLib|MdePkg/Library/BasePeCoffLib/BasePeCoffLib.inf + PeCoffLib2|MdePkg/Library/BasePeCoffLib2/BasePeCoffLib2.inf + UefiImageLib|MdePkg/Library/BaseUefiImageLib/BaseUefiImageLibPeCoff.inf CacheMaintenanceLib|MdePkg/Library/BaseCacheMaintenanceLib/BaseCacheMaintenanceLib.inf UefiDecompressLib|MdePkg/Library/BaseUefiDecompressLib/BaseUefiDecompressLib.inf UefiHiiServicesLib|MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.inf @@ -154,7 +159,6 @@ CapsuleLib|MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.inf DxeServicesLib|MdePkg/Library/DxeServicesLib/DxeServicesLib.inf DxeServicesTableLib|MdePkg/Library/DxeServicesTableLib/DxeServicesTableLib.inf - PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf PciCf8Lib|MdePkg/Library/BasePciCf8Lib/BasePciCf8Lib.inf PciExpressLib|MdePkg/Library/BasePciExpressLib/BasePciExpressLib.inf PciLib|MdePkg/Library/BasePciLibCf8/BasePciLibCf8.inf @@ -197,10 +201,10 @@ FrameBufferBltLib|MdeModulePkg/Library/FrameBufferBltLib/FrameBufferBltLib.inf !if $(SOURCE_DEBUG_ENABLE) == TRUE - PeCoffExtraActionLib|SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLibDebug.inf + UefiImageExtraActionLib|SourceLevelDebugPkg/Library/UefiImageExtraActionLibDebug/UefiImageExtraActionLibDebug.inf DebugCommunicationLib|SourceLevelDebugPkg/Library/DebugCommunicationLibSerialPort/DebugCommunicationLibSerialPort.inf !else - PeCoffExtraActionLib|MdePkg/Library/BasePeCoffExtraActionLibNull/BasePeCoffExtraActionLibNull.inf + UefiImageExtraActionLib|MdePkg/Library/BaseUefiImageExtraActionLibNull/BaseUefiImageExtraActionLibNull.inf DebugAgentLib|MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.inf !endif @@ -281,13 +285,13 @@ PeiCoreEntryPoint|MdePkg/Library/PeiCoreEntryPoint/PeiCoreEntryPoint.inf ReportStatusCodeLib|MdeModulePkg/Library/PeiReportStatusCodeLib/PeiReportStatusCodeLib.inf OemHookStatusCodeLib|MdeModulePkg/Library/OemHookStatusCodeLibNull/OemHookStatusCodeLibNull.inf - PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf !ifdef $(DEBUG_ON_SERIAL_PORT) DebugLib|MdePkg/Library/BaseDebugLibSerialPort/BaseDebugLibSerialPort.inf !else DebugLib|OvmfPkg/Library/PlatformDebugLibIoPort/PlatformRomDebugLibIoPort.inf !endif - PeCoffLib|MdePkg/Library/BasePeCoffLib/BasePeCoffLib.inf + PeCoffLib2|MdePkg/Library/BasePeCoffLib2/BasePeCoffLib2.inf + UefiImageLib|MdePkg/Library/BaseUefiImageLib/BaseUefiImageLibPeCoff.inf [LibraryClasses.common.PEIM] HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf @@ -297,13 +301,13 @@ PeimEntryPoint|MdePkg/Library/PeimEntryPoint/PeimEntryPoint.inf ReportStatusCodeLib|MdeModulePkg/Library/PeiReportStatusCodeLib/PeiReportStatusCodeLib.inf OemHookStatusCodeLib|MdeModulePkg/Library/OemHookStatusCodeLibNull/OemHookStatusCodeLibNull.inf - PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf !ifdef $(DEBUG_ON_SERIAL_PORT) DebugLib|MdePkg/Library/BaseDebugLibSerialPort/BaseDebugLibSerialPort.inf !else DebugLib|OvmfPkg/Library/PlatformDebugLibIoPort/PlatformRomDebugLibIoPort.inf !endif - PeCoffLib|MdePkg/Library/BasePeCoffLib/BasePeCoffLib.inf + PeCoffLib2|MdePkg/Library/BasePeCoffLib2/BasePeCoffLib2.inf + UefiImageLib|MdePkg/Library/BaseUefiImageLib/BaseUefiImageLibPeCoff.inf ResourcePublicationLib|MdePkg/Library/PeiResourcePublicationLib/PeiResourcePublicationLib.inf ExtractGuidedSectionLib|MdePkg/Library/PeiExtractGuidedSectionLib/PeiExtractGuidedSectionLib.inf !if $(SOURCE_DEBUG_ENABLE) == TRUE @@ -588,6 +592,21 @@ # gUefiCpuPkgTokenSpaceGuid.PcdFirstTimeWakeUpAPsBySipi|FALSE + # + # Security measures for memory protection. + # + !if $(LEGACY_WINDOWS_LOADER) == TRUE + # Allow execution of EfiLoaderData memory regions. + gEfiMdeModulePkgTokenSpaceGuid.PcdDxeNxMemoryProtectionPolicy|0x7FD1 + !elseif $(LINUX_LOADER) == TRUE + # Allow execution of EfiConventionalMemory, EfiBootServicesData and EfiLoaderData memory regions. + gEfiMdeModulePkgTokenSpaceGuid.PcdDxeNxMemoryProtectionPolicy|0x7F41 + gEfiMdePkgTokenSpaceGuid.PcdImageLoaderAllowMisalignedOffset|TRUE + !elseif $(WINDOWS_10_IA32) == TRUE + # Allow execution of EfiReservedMemoryType, EfiConventionalMemory, EfiBootServicesData and EfiRuntimeServicesData memory regions. + gEfiMdeModulePkgTokenSpaceGuid.PcdDxeNxMemoryProtectionPolicy|0x7F04 + !endif + ################################################################################ # # Pcd Dynamic Section - list of all EDK II PCD Entries defined by this Platform diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc index a39070a626..a79da15629 100644 --- a/OvmfPkg/OvmfPkgIa32X64.dsc +++ b/OvmfPkg/OvmfPkgIa32X64.dsc @@ -52,6 +52,10 @@ !include NetworkPkg/NetworkDefines.dsc.inc + DEFINE LEGACY_WINDOWS_LOADER = FALSE + DEFINE LINUX_LOADER = FALSE + DEFINE WINDOWS_10_IA32 = FALSE + # # Device drivers # @@ -103,19 +107,10 @@ !include NetworkPkg/NetworkBuildOptions.dsc.inc -[BuildOptions.common.EDKII.DXE_RUNTIME_DRIVER] - GCC:*_*_*_DLINK_FLAGS = -z common-page-size=0x1000 - XCODE:*_*_*_DLINK_FLAGS = -seg1addr 0x1000 -segalign 0x1000 - XCODE:*_*_*_MTOC_FLAGS = -align 0x1000 - CLANGPDB:*_*_*_DLINK_FLAGS = /ALIGN:4096 - -# Force PE/COFF sections to be aligned at 4KB boundaries to support page level -# protection of DXE_SMM_DRIVER/SMM_CORE modules -[BuildOptions.common.EDKII.DXE_SMM_DRIVER, BuildOptions.common.EDKII.SMM_CORE] GCC:*_*_*_DLINK_FLAGS = -z common-page-size=0x1000 XCODE:*_*_*_DLINK_FLAGS = -seg1addr 0x1000 -segalign 0x1000 XCODE:*_*_*_MTOC_FLAGS = -align 0x1000 - CLANGPDB:*_*_*_DLINK_FLAGS = /ALIGN:4096 + CLANGPDB:*_*_*_DLINK_FLAGS = /FILEALIGN:4096 /ALIGN:4096 ################################################################################ # @@ -147,7 +142,8 @@ SynchronizationLib|MdePkg/Library/BaseSynchronizationLib/BaseSynchronizationLib.inf CpuLib|MdePkg/Library/BaseCpuLib/BaseCpuLib.inf PerformanceLib|MdePkg/Library/BasePerformanceLibNull/BasePerformanceLibNull.inf - PeCoffLib|MdePkg/Library/BasePeCoffLib/BasePeCoffLib.inf + PeCoffLib2|MdePkg/Library/BasePeCoffLib2/BasePeCoffLib2.inf + UefiImageLib|MdePkg/Library/BaseUefiImageLib/BaseUefiImageLibPeCoff.inf CacheMaintenanceLib|MdePkg/Library/BaseCacheMaintenanceLib/BaseCacheMaintenanceLib.inf UefiDecompressLib|MdePkg/Library/BaseUefiDecompressLib/BaseUefiDecompressLib.inf UefiHiiServicesLib|MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.inf @@ -159,7 +155,6 @@ CapsuleLib|MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.inf DxeServicesLib|MdePkg/Library/DxeServicesLib/DxeServicesLib.inf DxeServicesTableLib|MdePkg/Library/DxeServicesTableLib/DxeServicesTableLib.inf - PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf PciCf8Lib|MdePkg/Library/BasePciCf8Lib/BasePciCf8Lib.inf PciExpressLib|MdePkg/Library/BasePciExpressLib/BasePciExpressLib.inf PciLib|MdePkg/Library/BasePciLibCf8/BasePciLibCf8.inf @@ -202,10 +197,10 @@ FrameBufferBltLib|MdeModulePkg/Library/FrameBufferBltLib/FrameBufferBltLib.inf !if $(SOURCE_DEBUG_ENABLE) == TRUE - PeCoffExtraActionLib|SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLibDebug.inf + UefiImageExtraActionLib|SourceLevelDebugPkg/Library/UefiImageExtraActionLibDebug/UefiImageExtraActionLibDebug.inf DebugCommunicationLib|SourceLevelDebugPkg/Library/DebugCommunicationLibSerialPort/DebugCommunicationLibSerialPort.inf !else - PeCoffExtraActionLib|MdePkg/Library/BasePeCoffExtraActionLibNull/BasePeCoffExtraActionLibNull.inf + UefiImageExtraActionLib|MdePkg/Library/BaseUefiImageExtraActionLibNull/BaseUefiImageExtraActionLibNull.inf DebugAgentLib|MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.inf !endif @@ -287,13 +282,13 @@ PeiCoreEntryPoint|MdePkg/Library/PeiCoreEntryPoint/PeiCoreEntryPoint.inf ReportStatusCodeLib|MdeModulePkg/Library/PeiReportStatusCodeLib/PeiReportStatusCodeLib.inf OemHookStatusCodeLib|MdeModulePkg/Library/OemHookStatusCodeLibNull/OemHookStatusCodeLibNull.inf - PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf !ifdef $(DEBUG_ON_SERIAL_PORT) DebugLib|MdePkg/Library/BaseDebugLibSerialPort/BaseDebugLibSerialPort.inf !else DebugLib|OvmfPkg/Library/PlatformDebugLibIoPort/PlatformRomDebugLibIoPort.inf !endif - PeCoffLib|MdePkg/Library/BasePeCoffLib/BasePeCoffLib.inf + PeCoffLib2|MdePkg/Library/BasePeCoffLib2/BasePeCoffLib2.inf + UefiImageLib|MdePkg/Library/BaseUefiImageLib/BaseUefiImageLibPeCoff.inf [LibraryClasses.common.PEIM] HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf @@ -303,13 +298,13 @@ PeimEntryPoint|MdePkg/Library/PeimEntryPoint/PeimEntryPoint.inf ReportStatusCodeLib|MdeModulePkg/Library/PeiReportStatusCodeLib/PeiReportStatusCodeLib.inf OemHookStatusCodeLib|MdeModulePkg/Library/OemHookStatusCodeLibNull/OemHookStatusCodeLibNull.inf - PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf !ifdef $(DEBUG_ON_SERIAL_PORT) DebugLib|MdePkg/Library/BaseDebugLibSerialPort/BaseDebugLibSerialPort.inf !else DebugLib|OvmfPkg/Library/PlatformDebugLibIoPort/PlatformRomDebugLibIoPort.inf !endif - PeCoffLib|MdePkg/Library/BasePeCoffLib/BasePeCoffLib.inf + PeCoffLib2|MdePkg/Library/BasePeCoffLib2/BasePeCoffLib2.inf + UefiImageLib|MdePkg/Library/BaseUefiImageLib/BaseUefiImageLibPeCoff.inf ResourcePublicationLib|MdePkg/Library/PeiResourcePublicationLib/PeiResourcePublicationLib.inf ExtractGuidedSectionLib|MdePkg/Library/PeiExtractGuidedSectionLib/PeiExtractGuidedSectionLib.inf !if $(SOURCE_DEBUG_ENABLE) == TRUE @@ -542,7 +537,7 @@ # DEBUG_VERBOSE 0x00400000 // Detailed debug messages that may # // significantly impact boot performance # DEBUG_ERROR 0x80000000 // Error - gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevel|0x8000004F + gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevel|0x800000CF !if $(SOURCE_DEBUG_ENABLE) == TRUE gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0x17 @@ -572,6 +567,9 @@ # gUefiCpuPkgTokenSpaceGuid.PcdFirstTimeWakeUpAPsBySipi|FALSE + gEfiMdePkgTokenSpaceGuid.PcdControlFlowEnforcementPropertyMask|0x1 + gEfiMdeModulePkgTokenSpaceGuid.PcdImageProtectionPolicy|0x00000003 + [PcdsFixedAtBuild.IA32] # # The NumberOfPages values below are ad-hoc. They are updated sporadically at @@ -594,12 +592,27 @@ gEfiShellPkgTokenSpaceGuid.PcdShellFileOperationSize|0x20000 !if $(SMM_REQUIRE) == TRUE - gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmStackSize|0x4000 + gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmStackSize|0x8000 !endif # Point to the MdeModulePkg/Application/UiApp/UiApp.inf gEfiMdeModulePkgTokenSpaceGuid.PcdBootManagerMenuFile|{ 0x21, 0xaa, 0x2c, 0x46, 0x14, 0x76, 0x03, 0x45, 0x83, 0x6e, 0x8a, 0xb6, 0xf4, 0x66, 0x23, 0x31 } + # + # Security measures for memory protection. + # + !if $(LEGACY_WINDOWS_LOADER) == TRUE + # Allow execution of EfiLoaderData memory regions. + gEfiMdeModulePkgTokenSpaceGuid.PcdDxeNxMemoryProtectionPolicy|0x7FD1 + !elseif $(LINUX_LOADER) == TRUE + # Allow execution of EfiConventionalMemory, EfiBootServicesData and EfiLoaderData memory regions. + gEfiMdeModulePkgTokenSpaceGuid.PcdDxeNxMemoryProtectionPolicy|0x7F41 + gEfiMdePkgTokenSpaceGuid.PcdImageLoaderAllowMisalignedOffset|TRUE + !elseif $(WINDOWS_10_IA32) == TRUE + # Allow execution of EfiReservedMemoryType, EfiConventionalMemory, EfiBootServicesData and EfiRuntimeServicesData memory regions. + gEfiMdeModulePkgTokenSpaceGuid.PcdDxeNxMemoryProtectionPolicy|0x7F04 + !endif + ################################################################################ # # Pcd Dynamic Section - list of all EDK II PCD Entries defined by this Platform diff --git a/OvmfPkg/OvmfPkgIa32X64.fdf b/OvmfPkg/OvmfPkgIa32X64.fdf index 23a825a012..53f59e9680 100644 --- a/OvmfPkg/OvmfPkgIa32X64.fdf +++ b/OvmfPkg/OvmfPkgIa32X64.fdf @@ -406,7 +406,7 @@ FILE FV_IMAGE = 9E21FD93-9C72-4c15-8C4B-E77F1DB2D792 { [Rule.Common.SEC] FILE SEC = $(NAMED_GUID) { - PE32 PE32 $(INF_OUTPUT)/$(MODULE_NAME).efi + PE32 PE32 Align=Auto $(INF_OUTPUT)/$(MODULE_NAME).efi UI STRING ="$(MODULE_NAME)" Optional VERSION STRING ="$(INF_VERSION)" Optional BUILD_NUM=$(BUILD_NUMBER) } diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc index 1b90aa8f57..b4246987e3 100644 --- a/OvmfPkg/OvmfPkgX64.dsc +++ b/OvmfPkg/OvmfPkgX64.dsc @@ -52,6 +52,9 @@ !include NetworkPkg/NetworkDefines.dsc.inc + DEFINE LEGACY_WINDOWS_LOADER = FALSE + DEFINE LINUX_LOADER = FALSE + # # Device drivers # @@ -160,7 +163,8 @@ SynchronizationLib|MdePkg/Library/BaseSynchronizationLib/BaseSynchronizationLib.inf CpuLib|MdePkg/Library/BaseCpuLib/BaseCpuLib.inf PerformanceLib|MdePkg/Library/BasePerformanceLibNull/BasePerformanceLibNull.inf - PeCoffLib|MdePkg/Library/BasePeCoffLib/BasePeCoffLib.inf + PeCoffLib2|MdePkg/Library/BasePeCoffLib2/BasePeCoffLib2.inf + UefiImageLib|MdePkg/Library/BaseUefiImageLib/BaseUefiImageLibPeCoff.inf CacheMaintenanceLib|MdePkg/Library/BaseCacheMaintenanceLib/BaseCacheMaintenanceLib.inf UefiDecompressLib|MdePkg/Library/BaseUefiDecompressLib/BaseUefiDecompressLib.inf UefiHiiServicesLib|MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.inf @@ -172,7 +176,6 @@ CapsuleLib|MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.inf DxeServicesLib|MdePkg/Library/DxeServicesLib/DxeServicesLib.inf DxeServicesTableLib|MdePkg/Library/DxeServicesTableLib/DxeServicesTableLib.inf - PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf PciCf8Lib|MdePkg/Library/BasePciCf8Lib/BasePciCf8Lib.inf PciExpressLib|MdePkg/Library/BasePciExpressLib/BasePciExpressLib.inf PciLib|MdePkg/Library/BasePciLibCf8/BasePciLibCf8.inf @@ -218,10 +221,10 @@ FrameBufferBltLib|MdeModulePkg/Library/FrameBufferBltLib/FrameBufferBltLib.inf !if $(SOURCE_DEBUG_ENABLE) == TRUE - PeCoffExtraActionLib|SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLibDebug.inf + UefiImageExtraActionLib|SourceLevelDebugPkg/Library/UefiImageExtraActionLibDebug/UefiImageExtraActionLibDebug.inf DebugCommunicationLib|SourceLevelDebugPkg/Library/DebugCommunicationLibSerialPort/DebugCommunicationLibSerialPort.inf !else - PeCoffExtraActionLib|MdePkg/Library/BasePeCoffExtraActionLibNull/BasePeCoffExtraActionLibNull.inf + UefiImageExtraActionLib|MdePkg/Library/BaseUefiImageExtraActionLibNull/BaseUefiImageExtraActionLibNull.inf DebugAgentLib|MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.inf !endif @@ -305,13 +308,13 @@ PeiCoreEntryPoint|MdePkg/Library/PeiCoreEntryPoint/PeiCoreEntryPoint.inf ReportStatusCodeLib|MdeModulePkg/Library/PeiReportStatusCodeLib/PeiReportStatusCodeLib.inf OemHookStatusCodeLib|MdeModulePkg/Library/OemHookStatusCodeLibNull/OemHookStatusCodeLibNull.inf - PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf !ifdef $(DEBUG_ON_SERIAL_PORT) DebugLib|MdePkg/Library/BaseDebugLibSerialPort/BaseDebugLibSerialPort.inf !else DebugLib|OvmfPkg/Library/PlatformDebugLibIoPort/PlatformRomDebugLibIoPort.inf !endif - PeCoffLib|MdePkg/Library/BasePeCoffLib/BasePeCoffLib.inf + PeCoffLib2|MdePkg/Library/BasePeCoffLib2/BasePeCoffLib2.inf + UefiImageLib|MdePkg/Library/BaseUefiImageLib/BaseUefiImageLibPeCoff.inf CcProbeLib|OvmfPkg/Library/CcProbeLib/SecPeiCcProbeLib.inf [LibraryClasses.common.PEIM] @@ -322,13 +325,13 @@ PeimEntryPoint|MdePkg/Library/PeimEntryPoint/PeimEntryPoint.inf ReportStatusCodeLib|MdeModulePkg/Library/PeiReportStatusCodeLib/PeiReportStatusCodeLib.inf OemHookStatusCodeLib|MdeModulePkg/Library/OemHookStatusCodeLibNull/OemHookStatusCodeLibNull.inf - PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf !ifdef $(DEBUG_ON_SERIAL_PORT) DebugLib|MdePkg/Library/BaseDebugLibSerialPort/BaseDebugLibSerialPort.inf !else DebugLib|OvmfPkg/Library/PlatformDebugLibIoPort/PlatformRomDebugLibIoPort.inf !endif - PeCoffLib|MdePkg/Library/BasePeCoffLib/BasePeCoffLib.inf + PeCoffLib2|MdePkg/Library/BasePeCoffLib2/BasePeCoffLib2.inf + UefiImageLib|MdePkg/Library/BaseUefiImageLib/BaseUefiImageLibPeCoff.inf ResourcePublicationLib|MdePkg/Library/PeiResourcePublicationLib/PeiResourcePublicationLib.inf ExtractGuidedSectionLib|MdePkg/Library/PeiExtractGuidedSectionLib/PeiExtractGuidedSectionLib.inf !if $(SOURCE_DEBUG_ENABLE) == TRUE @@ -561,7 +564,7 @@ # DEBUG_VERBOSE 0x00400000 // Detailed debug messages that may # // significantly impact boot performance # DEBUG_ERROR 0x80000000 // Error - gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevel|0x8000004F + gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevel|0x800000CF !if $(SOURCE_DEBUG_ENABLE) == TRUE gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0x17 @@ -618,6 +621,18 @@ # gUefiCpuPkgTokenSpaceGuid.PcdFirstTimeWakeUpAPsBySipi|FALSE + # + # Security measures for memory protection. + # + !if $(LEGACY_WINDOWS_LOADER) == TRUE + # Allow execution of EfiLoaderData memory regions. + gEfiMdeModulePkgTokenSpaceGuid.PcdDxeNxMemoryProtectionPolicy|0x7FD1 + !elseif $(LINUX_LOADER) == TRUE + # Allow execution of EfiConventionalMemory, EfiBootServicesData and EfiLoaderData memory regions. + gEfiMdeModulePkgTokenSpaceGuid.PcdDxeNxMemoryProtectionPolicy|0x7F41 + gEfiMdePkgTokenSpaceGuid.PcdImageLoaderAllowMisalignedOffset|TRUE + !endif + ################################################################################ # # Pcd Dynamic Section - list of all EDK II PCD Entries defined by this Platform diff --git a/OvmfPkg/OvmfXen.dsc b/OvmfPkg/OvmfXen.dsc index 7fc340d1c1..fc394114b8 100644 --- a/OvmfPkg/OvmfXen.dsc +++ b/OvmfPkg/OvmfXen.dsc @@ -129,7 +129,8 @@ SynchronizationLib|MdePkg/Library/BaseSynchronizationLib/BaseSynchronizationLib.inf CpuLib|MdePkg/Library/BaseCpuLib/BaseCpuLib.inf PerformanceLib|MdePkg/Library/BasePerformanceLibNull/BasePerformanceLibNull.inf - PeCoffLib|MdePkg/Library/BasePeCoffLib/BasePeCoffLib.inf + PeCoffLib2|MdePkg/Library/BasePeCoffLib2/BasePeCoffLib2.inf + UefiImageLib|MdePkg/Library/BaseUefiImageLib/BaseUefiImageLibPeCoff.inf CacheMaintenanceLib|MdePkg/Library/BaseCacheMaintenanceLib/BaseCacheMaintenanceLib.inf UefiDecompressLib|MdePkg/Library/BaseUefiDecompressLib/BaseUefiDecompressLib.inf UefiHiiServicesLib|MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.inf @@ -141,7 +142,6 @@ CapsuleLib|MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.inf DxeServicesLib|MdePkg/Library/DxeServicesLib/DxeServicesLib.inf DxeServicesTableLib|MdePkg/Library/DxeServicesTableLib/DxeServicesTableLib.inf - PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf PciCf8Lib|MdePkg/Library/BasePciCf8Lib/BasePciCf8Lib.inf PciExpressLib|MdePkg/Library/BasePciExpressLib/BasePciExpressLib.inf PciLib|MdePkg/Library/BasePciLibCf8/BasePciLibCf8.inf @@ -179,10 +179,10 @@ ImagePropertiesRecordLib|MdeModulePkg/Library/ImagePropertiesRecordLib/ImagePropertiesRecordLib.inf !if $(SOURCE_DEBUG_ENABLE) == TRUE - PeCoffExtraActionLib|SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLibDebug.inf + UefiImageExtraActionLib|SourceLevelDebugPkg/Library/UefiImageExtraActionLibDebug/UefiImageExtraActionLibDebug.inf DebugCommunicationLib|SourceLevelDebugPkg/Library/DebugCommunicationLibSerialPort/DebugCommunicationLibSerialPort.inf !else - PeCoffExtraActionLib|MdePkg/Library/BasePeCoffExtraActionLibNull/BasePeCoffExtraActionLibNull.inf + UefiImageExtraActionLib|MdePkg/Library/BaseUefiImageExtraActionLibNull/BaseUefiImageExtraActionLibNull.inf DebugAgentLib|MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.inf !endif @@ -263,8 +263,8 @@ PeiCoreEntryPoint|MdePkg/Library/PeiCoreEntryPoint/PeiCoreEntryPoint.inf ReportStatusCodeLib|MdeModulePkg/Library/PeiReportStatusCodeLib/PeiReportStatusCodeLib.inf OemHookStatusCodeLib|MdeModulePkg/Library/OemHookStatusCodeLibNull/OemHookStatusCodeLibNull.inf - PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf - PeCoffLib|MdePkg/Library/BasePeCoffLib/BasePeCoffLib.inf + PeCoffLib2|MdePkg/Library/BasePeCoffLib2/BasePeCoffLib2.inf + UefiImageLib|MdePkg/Library/BaseUefiImageLib/BaseUefiImageLibPeCoff.inf [LibraryClasses.common.PEIM] HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf @@ -274,8 +274,8 @@ PeimEntryPoint|MdePkg/Library/PeimEntryPoint/PeimEntryPoint.inf ReportStatusCodeLib|MdeModulePkg/Library/PeiReportStatusCodeLib/PeiReportStatusCodeLib.inf OemHookStatusCodeLib|MdeModulePkg/Library/OemHookStatusCodeLibNull/OemHookStatusCodeLibNull.inf - PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf - PeCoffLib|MdePkg/Library/BasePeCoffLib/BasePeCoffLib.inf + PeCoffLib2|MdePkg/Library/BasePeCoffLib2/BasePeCoffLib2.inf + UefiImageLib|MdePkg/Library/BaseUefiImageLib/BaseUefiImageLibPeCoff.inf ResourcePublicationLib|MdePkg/Library/PeiResourcePublicationLib/PeiResourcePublicationLib.inf ExtractGuidedSectionLib|MdePkg/Library/PeiExtractGuidedSectionLib/PeiExtractGuidedSectionLib.inf !if $(SOURCE_DEBUG_ENABLE) == TRUE diff --git a/OvmfPkg/Sec/SecMain.c b/OvmfPkg/Sec/SecMain.c index 60dfa61842..0d7d4a6dca 100644 --- a/OvmfPkg/Sec/SecMain.c +++ b/OvmfPkg/Sec/SecMain.c @@ -9,6 +9,7 @@ **/ +#include "ProcessorBind.h" #include #include @@ -19,9 +20,9 @@ #include #include #include -#include -#include -#include +#include + +#include #include #include #include @@ -486,7 +487,8 @@ DecompressMemFvs ( EFI_STATUS FindPeiCoreImageBaseInFv ( IN EFI_FIRMWARE_VOLUME_HEADER *Fv, - OUT EFI_PHYSICAL_ADDRESS *PeiCoreImageBase + OUT EFI_PHYSICAL_ADDRESS *PeiCoreImageBase, + OUT UINT32 *PeiCoreImageSize ) { EFI_STATUS Status; @@ -512,6 +514,8 @@ FindPeiCoreImageBaseInFv ( } *PeiCoreImageBase = (EFI_PHYSICAL_ADDRESS)(UINTN)(Section + 1); + // FIXME: Size check, common API? + *PeiCoreImageSize = SECTION_SIZE (Section) - sizeof (*Section); return EFI_SUCCESS; } @@ -569,7 +573,8 @@ GetS3ResumePeiFv ( VOID FindPeiCoreImageBase ( IN OUT EFI_FIRMWARE_VOLUME_HEADER **BootFv, - OUT EFI_PHYSICAL_ADDRESS *PeiCoreImageBase + OUT EFI_PHYSICAL_ADDRESS *PeiCoreImageBase, + OUT UINT32 *PeiCoreImageSize ) { BOOLEAN S3Resume; @@ -599,7 +604,7 @@ FindPeiCoreImageBase ( DecompressMemFvs (BootFv); } - FindPeiCoreImageBaseInFv (*BootFv, PeiCoreImageBase); + FindPeiCoreImageBaseInFv (*BootFv, PeiCoreImageBase, PeiCoreImageSize); } /** @@ -609,7 +614,8 @@ FindPeiCoreImageBase ( EFI_STATUS FindImageBase ( IN EFI_FIRMWARE_VOLUME_HEADER *BootFirmwareVolumePtr, - OUT EFI_PHYSICAL_ADDRESS *SecCoreImageBase + OUT EFI_PHYSICAL_ADDRESS *SecCoreImageBase, + OUT UINT32 *SecCoreImageSize ) { EFI_PHYSICAL_ADDRESS CurrentAddress; @@ -621,6 +627,7 @@ FindImageBase ( EFI_PHYSICAL_ADDRESS EndOfSection; *SecCoreImageBase = 0; + *SecCoreImageSize = 0; CurrentAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)BootFirmwareVolumePtr; EndOfFirmwareVolume = CurrentAddress + BootFirmwareVolumePtr->FvLength; @@ -676,6 +683,7 @@ FindImageBase ( if ((Section->Type == EFI_SECTION_PE32) || (Section->Type == EFI_SECTION_TE)) { if (File->Type == EFI_FV_FILETYPE_SECURITY_CORE) { *SecCoreImageBase = (PHYSICAL_ADDRESS)(UINTN)(Section + 1); + *SecCoreImageSize = Size - sizeof (*Section); } break; @@ -706,39 +714,45 @@ FindAndReportEntryPoints ( { EFI_STATUS Status; EFI_PHYSICAL_ADDRESS SecCoreImageBase; + UINT32 SecCoreImageSize; EFI_PHYSICAL_ADDRESS PeiCoreImageBase; - PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; + UINT32 PeiCoreImageSize; + UEFI_IMAGE_LOADER_IMAGE_CONTEXT ImageContext; // // Find SEC Core and PEI Core image base // - Status = FindImageBase (*BootFirmwareVolumePtr, &SecCoreImageBase); + Status = FindImageBase (*BootFirmwareVolumePtr, &SecCoreImageBase, &SecCoreImageSize); ASSERT_EFI_ERROR (Status); - FindPeiCoreImageBase (BootFirmwareVolumePtr, &PeiCoreImageBase); + FindPeiCoreImageBase (BootFirmwareVolumePtr, &PeiCoreImageBase, &PeiCoreImageSize); - ZeroMem ((VOID *)&ImageContext, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT)); // // Report SEC Core debug information when remote debug is enabled // - ImageContext.ImageAddress = SecCoreImageBase; - ImageContext.PdbPointer = PeCoffLoaderGetPdbPointer ((VOID *)(UINTN)ImageContext.ImageAddress); - PeCoffLoaderRelocateImageExtraAction (&ImageContext); + Status = UefiImageInitializeContext (&ImageContext, (VOID *) (UINTN) SecCoreImageBase, SecCoreImageSize); + ASSERT_EFI_ERROR (Status); + + Status = UefiImageLoadImageInplace (&ImageContext); + ASSERT_EFI_ERROR (Status); + + UefiImageLoaderRelocateImageExtraAction (&ImageContext); // - // Report PEI Core debug information when remote debug is enabled + // Find PEI Core entry point // - ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)PeiCoreImageBase; - ImageContext.PdbPointer = PeCoffLoaderGetPdbPointer ((VOID *)(UINTN)ImageContext.ImageAddress); - PeCoffLoaderRelocateImageExtraAction (&ImageContext); + Status = UefiImageInitializeContext (&ImageContext, (VOID *) (UINTN) PeiCoreImageBase, PeiCoreImageSize); + ASSERT_EFI_ERROR (Status); + + Status = UefiImageLoadImageInplace (&ImageContext); + ASSERT_EFI_ERROR (Status); // - // Find PEI Core entry point + // Report PEI Core debug information when remote debug is enabled // - Status = PeCoffLoaderGetEntryPoint ((VOID *)(UINTN)PeiCoreImageBase, (VOID **)PeiCoreEntryPoint); - if (EFI_ERROR (Status)) { - *PeiCoreEntryPoint = 0; - } + UefiImageLoaderRelocateImageExtraAction (&ImageContext); + + *PeiCoreEntryPoint = (EFI_PEI_CORE_ENTRY_POINT)(UINTN)(UefiImageLoaderGetImageEntryPoint (&ImageContext)); return; } diff --git a/OvmfPkg/Sec/SecMain.inf b/OvmfPkg/Sec/SecMain.inf index 88c2d3fb6d..b388acfe2e 100644 --- a/OvmfPkg/Sec/SecMain.inf +++ b/OvmfPkg/Sec/SecMain.inf @@ -47,9 +47,8 @@ CpuLib DebugAgentLib IoLib - PeCoffLib - PeCoffGetEntryPointLib - PeCoffExtraActionLib + UefiImageLib + UefiImageExtraActionLib ExtractGuidedSectionLib LocalApicLib MemEncryptSevLib diff --git a/OvmfPkg/Tcg/TdTcg2Dxe/MeasureBootPeCoff.c b/OvmfPkg/Tcg/TdTcg2Dxe/MeasureBootPeCoff.c index 4d542156ba..e6e372b6b6 100644 --- a/OvmfPkg/Tcg/TdTcg2Dxe/MeasureBootPeCoff.c +++ b/OvmfPkg/Tcg/TdTcg2Dxe/MeasureBootPeCoff.c @@ -19,11 +19,17 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #include #include #include -#include +#include #include UINTN mTcg2DxeImageSize = 0; +typedef union { + EFI_IMAGE_NT_HEADERS32 *Pe32; + EFI_IMAGE_NT_HEADERS64 *Pe32Plus; + EFI_IMAGE_OPTIONAL_HEADER_UNION *Union; +} EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION; + /** Reads contents of a PE/COFF image in memory buffer. @@ -113,25 +119,19 @@ MeasurePeImageAndExtend ( UINT32 NumberOfRvaAndSizes; UINT32 CertSize; HASH_HANDLE HashHandle; - PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; + UEFI_IMAGE_LOADER_IMAGE_CONTEXT ImageContext; HashHandle = 0xFFFFFFFF; // Know bad value Status = EFI_UNSUPPORTED; SectionHeader = NULL; - // - // Check PE/COFF image - // - ZeroMem (&ImageContext, sizeof (ImageContext)); - ImageContext.Handle = (VOID *)(UINTN)ImageAddress; - mTcg2DxeImageSize = ImageSize; - ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE)Tcg2DxeImageRead; + mTcg2DxeImageSize = ImageSize; // // Get information about the image being loaded // - Status = PeCoffLoaderGetImageInfo (&ImageContext); + Status = UefiImageInitializeContext (&ImageContext, (VOID *) (UINTN) ImageAddress, ImageSize); if (EFI_ERROR (Status)) { // // The information can't be got from the invalid PeImage @@ -147,7 +147,7 @@ MeasurePeImageAndExtend ( } Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINT8 *)(UINTN)ImageAddress + PeCoffHeaderOffset); - if (Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) { + if (Hdr.Pe32->CommonHeader.Signature != EFI_IMAGE_NT_SIGNATURE) { Status = EFI_UNSUPPORTED; goto Finish; } @@ -179,18 +179,18 @@ MeasurePeImageAndExtend ( // 4. Hash the image header from its base to beginning of the image checksum. // HashBase = (UINT8 *)(UINTN)ImageAddress; - if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + if (Hdr.Pe32->Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { // // Use PE32 offset // - NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes; - HashSize = (UINTN)(&Hdr.Pe32->OptionalHeader.CheckSum) - (UINTN)HashBase; + NumberOfRvaAndSizes = Hdr.Pe32->NumberOfRvaAndSizes; + HashSize = (UINTN)(&Hdr.Pe32->CheckSum) - (UINTN)HashBase; } else { // // Use PE32+ offset // - NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes; - HashSize = (UINTN)(&Hdr.Pe32Plus->OptionalHeader.CheckSum) - (UINTN)HashBase; + NumberOfRvaAndSizes = Hdr.Pe32Plus->NumberOfRvaAndSizes; + HashSize = (UINTN)(&Hdr.Pe32Plus->CheckSum) - (UINTN)HashBase; } Status = HashUpdate (HashHandle, HashBase, HashSize); @@ -206,18 +206,18 @@ MeasurePeImageAndExtend ( // 6. Since there is no Cert Directory in optional header, hash everything // from the end of the checksum to the end of image header. // - if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + if (Hdr.Pe32->Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { // // Use PE32 offset. // - HashBase = (UINT8 *)&Hdr.Pe32->OptionalHeader.CheckSum + sizeof (UINT32); - HashSize = Hdr.Pe32->OptionalHeader.SizeOfHeaders - (UINTN)(HashBase - ImageAddress); + HashBase = (UINT8 *)&Hdr.Pe32->CheckSum + sizeof (UINT32); + HashSize = Hdr.Pe32->SizeOfHeaders - (UINTN)(HashBase - ImageAddress); } else { // // Use PE32+ offset. // - HashBase = (UINT8 *)&Hdr.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32); - HashSize = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN)(HashBase - ImageAddress); + HashBase = (UINT8 *)&Hdr.Pe32Plus->CheckSum + sizeof (UINT32); + HashSize = Hdr.Pe32Plus->SizeOfHeaders - (UINTN)(HashBase - ImageAddress); } if (HashSize != 0) { @@ -230,18 +230,18 @@ MeasurePeImageAndExtend ( // // 7. Hash everything from the end of the checksum to the start of the Cert Directory. // - if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + if (Hdr.Pe32->Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { // // Use PE32 offset // - HashBase = (UINT8 *)&Hdr.Pe32->OptionalHeader.CheckSum + sizeof (UINT32); - HashSize = (UINTN)(&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - (UINTN)HashBase; + HashBase = (UINT8 *)&Hdr.Pe32->CheckSum + sizeof (UINT32); + HashSize = (UINTN)(&Hdr.Pe32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - (UINTN)HashBase; } else { // // Use PE32+ offset // - HashBase = (UINT8 *)&Hdr.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32); - HashSize = (UINTN)(&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - (UINTN)HashBase; + HashBase = (UINT8 *)&Hdr.Pe32Plus->CheckSum + sizeof (UINT32); + HashSize = (UINTN)(&Hdr.Pe32Plus->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - (UINTN)HashBase; } if (HashSize != 0) { @@ -255,18 +255,18 @@ MeasurePeImageAndExtend ( // 8. Skip over the Cert Directory. (It is sizeof(IMAGE_DATA_DIRECTORY) bytes.) // 9. Hash everything from the end of the Cert Directory to the end of image header. // - if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + if (Hdr.Pe32->Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { // // Use PE32 offset // - HashBase = (UINT8 *)&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]; - HashSize = Hdr.Pe32->OptionalHeader.SizeOfHeaders - (UINTN)(HashBase - ImageAddress); + HashBase = (UINT8 *)&Hdr.Pe32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]; + HashSize = Hdr.Pe32->SizeOfHeaders - (UINTN)(HashBase - ImageAddress); } else { // // Use PE32+ offset // - HashBase = (UINT8 *)&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]; - HashSize = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN)(HashBase - ImageAddress); + HashBase = (UINT8 *)&Hdr.Pe32Plus->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]; + HashSize = Hdr.Pe32Plus->SizeOfHeaders - (UINTN)(HashBase - ImageAddress); } if (HashSize != 0) { @@ -280,16 +280,16 @@ MeasurePeImageAndExtend ( // // 10. Set the SUM_OF_BYTES_HASHED to the size of the header // - if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + if (Hdr.Pe32->Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { // // Use PE32 offset // - SumOfBytesHashed = Hdr.Pe32->OptionalHeader.SizeOfHeaders; + SumOfBytesHashed = Hdr.Pe32->SizeOfHeaders; } else { // // Use PE32+ offset // - SumOfBytesHashed = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders; + SumOfBytesHashed = Hdr.Pe32Plus->SizeOfHeaders; } // @@ -298,7 +298,7 @@ MeasurePeImageAndExtend ( // header indicates how big the table should be. Do not include any // IMAGE_SECTION_HEADERs in the table whose 'SizeOfRawData' field is zero. // - SectionHeader = (EFI_IMAGE_SECTION_HEADER *)AllocateZeroPool (sizeof (EFI_IMAGE_SECTION_HEADER) * Hdr.Pe32->FileHeader.NumberOfSections); + SectionHeader = (EFI_IMAGE_SECTION_HEADER *)AllocateZeroPool (sizeof (EFI_IMAGE_SECTION_HEADER) * Hdr.Pe32->CommonHeader.FileHeader.NumberOfSections); if (SectionHeader == NULL) { Status = EFI_OUT_OF_RESOURCES; goto Finish; @@ -315,9 +315,9 @@ MeasurePeImageAndExtend ( PeCoffHeaderOffset + sizeof (UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + - Hdr.Pe32->FileHeader.SizeOfOptionalHeader + Hdr.Pe32->CommonHeader.FileHeader.SizeOfOptionalHeader ); - for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) { + for (Index = 0; Index < Hdr.Pe32->CommonHeader.FileHeader.NumberOfSections; Index++) { Pos = Index; while ((Pos > 0) && (Section->PointerToRawData < SectionHeader[Pos - 1].PointerToRawData)) { CopyMem (&SectionHeader[Pos], &SectionHeader[Pos - 1], sizeof (EFI_IMAGE_SECTION_HEADER)); @@ -335,7 +335,7 @@ MeasurePeImageAndExtend ( // 14. Add the section's 'SizeOfRawData' to SUM_OF_BYTES_HASHED . // 15. Repeat steps 13 and 14 for all the sections in the sorted table. // - for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) { + for (Index = 0; Index < Hdr.Pe32->CommonHeader.FileHeader.NumberOfSections; Index++) { Section = (EFI_IMAGE_SECTION_HEADER *)&SectionHeader[Index]; if (Section->SizeOfRawData == 0) { continue; @@ -364,16 +364,16 @@ MeasurePeImageAndExtend ( if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) { CertSize = 0; } else { - if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + if (Hdr.Pe32->Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { // // Use PE32 offset. // - CertSize = Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size; + CertSize = Hdr.Pe32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size; } else { // // Use PE32+ offset. // - CertSize = Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size; + CertSize = Hdr.Pe32Plus->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size; } } diff --git a/OvmfPkg/Tcg/TdTcg2Dxe/TdTcg2Dxe.inf b/OvmfPkg/Tcg/TdTcg2Dxe/TdTcg2Dxe.inf index 6861a1452d..a39dabe4e8 100644 --- a/OvmfPkg/Tcg/TdTcg2Dxe/TdTcg2Dxe.inf +++ b/OvmfPkg/Tcg/TdTcg2Dxe/TdTcg2Dxe.inf @@ -46,7 +46,7 @@ HashLib PerformanceLib ReportStatusCodeLib - PeCoffLib + UefiImageLib TpmMeasurementLib TdxLib diff --git a/README.md b/README.md new file mode 100644 index 0000000000..efa9528d4d --- /dev/null +++ b/README.md @@ -0,0 +1,71 @@ +# PE/COFF loader designed with formal methods + +This branch demonstrates the integration of a new PE/COFF loader designed with the help of formal methods into the EDK II infrastructure. + +## Introduction + +The PE/COFF loader is one of the central components of the firmware core and its trust base. Every Image which is part of a UEFI system, including platform drivers from the primary firmware storage, Option ROMs from external hardware, and OS loaders from arbitrary storage, is verified and loaded by this library. Clearly it is a key component to ensure platform reliability and software compatibility, and can only be modified with great care. It also is an essential component for security technologies such as Secure Boot and Measured Boot. + +![image](LoaderFlow.png) + +Unfortunately, over the years, the current solution has been subject to bug reports affecting platform reliability, some of which have been unresolved to date. Please refer to the TianoCore BugZilla and especially discussions on the edk2-devel mailing list for further reading. Due to the incremental changes to the existing solution over the years, the state of a sound solution has been lost, and it has become a maintenance burden that is hard to fix and further advance incrementally. At the same time, the demand on not only tested but proven security has become more important in the recent times. + +The usage of formal methods to design the new solution greatly helped restore the state of a truly sound solution, resolving many issues regarding inter-API guarantees and Image format validation. Many new abstractions have been introduced, external code has been centralized, and the overall flexibility has been improved, to hopefully aid developers to extend the codebase more easily in the future. Beyond that, the formal model ensures a high level of confidence that security-wise there have been no regressions, and there might even be potential improvements. + +Please also refer to the new work-in-progress documentation available at [MdePkg/Library/BasePeCoffLib2/Documentation.md](MdePkg/Library/BasePeCoffLib2/Documentation.md) + +## Further abstraction + +The new solution has been implemented as a new library class in MdePkg. ``PeCoffLib2`` features a new API that allows for a more resilient and a more flexible caller design. Most notably, all Image operations have been integrated into the API design rather than the callers accessing the library context and duplicating certain work. ``PeCoffLib`` remains intact as deprecated API to support legacy code during the transition period. + +To increase platform flexibility, a new layer of abstraction is introduced in the form of the library class ``UefiImageLib``, which can be found at [MdePkg/Include/Library/UefiImageLib.h](MdePkg/Include/Library/UefiImageLib.h). Currently, it is a subset of the APIs provided by ``PeCoffLib2`` that is expected to be compatible with most other common executable formats, plus a few convenience functions. As part of the proposal, the instance ``UefiImageLibPeCoff`` is provided, which is basically a shim for ``PeCoffLib2``. In the future, instances to support other file formats can be introduced without having to integrate them across the entire EDK II tree. + +## Issues of the current solution +* High level of maintenance cost due to convoluted function contracts +* Error-prone design promoting the introduction of code bugs +* Multiple real-world bugs affecting reliability, some unaddressed for years +* A lot of duplicate caller-side code that decreases the flexibility of porting and integration (e.g. Image permissions in PEI) +* Dependency on Image re-parsing for production code + +## Benefits of the new solution +* Fixes all known reported BugZilla tickets on PE/COFF loader reliability +* Formal methods increase confidence in a high level of reliability and security +* Improved design eases future maintenance and extension +* Architecture-independent Image processing (e.g. for emulation) +* Support for more granular Image section permissions (e.g. read-only) + +## Benefits of the formal methods involved +* Complete proof arithmetic cannot overflow (excluding intentional modulo arithmetic) +* Mostly complete proof memory accesses are safe (requires axioms) +* Complete proof of Image format compliance verification +* Complete proof of Image loading +* Mostly complete proof of Image relocation (final memory state cannot be easily described) + +## Further notes about the formal approach +* A snapshot of the new PE/COFF loader code will be provided with annotations and proving results +* The snapshot will not be current and updating the old code is out of the scope of this project, however the functional changes should be manageable to review +* We are currently investigating whether deploying the proving environment as a Docker container is feasible +* There may be aids to compare the updates over the last fully verified state (e.g. stripped versions of the code with diffs) +* If accepted, the new PE/COFF loader code should be developed further without updating the formal annotations, but with thorough review of important invariants and sufficient documentation + +## Current progress, future goals, and further notes +* OVMF boots to Shell with SMM and Secure Boot enabled +* Linux EmulatorPkg boots +* Extended support for Image protection has been implemented +* FFS and DebugTable enhancements have been implemented +* Not all features have been implemented, e.g. RISC-V support +* There are unrelated changes present to help testing and validation +* Specified interfaces need adjustments (e.g. security architectural protocol) +* Some validation is still absent + +## BZs fixed by integrating the new PE/COFF loader +* https://bugzilla.tianocore.org/show_bug.cgi?id=1860 +* https://bugzilla.tianocore.org/show_bug.cgi?id=1999 +* https://bugzilla.tianocore.org/show_bug.cgi?id=2120 +* https://bugzilla.tianocore.org/show_bug.cgi?id=3329 +* More to be added shortly... + +## BZs easier to address by integrating the new PE/COFF loader +* https://bugzilla.tianocore.org/show_bug.cgi?id=3326 +* https://bugzilla.tianocore.org/show_bug.cgi?id=3331 +* More to be added shortly... diff --git a/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c index b05da19c2b..af242af142 100644 --- a/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c +++ b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c @@ -19,22 +19,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include "DxeImageVerificationLib.h" - -// -// Caution: This is used by a function which may receive untrusted input. -// These global variables hold PE/COFF image data, and they should be validated before use. -// -EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION mNtHeader; -UINT32 mPeCoffHeaderOffset; -EFI_GUID mCertType; - -// -// Information on current PE/COFF image -// -UINTN mImageSize; -UINT8 *mImageBase = NULL; -UINT8 mImageDigest[MAX_DIGEST_SIZE]; -UINTN mImageDigestSize; +#include "Library/BaseCryptLib.h" +#include "Library/UefiImageLib.h" // // Notify string for authorization UI. @@ -57,20 +43,24 @@ UINT8 mHashOidValue[] = { 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, // OBJ_sha512 }; -HASH_TABLE mHash[] = { - #ifndef DISABLE_SHA1_DEPRECATED_INTERFACES - { L"SHA1", 20, &mHashOidValue[0], 5, Sha1GetContextSize, Sha1Init, Sha1Update, Sha1Final }, - #else - { L"SHA1", 20, &mHashOidValue[0], 5, NULL, NULL, NULL, NULL }, - #endif - { L"SHA224", 28, &mHashOidValue[5], 9, NULL, NULL, NULL, NULL }, - { L"SHA256", 32, &mHashOidValue[14], 9, Sha256GetContextSize, Sha256Init, Sha256Update, Sha256Final }, - { L"SHA384", 48, &mHashOidValue[23], 9, Sha384GetContextSize, Sha384Init, Sha384Update, Sha384Final }, - { L"SHA512", 64, &mHashOidValue[32], 9, Sha512GetContextSize, Sha512Init, Sha512Update, Sha512Final } +// +// Support hash types +// +#define HASHALG_SHA256 0x00000000 +#define HASHALG_SHA384 0x00000001 +#define HASHALG_SHA512 0x00000002 +#define HASHALG_SHA1 0x00000003 +#define HASHALG_MAX 0x00000004 + +HASH_TABLE mHash[] = { + { L"SHA256", 32, &mHashOidValue[14], 9, &gEfiCertSha256Guid, Sha256GetContextSize, Sha256Init, Sha256Update, Sha256Final }, + { L"SHA384", 48, &mHashOidValue[23], 9, &gEfiCertSha384Guid, Sha384GetContextSize, Sha384Init, Sha384Update, Sha384Final }, + { L"SHA512", 64, &mHashOidValue[32], 9, &gEfiCertSha512Guid, Sha512GetContextSize, Sha512Init, Sha512Update, Sha512Final }, +#ifndef DISABLE_SHA1_DEPRECATED_INTERFACES + { L"SHA1", 20, &mHashOidValue[0], 5, &gEfiCertSha1Guid, Sha1GetContextSize, Sha1Init, Sha1Update, Sha1Final }, +#endif }; -EFI_STRING mHashTypeStr; - /** SecureBoot Hook for processing image verification. @@ -90,54 +80,6 @@ SecureBootHook ( IN VOID *Data ); -/** - Reads contents of a PE/COFF image in memory buffer. - - Caution: This function may receive untrusted input. - PE/COFF image is external input, so this function will make sure the PE/COFF image content - read is within the image buffer. - - @param FileHandle Pointer to the file handle to read the PE/COFF image. - @param FileOffset Offset into the PE/COFF image to begin the read operation. - @param ReadSize On input, the size in bytes of the requested read operation. - On output, the number of bytes actually read. - @param Buffer Output buffer that contains the data read from the PE/COFF image. - - @retval EFI_SUCCESS The specified portion of the PE/COFF image was read and the size -**/ -EFI_STATUS -EFIAPI -DxeImageVerificationLibImageRead ( - IN VOID *FileHandle, - IN UINTN FileOffset, - IN OUT UINTN *ReadSize, - OUT VOID *Buffer - ) -{ - UINTN EndPosition; - - if ((FileHandle == NULL) || (ReadSize == NULL) || (Buffer == NULL)) { - return EFI_INVALID_PARAMETER; - } - - if (MAX_ADDRESS - FileOffset < *ReadSize) { - return EFI_INVALID_PARAMETER; - } - - EndPosition = FileOffset + *ReadSize; - if (EndPosition > mImageSize) { - *ReadSize = (UINT32)(mImageSize - FileOffset); - } - - if (FileOffset >= mImageSize) { - *ReadSize = 0; - } - - CopyMem (Buffer, (UINT8 *)((UINTN)FileHandle + FileOffset), *ReadSize); - - return EFI_SUCCESS; -} - /** Get the image type. @@ -279,7 +221,7 @@ GetImageType ( PE/COFF image is external input, so this function will validate its data structure within this image buffer before use. - Notes: PE/COFF image has been checked by BasePeCoffLib PeCoffLoaderGetImageInfo() in + Notes: PE/COFF image has been checked by UefiImageLibLib UefiImageInitializeContext() in its caller function DxeImageVerificationHandler(). @param[in] HashAlg Hash algorithm type. @@ -290,318 +232,54 @@ GetImageType ( **/ BOOLEAN HashPeImage ( - IN UINT32 HashAlg + IN UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext, + IN HASH_TABLE *HashAlg, + OUT UINT8 ImageDigest[MAX_DIGEST_SIZE], + OUT UINTN *ImageDigestSize ) { - BOOLEAN Status; - EFI_IMAGE_SECTION_HEADER *Section; - VOID *HashCtx; - UINTN CtxSize; - UINT8 *HashBase; - UINTN HashSize; - UINTN SumOfBytesHashed; - EFI_IMAGE_SECTION_HEADER *SectionHeader; - UINTN Index; - UINTN Pos; - UINT32 CertSize; - UINT32 NumberOfRvaAndSizes; - - HashCtx = NULL; - SectionHeader = NULL; - Status = FALSE; + BOOLEAN Status; + VOID *HashCtx; + UINTN CtxSize; - if ((HashAlg >= HASHALG_MAX)) { - return FALSE; - } + HashCtx = NULL; + Status = FALSE; // // Initialize context of hash. // - ZeroMem (mImageDigest, MAX_DIGEST_SIZE); - - switch (HashAlg) { - #ifndef DISABLE_SHA1_DEPRECATED_INTERFACES - case HASHALG_SHA1: - mImageDigestSize = SHA1_DIGEST_SIZE; - mCertType = gEfiCertSha1Guid; - break; - #endif - - case HASHALG_SHA256: - mImageDigestSize = SHA256_DIGEST_SIZE; - mCertType = gEfiCertSha256Guid; - break; - - case HASHALG_SHA384: - mImageDigestSize = SHA384_DIGEST_SIZE; - mCertType = gEfiCertSha384Guid; - break; - - case HASHALG_SHA512: - mImageDigestSize = SHA512_DIGEST_SIZE; - mCertType = gEfiCertSha512Guid; - break; - - default: - return FALSE; - } + ZeroMem (ImageDigest, MAX_DIGEST_SIZE); - mHashTypeStr = mHash[HashAlg].Name; - CtxSize = mHash[HashAlg].GetContextSize (); + CtxSize = HashAlg->GetContextSize (); HashCtx = AllocatePool (CtxSize); if (HashCtx == NULL) { return FALSE; } - // 1. Load the image header into memory. - - // 2. Initialize a SHA hash context. - Status = mHash[HashAlg].HashInit (HashCtx); + Status = HashAlg->HashInit (HashCtx); if (!Status) { goto Done; } - // - // Measuring PE/COFF Image Header; - // But CheckSum field and SECURITY data directory (certificate) are excluded - // - - // - // 3. Calculate the distance from the base of the image header to the image checksum address. - // 4. Hash the image header from its base to beginning of the image checksum. - // - HashBase = mImageBase; - if (mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { - // - // Use PE32 offset. - // - HashSize = (UINTN)(&mNtHeader.Pe32->OptionalHeader.CheckSum) - (UINTN)HashBase; - NumberOfRvaAndSizes = mNtHeader.Pe32->OptionalHeader.NumberOfRvaAndSizes; - } else if (mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) { - // - // Use PE32+ offset. - // - HashSize = (UINTN)(&mNtHeader.Pe32Plus->OptionalHeader.CheckSum) - (UINTN)HashBase; - NumberOfRvaAndSizes = mNtHeader.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes; - } else { - // - // Invalid header magic number. - // - Status = FALSE; - goto Done; - } + Status = UefiImageHashImageDefault (ImageContext, HashCtx, HashAlg->HashUpdate); - Status = mHash[HashAlg].HashUpdate (HashCtx, HashBase, HashSize); if (!Status) { + DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Failed to hash this image using %s.\n", HashAlg->Name)); goto Done; } - // - // 5. Skip over the image checksum (it occupies a single ULONG). - // - if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) { - // - // 6. Since there is no Cert Directory in optional header, hash everything - // from the end of the checksum to the end of image header. - // - if (mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { - // - // Use PE32 offset. - // - HashBase = (UINT8 *)&mNtHeader.Pe32->OptionalHeader.CheckSum + sizeof (UINT32); - HashSize = mNtHeader.Pe32->OptionalHeader.SizeOfHeaders - ((UINTN)HashBase - (UINTN)mImageBase); - } else { - // - // Use PE32+ offset. - // - HashBase = (UINT8 *)&mNtHeader.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32); - HashSize = mNtHeader.Pe32Plus->OptionalHeader.SizeOfHeaders - ((UINTN)HashBase - (UINTN)mImageBase); - } - - if (HashSize != 0) { - Status = mHash[HashAlg].HashUpdate (HashCtx, HashBase, HashSize); - if (!Status) { - goto Done; - } - } - } else { - // - // 7. Hash everything from the end of the checksum to the start of the Cert Directory. - // - if (mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { - // - // Use PE32 offset. - // - HashBase = (UINT8 *)&mNtHeader.Pe32->OptionalHeader.CheckSum + sizeof (UINT32); - HashSize = (UINTN)(&mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - (UINTN)HashBase; - } else { - // - // Use PE32+ offset. - // - HashBase = (UINT8 *)&mNtHeader.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32); - HashSize = (UINTN)(&mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - (UINTN)HashBase; - } - - if (HashSize != 0) { - Status = mHash[HashAlg].HashUpdate (HashCtx, HashBase, HashSize); - if (!Status) { - goto Done; - } - } - - // - // 8. Skip over the Cert Directory. (It is sizeof(IMAGE_DATA_DIRECTORY) bytes.) - // 9. Hash everything from the end of the Cert Directory to the end of image header. - // - if (mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { - // - // Use PE32 offset - // - HashBase = (UINT8 *)&mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]; - HashSize = mNtHeader.Pe32->OptionalHeader.SizeOfHeaders - ((UINTN)HashBase - (UINTN)mImageBase); - } else { - // - // Use PE32+ offset. - // - HashBase = (UINT8 *)&mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]; - HashSize = mNtHeader.Pe32Plus->OptionalHeader.SizeOfHeaders - ((UINTN)HashBase - (UINTN)mImageBase); - } + ASSERT (HashAlg->DigestLength <= MAX_DIGEST_SIZE); + Status = HashAlg->HashFinal(HashCtx, ImageDigest); - if (HashSize != 0) { - Status = mHash[HashAlg].HashUpdate (HashCtx, HashBase, HashSize); - if (!Status) { - goto Done; - } - } - } - - // - // 10. Set the SUM_OF_BYTES_HASHED to the size of the header. - // - if (mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { - // - // Use PE32 offset. - // - SumOfBytesHashed = mNtHeader.Pe32->OptionalHeader.SizeOfHeaders; - } else { - // - // Use PE32+ offset - // - SumOfBytesHashed = mNtHeader.Pe32Plus->OptionalHeader.SizeOfHeaders; - } - - Section = (EFI_IMAGE_SECTION_HEADER *)( - mImageBase + - mPeCoffHeaderOffset + - sizeof (UINT32) + - sizeof (EFI_IMAGE_FILE_HEADER) + - mNtHeader.Pe32->FileHeader.SizeOfOptionalHeader - ); - - // - // 11. Build a temporary table of pointers to all the IMAGE_SECTION_HEADER - // structures in the image. The 'NumberOfSections' field of the image - // header indicates how big the table should be. Do not include any - // IMAGE_SECTION_HEADERs in the table whose 'SizeOfRawData' field is zero. - // - SectionHeader = (EFI_IMAGE_SECTION_HEADER *)AllocateZeroPool (sizeof (EFI_IMAGE_SECTION_HEADER) * mNtHeader.Pe32->FileHeader.NumberOfSections); - if (SectionHeader == NULL) { - Status = FALSE; - goto Done; - } - - // - // 12. Using the 'PointerToRawData' in the referenced section headers as - // a key, arrange the elements in the table in ascending order. In other - // words, sort the section headers according to the disk-file offset of - // the section. - // - for (Index = 0; Index < mNtHeader.Pe32->FileHeader.NumberOfSections; Index++) { - Pos = Index; - while ((Pos > 0) && (Section->PointerToRawData < SectionHeader[Pos - 1].PointerToRawData)) { - CopyMem (&SectionHeader[Pos], &SectionHeader[Pos - 1], sizeof (EFI_IMAGE_SECTION_HEADER)); - Pos--; - } - - CopyMem (&SectionHeader[Pos], Section, sizeof (EFI_IMAGE_SECTION_HEADER)); - Section += 1; - } - - // - // 13. Walk through the sorted table, bring the corresponding section - // into memory, and hash the entire section (using the 'SizeOfRawData' - // field in the section header to determine the amount of data to hash). - // 14. Add the section's 'SizeOfRawData' to SUM_OF_BYTES_HASHED . - // 15. Repeat steps 13 and 14 for all the sections in the sorted table. - // - for (Index = 0; Index < mNtHeader.Pe32->FileHeader.NumberOfSections; Index++) { - Section = &SectionHeader[Index]; - if (Section->SizeOfRawData == 0) { - continue; - } - - HashBase = mImageBase + Section->PointerToRawData; - HashSize = (UINTN)Section->SizeOfRawData; - - Status = mHash[HashAlg].HashUpdate (HashCtx, HashBase, HashSize); - if (!Status) { - goto Done; - } - - SumOfBytesHashed += HashSize; - } - - // - // 16. If the file size is greater than SUM_OF_BYTES_HASHED, there is extra - // data in the file that needs to be added to the hash. This data begins - // at file offset SUM_OF_BYTES_HASHED and its length is: - // FileSize - (CertDirectory->Size) - // - if (mImageSize > SumOfBytesHashed) { - HashBase = mImageBase + SumOfBytesHashed; - - if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) { - CertSize = 0; - } else { - if (mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { - // - // Use PE32 offset. - // - CertSize = mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size; - } else { - // - // Use PE32+ offset. - // - CertSize = mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size; - } - } - - if (mImageSize > CertSize + SumOfBytesHashed) { - HashSize = (UINTN)(mImageSize - CertSize - SumOfBytesHashed); - - Status = mHash[HashAlg].HashUpdate (HashCtx, HashBase, HashSize); - if (!Status) { - goto Done; - } - } else if (mImageSize < CertSize + SumOfBytesHashed) { - Status = FALSE; - goto Done; - } - } - - Status = mHash[HashAlg].HashFinal (HashCtx, mImageDigest); + *ImageDigestSize = HashAlg->DigestLength; Done: if (HashCtx != NULL) { FreePool (HashCtx); } - if (SectionHeader != NULL) { - FreePool (SectionHeader); - } - return Status; } @@ -623,34 +301,38 @@ HashPeImage ( **/ EFI_STATUS HashPeImageByType ( - IN UINT8 *AuthData, - IN UINTN AuthDataSize + IN UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext, + IN CONST UINT8 *AuthData, + IN UINTN AuthDataSize, + OUT UINT8 ImageDigest[MAX_DIGEST_SIZE], + OUT UINTN *ImageDigestSize, + OUT CONST EFI_GUID **CertType ) { UINT8 Index; - for (Index = 0; Index < HASHALG_MAX; Index++) { + // + // Check the Hash algorithm in PE/COFF Authenticode. + // According to PKCS#7 Definition: + // SignedData ::= SEQUENCE { + // version Version, + // digestAlgorithms DigestAlgorithmIdentifiers, + // contentInfo ContentInfo, + // .... } + // The DigestAlgorithmIdentifiers can be used to determine the hash algorithm in PE/COFF hashing + // This field has the fixed offset (+32) in final Authenticode ASN.1 data. + // Fixed offset (+32) is calculated based on two bytes of length encoding. + // + if ((*(AuthData + 1) & TWO_BYTE_ENCODE) != TWO_BYTE_ENCODE) { // - // Check the Hash algorithm in PE/COFF Authenticode. - // According to PKCS#7 Definition: - // SignedData ::= SEQUENCE { - // version Version, - // digestAlgorithms DigestAlgorithmIdentifiers, - // contentInfo ContentInfo, - // .... } - // The DigestAlgorithmIdentifiers can be used to determine the hash algorithm in PE/COFF hashing - // This field has the fixed offset (+32) in final Authenticode ASN.1 data. - // Fixed offset (+32) is calculated based on two bytes of length encoding. + // Only support two bytes of Long Form of Length Encoding. // - if ((*(AuthData + 1) & TWO_BYTE_ENCODE) != TWO_BYTE_ENCODE) { - // - // Only support two bytes of Long Form of Length Encoding. - // - continue; - } + return EFI_UNSUPPORTED; + } + for (Index = 0; Index < HASHALG_MAX; Index++) { if (AuthDataSize < 32 + mHash[Index].OidLength) { - return EFI_UNSUPPORTED; + continue; } if (CompareMem (AuthData + 32, mHash[Index].OidValue, mHash[Index].OidLength) == 0) { @@ -665,10 +347,12 @@ HashPeImageByType ( // // HASH PE Image based on Hash algorithm in PE/COFF Authenticode. // - if (!HashPeImage (Index)) { + if (!HashPeImage (ImageContext, &mHash[Index], ImageDigest, ImageDigestSize)) { return EFI_UNSUPPORTED; } + *CertType = mHash[Index].CertType; + return EFI_SUCCESS; } @@ -980,11 +664,11 @@ IsCertHashFoundInDbx ( **/ EFI_STATUS IsSignatureFoundInDatabase ( - IN CHAR16 *VariableName, - IN UINT8 *Signature, - IN EFI_GUID *CertType, - IN UINTN SignatureSize, - OUT BOOLEAN *IsFound + IN CHAR16 *VariableName, + IN UINT8 *Signature, + IN CONST EFI_GUID *CertType, + IN UINTN SignatureSize, + OUT BOOLEAN *IsFound ) { EFI_STATUS Status; @@ -1137,9 +821,9 @@ IsTimeZero ( **/ BOOLEAN PassTimestampCheck ( - IN UINT8 *AuthData, - IN UINTN AuthDataSize, - IN EFI_TIME *RevocationTime + IN CONST UINT8 *AuthData, + IN UINTN AuthDataSize, + IN EFI_TIME *RevocationTime ) { EFI_STATUS Status; @@ -1244,8 +928,10 @@ PassTimestampCheck ( **/ BOOLEAN IsForbiddenByDbx ( - IN UINT8 *AuthData, - IN UINTN AuthDataSize + IN CONST UINT8 *AuthData, + IN UINTN AuthDataSize, + UINT8 ImageDigest[MAX_DIGEST_SIZE], + UINTN ImageDigestSize ) { EFI_STATUS Status; @@ -1338,8 +1024,8 @@ IsForbiddenByDbx ( AuthDataSize, RootCert, RootCertSize, - mImageDigest, - mImageDigestSize + ImageDigest, + ImageDigestSize ); if (IsForbidden) { DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Image is signed but signature is forbidden by DBX.\n")); @@ -1440,8 +1126,10 @@ IsForbiddenByDbx ( **/ BOOLEAN IsAllowedByDb ( - IN UINT8 *AuthData, - IN UINTN AuthDataSize + IN CONST UINT8 *AuthData, + IN UINTN AuthDataSize, + OUT UINT8 ImageDigest[MAX_DIGEST_SIZE], + OUT UINTN ImageDigestSize ) { EFI_STATUS Status; @@ -1543,8 +1231,8 @@ IsAllowedByDb ( AuthDataSize, RootCert, RootCertSize, - mImageDigest, - mImageDigestSize + ImageDigest, + ImageDigestSize ); if (VerifyStatus) { // @@ -1663,28 +1351,16 @@ DxeImageVerificationHandler ( IN BOOLEAN BootPolicy ) { - EFI_IMAGE_DOS_HEADER *DosHdr; BOOLEAN IsVerified; EFI_SIGNATURE_LIST *SignatureList; UINTN SignatureListSize; EFI_SIGNATURE_DATA *Signature; EFI_IMAGE_EXECUTION_ACTION Action; - WIN_CERTIFICATE *WinCertificate; UINT32 Policy; UINT8 SecureBoot; UINTN SecureBootSize; - PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; - UINT32 NumberOfRvaAndSizes; - WIN_CERTIFICATE_EFI_PKCS *PkcsCertData; - WIN_CERTIFICATE_UEFI_GUID *WinCertUefiGuid; - UINT8 *AuthData; UINTN AuthDataSize; - EFI_IMAGE_DATA_DIRECTORY *SecDataDir; - UINT32 SecDataDirEnd; - UINT32 SecDataDirLeft; - UINT32 OffSet; CHAR16 *NameStr; - RETURN_STATUS PeCoffStatus; EFI_STATUS HashStatus; EFI_STATUS DbStatus; EFI_STATUS VarStatus; @@ -1693,16 +1369,29 @@ DxeImageVerificationHandler ( UINT8 HashAlg; BOOLEAN IsFoundInDatabase; + CONST WIN_CERTIFICATE *WinCertificate; + CONST WIN_CERTIFICATE_EFI_PKCS *PkcsCertData; + CONST WIN_CERTIFICATE_UEFI_GUID *WinCertUefiGuid; + CONST UINT8 *AuthData; + UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext; + + UINT8 ImageDigest[MAX_DIGEST_SIZE]; + UINTN ImageDigestSize; + CONST EFI_GUID *CertType; + SignatureList = NULL; SignatureListSize = 0; WinCertificate = NULL; - SecDataDir = NULL; PkcsCertData = NULL; Action = EFI_IMAGE_EXECUTION_AUTH_UNTESTED; IsVerified = FALSE; IsFound = FALSE; IsFoundInDatabase = FALSE; + // FIXME: + ASSERT (FileSize == sizeof (UEFI_IMAGE_LOADER_IMAGE_CONTEXT)); + ImageContext = FileBuffer; + // // Check the image type and get policy setting. // @@ -1775,70 +1464,12 @@ DxeImageVerificationHandler ( return EFI_ACCESS_DENIED; } - mImageBase = (UINT8 *)FileBuffer; - mImageSize = FileSize; - - ZeroMem (&ImageContext, sizeof (ImageContext)); - ImageContext.Handle = (VOID *)FileBuffer; - ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE)DxeImageVerificationLibImageRead; - - // - // Get information about the image being loaded - // - PeCoffStatus = PeCoffLoaderGetImageInfo (&ImageContext); - if (RETURN_ERROR (PeCoffStatus)) { - // - // The information can't be got from the invalid PeImage - // - DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: PeImage invalid. Cannot retrieve image information.\n")); - goto Failed; - } - - DosHdr = (EFI_IMAGE_DOS_HEADER *)mImageBase; - if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) { - // - // DOS image header is present, - // so read the PE header after the DOS image header. - // - mPeCoffHeaderOffset = DosHdr->e_lfanew; - } else { - mPeCoffHeaderOffset = 0; - } - - // - // Check PE/COFF image. - // - mNtHeader.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)(mImageBase + mPeCoffHeaderOffset); - if (mNtHeader.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) { - // - // It is not a valid Pe/Coff file. - // - DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Not a valid PE/COFF image.\n")); - goto Failed; - } - - if (mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { - // - // Use PE32 offset. - // - NumberOfRvaAndSizes = mNtHeader.Pe32->OptionalHeader.NumberOfRvaAndSizes; - if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) { - SecDataDir = (EFI_IMAGE_DATA_DIRECTORY *)&mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]; - } - } else { - // - // Use PE32+ offset. - // - NumberOfRvaAndSizes = mNtHeader.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes; - if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) { - SecDataDir = (EFI_IMAGE_DATA_DIRECTORY *)&mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]; - } - } + HashStatus = UefiImageGetFirstCertificate (ImageContext, &WinCertificate); // // Start Image Validation. // - if ((SecDataDir == NULL) || (SecDataDir->Size == 0)) { + if (HashStatus == RETURN_NOT_FOUND) { // // This image is not signed. The hash value of the image must match a record in the security database "db", // and not be reflected in the security data base "dbx". @@ -1850,30 +1481,32 @@ DxeImageVerificationHandler ( continue; } - if (!HashPeImage (HashAlg)) { + if (!HashPeImage (ImageContext, &mHash[HashAlg], ImageDigest, &ImageDigestSize)) { continue; } + CertType = mHash[HashAlg].CertType; + DbStatus = IsSignatureFoundInDatabase ( EFI_IMAGE_SECURITY_DATABASE1, - mImageDigest, - &mCertType, - mImageDigestSize, + ImageDigest, + CertType, + ImageDigestSize, &IsFound ); if (EFI_ERROR (DbStatus) || IsFound) { // // Image Hash is in forbidden database (DBX). // - DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Image is not signed and %s hash of image is forbidden by DBX.\n", mHashTypeStr)); + DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Image is not signed and hash of image is forbidden by DBX.\n")); goto Failed; } DbStatus = IsSignatureFoundInDatabase ( EFI_IMAGE_SECURITY_DATABASE, - mImageDigest, - &mCertType, - mImageDigestSize, + ImageDigest, + CertType, + ImageDigestSize, &IsFound ); if (!EFI_ERROR (DbStatus) && IsFound) { @@ -1891,7 +1524,7 @@ DxeImageVerificationHandler ( // // Image Hash is not found in both forbidden and allowed database. // - DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Image is not signed and %s hash of image is not found in DB/DBX.\n", mHashTypeStr)); + DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Image is not signed and hash of image is not found in DB/DBX.\n")); goto Failed; } @@ -1900,24 +1533,12 @@ DxeImageVerificationHandler ( // "Attribute Certificate Table". // The first certificate starts at offset (SecDataDir->VirtualAddress) from the start of the file. // - SecDataDirEnd = SecDataDir->VirtualAddress + SecDataDir->Size; - for (OffSet = SecDataDir->VirtualAddress; - OffSet < SecDataDirEnd; - OffSet += (WinCertificate->dwLength + ALIGN_SIZE (WinCertificate->dwLength))) + for ( + ; + !RETURN_ERROR (HashStatus); + HashStatus = UefiImageGetNextCertificate (ImageContext, &WinCertificate) + ) { - SecDataDirLeft = SecDataDirEnd - OffSet; - if (SecDataDirLeft <= sizeof (WIN_CERTIFICATE)) { - break; - } - - WinCertificate = (WIN_CERTIFICATE *)(mImageBase + OffSet); - if ((SecDataDirLeft < WinCertificate->dwLength) || - (SecDataDirLeft - WinCertificate->dwLength < - ALIGN_SIZE (WinCertificate->dwLength))) - { - break; - } - // // Verify the image's Authenticode signature, only DER-encoded PKCS#7 signed data is supported. // @@ -1926,7 +1547,7 @@ DxeImageVerificationHandler ( // The certificate is formatted as WIN_CERTIFICATE_EFI_PKCS which is described in the // Authenticode specification. // - PkcsCertData = (WIN_CERTIFICATE_EFI_PKCS *)WinCertificate; + PkcsCertData = (CONST WIN_CERTIFICATE_EFI_PKCS *)WinCertificate; if (PkcsCertData->Hdr.dwLength <= sizeof (PkcsCertData->Hdr)) { break; } @@ -1937,26 +1558,23 @@ DxeImageVerificationHandler ( // // The certificate is formatted as WIN_CERTIFICATE_UEFI_GUID which is described in UEFI Spec. // - WinCertUefiGuid = (WIN_CERTIFICATE_UEFI_GUID *)WinCertificate; - if (WinCertUefiGuid->Hdr.dwLength <= OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData)) { - break; - } + WinCertUefiGuid = (CONST WIN_CERTIFICATE_UEFI_GUID *)WinCertificate; if (!CompareGuid (&WinCertUefiGuid->CertType, &gEfiCertPkcs7Guid)) { continue; } + if (WinCertUefiGuid->Hdr.dwLength <= OFFSET_OF(WIN_CERTIFICATE_UEFI_GUID, CertData)) { + break; + } AuthData = WinCertUefiGuid->CertData; AuthDataSize = WinCertUefiGuid->Hdr.dwLength - OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData); } else { - if (WinCertificate->dwLength < sizeof (WIN_CERTIFICATE)) { - break; - } continue; } - HashStatus = HashPeImageByType (AuthData, AuthDataSize); + HashStatus = HashPeImageByType (ImageContext, AuthData, AuthDataSize, ImageDigest, &ImageDigestSize, &CertType); if (EFI_ERROR (HashStatus)) { continue; } @@ -1964,17 +1582,16 @@ DxeImageVerificationHandler ( // // Check the digital signature against the revoked certificate in forbidden database (dbx). // - if (IsForbiddenByDbx (AuthData, AuthDataSize)) { + if (IsForbiddenByDbx (AuthData, AuthDataSize, ImageDigest, ImageDigestSize)) { Action = EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED; IsVerified = FALSE; - break; } // // Check the digital signature against the valid certificate in allowed database (db). // if (!IsVerified) { - if (IsAllowedByDb (AuthData, AuthDataSize)) { + if (IsAllowedByDb (AuthData, AuthDataSize, ImageDigest, ImageDigestSize)) { IsVerified = TRUE; } } @@ -1984,14 +1601,14 @@ DxeImageVerificationHandler ( // DbStatus = IsSignatureFoundInDatabase ( EFI_IMAGE_SECURITY_DATABASE1, - mImageDigest, - &mCertType, - mImageDigestSize, + ImageDigest, + CertType, + ImageDigestSize, &IsFound ); if (EFI_ERROR (DbStatus) || IsFound) { Action = EFI_IMAGE_EXECUTION_AUTH_SIG_FOUND; - DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Image is signed but %s hash of image is found in DBX.\n", mHashTypeStr)); + DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Image is signed but hash of image is found in DBX.\n")); IsVerified = FALSE; break; } @@ -1999,36 +1616,28 @@ DxeImageVerificationHandler ( if (!IsVerified) { DbStatus = IsSignatureFoundInDatabase ( EFI_IMAGE_SECURITY_DATABASE, - mImageDigest, - &mCertType, - mImageDigestSize, + ImageDigest, + CertType, + ImageDigestSize, &IsFound ); if (!EFI_ERROR (DbStatus) && IsFound) { IsVerified = TRUE; } else { Action = EFI_IMAGE_EXECUTION_AUTH_SIG_NOT_FOUND; - DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Image is signed but signature is not allowed by DB and %s hash of image is not found in DB/DBX.\n", mHashTypeStr)); + DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Image is signed but signature is not allowed by DB and hash of image is not found in DB/DBX.\n")); } } } - if (OffSet != SecDataDirEnd) { - // - // The Size in Certificate Table or the attribute certificate table is corrupted. - // - IsVerified = FALSE; - } - if (IsVerified) { return EFI_SUCCESS; } - if ((Action == EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED) || (Action == EFI_IMAGE_EXECUTION_AUTH_SIG_FOUND)) { // // Get image hash value as signature of executable. // - SignatureListSize = sizeof (EFI_SIGNATURE_LIST) + sizeof (EFI_SIGNATURE_DATA) - 1 + mImageDigestSize; + SignatureListSize = sizeof (EFI_SIGNATURE_LIST) + sizeof (EFI_SIGNATURE_DATA) - 1 + ImageDigestSize; SignatureList = (EFI_SIGNATURE_LIST *)AllocateZeroPool (SignatureListSize); if (SignatureList == NULL) { SignatureListSize = 0; @@ -2037,10 +1646,10 @@ DxeImageVerificationHandler ( SignatureList->SignatureHeaderSize = 0; SignatureList->SignatureListSize = (UINT32)SignatureListSize; - SignatureList->SignatureSize = (UINT32)(sizeof (EFI_SIGNATURE_DATA) - 1 + mImageDigestSize); - CopyMem (&SignatureList->SignatureType, &mCertType, sizeof (EFI_GUID)); + SignatureList->SignatureSize = (UINT32)(sizeof (EFI_SIGNATURE_DATA) - 1 + ImageDigestSize); + CopyMem (&SignatureList->SignatureType, CertType, sizeof (EFI_GUID)); Signature = (EFI_SIGNATURE_DATA *)((UINT8 *)SignatureList + sizeof (EFI_SIGNATURE_LIST)); - CopyMem (Signature->SignatureData, mImageDigest, mImageDigestSize); + CopyMem (Signature->SignatureData, ImageDigest, ImageDigestSize); } Failed: @@ -2078,8 +1687,8 @@ DxeImageVerificationHandler ( VOID EFIAPI OnReadyToBoot ( - IN EFI_EVENT Event, - IN VOID *Context + IN EFI_EVENT Event, + IN VOID *Context ) { EFI_IMAGE_EXECUTION_INFO_TABLE *ImageExeInfoTable; diff --git a/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.h b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.h index 53fe34358c..903ffd3f29 100644 --- a/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.h +++ b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.h @@ -22,7 +22,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #include #include #include -#include +#include #include #include #include @@ -30,7 +30,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #include #include #include -#include +#include #define EFI_CERT_TYPE_RSA2048_SHA256_SIZE 256 #define EFI_CERT_TYPE_RSA2048_SIZE 256 @@ -59,16 +59,6 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #define DENY_EXECUTE_ON_SECURITY_VIOLATION 0x00000004 #define QUERY_USER_ON_SECURITY_VIOLATION 0x00000005 -// -// Support hash types -// -#define HASHALG_SHA1 0x00000000 -#define HASHALG_SHA224 0x00000001 -#define HASHALG_SHA256 0x00000002 -#define HASHALG_SHA384 0x00000003 -#define HASHALG_SHA512 0x00000004 -#define HASHALG_MAX 0x00000005 - // // Set max digest size as SHA512 Output (64 bytes) by far // @@ -178,6 +168,10 @@ typedef struct { // UINTN OidLength; // + // GUID of the certificate type + // + CONST GUID *CertType; + // // Pointer to Hash GetContentSize function // HASH_GET_CONTEXT_SIZE GetContextSize; diff --git a/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.inf b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.inf index 1e1a639857..3b944cddf9 100644 --- a/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.inf +++ b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.inf @@ -51,7 +51,7 @@ DevicePathLib BaseCryptLib SecurityManagementLib - PeCoffLib + UefiImageLib TpmMeasurementLib [Protocols] @@ -75,6 +75,10 @@ ## SOMETIMES_PRODUCES ## GUID # Unique ID for the type of the signature. gEfiCertSha256Guid + ## SOMETIMES_CONSUMES ## GUID # Unique ID for the type of the signature. + ## SOMETIMES_PRODUCES ## GUID # Unique ID for the type of the signature. + gEfiCertSha224Guid + ## SOMETIMES_CONSUMES ## GUID # Unique ID for the type of the signature. ## SOMETIMES_PRODUCES ## GUID # Unique ID for the type of the signature. gEfiCertSha384Guid diff --git a/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c index 73719f3b96..c963739c17 100644 --- a/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c +++ b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c @@ -7,9 +7,6 @@ This external input must be validated carefully to avoid security issue like buffer overflow, integer overflow. - DxeTpm2MeasureBootLibImageRead() function will make sure the PE/COFF image content - read is within the image buffer. - Tcg2MeasurePeImage() function will accept untrusted PE/COFF image and validate its data structure within this image buffer before use. @@ -41,7 +38,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #include #include #include -#include +#include #include #include #include @@ -58,62 +55,12 @@ typedef struct { // BOOLEAN mTcg2MeasureGptTableFlag = FALSE; UINTN mTcg2MeasureGptCount = 0; -VOID *mTcg2FileBuffer; -UINTN mTcg2ImageSize; // // Measured FV handle cache // EFI_HANDLE mTcg2CacheMeasuredHandle = NULL; MEASURED_HOB_DATA *mTcg2MeasuredHobData = NULL; -/** - Reads contents of a PE/COFF image in memory buffer. - - Caution: This function may receive untrusted input. - PE/COFF image is external input, so this function will make sure the PE/COFF image content - read is within the image buffer. - - @param FileHandle Pointer to the file handle to read the PE/COFF image. - @param FileOffset Offset into the PE/COFF image to begin the read operation. - @param ReadSize On input, the size in bytes of the requested read operation. - On output, the number of bytes actually read. - @param Buffer Output buffer that contains the data read from the PE/COFF image. - - @retval EFI_SUCCESS The specified portion of the PE/COFF image was read and the size -**/ -EFI_STATUS -EFIAPI -DxeTpm2MeasureBootLibImageRead ( - IN VOID *FileHandle, - IN UINTN FileOffset, - IN OUT UINTN *ReadSize, - OUT VOID *Buffer - ) -{ - UINTN EndPosition; - - if ((FileHandle == NULL) || (ReadSize == NULL) || (Buffer == NULL)) { - return EFI_INVALID_PARAMETER; - } - - if (MAX_ADDRESS - FileOffset < *ReadSize) { - return EFI_INVALID_PARAMETER; - } - - EndPosition = FileOffset + *ReadSize; - if (EndPosition > mTcg2ImageSize) { - *ReadSize = (UINT32)(mTcg2ImageSize - FileOffset); - } - - if (FileOffset >= mTcg2ImageSize) { - *ReadSize = 0; - } - - CopyMem (Buffer, (UINT8 *)((UINTN)FileHandle + FileOffset), *ReadSize); - - return EFI_SUCCESS; -} - /** Measure GPT table data into TPM log. @@ -640,11 +587,15 @@ DxeTpm2MeasureBootHandler ( EFI_HANDLE Handle; EFI_HANDLE TempHandle; BOOLEAN ApplicationRequired; - PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; + UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext; EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol; EFI_PHYSICAL_ADDRESS FvAddress; UINT32 Index; + // FIXME: + ASSERT (FileSize == sizeof (UEFI_IMAGE_LOADER_IMAGE_CONTEXT)); + ImageContext = FileBuffer; + MeasureBootProtocols.Tcg2Protocol = NULL; MeasureBootProtocols.CcProtocol = NULL; @@ -806,42 +757,17 @@ DxeTpm2MeasureBootHandler ( goto Finish; } - mTcg2ImageSize = FileSize; - mTcg2FileBuffer = FileBuffer; - // // Measure PE Image // DevicePathNode = OrigDevicePathNode; - ZeroMem (&ImageContext, sizeof (ImageContext)); - ImageContext.Handle = (VOID *)FileBuffer; - ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE)DxeTpm2MeasureBootLibImageRead; - - // - // Get information about the image being loaded - // - Status = PeCoffLoaderGetImageInfo (&ImageContext); - if (EFI_ERROR (Status)) { - // - // Check for invalid parameters. - // - if (File == NULL) { - Status = EFI_ACCESS_DENIED; - } - - // - // The information can't be got from the invalid PeImage - // - goto Finish; - } // // Measure only application if Application flag is set // Measure drivers and applications if Application flag is not set // if ((!ApplicationRequired) || - (ApplicationRequired && (ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION))) - { + (ApplicationRequired && UefiImageGetSubsystem (ImageContext) == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION)) { // // Print the image path to be measured. // @@ -862,12 +788,13 @@ DxeTpm2MeasureBootHandler ( // // Measure PE image into TPM log. // + // FIXME: Pass context? Status = Tcg2MeasurePeImage ( &MeasureBootProtocols, (EFI_PHYSICAL_ADDRESS)(UINTN)FileBuffer, FileSize, - (UINTN)ImageContext.ImageAddress, - ImageContext.ImageType, + UefiImageLoaderGetImageAddress (ImageContext), + UefiImageGetSubsystem (ImageContext), DevicePathNode ); } diff --git a/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.inf b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.inf index 28995f438d..713c56b1ab 100644 --- a/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.inf +++ b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.inf @@ -54,7 +54,7 @@ DevicePathLib UefiBootServicesTableLib BaseCryptLib - PeCoffLib + UefiImageLib BaseLib SecurityManagementLib HobLib diff --git a/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c index ac855b8fbb..fb06a8112b 100644 --- a/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c +++ b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c @@ -6,9 +6,6 @@ This external input must be validated carefully to avoid security issue like buffer overflow, integer overflow. - DxeTpmMeasureBootLibImageRead() function will make sure the PE/COFF image content - read is within the image buffer. - TcgMeasurePeImage() function will accept untrusted PE/COFF image and validate its data structure within this image buffer before use. @@ -39,7 +36,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #include #include #include -#include +#include #include #include @@ -50,62 +47,12 @@ SPDX-License-Identifier: BSD-2-Clause-Patent // BOOLEAN mMeasureGptTableFlag = FALSE; UINTN mMeasureGptCount = 0; -VOID *mFileBuffer; -UINTN mTpmImageSize; // // Measured FV handle cache // EFI_HANDLE mCacheMeasuredHandle = NULL; MEASURED_HOB_DATA *mMeasuredHobData = NULL; -/** - Reads contents of a PE/COFF image in memory buffer. - - Caution: This function may receive untrusted input. - PE/COFF image is external input, so this function will make sure the PE/COFF image content - read is within the image buffer. - - @param FileHandle Pointer to the file handle to read the PE/COFF image. - @param FileOffset Offset into the PE/COFF image to begin the read operation. - @param ReadSize On input, the size in bytes of the requested read operation. - On output, the number of bytes actually read. - @param Buffer Output buffer that contains the data read from the PE/COFF image. - - @retval EFI_SUCCESS The specified portion of the PE/COFF image was read and the size -**/ -EFI_STATUS -EFIAPI -DxeTpmMeasureBootLibImageRead ( - IN VOID *FileHandle, - IN UINTN FileOffset, - IN OUT UINTN *ReadSize, - OUT VOID *Buffer - ) -{ - UINTN EndPosition; - - if ((FileHandle == NULL) || (ReadSize == NULL) || (Buffer == NULL)) { - return EFI_INVALID_PARAMETER; - } - - if (MAX_ADDRESS - FileOffset < *ReadSize) { - return EFI_INVALID_PARAMETER; - } - - EndPosition = FileOffset + *ReadSize; - if (EndPosition > mTpmImageSize) { - *ReadSize = (UINT32)(mTpmImageSize - FileOffset); - } - - if (FileOffset >= mTpmImageSize) { - *ReadSize = 0; - } - - CopyMem (Buffer, (UINT8 *)((UINTN)FileHandle + FileOffset), *ReadSize); - - return EFI_SUCCESS; -} - /** Measure GPT table data into TPM log. @@ -292,7 +239,7 @@ TcgMeasureGptTable ( PE/COFF image is external input, so this function will validate its data structure within this image buffer before use. - Notes: PE/COFF image has been checked by BasePeCoffLib PeCoffLoaderGetImageInfo() in + Notes: PE/COFF image has been checked by UefiImageLibLib UefiImageInitializeContext() in its caller function DxeTpmMeasureBootHandler(). @param[in] TcgProtocol Pointer to the located TCG protocol instance. @@ -311,12 +258,11 @@ TcgMeasureGptTable ( EFI_STATUS EFIAPI TcgMeasurePeImage ( - IN EFI_TCG_PROTOCOL *TcgProtocol, - IN EFI_PHYSICAL_ADDRESS ImageAddress, - IN UINTN ImageSize, - IN UINTN LinkTimeBase, - IN UINT16 ImageType, - IN EFI_DEVICE_PATH_PROTOCOL *FilePath + IN EFI_TCG_PROTOCOL *TcgProtocol, + IN EFI_PHYSICAL_ADDRESS ImageAddress, + IN UINTN ImageSize, + IN UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext, + IN EFI_DEVICE_PATH_PROTOCOL *FilePath ) { EFI_STATUS Status; @@ -325,22 +271,12 @@ TcgMeasurePeImage ( UINT32 FilePathSize; VOID *Sha1Ctx; UINTN CtxSize; - EFI_IMAGE_DOS_HEADER *DosHdr; - UINT32 PeCoffHeaderOffset; - EFI_IMAGE_SECTION_HEADER *Section; - UINT8 *HashBase; - UINTN HashSize; - UINTN SumOfBytesHashed; EFI_IMAGE_SECTION_HEADER *SectionHeader; - UINTN Index; - UINTN Pos; UINT32 EventSize; UINT32 EventNumber; EFI_PHYSICAL_ADDRESS EventLogLastEntry; - EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr; - UINT32 NumberOfRvaAndSizes; BOOLEAN HashStatus; - UINT32 CertSize; + UINT16 ImageType; Status = EFI_UNSUPPORTED; ImageLoad = NULL; @@ -364,6 +300,8 @@ TcgMeasurePeImage ( TcgEvent->EventSize = EventSize - sizeof (TCG_PCR_EVENT_HDR); ImageLoad = (EFI_IMAGE_LOAD_EVENT *)TcgEvent->Event; + ImageType = UefiImageGetSubsystem (ImageContext); + switch (ImageType) { case EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION: TcgEvent->EventType = EV_EFI_BOOT_SERVICES_APPLICATION; @@ -390,26 +328,12 @@ TcgMeasurePeImage ( ImageLoad->ImageLocationInMemory = ImageAddress; ImageLoad->ImageLengthInMemory = ImageSize; - ImageLoad->ImageLinkTimeAddress = LinkTimeBase; + ImageLoad->ImageLinkTimeAddress = UefiImageLoaderGetImageAddress (ImageContext); ImageLoad->LengthOfDevicePath = FilePathSize; if ((FilePath != NULL) && (FilePathSize != 0)) { CopyMem (ImageLoad->DevicePath, FilePath, FilePathSize); } - // - // Check PE/COFF image - // - DosHdr = (EFI_IMAGE_DOS_HEADER *)(UINTN)ImageAddress; - PeCoffHeaderOffset = 0; - if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) { - PeCoffHeaderOffset = DosHdr->e_lfanew; - } - - Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINT8 *)(UINTN)ImageAddress + PeCoffHeaderOffset); - if (Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) { - goto Finish; - } - // // PE/COFF Image Measurement // @@ -418,9 +342,7 @@ TcgMeasurePeImage ( // // - // 1. Load the image header into memory. - - // 2. Initialize a SHA hash context. + // Initialize a SHA hash context. CtxSize = Sha1GetContextSize (); Sha1Ctx = AllocatePool (CtxSize); if (Sha1Ctx == NULL) { @@ -438,220 +360,7 @@ TcgMeasurePeImage ( // But CheckSum field and SECURITY data directory (certificate) are excluded // - // - // 3. Calculate the distance from the base of the image header to the image checksum address. - // 4. Hash the image header from its base to beginning of the image checksum. - // - HashBase = (UINT8 *)(UINTN)ImageAddress; - if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { - // - // Use PE32 offset - // - NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes; - HashSize = (UINTN)(&Hdr.Pe32->OptionalHeader.CheckSum) - (UINTN)HashBase; - } else { - // - // Use PE32+ offset - // - NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes; - HashSize = (UINTN)(&Hdr.Pe32Plus->OptionalHeader.CheckSum) - (UINTN)HashBase; - } - - HashStatus = Sha1Update (Sha1Ctx, HashBase, HashSize); - if (!HashStatus) { - goto Finish; - } - - // - // 5. Skip over the image checksum (it occupies a single ULONG). - // - if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) { - // - // 6. Since there is no Cert Directory in optional header, hash everything - // from the end of the checksum to the end of image header. - // - if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { - // - // Use PE32 offset. - // - HashBase = (UINT8 *)&Hdr.Pe32->OptionalHeader.CheckSum + sizeof (UINT32); - HashSize = Hdr.Pe32->OptionalHeader.SizeOfHeaders - (UINTN)(HashBase - ImageAddress); - } else { - // - // Use PE32+ offset. - // - HashBase = (UINT8 *)&Hdr.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32); - HashSize = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN)(HashBase - ImageAddress); - } - - if (HashSize != 0) { - HashStatus = Sha1Update (Sha1Ctx, HashBase, HashSize); - if (!HashStatus) { - goto Finish; - } - } - } else { - // - // 7. Hash everything from the end of the checksum to the start of the Cert Directory. - // - if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { - // - // Use PE32 offset - // - HashBase = (UINT8 *)&Hdr.Pe32->OptionalHeader.CheckSum + sizeof (UINT32); - HashSize = (UINTN)(&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - (UINTN)HashBase; - } else { - // - // Use PE32+ offset - // - HashBase = (UINT8 *)&Hdr.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32); - HashSize = (UINTN)(&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - (UINTN)HashBase; - } - - if (HashSize != 0) { - HashStatus = Sha1Update (Sha1Ctx, HashBase, HashSize); - if (!HashStatus) { - goto Finish; - } - } - - // - // 8. Skip over the Cert Directory. (It is sizeof(IMAGE_DATA_DIRECTORY) bytes.) - // 9. Hash everything from the end of the Cert Directory to the end of image header. - // - if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { - // - // Use PE32 offset - // - HashBase = (UINT8 *)&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]; - HashSize = Hdr.Pe32->OptionalHeader.SizeOfHeaders - (UINTN)(HashBase - ImageAddress); - } else { - // - // Use PE32+ offset - // - HashBase = (UINT8 *)&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]; - HashSize = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN)(HashBase - ImageAddress); - } - - if (HashSize != 0) { - HashStatus = Sha1Update (Sha1Ctx, HashBase, HashSize); - if (!HashStatus) { - goto Finish; - } - } - } - - // - // 10. Set the SUM_OF_BYTES_HASHED to the size of the header - // - if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { - // - // Use PE32 offset - // - SumOfBytesHashed = Hdr.Pe32->OptionalHeader.SizeOfHeaders; - } else { - // - // Use PE32+ offset - // - SumOfBytesHashed = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders; - } - - // - // 11. Build a temporary table of pointers to all the IMAGE_SECTION_HEADER - // structures in the image. The 'NumberOfSections' field of the image - // header indicates how big the table should be. Do not include any - // IMAGE_SECTION_HEADERs in the table whose 'SizeOfRawData' field is zero. - // - SectionHeader = (EFI_IMAGE_SECTION_HEADER *)AllocateZeroPool (sizeof (EFI_IMAGE_SECTION_HEADER) * Hdr.Pe32->FileHeader.NumberOfSections); - if (SectionHeader == NULL) { - Status = EFI_OUT_OF_RESOURCES; - goto Finish; - } - - // - // 12. Using the 'PointerToRawData' in the referenced section headers as - // a key, arrange the elements in the table in ascending order. In other - // words, sort the section headers according to the disk-file offset of - // the section. - // - Section = (EFI_IMAGE_SECTION_HEADER *)( - (UINT8 *)(UINTN)ImageAddress + - PeCoffHeaderOffset + - sizeof (UINT32) + - sizeof (EFI_IMAGE_FILE_HEADER) + - Hdr.Pe32->FileHeader.SizeOfOptionalHeader - ); - for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) { - Pos = Index; - while ((Pos > 0) && (Section->PointerToRawData < SectionHeader[Pos - 1].PointerToRawData)) { - CopyMem (&SectionHeader[Pos], &SectionHeader[Pos - 1], sizeof (EFI_IMAGE_SECTION_HEADER)); - Pos--; - } - - CopyMem (&SectionHeader[Pos], Section, sizeof (EFI_IMAGE_SECTION_HEADER)); - Section += 1; - } - - // - // 13. Walk through the sorted table, bring the corresponding section - // into memory, and hash the entire section (using the 'SizeOfRawData' - // field in the section header to determine the amount of data to hash). - // 14. Add the section's 'SizeOfRawData' to SUM_OF_BYTES_HASHED . - // 15. Repeat steps 13 and 14 for all the sections in the sorted table. - // - for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) { - Section = (EFI_IMAGE_SECTION_HEADER *)&SectionHeader[Index]; - if (Section->SizeOfRawData == 0) { - continue; - } - - HashBase = (UINT8 *)(UINTN)ImageAddress + Section->PointerToRawData; - HashSize = (UINTN)Section->SizeOfRawData; - - HashStatus = Sha1Update (Sha1Ctx, HashBase, HashSize); - if (!HashStatus) { - goto Finish; - } - - SumOfBytesHashed += HashSize; - } - - // - // 16. If the file size is greater than SUM_OF_BYTES_HASHED, there is extra - // data in the file that needs to be added to the hash. This data begins - // at file offset SUM_OF_BYTES_HASHED and its length is: - // FileSize - (CertDirectory->Size) - // - if (ImageSize > SumOfBytesHashed) { - HashBase = (UINT8 *)(UINTN)ImageAddress + SumOfBytesHashed; - - if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) { - CertSize = 0; - } else { - if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { - // - // Use PE32 offset. - // - CertSize = Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size; - } else { - // - // Use PE32+ offset. - // - CertSize = Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size; - } - } - - if (ImageSize > CertSize + SumOfBytesHashed) { - HashSize = (UINTN)(ImageSize - CertSize - SumOfBytesHashed); - - HashStatus = Sha1Update (Sha1Ctx, HashBase, HashSize); - if (!HashStatus) { - goto Finish; - } - } else if (ImageSize < CertSize + SumOfBytesHashed) { - goto Finish; - } - } + UefiImageHashImageDefault (ImageContext, Sha1Ctx, Sha1Update); // // 17. Finalize the SHA hash. @@ -756,11 +465,15 @@ DxeTpmMeasureBootHandler ( EFI_HANDLE Handle; EFI_HANDLE TempHandle; BOOLEAN ApplicationRequired; - PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; + UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext; EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol; EFI_PHYSICAL_ADDRESS FvAddress; UINT32 Index; + // FIXME: + ASSERT (FileSize == sizeof (UEFI_IMAGE_LOADER_IMAGE_CONTEXT)); + ImageContext = FileBuffer; + Status = gBS->LocateProtocol (&gEfiTcgProtocolGuid, NULL, (VOID **)&TcgProtocol); if (EFI_ERROR (Status)) { // @@ -922,42 +635,17 @@ DxeTpmMeasureBootHandler ( goto Finish; } - mTpmImageSize = FileSize; - mFileBuffer = FileBuffer; - // // Measure PE Image // DevicePathNode = OrigDevicePathNode; - ZeroMem (&ImageContext, sizeof (ImageContext)); - ImageContext.Handle = (VOID *)FileBuffer; - ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE)DxeTpmMeasureBootLibImageRead; - - // - // Get information about the image being loaded - // - Status = PeCoffLoaderGetImageInfo (&ImageContext); - if (EFI_ERROR (Status)) { - // - // Check for invalid parameters. - // - if (File == NULL) { - return EFI_ACCESS_DENIED; - } - - // - // The information can't be got from the invalid PeImage - // - goto Finish; - } // // Measure only application if Application flag is set // Measure drivers and applications if Application flag is not set // if ((!ApplicationRequired) || - (ApplicationRequired && (ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION))) - { + (ApplicationRequired && UefiImageGetSubsystem (ImageContext) == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION)) { // // Print the image path to be measured. // @@ -982,8 +670,7 @@ DxeTpmMeasureBootHandler ( TcgProtocol, (EFI_PHYSICAL_ADDRESS)(UINTN)FileBuffer, FileSize, - (UINTN)ImageContext.ImageAddress, - ImageContext.ImageType, + ImageContext, DevicePathNode ); } diff --git a/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.inf b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.inf index 414c654d15..ffe925af25 100644 --- a/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.inf +++ b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.inf @@ -49,7 +49,7 @@ DevicePathLib UefiBootServicesTableLib BaseCryptLib - PeCoffLib + UefiImageLib BaseLib SecurityManagementLib HobLib diff --git a/SecurityPkg/Library/HashInstanceLibSha1/HashInstanceLibSha1.c b/SecurityPkg/Library/HashInstanceLibSha1/HashInstanceLibSha1.c index c786c2189c..e9bee506c4 100644 --- a/SecurityPkg/Library/HashInstanceLibSha1/HashInstanceLibSha1.c +++ b/SecurityPkg/Library/HashInstanceLibSha1/HashInstanceLibSha1.c @@ -45,10 +45,10 @@ Tpm2SetSha1ToDigestList ( @retval EFI_SUCCESS Hash sequence start and HandleHandle returned. @retval EFI_OUT_OF_RESOURCES No enough resource to start hash. **/ -EFI_STATUS +BOOLEAN EFIAPI Sha1HashInit ( - OUT HASH_HANDLE *HashHandle + OUT VOID **HashHandle ) { VOID *Sha1Ctx; @@ -60,9 +60,9 @@ Sha1HashInit ( Sha1Init (Sha1Ctx); - *HashHandle = (HASH_HANDLE)Sha1Ctx; + *HashHandle = Sha1Ctx; - return EFI_SUCCESS; + return TRUE; } /** @@ -74,20 +74,17 @@ Sha1HashInit ( @retval EFI_SUCCESS Hash sequence updated. **/ -EFI_STATUS +BOOLEAN EFIAPI Sha1HashUpdate ( - IN HASH_HANDLE HashHandle, - IN VOID *DataToHash, + IN VOID *HashHandle, + IN CONST VOID *DataToHash, IN UINTN DataToHashLen ) { - VOID *Sha1Ctx; - - Sha1Ctx = (VOID *)HashHandle; - Sha1Update (Sha1Ctx, DataToHash, DataToHashLen); + Sha1Update (HashHandle, DataToHash, DataToHashLen); - return EFI_SUCCESS; + return TRUE; } /** @@ -98,30 +95,28 @@ Sha1HashUpdate ( @retval EFI_SUCCESS Hash sequence complete and DigestList is returned. **/ -EFI_STATUS +BOOLEAN EFIAPI Sha1HashFinal ( - IN HASH_HANDLE HashHandle, + IN VOID *HashHandle, OUT TPML_DIGEST_VALUES *DigestList ) { UINT8 Digest[SHA1_DIGEST_SIZE]; - VOID *Sha1Ctx; - Sha1Ctx = (VOID *)HashHandle; - Sha1Final (Sha1Ctx, Digest); + Sha1Final (HashHandle, Digest); - FreePool (Sha1Ctx); + FreePool (HashHandle); Tpm2SetSha1ToDigestList (DigestList, Digest); - return EFI_SUCCESS; + return TRUE; } HASH_INTERFACE mSha1InternalHashInstance = { HASH_ALGORITHM_SHA1_GUID, Sha1HashInit, - Sha1HashUpdate, + Sha1Update, Sha1HashFinal, }; diff --git a/SecurityPkg/Library/HashInstanceLibSha256/HashInstanceLibSha256.c b/SecurityPkg/Library/HashInstanceLibSha256/HashInstanceLibSha256.c index 4387740001..d02d325cec 100644 --- a/SecurityPkg/Library/HashInstanceLibSha256/HashInstanceLibSha256.c +++ b/SecurityPkg/Library/HashInstanceLibSha256/HashInstanceLibSha256.c @@ -45,10 +45,10 @@ Tpm2SetSha256ToDigestList ( @retval EFI_SUCCESS Hash sequence start and HandleHandle returned. @retval EFI_OUT_OF_RESOURCES No enough resource to start hash. **/ -EFI_STATUS +BOOLEAN EFIAPI Sha256HashInit ( - OUT HASH_HANDLE *HashHandle + OUT VOID **HashHandle ) { VOID *Sha256Ctx; @@ -60,9 +60,9 @@ Sha256HashInit ( Sha256Init (Sha256Ctx); - *HashHandle = (HASH_HANDLE)Sha256Ctx; + *HashHandle = Sha256Ctx; - return EFI_SUCCESS; + return TRUE; } /** @@ -74,20 +74,17 @@ Sha256HashInit ( @retval EFI_SUCCESS Hash sequence updated. **/ -EFI_STATUS +BOOLEAN EFIAPI Sha256HashUpdate ( - IN HASH_HANDLE HashHandle, - IN VOID *DataToHash, + IN VOID *HashHandle, + IN CONST VOID *DataToHash, IN UINTN DataToHashLen ) { - VOID *Sha256Ctx; - - Sha256Ctx = (VOID *)HashHandle; - Sha256Update (Sha256Ctx, DataToHash, DataToHashLen); + Sha256Update (HashHandle, DataToHash, DataToHashLen); - return EFI_SUCCESS; + return TRUE; } /** @@ -98,24 +95,22 @@ Sha256HashUpdate ( @retval EFI_SUCCESS Hash sequence complete and DigestList is returned. **/ -EFI_STATUS +BOOLEAN EFIAPI Sha256HashFinal ( - IN HASH_HANDLE HashHandle, + IN VOID *HashHandle, OUT TPML_DIGEST_VALUES *DigestList ) { UINT8 Digest[SHA256_DIGEST_SIZE]; - VOID *Sha256Ctx; - Sha256Ctx = (VOID *)HashHandle; - Sha256Final (Sha256Ctx, Digest); + Sha256Final (HashHandle, Digest); - FreePool (Sha256Ctx); + FreePool (HashHandle); Tpm2SetSha256ToDigestList (DigestList, Digest); - return EFI_SUCCESS; + return TRUE; } HASH_INTERFACE mSha256InternalHashInstance = { diff --git a/SecurityPkg/Library/HashInstanceLibSha512/HashInstanceLibSha512.c b/SecurityPkg/Library/HashInstanceLibSha512/HashInstanceLibSha512.c index e25ecb9ed6..7b47d7d9f7 100644 --- a/SecurityPkg/Library/HashInstanceLibSha512/HashInstanceLibSha512.c +++ b/SecurityPkg/Library/HashInstanceLibSha512/HashInstanceLibSha512.c @@ -44,10 +44,10 @@ Tpm2SetSha512ToDigestList ( @retval EFI_SUCCESS Hash sequence start and HandleHandle returned. @retval EFI_OUT_OF_RESOURCES No enough resource to start hash. **/ -EFI_STATUS +BOOLEAN EFIAPI Sha512HashInit ( - OUT HASH_HANDLE *HashHandle + OUT VOID **HashHandle ) { VOID *Sha512Ctx; @@ -59,9 +59,9 @@ Sha512HashInit ( Sha512Init (Sha512Ctx); - *HashHandle = (HASH_HANDLE)Sha512Ctx; + *HashHandle = Sha512Ctx; - return EFI_SUCCESS; + return TRUE; } /** @@ -73,20 +73,17 @@ Sha512HashInit ( @retval EFI_SUCCESS Hash sequence updated. **/ -EFI_STATUS +BOOLEAN EFIAPI Sha512HashUpdate ( - IN HASH_HANDLE HashHandle, - IN VOID *DataToHash, + IN VOID *HashHandle, + IN CONST VOID *DataToHash, IN UINTN DataToHashLen ) { - VOID *Sha512Ctx; + Sha512Update (HashHandle, DataToHash, DataToHashLen); - Sha512Ctx = (VOID *)HashHandle; - Sha512Update (Sha512Ctx, DataToHash, DataToHashLen); - - return EFI_SUCCESS; + return TRUE; } /** @@ -97,10 +94,10 @@ Sha512HashUpdate ( @retval EFI_SUCCESS Hash sequence complete and DigestList is returned. **/ -EFI_STATUS +BOOLEAN EFIAPI Sha512HashFinal ( - IN HASH_HANDLE HashHandle, + IN VOID *HashHandle, OUT TPML_DIGEST_VALUES *DigestList ) { @@ -114,7 +111,7 @@ Sha512HashFinal ( Tpm2SetSha512ToDigestList (DigestList, Digest); - return EFI_SUCCESS; + return TRUE; } HASH_INTERFACE mSha512InternalHashInstance = { diff --git a/SecurityPkg/Library/HashInstanceLibSm3/HashInstanceLibSm3.c b/SecurityPkg/Library/HashInstanceLibSm3/HashInstanceLibSm3.c index 635ca1ebfb..bdb8575826 100644 --- a/SecurityPkg/Library/HashInstanceLibSm3/HashInstanceLibSm3.c +++ b/SecurityPkg/Library/HashInstanceLibSm3/HashInstanceLibSm3.c @@ -44,10 +44,10 @@ Tpm2SetSm3ToDigestList ( @retval EFI_SUCCESS Hash sequence start and HandleHandle returned. @retval EFI_OUT_OF_RESOURCES No enough resource to start hash. **/ -EFI_STATUS +BOOLEAN EFIAPI Sm3HashInit ( - OUT HASH_HANDLE *HashHandle + OUT VOID **HashHandle ) { VOID *Sm3Ctx; @@ -56,14 +56,14 @@ Sm3HashInit ( CtxSize = Sm3GetContextSize (); Sm3Ctx = AllocatePool (CtxSize); if (Sm3Ctx == NULL) { - return EFI_OUT_OF_RESOURCES; + return FALSE; } Sm3Init (Sm3Ctx); - *HashHandle = (HASH_HANDLE)Sm3Ctx; + *HashHandle = Sm3Ctx; - return EFI_SUCCESS; + return TRUE; } /** @@ -75,20 +75,17 @@ Sm3HashInit ( @retval EFI_SUCCESS Hash sequence updated. **/ -EFI_STATUS +BOOLEAN EFIAPI Sm3HashUpdate ( - IN HASH_HANDLE HashHandle, - IN VOID *DataToHash, + IN VOID *HashHandle, + IN CONST VOID *DataToHash, IN UINTN DataToHashLen ) { - VOID *Sm3Ctx; - - Sm3Ctx = (VOID *)HashHandle; - Sm3Update (Sm3Ctx, DataToHash, DataToHashLen); + Sm3Update (HashHandle, DataToHash, DataToHashLen); - return EFI_SUCCESS; + return TRUE; } /** @@ -99,24 +96,22 @@ Sm3HashUpdate ( @retval EFI_SUCCESS Hash sequence complete and DigestList is returned. **/ -EFI_STATUS +BOOLEAN EFIAPI Sm3HashFinal ( - IN HASH_HANDLE HashHandle, + IN VOID *HashHandle, OUT TPML_DIGEST_VALUES *DigestList ) { UINT8 Digest[SM3_256_DIGEST_SIZE]; - VOID *Sm3Ctx; - Sm3Ctx = (VOID *)HashHandle; - Sm3Final (Sm3Ctx, Digest); + Sm3Final (HashHandle, Digest); - FreePool (Sm3Ctx); + FreePool (HashHandle); Tpm2SetSm3ToDigestList (DigestList, Digest); - return EFI_SUCCESS; + return TRUE; } HASH_INTERFACE mSm3InternalHashInstance = { diff --git a/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterDxe.c b/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterDxe.c index 2169c5e185..5d1312c32c 100644 --- a/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterDxe.c +++ b/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterDxe.c @@ -59,18 +59,18 @@ CheckSupportedHashMaskMismatch ( @retval EFI_SUCCESS Hash sequence start and HandleHandle returned. @retval EFI_OUT_OF_RESOURCES No enough resource to start hash. **/ -EFI_STATUS +BOOLEAN EFIAPI HashStart ( - OUT HASH_HANDLE *HashHandle + OUT VOID **HashHandle ) { - HASH_HANDLE *HashCtx; + VOID **HashCtx; UINTN Index; UINT32 HashMask; if (mHashInterfaceCount == 0) { - return EFI_UNSUPPORTED; + return FALSE; } CheckSupportedHashMaskMismatch (); @@ -85,9 +85,9 @@ HashStart ( } } - *HashHandle = (HASH_HANDLE)HashCtx; + *HashHandle = HashCtx; - return EFI_SUCCESS; + return TRUE; } /** @@ -99,25 +99,25 @@ HashStart ( @retval EFI_SUCCESS Hash sequence updated. **/ -EFI_STATUS +BOOLEAN EFIAPI HashUpdate ( - IN HASH_HANDLE HashHandle, - IN VOID *DataToHash, - IN UINTN DataToHashLen + IN VOID *HashHandle, + IN CONST VOID *DataToHash, + IN UINTN DataToHashLen ) { - HASH_HANDLE *HashCtx; + VOID **HashCtx; UINTN Index; UINT32 HashMask; if (mHashInterfaceCount == 0) { - return EFI_UNSUPPORTED; + return FALSE; } CheckSupportedHashMaskMismatch (); - HashCtx = (HASH_HANDLE *)HashHandle; + HashCtx = (VOID **)HashHandle; for (Index = 0; Index < mHashInterfaceCount; Index++) { HashMask = Tpm2GetHashMaskFromAlgo (&mHashInterface[Index].HashGuid); @@ -126,7 +126,7 @@ HashUpdate ( } } - return EFI_SUCCESS; + return TRUE; } /** @@ -186,7 +186,7 @@ Tpm2ExtendNvIndex ( EFI_STATUS EFIAPI HashCompleteAndExtend ( - IN HASH_HANDLE HashHandle, + IN VOID *HashHandle, IN TPMI_DH_PCR PcrIndex, IN VOID *DataToHash, IN UINTN DataToHashLen, @@ -194,7 +194,7 @@ HashCompleteAndExtend ( ) { TPML_DIGEST_VALUES Digest; - HASH_HANDLE *HashCtx; + VOID **HashCtx; UINTN Index; EFI_STATUS Status; UINT32 HashMask; @@ -210,7 +210,7 @@ HashCompleteAndExtend ( CheckSupportedHashMaskMismatch (); - HashCtx = (HASH_HANDLE *)HashHandle; + HashCtx = (VOID **)HashHandle; ZeroMem (DigestList, sizeof (*DigestList)); for (Index = 0; Index < mHashInterfaceCount; Index++) { @@ -269,8 +269,8 @@ HashAndExtend ( OUT TPML_DIGEST_VALUES *DigestList ) { - HASH_HANDLE HashHandle; - EFI_STATUS Status; + VOID *HashHandle; + EFI_STATUS Status; if (mHashInterfaceCount == 0) { return EFI_UNSUPPORTED; diff --git a/SecurityPkg/Library/HashLibTpm2/HashLibTpm2.c b/SecurityPkg/Library/HashLibTpm2/HashLibTpm2.c index 00ba80b884..91101ccd1f 100644 --- a/SecurityPkg/Library/HashLibTpm2/HashLibTpm2.c +++ b/SecurityPkg/Library/HashLibTpm2/HashLibTpm2.c @@ -59,10 +59,10 @@ Tpm2GetAlgoFromHashMask ( @retval EFI_SUCCESS Hash sequence start and HandleHandle returned. @retval EFI_OUT_OF_RESOURCES No enough resource to start hash. **/ -EFI_STATUS +BOOLEAN EFIAPI HashStart ( - OUT HASH_HANDLE *HashHandle + OUT VOID **HashHandle ) { TPMI_DH_OBJECT SequenceHandle; @@ -73,10 +73,11 @@ HashStart ( Status = Tpm2HashSequenceStart (AlgoId, &SequenceHandle); if (!EFI_ERROR (Status)) { - *HashHandle = (HASH_HANDLE)SequenceHandle; + *HashHandle = (VOID *)(UINTN)SequenceHandle; + return TRUE; } - return Status; + return FALSE; } /** @@ -88,11 +89,11 @@ HashStart ( @retval EFI_SUCCESS Hash sequence updated. **/ -EFI_STATUS +BOOLEAN EFIAPI HashUpdate ( - IN HASH_HANDLE HashHandle, - IN VOID *DataToHash, + IN VOID *HashHandle, + IN CONST VOID *DataToHash, IN UINTN DataToHashLen ) { @@ -107,9 +108,9 @@ HashUpdate ( CopyMem (HashBuffer.buffer, Buffer, sizeof (HashBuffer.buffer)); Buffer += sizeof (HashBuffer.buffer); - Status = Tpm2SequenceUpdate ((TPMI_DH_OBJECT)HashHandle, &HashBuffer); + Status = Tpm2SequenceUpdate ((TPMI_DH_OBJECT)(UINTN)HashHandle, &HashBuffer); if (EFI_ERROR (Status)) { - return EFI_DEVICE_ERROR; + return FALSE; } } @@ -118,12 +119,12 @@ HashUpdate ( // HashBuffer.size = (UINT16)HashLen; CopyMem (HashBuffer.buffer, Buffer, (UINTN)HashLen); - Status = Tpm2SequenceUpdate ((TPMI_DH_OBJECT)HashHandle, &HashBuffer); + Status = Tpm2SequenceUpdate ((TPMI_DH_OBJECT)(UINTN)HashHandle, &HashBuffer); if (EFI_ERROR (Status)) { - return EFI_DEVICE_ERROR; + return FALSE; } - return EFI_SUCCESS; + return TRUE; } /** @@ -140,7 +141,7 @@ HashUpdate ( EFI_STATUS EFIAPI HashCompleteAndExtend ( - IN HASH_HANDLE HashHandle, + IN VOID *HashHandle, IN TPMI_DH_PCR PcrIndex, IN VOID *DataToHash, IN UINTN DataToHashLen, @@ -162,7 +163,7 @@ HashCompleteAndExtend ( CopyMem (HashBuffer.buffer, Buffer, sizeof (HashBuffer.buffer)); Buffer += sizeof (HashBuffer.buffer); - Status = Tpm2SequenceUpdate ((TPMI_DH_OBJECT)HashHandle, &HashBuffer); + Status = Tpm2SequenceUpdate ((TPMI_DH_OBJECT)(UINTN)HashHandle, &HashBuffer); if (EFI_ERROR (Status)) { return EFI_DEVICE_ERROR; } @@ -180,13 +181,13 @@ HashCompleteAndExtend ( if (AlgoId == TPM_ALG_NULL) { Status = Tpm2EventSequenceComplete ( PcrIndex, - (TPMI_DH_OBJECT)HashHandle, + (TPMI_DH_OBJECT)(UINTN)HashHandle, &HashBuffer, DigestList ); } else { Status = Tpm2SequenceComplete ( - (TPMI_DH_OBJECT)HashHandle, + (TPMI_DH_OBJECT)(UINTN)HashHandle, &HashBuffer, &Result ); diff --git a/SecurityPkg/SecurityPkg.dsc b/SecurityPkg/SecurityPkg.dsc index 70981da361..d7b7715668 100644 --- a/SecurityPkg/SecurityPkg.dsc +++ b/SecurityPkg/SecurityPkg.dsc @@ -32,8 +32,12 @@ PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf UefiApplicationEntryPoint|MdePkg/Library/UefiApplicationEntryPoint/UefiApplicationEntryPoint.inf PerformanceLib|MdePkg/Library/BasePerformanceLibNull/BasePerformanceLibNull.inf - PeCoffLib|MdePkg/Library/BasePeCoffLib/BasePeCoffLib.inf - PeCoffExtraActionLib|MdePkg/Library/BasePeCoffExtraActionLibNull/BasePeCoffExtraActionLibNull.inf + PeCoffLib2|MdePkg/Library/BasePeCoffLib2/BasePeCoffLib2.inf + UefiImageLib|MdePkg/Library/BaseUefiImageLib/BaseUefiImageLibPeCoff.inf + UefiImageExtraActionLib|MdePkg/Library/BaseUefiImageExtraActionLibNull/BaseUefiImageExtraActionLibNull.inf + # FIXME: ARM? + CacheMaintenanceLib|MdePkg/Library/BaseCacheMaintenanceLib/BaseCacheMaintenanceLib.inf + DxeServicesLib|MdePkg/Library/DxeServicesLib/DxeServicesLib.inf UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf diff --git a/SecurityPkg/Tcg/Tcg2Dxe/MeasureBootPeCoff.c b/SecurityPkg/Tcg/Tcg2Dxe/MeasureBootPeCoff.c deleted file mode 100644 index b6c6faf2d2..0000000000 --- a/SecurityPkg/Tcg/Tcg2Dxe/MeasureBootPeCoff.c +++ /dev/null @@ -1,408 +0,0 @@ -/** @file - This module implements measuring PeCoff image for Tcg2 Protocol. - - Caution: This file requires additional review when modified. - This driver will have external input - PE/COFF image. - This external input must be validated carefully to avoid security issue like - buffer overflow, integer overflow. - -Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.
-SPDX-License-Identifier: BSD-2-Clause-Patent - -**/ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -UINTN mTcg2DxeImageSize = 0; - -/** - Reads contents of a PE/COFF image in memory buffer. - - Caution: This function may receive untrusted input. - PE/COFF image is external input, so this function will make sure the PE/COFF image content - read is within the image buffer. - - @param FileHandle Pointer to the file handle to read the PE/COFF image. - @param FileOffset Offset into the PE/COFF image to begin the read operation. - @param ReadSize On input, the size in bytes of the requested read operation. - On output, the number of bytes actually read. - @param Buffer Output buffer that contains the data read from the PE/COFF image. - - @retval EFI_SUCCESS The specified portion of the PE/COFF image was read and the size -**/ -EFI_STATUS -EFIAPI -Tcg2DxeImageRead ( - IN VOID *FileHandle, - IN UINTN FileOffset, - IN OUT UINTN *ReadSize, - OUT VOID *Buffer - ) -{ - UINTN EndPosition; - - if ((FileHandle == NULL) || (ReadSize == NULL) || (Buffer == NULL)) { - return EFI_INVALID_PARAMETER; - } - - if (MAX_ADDRESS - FileOffset < *ReadSize) { - return EFI_INVALID_PARAMETER; - } - - EndPosition = FileOffset + *ReadSize; - if (EndPosition > mTcg2DxeImageSize) { - *ReadSize = (UINT32)(mTcg2DxeImageSize - FileOffset); - } - - if (FileOffset >= mTcg2DxeImageSize) { - *ReadSize = 0; - } - - CopyMem (Buffer, (UINT8 *)((UINTN)FileHandle + FileOffset), *ReadSize); - - return EFI_SUCCESS; -} - -/** - Measure PE image into TPM log based on the authenticode image hashing in - PE/COFF Specification 8.0 Appendix A. - - Caution: This function may receive untrusted input. - PE/COFF image is external input, so this function will validate its data structure - within this image buffer before use. - - Notes: PE/COFF image is checked by BasePeCoffLib PeCoffLoaderGetImageInfo(). - - @param[in] PCRIndex TPM PCR index - @param[in] ImageAddress Start address of image buffer. - @param[in] ImageSize Image size - @param[out] DigestList Digest list of this image. - - @retval EFI_SUCCESS Successfully measure image. - @retval EFI_OUT_OF_RESOURCES No enough resource to measure image. - @retval other error value -**/ -EFI_STATUS -MeasurePeImageAndExtend ( - IN UINT32 PCRIndex, - IN EFI_PHYSICAL_ADDRESS ImageAddress, - IN UINTN ImageSize, - OUT TPML_DIGEST_VALUES *DigestList - ) -{ - EFI_STATUS Status; - EFI_IMAGE_DOS_HEADER *DosHdr; - UINT32 PeCoffHeaderOffset; - EFI_IMAGE_SECTION_HEADER *Section; - UINT8 *HashBase; - UINTN HashSize; - UINTN SumOfBytesHashed; - EFI_IMAGE_SECTION_HEADER *SectionHeader; - UINTN Index; - UINTN Pos; - EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr; - UINT32 NumberOfRvaAndSizes; - UINT32 CertSize; - HASH_HANDLE HashHandle; - PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; - - HashHandle = 0xFFFFFFFF; // Know bad value - - Status = EFI_UNSUPPORTED; - SectionHeader = NULL; - - // - // Check PE/COFF image - // - ZeroMem (&ImageContext, sizeof (ImageContext)); - ImageContext.Handle = (VOID *)(UINTN)ImageAddress; - mTcg2DxeImageSize = ImageSize; - ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE)Tcg2DxeImageRead; - - // - // Get information about the image being loaded - // - Status = PeCoffLoaderGetImageInfo (&ImageContext); - if (EFI_ERROR (Status)) { - // - // The information can't be got from the invalid PeImage - // - DEBUG ((DEBUG_INFO, "Tcg2Dxe: PeImage invalid. Cannot retrieve image information.\n")); - goto Finish; - } - - DosHdr = (EFI_IMAGE_DOS_HEADER *)(UINTN)ImageAddress; - PeCoffHeaderOffset = 0; - if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) { - PeCoffHeaderOffset = DosHdr->e_lfanew; - } - - Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINT8 *)(UINTN)ImageAddress + PeCoffHeaderOffset); - if (Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) { - Status = EFI_UNSUPPORTED; - goto Finish; - } - - // - // PE/COFF Image Measurement - // - // NOTE: The following codes/steps are based upon the authenticode image hashing in - // PE/COFF Specification 8.0 Appendix A. - // - // - - // 1. Load the image header into memory. - - // 2. Initialize a SHA hash context. - - Status = HashStart (&HashHandle); - if (EFI_ERROR (Status)) { - goto Finish; - } - - // - // Measuring PE/COFF Image Header; - // But CheckSum field and SECURITY data directory (certificate) are excluded - // - - // - // 3. Calculate the distance from the base of the image header to the image checksum address. - // 4. Hash the image header from its base to beginning of the image checksum. - // - HashBase = (UINT8 *)(UINTN)ImageAddress; - if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { - // - // Use PE32 offset - // - NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes; - HashSize = (UINTN)(&Hdr.Pe32->OptionalHeader.CheckSum) - (UINTN)HashBase; - } else { - // - // Use PE32+ offset - // - NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes; - HashSize = (UINTN)(&Hdr.Pe32Plus->OptionalHeader.CheckSum) - (UINTN)HashBase; - } - - Status = HashUpdate (HashHandle, HashBase, HashSize); - if (EFI_ERROR (Status)) { - goto Finish; - } - - // - // 5. Skip over the image checksum (it occupies a single ULONG). - // - if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) { - // - // 6. Since there is no Cert Directory in optional header, hash everything - // from the end of the checksum to the end of image header. - // - if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { - // - // Use PE32 offset. - // - HashBase = (UINT8 *)&Hdr.Pe32->OptionalHeader.CheckSum + sizeof (UINT32); - HashSize = Hdr.Pe32->OptionalHeader.SizeOfHeaders - (UINTN)(HashBase - ImageAddress); - } else { - // - // Use PE32+ offset. - // - HashBase = (UINT8 *)&Hdr.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32); - HashSize = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN)(HashBase - ImageAddress); - } - - if (HashSize != 0) { - Status = HashUpdate (HashHandle, HashBase, HashSize); - if (EFI_ERROR (Status)) { - goto Finish; - } - } - } else { - // - // 7. Hash everything from the end of the checksum to the start of the Cert Directory. - // - if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { - // - // Use PE32 offset - // - HashBase = (UINT8 *)&Hdr.Pe32->OptionalHeader.CheckSum + sizeof (UINT32); - HashSize = (UINTN)(&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - (UINTN)HashBase; - } else { - // - // Use PE32+ offset - // - HashBase = (UINT8 *)&Hdr.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32); - HashSize = (UINTN)(&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - (UINTN)HashBase; - } - - if (HashSize != 0) { - Status = HashUpdate (HashHandle, HashBase, HashSize); - if (EFI_ERROR (Status)) { - goto Finish; - } - } - - // - // 8. Skip over the Cert Directory. (It is sizeof(IMAGE_DATA_DIRECTORY) bytes.) - // 9. Hash everything from the end of the Cert Directory to the end of image header. - // - if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { - // - // Use PE32 offset - // - HashBase = (UINT8 *)&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]; - HashSize = Hdr.Pe32->OptionalHeader.SizeOfHeaders - (UINTN)(HashBase - ImageAddress); - } else { - // - // Use PE32+ offset - // - HashBase = (UINT8 *)&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]; - HashSize = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN)(HashBase - ImageAddress); - } - - if (HashSize != 0) { - Status = HashUpdate (HashHandle, HashBase, HashSize); - if (EFI_ERROR (Status)) { - goto Finish; - } - } - } - - // - // 10. Set the SUM_OF_BYTES_HASHED to the size of the header - // - if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { - // - // Use PE32 offset - // - SumOfBytesHashed = Hdr.Pe32->OptionalHeader.SizeOfHeaders; - } else { - // - // Use PE32+ offset - // - SumOfBytesHashed = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders; - } - - // - // 11. Build a temporary table of pointers to all the IMAGE_SECTION_HEADER - // structures in the image. The 'NumberOfSections' field of the image - // header indicates how big the table should be. Do not include any - // IMAGE_SECTION_HEADERs in the table whose 'SizeOfRawData' field is zero. - // - SectionHeader = (EFI_IMAGE_SECTION_HEADER *)AllocateZeroPool (sizeof (EFI_IMAGE_SECTION_HEADER) * Hdr.Pe32->FileHeader.NumberOfSections); - if (SectionHeader == NULL) { - Status = EFI_OUT_OF_RESOURCES; - goto Finish; - } - - // - // 12. Using the 'PointerToRawData' in the referenced section headers as - // a key, arrange the elements in the table in ascending order. In other - // words, sort the section headers according to the disk-file offset of - // the section. - // - Section = (EFI_IMAGE_SECTION_HEADER *)( - (UINT8 *)(UINTN)ImageAddress + - PeCoffHeaderOffset + - sizeof (UINT32) + - sizeof (EFI_IMAGE_FILE_HEADER) + - Hdr.Pe32->FileHeader.SizeOfOptionalHeader - ); - for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) { - Pos = Index; - while ((Pos > 0) && (Section->PointerToRawData < SectionHeader[Pos - 1].PointerToRawData)) { - CopyMem (&SectionHeader[Pos], &SectionHeader[Pos - 1], sizeof (EFI_IMAGE_SECTION_HEADER)); - Pos--; - } - - CopyMem (&SectionHeader[Pos], Section, sizeof (EFI_IMAGE_SECTION_HEADER)); - Section += 1; - } - - // - // 13. Walk through the sorted table, bring the corresponding section - // into memory, and hash the entire section (using the 'SizeOfRawData' - // field in the section header to determine the amount of data to hash). - // 14. Add the section's 'SizeOfRawData' to SUM_OF_BYTES_HASHED . - // 15. Repeat steps 13 and 14 for all the sections in the sorted table. - // - for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) { - Section = (EFI_IMAGE_SECTION_HEADER *)&SectionHeader[Index]; - if (Section->SizeOfRawData == 0) { - continue; - } - - HashBase = (UINT8 *)(UINTN)ImageAddress + Section->PointerToRawData; - HashSize = (UINTN)Section->SizeOfRawData; - - Status = HashUpdate (HashHandle, HashBase, HashSize); - if (EFI_ERROR (Status)) { - goto Finish; - } - - SumOfBytesHashed += HashSize; - } - - // - // 16. If the file size is greater than SUM_OF_BYTES_HASHED, there is extra - // data in the file that needs to be added to the hash. This data begins - // at file offset SUM_OF_BYTES_HASHED and its length is: - // FileSize - (CertDirectory->Size) - // - if (ImageSize > SumOfBytesHashed) { - HashBase = (UINT8 *)(UINTN)ImageAddress + SumOfBytesHashed; - - if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) { - CertSize = 0; - } else { - if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { - // - // Use PE32 offset. - // - CertSize = Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size; - } else { - // - // Use PE32+ offset. - // - CertSize = Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size; - } - } - - if (ImageSize > CertSize + SumOfBytesHashed) { - HashSize = (UINTN)(ImageSize - CertSize - SumOfBytesHashed); - - Status = HashUpdate (HashHandle, HashBase, HashSize); - if (EFI_ERROR (Status)) { - goto Finish; - } - } else if (ImageSize < CertSize + SumOfBytesHashed) { - Status = EFI_UNSUPPORTED; - goto Finish; - } - } - - // - // 17. Finalize the SHA hash. - // - Status = HashCompleteAndExtend (HashHandle, PCRIndex, NULL, 0, DigestList); - if (EFI_ERROR (Status)) { - goto Finish; - } - -Finish: - if (SectionHeader != NULL) { - FreePool (SectionHeader); - } - - return Status; -} diff --git a/SecurityPkg/Tcg/Tcg2Dxe/MeasureBootUefiImage.c b/SecurityPkg/Tcg/Tcg2Dxe/MeasureBootUefiImage.c new file mode 100644 index 0000000000..7d77df60a9 --- /dev/null +++ b/SecurityPkg/Tcg/Tcg2Dxe/MeasureBootUefiImage.c @@ -0,0 +1,96 @@ +/** @file + This module implements measuring UEFI Image for Tcg2 Protocol. + + Caution: This file requires additional review when modified. + This driver will have external input - PE/COFF image. + This external input must be validated carefully to avoid security issue like + buffer overflow, integer overflow. + +Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + Measure UEFI image into TPM log based on its default image hashing. + + Caution: This function may receive untrusted input. + UEFI image is external input, so this function will validate its data structure + within this image buffer before use. + + Notes: UEFI image is checked by UefiImageLibLib UefiImageInitializeContext(). + + @param[in] PCRIndex TPM PCR index + @param[in] ImageAddress Start address of image buffer. + @param[in] ImageSize Image size + @param[out] DigestList Digest list of this image. + + @retval EFI_SUCCESS Successfully measure image. + @retval EFI_OUT_OF_RESOURCES No enough resource to measure image. + @retval other error value +**/ +EFI_STATUS +MeasureUefiImageAndExtend ( + IN UINT32 PCRIndex, + IN EFI_PHYSICAL_ADDRESS ImageAddress, + IN UINTN ImageSize, + OUT TPML_DIGEST_VALUES *DigestList + ) +{ + EFI_STATUS Status; + VOID *HashHandle; + UEFI_IMAGE_LOADER_IMAGE_CONTEXT ImageContext; + + Status = EFI_UNSUPPORTED; + + // FIXME: Can this somehow be abstracted away? + // + // Get information about the image being loaded + // + Status = UefiImageInitializeContextPreHash ( + &ImageContext, + (VOID *) (UINTN) ImageAddress, + (UINT32) ImageSize + ); + if (EFI_ERROR (Status)) { + // + // The information can't be got from the invalid PeImage + // + DEBUG ((DEBUG_INFO, "Tcg2Dxe: PeImage invalid. Cannot retrieve image information.\n")); + return Status; + } + + // + // UEFI Image Measurement + // + + // Initialize a SHA hash context. + + Status = HashStart (&HashHandle); + if (EFI_ERROR (Status)) { + return Status; + } + + // FIXME: This is just an ugly wrapper, the types should match (UINTN <-> VOID *), fix the libs + UefiImageHashImageDefault (&ImageContext, HashHandle, HashUpdate); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // 17. Finalize the SHA hash. + // + return HashCompleteAndExtend (HashHandle, PCRIndex, NULL, 0, DigestList); +} diff --git a/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c b/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c index b55b6c12d2..b8537d8b69 100644 --- a/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c +++ b/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c @@ -9,7 +9,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #include #include -#include +#include #include #include @@ -124,7 +124,7 @@ EFI_HANDLE mImageHandle; PE/COFF image is external input, so this function will validate its data structure within this image buffer before use. - Notes: PE/COFF image is checked by BasePeCoffLib PeCoffLoaderGetImageInfo(). + Notes: PE/COFF image is checked by UefiImageLibLib UefiImageInitializeContext(). @param[in] PCRIndex TPM PCR index @param[in] ImageAddress Start address of image buffer. @@ -136,7 +136,7 @@ EFI_HANDLE mImageHandle; @retval other error value **/ EFI_STATUS -MeasurePeImageAndExtend ( +MeasureUefiImageAndExtend ( IN UINT32 PCRIndex, IN EFI_PHYSICAL_ADDRESS ImageAddress, IN UINTN ImageSize, @@ -1346,7 +1346,7 @@ Tcg2HashLogExtendEvent ( NewEventHdr.EventType = Event->Header.EventType; NewEventHdr.EventSize = Event->Size - sizeof (UINT32) - Event->Header.HeaderSize; if ((Flags & PE_COFF_IMAGE) != 0) { - Status = MeasurePeImageAndExtend ( + Status = MeasureUefiImageAndExtend ( NewEventHdr.PCRIndex, DataToHash, (UINTN)DataToHashLen, @@ -1359,7 +1359,7 @@ Tcg2HashLogExtendEvent ( } if (Status == EFI_DEVICE_ERROR) { - DEBUG ((DEBUG_ERROR, "MeasurePeImageAndExtend - %r. Disable TPM.\n", Status)); + DEBUG ((DEBUG_ERROR, "MeasureUefiImageAndExtend - %r. Disable TPM.\n", Status)); mTcgDxeData.BsCap.TPMPresentFlag = FALSE; REPORT_STATUS_CODE ( EFI_ERROR_CODE | EFI_ERROR_MINOR, diff --git a/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.inf b/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.inf index a645474bf3..3e86b6c999 100644 --- a/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.inf +++ b/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.inf @@ -38,7 +38,7 @@ [Sources] Tcg2Dxe.c - MeasureBootPeCoff.c + MeasureBootUefiImage.c [Packages] MdePkg/MdePkg.dec @@ -63,7 +63,7 @@ PerformanceLib ReportStatusCodeLib Tcg2PhysicalPresenceLib - PeCoffLib + UefiImageLib [Guids] ## SOMETIMES_CONSUMES ## Variable:L"SecureBoot" diff --git a/SecurityPkg/Tcg/TcgDxe/TcgDxe.c b/SecurityPkg/Tcg/TcgDxe/TcgDxe.c index ee6c627303..95458a2c4c 100644 --- a/SecurityPkg/Tcg/TcgDxe/TcgDxe.c +++ b/SecurityPkg/Tcg/TcgDxe/TcgDxe.c @@ -17,7 +17,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #include #include #include -#include +#include #include #include diff --git a/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxe.inf b/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxe.inf index 0602acf702..ba5775198f 100644 --- a/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxe.inf +++ b/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxe.inf @@ -53,7 +53,7 @@ PlatformSecureLib DevicePathLib FileExplorerLib - PeCoffLib + UefiImageLib SecureBootVariableLib SecureBootVariableProvisionLib diff --git a/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigImpl.c b/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigImpl.c index 6d4560c39b..d135e30386 100644 --- a/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigImpl.c +++ b/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigImpl.c @@ -11,6 +11,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #include #include #include +#include "Library/UefiImageLib.h" #include #include #include @@ -62,26 +63,25 @@ UINT8 mHashOidValue[] = { 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, // OBJ_sha512 }; +// +// Support hash types +// +#define HASHALG_SHA256 0x00000001 +#define HASHALG_SHA384 0x00000002 +#define HASHALG_SHA512 0x00000003 +#define HASHALG_RAW 0x00000004 +#define HASHALG_MAX 0x00000004 + HASH_TABLE mHash[] = { - { L"SHA224", 28, &mHashOidValue[13], 9, NULL, NULL, NULL, NULL }, - { L"SHA256", 32, &mHashOidValue[22], 9, Sha256GetContextSize, Sha256Init, Sha256Update, Sha256Final }, - { L"SHA384", 48, &mHashOidValue[31], 9, Sha384GetContextSize, Sha384Init, Sha384Update, Sha384Final }, - { L"SHA512", 64, &mHashOidValue[40], 9, Sha512GetContextSize, Sha512Init, Sha512Update, Sha512Final } + { L"SHA256", 32, &mHashOidValue[14], 9, &gEfiCertSha256Guid, Sha256GetContextSize, Sha256Init, Sha256Update, Sha256Final }, + { L"SHA384", 48, &mHashOidValue[23], 9, &gEfiCertSha384Guid, Sha384GetContextSize, Sha384Init, Sha384Update, Sha384Final }, + { L"SHA512", 64, &mHashOidValue[32], 9, &gEfiCertSha512Guid, Sha512GetContextSize, Sha512Init, Sha512Update, Sha512Final } }; // // Variable Definitions // -UINT32 mPeCoffHeaderOffset = 0; -WIN_CERTIFICATE *mCertificate = NULL; -IMAGE_TYPE mImageType; -UINT8 *mImageBase = NULL; -UINTN mImageSize = 0; -UINT8 mImageDigest[MAX_DIGEST_SIZE]; -UINTN mImageDigestSize; -EFI_GUID mCertType; -EFI_IMAGE_SECURITY_DATA_DIRECTORY *mSecDataDir = NULL; -EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION mNtHeader; +EFI_IMAGE_SECURITY_DATA_DIRECTORY *mSecDataDir = NULL; // // Possible DER-encoded certificate file suffixes, end with NULL pointer. @@ -225,6 +225,8 @@ IsAuthentication2Format ( EFI_STATUS Status; EFI_VARIABLE_AUTHENTICATION_2 *Auth2; BOOLEAN IsAuth2Format; + UINT8 *ImageBase; + UINTN ImageSize; IsAuth2Format = FALSE; @@ -233,15 +235,15 @@ IsAuthentication2Format ( // Status = ReadFileContent ( FileHandle, - (VOID **)&mImageBase, - &mImageSize, + (VOID **)&ImageBase, + &ImageSize, 0 ); if (EFI_ERROR (Status)) { goto ON_EXIT; } - Auth2 = (EFI_VARIABLE_AUTHENTICATION_2 *)mImageBase; + Auth2 = (EFI_VARIABLE_AUTHENTICATION_2 *)ImageBase; if (Auth2->AuthInfo.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID) { goto ON_EXIT; } @@ -254,9 +256,8 @@ IsAuthentication2Format ( // // Do not close File. simply check file content // - if (mImageBase != NULL) { - FreePool (mImageBase); - mImageBase = NULL; + if (ImageBase != NULL) { + FreePool (ImageBase); } return IsAuth2Format; @@ -1674,151 +1675,11 @@ IsX509CertInDbx ( return IsFound; } -/** - Reads contents of a PE/COFF image in memory buffer. - - Caution: This function may receive untrusted input. - PE/COFF image is external input, so this function will make sure the PE/COFF image content - read is within the image buffer. - - @param FileHandle Pointer to the file handle to read the PE/COFF image. - @param FileOffset Offset into the PE/COFF image to begin the read operation. - @param ReadSize On input, the size in bytes of the requested read operation. - On output, the number of bytes actually read. - @param Buffer Output buffer that contains the data read from the PE/COFF image. - - @retval EFI_SUCCESS The specified portion of the PE/COFF image was read and the size -**/ -EFI_STATUS -EFIAPI -SecureBootConfigImageRead ( - IN VOID *FileHandle, - IN UINTN FileOffset, - IN OUT UINTN *ReadSize, - OUT VOID *Buffer - ) -{ - UINTN EndPosition; - - if ((FileHandle == NULL) || (ReadSize == NULL) || (Buffer == NULL)) { - return EFI_INVALID_PARAMETER; - } - - if (MAX_ADDRESS - FileOffset < *ReadSize) { - return EFI_INVALID_PARAMETER; - } - - EndPosition = FileOffset + *ReadSize; - if (EndPosition > mImageSize) { - *ReadSize = (UINT32)(mImageSize - FileOffset); - } - - if (FileOffset >= mImageSize) { - *ReadSize = 0; - } - - CopyMem (Buffer, (UINT8 *)((UINTN)FileHandle + FileOffset), *ReadSize); - - return EFI_SUCCESS; -} - -/** - Load PE/COFF image information into internal buffer and check its validity. - - @retval EFI_SUCCESS Successful - @retval EFI_UNSUPPORTED Invalid PE/COFF file - @retval EFI_ABORTED Serious error occurs, like file I/O error etc. - -**/ -EFI_STATUS -LoadPeImage ( - VOID - ) -{ - EFI_IMAGE_DOS_HEADER *DosHdr; - EFI_IMAGE_NT_HEADERS32 *NtHeader32; - EFI_IMAGE_NT_HEADERS64 *NtHeader64; - PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; - EFI_STATUS Status; - - NtHeader32 = NULL; - NtHeader64 = NULL; - - ZeroMem (&ImageContext, sizeof (ImageContext)); - ImageContext.Handle = (VOID *)mImageBase; - ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE)SecureBootConfigImageRead; - - // - // Get information about the image being loaded - // - Status = PeCoffLoaderGetImageInfo (&ImageContext); - if (EFI_ERROR (Status)) { - // - // The information can't be got from the invalid PeImage - // - DEBUG ((DEBUG_INFO, "SecureBootConfigDxe: PeImage invalid. \n")); - return Status; - } - - // - // Read the Dos header - // - DosHdr = (EFI_IMAGE_DOS_HEADER *)(mImageBase); - if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) { - // - // DOS image header is present, - // So read the PE header after the DOS image header - // - mPeCoffHeaderOffset = DosHdr->e_lfanew; - } else { - mPeCoffHeaderOffset = 0; - } - - // - // Read PE header and check the signature validity and machine compatibility - // - NtHeader32 = (EFI_IMAGE_NT_HEADERS32 *)(mImageBase + mPeCoffHeaderOffset); - if (NtHeader32->Signature != EFI_IMAGE_NT_SIGNATURE) { - return EFI_UNSUPPORTED; - } - - mNtHeader.Pe32 = NtHeader32; - - // - // Check the architecture field of PE header and get the Certificate Data Directory data - // Note the size of FileHeader field is constant for both IA32 and X64 arch - // - if ( (NtHeader32->FileHeader.Machine == EFI_IMAGE_MACHINE_IA32) - || (NtHeader32->FileHeader.Machine == EFI_IMAGE_MACHINE_EBC) - || (NtHeader32->FileHeader.Machine == EFI_IMAGE_MACHINE_ARMTHUMB_MIXED)) - { - // - // 32-bits Architecture - // - mImageType = ImageType_IA32; - mSecDataDir = (EFI_IMAGE_SECURITY_DATA_DIRECTORY *)&(NtHeader32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]); - } else if ( (NtHeader32->FileHeader.Machine == EFI_IMAGE_MACHINE_IA64) - || (NtHeader32->FileHeader.Machine == EFI_IMAGE_MACHINE_X64) - || (NtHeader32->FileHeader.Machine == EFI_IMAGE_MACHINE_AARCH64)) - { - // - // 64-bits Architecture - // - mImageType = ImageType_X64; - NtHeader64 = (EFI_IMAGE_NT_HEADERS64 *)(mImageBase + mPeCoffHeaderOffset); - mSecDataDir = (EFI_IMAGE_SECURITY_DATA_DIRECTORY *)&(NtHeader64->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]); - } else { - return EFI_UNSUPPORTED; - } - - return EFI_SUCCESS; -} - /** Calculate hash of Pe/Coff image based on the authenticode image hashing in PE/COFF Specification 8.0 Appendix A - Notes: PE/COFF image has been checked by BasePeCoffLib PeCoffLoaderGetImageInfo() in + Notes: PE/COFF image has been checked by UefiImageLibLib UefiImageInitializeContext() in the function LoadPeImage (). @param[in] HashAlg Hash algorithm type. @@ -1829,254 +1690,56 @@ LoadPeImage ( **/ BOOLEAN HashPeImage ( - IN UINT32 HashAlg + UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext, + IN UINT32 HashAlg, + UINT8 ImageDigest[MAX_DIGEST_SIZE], + UINTN *ImageDigestSize ) { - BOOLEAN Status; - EFI_IMAGE_SECTION_HEADER *Section; - VOID *HashCtx; - UINTN CtxSize; - UINT8 *HashBase; - UINTN HashSize; - UINTN SumOfBytesHashed; - EFI_IMAGE_SECTION_HEADER *SectionHeader; - UINTN Index; - UINTN Pos; - - HashCtx = NULL; - SectionHeader = NULL; - Status = FALSE; - - if ((HashAlg >= HASHALG_MAX)) { - return FALSE; - } + BOOLEAN Status; + VOID *HashCtx; + UINTN CtxSize; + + ASSERT (HashAlg < HASHALG_MAX); + + HashCtx = NULL; + Status = FALSE; // // Initialize context of hash. // - ZeroMem (mImageDigest, MAX_DIGEST_SIZE); - - switch (HashAlg) { - case HASHALG_SHA256: - mImageDigestSize = SHA256_DIGEST_SIZE; - mCertType = gEfiCertSha256Guid; - break; - - case HASHALG_SHA384: - mImageDigestSize = SHA384_DIGEST_SIZE; - mCertType = gEfiCertSha384Guid; - break; - - case HASHALG_SHA512: - mImageDigestSize = SHA512_DIGEST_SIZE; - mCertType = gEfiCertSha512Guid; - break; - - default: - return FALSE; - } + ZeroMem (ImageDigest, MAX_DIGEST_SIZE); CtxSize = mHash[HashAlg].GetContextSize (); HashCtx = AllocatePool (CtxSize); - ASSERT (HashCtx != NULL); - - // 1. Load the image header into memory. - - // 2. Initialize a SHA hash context. - Status = mHash[HashAlg].HashInit (HashCtx); - if (!Status) { - goto Done; - } - - // - // Measuring PE/COFF Image Header; - // But CheckSum field and SECURITY data directory (certificate) are excluded - // - - // - // 3. Calculate the distance from the base of the image header to the image checksum address. - // 4. Hash the image header from its base to beginning of the image checksum. - // - HashBase = mImageBase; - if (mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { - // - // Use PE32 offset. - // - HashSize = (UINTN)(&mNtHeader.Pe32->OptionalHeader.CheckSum) - (UINTN)HashBase; - } else { - // - // Use PE32+ offset. - // - HashSize = (UINTN)(&mNtHeader.Pe32Plus->OptionalHeader.CheckSum) - (UINTN)HashBase; - } - - Status = mHash[HashAlg].HashUpdate (HashCtx, HashBase, HashSize); - if (!Status) { - goto Done; + if (HashCtx == NULL) { + return FALSE; } - // - // 5. Skip over the image checksum (it occupies a single ULONG). - // 6. Get the address of the beginning of the Cert Directory. - // 7. Hash everything from the end of the checksum to the start of the Cert Directory. - // - if (mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { - // - // Use PE32 offset. - // - HashBase = (UINT8 *)&mNtHeader.Pe32->OptionalHeader.CheckSum + sizeof (UINT32); - HashSize = (UINTN)(&mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - (UINTN)HashBase; - } else { - // - // Use PE32+ offset. - // - HashBase = (UINT8 *)&mNtHeader.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32); - HashSize = (UINTN)(&mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - (UINTN)HashBase; - } + Status = mHash[HashAlg].HashInit (HashCtx); - Status = mHash[HashAlg].HashUpdate (HashCtx, HashBase, HashSize); if (!Status) { goto Done; } - // - // 8. Skip over the Cert Directory. (It is sizeof(IMAGE_DATA_DIRECTORY) bytes.) - // 9. Hash everything from the end of the Cert Directory to the end of image header. - // - if (mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { - // - // Use PE32 offset - // - HashBase = (UINT8 *)&mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]; - HashSize = mNtHeader.Pe32->OptionalHeader.SizeOfHeaders - ((UINTN)(&mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]) - (UINTN)mImageBase); - } else { - // - // Use PE32+ offset. - // - HashBase = (UINT8 *)&mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]; - HashSize = mNtHeader.Pe32Plus->OptionalHeader.SizeOfHeaders - ((UINTN)(&mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]) - (UINTN)mImageBase); - } + Status = UefiImageHashImageDefault (ImageContext, HashCtx, mHash[HashAlg].HashUpdate); - Status = mHash[HashAlg].HashUpdate (HashCtx, HashBase, HashSize); if (!Status) { + DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Failed to hash this image using %s.\n", mHash[HashAlg].Name)); goto Done; } - // - // 10. Set the SUM_OF_BYTES_HASHED to the size of the header. - // - if (mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { - // - // Use PE32 offset. - // - SumOfBytesHashed = mNtHeader.Pe32->OptionalHeader.SizeOfHeaders; - } else { - // - // Use PE32+ offset - // - SumOfBytesHashed = mNtHeader.Pe32Plus->OptionalHeader.SizeOfHeaders; - } - - // - // 11. Build a temporary table of pointers to all the IMAGE_SECTION_HEADER - // structures in the image. The 'NumberOfSections' field of the image - // header indicates how big the table should be. Do not include any - // IMAGE_SECTION_HEADERs in the table whose 'SizeOfRawData' field is zero. - // - SectionHeader = (EFI_IMAGE_SECTION_HEADER *)AllocateZeroPool (sizeof (EFI_IMAGE_SECTION_HEADER) * mNtHeader.Pe32->FileHeader.NumberOfSections); - ASSERT (SectionHeader != NULL); - // - // 12. Using the 'PointerToRawData' in the referenced section headers as - // a key, arrange the elements in the table in ascending order. In other - // words, sort the section headers according to the disk-file offset of - // the section. - // - Section = (EFI_IMAGE_SECTION_HEADER *)( - mImageBase + - mPeCoffHeaderOffset + - sizeof (UINT32) + - sizeof (EFI_IMAGE_FILE_HEADER) + - mNtHeader.Pe32->FileHeader.SizeOfOptionalHeader - ); - for (Index = 0; Index < mNtHeader.Pe32->FileHeader.NumberOfSections; Index++) { - Pos = Index; - while ((Pos > 0) && (Section->PointerToRawData < SectionHeader[Pos - 1].PointerToRawData)) { - CopyMem (&SectionHeader[Pos], &SectionHeader[Pos - 1], sizeof (EFI_IMAGE_SECTION_HEADER)); - Pos--; - } - - CopyMem (&SectionHeader[Pos], Section, sizeof (EFI_IMAGE_SECTION_HEADER)); - Section += 1; - } - - // - // 13. Walk through the sorted table, bring the corresponding section - // into memory, and hash the entire section (using the 'SizeOfRawData' - // field in the section header to determine the amount of data to hash). - // 14. Add the section's 'SizeOfRawData' to SUM_OF_BYTES_HASHED . - // 15. Repeat steps 13 and 14 for all the sections in the sorted table. - // - for (Index = 0; Index < mNtHeader.Pe32->FileHeader.NumberOfSections; Index++) { - Section = &SectionHeader[Index]; - if (Section->SizeOfRawData == 0) { - continue; - } - - HashBase = mImageBase + Section->PointerToRawData; - HashSize = (UINTN)Section->SizeOfRawData; - - Status = mHash[HashAlg].HashUpdate (HashCtx, HashBase, HashSize); - if (!Status) { - goto Done; - } - - SumOfBytesHashed += HashSize; - } - - // - // 16. If the file size is greater than SUM_OF_BYTES_HASHED, there is extra - // data in the file that needs to be added to the hash. This data begins - // at file offset SUM_OF_BYTES_HASHED and its length is: - // FileSize - (CertDirectory->Size) - // - if (mImageSize > SumOfBytesHashed) { - HashBase = mImageBase + SumOfBytesHashed; - if (mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { - // - // Use PE32 offset. - // - HashSize = (UINTN)( - mImageSize - - mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size - - SumOfBytesHashed); - } else { - // - // Use PE32+ offset. - // - HashSize = (UINTN)( - mImageSize - - mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size - - SumOfBytesHashed); - } - - Status = mHash[HashAlg].HashUpdate (HashCtx, HashBase, HashSize); - if (!Status) { - goto Done; - } - } + ASSERT (mHash[HashAlg].DigestLength <= MAX_DIGEST_SIZE); + Status = mHash[HashAlg].HashFinal (HashCtx, ImageDigest); - Status = mHash[HashAlg].HashFinal (HashCtx, mImageDigest); + *ImageDigestSize = mHash[HashAlg].DigestLength; Done: if (HashCtx != NULL) { FreePool (HashCtx); } - if (SectionHeader != NULL) { - FreePool (SectionHeader); - } - return Status; } @@ -2091,36 +1754,41 @@ HashPeImage ( **/ EFI_STATUS HashPeImageByType ( - VOID + UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext, + IN CONST UINT8 *AuthData, + IN UINTN AuthDataSize, + UINT8 ImageDigest[MAX_DIGEST_SIZE], + UINTN *ImageDigestSize, + OUT CONST EFI_GUID **CertType ) { - UINT8 Index; - WIN_CERTIFICATE_EFI_PKCS *PkcsCertData; - - PkcsCertData = (WIN_CERTIFICATE_EFI_PKCS *)(mImageBase + mSecDataDir->Offset); + UINT8 Index; - for (Index = 0; Index < HASHALG_MAX; Index++) { + // + // Check the Hash algorithm in PE/COFF Authenticode. + // According to PKCS#7 Definition: + // SignedData ::= SEQUENCE { + // version Version, + // digestAlgorithms DigestAlgorithmIdentifiers, + // contentInfo ContentInfo, + // .... } + // The DigestAlgorithmIdentifiers can be used to determine the hash algorithm in PE/COFF hashing + // This field has the fixed offset (+32) in final Authenticode ASN.1 data. + // Fixed offset (+32) is calculated based on two bytes of length encoding. + // + if ((*(AuthData + 1) & TWO_BYTE_ENCODE) != TWO_BYTE_ENCODE) { // - // Check the Hash algorithm in PE/COFF Authenticode. - // According to PKCS#7 Definition: - // SignedData ::= SEQUENCE { - // version Version, - // digestAlgorithms DigestAlgorithmIdentifiers, - // contentInfo ContentInfo, - // .... } - // The DigestAlgorithmIdentifiers can be used to determine the hash algorithm in PE/COFF hashing - // This field has the fixed offset (+32) in final Authenticode ASN.1 data. - // Fixed offset (+32) is calculated based on two bytes of length encoding. + // Only support two bytes of Long Form of Length Encoding. // - if ((*(PkcsCertData->CertData + 1) & TWO_BYTE_ENCODE) != TWO_BYTE_ENCODE) { - // - // Only support two bytes of Long Form of Length Encoding. - // + return EFI_UNSUPPORTED; + } + + for (Index = 0; Index < HASHALG_MAX; Index++) { + if (AuthDataSize < 32 + mHash[Index].OidLength) { continue; } - // - if (CompareMem (PkcsCertData->CertData + 32, mHash[Index].OidValue, mHash[Index].OidLength) == 0) { + if (CompareMem (AuthData + 32, mHash[Index].OidValue, mHash[Index].OidLength) == 0) { break; } } @@ -2132,10 +1800,12 @@ HashPeImageByType ( // // HASH PE Image based on Hash algorithm in PE/COFF Authenticode. // - if (!HashPeImage (Index)) { + if (!HashPeImage (ImageContext, Index, ImageDigest, ImageDigestSize)) { return EFI_UNSUPPORTED; } + *CertType = mHash[Index].CertType; + return EFI_SUCCESS; } @@ -2163,6 +1833,8 @@ EnrollAuthentication2Descriptor ( VOID *Data; UINTN DataSize; UINT32 Attr; + UINT8 *ImageBase; + UINTN ImageSize; Data = NULL; @@ -2178,16 +1850,14 @@ EnrollAuthentication2Descriptor ( // Status = ReadFileContent ( Private->FileContext->FHandle, - (VOID **)&mImageBase, - &mImageSize, + (VOID **)&ImageBase, + &ImageSize, 0 ); if (EFI_ERROR (Status)) { goto ON_EXIT; } - ASSERT (mImageBase != NULL); - Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS; @@ -2217,8 +1887,8 @@ EnrollAuthentication2Descriptor ( VariableName, &gEfiImageSecurityDatabaseGuid, Attr, - mImageSize, - mImageBase + ImageSize, + ImageBase ); DEBUG ((DEBUG_INFO, "Enroll AUTH_2 data to Var:%s Status: %x\n", VariableName, Status)); @@ -2231,9 +1901,8 @@ EnrollAuthentication2Descriptor ( FreePool (Data); } - if (mImageBase != NULL) { - FreePool (mImageBase); - mImageBase = NULL; + if (ImageBase != NULL) { + FreePool (ImageBase); } return Status; @@ -2259,16 +1928,24 @@ EnrollImageSignatureToSigDB ( IN CHAR16 *VariableName ) { - EFI_STATUS Status; - EFI_SIGNATURE_LIST *SigDBCert; - EFI_SIGNATURE_DATA *SigDBCertData; - VOID *Data; - UINTN DataSize; - UINTN SigDBSize; - UINT32 Attr; - WIN_CERTIFICATE_UEFI_GUID *GuidCertData; - EFI_TIME Time; - UINT32 HashAlg; + EFI_STATUS Status; + EFI_SIGNATURE_LIST *SigDBCert; + EFI_SIGNATURE_DATA *SigDBCertData; + VOID *Data; + UINTN DataSize; + UINTN SigDBSize; + UINT32 Attr; + EFI_TIME Time; + UINT32 HashAlg; + CONST WIN_CERTIFICATE_UEFI_GUID *GuidCertData; + CONST WIN_CERTIFICATE *Certificate; + UEFI_IMAGE_LOADER_IMAGE_CONTEXT ImageContext; + UINT8 *ImageBase; + UINTN ImageSize; + UINT8 ImageDigest[MAX_DIGEST_SIZE]; + UINTN ImageDigestSize; + CONST EFI_GUID *CertType; + CONST WIN_CERTIFICATE_EFI_PKCS *PkcsCertData; Data = NULL; GuidCertData = NULL; @@ -2291,22 +1968,22 @@ EnrollImageSignatureToSigDB ( // Status = ReadFileContent ( Private->FileContext->FHandle, - (VOID **)&mImageBase, - &mImageSize, + (VOID **)&ImageBase, + &ImageSize, 0 ); if (EFI_ERROR (Status)) { goto ON_EXIT; } - ASSERT (mImageBase != NULL); - - Status = LoadPeImage (); + Status = UefiImageInitializeContextPreHash (&ImageContext, ImageBase, (UINT32)ImageSize); if (EFI_ERROR (Status)) { goto ON_EXIT; } - if (mSecDataDir->SizeOfCert == 0) { + Status = UefiImageGetFirstCertificate (&ImageContext, &Certificate); + + if (Status == RETURN_NOT_FOUND) { Status = EFI_SECURITY_VIOLATION; HashAlg = sizeof (mHash) / sizeof (HASH_TABLE); while (HashAlg > 0) { @@ -2315,7 +1992,7 @@ EnrollImageSignatureToSigDB ( continue; } - if (HashPeImage (HashAlg)) { + if (HashPeImage (&ImageContext, HashAlg, ImageDigest, &ImageDigestSize)) { Status = EFI_SUCCESS; break; } @@ -2326,24 +2003,21 @@ EnrollImageSignatureToSigDB ( goto ON_EXIT; } } else { - // - // Read the certificate data - // - mCertificate = (WIN_CERTIFICATE *)(mImageBase + mSecDataDir->Offset); - - if (mCertificate->wCertificateType == WIN_CERT_TYPE_EFI_GUID) { - GuidCertData = (WIN_CERTIFICATE_UEFI_GUID *)mCertificate; + if (Certificate->wCertificateType == WIN_CERT_TYPE_EFI_GUID) { + GuidCertData = (CONST WIN_CERTIFICATE_UEFI_GUID *)Certificate; if (CompareMem (&GuidCertData->CertType, &gEfiCertTypeRsa2048Sha256Guid, sizeof (EFI_GUID)) != 0) { Status = EFI_ABORTED; goto ON_EXIT; } - if (!HashPeImage (HASHALG_SHA256)) { + if (!HashPeImage (&ImageContext, HASHALG_SHA256, ImageDigest, &ImageDigestSize)) { Status = EFI_ABORTED; goto ON_EXIT; } - } else if (mCertificate->wCertificateType == WIN_CERT_TYPE_PKCS_SIGNED_DATA) { - Status = HashPeImageByType (); + } else if (Certificate->wCertificateType == WIN_CERT_TYPE_PKCS_SIGNED_DATA) { + PkcsCertData = (CONST WIN_CERTIFICATE_EFI_PKCS *)Certificate; + + Status = HashPeImageByType (&ImageContext, PkcsCertData->CertData, PkcsCertData->Hdr.dwLength - sizeof (PkcsCertData->Hdr), ImageDigest, &ImageDigestSize, &CertType); if (EFI_ERROR (Status)) { goto ON_EXIT; } @@ -2358,7 +2032,7 @@ EnrollImageSignatureToSigDB ( // SigDBSize = sizeof (EFI_SIGNATURE_LIST) + sizeof (EFI_SIGNATURE_DATA) - 1 - + (UINT32)mImageDigestSize; + + (UINT32)ImageDigestSize; Data = (UINT8 *)AllocateZeroPool (SigDBSize); if (Data == NULL) { @@ -2372,12 +2046,12 @@ EnrollImageSignatureToSigDB ( SigDBCert = (EFI_SIGNATURE_LIST *)Data; SigDBCert->SignatureListSize = (UINT32)SigDBSize; SigDBCert->SignatureHeaderSize = 0; - SigDBCert->SignatureSize = sizeof (EFI_SIGNATURE_DATA) - 1 + (UINT32)mImageDigestSize; - CopyGuid (&SigDBCert->SignatureType, &mCertType); + SigDBCert->SignatureSize = sizeof (EFI_SIGNATURE_DATA) - 1 + (UINT32)ImageDigestSize; + CopyGuid (&SigDBCert->SignatureType, CertType); SigDBCertData = (EFI_SIGNATURE_DATA *)((UINT8 *)SigDBCert + sizeof (EFI_SIGNATURE_LIST)); CopyGuid (&SigDBCertData->SignatureOwner, Private->SignatureGUID); - CopyMem (SigDBCertData->SignatureData, mImageDigest, mImageDigestSize); + CopyMem (SigDBCertData->SignatureData, ImageDigest, ImageDigestSize); Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS; @@ -2439,9 +2113,9 @@ EnrollImageSignatureToSigDB ( FreePool (Data); } - if (mImageBase != NULL) { - FreePool (mImageBase); - mImageBase = NULL; + if (ImageBase != NULL) { + FreePool (ImageBase); + ImageBase = NULL; } return Status; diff --git a/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigImpl.h b/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigImpl.h index ff6e7301af..7ad3052a6a 100644 --- a/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigImpl.h +++ b/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigImpl.h @@ -34,7 +34,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #include #include #include -#include +#include #include #include @@ -85,16 +85,6 @@ extern EFI_IFR_GUID_LABEL *mEndLabel; #define WIN_CERT_UEFI_RSA3072_SIZE 384 #define WIN_CERT_UEFI_RSA4096_SIZE 512 -// -// Support hash types -// -#define HASHALG_SHA224 0x00000000 -#define HASHALG_SHA256 0x00000001 -#define HASHALG_SHA384 0x00000002 -#define HASHALG_SHA512 0x00000003 -#define HASHALG_RAW 0x00000004 -#define HASHALG_MAX 0x00000004 - // // Certificate public key minimum size (bytes) // @@ -306,6 +296,7 @@ typedef struct { UINTN DigestLength; ///< Digest Length UINT8 *OidValue; ///< Hash Algorithm OID ASN.1 Value UINTN OidLength; ///< Length of Hash OID Value + CONST GUID *CertType; ///< GUID of the certificate type HASH_GET_CONTEXT_SIZE GetContextSize; ///< Pointer to Hash GetContentSize function HASH_INIT HashInit; ///< Pointer to Hash Init function HASH_UPDATE HashUpdate; ///< Pointer to Hash Update function diff --git a/ShellPkg/DynamicCommand/DpDynamicCommand/DpApp.inf b/ShellPkg/DynamicCommand/DpDynamicCommand/DpApp.inf index d9e1c23a1e..abe15b3f42 100644 --- a/ShellPkg/DynamicCommand/DpDynamicCommand/DpApp.inf +++ b/ShellPkg/DynamicCommand/DpDynamicCommand/DpApp.inf @@ -50,7 +50,6 @@ DevicePathLib PerformanceLib DxeServicesLib - PeCoffGetEntryPointLib [Guids] gPerformanceProtocolGuid ## CONSUMES ## SystemTable diff --git a/ShellPkg/DynamicCommand/DpDynamicCommand/DpDynamicCommand.inf b/ShellPkg/DynamicCommand/DpDynamicCommand/DpDynamicCommand.inf index 2723fee706..290d1adebd 100644 --- a/ShellPkg/DynamicCommand/DpDynamicCommand/DpDynamicCommand.inf +++ b/ShellPkg/DynamicCommand/DpDynamicCommand/DpDynamicCommand.inf @@ -51,11 +51,11 @@ DevicePathLib PerformanceLib DxeServicesLib - PeCoffGetEntryPointLib [Guids] gPerformanceProtocolGuid ## CONSUMES ## SystemTable gEdkiiFpdtExtendedFirmwarePerformanceGuid ## CONSUMES ## SystemTable + gEfiDebugImageInfoTableGuid ## CONSUMES ## SystemTable [Protocols] gEfiLoadedImageProtocolGuid ## CONSUMES diff --git a/ShellPkg/DynamicCommand/DpDynamicCommand/DpInternal.h b/ShellPkg/DynamicCommand/DpDynamicCommand/DpInternal.h index 97f47f2960..3ce8d05d49 100644 --- a/ShellPkg/DynamicCommand/DpDynamicCommand/DpInternal.h +++ b/ShellPkg/DynamicCommand/DpDynamicCommand/DpInternal.h @@ -109,8 +109,8 @@ IsCorePerf ( **/ VOID DpGetShortPdbFileName ( - IN CHAR8 *PdbFileName, - OUT CHAR16 *UnicodeBuffer + IN CONST CHAR8 *PdbFileName, + OUT CHAR16 *UnicodeBuffer ); /** diff --git a/ShellPkg/DynamicCommand/DpDynamicCommand/DpTrace.c b/ShellPkg/DynamicCommand/DpDynamicCommand/DpTrace.c index 9c0a9a06a1..5cd28ff919 100644 --- a/ShellPkg/DynamicCommand/DpDynamicCommand/DpTrace.c +++ b/ShellPkg/DynamicCommand/DpDynamicCommand/DpTrace.c @@ -11,7 +11,7 @@ #include #include #include -#include + #include #include #include diff --git a/ShellPkg/DynamicCommand/DpDynamicCommand/DpUtilities.c b/ShellPkg/DynamicCommand/DpDynamicCommand/DpUtilities.c index 60c886c11d..240093dc26 100644 --- a/ShellPkg/DynamicCommand/DpDynamicCommand/DpUtilities.c +++ b/ShellPkg/DynamicCommand/DpDynamicCommand/DpUtilities.c @@ -11,7 +11,7 @@ #include #include #include -#include + #include #include #include @@ -28,6 +28,7 @@ #include #include +#include #include "Dp.h" #include "Literals.h" @@ -148,8 +149,8 @@ IsCorePerf ( **/ VOID DpGetShortPdbFileName ( - IN CHAR8 *PdbFileName, - OUT CHAR16 *UnicodeBuffer + IN CONST CHAR8 *PdbFileName, + OUT CHAR16 *UnicodeBuffer ) { UINTN IndexA; // Current work location within an ASCII string. @@ -188,6 +189,41 @@ DpGetShortPdbFileName ( } } +// FIXME: Duplicate (GetImageName), create API +CONST CHAR8 * +GetImagePdb ( + IN CONST VOID *ImageBase + ) +{ + EFI_STATUS Status; + EFI_DEBUG_IMAGE_INFO_TABLE_HEADER *DebugTableHeader; + EFI_DEBUG_IMAGE_INFO *DebugTable; + UINTN Entry; + + Status = EfiGetSystemConfigurationTable (&gEfiDebugImageInfoTableGuid, (VOID **)&DebugTableHeader); + if (EFI_ERROR (Status)) { + return NULL; + } + + DebugTable = DebugTableHeader->EfiDebugImageInfoTable; + if (DebugTable == NULL) { + return NULL; + } + + for (Entry = 0; Entry < DebugTableHeader->TableSize; Entry++, DebugTable++) { + if (DebugTable->NormalImage != NULL) { + if ((DebugTable->NormalImage->ImageInfoType == EFI_DEBUG_IMAGE_INFO_TYPE_NORMAL) && + (DebugTable->NormalImage->LoadedImageProtocolInstance != NULL)) { + if (ImageBase == DebugTable->NormalImage->LoadedImageProtocolInstance->ImageBase) { + return DebugTable->NormalImage->PdbPath; + } + } + } + } + + return NULL; +} + /** Get a human readable name for an image handle. The following methods will be tried orderly: @@ -211,7 +247,7 @@ DpGetNameFromHandle ( { EFI_STATUS Status; EFI_LOADED_IMAGE_PROTOCOL *Image; - CHAR8 *PdbFileName; + CONST CHAR8 *PdbFileName; EFI_DRIVER_BINDING_PROTOCOL *DriverBinding; EFI_STRING StringPtr; EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath; @@ -255,7 +291,7 @@ DpGetNameFromHandle ( } if (!EFI_ERROR (Status)) { - PdbFileName = PeCoffLoaderGetPdbPointer (Image->ImageBase); + PdbFileName = GetImagePdb (Image->ImageBase); if (PdbFileName != NULL) { DpGetShortPdbFileName (PdbFileName, mGaugeString); diff --git a/ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.c b/ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.c index 781da4d55d..2d62bd4f1d 100644 --- a/ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.c +++ b/ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.c @@ -306,7 +306,9 @@ LoadedImageProtocolDumpInformation ( return NULL; } - PdbFileName = PeCoffLoaderGetPdbPointer (LoadedImage->ImageBase); + // FIXME: + //PdbFileName = UefiImageLoaderGetPdbPointer (LoadedImage->ImageBase); + PdbFileName = NULL; DataType = ConvertMemoryType (LoadedImage->ImageDataType); CodeType = ConvertMemoryType (LoadedImage->ImageCodeType); diff --git a/ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.h b/ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.h index 6be0d78c4c..74aa3c88f6 100644 --- a/ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.h +++ b/ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.h @@ -148,7 +148,7 @@ #include #include #include -#include + #define EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION_V1 1 #define EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION_V2 2 diff --git a/ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.inf b/ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.inf index 0d483805e7..f51b22516b 100644 --- a/ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.inf +++ b/ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.inf @@ -45,7 +45,6 @@ UefiLib HiiLib SortLib - PeCoffGetEntryPointLib [Protocols] gEfiSimpleFileSystemProtocolGuid ## SOMETIMES_CONSUMES diff --git a/ShellPkg/Library/UefiShellDebug1CommandsLib/LoadPciRom.c b/ShellPkg/Library/UefiShellDebug1CommandsLib/LoadPciRom.c index 852d6dcf80..fc0ba4d411 100644 --- a/ShellPkg/Library/UefiShellDebug1CommandsLib/LoadPciRom.c +++ b/ShellPkg/Library/UefiShellDebug1CommandsLib/LoadPciRom.c @@ -10,7 +10,7 @@ #include "UefiShellDebug1CommandsLib.h" #include #include -#include +#include #include /** diff --git a/ShellPkg/Library/UefiShellDriver1CommandsLib/UefiShellDriver1CommandsLib.h b/ShellPkg/Library/UefiShellDriver1CommandsLib/UefiShellDriver1CommandsLib.h index 1c002361de..6273491aee 100644 --- a/ShellPkg/Library/UefiShellDriver1CommandsLib/UefiShellDriver1CommandsLib.h +++ b/ShellPkg/Library/UefiShellDriver1CommandsLib/UefiShellDriver1CommandsLib.h @@ -54,7 +54,7 @@ #include #include #include -#include + #include extern EFI_HII_HANDLE gShellDriver1HiiHandle; diff --git a/ShellPkg/Library/UefiShellDriver1CommandsLib/UefiShellDriver1CommandsLib.inf b/ShellPkg/Library/UefiShellDriver1CommandsLib/UefiShellDriver1CommandsLib.inf index e7661c3fce..518eb1a09e 100644 --- a/ShellPkg/Library/UefiShellDriver1CommandsLib/UefiShellDriver1CommandsLib.inf +++ b/ShellPkg/Library/UefiShellDriver1CommandsLib/UefiShellDriver1CommandsLib.inf @@ -50,7 +50,6 @@ UefiBootServicesTableLib SortLib PrintLib - PeCoffGetEntryPointLib [Pcd] gEfiShellPkgTokenSpaceGuid.PcdShellProfileMask ## CONSUMES diff --git a/ShellPkg/ShellPkg.dsc b/ShellPkg/ShellPkg.dsc index 557b0ec0f3..85983ee435 100644 --- a/ShellPkg/ShellPkg.dsc +++ b/ShellPkg/ShellPkg.dsc @@ -53,7 +53,6 @@ HandleParsingLib|ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.inf OrderedCollectionLib|MdePkg/Library/BaseOrderedCollectionRedBlackTreeLib/BaseOrderedCollectionRedBlackTreeLib.inf - PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf BcfgCommandLib|ShellPkg/Library/UefiShellBcfgCommandLib/UefiShellBcfgCommandLib.inf AcpiViewCommandLib|ShellPkg/Library/UefiShellAcpiViewCommandLib/UefiShellAcpiViewCommandLib.inf IoLib|MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf diff --git a/SignedCapsulePkg/SignedCapsulePkg.dsc b/SignedCapsulePkg/SignedCapsulePkg.dsc index 4c656666e9..b0bd023a4c 100644 --- a/SignedCapsulePkg/SignedCapsulePkg.dsc +++ b/SignedCapsulePkg/SignedCapsulePkg.dsc @@ -40,8 +40,8 @@ PciCf8Lib|MdePkg/Library/BasePciCf8Lib/BasePciCf8Lib.inf PciSegmentLib|MdePkg/Library/BasePciSegmentLibPci/BasePciSegmentLibPci.inf CacheMaintenanceLib|MdePkg/Library/BaseCacheMaintenanceLib/BaseCacheMaintenanceLib.inf - PeCoffLib|MdePkg/Library/BasePeCoffLib/BasePeCoffLib.inf - PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf + PeCoffLib2|MdePkg/Library/BasePeCoffLib2/BasePeCoffLib2.inf + UefiImageLib|MdePkg/Library/BaseUefiImageLib/BaseUefiImageLibPeCoff.inf SortLib|MdeModulePkg/Library/BaseSortLib/BaseSortLib.inf # # UEFI & PI @@ -75,7 +75,7 @@ DebugLib|MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.inf DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf ReportStatusCodeLib|MdePkg/Library/BaseReportStatusCodeLibNull/BaseReportStatusCodeLibNull.inf - PeCoffExtraActionLib|MdePkg/Library/BasePeCoffExtraActionLibNull/BasePeCoffExtraActionLibNull.inf + UefiImageExtraActionLib|MdePkg/Library/BaseUefiImageExtraActionLibNull/BaseUefiImageExtraActionLibNull.inf PerformanceLib|MdePkg/Library/BasePerformanceLibNull/BasePerformanceLibNull.inf DebugAgentLib|MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.inf PlatformHookLib|MdeModulePkg/Library/BasePlatformHookLibNull/BasePlatformHookLibNull.inf diff --git a/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugAgent.c b/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugAgent.c index b553a2a9aa..8fc4c6d79b 100644 --- a/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugAgent.c +++ b/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugAgent.c @@ -183,30 +183,7 @@ IsDebugAgentInitialzed ( } } -/** - Find and report module image info to HOST. - - @param[in] AlignSize Image aligned size. - -**/ -VOID -FindAndReportModuleImageInfo ( - IN UINTN AlignSize - ) -{ - UINTN Pe32Data; - PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; - - // - // Find Image Base - // - Pe32Data = PeCoffSearchImageBase ((UINTN)mErrorMsgVersionAlert); - if (Pe32Data != 0) { - ImageContext.ImageAddress = Pe32Data; - ImageContext.PdbPointer = PeCoffLoaderGetPdbPointer ((VOID *)(UINTN)ImageContext.ImageAddress); - PeCoffLoaderRelocateImageExtraAction (&ImageContext); - } -} +// FIXME: UefiImageRelocExtra functio removed, done by *Core? /** Trigger one software interrupt to debug agent to handle it. @@ -1315,7 +1292,7 @@ GetBreakCause ( // triggered by the single step execution mode. // The single-step mode is the highest priority debug exception. // This is single step, no need to check DR0, to ensure single step - // work in PeCoffExtraActionLib (right after triggering a breakpoint + // work in UefiImageExtraActionLib (right after triggering a breakpoint // to report image load/unload). // return Cause; diff --git a/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugAgent.h b/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugAgent.h index 4c72f8f3a9..fdbef964bd 100644 --- a/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugAgent.h +++ b/SourceLevelDebugPkg/Library/DebugAgent/DebugAgentCommon/DebugAgent.h @@ -26,8 +26,7 @@ #include #include #include -#include -#include +#include #include #include @@ -313,17 +312,6 @@ MultiProcessorDebugSupport ( VOID ); -/** - Find and report module image info to HOST. - - @param[in] AlignSize Image aligned size. - -**/ -VOID -FindAndReportModuleImageInfo ( - IN UINTN AlignSize - ); - /** Read IDT entry to check if IDT entries are setup by Debug Agent. diff --git a/SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgent/DxeDebugAgentLib.c b/SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgent/DxeDebugAgentLib.c index a41bba2c4b..9510268676 100644 --- a/SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgent/DxeDebugAgentLib.c +++ b/SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgent/DxeDebugAgentLib.c @@ -445,7 +445,6 @@ InitializeDebugAgent ( EnableInterrupts (); mDebugAgentInitialized = TRUE; - FindAndReportModuleImageInfo (SIZE_4KB); *(EFI_STATUS *)Context = EFI_SUCCESS; @@ -527,7 +526,6 @@ InitializeDebugAgent ( // Disable interrupt // DisableInterrupts (); - FindAndReportModuleImageInfo (SIZE_4KB); if (GetDebugFlag (DEBUG_AGENT_FLAG_BREAK_BOOT_SCRIPT) == 1) { // // If Boot Script entry break is set, code will be break at here. diff --git a/SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgentLib.inf b/SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgentLib.inf index aa50048780..ba670014c6 100644 --- a/SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgentLib.inf +++ b/SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgentLib.inf @@ -69,8 +69,7 @@ LocalApicLib TimerLib PrintLib - PeCoffGetEntryPointLib - PeCoffExtraActionLib + UefiImageExtraActionLib MemoryAllocationLib [Guids] diff --git a/SourceLevelDebugPkg/Library/DebugAgent/SecPeiDebugAgent/SecPeiDebugAgentLib.c b/SourceLevelDebugPkg/Library/DebugAgent/SecPeiDebugAgent/SecPeiDebugAgentLib.c index b32754fc2a..64e66b3d29 100644 --- a/SourceLevelDebugPkg/Library/DebugAgent/SecPeiDebugAgent/SecPeiDebugAgentLib.c +++ b/SourceLevelDebugPkg/Library/DebugAgent/SecPeiDebugAgent/SecPeiDebugAgentLib.c @@ -575,10 +575,7 @@ InitializeDebugAgent ( Phase2Context.InitFlag = InitFlag; Phase2Context.Context = Context; Phase2Context.Function = Function; - DebugPortInitialize ((VOID *)&Phase2Context, InitializeDebugAgentPhase2); - - FindAndReportModuleImageInfo (4); - + DebugPortInitialize ((VOID *) &Phase2Context, InitializeDebugAgentPhase2); break; case DEBUG_AGENT_INIT_THUNK_PEI_IA32TOX64: @@ -606,10 +603,7 @@ InitializeDebugAgent ( // Update IDT entry to save location pointer saved the mailbox pointer // SetLocationSavedMailboxPointerInIdtEntry (MailboxLocationPointer); - - FindAndReportModuleImageInfo (4); } - break; default: diff --git a/SourceLevelDebugPkg/Library/DebugAgent/SecPeiDebugAgentLib.inf b/SourceLevelDebugPkg/Library/DebugAgent/SecPeiDebugAgentLib.inf index f91e2d01ad..da030e9bc7 100644 --- a/SourceLevelDebugPkg/Library/DebugAgent/SecPeiDebugAgentLib.inf +++ b/SourceLevelDebugPkg/Library/DebugAgent/SecPeiDebugAgentLib.inf @@ -66,8 +66,7 @@ PrintLib PeiServicesLib MemoryAllocationLib - PeCoffGetEntryPointLib - PeCoffExtraActionLib + UefiImageExtraActionLib [Ppis] gEfiPeiMemoryDiscoveredPpiGuid ## NOTIFY diff --git a/SourceLevelDebugPkg/Library/DebugAgent/SmmDebugAgent/SmmDebugAgentLib.c b/SourceLevelDebugPkg/Library/DebugAgent/SmmDebugAgent/SmmDebugAgentLib.c index cc5bb957f7..633d009ceb 100644 --- a/SourceLevelDebugPkg/Library/DebugAgent/SmmDebugAgent/SmmDebugAgentLib.c +++ b/SourceLevelDebugPkg/Library/DebugAgent/SmmDebugAgent/SmmDebugAgentLib.c @@ -278,11 +278,6 @@ InitializeDebugAgent ( // TriggerSoftInterrupt (MEMORY_READY_SIGNATURE); } - - // - // Find and report PE/COFF image info to HOST - // - FindAndReportModuleImageInfo (SIZE_4KB); // // Restore saved IDT entries // @@ -396,10 +391,7 @@ InitializeDebugAgent ( // SaveAndSetDebugTimerInterrupt (TRUE); EnableInterrupts (); - - FindAndReportModuleImageInfo (SIZE_4KB); } - break; default: diff --git a/SourceLevelDebugPkg/Library/DebugAgent/SmmDebugAgentLib.inf b/SourceLevelDebugPkg/Library/DebugAgent/SmmDebugAgentLib.inf index 2084b34a85..e4abdd50cd 100644 --- a/SourceLevelDebugPkg/Library/DebugAgent/SmmDebugAgentLib.inf +++ b/SourceLevelDebugPkg/Library/DebugAgent/SmmDebugAgentLib.inf @@ -63,8 +63,7 @@ LocalApicLib TimerLib PrintLib - PeCoffExtraActionLib - PeCoffGetEntryPointLib + UefiImageExtraActionLib SmmServicesTableLib [Guids] diff --git a/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/Ia32/IntHandler.nasm b/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/Ia32/IntHandler.nasm index 9442d3adc5..fc08898254 100644 --- a/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/Ia32/IntHandler.nasm +++ b/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/Ia32/IntHandler.nasm @@ -1,3 +1,5 @@ +#ifndef DISABLE_NEW_DEPRECATED_INTERFACES + ;------------------------------------------------------------------------------ ; ; Copyright (c) 2016, Intel Corporation. All rights reserved.
@@ -20,3 +22,5 @@ ASM_PFX(AsmInterruptHandle): cli mov al, 1 iretd + +#endif // DISABLE_NEW_DEPRECATED_INTERFACES diff --git a/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLib.c b/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLib.c index 2c80f7e22d..80ab235376 100644 --- a/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLib.c +++ b/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLib.c @@ -1,3 +1,5 @@ +#ifndef DISABLE_NEW_DEPRECATED_INTERFACES + /** @file PE/Coff Extra Action library instances. @@ -27,7 +29,7 @@ IsDrxEnabled ( IN UINTN Dr7 ) { - return (BOOLEAN)(((Dr7 >> (RegisterIndex * 2)) & (BIT0 | BIT1)) == (BIT0 | BIT1)); + return (BOOLEAN) (((Dr7 >> (RegisterIndex * 2)) & (BIT0 | BIT1)) == (BIT0 | BIT1)); } /** @@ -46,25 +48,25 @@ PeCoffLoaderExtraActionCommon ( IN UINTN Signature ) { - BOOLEAN InterruptState; - UINTN Dr0; - UINTN Dr1; - UINTN Dr2; - UINTN Dr3; - UINTN Dr7; - UINTN Cr4; - UINTN NewDr7; - UINT8 LoadImageMethod; - UINT8 DebugAgentStatus; - IA32_DESCRIPTOR IdtDescriptor; - IA32_IDT_GATE_DESCRIPTOR OriginalIdtEntry; - BOOLEAN IdtEntryHooked; - UINT32 RegEdx; + BOOLEAN InterruptState; + UINTN Dr0; + UINTN Dr1; + UINTN Dr2; + UINTN Dr3; + UINTN Dr7; + UINTN Cr4; + UINTN NewDr7; + UINT8 LoadImageMethod; + UINT8 DebugAgentStatus; + IA32_DESCRIPTOR IdtDescriptor; + IA32_IDT_GATE_DESCRIPTOR OriginalIdtEntry; + BOOLEAN IdtEntryHooked; + UINT32 RegEdx; ASSERT (ImageContext != NULL); if (ImageContext->PdbPointer != NULL) { - DEBUG ((DEBUG_ERROR, " PDB = %a\n", ImageContext->PdbPointer)); + DEBUG((EFI_D_ERROR, " PDB = %a\n", ImageContext->PdbPointer)); } // @@ -84,7 +86,6 @@ PeCoffLoaderExtraActionCommon ( LoadImageMethod = DEBUG_LOAD_IMAGE_METHOD_SOFT_INT3; } } - AsmReadIdtr (&IdtDescriptor); if (LoadImageMethod == DEBUG_LOAD_IMAGE_METHOD_SOFT_INT3) { if (!CheckDebugAgentHandler (&IdtDescriptor, SOFT_INT_VECTOR_NUM)) { @@ -123,8 +124,8 @@ PeCoffLoaderExtraActionCommon ( // AsmWriteDr7 (BIT10); AsmWriteDr0 (Signature); - AsmWriteDr1 ((UINTN)ImageContext->PdbPointer); - AsmWriteDr2 ((UINTN)ImageContext); + AsmWriteDr1 ((UINTN) ImageContext->PdbPointer); + AsmWriteDr2 ((UINTN) ImageContext); AsmWriteDr3 (IO_PORT_BREAKPOINT_ADDRESS); if (LoadImageMethod == DEBUG_LOAD_IMAGE_METHOD_IO_HW_BREAKPOINT) { @@ -137,6 +138,7 @@ PeCoffLoaderExtraActionCommon ( do { DebugAgentStatus = IoRead8 (IO_PORT_BREAKPOINT_ADDRESS); } while (DebugAgentStatus == DEBUG_AGENT_IMAGE_WAIT); + } else if (LoadImageMethod == DEBUG_LOAD_IMAGE_METHOD_SOFT_INT3) { // // Generate a software break point. @@ -150,31 +152,26 @@ PeCoffLoaderExtraActionCommon ( // in the above exception handler // NewDr7 = AsmReadDr7 () | BIT10; // H/w sets bit 10, some simulators don't - if (!IsDrxEnabled (0, NewDr7) && ((AsmReadDr0 () == 0) || (AsmReadDr0 () == Signature))) { + if (!IsDrxEnabled (0, NewDr7) && (AsmReadDr0 () == 0 || AsmReadDr0 () == Signature)) { // // If user changed Dr3 (by setting HW bp in the above exception handler, // we will not set Dr0 to 0 in GO/STEP handler because the break cause is not IMAGE_LOAD/_UNLOAD. // AsmWriteDr0 (Dr0); } - - if (!IsDrxEnabled (1, NewDr7) && (AsmReadDr1 () == (UINTN)ImageContext->PdbPointer)) { + if (!IsDrxEnabled (1, NewDr7) && (AsmReadDr1 () == (UINTN) ImageContext->PdbPointer)) { AsmWriteDr1 (Dr1); } - - if (!IsDrxEnabled (2, NewDr7) && (AsmReadDr2 () == (UINTN)ImageContext)) { + if (!IsDrxEnabled (2, NewDr7) && (AsmReadDr2 () == (UINTN) ImageContext)) { AsmWriteDr2 (Dr2); } - if (!IsDrxEnabled (3, NewDr7) && (AsmReadDr3 () == IO_PORT_BREAKPOINT_ADDRESS)) { AsmWriteDr3 (Dr3); } - if (LoadImageMethod == DEBUG_LOAD_IMAGE_METHOD_IO_HW_BREAKPOINT) { if (AsmReadCr4 () == (Cr4 | BIT3)) { AsmWriteCr4 (Cr4); } - if (NewDr7 == 0x20000480) { AsmWriteDr7 (Dr7); } @@ -183,14 +180,12 @@ PeCoffLoaderExtraActionCommon ( AsmWriteDr7 (Dr7); } } - // // Restore original IDT entry for INT1 if it was hooked. // if (IdtEntryHooked) { RestoreIdtEntry1 (&IdtDescriptor, &OriginalIdtEntry); } - // // Restore the interrupt state // @@ -229,3 +224,5 @@ PeCoffLoaderUnloadImageExtraAction ( { PeCoffLoaderExtraActionCommon (ImageContext, IMAGE_UNLOAD_SIGNATURE); } + +#endif // DISABLE_NEW_DEPRECATED_INTERFACES diff --git a/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/X64/IntHandler.nasm b/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/X64/IntHandler.nasm index 6b3a7a526f..2aa9280797 100644 --- a/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/X64/IntHandler.nasm +++ b/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/X64/IntHandler.nasm @@ -1,3 +1,5 @@ +#ifndef DISABLE_NEW_DEPRECATED_INTERFACES + ;------------------------------------------------------------------------------ ; ; Copyright (c) 2016, Intel Corporation. All rights reserved.
@@ -21,3 +23,5 @@ ASM_PFX(AsmInterruptHandle): cli mov al, 1 iretq + +#endif // DISABLE_NEW_DEPRECATED_INTERFACES diff --git a/SourceLevelDebugPkg/Library/UefiImageExtraActionLibDebug/Ia32/IntHandler.nasm b/SourceLevelDebugPkg/Library/UefiImageExtraActionLibDebug/Ia32/IntHandler.nasm new file mode 100644 index 0000000000..9442d3adc5 --- /dev/null +++ b/SourceLevelDebugPkg/Library/UefiImageExtraActionLibDebug/Ia32/IntHandler.nasm @@ -0,0 +1,22 @@ +;------------------------------------------------------------------------------ +; +; Copyright (c) 2016, Intel Corporation. All rights reserved.
+; SPDX-License-Identifier: BSD-2-Clause-Patent +; +; Module Name: +; +; IntHandler.nasm +; +; Abstract: +; +; Assembly interrupt handler function. +; +;------------------------------------------------------------------------------ + +global ASM_PFX(AsmInterruptHandle) + +SECTION .text +ASM_PFX(AsmInterruptHandle): + cli + mov al, 1 + iretd diff --git a/SourceLevelDebugPkg/Library/UefiImageExtraActionLibDebug/Ia32/IntHandlerFuncs.c b/SourceLevelDebugPkg/Library/UefiImageExtraActionLibDebug/Ia32/IntHandlerFuncs.c new file mode 100644 index 0000000000..9e2934fda5 --- /dev/null +++ b/SourceLevelDebugPkg/Library/UefiImageExtraActionLibDebug/Ia32/IntHandlerFuncs.c @@ -0,0 +1,93 @@ +/** @file + Ia32 arch functions to access IDT vector. + + Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include + +/** + Read IDT entry to check if IDT entries are setup by Debug Agent. + + @param[in] IdtDescriptor Pointer to IDT Descriptor. + @param[in] InterruptType Interrupt type. + + @retval TRUE IDT entries were setup by Debug Agent. + @retval FALSE IDT entries were not setuo by Debug Agent. + +**/ +BOOLEAN +CheckDebugAgentHandler ( + IN IA32_DESCRIPTOR *IdtDescriptor, + IN UINTN InterruptType + ) +{ + IA32_IDT_GATE_DESCRIPTOR *IdtEntry; + UINTN InterruptHandler; + + IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *)IdtDescriptor->Base; + if (IdtEntry == NULL) { + return FALSE; + } + + InterruptHandler = IdtEntry[InterruptType].Bits.OffsetLow + + (IdtEntry[InterruptType].Bits.OffsetHigh << 16); + if ((InterruptHandler >= sizeof (UINT32)) && (*(UINT32 *)(InterruptHandler - sizeof (UINT32)) == AGENT_HANDLER_SIGNATURE)) { + return TRUE; + } else { + return FALSE; + } +} + +/** + Save IDT entry for INT1 and update it. + + @param[in] IdtDescriptor Pointer to IDT Descriptor. + @param[out] SavedIdtEntry Original IDT entry returned. + +**/ +VOID +SaveAndUpdateIdtEntry1 ( + IN IA32_DESCRIPTOR *IdtDescriptor, + OUT IA32_IDT_GATE_DESCRIPTOR *SavedIdtEntry + ) +{ + IA32_IDT_GATE_DESCRIPTOR *IdtEntry; + UINT16 CodeSegment; + UINTN InterruptHandler; + + IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *)IdtDescriptor->Base; + CopyMem (SavedIdtEntry, &IdtEntry[1], sizeof (IA32_IDT_GATE_DESCRIPTOR)); + + // + // Use current CS as the segment selector of interrupt gate in IDT + // + CodeSegment = AsmReadCs (); + + InterruptHandler = (UINTN)&AsmInterruptHandle; + IdtEntry[1].Bits.OffsetLow = (UINT16)(UINTN)InterruptHandler; + IdtEntry[1].Bits.OffsetHigh = (UINT16)((UINTN)InterruptHandler >> 16); + IdtEntry[1].Bits.Selector = CodeSegment; + IdtEntry[1].Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32; +} + +/** + Restore IDT entry for INT1. + + @param[in] IdtDescriptor Pointer to IDT Descriptor. + @param[in] RestoredIdtEntry IDT entry to be restored. + +**/ +VOID +RestoreIdtEntry1 ( + IN IA32_DESCRIPTOR *IdtDescriptor, + IN IA32_IDT_GATE_DESCRIPTOR *RestoredIdtEntry + ) +{ + IA32_IDT_GATE_DESCRIPTOR *IdtEntry; + + IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *)IdtDescriptor->Base; + CopyMem (&IdtEntry[1], RestoredIdtEntry, sizeof (IA32_IDT_GATE_DESCRIPTOR)); +} diff --git a/SourceLevelDebugPkg/Library/UefiImageExtraActionLibDebug/UefiImageExtraActionLib.c b/SourceLevelDebugPkg/Library/UefiImageExtraActionLibDebug/UefiImageExtraActionLib.c new file mode 100644 index 0000000000..35f7db1258 --- /dev/null +++ b/SourceLevelDebugPkg/Library/UefiImageExtraActionLibDebug/UefiImageExtraActionLib.c @@ -0,0 +1,241 @@ +/** @file + PE/Coff Extra Action library instances. + + Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "Library/UefiImageLib.h" +#include "ProcessorBind.h" +#include "Uefi/UefiBaseType.h" +#include + +/** + Check if the hardware breakpoint in Drx is enabled by checking the Lx and Gx bit in Dr7. + + It assumes that DebugAgent will set both Lx and Gx bit when setting up the hardware breakpoint. + + + @param RegisterIndex Index of Dr register. The value range is from 0 to 3. + @param Dr7 Value of Dr7 register. + + @return TRUE The hardware breakpoint specified in the Drx is enabled. + @return FALSE The hardware breakpoint specified in the Drx is disabled. + +**/ +BOOLEAN +IsDrxEnabled ( + IN UINT8 RegisterIndex, + IN UINTN Dr7 + ) +{ + return (BOOLEAN)(((Dr7 >> (RegisterIndex * 2)) & (BIT0 | BIT1)) == (BIT0 | BIT1)); +} + +/** + Common routine to report the PE/COFF image loading/relocating or unloading event. + + If ImageContext is NULL, then ASSERT(). + + @param ImageContext Pointer to the image context structure that describes the + PE/COFF image. + @param Signature IMAGE_LOAD_SIGNATURE or IMAGE_UNLOAD_SIGNATURE. + +**/ +VOID +UefiImageLoaderExtraActionCommon ( + IN CONST UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext, + IN UINTN Signature + ) +{ + BOOLEAN InterruptState; + UINTN Dr0; + UINTN Dr1; + UINTN Dr2; + UINTN Dr3; + UINTN Dr7; + UINTN Cr4; + UINTN NewDr7; + UINT8 LoadImageMethod; + UINT8 DebugAgentStatus; + IA32_DESCRIPTOR IdtDescriptor; + IA32_IDT_GATE_DESCRIPTOR OriginalIdtEntry; + BOOLEAN IdtEntryHooked; + UINT32 RegEdx; + RETURN_STATUS Status; + CONST CHAR8 *PdbPath; + UINT32 PdbPathSize; + EFI_PHYSICAL_ADDRESS ImageBase; + + ASSERT (ImageContext != NULL); + + Status = UefiImageGetSymbolsPath (ImageContext, &PdbPath, &PdbPathSize); + if (!RETURN_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, " PDB = %a\n", PdbPath)); + } + + // + // Disable interrupts and save the current interrupt state + // + InterruptState = SaveAndDisableInterrupts (); + + IdtEntryHooked = FALSE; + LoadImageMethod = PcdGet8 (PcdDebugLoadImageMethod); + if (LoadImageMethod == DEBUG_LOAD_IMAGE_METHOD_IO_HW_BREAKPOINT) { + // + // If the CPU does not support Debug Extensions(CPUID:01 EDX:BIT2) + // then force use of DEBUG_LOAD_IMAGE_METHOD_SOFT_INT3 + // + AsmCpuid (1, NULL, NULL, NULL, &RegEdx); + if ((RegEdx & BIT2) == 0) { + LoadImageMethod = DEBUG_LOAD_IMAGE_METHOD_SOFT_INT3; + } + } + + AsmReadIdtr (&IdtDescriptor); + if (LoadImageMethod == DEBUG_LOAD_IMAGE_METHOD_SOFT_INT3) { + if (!CheckDebugAgentHandler (&IdtDescriptor, SOFT_INT_VECTOR_NUM)) { + // + // Do not trigger INT3 if Debug Agent did not setup IDT entries. + // + return; + } + } else { + if (!CheckDebugAgentHandler (&IdtDescriptor, IO_HW_BREAKPOINT_VECTOR_NUM)) { + // + // Save and update IDT entry for INT1 + // + SaveAndUpdateIdtEntry1 (&IdtDescriptor, &OriginalIdtEntry); + IdtEntryHooked = TRUE; + } + } + + ImageBase = UefiImageLoaderGetImageAddress (ImageContext); + + // + // Save Debug Register State + // + Dr0 = AsmReadDr0 (); + Dr1 = AsmReadDr1 (); + Dr2 = AsmReadDr2 (); + Dr3 = AsmReadDr3 (); + Dr7 = AsmReadDr7 () | BIT10; // H/w sets bit 10, some simulators don't + Cr4 = AsmReadCr4 (); + + // + // DR0 = Signature + // DR1 = The address of the Null-terminated ASCII string for the PE/COFF image's PDB file name + // DR2 = The pointer to the ImageBase address + // DR3 = IO_PORT_BREAKPOINT_ADDRESS + // DR7 = Disables all HW breakpoints except for DR3 I/O port access of length 1 byte + // CR4 = Make sure DE(BIT3) is set + // + AsmWriteDr7 (BIT10); + AsmWriteDr0 (Signature); + AsmWriteDr1 ((UINTN)PdbPath); + AsmWriteDr2 ((UINTN)&ImageBase); + AsmWriteDr3 (IO_PORT_BREAKPOINT_ADDRESS); + + if (LoadImageMethod == DEBUG_LOAD_IMAGE_METHOD_IO_HW_BREAKPOINT) { + AsmWriteDr7 (0x20000480); + AsmWriteCr4 (Cr4 | BIT3); + // + // Do an IN from IO_PORT_BREAKPOINT_ADDRESS to generate a HW breakpoint until the port + // returns a read value other than DEBUG_AGENT_IMAGE_WAIT + // + do { + DebugAgentStatus = IoRead8 (IO_PORT_BREAKPOINT_ADDRESS); + } while (DebugAgentStatus == DEBUG_AGENT_IMAGE_WAIT); + } else if (LoadImageMethod == DEBUG_LOAD_IMAGE_METHOD_SOFT_INT3) { + // + // Generate a software break point. + // + CpuBreakpoint (); + } + + // + // Restore Debug Register State only when Host didn't change it inside exception handler. + // E.g.: User halts the target and sets the HW breakpoint while target is + // in the above exception handler + // + NewDr7 = AsmReadDr7 () | BIT10; // H/w sets bit 10, some simulators don't + if (!IsDrxEnabled (0, NewDr7) && ((AsmReadDr0 () == 0) || (AsmReadDr0 () == Signature))) { + // + // If user changed Dr3 (by setting HW bp in the above exception handler, + // we will not set Dr0 to 0 in GO/STEP handler because the break cause is not IMAGE_LOAD/_UNLOAD. + // + AsmWriteDr0 (Dr0); + } + + if (!IsDrxEnabled (1, NewDr7) && (AsmReadDr1 () == (UINTN)PdbPath)) { + AsmWriteDr1 (Dr1); + } + + if (!IsDrxEnabled (2, NewDr7) && (AsmReadDr2 () == (UINTN)&ImageBase)) { + AsmWriteDr2 (Dr2); + } + + if (!IsDrxEnabled (3, NewDr7) && (AsmReadDr3 () == IO_PORT_BREAKPOINT_ADDRESS)) { + AsmWriteDr3 (Dr3); + } + + if (LoadImageMethod == DEBUG_LOAD_IMAGE_METHOD_IO_HW_BREAKPOINT) { + if (AsmReadCr4 () == (Cr4 | BIT3)) { + AsmWriteCr4 (Cr4); + } + + if (NewDr7 == 0x20000480) { + AsmWriteDr7 (Dr7); + } + } else if (LoadImageMethod == DEBUG_LOAD_IMAGE_METHOD_SOFT_INT3) { + if (NewDr7 == BIT10) { + AsmWriteDr7 (Dr7); + } + } + + // + // Restore original IDT entry for INT1 if it was hooked. + // + if (IdtEntryHooked) { + RestoreIdtEntry1 (&IdtDescriptor, &OriginalIdtEntry); + } + + // + // Restore the interrupt state + // + SetInterruptState (InterruptState); +} + +/** + Performs additional actions after a PE/COFF image has been loaded and relocated. + + @param ImageContext Pointer to the image context structure that describes the + PE/COFF image that has already been loaded and relocated. + +**/ +VOID +EFIAPI +UefiImageLoaderRelocateImageExtraAction ( + IN CONST UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext + ) +{ + UefiImageLoaderExtraActionCommon (ImageContext, IMAGE_LOAD_SIGNATURE); +} + +/** + Performs additional actions just before a PE/COFF image is unloaded. Any resources + that were allocated by UefiImageLoaderRelocateImageExtraAction() must be freed. + + @param ImageContext Pointer to the image context structure that describes the + PE/COFF image that is being unloaded. + +**/ +VOID +EFIAPI +UefiImageLoaderUnloadImageExtraAction ( + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext + ) +{ + UefiImageLoaderExtraActionCommon (ImageContext, IMAGE_UNLOAD_SIGNATURE); +} diff --git a/SourceLevelDebugPkg/Library/UefiImageExtraActionLibDebug/UefiImageExtraActionLib.h b/SourceLevelDebugPkg/Library/UefiImageExtraActionLibDebug/UefiImageExtraActionLib.h new file mode 100644 index 0000000000..594ad394aa --- /dev/null +++ b/SourceLevelDebugPkg/Library/UefiImageExtraActionLibDebug/UefiImageExtraActionLib.h @@ -0,0 +1,72 @@ +/** @file + PE/Coff Extra Action library instances, it will report image debug info. + + Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _UEFI_IMAGE_EXTRA_ACTION_LIB_H_ +#define _UEFI_IMAGE_EXTRA_ACTION_LIB_H_ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#define DEBUG_LOAD_IMAGE_METHOD_IO_HW_BREAKPOINT 1 +#define DEBUG_LOAD_IMAGE_METHOD_SOFT_INT3 2 + +#define IO_HW_BREAKPOINT_VECTOR_NUM 1 +#define SOFT_INT_VECTOR_NUM 3 + +extern UINTN AsmInterruptHandle; + +/** + Read IDT entry to check if IDT entries are setup by Debug Agent. + + @param[in] IdtDescriptor Pointer to IDT Descriptor. + @param[in] InterruptType Interrupt type. + + @retval TRUE IDT entries were setup by Debug Agent. + @retval FALSE IDT entries were not setuo by Debug Agent. + +**/ +BOOLEAN +CheckDebugAgentHandler ( + IN IA32_DESCRIPTOR *IdtDescriptor, + IN UINTN InterruptType + ); + +/** + Save IDT entry for INT1 and update it. + + @param[in] IdtDescriptor Pointer to IDT Descriptor. + @param[out] SavedIdtEntry Original IDT entry returned. + +**/ +VOID +SaveAndUpdateIdtEntry1 ( + IN IA32_DESCRIPTOR *IdtDescriptor, + OUT IA32_IDT_GATE_DESCRIPTOR *SavedIdtEntry + ); + +/** + Restore IDT entry for INT1. + + @param[in] IdtDescriptor Pointer to IDT Descriptor. + @param[in] RestoredIdtEntry IDT entry to be restored. + +**/ +VOID +RestoreIdtEntry1 ( + IN IA32_DESCRIPTOR *IdtDescriptor, + IN IA32_IDT_GATE_DESCRIPTOR *RestoredIdtEntry + ); + +#endif diff --git a/SourceLevelDebugPkg/Library/UefiImageExtraActionLibDebug/UefiImageExtraActionLib.uni b/SourceLevelDebugPkg/Library/UefiImageExtraActionLibDebug/UefiImageExtraActionLib.uni new file mode 100644 index 0000000000..f2ba4aa32d --- /dev/null +++ b/SourceLevelDebugPkg/Library/UefiImageExtraActionLibDebug/UefiImageExtraActionLib.uni @@ -0,0 +1,15 @@ +// /** @file +// UefiImageExtraAction Library to support source level debug. +// +// UefiImageExtraAction Library to support source level debug. +// +// Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.
+// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + + +#string STR_MODULE_ABSTRACT #language en-US "UefiImageExtraAction Library to support source level debug" + +#string STR_MODULE_DESCRIPTION #language en-US "UefiImageExtraAction Library to support source level debug." diff --git a/SourceLevelDebugPkg/Library/UefiImageExtraActionLibDebug/UefiImageExtraActionLibDebug.inf b/SourceLevelDebugPkg/Library/UefiImageExtraActionLibDebug/UefiImageExtraActionLibDebug.inf new file mode 100644 index 0000000000..82a3dc7971 --- /dev/null +++ b/SourceLevelDebugPkg/Library/UefiImageExtraActionLibDebug/UefiImageExtraActionLibDebug.inf @@ -0,0 +1,50 @@ +## @file +# UefiImageExtraAction Library to support source level debug. +# +# Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = UefiImageExtraActionLib + MODULE_UNI_FILE = UefiImageExtraActionLib.uni + FILE_GUID = 8F01CBD5-E069-44d7-90C9-35F0318603AD + MODULE_TYPE = BASE + VERSION_STRING = 0.8 + LIBRARY_CLASS = UefiImageExtraActionLib + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources.common] + UefiImageExtraActionLib.h + UefiImageExtraActionLib.c + +[Sources.IA32] + Ia32/IntHandlerFuncs.c + Ia32/IntHandler.nasm + +[Sources.X64] + X64/IntHandlerFuncs.c + X64/IntHandler.nasm + +[Packages] + MdePkg/MdePkg.dec + SourceLevelDebugPkg/SourceLevelDebugPkg.dec + +[LibraryClasses] + BaseLib + DebugLib + IoLib + PcdLib + +[Pcd] + gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdDebugLoadImageMethod ## CONSUMES + diff --git a/SourceLevelDebugPkg/Library/UefiImageExtraActionLibDebug/X64/IntHandler.nasm b/SourceLevelDebugPkg/Library/UefiImageExtraActionLibDebug/X64/IntHandler.nasm new file mode 100644 index 0000000000..6b3a7a526f --- /dev/null +++ b/SourceLevelDebugPkg/Library/UefiImageExtraActionLibDebug/X64/IntHandler.nasm @@ -0,0 +1,23 @@ +;------------------------------------------------------------------------------ +; +; Copyright (c) 2016, Intel Corporation. All rights reserved.
+; SPDX-License-Identifier: BSD-2-Clause-Patent +; +; Module Name: +; +; IntHandler.nasm +; +; Abstract: +; +; Assembly interrupt handler function. +; +;------------------------------------------------------------------------------ + +global ASM_PFX(AsmInterruptHandle) + +DEFAULT REL +SECTION .text +ASM_PFX(AsmInterruptHandle): + cli + mov al, 1 + iretq diff --git a/SourceLevelDebugPkg/Library/UefiImageExtraActionLibDebug/X64/IntHandlerFuncs.c b/SourceLevelDebugPkg/Library/UefiImageExtraActionLibDebug/X64/IntHandlerFuncs.c new file mode 100644 index 0000000000..a518892d2c --- /dev/null +++ b/SourceLevelDebugPkg/Library/UefiImageExtraActionLibDebug/X64/IntHandlerFuncs.c @@ -0,0 +1,95 @@ +/** @file + X64 arch function to access IDT vector. + + Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include + +/** + Read IDT entry to check if IDT entries are setup by Debug Agent. + + @param[in] IdtDescriptor Pointer to IDT Descriptor. + @param[in] InterruptType Interrupt type. + + @retval TRUE IDT entries were setup by Debug Agent. + @retval FALSE IDT entries were not setuo by Debug Agent. + +**/ +BOOLEAN +CheckDebugAgentHandler ( + IN IA32_DESCRIPTOR *IdtDescriptor, + IN UINTN InterruptType + ) +{ + IA32_IDT_GATE_DESCRIPTOR *IdtEntry; + UINTN InterruptHandler; + + IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *)IdtDescriptor->Base; + if (IdtEntry == NULL) { + return FALSE; + } + + InterruptHandler = IdtEntry[InterruptType].Bits.OffsetLow + + (((UINTN)IdtEntry[InterruptType].Bits.OffsetHigh) << 16) + + (((UINTN)IdtEntry[InterruptType].Bits.OffsetUpper) << 32); + if ((InterruptHandler >= sizeof (UINT32)) && (*(UINT32 *)(InterruptHandler - sizeof (UINT32)) == AGENT_HANDLER_SIGNATURE)) { + return TRUE; + } else { + return FALSE; + } +} + +/** + Save IDT entry for INT1 and update it. + + @param[in] IdtDescriptor Pointer to IDT Descriptor. + @param[out] SavedIdtEntry Original IDT entry returned. + +**/ +VOID +SaveAndUpdateIdtEntry1 ( + IN IA32_DESCRIPTOR *IdtDescriptor, + OUT IA32_IDT_GATE_DESCRIPTOR *SavedIdtEntry + ) +{ + IA32_IDT_GATE_DESCRIPTOR *IdtEntry; + UINT16 CodeSegment; + UINTN InterruptHandler; + + IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *)IdtDescriptor->Base; + CopyMem (SavedIdtEntry, &IdtEntry[1], sizeof (IA32_IDT_GATE_DESCRIPTOR)); + + // + // Use current CS as the segment selector of interrupt gate in IDT + // + CodeSegment = AsmReadCs (); + + InterruptHandler = (UINTN)&AsmInterruptHandle; + IdtEntry[1].Bits.OffsetLow = (UINT16)(UINTN)InterruptHandler; + IdtEntry[1].Bits.OffsetHigh = (UINT16)((UINTN)InterruptHandler >> 16); + IdtEntry[1].Bits.OffsetUpper = (UINT32)((UINTN)InterruptHandler >> 32); + IdtEntry[1].Bits.Selector = CodeSegment; + IdtEntry[1].Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32; +} + +/** + Restore IDT entry for INT1. + + @param[in] IdtDescriptor Pointer to IDT Descriptor. + @param[in] RestoredIdtEntry IDT entry to be restored. + +**/ +VOID +RestoreIdtEntry1 ( + IN IA32_DESCRIPTOR *IdtDescriptor, + IN IA32_IDT_GATE_DESCRIPTOR *RestoredIdtEntry + ) +{ + IA32_IDT_GATE_DESCRIPTOR *IdtEntry; + + IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *)IdtDescriptor->Base; + CopyMem (&IdtEntry[1], RestoredIdtEntry, sizeof (IA32_IDT_GATE_DESCRIPTOR)); +} diff --git a/SourceLevelDebugPkg/SourceLevelDebugPkg.dec b/SourceLevelDebugPkg/SourceLevelDebugPkg.dec index 564aca6e7c..a743a69bfe 100644 --- a/SourceLevelDebugPkg/SourceLevelDebugPkg.dec +++ b/SourceLevelDebugPkg/SourceLevelDebugPkg.dec @@ -3,7 +3,7 @@ # The target side components includes the Debug Agent Library instance # to communicate with host side modules, Debug Communication Library and # instances to provide the communication I/O functions between Debug Agent -# and host, PeCoffExtraActionLib instance to report symbol path information, +# and host, UefiImageExtraActionLib instance to report symbol path information, # etc. # # Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.
diff --git a/SourceLevelDebugPkg/SourceLevelDebugPkg.dsc b/SourceLevelDebugPkg/SourceLevelDebugPkg.dsc index 986dd5a769..744b9527b4 100644 --- a/SourceLevelDebugPkg/SourceLevelDebugPkg.dsc +++ b/SourceLevelDebugPkg/SourceLevelDebugPkg.dsc @@ -35,9 +35,9 @@ IoLib|MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf SynchronizationLib|MdePkg/Library/BaseSynchronizationLib/BaseSynchronizationLib.inf LocalApicLib|UefiCpuPkg/Library/BaseXApicLib/BaseXApicLib.inf - PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf + UefiCpuLib|UefiCpuPkg/Library/BaseUefiCpuLib/BaseUefiCpuLib.inf SerialPortLib|MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.inf - PeCoffExtraActionLib|SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLibDebug.inf + UefiImageExtraActionLib|SourceLevelDebugPkg/Library/UefiImageExtraActionLibDebug/UefiImageExtraActionLibDebug.inf TimerLib|UefiCpuPkg/Library/SecPeiDxeTimerLibUefiCpu/SecPeiDxeTimerLibUefiCpu.inf ResetSystemLib|MdeModulePkg/Library/BaseResetSystemLibNull/BaseResetSystemLibNull.inf PciLib|MdePkg/Library/BasePciLibCf8/BasePciLibCf8.inf @@ -100,7 +100,7 @@ SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Pei.inf SourceLevelDebugPkg/Library/DebugCommunicationLibSerialPort/DebugCommunicationLibSerialPort.inf SourceLevelDebugPkg/Library/DebugCommunicationLibUsb/DebugCommunicationLibUsb.inf - SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLibDebug.inf + SourceLevelDebugPkg/Library/UefiImageExtraActionLibDebug/UefiImageExtraActionLibDebug.inf SourceLevelDebugPkg/Library/DebugAgent/SecPeiDebugAgentLib.inf SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgentLib.inf SourceLevelDebugPkg/Library/DebugAgent/SmmDebugAgentLib.inf diff --git a/SourceLevelDebugPkg/SourceLevelDebugPkg.uni b/SourceLevelDebugPkg/SourceLevelDebugPkg.uni index 8d2f06eb4e..2613c5fd2e 100644 --- a/SourceLevelDebugPkg/SourceLevelDebugPkg.uni +++ b/SourceLevelDebugPkg/SourceLevelDebugPkg.uni @@ -5,7 +5,7 @@ // The target side components includes the Debug Agent Library instance // to communicate with host side modules, Debug Communication Library and // instances to provide the communication I/O functions between Debug Agent -// and host, PeCoffExtraActionLib instance to report symbol path information, +// and host, UefiImageExtraActionLib instance to report symbol path information, // etc. // // Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.
@@ -20,7 +20,7 @@ #string STR_PACKAGE_DESCRIPTION #language en-US "The target side components includes the Debug Agent Library instance\n" "to communicate with host side modules, Debug Communication Library and\n" "instances to provide the communication I/O functions between Debug Agent\n" - "and host, PeCoffExtraActionLib instance to report symbol path information,\n" + "and host, UefiImageExtraActionLib instance to report symbol path information,\n" "etc." diff --git a/StandaloneMmPkg/Core/Dispatcher.c b/StandaloneMmPkg/Core/Dispatcher.c index 01a2b3af0d..8174e2b71e 100644 --- a/StandaloneMmPkg/Core/Dispatcher.c +++ b/StandaloneMmPkg/Core/Dispatcher.c @@ -36,6 +36,7 @@ **/ +#include "ProcessorBind.h" #include "StandaloneMmCore.h" // @@ -97,6 +98,76 @@ BOOLEAN gDispatcherRunning = FALSE; // BOOLEAN gRequestDispatch = FALSE; +STATIC +RETURN_STATUS +InternalProtectMmImage ( + IN OUT UEFI_IMAGE_LOADER_IMAGE_CONTEXT *ImageContext + ) +{ + UEFI_IMAGE_RECORD *ImageRecord; + UINTN SectionAddress; + UINT32 SectionIndex; + + if (UefiImageGetSegmentAlignment (ImageContext) < EFI_PAGE_SIZE) { + // FIXME: PCD to abort loading? + // + // The sections need to be at least 4 KB aligned, since that is the + // granularity at which we can tighten permissions. So just clear the + // noexec permissions on the entire region. + // + DEBUG ((DEBUG_WARN, + "%a: Image at 0x%lx has SectionAlignment < 4 KB (%lu)\n", + __FUNCTION__, UefiImageLoaderGetImageAddress (ImageContext), UefiImageGetSegmentAlignment (ImageContext))); + + ASSERT ((UefiImageLoaderGetImageAddress (ImageContext) & (EFI_PAGE_SIZE - 1)) == 0); + + ClearMemoryRegionNoExec ( + UefiImageLoaderGetImageAddress (ImageContext), + ALIGN_VALUE (UefiImageGetImageSize (ImageContext), EFI_PAGE_SIZE) + ); + + return RETURN_SUCCESS; + } + + ImageRecord = UefiImageLoaderGetImageRecord (ImageContext); + if (ImageRecord == NULL) { + return RETURN_OUT_OF_RESOURCES; + } + // + // Images are loaded into RW memory, thus only +X and -W need to be handled. + // + SectionAddress = ImageRecord->StartAddress; + for (SectionIndex = 0; SectionIndex < ImageRecord->NumSegments; ++ SectionIndex) { + DEBUG ((DEBUG_INFO, + "%a: Mapping segment of image at 0x%lx with %s-%s permissions and size 0x%x\n", + __FUNCTION__, SectionAddress, + (ImageRecord->Segments[SectionIndex].Attributes & EFI_MEMORY_RO) != 0 ? "RO" : "RW", + (ImageRecord->Segments[SectionIndex].Attributes & EFI_MEMORY_XP) != 0 ? "XN" : "X", + ImageRecord->Segments[SectionIndex].Size)); + + // FIXME: What about their return values? + if ((ImageRecord->Segments[SectionIndex].Attributes & EFI_MEMORY_RO) != 0) { + SetMemoryRegionReadOnly ( + SectionAddress, + ImageRecord->Segments[SectionIndex].Size + ); + } + + if ((ImageRecord->Segments[SectionIndex].Attributes & EFI_MEMORY_XP) == 0) { + ClearMemoryRegionNoExec ( + SectionAddress, + ImageRecord->Segments[SectionIndex].Size + ); + } + + SectionAddress += ImageRecord->Segments[SectionIndex].Size; + } + + FreePool (ImageRecord); + + return RETURN_SUCCESS; +} + /** Loads an EFI image into SMRAM. @@ -111,79 +182,51 @@ MmLoadImage ( IN OUT EFI_MM_DRIVER_ENTRY *DriverEntry ) { - UINTN PageCount; - EFI_STATUS Status; - EFI_PHYSICAL_ADDRESS DstBuffer; - PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; + UINT32 ImageSize; + UINT32 ImageAlignment; + EFI_STATUS Status; + VOID *DstBuffer; + UINT32 DstBufferPages; + UINT32 DstBufferSize; + UEFI_IMAGE_LOADER_IMAGE_CONTEXT ImageContext; DEBUG ((DEBUG_INFO, "MmLoadImage - %g\n", &DriverEntry->FileName)); Status = EFI_SUCCESS; - // - // Initialize ImageContext - // - ImageContext.Handle = DriverEntry->Pe32Data; - ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory; - // // Get information about the image being loaded // - Status = PeCoffLoaderGetImageInfo (&ImageContext); + Status = UefiImageInitializeContext (&ImageContext, DriverEntry->Pe32Data, DriverEntry->Pe32DataSize); if (EFI_ERROR (Status)) { return Status; } - PageCount = (UINTN)EFI_SIZE_TO_PAGES ((UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment); - DstBuffer = (UINTN)(-1); + ImageSize = UefiImageGetImageSize (&ImageContext); + DstBufferPages = EFI_SIZE_TO_PAGES (ImageSize); + DstBufferSize = EFI_PAGES_TO_SIZE (DstBufferPages); + ImageAlignment = UefiImageGetSegmentAlignment (&ImageContext); - Status = MmAllocatePages ( - AllocateMaxAddress, - EfiRuntimeServicesCode, - PageCount, - &DstBuffer - ); - if (EFI_ERROR (Status)) { - return Status; + DstBuffer = AllocateAlignedCodePages (DstBufferPages, ImageAlignment); + if (DstBuffer == NULL) { + return EFI_OUT_OF_RESOURCES; } - ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)DstBuffer; - - // - // Align buffer on section boundary - // - ImageContext.ImageAddress += ImageContext.SectionAlignment - 1; - ImageContext.ImageAddress &= ~((EFI_PHYSICAL_ADDRESS)(ImageContext.SectionAlignment - 1)); - // // Load the image to our new buffer // - Status = PeCoffLoaderLoadImage (&ImageContext); - if (EFI_ERROR (Status)) { - MmFreePages (DstBuffer, PageCount); - return Status; - } - - // - // Relocate the image in our new buffer - // - Status = PeCoffLoaderRelocateImage (&ImageContext); + Status = UefiImageLoadImageForExecution (&ImageContext, DstBuffer, DstBufferSize, NULL, 0); if (EFI_ERROR (Status)) { - MmFreePages (DstBuffer, PageCount); + FreeAlignedPages (DstBuffer, DstBufferPages); return Status; } - // - // Flush the instruction cache so the image data are written before we execute it - // - InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize); - // // Save Image EntryPoint in DriverEntry // - DriverEntry->ImageEntryPoint = ImageContext.EntryPoint; - DriverEntry->ImageBuffer = DstBuffer; - DriverEntry->NumberOfPage = PageCount; + DriverEntry->ImageEntryPoint = UefiImageLoaderGetImageEntryPoint (&ImageContext); + DriverEntry->ImageBuffer = (UINTN)DstBuffer; + DriverEntry->NumberOfPage = DstBufferPages; if (mEfiSystemTable != NULL) { Status = mEfiSystemTable->BootServices->AllocatePool ( @@ -192,7 +235,7 @@ MmLoadImage ( (VOID **)&DriverEntry->LoadedImage ); if (EFI_ERROR (Status)) { - MmFreePages (DstBuffer, PageCount); + FreeAlignedPages (DstBuffer, DstBufferPages); return Status; } @@ -207,8 +250,8 @@ MmLoadImage ( DriverEntry->LoadedImage->DeviceHandle = NULL; DriverEntry->LoadedImage->FilePath = NULL; - DriverEntry->LoadedImage->ImageBase = (VOID *)(UINTN)DriverEntry->ImageBuffer; - DriverEntry->LoadedImage->ImageSize = ImageContext.ImageSize; + DriverEntry->LoadedImage->ImageBase = DstBuffer; + DriverEntry->LoadedImage->ImageSize = ImageSize; DriverEntry->LoadedImage->ImageCodeType = EfiRuntimeServicesCode; DriverEntry->LoadedImage->ImageDataType = EfiRuntimeServicesData; @@ -224,58 +267,32 @@ MmLoadImage ( ); } + InternalProtectMmImage (&ImageContext); + // // Print the load address and the PDB file name if it is available // DEBUG_CODE_BEGIN (); - UINTN Index; - UINTN StartIndex; CHAR8 EfiFileName[256]; DEBUG (( DEBUG_INFO | DEBUG_LOAD, "Loading MM driver at 0x%11p EntryPoint=0x%11p ", - (VOID *)(UINTN)ImageContext.ImageAddress, - FUNCTION_ENTRY_POINT (ImageContext.EntryPoint) + DstBuffer, + FUNCTION_ENTRY_POINT (UefiImageLoaderGetImageEntryPoint (&ImageContext)) )); + Status = UefiImageGetModuleNameFromSymbolsPath ( + &ImageContext, + EfiFileName, + sizeof (EfiFileName) + ); + // // Print Module Name by Pdb file path. - // Windows and Unix style file path are all trimmed correctly. // - if (ImageContext.PdbPointer != NULL) { - StartIndex = 0; - for (Index = 0; ImageContext.PdbPointer[Index] != 0; Index++) { - if ((ImageContext.PdbPointer[Index] == '\\') || (ImageContext.PdbPointer[Index] == '/')) { - StartIndex = Index + 1; - } - } - - // - // Copy the PDB file name to our temporary string, and replace .pdb with .efi - // The PDB file name is limited in the range of 0~255. - // If the length is bigger than 255, trim the redundant characters to avoid overflow in array boundary. - // - for (Index = 0; Index < sizeof (EfiFileName) - 4; Index++) { - EfiFileName[Index] = ImageContext.PdbPointer[Index + StartIndex]; - if (EfiFileName[Index] == 0) { - EfiFileName[Index] = '.'; - } - - if (EfiFileName[Index] == '.') { - EfiFileName[Index + 1] = 'e'; - EfiFileName[Index + 2] = 'f'; - EfiFileName[Index + 3] = 'i'; - EfiFileName[Index + 4] = 0; - break; - } - } - - if (Index == sizeof (EfiFileName) - 4) { - EfiFileName[Index] = 0; - } - + if (!EFI_ERROR (Status)) { DEBUG ((DEBUG_INFO | DEBUG_LOAD, "%a", EfiFileName)); } @@ -676,7 +693,7 @@ EFI_STATUS MmAddToDriverList ( IN EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader, IN VOID *Pe32Data, - IN UINTN Pe32DataSize, + IN UINT32 Pe32DataSize, IN VOID *Depex, IN UINTN DepexSize, IN EFI_GUID *DriverName diff --git a/StandaloneMmPkg/Core/FwVol.c b/StandaloneMmPkg/Core/FwVol.c index 07500cee41..163be2d0ae 100644 --- a/StandaloneMmPkg/Core/FwVol.c +++ b/StandaloneMmPkg/Core/FwVol.c @@ -27,7 +27,7 @@ EFI_STATUS MmAddToDriverList ( IN EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader, IN VOID *Pe32Data, - IN UINTN Pe32DataSize, + IN UINT32 Pe32DataSize, IN VOID *Depex, IN UINTN DepexSize, IN EFI_GUID *DriverName @@ -74,13 +74,13 @@ MmCoreFfsFindMmDriver ( EFI_FFS_FILE_HEADER *FileHeader; EFI_FV_FILETYPE FileType; VOID *Pe32Data; - UINTN Pe32DataSize; + UINT32 Pe32DataSize; VOID *Depex; - UINTN DepexSize; + UINT32 DepexSize; UINTN Index; EFI_COMMON_SECTION_HEADER *Section; VOID *SectionData; - UINTN SectionDataSize; + UINT32 SectionDataSize; UINT32 DstBufferSize; VOID *ScratchBuffer; UINT32 ScratchBufferSize; diff --git a/StandaloneMmPkg/Core/StandaloneMmCore.h b/StandaloneMmPkg/Core/StandaloneMmCore.h index cfb417d7cc..b57b39621c 100644 --- a/StandaloneMmPkg/Core/StandaloneMmCore.h +++ b/StandaloneMmPkg/Core/StandaloneMmCore.h @@ -32,9 +32,10 @@ #include #include +#include #include #include -#include +#include #include #include #include @@ -70,7 +71,7 @@ typedef struct { EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; EFI_GUID FileName; VOID *Pe32Data; - UINTN Pe32DataSize; + UINT32 Pe32DataSize; VOID *Depex; UINTN DepexSize; diff --git a/StandaloneMmPkg/Core/StandaloneMmCore.inf b/StandaloneMmPkg/Core/StandaloneMmCore.inf index 02ecd68f37..b52534ea6c 100644 --- a/StandaloneMmPkg/Core/StandaloneMmCore.inf +++ b/StandaloneMmPkg/Core/StandaloneMmCore.inf @@ -49,8 +49,9 @@ HobLib MemoryAllocationLib MemLib - PeCoffLib + UefiImageLib ReportStatusCodeLib + StandaloneMmProtectionLib StandaloneMmCoreEntryPoint [Protocols] @@ -80,13 +81,10 @@ gStandaloneMmPkgTokenSpaceGuid.PcdFwVolMmMaxEncapsulationDepth ##CONSUMES # -# This configuration fails for CLANGPDB, which does not support PIE in the GCC -# sense. Such however is required for ARM family StandaloneMmCore -# self-relocation, and thus the CLANGPDB toolchain is unsupported for ARM and -# AARCH64 for this module. +# This configuration fails for CLANGDPB, which does not support PIE in the GCC +# sense. Such however is required for AArch64 StandaloneMmCore self-relocation, +# and thus the CLANGPDB toolchain is unsupported for AArch64 for this module. # [BuildOptions] - GCC:*_*_ARM_CC_FLAGS = -fpie - GCC:*_*_ARM_DLINK_FLAGS = -Wl,-z,text,-Bsymbolic,-pie GCC:*_*_AARCH64_CC_FLAGS = -fpie GCC:*_*_AARCH64_DLINK_FLAGS = -Wl,-z,text,-Bsymbolic,-pie diff --git a/StandaloneMmPkg/Include/Library/Arm/StandaloneMmCoreEntryPoint.h b/StandaloneMmPkg/Include/Library/Arm/StandaloneMmCoreEntryPoint.h index dbb81610ff..3141437337 100644 --- a/StandaloneMmPkg/Include/Library/Arm/StandaloneMmCoreEntryPoint.h +++ b/StandaloneMmPkg/Include/Library/Arm/StandaloneMmCoreEntryPoint.h @@ -11,7 +11,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #define __STANDALONEMMCORE_ENTRY_POINT_H__ #include -#include +#include #include #define CPU_INFO_FLAG_PRIMARY_CPU 0x00000001 @@ -53,56 +53,6 @@ typedef RETURN_STATUS (*REGION_PERMISSION_UPDATE_FUNC) ( IN UINT64 Length ); -/** - Privileged firmware assigns RO & Executable attributes to all memory occupied - by the Boot Firmware Volume. This function sets the correct permissions of - sections in the Standalone MM Core module to be able to access RO and RW data - and make further progress in the boot process. - - @param [in] ImageContext Pointer to PE/COFF image context - @param [in] ImageBase Base of image in memory - @param [in] SectionHeaderOffset Offset of PE/COFF image section header - @param [in] NumberOfSections Number of Sections - @param [in] TextUpdater Function to change code permissions - @param [in] ReadOnlyUpdater Function to change RO permissions - @param [in] ReadWriteUpdater Function to change RW permissions - -**/ -EFI_STATUS -EFIAPI -UpdateMmFoundationPeCoffPermissions ( - IN CONST PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext, - IN EFI_PHYSICAL_ADDRESS ImageBase, - IN UINT32 SectionHeaderOffset, - IN CONST UINT16 NumberOfSections, - IN REGION_PERMISSION_UPDATE_FUNC TextUpdater, - IN REGION_PERMISSION_UPDATE_FUNC ReadOnlyUpdater, - IN REGION_PERMISSION_UPDATE_FUNC ReadWriteUpdater - ); - -/** - Privileged firmware assigns RO & Executable attributes to all memory occupied - by the Boot Firmware Volume. This function locates the section information of - the Standalone MM Core module to be able to change permissions of the - individual sections later in the boot process. - - @param [in] TeData Pointer to PE/COFF image data - @param [in, out] ImageContext Pointer to PE/COFF image context - @param [out] ImageBase Pointer to ImageBase variable - @param [in, out] SectionHeaderOffset Offset of PE/COFF image section header - @param [in, out] NumberOfSections Number of Sections - -**/ -EFI_STATUS -EFIAPI -GetStandaloneMmCorePeCoffSections ( - IN VOID *TeData, - IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext, - OUT EFI_PHYSICAL_ADDRESS *ImageBase, - IN OUT UINT32 *SectionHeaderOffset, - IN OUT UINT16 *NumberOfSections - ); - /** Privileged firmware assigns RO & Executable attributes to all memory occupied by the Boot Firmware Volume. This function locates the Standalone MM Core @@ -116,10 +66,10 @@ GetStandaloneMmCorePeCoffSections ( **/ EFI_STATUS EFIAPI -LocateStandaloneMmCorePeCoffData ( +LocateStandaloneMmCoreUefiImage ( IN EFI_FIRMWARE_VOLUME_HEADER *BfvAddress, IN OUT VOID **TeData, - IN OUT UINTN *TeDataSize + IN OUT UINT32 *TeDataSize ); /** diff --git a/StandaloneMmPkg/Include/Library/FvLib.h b/StandaloneMmPkg/Include/Library/FvLib.h index 1eb9ea7e04..a993b70338 100644 --- a/StandaloneMmPkg/Include/Library/FvLib.h +++ b/StandaloneMmPkg/Include/Library/FvLib.h @@ -98,7 +98,7 @@ FfsFindSectionData ( IN EFI_SECTION_TYPE SectionType, IN EFI_FFS_FILE_HEADER *FfsFileHeader, OUT VOID **SectionData, - OUT UINTN *SectionDataSize + OUT UINT32 *SectionDataSize ); #endif diff --git a/StandaloneMmPkg/Include/Library/StandaloneMmProtectionLib.h b/StandaloneMmPkg/Include/Library/StandaloneMmProtectionLib.h new file mode 100644 index 0000000000..395aaff910 --- /dev/null +++ b/StandaloneMmPkg/Include/Library/StandaloneMmProtectionLib.h @@ -0,0 +1,30 @@ +// FIXME: docs + +#ifndef STANDALONE_MM_PROTECTION_LIB_H_ +#define STANDALONE_MM_PROTECTION_LIB_H_ + +EFI_STATUS +SetMemoryRegionNoExec ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ); + +EFI_STATUS +ClearMemoryRegionNoExec ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ); + +EFI_STATUS +SetMemoryRegionReadOnly ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ); + +EFI_STATUS +ClearMemoryRegionReadOnly ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ); + +#endif // STANDALONE_MM_PROTECTION_LIB_H_ diff --git a/StandaloneMmPkg/Library/FvLib/FvLib.c b/StandaloneMmPkg/Library/FvLib/FvLib.c index 89504b9ee9..5146dc39ef 100644 --- a/StandaloneMmPkg/Library/FvLib/FvLib.c +++ b/StandaloneMmPkg/Library/FvLib/FvLib.c @@ -353,7 +353,7 @@ FfsFindSectionData ( IN EFI_SECTION_TYPE SectionType, IN EFI_FFS_FILE_HEADER *FfsFileHeader, IN OUT VOID **SectionData, - IN OUT UINTN *SectionDataSize + IN OUT UINT32 *SectionDataSize ) { UINT32 FileSize; diff --git a/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/Arm/SetPermissions.c b/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/Arm/SetPermissions.c index 5c6bd0e1d7..70ba054e2f 100644 --- a/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/Arm/SetPermissions.c +++ b/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/Arm/SetPermissions.c @@ -24,162 +24,23 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #include -/** - Privileged firmware assigns RO & Executable attributes to all memory occupied - by the Boot Firmware Volume. This function sets the correct permissions of - sections in the Standalone MM Core module to be able to access RO and RW data - and make further progress in the boot process. - - @param [in] ImageContext Pointer to PE/COFF image context - @param [in] ImageBase Base of image in memory - @param [in] SectionHeaderOffset Offset of PE/COFF image section header - @param [in] NumberOfSections Number of Sections - @param [in] TextUpdater Function to change code permissions - @param [in] ReadOnlyUpdater Function to change RO permissions - @param [in] ReadWriteUpdater Function to change RW permissions - -**/ -EFI_STATUS -EFIAPI -UpdateMmFoundationPeCoffPermissions ( - IN CONST PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext, - IN EFI_PHYSICAL_ADDRESS ImageBase, - IN UINT32 SectionHeaderOffset, - IN CONST UINT16 NumberOfSections, - IN REGION_PERMISSION_UPDATE_FUNC TextUpdater, - IN REGION_PERMISSION_UPDATE_FUNC ReadOnlyUpdater, - IN REGION_PERMISSION_UPDATE_FUNC ReadWriteUpdater - ) -{ - EFI_IMAGE_SECTION_HEADER SectionHeader; - RETURN_STATUS Status; - EFI_PHYSICAL_ADDRESS Base; - UINTN Size; - UINTN ReadSize; - UINTN Index; - - ASSERT (ImageContext != NULL); - - // - // Iterate over the sections - // - for (Index = 0; Index < NumberOfSections; Index++) { - // - // Read section header from file - // - Size = sizeof (EFI_IMAGE_SECTION_HEADER); - ReadSize = Size; - Status = ImageContext->ImageRead ( - ImageContext->Handle, - SectionHeaderOffset, - &Size, - &SectionHeader - ); - - if (RETURN_ERROR (Status) || (Size != ReadSize)) { - DEBUG (( - DEBUG_ERROR, - "%a: ImageContext->ImageRead () failed (Status = %r)\n", - __func__, - Status - )); - return Status; - } - - DEBUG (( - DEBUG_INFO, - "%a: Section %d of image at 0x%lx has 0x%x permissions\n", - __func__, - Index, - ImageContext->ImageAddress, - SectionHeader.Characteristics - )); - DEBUG (( - DEBUG_INFO, - "%a: Section %d of image at 0x%lx has %a name\n", - __func__, - Index, - ImageContext->ImageAddress, - SectionHeader.Name - )); - DEBUG (( - DEBUG_INFO, - "%a: Section %d of image at 0x%lx has 0x%x address\n", - __func__, - Index, - ImageContext->ImageAddress, - ImageContext->ImageAddress + SectionHeader.VirtualAddress - )); - DEBUG (( - DEBUG_INFO, - "%a: Section %d of image at 0x%lx has 0x%x data\n", - __func__, - Index, - ImageContext->ImageAddress, - SectionHeader.PointerToRawData - )); - - // - // If the section is marked as XN then remove the X attribute. Furthermore, - // if it is a writeable section then mark it appropriately as well. - // - if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_MEM_EXECUTE) == 0) { - Base = ImageBase + SectionHeader.VirtualAddress; - - TextUpdater (Base, SectionHeader.Misc.VirtualSize); - - if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_MEM_WRITE) != 0) { - ReadWriteUpdater (Base, SectionHeader.Misc.VirtualSize); - DEBUG (( - DEBUG_INFO, - "%a: Mapping section %d of image at 0x%lx with RW-XN permissions\n", - __func__, - Index, - ImageContext->ImageAddress - )); - } else { - DEBUG (( - DEBUG_INFO, - "%a: Mapping section %d of image at 0x%lx with RO-XN permissions\n", - __func__, - Index, - ImageContext->ImageAddress - )); - } - } else { - DEBUG (( - DEBUG_INFO, - "%a: Ignoring section %d of image at 0x%lx with 0x%x permissions\n", - __func__, - Index, - ImageContext->ImageAddress, - SectionHeader.Characteristics - )); - } - - SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER); - } - - return RETURN_SUCCESS; -} - /** Privileged firmware assigns RO & Executable attributes to all memory occupied by the Boot Firmware Volume. This function locates the Standalone MM Core module PE/COFF image in the BFV and returns this information. - @param [in] BfvAddress Base Address of Boot Firmware Volume - @param [in, out] TeData Pointer to address for allocating memory - for PE/COFF image data - @param [in, out] TeDataSize Pointer to size of PE/COFF image data + @param [in] BfvAddress Base Address of Boot Firmware Volume + @param [in, out] UefiImage Pointer to address for allocating memory + for PE/COFF image data + @param [in, out] UefiImageSize Pointer to size of PE/COFF image data **/ EFI_STATUS EFIAPI -LocateStandaloneMmCorePeCoffData ( +LocateStandaloneMmCoreUefiImage ( IN EFI_FIRMWARE_VOLUME_HEADER *BfvAddress, - IN OUT VOID **TeData, - IN OUT UINTN *TeDataSize + IN OUT VOID **UefiImage, + IN OUT UINT32 *UefiImageSize ) { EFI_FFS_FILE_HEADER *FileHeader; @@ -201,9 +62,9 @@ LocateStandaloneMmCorePeCoffData ( return Status; } - Status = FfsFindSectionData (EFI_SECTION_PE32, FileHeader, TeData, TeDataSize); + Status = FfsFindSectionData (EFI_SECTION_PE32, FileHeader, UefiImage, UefiImageSize); if (EFI_ERROR (Status)) { - Status = FfsFindSectionData (EFI_SECTION_TE, FileHeader, TeData, TeDataSize); + Status = FfsFindSectionData (EFI_SECTION_TE, FileHeader, UefiImage, UefiImageSize); if (EFI_ERROR (Status)) { DEBUG (( DEBUG_ERROR, @@ -214,170 +75,6 @@ LocateStandaloneMmCorePeCoffData ( } } - DEBUG ((DEBUG_INFO, "Found Standalone MM PE data - 0x%x\n", *TeData)); - return Status; -} - -/** - Returns the PC COFF section information. - - @param [in, out] ImageContext Pointer to PE/COFF image context - @param [out] ImageBase Base of image in memory - @param [out] SectionHeaderOffset Offset of PE/COFF image section header - @param [out] NumberOfSections Number of Sections - -**/ -STATIC -EFI_STATUS -GetPeCoffSectionInformation ( - IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext, - OUT EFI_PHYSICAL_ADDRESS *ImageBase, - OUT UINT32 *SectionHeaderOffset, - OUT UINT16 *NumberOfSections - ) -{ - RETURN_STATUS Status; - EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr; - EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData; - UINTN Size; - UINTN ReadSize; - - ASSERT (ImageContext != NULL); - ASSERT (SectionHeaderOffset != NULL); - ASSERT (NumberOfSections != NULL); - - Status = PeCoffLoaderGetImageInfo (ImageContext); - if (RETURN_ERROR (Status)) { - DEBUG (( - DEBUG_ERROR, - "%a: PeCoffLoaderGetImageInfo () failed (Status == %r)\n", - __func__, - Status - )); - return Status; - } - - if (ImageContext->SectionAlignment < EFI_PAGE_SIZE) { - // - // The sections need to be at least 4 KB aligned, since that is the - // granularity at which we can tighten permissions. - // - if (!ImageContext->IsTeImage) { - DEBUG (( - DEBUG_WARN, - "%a: non-TE Image at 0x%lx has SectionAlignment < 4 KB (%lu)\n", - __func__, - ImageContext->ImageAddress, - ImageContext->SectionAlignment - )); - return RETURN_UNSUPPORTED; - } - - ImageContext->SectionAlignment = EFI_PAGE_SIZE; - } - - // - // Read the PE/COFF Header. For PE32 (32-bit) this will read in too much - // data, but that should not hurt anything. Hdr.Pe32->OptionalHeader.Magic - // determines if this is a PE32 or PE32+ image. The magic is in the same - // location in both images. - // - Hdr.Union = &HdrData; - Size = sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION); - ReadSize = Size; - Status = ImageContext->ImageRead ( - ImageContext->Handle, - ImageContext->PeCoffHeaderOffset, - &Size, - Hdr.Pe32 - ); - - if (RETURN_ERROR (Status) || (Size != ReadSize)) { - DEBUG (( - DEBUG_ERROR, - "%a: TmpContext->ImageRead () failed (Status = %r)\n", - __func__, - Status - )); - return Status; - } - - *ImageBase = ImageContext->ImageAddress; - if (!ImageContext->IsTeImage) { - ASSERT (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE); - - *SectionHeaderOffset = ImageContext->PeCoffHeaderOffset + sizeof (UINT32) + - sizeof (EFI_IMAGE_FILE_HEADER); - *NumberOfSections = Hdr.Pe32->FileHeader.NumberOfSections; - - switch (Hdr.Pe32->OptionalHeader.Magic) { - case EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC: - *SectionHeaderOffset += Hdr.Pe32->FileHeader.SizeOfOptionalHeader; - break; - case EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC: - *SectionHeaderOffset += Hdr.Pe32Plus->FileHeader.SizeOfOptionalHeader; - break; - default: - ASSERT (FALSE); - } - } else { - *SectionHeaderOffset = (UINTN)(sizeof (EFI_TE_IMAGE_HEADER)); - *NumberOfSections = Hdr.Te->NumberOfSections; - *ImageBase -= (UINT32)Hdr.Te->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER); - } - - return RETURN_SUCCESS; -} - -/** - Privileged firmware assigns RO & Executable attributes to all memory occupied - by the Boot Firmware Volume. This function locates the section information of - the Standalone MM Core module to be able to change permissions of the - individual sections later in the boot process. - - @param [in] TeData Pointer to PE/COFF image data - @param [in, out] ImageContext Pointer to PE/COFF image context - @param [out] ImageBase Pointer to ImageBase variable - @param [in, out] SectionHeaderOffset Offset of PE/COFF image section header - @param [in, out] NumberOfSections Number of Sections - -**/ -EFI_STATUS -EFIAPI -GetStandaloneMmCorePeCoffSections ( - IN VOID *TeData, - IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext, - OUT EFI_PHYSICAL_ADDRESS *ImageBase, - IN OUT UINT32 *SectionHeaderOffset, - IN OUT UINT16 *NumberOfSections - ) -{ - EFI_STATUS Status; - - // Initialize the Image Context - ZeroMem (ImageContext, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT)); - ImageContext->Handle = TeData; - ImageContext->ImageRead = PeCoffLoaderImageReadFromMemory; - - DEBUG ((DEBUG_INFO, "Found Standalone MM PE data - 0x%x\n", TeData)); - - Status = GetPeCoffSectionInformation ( - ImageContext, - ImageBase, - SectionHeaderOffset, - NumberOfSections - ); - if (EFI_ERROR (Status)) { - DEBUG ((DEBUG_ERROR, "Unable to locate Standalone MM Core PE-COFF Section information - %r\n", Status)); - return Status; - } - - DEBUG (( - DEBUG_INFO, - "Standalone MM Core PE-COFF SectionHeaderOffset - 0x%x, NumberOfSections - %d\n", - *SectionHeaderOffset, - *NumberOfSections - )); - + DEBUG ((DEBUG_INFO, "Found Standalone MM PE data - 0x%x\n", *UefiImage)); return Status; } diff --git a/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/Arm/StandaloneMmCoreEntryPoint.c b/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/Arm/StandaloneMmCoreEntryPoint.c index 70306be249..9ae97482f9 100644 --- a/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/Arm/StandaloneMmCoreEntryPoint.c +++ b/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/Arm/StandaloneMmCoreEntryPoint.c @@ -24,6 +24,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #include #include #include +#include #include #include @@ -341,12 +342,11 @@ _ModuleEntryPoint ( ARM_SVC_ARGS InitMmFoundationSvcArgs; EFI_STATUS Status; INT32 Ret; - UINT32 SectionHeaderOffset; - UINT16 NumberOfSections; VOID *HobStart; VOID *TeData; - UINTN TeDataSize; - EFI_PHYSICAL_ADDRESS ImageBase; + UINT32 TeDataSize; + UINT32 SectionIndex; + UEFI_IMAGE_RECORD *ImageRecord; // Get Secure Partition Manager Version Information Status = GetSpmVersion (); @@ -361,7 +361,7 @@ _ModuleEntryPoint ( } // Locate PE/COFF File information for the Standalone MM core module - Status = LocateStandaloneMmCorePeCoffData ( + Status = LocateStandaloneMmCoreUefiImage ( (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)PayloadBootInfo->SpImageBase, &TeData, &TeDataSize @@ -371,54 +371,47 @@ _ModuleEntryPoint ( goto finish; } + DEBUG ((DEBUG_INFO, "Found Standalone MM PE data - 0x%x\n", TeData)); + // Obtain the PE/COFF Section information for the Standalone MM core module - Status = GetStandaloneMmCorePeCoffSections ( - TeData, - &ImageContext, - &ImageBase, - &SectionHeaderOffset, - &NumberOfSections - ); + Status = UefiImageInitializeContext (&ImageContext, TeData, TeDataSize); if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Unable to locate Standalone MM Core PE-COFF Section information - %r\n", Status)); goto finish; } - // - // ImageBase may deviate from ImageContext.ImageAddress if we are dealing - // with a TE image, in which case the latter points to the actual offset - // of the image, whereas ImageBase refers to the address where the image - // would start if the stripped PE headers were still in place. In either - // case, we need to fix up ImageBase so it refers to the actual current - // load address. - // - ImageBase += (UINTN)TeData - ImageContext.ImageAddress; - - // Update the memory access permissions of individual sections in the - // Standalone MM core module - Status = UpdateMmFoundationPeCoffPermissions ( - &ImageContext, - ImageBase, - SectionHeaderOffset, - NumberOfSections, - ArmSetMemoryRegionNoExec, - ArmSetMemoryRegionReadOnly, - ArmClearMemoryRegionReadOnly - ); + ImageRecord = UefiImageLoaderGetImageRecord (&ImageContext); - if (EFI_ERROR (Status)) { + if (ImageRecord == NULL) { goto finish; } - if (ImageContext.ImageAddress != (UINTN)TeData) { - ImageContext.ImageAddress = (UINTN)TeData; - ArmSetMemoryRegionNoExec (ImageBase, SIZE_4KB); - ArmClearMemoryRegionReadOnly (ImageBase, SIZE_4KB); + UINT32 Address = 0; + for (SectionIndex = 0; SectionIndex < ImageRecord->NumSegments; ++ SectionIndex) { + if ((ImageRecord->Segments[SectionIndex].Attributes & EFI_MEMORY_XP) != 0) { + ArmSetMemoryRegionNoExec ( + Address, + ImageRecord->Segments[SectionIndex].Size + ); + } + + if ((ImageRecord->Segments[SectionIndex].Attributes & EFI_MEMORY_RO) == 0) { + ArmClearMemoryRegionReadOnly ( + Address, + ImageRecord->Segments[SectionIndex].Size + ); + } - Status = PeCoffLoaderRelocateImage (&ImageContext); - ASSERT_EFI_ERROR (Status); + Address += ImageRecord->Segments[SectionIndex].Size; } + FreePool (ImageRecord); + + // FIXME: Should relocation not be performed with all of the Image writable? + Status = UefiImageRelocateImageInplaceForExecution (&ImageContext); + ASSERT_EFI_ERROR (Status); + // // Create Hoblist based upon boot information passed by privileged software // diff --git a/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/StandaloneMmCoreEntryPoint.inf b/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/StandaloneMmCoreEntryPoint.inf index d41d7630b6..27e3ae86a3 100644 --- a/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/StandaloneMmCoreEntryPoint.inf +++ b/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/StandaloneMmCoreEntryPoint.inf @@ -55,11 +55,9 @@ gArmTokenSpaceGuid.PcdFfaEnable # -# This configuration fails for CLANGPDB, which does not support PIE in the GCC -# sense. Such however is required for ARM family StandaloneMmCore -# self-relocation, and thus the CLANGPDB toolchain is unsupported for ARM and -# AARCH64 for this module. +# This configuration fails for CLANGDPB, which does not support PIE in the GCC +# sense. Such however is required for AArch64 StandaloneMmCore self-relocation, +# and thus the CLANGPDB toolchain is unsupported for AArch64 for this module. # [BuildOptions] - GCC:*_*_ARM_CC_FLAGS = -fpie GCC:*_*_AARCH64_CC_FLAGS = -fpie diff --git a/StandaloneMmPkg/Library/StandaloneMmProtectionLib/ProtectionAarch64.c b/StandaloneMmPkg/Library/StandaloneMmProtectionLib/ProtectionAarch64.c new file mode 100644 index 0000000000..b1258fb373 --- /dev/null +++ b/StandaloneMmPkg/Library/StandaloneMmProtectionLib/ProtectionAarch64.c @@ -0,0 +1,41 @@ +// FIXME: Docs, more general libclass for DXE? + +#include + +#include + +EFI_STATUS +SetMemoryRegionNoExec ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ) +{ + return ArmSetMemoryRegionNoExec (BaseAddress, Length); +} + +EFI_STATUS +ClearMemoryRegionNoExec ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ) +{ + return ArmClearMemoryRegionNoExec (BaseAddress, Length); +} + +EFI_STATUS +SetMemoryRegionReadOnly ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ) +{ + return ArmSetMemoryRegionReadOnly (BaseAddress, Length); +} + +EFI_STATUS +ClearMemoryRegionReadOnly ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ) +{ + return ArmClearMemoryRegionReadOnly (BaseAddress, Length); +} diff --git a/StandaloneMmPkg/Library/StandaloneMmProtectionLib/ProtectionNull.c b/StandaloneMmPkg/Library/StandaloneMmProtectionLib/ProtectionNull.c new file mode 100644 index 0000000000..706762d8c8 --- /dev/null +++ b/StandaloneMmPkg/Library/StandaloneMmProtectionLib/ProtectionNull.c @@ -0,0 +1,49 @@ +#include + +EFI_STATUS +SetMemoryRegionNoExec ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ) +{ + (VOID) BaseAddress; + (VOID) Length; + + return RETURN_SUCCESS; +} + +EFI_STATUS +ClearMemoryRegionNoExec ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ) +{ + (VOID) BaseAddress; + (VOID) Length; + + return RETURN_SUCCESS; +} + +EFI_STATUS +SetMemoryRegionReadOnly ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ) +{ + (VOID) BaseAddress; + (VOID) Length; + + return RETURN_SUCCESS; +} + +EFI_STATUS +ClearMemoryRegionReadOnly ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ) +{ + (VOID) BaseAddress; + (VOID) Length; + + return RETURN_SUCCESS; +} diff --git a/StandaloneMmPkg/Library/StandaloneMmProtectionLib/StandaloneMmProtectionLib.inf b/StandaloneMmPkg/Library/StandaloneMmProtectionLib/StandaloneMmProtectionLib.inf new file mode 100644 index 0000000000..fe817c6f8e --- /dev/null +++ b/StandaloneMmPkg/Library/StandaloneMmProtectionLib/StandaloneMmProtectionLib.inf @@ -0,0 +1,29 @@ +# FIXME: Docs +[Defines] + INF_VERSION = 0x0001001A + BASE_NAME = StandaloneMmProtectionLib + FILE_GUID = 4FCCC091-D240-4FE3-A922-5153D1DB1649 + MODULE_TYPE = MM_CORE_STANDALONE + VERSION_STRING = 1.0 + PI_SPECIFICATION_VERSION = 0x00010032 + LIBRARY_CLASS = StandaloneMmProtectionLib|MM_CORE_STANDALONE + +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC (EBC is for build only) +# + +[Sources.AARCH64] + ProtectionAarch64.c + +[Sources.X64, Sources.ARM] + ProtectionNull.c + +[Packages] + MdePkg/MdePkg.dec + StandaloneMmPkg/StandaloneMmPkg.dec + +[Packages.AARCH64] + ArmPkg/ArmPkg.dec + +[LibraryClasses.AARCH64] + StandaloneMmMmuLib diff --git a/StandaloneMmPkg/StandaloneMmPkg.dec b/StandaloneMmPkg/StandaloneMmPkg.dec index fc91bb4c3e..31ee80f9a9 100644 --- a/StandaloneMmPkg/StandaloneMmPkg.dec +++ b/StandaloneMmPkg/StandaloneMmPkg.dec @@ -34,6 +34,9 @@ ## AArch64 and ARM. StandaloneMmCoreEntryPoint|Include/Library/Arm/StandaloneMmCoreEntryPoint.h + ## FIXME: docs + StandaloneMmProtectionLib|Include/Library/StandaloneMmProtectionLib.h + [Guids] gStandaloneMmPkgTokenSpaceGuid = { 0x18fe7632, 0xf5c8, 0x4e63, { 0x8d, 0xe8, 0x17, 0xa5, 0x5c, 0x59, 0x13, 0xbd }} gMpInformationHobGuid = { 0xba33f15d, 0x4000, 0x45c1, { 0x8e, 0x88, 0xf9, 0x16, 0x92, 0xd4, 0x57, 0xe3 }} diff --git a/StandaloneMmPkg/StandaloneMmPkg.dsc b/StandaloneMmPkg/StandaloneMmPkg.dsc index 8012f93b7d..2ec184774c 100644 --- a/StandaloneMmPkg/StandaloneMmPkg.dsc +++ b/StandaloneMmPkg/StandaloneMmPkg.dsc @@ -52,12 +52,14 @@ MemoryAllocationLib|StandaloneMmPkg/Library/StandaloneMmCoreMemoryAllocationLib/StandaloneMmCoreMemoryAllocationLib.inf MmServicesTableLib|MdePkg/Library/StandaloneMmServicesTableLib/StandaloneMmServicesTableLib.inf PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf - PeCoffExtraActionLib|MdePkg/Library/BasePeCoffExtraActionLibNull/BasePeCoffExtraActionLibNull.inf - PeCoffLib|MdePkg/Library/BasePeCoffLib/BasePeCoffLib.inf + UefiImageExtraActionLib|MdePkg/Library/BaseUefiImageExtraActionLibNull/BaseUefiImageExtraActionLibNull.inf + PeCoffLib2|MdePkg/Library/BasePeCoffLib2/BasePeCoffLib2.inf + UefiImageLib|MdePkg/Library/BaseUefiImageLib/BaseUefiImageLibPeCoff.inf PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf ReportStatusCodeLib|MdePkg/Library/BaseReportStatusCodeLibNull/BaseReportStatusCodeLibNull.inf StandaloneMmCoreEntryPoint|StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/StandaloneMmCoreEntryPoint.inf StandaloneMmDriverEntryPoint|MdePkg/Library/StandaloneMmDriverEntryPoint/StandaloneMmDriverEntryPoint.inf + StandaloneMmProtectionLib|StandaloneMmPkg/Library/StandaloneMmProtectionLib/StandaloneMmProtectionLib.inf VariableMmDependency|StandaloneMmPkg/Library/VariableMmDependency/VariableMmDependency.inf [LibraryClasses.AARCH64, LibraryClasses.ARM] @@ -65,7 +67,6 @@ StandaloneMmMmuLib|ArmPkg/Library/StandaloneMmMmuLib/ArmMmuStandaloneMmLib.inf ArmSvcLib|ArmPkg/Library/ArmSvcLib/ArmSvcLib.inf CacheMaintenanceLib|ArmPkg/Library/ArmCacheMaintenanceLib/ArmCacheMaintenanceLib.inf - PeCoffExtraActionLib|StandaloneMmPkg/Library/StandaloneMmPeCoffExtraActionLib/StandaloneMmPeCoffExtraActionLib.inf NULL|ArmPkg/Library/CompilerIntrinsicsLib/CompilerIntrinsicsLib.inf NULL|MdePkg/Library/BaseStackCheckLib/BaseStackCheckLib.inf @@ -117,6 +118,7 @@ StandaloneMmPkg/Library/StandaloneMmMemLib/StandaloneMmMemLib.inf StandaloneMmPkg/Library/StandaloneMmMemoryAllocationLib/StandaloneMmMemoryAllocationLib.inf StandaloneMmPkg/Library/VariableMmDependency/VariableMmDependency.inf + StandaloneMmPkg/Library/StandaloneMmProtectionLib/StandaloneMmProtectionLib.inf [Components.AARCH64, Components.ARM] StandaloneMmPkg/Drivers/StandaloneMmCpu/StandaloneMmCpu.inf diff --git a/UefiCpuPkg/CpuDxe/CpuPageTable.c b/UefiCpuPkg/CpuDxe/CpuPageTable.c index 5b1dec2d67..b5609da9c2 100644 --- a/UefiCpuPkg/CpuDxe/CpuPageTable.c +++ b/UefiCpuPkg/CpuDxe/CpuPageTable.c @@ -10,7 +10,7 @@ #include #include -#include + #include #include #include diff --git a/UefiCpuPkg/CpuDxe/CpuPageTable.h b/UefiCpuPkg/CpuDxe/CpuPageTable.h index 607e936b8a..d4d7ab0a7e 100644 --- a/UefiCpuPkg/CpuDxe/CpuPageTable.h +++ b/UefiCpuPkg/CpuDxe/CpuPageTable.h @@ -9,7 +9,7 @@ #ifndef _PAGE_TABLE_LIB_H_ #define _PAGE_TABLE_LIB_H_ -#include +#include #define PAGE_TABLE_LIB_PAGING_CONTEXT_IA32_X64_ATTRIBUTES_PSE BIT0 #define PAGE_TABLE_LIB_PAGING_CONTEXT_IA32_X64_ATTRIBUTES_PAE BIT1 diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.c index 903fac927e..76ea152955 100644 --- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.c +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.c @@ -118,35 +118,29 @@ DumpModuleImageInfo ( IN UINTN CurrentEip ) { - EFI_STATUS Status; - UINTN Pe32Data; - VOID *PdbPointer; - VOID *EntryPoint; + BOOLEAN Result; + UINTN ImageBase; + CONST CHAR8 *PdbPath; - Pe32Data = PeCoffSearchImageBase (CurrentEip); - if (Pe32Data == 0) { + Result = GetImageInfoByIp (&ImageBase, &PdbPath, CurrentEip); + + if (!Result) { InternalPrintMessage ("!!!! Can't find image information. !!!!\n"); } else { // // Find Image Base entry point // - Status = PeCoffLoaderGetEntryPoint ((VOID *)Pe32Data, &EntryPoint); - if (EFI_ERROR (Status)) { - EntryPoint = NULL; - } InternalPrintMessage ("!!!! Find image based on IP(0x%x) ", CurrentEip); - PdbPointer = PeCoffLoaderGetPdbPointer ((VOID *)Pe32Data); - if (PdbPointer != NULL) { - InternalPrintMessage ("%a", PdbPointer); + if (PdbPath!= NULL) { + InternalPrintMessage ("%a", PdbPath); } else { InternalPrintMessage ("(No PDB) "); } InternalPrintMessage ( - " (ImageBase=%016lp, EntryPoint=%016p) !!!!\n", - (VOID *)Pe32Data, - EntryPoint + " (ImageBase=%016lp) !!!!\n", + (EFI_PHYSICAL_ADDRESS) ImageBase ); } } diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.h b/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.h index 4593c204a6..95877b8be0 100644 --- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.h +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.h @@ -15,7 +15,8 @@ #include #include #include -#include +#include + #include #include #include @@ -321,4 +322,13 @@ AsmGetTssTemplateMap ( OUT EXCEPTION_HANDLER_TEMPLATE_MAP *AddressMap ); +// FIXME: +BOOLEAN +GetImageInfoByIp ( + OUT UINTN *ImageBase, + OUT CONST CHAR8 **SymbolsPath, + IN UINTN CurrentEip + ); + #endif + diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf b/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf index 9fcba009d6..e8b4deeddd 100644 --- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf @@ -63,7 +63,6 @@ BaseLib DebugLib MemoryAllocationLib - PeCoffGetEntryPointLib PrintLib SerialPortLib SynchronizationLib @@ -77,3 +76,6 @@ [BuildOptions] XCODE:*_*_X64_NASM_FLAGS = -D NO_ABSOLUTE_RELOCS_IN_TEXT + +[Guids] + gEfiDebugImageInfoTableGuid ## CONSUMES ## SystemTable diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeException.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeException.c index d4e9979c92..2a4fca621a 100644 --- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeException.c +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeException.c @@ -11,6 +11,8 @@ #include #include #include +#include +#include CONST UINTN mDoFarReturnFlag = 0; @@ -26,6 +28,8 @@ EXCEPTION_HANDLER_DATA mExceptionHandlerData = { UINT8 mBuffer[CPU_STACK_SWITCH_EXCEPTION_NUMBER * CPU_KNOWN_GOOD_STACK_SIZE + sizeof (IA32_TSS_DESCRIPTOR) + CPU_TSS_GDT_SIZE]; +STATIC CONST EFI_DEBUG_IMAGE_INFO_TABLE_HEADER *mDebugImageInfoTable = NULL; + /** Common exception handler. @@ -135,3 +139,51 @@ InitializeSeparateExceptionStacks ( return ArchSetupExceptionStack (Buffer, BufferSize); } } + +BOOLEAN +GetImageInfoByIp ( + OUT UINTN *ImageBase, + OUT CONST CHAR8 **SymbolsPath, + IN UINTN CurrentEip + ) +{ + EFI_STATUS Status; + UINT32 Index; + CONST EFI_DEBUG_IMAGE_INFO_NORMAL *NormalImage; + + if (mDebugImageInfoTable == NULL) { + Status = EfiGetSystemConfigurationTable ( + &gEfiDebugImageInfoTableGuid, + (VOID **) &mDebugImageInfoTable + ); + if (EFI_ERROR (Status)) { + mDebugImageInfoTable = NULL; + return FALSE; + } + } + + ASSERT (mDebugImageInfoTable != NULL); + + for (Index = 0; Index < mDebugImageInfoTable->TableSize; ++Index) { + if (mDebugImageInfoTable->EfiDebugImageInfoTable[Index].ImageInfoType == NULL) { + continue; + } + + if (*mDebugImageInfoTable->EfiDebugImageInfoTable[Index].ImageInfoType != EFI_DEBUG_IMAGE_INFO_TYPE_NORMAL) { + continue; + } + + NormalImage = mDebugImageInfoTable->EfiDebugImageInfoTable[Index].NormalImage; + + ASSERT (NormalImage->LoadedImageProtocolInstance != NULL); + + if (CurrentEip >= (UINTN) NormalImage->LoadedImageProtocolInstance->ImageBase && + CurrentEip < (UINTN) NormalImage->LoadedImageProtocolInstance->ImageBase + NormalImage->LoadedImageProtocolInstance->ImageSize) { + *ImageBase = (UINTN) NormalImage->LoadedImageProtocolInstance->ImageBase; + *SymbolsPath = NormalImage->PdbPath; + return TRUE; + } + } + + return FALSE; +} diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuException.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuException.c index 3e38676b23..d98b60a0b0 100644 --- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuException.c +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuException.c @@ -12,6 +12,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #include #include #include +#include CONST UINTN mDoFarReturnFlag = 0; @@ -212,3 +213,26 @@ InitializeSeparateExceptionStacks ( return ArchSetupExceptionStack (Buffer, BufferSize); } + +// FIXME: Expose DebugImageInfoTable as PPI? +BOOLEAN +GetImageInfoByIp ( + OUT UINTN *ImageBase, + OUT CONST CHAR8 **SymbolsPath, + IN UINTN CurrentEip + ) +{ + RETURN_STATUS Status; + UEFI_IMAGE_LOADER_IMAGE_CONTEXT ImageContext; + UINT32 PdbPathSize; + + Status = UefiImageDebugLocateImage (&ImageContext, CurrentEip); + if (RETURN_ERROR (Status)) { + return FALSE; + } + + *ImageBase = UefiImageLoaderGetImageAddress (&ImageContext); + + Status = UefiImageGetSymbolsPath (&ImageContext, SymbolsPath, &PdbPathSize); + return !RETURN_ERROR (Status); +} diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuExceptionHandlerLib.inf b/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuExceptionHandlerLib.inf index 3a11516e32..3db1ad47ab 100644 --- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuExceptionHandlerLib.inf +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuExceptionHandlerLib.inf @@ -49,7 +49,7 @@ HobLib LocalApicLib MemoryAllocationLib - PeCoffGetEntryPointLib + UefiImageLib PrintLib SerialPortLib SynchronizationLib diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuException.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuException.c index 497cd16499..8351d29b96 100644 --- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuException.c +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuException.c @@ -222,3 +222,13 @@ InitializeSeparateExceptionStacks ( { return EFI_UNSUPPORTED; } + +BOOLEAN +GetImageInfoByIp ( + OUT UINTN *ImageBase, + OUT CONST CHAR8 **SymbolsPath, + IN UINTN CurrentEip + ) +{ + return FALSE; +} diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf index 64de252dcd..55acb46ebe 100644 --- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf @@ -54,7 +54,7 @@ [LibraryClasses.common] BaseLib - PeCoffGetEntryPointLib + UefiImageLib PrintLib SerialPortLib diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmCpuExceptionHandlerLib.inf b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmCpuExceptionHandlerLib.inf index cc280a6ee7..ef835ee9dc 100644 --- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmCpuExceptionHandlerLib.inf +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmCpuExceptionHandlerLib.inf @@ -48,7 +48,6 @@ CcExitLib DebugLib LocalApicLib - PeCoffGetEntryPointLib PrintLib SerialPortLib SynchronizationLib @@ -63,3 +62,6 @@ [BuildOptions] XCODE:*_*_X64_NASM_FLAGS = -D NO_ABSOLUTE_RELOCS_IN_TEXT + +[Guids] + gEfiDebugImageInfoTableGuid ## CONSUMES ## SystemTable diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmException.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmException.c index 46a86ad2c6..d14d00aa7e 100644 --- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmException.c +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmException.c @@ -8,6 +8,8 @@ #include #include "CpuExceptionCommon.h" +#include +#include CONST UINTN mDoFarReturnFlag = 1; @@ -20,6 +22,7 @@ EXCEPTION_HANDLER_DATA mExceptionHandlerData = { mExternalInterruptHandlerTable }; +STATIC CONST EFI_DEBUG_IMAGE_INFO_TABLE_HEADER *mDebugImageInfoTableHeader = NULL; /** Common exception handler. @@ -118,3 +121,76 @@ InitializeSeparateExceptionStacks ( { return EFI_UNSUPPORTED; } + +// FIXME: Lib? +STATIC +EFI_STATUS +EFIAPI +InternalGetSystemConfigurationTable ( + IN EFI_GUID *TableGuid, + OUT VOID **Table + ) +{ + UINTN Index; + + ASSERT (TableGuid != NULL); + ASSERT (Table != NULL); + + *Table = NULL; + for (Index = 0; Index < gSmst->NumberOfTableEntries; Index++) { + if (CompareGuid (TableGuid, &(gSmst->SmmConfigurationTable[Index].VendorGuid))) { + *Table = gSmst->SmmConfigurationTable[Index].VendorTable; + return EFI_SUCCESS; + } + } + + return EFI_NOT_FOUND; +} + +BOOLEAN +GetImageInfoByIp ( + OUT UINTN *ImageBase, + OUT CONST CHAR8 **SymbolsPath, + IN UINTN CurrentEip + ) +{ + EFI_STATUS Status; + UINT32 Index; + CONST EFI_DEBUG_IMAGE_INFO_NORMAL *NormalImage; + + if (mDebugImageInfoTableHeader == NULL) { + Status = InternalGetSystemConfigurationTable ( + &gEfiDebugImageInfoTableGuid, + (VOID **) &mDebugImageInfoTableHeader + ); + if (EFI_ERROR (Status)) { + mDebugImageInfoTableHeader = NULL; + return FALSE; + } + } + + ASSERT (mDebugImageInfoTableHeader != NULL); + + for (Index = 0; Index < mDebugImageInfoTableHeader->TableSize; ++Index) { + if (mDebugImageInfoTableHeader->EfiDebugImageInfoTable[Index].ImageInfoType == NULL) { + continue; + } + + if (*mDebugImageInfoTableHeader->EfiDebugImageInfoTable[Index].ImageInfoType != EFI_DEBUG_IMAGE_INFO_TYPE_NORMAL) { + continue; + } + + NormalImage = mDebugImageInfoTableHeader->EfiDebugImageInfoTable[Index].NormalImage; + + ASSERT (NormalImage->LoadedImageProtocolInstance != NULL); + + if (CurrentEip >= (UINTN) NormalImage->LoadedImageProtocolInstance->ImageBase && + CurrentEip < (UINTN) NormalImage->LoadedImageProtocolInstance->ImageBase + NormalImage->LoadedImageProtocolInstance->ImageSize) { + *ImageBase = (UINTN) NormalImage->LoadedImageProtocolInstance->ImageBase; + *SymbolsPath = NormalImage->PdbPath; + return TRUE; + } + } + + return FALSE; +} diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c index e400bee8d5..11924cc7a2 100644 --- a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c @@ -176,6 +176,64 @@ InitializeSmmIdt ( SetInterruptState (InterruptState); } +#include +#include +#include + +EFI_STATUS +EFIAPI +SmmGetSystemConfigurationTable ( + IN EFI_GUID *TableGuid, + OUT VOID **Table + ); + +CONST EFI_DEBUG_IMAGE_INFO_TABLE_HEADER *mDebugImageInfoTableHeader = NULL; + +// FIXME: +CONST EFI_DEBUG_IMAGE_INFO_NORMAL * +InternalLocateImage ( + IN UINTN CurrentEip + ) +{ + EFI_STATUS Status; + UINT32 Index; + CONST EFI_DEBUG_IMAGE_INFO_NORMAL *NormalImage; + + if (mDebugImageInfoTableHeader == NULL) { + Status = SmmGetSystemConfigurationTable ( + &gEfiDebugImageInfoTableGuid, + (VOID **) &mDebugImageInfoTableHeader + ); + if (EFI_ERROR (Status)) { + mDebugImageInfoTableHeader = NULL; + return NULL; + } + } + + ASSERT (mDebugImageInfoTableHeader != NULL); + + for (Index = 0; Index < mDebugImageInfoTableHeader->TableSize; ++Index) { + if (mDebugImageInfoTableHeader->EfiDebugImageInfoTable[Index].ImageInfoType == NULL) { + continue; + } + + if (*mDebugImageInfoTableHeader->EfiDebugImageInfoTable[Index].ImageInfoType != EFI_DEBUG_IMAGE_INFO_TYPE_NORMAL) { + continue; + } + + NormalImage = mDebugImageInfoTableHeader->EfiDebugImageInfoTable[Index].NormalImage; + + ASSERT (NormalImage->LoadedImageProtocolInstance != NULL); + + if (CurrentEip >= (UINTN) NormalImage->LoadedImageProtocolInstance->ImageBase && + CurrentEip < (UINTN) NormalImage->LoadedImageProtocolInstance->ImageBase + NormalImage->LoadedImageProtocolInstance->ImageSize) { + return NormalImage; + } + } + + return NULL; +} + /** Search module name by input IP address and output it. @@ -187,18 +245,17 @@ DumpModuleInfoByIp ( IN UINTN CallerIpAddress ) { - UINTN Pe32Data; - VOID *PdbPointer; + CONST EFI_DEBUG_IMAGE_INFO_NORMAL *NormalImage; + + NormalImage = InternalLocateImage (CallerIpAddress); // // Find Image Base // - Pe32Data = PeCoffSearchImageBase (CallerIpAddress); - if (Pe32Data != 0) { + if (NormalImage != NULL) { DEBUG ((DEBUG_ERROR, "It is invoked from the instruction before IP(0x%p)", (VOID *)CallerIpAddress)); - PdbPointer = PeCoffLoaderGetPdbPointer ((VOID *)Pe32Data); - if (PdbPointer != NULL) { - DEBUG ((DEBUG_ERROR, " in module (%a)\n", PdbPointer)); + if (NormalImage->PdbPath!= NULL) { + DEBUG ((DEBUG_ERROR, " in module (%a)\n", NormalImage->PdbPath)); } } } diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h index f42910ddf1..feeebfe653 100644 --- a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h @@ -49,7 +49,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #include #include #include -#include + #include #include #include diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf index 3354f94a64..b617c49cc0 100644 --- a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf @@ -95,7 +95,6 @@ CpuLib ReportStatusCodeLib SmmCpuFeaturesLib - PeCoffGetEntryPointLib PerformanceLib CpuPageTableLib MmSaveStateLib @@ -118,6 +117,7 @@ gEfiMemoryAttributesTableGuid ## CONSUMES ## SystemTable gSmmBaseHobGuid ## CONSUMES gMpInformation2HobGuid ## CONSUMES # Assume the HOB must has been created + gEfiDebugImageInfoTableGuid ## CONSUMES ## SystemTable [FeaturePcd] gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmDebug ## CONSUMES diff --git a/UefiCpuPkg/SecCore/FindPeiCore.c b/UefiCpuPkg/SecCore/FindPeiCore.c index 97adb68138..3187dcf60f 100644 --- a/UefiCpuPkg/SecCore/FindPeiCore.c +++ b/UefiCpuPkg/SecCore/FindPeiCore.c @@ -23,7 +23,8 @@ EFIAPI FindImageBase ( IN EFI_FIRMWARE_VOLUME_HEADER *FirmwareVolumePtr, IN EFI_FV_FILETYPE FileType, - OUT EFI_PHYSICAL_ADDRESS *CoreImageBase + OUT EFI_PHYSICAL_ADDRESS *CoreImageBase, + OUT UINT32 *CoreImageSize ) { EFI_PHYSICAL_ADDRESS CurrentAddress; @@ -110,8 +111,10 @@ FindImageBase ( if (File->Type == FileType) { if (IS_SECTION2 (Section)) { *CoreImageBase = (PHYSICAL_ADDRESS)(UINTN)((UINT8 *)Section + sizeof (EFI_COMMON_SECTION_HEADER2)); + *CoreImageSize = Size - sizeof (EFI_COMMON_SECTION_HEADER2); } else { *CoreImageBase = (PHYSICAL_ADDRESS)(UINTN)((UINT8 *)Section + sizeof (EFI_COMMON_SECTION_HEADER)); + *CoreImageSize = Size - sizeof (EFI_COMMON_SECTION_HEADER); } } @@ -147,45 +150,70 @@ FindAndReportEntryPoints ( OUT EFI_PEI_CORE_ENTRY_POINT *PeiCoreEntryPoint ) { - EFI_STATUS Status; - EFI_PHYSICAL_ADDRESS SecCoreImageBase; - EFI_PHYSICAL_ADDRESS PeiCoreImageBase; - PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS SecCoreImageBase; + UINT32 SecCoreImageSize; + EFI_PHYSICAL_ADDRESS PeiCoreImageBase; + UINT32 PeiCoreImageSize; + UEFI_IMAGE_LOADER_IMAGE_CONTEXT ImageContext; // // Find SEC Core image base // - Status = FindImageBase (SecCoreFirmwareVolumePtr, EFI_FV_FILETYPE_SECURITY_CORE, &SecCoreImageBase); + Status = FindImageBase ( + SecCoreFirmwareVolumePtr, + EFI_FV_FILETYPE_SECURITY_CORE, + &SecCoreImageBase, + &SecCoreImageSize + ); + ASSERT_EFI_ERROR (Status); + + // FIXME: DEBUG-only + Status = UefiImageInitializeContext ( + &ImageContext, + (VOID*) (UINTN) SecCoreImageBase, + SecCoreImageSize + ); + ASSERT_EFI_ERROR (Status); + + Status = UefiImageLoadImageInplace (&ImageContext); ASSERT_EFI_ERROR (Status); - ZeroMem ((VOID *)&ImageContext, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT)); // // Report SEC Core debug information when remote debug is enabled // - ImageContext.ImageAddress = SecCoreImageBase; - ImageContext.PdbPointer = PeCoffLoaderGetPdbPointer ((VOID *)(UINTN)ImageContext.ImageAddress); - PeCoffLoaderRelocateImageExtraAction (&ImageContext); + UefiImageLoaderRelocateImageExtraAction (&ImageContext); // // Find PEI Core image base // - Status = FindImageBase (PeiCoreFirmwareVolumePtr, EFI_FV_FILETYPE_PEI_CORE, &PeiCoreImageBase); + Status = FindImageBase ( + PeiCoreFirmwareVolumePtr, + EFI_FV_FILETYPE_PEI_CORE, + &PeiCoreImageBase, + &PeiCoreImageSize + ); + ASSERT_EFI_ERROR (Status); + + Status = UefiImageInitializeContext ( + &ImageContext, + (VOID*)(UINTN)PeiCoreImageBase, + PeiCoreImageSize + ); + ASSERT_EFI_ERROR (Status); + + Status = UefiImageLoadImageInplace (&ImageContext); ASSERT_EFI_ERROR (Status); // // Report PEI Core debug information when remote debug is enabled // - ImageContext.ImageAddress = PeiCoreImageBase; - ImageContext.PdbPointer = PeCoffLoaderGetPdbPointer ((VOID *)(UINTN)ImageContext.ImageAddress); - PeCoffLoaderRelocateImageExtraAction (&ImageContext); + UefiImageLoaderRelocateImageExtraAction (&ImageContext); // // Find PEI Core entry point // - Status = PeCoffLoaderGetEntryPoint ((VOID *)(UINTN)PeiCoreImageBase, (VOID **)PeiCoreEntryPoint); - if (EFI_ERROR (Status)) { - *PeiCoreEntryPoint = 0; - } + *PeiCoreEntryPoint = (EFI_PEI_CORE_ENTRY_POINT) (UINTN) (UefiImageLoaderGetImageEntryPoint (&ImageContext)); return; } diff --git a/UefiCpuPkg/SecCore/SecCore.inf b/UefiCpuPkg/SecCore/SecCore.inf index 4f732cccb7..2719937d4c 100644 --- a/UefiCpuPkg/SecCore/SecCore.inf +++ b/UefiCpuPkg/SecCore/SecCore.inf @@ -48,8 +48,8 @@ PcdLib DebugAgentLib CpuLib - PeCoffGetEntryPointLib - PeCoffExtraActionLib + UefiCpuLib + UefiImageExtraActionLib CpuExceptionHandlerLib ReportStatusCodeLib PeiServicesLib diff --git a/UefiCpuPkg/SecCore/SecMain.h b/UefiCpuPkg/SecCore/SecMain.h index 81c561424e..f26d337843 100644 --- a/UefiCpuPkg/SecCore/SecMain.h +++ b/UefiCpuPkg/SecCore/SecMain.h @@ -25,8 +25,9 @@ #include #include #include -#include -#include +#include + +#include #include #include #include diff --git a/UefiCpuPkg/UefiCpuPkg.dec b/UefiCpuPkg/UefiCpuPkg.dec index f86a6d2bcb..cc31554f10 100644 --- a/UefiCpuPkg/UefiCpuPkg.dec +++ b/UefiCpuPkg/UefiCpuPkg.dec @@ -417,7 +417,7 @@ # TRUE - Access to non-SMRAM memory is restricted to reserved, runtime and ACPI NVS type after SmmReadyToLock.
# FALSE - Access to any type of non-SMRAM memory after SmmReadyToLock is allowed.
# @Prompt Access to non-SMRAM memory is restricted to reserved, runtime and ACPI NVS type after SmmReadyToLock. - gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmRestrictedMemoryAccess|TRUE|BOOLEAN|0x3213210F + gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmRestrictedMemoryAccess|FALSE|BOOLEAN|0x3213210F [PcdsFixedAtBuild.RISCV64] ## Indicate the maximum SATP mode allowed. diff --git a/UefiCpuPkg/UefiCpuPkg.dsc b/UefiCpuPkg/UefiCpuPkg.dsc index 3d49f72588..0e1f962235 100644 --- a/UefiCpuPkg/UefiCpuPkg.dsc +++ b/UefiCpuPkg/UefiCpuPkg.dsc @@ -57,8 +57,9 @@ SmmCpuPlatformHookLib|UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.inf SmmCpuFeaturesLib|UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.inf SmmCpuSyncLib|UefiCpuPkg/Library/SmmCpuSyncLib/SmmCpuSyncLib.inf - PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf - PeCoffExtraActionLib|MdePkg/Library/BasePeCoffExtraActionLibNull/BasePeCoffExtraActionLibNull.inf + PeCoffLib2|MdePkg/Library/BasePeCoffLib2/BasePeCoffLib2.inf + UefiImageLib|MdePkg/Library/BaseUefiImageLib/BaseUefiImageLibPeCoff.inf + UefiImageExtraActionLib|MdePkg/Library/BaseUefiImageExtraActionLibNull/BaseUefiImageExtraActionLibNull.inf TpmMeasurementLib|MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.inf CcExitLib|UefiCpuPkg/Library/CcExitLibNull/CcExitLibNull.inf AmdSvsmLib|UefiCpuPkg/Library/AmdSvsmLibNull/AmdSvsmLibNull.inf diff --git a/UefiPayloadPkg/UefiPayloadEntry/MemoryAllocation.c b/UefiPayloadPkg/Library/UefiPayloadEntryMemoryAllocationLib/MemoryAllocation.c similarity index 100% rename from UefiPayloadPkg/UefiPayloadEntry/MemoryAllocation.c rename to UefiPayloadPkg/Library/UefiPayloadEntryMemoryAllocationLib/MemoryAllocation.c diff --git a/UefiPayloadPkg/Library/UefiPayloadEntryMemoryAllocationLib/UefiPayloadEntryMemoryAllocationLib.inf b/UefiPayloadPkg/Library/UefiPayloadEntryMemoryAllocationLib/UefiPayloadEntryMemoryAllocationLib.inf new file mode 100644 index 0000000000..03da9b5cff --- /dev/null +++ b/UefiPayloadPkg/Library/UefiPayloadEntryMemoryAllocationLib/UefiPayloadEntryMemoryAllocationLib.inf @@ -0,0 +1,27 @@ +# FIXME: Docs + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = UefiPayloadEntryMemoryAllocationLib + FILE_GUID = D3C5B8A1-B946-4D46-8251-9020A527EE40 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = UefiPayloadEntryMemoryAllocationLib|SEC + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + MemoryAllocation.c + +[Packages] + MdePkg/MdePkg.dec + UefiPayloadPkg/UefiPayloadPkg.dec + +[LibraryClasses] + BaseMemoryLib + DebugLib + HobLib diff --git a/UefiPayloadPkg/UefiPayloadEntry/LoadDxeCore.c b/UefiPayloadPkg/UefiPayloadEntry/LoadDxeCore.c index 898d610951..2fff315b5d 100644 --- a/UefiPayloadPkg/UefiPayloadEntry/LoadDxeCore.c +++ b/UefiPayloadPkg/UefiPayloadEntry/LoadDxeCore.c @@ -48,7 +48,7 @@ AllocateCodePages ( /** Loads and relocates a PE/COFF image - @param[in] PeCoffImage Point to a Pe/Coff image. + @param[in] UefiImage Point to a Pe/Coff image. @param[out] ImageAddress The image memory address after relocation. @param[out] ImageSize The image size. @param[out] EntryPoint The image entry point. @@ -57,59 +57,59 @@ AllocateCodePages ( @return Others If the image failed to load or relocate. **/ EFI_STATUS -LoadPeCoffImage ( - IN VOID *PeCoffImage, +LoadUefiImage ( + IN VOID *UefiImage, + IN UINT32 UefiImageSize, OUT EFI_PHYSICAL_ADDRESS *ImageAddress, - OUT UINT64 *ImageSize, + OUT UINT64 *DestinationSize, OUT EFI_PHYSICAL_ADDRESS *EntryPoint ) { RETURN_STATUS Status; - PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; + UEFI_IMAGE_LOADER_IMAGE_CONTEXT ImageContext; + UINT32 ImageSize; + UINT32 ImageAlignment; + UINT32 BufferPages; + UINT32 BufferSize; VOID *Buffer; - ZeroMem (&ImageContext, sizeof (ImageContext)); - - ImageContext.Handle = PeCoffImage; - ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory; - - Status = PeCoffLoaderGetImageInfo (&ImageContext); + Status = UefiImageInitializeContext (&ImageContext, UefiImage, UefiImageSize); if (EFI_ERROR (Status)) { ASSERT_EFI_ERROR (Status); return Status; } + ImageSize = UefiImageGetImageSize (&ImageContext); + BufferPages = EFI_SIZE_TO_PAGES (ImageSize); + BufferSize = EFI_PAGES_TO_SIZE (BufferPages); + ImageAlignment = UefiImageGetSegmentAlignment (&ImageContext); + // // Allocate Memory for the image // - Buffer = AllocateCodePages (EFI_SIZE_TO_PAGES ((UINT32)ImageContext.ImageSize)); + Buffer = AllocateAlignedCodePages (BufferPages, ImageAlignment); if (Buffer == NULL) { return EFI_OUT_OF_RESOURCES; } - ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer; - - // - // Load the image to our new buffer - // - Status = PeCoffLoaderLoadImage (&ImageContext); - if (EFI_ERROR (Status)) { - ASSERT_EFI_ERROR (Status); - return Status; - } - // - // Relocate the image in our new buffer + // Load and relocate the image to our new buffer // - Status = PeCoffLoaderRelocateImage (&ImageContext); + Status = UefiImageLoadImageForExecution ( + &ImageContext, + Buffer, + BufferSize, + NULL, + 0 + ); if (EFI_ERROR (Status)) { ASSERT_EFI_ERROR (Status); return Status; } - *ImageAddress = ImageContext.ImageAddress; - *ImageSize = ImageContext.ImageSize; - *EntryPoint = ImageContext.EntryPoint; + *ImageAddress = (UINTN)Buffer; + *DestinationSize = BufferSize; + *EntryPoint = UefiImageLoaderGetImageEntryPoint (&ImageContext); return EFI_SUCCESS; } @@ -201,12 +201,13 @@ EFI_STATUS FileFindSection ( IN EFI_FFS_FILE_HEADER *FileHeader, IN EFI_SECTION_TYPE SectionType, - OUT VOID **SectionData + OUT VOID **SectionData, + OUT UINT32 *SectionSize ) { UINT32 FileSize; EFI_COMMON_SECTION_HEADER *Section; - UINT32 SectionSize; + UINT32 CurSectionSize; UINT32 Index; if (IS_FFS_FILE2 (FileHeader)) { @@ -221,26 +222,29 @@ FileFindSection ( Index = 0; while (Index < FileSize) { if (Section->Type == SectionType) { + // FIXME: Use general API (MdePkg?) with proper size checks if (IS_SECTION2 (Section)) { *SectionData = (VOID *)((UINT8 *)Section + sizeof (EFI_COMMON_SECTION_HEADER2)); + *SectionSize = CurSectionSize - sizeof (EFI_COMMON_SECTION_HEADER2); } else { *SectionData = (VOID *)((UINT8 *)Section + sizeof (EFI_COMMON_SECTION_HEADER)); + *SectionSize = CurSectionSize - sizeof (EFI_COMMON_SECTION_HEADER); } return EFI_SUCCESS; } if (IS_SECTION2 (Section)) { - SectionSize = SECTION2_SIZE (Section); + CurSectionSize = SECTION2_SIZE (Section); } else { - SectionSize = SECTION_SIZE (Section); + CurSectionSize = SECTION_SIZE (Section); } - SectionSize = GET_OCCUPIED_SIZE (SectionSize, 4); - ASSERT (SectionSize != 0); - Index += SectionSize; + CurSectionSize = GET_OCCUPIED_SIZE (CurSectionSize, 4); + ASSERT (CurSectionSize != 0); + Index += CurSectionSize; - Section = (EFI_COMMON_SECTION_HEADER *)((UINT8 *)Section + SectionSize); + Section = (EFI_COMMON_SECTION_HEADER *)((UINT8 *)Section + CurSectionSize); } return EFI_NOT_FOUND; @@ -262,10 +266,12 @@ LoadDxeCore ( EFI_STATUS Status; EFI_FIRMWARE_VOLUME_HEADER *PayloadFv; EFI_FIRMWARE_VOLUME_HEADER *DxeCoreFv; + UINT32 DxeCoreFvSize; EFI_FFS_FILE_HEADER *FileHeader; - VOID *PeCoffImage; + VOID *UefiImage; + UINT32 UefiImageSize; EFI_PHYSICAL_ADDRESS ImageAddress; - UINT64 ImageSize; + UINT64 DestinationSize; PayloadFv = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)PcdGet32 (PcdPayloadFdMemBase); @@ -277,7 +283,7 @@ LoadDxeCore ( return Status; } - Status = FileFindSection (FileHeader, EFI_SECTION_FIRMWARE_VOLUME_IMAGE, (VOID **)&DxeCoreFv); + Status = FileFindSection (FileHeader, EFI_SECTION_FIRMWARE_VOLUME_IMAGE, (VOID **)&DxeCoreFv, &DxeCoreFvSize); if (EFI_ERROR (Status)) { return Status; } @@ -295,7 +301,7 @@ LoadDxeCore ( return Status; } - Status = FileFindSection (FileHeader, EFI_SECTION_PE32, (VOID **)&PeCoffImage); + Status = FileFindSection (FileHeader, EFI_SECTION_PE32, (VOID **)&UefiImage, &UefiImageSize); if (EFI_ERROR (Status)) { return Status; } @@ -303,12 +309,12 @@ LoadDxeCore ( // // Get DXE core info // - Status = LoadPeCoffImage (PeCoffImage, &ImageAddress, &ImageSize, DxeCoreEntryPoint); + Status = LoadUefiImage (UefiImage, UefiImageSize, &ImageAddress, &DestinationSize, DxeCoreEntryPoint); if (EFI_ERROR (Status)) { return Status; } - BuildModuleHob (&FileHeader->Name, ImageAddress, EFI_SIZE_TO_PAGES ((UINT32)ImageSize) * EFI_PAGE_SIZE, *DxeCoreEntryPoint); + BuildModuleHob (&FileHeader->Name, ImageAddress, DestinationSize, *DxeCoreEntryPoint); return EFI_SUCCESS; } @@ -330,7 +336,8 @@ UniversalLoadDxeCore ( { EFI_STATUS Status; EFI_FFS_FILE_HEADER *FileHeader; - VOID *PeCoffImage; + VOID *UefiImage; + UINT32 UefiImageSize; EFI_PHYSICAL_ADDRESS ImageAddress; UINT64 ImageSize; @@ -342,7 +349,7 @@ UniversalLoadDxeCore ( return Status; } - Status = FileFindSection (FileHeader, EFI_SECTION_PE32, (VOID **)&PeCoffImage); + Status = FileFindSection (FileHeader, EFI_SECTION_PE32, (VOID **)&UefiImage, &UefiImageSize); if (EFI_ERROR (Status)) { return Status; } @@ -350,7 +357,7 @@ UniversalLoadDxeCore ( // // Get DXE core info // - Status = LoadPeCoffImage (PeCoffImage, &ImageAddress, &ImageSize, DxeCoreEntryPoint); + Status = LoadUefiImage (UefiImage, UefiImageSize, &ImageAddress, &ImageSize, DxeCoreEntryPoint); if (EFI_ERROR (Status)) { return Status; } diff --git a/UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.h b/UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.h index 80ccc5072c..1cc05c87b9 100644 --- a/UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.h +++ b/UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.h @@ -15,12 +15,12 @@ #include #include #include -#include +#include #include #include #include #include -#include +#include #include #include #include @@ -170,7 +170,8 @@ EFI_STATUS FileFindSection ( IN EFI_FFS_FILE_HEADER *FileHeader, IN EFI_SECTION_TYPE SectionType, - OUT VOID **SectionData + OUT VOID **SectionData, + OUT UINT32 *SectionSize ); /** diff --git a/UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.inf b/UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.inf index a3ff4b86ea..9167850ce4 100644 --- a/UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.inf +++ b/UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.inf @@ -24,7 +24,6 @@ [Sources] UefiPayloadEntry.c LoadDxeCore.c - MemoryAllocation.c AcpiTable.c [Sources.Ia32] @@ -52,9 +51,10 @@ IoLib BlParseLib HobLib - PeCoffLib + UefiImageLib PlatformSupportLib CpuLib + MemoryAllocationLib [Guids] gEfiMemoryTypeInformationGuid @@ -95,4 +95,3 @@ gEfiMdeModulePkgTokenSpaceGuid.PcdSetNxForStack ## SOMETIMES_CONSUMES gEfiMdeModulePkgTokenSpaceGuid.PcdDxeNxMemoryProtectionPolicy ## SOMETIMES_CONSUMES gEfiMdeModulePkgTokenSpaceGuid.PcdImageProtectionPolicy ## SOMETIMES_CONSUMES - diff --git a/UefiPayloadPkg/UefiPayloadEntry/UniversalPayloadEntry.c b/UefiPayloadPkg/UefiPayloadEntry/UniversalPayloadEntry.c index f37c00fad7..5eac470f3f 100644 --- a/UefiPayloadPkg/UefiPayloadEntry/UniversalPayloadEntry.c +++ b/UefiPayloadPkg/UefiPayloadEntry/UniversalPayloadEntry.c @@ -54,6 +54,7 @@ FixUpPcdDatabase ( EFI_STATUS Status; EFI_FFS_FILE_HEADER *FileHeader; VOID *PcdRawData; + UINT32 PcdRawSize; PEI_PCD_DATABASE *PeiDatabase; PEI_PCD_DATABASE *UplDatabase; EFI_HOB_GUID_TYPE *GuidHob; @@ -77,7 +78,7 @@ FixUpPcdDatabase ( return Status; } - Status = FileFindSection (FileHeader, EFI_SECTION_RAW, &PcdRawData); + Status = FileFindSection (FileHeader, EFI_SECTION_RAW, &PcdRawData, &PcdRawSize); ASSERT_EFI_ERROR (Status); if (EFI_ERROR (Status)) { return Status; diff --git a/UefiPayloadPkg/UefiPayloadEntry/UniversalPayloadEntry.inf b/UefiPayloadPkg/UefiPayloadEntry/UniversalPayloadEntry.inf index a62da5c705..388dbf397e 100644 --- a/UefiPayloadPkg/UefiPayloadEntry/UniversalPayloadEntry.inf +++ b/UefiPayloadPkg/UefiPayloadEntry/UniversalPayloadEntry.inf @@ -51,8 +51,8 @@ SerialPortLib IoLib HobLib - PeCoffLib CpuLib + UefiImageLib [Guids] gEfiMemoryTypeInformationGuid @@ -94,4 +94,3 @@ gEfiMdeModulePkgTokenSpaceGuid.PcdSetNxForStack ## SOMETIMES_CONSUMES gEfiMdeModulePkgTokenSpaceGuid.PcdDxeNxMemoryProtectionPolicy ## SOMETIMES_CONSUMES gEfiMdeModulePkgTokenSpaceGuid.PcdImageProtectionPolicy ## SOMETIMES_CONSUMES - diff --git a/UefiPayloadPkg/UefiPayloadPkg.dsc b/UefiPayloadPkg/UefiPayloadPkg.dsc index 2860a659f6..d6c5c2e0e2 100644 --- a/UefiPayloadPkg/UefiPayloadPkg.dsc +++ b/UefiPayloadPkg/UefiPayloadPkg.dsc @@ -210,8 +210,8 @@ !endif PciSegmentLib|MdePkg/Library/PciSegmentLibSegmentInfo/BasePciSegmentLibSegmentInfo.inf PciSegmentInfoLib|UefiPayloadPkg/Library/PciSegmentInfoLibAcpiBoardInfo/PciSegmentInfoLibAcpiBoardInfo.inf - PeCoffLib|MdePkg/Library/BasePeCoffLib/BasePeCoffLib.inf - PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf + PeCoffLib2|MdePkg/Library/BasePeCoffLib2/BasePeCoffLib2.inf + UefiImageLib|MdePkg/Library/BaseUefiImageLib/BaseUefiImageLibPeCoff.inf CacheMaintenanceLib|MdePkg/Library/BaseCacheMaintenanceLib/BaseCacheMaintenanceLib.inf SafeIntLib|MdePkg/Library/BaseSafeIntLib/BaseSafeIntLib.inf DxeHobListLib|UefiPayloadPkg/Library/DxeHobListLib/DxeHobListLib.inf @@ -281,10 +281,10 @@ PerformanceLib|MdePkg/Library/BasePerformanceLibNull/BasePerformanceLibNull.inf ImagePropertiesRecordLib|MdeModulePkg/Library/ImagePropertiesRecordLib/ImagePropertiesRecordLib.inf !if $(SOURCE_DEBUG_ENABLE) == TRUE - PeCoffExtraActionLib|SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLibDebug.inf + UefiImageExtraActionLib|SourceLevelDebugPkg/Library/UefiImageExtraActionLibDebug/UefiImageExtraActionLibDebug.inf DebugCommunicationLib|SourceLevelDebugPkg/Library/DebugCommunicationLibSerialPort/DebugCommunicationLibSerialPort.inf !else - PeCoffExtraActionLib|MdePkg/Library/BasePeCoffExtraActionLibNull/BasePeCoffExtraActionLibNull.inf + UefiImageExtraActionLib|MdePkg/Library/BaseUefiImageExtraActionLibNull/BaseUefiImageExtraActionLibNull.inf DebugAgentLib|MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.inf !endif PlatformSupportLib|UefiPayloadPkg/Library/PlatformSupportLibNull/PlatformSupportLibNull.inf @@ -348,6 +348,7 @@ !if $(MULTIPLE_DEBUG_PORT_SUPPORT) == TRUE SerialPortLib|UefiPayloadPkg/Library/BaseSerialPortLibHob/BaseSerialPortLibHob.inf !endif + MemoryAllocationLib|UefiPayloadPkg/Library/UefiPayloadEntryMemoryAllocationLib/UefiPayloadEntryMemoryAllocationLib.inf [LibraryClasses.common.DXE_CORE] DxeHobListLib|UefiPayloadPkg/Library/DxeHobListLibNull/DxeHobListLibNull.inf