summaryrefslogtreecommitdiff
path: root/Core/MdeModulePkg/Library
diff options
context:
space:
mode:
Diffstat (limited to 'Core/MdeModulePkg/Library')
-rw-r--r--Core/MdeModulePkg/Library/AuthVariableLibNull/AuthVariableLibNull.c78
-rw-r--r--Core/MdeModulePkg/Library/AuthVariableLibNull/AuthVariableLibNull.inf40
-rw-r--r--Core/MdeModulePkg/Library/AuthVariableLibNull/AuthVariableLibNull.unibin0 -> 1710 bytes
-rw-r--r--Core/MdeModulePkg/Library/BaseIpmiLibNull/BaseIpmiLibNull.c53
-rw-r--r--Core/MdeModulePkg/Library/BaseIpmiLibNull/BaseIpmiLibNull.inf38
-rw-r--r--Core/MdeModulePkg/Library/BasePlatformHookLibNull/BasePlatformHookLibNull.c37
-rw-r--r--Core/MdeModulePkg/Library/BasePlatformHookLibNull/BasePlatformHookLibNull.inf35
-rw-r--r--Core/MdeModulePkg/Library/BasePlatformHookLibNull/BasePlatformHookLibNull.unibin0 -> 1644 bytes
-rw-r--r--Core/MdeModulePkg/Library/BaseResetSystemLibNull/BaseResetSystemLibNull.c79
-rw-r--r--Core/MdeModulePkg/Library/BaseResetSystemLibNull/BaseResetSystemLibNull.inf38
-rw-r--r--Core/MdeModulePkg/Library/BaseResetSystemLibNull/BaseResetSystemLibNull.unibin0 -> 1956 bytes
-rw-r--r--Core/MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.c1100
-rw-r--r--Core/MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.inf48
-rw-r--r--Core/MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.unibin0 -> 1672 bytes
-rw-r--r--Core/MdeModulePkg/Library/BaseSortLib/BaseSortLib.c238
-rw-r--r--Core/MdeModulePkg/Library/BaseSortLib/BaseSortLib.inf40
-rw-r--r--Core/MdeModulePkg/Library/BaseSortLib/BaseSortLib.unibin0 -> 1582 bytes
-rw-r--r--Core/MdeModulePkg/Library/CpuExceptionHandlerLibNull/CpuExceptionHandlerLibNull.c99
-rw-r--r--Core/MdeModulePkg/Library/CpuExceptionHandlerLibNull/CpuExceptionHandlerLibNull.inf36
-rw-r--r--Core/MdeModulePkg/Library/CpuExceptionHandlerLibNull/CpuExceptionHandlerLibNull.unibin0 -> 1902 bytes
-rw-r--r--Core/MdeModulePkg/Library/CustomizedDisplayLib/Colors.h44
-rw-r--r--Core/MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.c958
-rw-r--r--Core/MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.inf65
-rw-r--r--Core/MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.unibin0 -> 7256 bytes
-rw-r--r--Core/MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLibInternal.c984
-rw-r--r--Core/MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLibInternal.h297
-rw-r--r--Core/MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLibModStrs.unibin0 -> 1678 bytes
-rw-r--r--Core/MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.c72
-rw-r--r--Core/MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.inf36
-rw-r--r--Core/MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.unibin0 -> 1820 bytes
-rw-r--r--Core/MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.c51
-rw-r--r--Core/MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.inf38
-rw-r--r--Core/MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.unibin0 -> 1692 bytes
-rw-r--r--Core/MdeModulePkg/Library/DxeCoreMemoryAllocationLib/DxeCoreMemoryAllocationLib.inf46
-rw-r--r--Core/MdeModulePkg/Library/DxeCoreMemoryAllocationLib/DxeCoreMemoryAllocationLib.unibin0 -> 2582 bytes
-rw-r--r--Core/MdeModulePkg/Library/DxeCoreMemoryAllocationLib/DxeCoreMemoryAllocationServices.h106
-rw-r--r--Core/MdeModulePkg/Library/DxeCoreMemoryAllocationLib/MemoryAllocationLib.c823
-rw-r--r--Core/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.c847
-rw-r--r--Core/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.inf70
-rw-r--r--Core/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.unibin0 -> 4064 bytes
-rw-r--r--Core/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLibInternal.h233
-rw-r--r--Core/MdeModulePkg/Library/DxeCrc32GuidedSectionExtractLib/DxeCrc32GuidedSectionExtractLib.c236
-rw-r--r--Core/MdeModulePkg/Library/DxeCrc32GuidedSectionExtractLib/DxeCrc32GuidedSectionExtractLib.inf55
-rw-r--r--Core/MdeModulePkg/Library/DxeCrc32GuidedSectionExtractLib/DxeCrc32GuidedSectionExtractLib.unibin0 -> 2708 bytes
-rw-r--r--Core/MdeModulePkg/Library/DxeDebugPrintErrorLevelLib/DxeDebugPrintErrorLevelLib.c388
-rw-r--r--Core/MdeModulePkg/Library/DxeDebugPrintErrorLevelLib/DxeDebugPrintErrorLevelLib.inf54
-rw-r--r--Core/MdeModulePkg/Library/DxeDebugPrintErrorLevelLib/DxeDebugPrintErrorLevelLib.unibin0 -> 2474 bytes
-rw-r--r--Core/MdeModulePkg/Library/DxeDpcLib/DpcLib.c100
-rw-r--r--Core/MdeModulePkg/Library/DxeDpcLib/DxeDpcLib.inf46
-rw-r--r--Core/MdeModulePkg/Library/DxeDpcLib/DxeDpcLib.unibin0 -> 1932 bytes
-rw-r--r--Core/MdeModulePkg/Library/DxeHttpLib/DxeHttpLib.c1427
-rw-r--r--Core/MdeModulePkg/Library/DxeHttpLib/DxeHttpLib.inf42
-rw-r--r--Core/MdeModulePkg/Library/DxeHttpLib/DxeHttpLib.unibin0 -> 1862 bytes
-rw-r--r--Core/MdeModulePkg/Library/DxeIpIoLib/DxeIpIoLib.c2150
-rw-r--r--Core/MdeModulePkg/Library/DxeIpIoLib/DxeIpIoLib.inf53
-rw-r--r--Core/MdeModulePkg/Library/DxeIpIoLib/DxeIpIoLib.unibin0 -> 1868 bytes
-rw-r--r--Core/MdeModulePkg/Library/DxeIpmiLibIpmiProtocol/DxeIpmiLibIpmiProtocol.c81
-rw-r--r--Core/MdeModulePkg/Library/DxeIpmiLibIpmiProtocol/DxeIpmiLibIpmiProtocol.inf40
-rw-r--r--Core/MdeModulePkg/Library/DxeNetLib/DxeNetLib.c3334
-rw-r--r--Core/MdeModulePkg/Library/DxeNetLib/DxeNetLib.inf65
-rw-r--r--Core/MdeModulePkg/Library/DxeNetLib/DxeNetLib.unibin0 -> 1788 bytes
-rw-r--r--Core/MdeModulePkg/Library/DxeNetLib/NetBuffer.c1892
-rw-r--r--Core/MdeModulePkg/Library/DxePerformanceLib/DxePerformanceLib.c429
-rw-r--r--Core/MdeModulePkg/Library/DxePerformanceLib/DxePerformanceLib.inf57
-rw-r--r--Core/MdeModulePkg/Library/DxePerformanceLib/DxePerformanceLib.unibin0 -> 2782 bytes
-rw-r--r--Core/MdeModulePkg/Library/DxePrintLibPrint2Protocol/DxePrintLibPrint2Protocol.inf41
-rw-r--r--Core/MdeModulePkg/Library/DxePrintLibPrint2Protocol/DxePrintLibPrint2Protocol.unibin0 -> 2064 bytes
-rw-r--r--Core/MdeModulePkg/Library/DxePrintLibPrint2Protocol/PrintLib.c1921
-rw-r--r--Core/MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.inf57
-rw-r--r--Core/MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.unibin0 -> 1708 bytes
-rw-r--r--Core/MdeModulePkg/Library/DxeReportStatusCodeLib/ReportStatusCodeLib.c631
-rw-r--r--Core/MdeModulePkg/Library/DxeSecurityManagementLib/DxeSecurityManagementLib.c533
-rw-r--r--Core/MdeModulePkg/Library/DxeSecurityManagementLib/DxeSecurityManagementLib.inf48
-rw-r--r--Core/MdeModulePkg/Library/DxeSecurityManagementLib/DxeSecurityManagementLib.unibin0 -> 1892 bytes
-rw-r--r--Core/MdeModulePkg/Library/DxeSmmPerformanceLib/DxeSmmPerformanceLib.c866
-rw-r--r--Core/MdeModulePkg/Library/DxeSmmPerformanceLib/DxeSmmPerformanceLib.inf68
-rw-r--r--Core/MdeModulePkg/Library/DxeSmmPerformanceLib/DxeSmmPerformanceLib.unibin0 -> 2598 bytes
-rw-r--r--Core/MdeModulePkg/Library/DxeTcpIoLib/DxeTcpIoLib.c1007
-rw-r--r--Core/MdeModulePkg/Library/DxeTcpIoLib/DxeTcpIoLib.inf51
-rw-r--r--Core/MdeModulePkg/Library/DxeTcpIoLib/DxeTcpIoLib.unibin0 -> 1908 bytes
-rw-r--r--Core/MdeModulePkg/Library/DxeUdpIoLib/DxeUdpIoLib.c1067
-rw-r--r--Core/MdeModulePkg/Library/DxeUdpIoLib/DxeUdpIoLib.inf53
-rw-r--r--Core/MdeModulePkg/Library/DxeUdpIoLib/DxeUpdIoLib.unibin0 -> 1988 bytes
-rw-r--r--Core/MdeModulePkg/Library/LockBoxNullLib/LockBoxNullLib.c139
-rw-r--r--Core/MdeModulePkg/Library/LockBoxNullLib/LockBoxNullLib.inf39
-rw-r--r--Core/MdeModulePkg/Library/LockBoxNullLib/LockBoxNullLib.unibin0 -> 1616 bytes
-rw-r--r--Core/MdeModulePkg/Library/LzmaCustomDecompressLib/F86GuidedSectionExtraction.c218
-rw-r--r--Core/MdeModulePkg/Library/LzmaCustomDecompressLib/GuidedSectionExtraction.c201
-rw-r--r--Core/MdeModulePkg/Library/LzmaCustomDecompressLib/LZMA-SDK-README.txt4
-rw-r--r--Core/MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaArchCustomDecompressLib.inf66
-rw-r--r--Core/MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaArchDecompressLib.unibin0 -> 2480 bytes
-rw-r--r--Core/MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaCustomDecompressLib.inf62
-rw-r--r--Core/MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaDecompress.c220
-rw-r--r--Core/MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaDecompressLib.unibin0 -> 2274 bytes
-rw-r--r--Core/MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaDecompressLibInternal.h96
-rw-r--r--Core/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/7zVersion.h7
-rw-r--r--Core/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/Bra.h60
-rw-r--r--Core/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/Bra86.c85
-rw-r--r--Core/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/CpuArch.h69
-rw-r--r--Core/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/LzFind.c770
-rw-r--r--Core/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/LzFind.h107
-rw-r--r--Core/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/LzHash.h54
-rw-r--r--Core/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/LzmaDec.c1026
-rw-r--r--Core/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/LzmaDec.h223
-rw-r--r--Core/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/Types.h231
-rw-r--r--Core/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/history.txt236
-rw-r--r--Core/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/lzma.txt594
-rw-r--r--Core/MdeModulePkg/Library/LzmaCustomDecompressLib/UefiLzma.h47
-rw-r--r--Core/MdeModulePkg/Library/OemHookStatusCodeLibNull/OemHookStatusCodeLibNull.c62
-rw-r--r--Core/MdeModulePkg/Library/OemHookStatusCodeLibNull/OemHookStatusCodeLibNull.inf35
-rw-r--r--Core/MdeModulePkg/Library/OemHookStatusCodeLibNull/OemHookStatusCodeLibNull.unibin0 -> 1892 bytes
-rw-r--r--Core/MdeModulePkg/Library/PciHostBridgeLibNull/PciHostBridgeLibNull.c115
-rw-r--r--Core/MdeModulePkg/Library/PciHostBridgeLibNull/PciHostBridgeLibNull.inf38
-rw-r--r--Core/MdeModulePkg/Library/PciHostBridgeLibNull/PciHostBridgeLibNull.uni20
-rw-r--r--Core/MdeModulePkg/Library/PeiCrc32GuidedSectionExtractLib/PeiCrc32GuidedSectionExtractLib.c312
-rw-r--r--Core/MdeModulePkg/Library/PeiCrc32GuidedSectionExtractLib/PeiCrc32GuidedSectionExtractLib.inf48
-rw-r--r--Core/MdeModulePkg/Library/PeiCrc32GuidedSectionExtractLib/PeiCrc32GuidedSectionExtractLib.unibin0 -> 2390 bytes
-rw-r--r--Core/MdeModulePkg/Library/PeiDebugPrintHobLib/PeiDebugPrintHobLib.c78
-rw-r--r--Core/MdeModulePkg/Library/PeiDebugPrintHobLib/PeiDebugPrintHobLib.inf50
-rw-r--r--Core/MdeModulePkg/Library/PeiDebugPrintHobLib/PeiDebugPrintHobLib.unibin0 -> 2076 bytes
-rw-r--r--Core/MdeModulePkg/Library/PeiDxeDebugLibReportStatusCode/DebugLib.c461
-rw-r--r--Core/MdeModulePkg/Library/PeiDxeDebugLibReportStatusCode/PeiDxeDebugLibReportStatusCode.inf54
-rw-r--r--Core/MdeModulePkg/Library/PeiDxeDebugLibReportStatusCode/PeiDxeDebugLibReportStatusCode.unibin0 -> 1896 bytes
-rw-r--r--Core/MdeModulePkg/Library/PeiIpmiLibIpmiPpi/PeiIpmiLibIpmiPpi.c81
-rw-r--r--Core/MdeModulePkg/Library/PeiIpmiLibIpmiPpi/PeiIpmiLibIpmiPpi.inf41
-rw-r--r--Core/MdeModulePkg/Library/PeiPerformanceLib/PeiPerformanceLib.c494
-rw-r--r--Core/MdeModulePkg/Library/PeiPerformanceLib/PeiPerformanceLib.inf62
-rw-r--r--Core/MdeModulePkg/Library/PeiPerformanceLib/PeiPerformanceLib.unibin0 -> 2504 bytes
-rw-r--r--Core/MdeModulePkg/Library/PeiRecoveryLibNull/PeiRecoveryLibNull.c34
-rw-r--r--Core/MdeModulePkg/Library/PeiRecoveryLibNull/PeiRecoveryLibNull.inf39
-rw-r--r--Core/MdeModulePkg/Library/PeiRecoveryLibNull/PeiRecoveryLibNull.unibin0 -> 2246 bytes
-rw-r--r--Core/MdeModulePkg/Library/PeiReportStatusCodeLib/PeiReportStatusCodeLib.inf59
-rw-r--r--Core/MdeModulePkg/Library/PeiReportStatusCodeLib/PeiReportStatusCodeLib.unibin0 -> 2416 bytes
-rw-r--r--Core/MdeModulePkg/Library/PeiReportStatusCodeLib/ReportStatusCodeLib.c560
-rw-r--r--Core/MdeModulePkg/Library/PeiS3LibNull/PeiS3LibNull.c35
-rw-r--r--Core/MdeModulePkg/Library/PeiS3LibNull/PeiS3LibNull.inf40
-rw-r--r--Core/MdeModulePkg/Library/PeiS3LibNull/PeiS3LibNull.unibin0 -> 2200 bytes
-rw-r--r--Core/MdeModulePkg/Library/PiDxeS3BootScriptLib/BootScriptExecute.c1792
-rw-r--r--Core/MdeModulePkg/Library/PiDxeS3BootScriptLib/BootScriptInternalFormat.h188
-rw-r--r--Core/MdeModulePkg/Library/PiDxeS3BootScriptLib/BootScriptSave.c2358
-rw-r--r--Core/MdeModulePkg/Library/PiDxeS3BootScriptLib/DxeS3BootScriptLib.inf74
-rw-r--r--Core/MdeModulePkg/Library/PiDxeS3BootScriptLib/DxeS3BootScriptLib.unibin0 -> 1794 bytes
-rw-r--r--Core/MdeModulePkg/Library/PiDxeS3BootScriptLib/InternalBootScriptLib.h110
-rw-r--r--Core/MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/MemoryAllocationLib.c929
-rw-r--r--Core/MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/PiSmmCoreMemoryAllocationLib.inf48
-rw-r--r--Core/MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/PiSmmCoreMemoryAllocationLib.unibin0 -> 2634 bytes
-rw-r--r--Core/MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/PiSmmCoreMemoryAllocationServices.h191
-rw-r--r--Core/MdeModulePkg/Library/PiSmmCoreSmmServicesTableLib/PiSmmCoreSmmServicesTableLib.c60
-rw-r--r--Core/MdeModulePkg/Library/PiSmmCoreSmmServicesTableLib/PiSmmCoreSmmServicesTableLib.inf36
-rw-r--r--Core/MdeModulePkg/Library/PiSmmCoreSmmServicesTableLib/PiSmmCoreSmmServicesTableLib.unibin0 -> 1644 bytes
-rw-r--r--Core/MdeModulePkg/Library/PlatformBootManagerLibNull/PlatformBootManager.c67
-rw-r--r--Core/MdeModulePkg/Library/PlatformBootManagerLibNull/PlatformBootManagerLibNull.inf37
-rw-r--r--Core/MdeModulePkg/Library/PlatformBootManagerLibNull/PlatformBootManagerLibNull.unibin0 -> 1756 bytes
-rw-r--r--Core/MdeModulePkg/Library/PlatformHookLibSerialPortPpi/PlatformHookLibSerialPortPpi.c36
-rw-r--r--Core/MdeModulePkg/Library/PlatformHookLibSerialPortPpi/PlatformHookLibSerialPortPpi.inf38
-rw-r--r--Core/MdeModulePkg/Library/PlatformHookLibSerialPortPpi/PlatformHookLibSerialPortPpi.unibin0 -> 2256 bytes
-rw-r--r--Core/MdeModulePkg/Library/PlatformVarCleanupLib/PlatVarCleanup.h108
-rw-r--r--Core/MdeModulePkg/Library/PlatformVarCleanupLib/PlatVarCleanup.vfr41
-rw-r--r--Core/MdeModulePkg/Library/PlatformVarCleanupLib/PlatVarCleanupHii.h59
-rw-r--r--Core/MdeModulePkg/Library/PlatformVarCleanupLib/PlatVarCleanupLib.c1250
-rw-r--r--Core/MdeModulePkg/Library/PlatformVarCleanupLib/PlatformVarCleanupLib.inf73
-rw-r--r--Core/MdeModulePkg/Library/PlatformVarCleanupLib/PlatformVarCleanupLib.unibin0 -> 1766 bytes
-rw-r--r--Core/MdeModulePkg/Library/PlatformVarCleanupLib/VfrStrings.unibin0 -> 4528 bytes
-rw-r--r--Core/MdeModulePkg/Library/RuntimeDxeReportStatusCodeLib/ReportStatusCodeLib.c754
-rw-r--r--Core/MdeModulePkg/Library/RuntimeDxeReportStatusCodeLib/RuntimeDxeReportStatusCodeLib.inf59
-rw-r--r--Core/MdeModulePkg/Library/RuntimeDxeReportStatusCodeLib/RuntimeDxeReportStatusCodeLib.unibin0 -> 1990 bytes
-rw-r--r--Core/MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLib.c1099
-rw-r--r--Core/MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLib.inf73
-rw-r--r--Core/MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLib.unibin0 -> 3528 bytes
-rw-r--r--Core/MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLibInternal.h236
-rw-r--r--Core/MdeModulePkg/Library/SmmCorePlatformHookLibNull/SmmCorePlatformHookLibNull.c52
-rw-r--r--Core/MdeModulePkg/Library/SmmCorePlatformHookLibNull/SmmCorePlatformHookLibNull.inf36
-rw-r--r--Core/MdeModulePkg/Library/SmmCorePlatformHookLibNull/SmmCorePlatformHookLibNull.unibin0 -> 1710 bytes
-rw-r--r--Core/MdeModulePkg/Library/SmmIpmiLibSmmIpmiProtocol/SmmIpmiLibSmmIpmiProtocol.c82
-rw-r--r--Core/MdeModulePkg/Library/SmmIpmiLibSmmIpmiProtocol/SmmIpmiLibSmmIpmiProtocol.inf40
-rw-r--r--Core/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.c455
-rw-r--r--Core/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.inf50
-rw-r--r--Core/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.unibin0 -> 1608 bytes
-rw-r--r--Core/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxLibPrivate.h54
-rw-r--r--Core/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.c741
-rw-r--r--Core/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.inf59
-rw-r--r--Core/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.unibin0 -> 1608 bytes
-rw-r--r--Core/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.c591
-rw-r--r--Core/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.inf50
-rw-r--r--Core/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.unibin0 -> 1608 bytes
-rw-r--r--Core/MdeModulePkg/Library/SmmPerformanceLib/SmmPerformanceLib.c451
-rw-r--r--Core/MdeModulePkg/Library/SmmPerformanceLib/SmmPerformanceLib.inf57
-rw-r--r--Core/MdeModulePkg/Library/SmmPerformanceLib/SmmPerformanceLib.unibin0 -> 2848 bytes
-rw-r--r--Core/MdeModulePkg/Library/SmmReportStatusCodeLib/ReportStatusCodeLib.c545
-rw-r--r--Core/MdeModulePkg/Library/SmmReportStatusCodeLib/SmmReportStatusCodeLib.inf56
-rw-r--r--Core/MdeModulePkg/Library/SmmReportStatusCodeLib/SmmReportStatusCodeLib.unibin0 -> 1718 bytes
-rw-r--r--Core/MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.c45
-rw-r--r--Core/MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.inf34
-rw-r--r--Core/MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.unibin0 -> 1654 bytes
-rw-r--r--Core/MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c2351
-rw-r--r--Core/MdeModulePkg/Library/UefiBootManagerLib/BmConnect.c321
-rw-r--r--Core/MdeModulePkg/Library/UefiBootManagerLib/BmConsole.c764
-rw-r--r--Core/MdeModulePkg/Library/UefiBootManagerLib/BmDriverHealth.c576
-rw-r--r--Core/MdeModulePkg/Library/UefiBootManagerLib/BmHotkey.c1101
-rw-r--r--Core/MdeModulePkg/Library/UefiBootManagerLib/BmLoadOption.c1253
-rw-r--r--Core/MdeModulePkg/Library/UefiBootManagerLib/BmMisc.c391
-rw-r--r--Core/MdeModulePkg/Library/UefiBootManagerLib/BmPerformance.c317
-rw-r--r--Core/MdeModulePkg/Library/UefiBootManagerLib/InternalBm.h454
-rw-r--r--Core/MdeModulePkg/Library/UefiBootManagerLib/UefiBootManagerLib.inf117
-rw-r--r--Core/MdeModulePkg/Library/UefiBootManagerLib/UefiBootManagerLib.unibin0 -> 2378 bytes
-rw-r--r--Core/MdeModulePkg/Library/UefiHiiLib/HiiLanguage.c96
-rw-r--r--Core/MdeModulePkg/Library/UefiHiiLib/HiiLib.c4231
-rw-r--r--Core/MdeModulePkg/Library/UefiHiiLib/HiiString.c355
-rw-r--r--Core/MdeModulePkg/Library/UefiHiiLib/InternalHiiLib.h34
-rw-r--r--Core/MdeModulePkg/Library/UefiHiiLib/UefiHiiLib.inf53
-rw-r--r--Core/MdeModulePkg/Library/UefiHiiLib/UefiHiiLib.unibin0 -> 1886 bytes
-rw-r--r--Core/MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.c113
-rw-r--r--Core/MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.inf67
-rw-r--r--Core/MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.unibin0 -> 1686 bytes
-rw-r--r--Core/MdeModulePkg/Library/UefiSortLib/UefiSortLib.c322
-rw-r--r--Core/MdeModulePkg/Library/UefiSortLib/UefiSortLib.inf47
-rw-r--r--Core/MdeModulePkg/Library/UefiSortLib/UefiSortLib.unibin0 -> 1582 bytes
-rw-r--r--Core/MdeModulePkg/Library/VarCheckHiiLib/InternalVarCheckStructure.h82
-rw-r--r--Core/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHii.h63
-rw-r--r--Core/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiGen.c1483
-rw-r--r--Core/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiGen.h136
-rw-r--r--Core/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiGenFromFv.c443
-rw-r--r--Core/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiGenFromHii.c73
-rw-r--r--Core/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLib.inf58
-rw-r--r--Core/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLib.unibin0 -> 1766 bytes
-rw-r--r--Core/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLibNullClass.c539
-rw-r--r--Core/MdeModulePkg/Library/VarCheckLib/VarCheckLib.c663
-rw-r--r--Core/MdeModulePkg/Library/VarCheckLib/VarCheckLib.inf51
-rw-r--r--Core/MdeModulePkg/Library/VarCheckLib/VarCheckLib.unibin0 -> 1798 bytes
-rw-r--r--Core/MdeModulePkg/Library/VarCheckPcdLib/VarCheckPcdLib.inf65
-rw-r--r--Core/MdeModulePkg/Library/VarCheckPcdLib/VarCheckPcdLib.unibin0 -> 1766 bytes
-rw-r--r--Core/MdeModulePkg/Library/VarCheckPcdLib/VarCheckPcdLibNullClass.c474
-rw-r--r--Core/MdeModulePkg/Library/VarCheckPcdLib/VarCheckPcdStructure.h76
-rw-r--r--Core/MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLib.inf88
-rw-r--r--Core/MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLib.unibin0 -> 2158 bytes
-rw-r--r--Core/MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLibNullClass.c930
236 files changed, 61994 insertions, 0 deletions
diff --git a/Core/MdeModulePkg/Library/AuthVariableLibNull/AuthVariableLibNull.c b/Core/MdeModulePkg/Library/AuthVariableLibNull/AuthVariableLibNull.c
new file mode 100644
index 0000000000..054131fd3e
--- /dev/null
+++ b/Core/MdeModulePkg/Library/AuthVariableLibNull/AuthVariableLibNull.c
@@ -0,0 +1,78 @@
+/** @file
+ Implements NULL authenticated variable services.
+
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Library/AuthVariableLib.h>
+#include <Library/DebugLib.h>
+
+/**
+ Initialization for authenticated varibale services.
+ If this initialization returns error status, other APIs will not work
+ and expect to be not called then.
+
+ @param[in] AuthVarLibContextIn Pointer to input auth variable lib context.
+ @param[out] AuthVarLibContextOut Pointer to output auth variable lib context.
+
+ @retval EFI_SUCCESS Function successfully executed.
+ @retval EFI_INVALID_PARAMETER If AuthVarLibContextIn == NULL or AuthVarLibContextOut == NULL.
+ @retval EFI_OUT_OF_RESOURCES Fail to allocate enough resource.
+ @retval EFI_UNSUPPORTED Unsupported to process authenticated variable.
+
+**/
+EFI_STATUS
+EFIAPI
+AuthVariableLibInitialize (
+ IN AUTH_VAR_LIB_CONTEXT_IN *AuthVarLibContextIn,
+ OUT AUTH_VAR_LIB_CONTEXT_OUT *AuthVarLibContextOut
+ )
+{
+ //
+ // Do nothing, just return EFI_UNSUPPORTED.
+ //
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Process variable with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS/EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set.
+
+ @param[in] VariableName Name of the variable.
+ @param[in] VendorGuid Variable vendor GUID.
+ @param[in] Data Data pointer.
+ @param[in] DataSize Size of Data.
+ @param[in] Attributes Attribute value of the variable.
+
+ @retval EFI_SUCCESS The firmware has successfully stored the variable and its data as
+ defined by the Attributes.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_WRITE_PROTECTED Variable is write-protected.
+ @retval EFI_OUT_OF_RESOURCES There is not enough resource.
+ @retval EFI_SECURITY_VIOLATION The variable is with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
+ or EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACESS
+ set, but the AuthInfo does NOT pass the validation
+ check carried out by the firmware.
+ @retval EFI_UNSUPPORTED Unsupported to process authenticated variable.
+
+**/
+EFI_STATUS
+EFIAPI
+AuthVariableLibProcessVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN VOID *Data,
+ IN UINTN DataSize,
+ IN UINT32 Attributes
+ )
+{
+ ASSERT (FALSE);
+ return EFI_UNSUPPORTED;
+}
diff --git a/Core/MdeModulePkg/Library/AuthVariableLibNull/AuthVariableLibNull.inf b/Core/MdeModulePkg/Library/AuthVariableLibNull/AuthVariableLibNull.inf
new file mode 100644
index 0000000000..900fef5d49
--- /dev/null
+++ b/Core/MdeModulePkg/Library/AuthVariableLibNull/AuthVariableLibNull.inf
@@ -0,0 +1,40 @@
+## @file
+# Provides NULL authenticated variable services.
+#
+# Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions
+# of the BSD License which accompanies this distribution. The
+# full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = AuthVariableLibNull
+ MODULE_UNI_FILE = AuthVariableLibNull.uni
+ FILE_GUID = 435CB0E4-7C9A-4BB7-9907-8FD4643E978A
+ MODULE_TYPE = DXE_RUNTIME_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = AuthVariableLib|DXE_RUNTIME_DRIVER DXE_SMM_DRIVER
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ AuthVariableLibNull.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ DebugLib
diff --git a/Core/MdeModulePkg/Library/AuthVariableLibNull/AuthVariableLibNull.uni b/Core/MdeModulePkg/Library/AuthVariableLibNull/AuthVariableLibNull.uni
new file mode 100644
index 0000000000..02237fffe2
--- /dev/null
+++ b/Core/MdeModulePkg/Library/AuthVariableLibNull/AuthVariableLibNull.uni
Binary files differ
diff --git a/Core/MdeModulePkg/Library/BaseIpmiLibNull/BaseIpmiLibNull.c b/Core/MdeModulePkg/Library/BaseIpmiLibNull/BaseIpmiLibNull.c
new file mode 100644
index 0000000000..a7db3f13f8
--- /dev/null
+++ b/Core/MdeModulePkg/Library/BaseIpmiLibNull/BaseIpmiLibNull.c
@@ -0,0 +1,53 @@
+/** @file
+ A emptry template implementation of Ipmi Library.
+
+ Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/IpmiLib.h>
+
+
+/**
+ This service enables submitting commands via Ipmi.
+
+ @param[in] NetFunction Net function of the command.
+ @param[in] Command IPMI Command.
+ @param[in] RequestData Command Request Data.
+ @param[in] RequestDataSize Size of Command Request Data.
+ @param[out] ResponseData Command Response Data. The completion code is the first byte of response data.
+ @param[in, out] ResponseDataSize Size of Command Response Data.
+
+ @retval EFI_SUCCESS The command byte stream was successfully submit to the device and a response was successfully received.
+ @retval EFI_NOT_FOUND The command was not successfully sent to the device or a response was not successfully received from the device.
+ @retval EFI_NOT_READY Ipmi Device is not ready for Ipmi command access.
+ @retval EFI_DEVICE_ERROR Ipmi Device hardware error.
+ @retval EFI_TIMEOUT The command time out.
+ @retval EFI_UNSUPPORTED The command was not successfully sent to the device.
+ @retval EFI_OUT_OF_RESOURCES The resource allcation is out of resource or data size error.
+**/
+EFI_STATUS
+EFIAPI
+IpmiSubmitCommand (
+ IN UINT8 NetFunction,
+ IN UINT8 Command,
+ IN UINT8 *RequestData,
+ IN UINT32 RequestDataSize,
+ OUT UINT8 *ResponseData,
+ IN OUT UINT32 *ResponseDataSize
+ )
+{
+ //
+ // Do nothing, just return EFI_UNSUPPORTED.
+ //
+ return EFI_UNSUPPORTED;
+}
diff --git a/Core/MdeModulePkg/Library/BaseIpmiLibNull/BaseIpmiLibNull.inf b/Core/MdeModulePkg/Library/BaseIpmiLibNull/BaseIpmiLibNull.inf
new file mode 100644
index 0000000000..fc9d06d24b
--- /dev/null
+++ b/Core/MdeModulePkg/Library/BaseIpmiLibNull/BaseIpmiLibNull.inf
@@ -0,0 +1,38 @@
+## @file
+# Null Instance of IPMI Library.
+#
+# Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php.
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = BaseIpmiLibNull
+ FILE_GUID = 46805D61-0BB8-4680-A9BE-C96C751AB5A4
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = IpmiLib
+
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ BaseIpmiLibNull.c
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ DebugLib
diff --git a/Core/MdeModulePkg/Library/BasePlatformHookLibNull/BasePlatformHookLibNull.c b/Core/MdeModulePkg/Library/BasePlatformHookLibNull/BasePlatformHookLibNull.c
new file mode 100644
index 0000000000..bd1a31a36e
--- /dev/null
+++ b/Core/MdeModulePkg/Library/BasePlatformHookLibNull/BasePlatformHookLibNull.c
@@ -0,0 +1,37 @@
+/** @file
+ Null Platform Hook Library instance.
+
+ Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Base.h>
+#include <Library/PlatformHookLib.h>
+
+/**
+ Performs platform specific initialization required for the CPU to access
+ the hardware associated with a SerialPortLib instance. This function does
+ not intiailzie the serial port hardware itself. Instead, it initializes
+ hardware devices that are required for the CPU to access the serial port
+ hardware. This function may be called more than once.
+
+ @retval RETURN_SUCCESS The platform specific initialization succeeded.
+ @retval RETURN_DEVICE_ERROR The platform specific initialization could not be completed.
+
+**/
+RETURN_STATUS
+EFIAPI
+PlatformHookSerialPortInitialize (
+ VOID
+ )
+{
+ return RETURN_SUCCESS;
+}
+
diff --git a/Core/MdeModulePkg/Library/BasePlatformHookLibNull/BasePlatformHookLibNull.inf b/Core/MdeModulePkg/Library/BasePlatformHookLibNull/BasePlatformHookLibNull.inf
new file mode 100644
index 0000000000..6d5195576f
--- /dev/null
+++ b/Core/MdeModulePkg/Library/BasePlatformHookLibNull/BasePlatformHookLibNull.inf
@@ -0,0 +1,35 @@
+## @file
+# Null Platform Hook Library instance.
+#
+# Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = BasePlatformHookLibNull
+ MODULE_UNI_FILE = BasePlatformHookLibNull.uni
+ FILE_GUID = EBC3AEAD-CC13-49b0-A678-5BED93956955
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = PlatformHookLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ BasePlatformHookLibNull.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
diff --git a/Core/MdeModulePkg/Library/BasePlatformHookLibNull/BasePlatformHookLibNull.uni b/Core/MdeModulePkg/Library/BasePlatformHookLibNull/BasePlatformHookLibNull.uni
new file mode 100644
index 0000000000..b45b1ae3ce
--- /dev/null
+++ b/Core/MdeModulePkg/Library/BasePlatformHookLibNull/BasePlatformHookLibNull.uni
Binary files differ
diff --git a/Core/MdeModulePkg/Library/BaseResetSystemLibNull/BaseResetSystemLibNull.c b/Core/MdeModulePkg/Library/BaseResetSystemLibNull/BaseResetSystemLibNull.c
new file mode 100644
index 0000000000..d21a77401c
--- /dev/null
+++ b/Core/MdeModulePkg/Library/BaseResetSystemLibNull/BaseResetSystemLibNull.c
@@ -0,0 +1,79 @@
+/** @file
+ Null Reset System Library instance that only generates ASSERT() conditions.
+
+ Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Base.h>
+
+#include <Library/ResetSystemLib.h>
+#include <Library/DebugLib.h>
+
+/**
+ This function causes a system-wide reset (cold reset), in which
+ all circuitry within the system returns to its initial state. This type of reset
+ is asynchronous to system operation and operates without regard to
+ cycle boundaries.
+
+ If this function returns, it means that the system does not support cold reset.
+**/
+VOID
+EFIAPI
+ResetCold (
+ VOID
+ )
+{
+ ASSERT (FALSE);
+}
+
+/**
+ This function causes a system-wide initialization (warm reset), in which all processors
+ are set to their initial state. Pending cycles are not corrupted.
+
+ If this function returns, it means that the system does not support warm reset.
+**/
+VOID
+EFIAPI
+ResetWarm (
+ VOID
+ )
+{
+ ASSERT (FALSE);
+}
+
+/**
+ This function causes the system to enter a power state equivalent
+ to the ACPI G2/S5 or G3 states.
+
+ If this function returns, it means that the system does not support shut down reset.
+**/
+VOID
+EFIAPI
+ResetShutdown (
+ VOID
+ )
+{
+ ASSERT (FALSE);
+}
+
+/**
+ This function causes the system to enter S3 and then wake up immediately.
+
+ If this function returns, it means that the system does not support S3 feature.
+**/
+VOID
+EFIAPI
+EnterS3WithImmediateWake (
+ VOID
+ )
+{
+ ASSERT (FALSE);
+}
diff --git a/Core/MdeModulePkg/Library/BaseResetSystemLibNull/BaseResetSystemLibNull.inf b/Core/MdeModulePkg/Library/BaseResetSystemLibNull/BaseResetSystemLibNull.inf
new file mode 100644
index 0000000000..96e0ebb212
--- /dev/null
+++ b/Core/MdeModulePkg/Library/BaseResetSystemLibNull/BaseResetSystemLibNull.inf
@@ -0,0 +1,38 @@
+## @file
+# Null Reset System Library instance that only generates ASSERT() conditions.
+#
+# Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = BaseResetSystemLibNull
+ MODULE_UNI_FILE = BaseResetSystemLibNull.uni
+ FILE_GUID = 667A8B1C-9C97-4b2a-AE7E-568772FE45F3
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = ResetSystemLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ BaseResetSystemLibNull.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ DebugLib
diff --git a/Core/MdeModulePkg/Library/BaseResetSystemLibNull/BaseResetSystemLibNull.uni b/Core/MdeModulePkg/Library/BaseResetSystemLibNull/BaseResetSystemLibNull.uni
new file mode 100644
index 0000000000..a097a82b30
--- /dev/null
+++ b/Core/MdeModulePkg/Library/BaseResetSystemLibNull/BaseResetSystemLibNull.uni
Binary files differ
diff --git a/Core/MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.c b/Core/MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.c
new file mode 100644
index 0000000000..f4fc31913b
--- /dev/null
+++ b/Core/MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.c
@@ -0,0 +1,1100 @@
+/** @file
+ 16550 UART Serial Port library functions
+
+ (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>
+ Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Base.h>
+#include <IndustryStandard/Pci.h>
+#include <Library/SerialPortLib.h>
+#include <Library/PcdLib.h>
+#include <Library/IoLib.h>
+#include <Library/PciLib.h>
+#include <Library/PlatformHookLib.h>
+#include <Library/BaseLib.h>
+
+//
+// PCI Defintions.
+//
+#define PCI_BRIDGE_32_BIT_IO_SPACE 0x01
+
+//
+// 16550 UART register offsets and bitfields
+//
+#define R_UART_RXBUF 0
+#define R_UART_TXBUF 0
+#define R_UART_BAUD_LOW 0
+#define R_UART_BAUD_HIGH 1
+#define R_UART_FCR 2
+#define B_UART_FCR_FIFOE BIT0
+#define B_UART_FCR_FIFO64 BIT5
+#define R_UART_LCR 3
+#define B_UART_LCR_DLAB BIT7
+#define R_UART_MCR 4
+#define B_UART_MCR_DTRC BIT0
+#define B_UART_MCR_RTS BIT1
+#define R_UART_LSR 5
+#define B_UART_LSR_RXRDY BIT0
+#define B_UART_LSR_TXRDY BIT5
+#define B_UART_LSR_TEMT BIT6
+#define R_UART_MSR 6
+#define B_UART_MSR_CTS BIT4
+#define B_UART_MSR_DSR BIT5
+#define B_UART_MSR_RI BIT6
+#define B_UART_MSR_DCD BIT7
+
+//
+// 4-byte structure for each PCI node in PcdSerialPciDeviceInfo
+//
+typedef struct {
+ UINT8 Device;
+ UINT8 Function;
+ UINT16 PowerManagementStatusAndControlRegister;
+} PCI_UART_DEVICE_INFO;
+
+/**
+ Read an 8-bit 16550 register. If PcdSerialUseMmio is TRUE, then the value is read from
+ MMIO space. If PcdSerialUseMmio is FALSE, then the value is read from I/O space. The
+ parameter Offset is added to the base address of the 16550 registers that is specified
+ by PcdSerialRegisterBase.
+
+ @param Base The base address register of UART device.
+ @param Offset The offset of the 16550 register to read.
+
+ @return The value read from the 16550 register.
+
+**/
+UINT8
+SerialPortReadRegister (
+ UINTN Base,
+ UINTN Offset
+ )
+{
+ if (PcdGetBool (PcdSerialUseMmio)) {
+ return MmioRead8 (Base + Offset * PcdGet32 (PcdSerialRegisterStride));
+ } else {
+ return IoRead8 (Base + Offset * PcdGet32 (PcdSerialRegisterStride));
+ }
+}
+
+/**
+ Write an 8-bit 16550 register. If PcdSerialUseMmio is TRUE, then the value is written to
+ MMIO space. If PcdSerialUseMmio is FALSE, then the value is written to I/O space. The
+ parameter Offset is added to the base address of the 16550 registers that is specified
+ by PcdSerialRegisterBase.
+
+ @param Base The base address register of UART device.
+ @param Offset The offset of the 16550 register to write.
+ @param Value The value to write to the 16550 register specified by Offset.
+
+ @return The value written to the 16550 register.
+
+**/
+UINT8
+SerialPortWriteRegister (
+ UINTN Base,
+ UINTN Offset,
+ UINT8 Value
+ )
+{
+ if (PcdGetBool (PcdSerialUseMmio)) {
+ return MmioWrite8 (Base + Offset * PcdGet32 (PcdSerialRegisterStride), Value);
+ } else {
+ return IoWrite8 (Base + Offset * PcdGet32 (PcdSerialRegisterStride), Value);
+ }
+}
+
+/**
+ Update the value of an 16-bit PCI configuration register in a PCI device. If the
+ PCI Configuration register specified by PciAddress is already programmed with a
+ non-zero value, then return the current value. Otherwise update the PCI configuration
+ register specified by PciAddress with the value specified by Value and return the
+ value programmed into the PCI configuration register. All values must be masked
+ using the bitmask specified by Mask.
+
+ @param PciAddress PCI Library address of the PCI Configuration register to update.
+ @param Value The value to program into the PCI Configuration Register.
+ @param Mask Bitmask of the bits to check and update in the PCI configuration register.
+
+**/
+UINT16
+SerialPortLibUpdatePciRegister16 (
+ UINTN PciAddress,
+ UINT16 Value,
+ UINT16 Mask
+ )
+{
+ UINT16 CurrentValue;
+
+ CurrentValue = PciRead16 (PciAddress) & Mask;
+ if (CurrentValue != 0) {
+ return CurrentValue;
+ }
+ return PciWrite16 (PciAddress, Value & Mask);
+}
+
+/**
+ Update the value of an 32-bit PCI configuration register in a PCI device. If the
+ PCI Configuration register specified by PciAddress is already programmed with a
+ non-zero value, then return the current value. Otherwise update the PCI configuration
+ register specified by PciAddress with the value specified by Value and return the
+ value programmed into the PCI configuration register. All values must be masked
+ using the bitmask specified by Mask.
+
+ @param PciAddress PCI Library address of the PCI Configuration register to update.
+ @param Value The value to program into the PCI Configuration Register.
+ @param Mask Bitmask of the bits to check and update in the PCI configuration register.
+
+ @return The Secondary bus number that is actually programed into the PCI to PCI Bridge device.
+
+**/
+UINT32
+SerialPortLibUpdatePciRegister32 (
+ UINTN PciAddress,
+ UINT32 Value,
+ UINT32 Mask
+ )
+{
+ UINT32 CurrentValue;
+
+ CurrentValue = PciRead32 (PciAddress) & Mask;
+ if (CurrentValue != 0) {
+ return CurrentValue;
+ }
+ return PciWrite32 (PciAddress, Value & Mask);
+}
+
+/**
+ Retrieve the I/O or MMIO base address register for the PCI UART device.
+
+ This function assumes Root Bus Numer is Zero, and enables I/O and MMIO in PCI UART
+ Device if they are not already enabled.
+
+ @return The base address register of the UART device.
+
+**/
+UINTN
+GetSerialRegisterBase (
+ VOID
+ )
+{
+ UINTN PciLibAddress;
+ UINTN BusNumber;
+ UINTN SubordinateBusNumber;
+ UINT32 ParentIoBase;
+ UINT32 ParentIoLimit;
+ UINT16 ParentMemoryBase;
+ UINT16 ParentMemoryLimit;
+ UINT32 IoBase;
+ UINT32 IoLimit;
+ UINT16 MemoryBase;
+ UINT16 MemoryLimit;
+ UINTN SerialRegisterBase;
+ UINTN BarIndex;
+ UINT32 RegisterBaseMask;
+ PCI_UART_DEVICE_INFO *DeviceInfo;
+
+ //
+ // Get PCI Device Info
+ //
+ DeviceInfo = (PCI_UART_DEVICE_INFO *) PcdGetPtr (PcdSerialPciDeviceInfo);
+
+ //
+ // If PCI Device Info is empty, then assume fixed address UART and return PcdSerialRegisterBase
+ //
+ if (DeviceInfo->Device == 0xff) {
+ return (UINTN)PcdGet64 (PcdSerialRegisterBase);
+ }
+
+ //
+ // Assume PCI Bus 0 I/O window is 0-64KB and MMIO windows is 0-4GB
+ //
+ ParentMemoryBase = 0 >> 16;
+ ParentMemoryLimit = 0xfff00000 >> 16;
+ ParentIoBase = 0 >> 12;
+ ParentIoLimit = 0xf000 >> 12;
+
+ //
+ // Enable I/O and MMIO in PCI Bridge
+ // Assume Root Bus Numer is Zero.
+ //
+ for (BusNumber = 0; (DeviceInfo + 1)->Device != 0xff; DeviceInfo++) {
+ //
+ // Compute PCI Lib Address to PCI to PCI Bridge
+ //
+ PciLibAddress = PCI_LIB_ADDRESS (BusNumber, DeviceInfo->Device, DeviceInfo->Function, 0);
+
+ //
+ // Retrieve and verify the bus numbers in the PCI to PCI Bridge
+ //
+ BusNumber = PciRead8 (PciLibAddress + PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET);
+ SubordinateBusNumber = PciRead8 (PciLibAddress + PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET);
+ if (BusNumber == 0 || BusNumber > SubordinateBusNumber) {
+ return 0;
+ }
+
+ //
+ // Retrieve and verify the I/O or MMIO decode window in the PCI to PCI Bridge
+ //
+ if (PcdGetBool (PcdSerialUseMmio)) {
+ MemoryLimit = PciRead16 (PciLibAddress + OFFSET_OF (PCI_TYPE01, Bridge.MemoryLimit)) & 0xfff0;
+ MemoryBase = PciRead16 (PciLibAddress + OFFSET_OF (PCI_TYPE01, Bridge.MemoryBase)) & 0xfff0;
+
+ //
+ // If PCI Bridge MMIO window is disabled, then return 0
+ //
+ if (MemoryLimit < MemoryBase) {
+ return 0;
+ }
+
+ //
+ // If PCI Bridge MMIO window is not in the address range decoded by the parent PCI Bridge, then return 0
+ //
+ if (MemoryBase < ParentMemoryBase || MemoryBase > ParentMemoryLimit || MemoryLimit > ParentMemoryLimit) {
+ return 0;
+ }
+ ParentMemoryBase = MemoryBase;
+ ParentMemoryLimit = MemoryLimit;
+ } else {
+ IoLimit = PciRead8 (PciLibAddress + OFFSET_OF (PCI_TYPE01, Bridge.IoLimit));
+ if ((IoLimit & PCI_BRIDGE_32_BIT_IO_SPACE ) == 0) {
+ IoLimit = IoLimit >> 4;
+ } else {
+ IoLimit = (PciRead16 (PciLibAddress + OFFSET_OF (PCI_TYPE01, Bridge.IoLimitUpper16)) << 4) | (IoLimit >> 4);
+ }
+ IoBase = PciRead8 (PciLibAddress + OFFSET_OF (PCI_TYPE01, Bridge.IoBase));
+ if ((IoBase & PCI_BRIDGE_32_BIT_IO_SPACE ) == 0) {
+ IoBase = IoBase >> 4;
+ } else {
+ IoBase = (PciRead16 (PciLibAddress + OFFSET_OF (PCI_TYPE01, Bridge.IoBaseUpper16)) << 4) | (IoBase >> 4);
+ }
+
+ //
+ // If PCI Bridge I/O window is disabled, then return 0
+ //
+ if (IoLimit < IoBase) {
+ return 0;
+ }
+
+ //
+ // If PCI Bridge I/O window is not in the address range decoded by the parent PCI Bridge, then return 0
+ //
+ if (IoBase < ParentIoBase || IoBase > ParentIoLimit || IoLimit > ParentIoLimit) {
+ return 0;
+ }
+ ParentIoBase = IoBase;
+ ParentIoLimit = IoLimit;
+ }
+ }
+
+ //
+ // Compute PCI Lib Address to PCI UART
+ //
+ PciLibAddress = PCI_LIB_ADDRESS (BusNumber, DeviceInfo->Device, DeviceInfo->Function, 0);
+
+ //
+ // Find the first IO or MMIO BAR
+ //
+ RegisterBaseMask = 0xFFFFFFF0;
+ for (BarIndex = 0; BarIndex < PCI_MAX_BAR; BarIndex ++) {
+ SerialRegisterBase = PciRead32 (PciLibAddress + PCI_BASE_ADDRESSREG_OFFSET + BarIndex * 4);
+ if (PcdGetBool (PcdSerialUseMmio) && ((SerialRegisterBase & BIT0) == 0)) {
+ //
+ // MMIO BAR is found
+ //
+ RegisterBaseMask = 0xFFFFFFF0;
+ break;
+ }
+
+ if ((!PcdGetBool (PcdSerialUseMmio)) && ((SerialRegisterBase & BIT0) != 0)) {
+ //
+ // IO BAR is found
+ //
+ RegisterBaseMask = 0xFFFFFFF8;
+ break;
+ }
+ }
+
+ //
+ // MMIO or IO BAR is not found.
+ //
+ if (BarIndex == PCI_MAX_BAR) {
+ return 0;
+ }
+
+ //
+ // Program UART BAR
+ //
+ SerialRegisterBase = SerialPortLibUpdatePciRegister32 (
+ PciLibAddress + PCI_BASE_ADDRESSREG_OFFSET + BarIndex * 4,
+ (UINT32)PcdGet64 (PcdSerialRegisterBase),
+ RegisterBaseMask
+ );
+
+ //
+ // Verify that the UART BAR is in the address range decoded by the parent PCI Bridge
+ //
+ if (PcdGetBool (PcdSerialUseMmio)) {
+ if (((SerialRegisterBase >> 16) & 0xfff0) < ParentMemoryBase || ((SerialRegisterBase >> 16) & 0xfff0) > ParentMemoryLimit) {
+ return 0;
+ }
+ } else {
+ if ((SerialRegisterBase >> 12) < ParentIoBase || (SerialRegisterBase >> 12) > ParentIoLimit) {
+ return 0;
+ }
+ }
+
+ //
+ // Enable I/O and MMIO in PCI UART Device if they are not already enabled
+ //
+ PciOr16 (
+ PciLibAddress + PCI_COMMAND_OFFSET,
+ PcdGetBool (PcdSerialUseMmio) ? EFI_PCI_COMMAND_MEMORY_SPACE : EFI_PCI_COMMAND_IO_SPACE
+ );
+
+ //
+ // Force D0 state if a Power Management and Status Register is specified
+ //
+ if (DeviceInfo->PowerManagementStatusAndControlRegister != 0x00) {
+ if ((PciRead16 (PciLibAddress + DeviceInfo->PowerManagementStatusAndControlRegister) & (BIT0 | BIT1)) != 0x00) {
+ PciAnd16 (PciLibAddress + DeviceInfo->PowerManagementStatusAndControlRegister, (UINT16)~(BIT0 | BIT1));
+ //
+ // If PCI UART was not in D0, then make sure FIFOs are enabled, but do not reset FIFOs
+ //
+ SerialPortWriteRegister (SerialRegisterBase, R_UART_FCR, (UINT8)(PcdGet8 (PcdSerialFifoControl) & (B_UART_FCR_FIFOE | B_UART_FCR_FIFO64)));
+ }
+ }
+
+ //
+ // Get PCI Device Info
+ //
+ DeviceInfo = (PCI_UART_DEVICE_INFO *) PcdGetPtr (PcdSerialPciDeviceInfo);
+
+ //
+ // Enable I/O or MMIO in PCI Bridge
+ // Assume Root Bus Numer is Zero.
+ //
+ for (BusNumber = 0; (DeviceInfo + 1)->Device != 0xff; DeviceInfo++) {
+ //
+ // Compute PCI Lib Address to PCI to PCI Bridge
+ //
+ PciLibAddress = PCI_LIB_ADDRESS (BusNumber, DeviceInfo->Device, DeviceInfo->Function, 0);
+
+ //
+ // Enable the I/O or MMIO decode windows in the PCI to PCI Bridge
+ //
+ PciOr16 (
+ PciLibAddress + PCI_COMMAND_OFFSET,
+ PcdGetBool (PcdSerialUseMmio) ? EFI_PCI_COMMAND_MEMORY_SPACE : EFI_PCI_COMMAND_IO_SPACE
+ );
+
+ //
+ // Force D0 state if a Power Management and Status Register is specified
+ //
+ if (DeviceInfo->PowerManagementStatusAndControlRegister != 0x00) {
+ if ((PciRead16 (PciLibAddress + DeviceInfo->PowerManagementStatusAndControlRegister) & (BIT0 | BIT1)) != 0x00) {
+ PciAnd16 (PciLibAddress + DeviceInfo->PowerManagementStatusAndControlRegister, (UINT16)~(BIT0 | BIT1));
+ }
+ }
+
+ BusNumber = PciRead8 (PciLibAddress + PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET);
+ }
+
+ return SerialRegisterBase;
+}
+
+/**
+ Return whether the hardware flow control signal allows writing.
+
+ @param SerialRegisterBase The base address register of UART device.
+
+ @retval TRUE The serial port is writable.
+ @retval FALSE The serial port is not writable.
+**/
+BOOLEAN
+SerialPortWritable (
+ UINTN SerialRegisterBase
+ )
+{
+ if (PcdGetBool (PcdSerialUseHardwareFlowControl)) {
+ if (PcdGetBool (PcdSerialDetectCable)) {
+ //
+ // Wait for both DSR and CTS to be set
+ // DSR is set if a cable is connected.
+ // CTS is set if it is ok to transmit data
+ //
+ // DSR CTS Description Action
+ // === === ======================================== ========
+ // 0 0 No cable connected. Wait
+ // 0 1 No cable connected. Wait
+ // 1 0 Cable connected, but not clear to send. Wait
+ // 1 1 Cable connected, and clear to send. Transmit
+ //
+ return (BOOLEAN) ((SerialPortReadRegister (SerialRegisterBase, R_UART_MSR) & (B_UART_MSR_DSR | B_UART_MSR_CTS)) == (B_UART_MSR_DSR | B_UART_MSR_CTS));
+ } else {
+ //
+ // Wait for both DSR and CTS to be set OR for DSR to be clear.
+ // DSR is set if a cable is connected.
+ // CTS is set if it is ok to transmit data
+ //
+ // DSR CTS Description Action
+ // === === ======================================== ========
+ // 0 0 No cable connected. Transmit
+ // 0 1 No cable connected. Transmit
+ // 1 0 Cable connected, but not clear to send. Wait
+ // 1 1 Cable connected, and clar to send. Transmit
+ //
+ return (BOOLEAN) ((SerialPortReadRegister (SerialRegisterBase, R_UART_MSR) & (B_UART_MSR_DSR | B_UART_MSR_CTS)) != (B_UART_MSR_DSR));
+ }
+ }
+
+ return TRUE;
+}
+
+/**
+ Initialize the serial device hardware.
+
+ If no initialization is required, then return RETURN_SUCCESS.
+ If the serial device was successfully initialized, then return RETURN_SUCCESS.
+ If the serial device could not be initialized, then return RETURN_DEVICE_ERROR.
+
+ @retval RETURN_SUCCESS The serial device was initialized.
+ @retval RETURN_DEVICE_ERROR The serial device could not be initialized.
+
+**/
+RETURN_STATUS
+EFIAPI
+SerialPortInitialize (
+ VOID
+ )
+{
+ RETURN_STATUS Status;
+ UINTN SerialRegisterBase;
+ UINT32 Divisor;
+ UINT32 CurrentDivisor;
+ BOOLEAN Initialized;
+
+ //
+ // Perform platform specific initialization required to enable use of the 16550 device
+ // at the location specified by PcdSerialUseMmio and PcdSerialRegisterBase.
+ //
+ Status = PlatformHookSerialPortInitialize ();
+ if (RETURN_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Calculate divisor for baud generator
+ // Ref_Clk_Rate / Baud_Rate / 16
+ //
+ Divisor = PcdGet32 (PcdSerialClockRate) / (PcdGet32 (PcdSerialBaudRate) * 16);
+ if ((PcdGet32 (PcdSerialClockRate) % (PcdGet32 (PcdSerialBaudRate) * 16)) >= PcdGet32 (PcdSerialBaudRate) * 8) {
+ Divisor++;
+ }
+
+ //
+ // Get the base address of the serial port in either I/O or MMIO space
+ //
+ SerialRegisterBase = GetSerialRegisterBase ();
+ if (SerialRegisterBase ==0) {
+ return RETURN_DEVICE_ERROR;
+ }
+
+ //
+ // See if the serial port is already initialized
+ //
+ Initialized = TRUE;
+ if ((SerialPortReadRegister (SerialRegisterBase, R_UART_LCR) & 0x3F) != (PcdGet8 (PcdSerialLineControl) & 0x3F)) {
+ Initialized = FALSE;
+ }
+ SerialPortWriteRegister (SerialRegisterBase, R_UART_LCR, (UINT8)(SerialPortReadRegister (SerialRegisterBase, R_UART_LCR) | B_UART_LCR_DLAB));
+ CurrentDivisor = SerialPortReadRegister (SerialRegisterBase, R_UART_BAUD_HIGH) << 8;
+ CurrentDivisor |= (UINT32) SerialPortReadRegister (SerialRegisterBase, R_UART_BAUD_LOW);
+ SerialPortWriteRegister (SerialRegisterBase, R_UART_LCR, (UINT8)(SerialPortReadRegister (SerialRegisterBase, R_UART_LCR) & ~B_UART_LCR_DLAB));
+ if (CurrentDivisor != Divisor) {
+ Initialized = FALSE;
+ }
+ if (Initialized) {
+ return RETURN_SUCCESS;
+ }
+
+ //
+ // Wait for the serial port to be ready.
+ // Verify that both the transmit FIFO and the shift register are empty.
+ //
+ while ((SerialPortReadRegister (SerialRegisterBase, R_UART_LSR) & (B_UART_LSR_TEMT | B_UART_LSR_TXRDY)) != (B_UART_LSR_TEMT | B_UART_LSR_TXRDY));
+
+ //
+ // Configure baud rate
+ //
+ SerialPortWriteRegister (SerialRegisterBase, R_UART_LCR, B_UART_LCR_DLAB);
+ SerialPortWriteRegister (SerialRegisterBase, R_UART_BAUD_HIGH, (UINT8) (Divisor >> 8));
+ SerialPortWriteRegister (SerialRegisterBase, R_UART_BAUD_LOW, (UINT8) (Divisor & 0xff));
+
+ //
+ // Clear DLAB and configure Data Bits, Parity, and Stop Bits.
+ // Strip reserved bits from PcdSerialLineControl
+ //
+ SerialPortWriteRegister (SerialRegisterBase, R_UART_LCR, (UINT8)(PcdGet8 (PcdSerialLineControl) & 0x3F));
+
+ //
+ // Enable and reset FIFOs
+ // Strip reserved bits from PcdSerialFifoControl
+ //
+ SerialPortWriteRegister (SerialRegisterBase, R_UART_FCR, 0x00);
+ SerialPortWriteRegister (SerialRegisterBase, R_UART_FCR, (UINT8)(PcdGet8 (PcdSerialFifoControl) & (B_UART_FCR_FIFOE | B_UART_FCR_FIFO64)));
+
+ //
+ // Put Modem Control Register(MCR) into its reset state of 0x00.
+ //
+ SerialPortWriteRegister (SerialRegisterBase, R_UART_MCR, 0x00);
+
+ return RETURN_SUCCESS;
+}
+
+/**
+ Write data from buffer to serial device.
+
+ Writes NumberOfBytes data bytes from Buffer to the serial device.
+ The number of bytes actually written to the serial device is returned.
+ If the return value is less than NumberOfBytes, then the write operation failed.
+
+ If Buffer is NULL, then ASSERT().
+
+ If NumberOfBytes is zero, then return 0.
+
+ @param Buffer Pointer to the data buffer to be written.
+ @param NumberOfBytes Number of bytes to written to the serial device.
+
+ @retval 0 NumberOfBytes is 0.
+ @retval >0 The number of bytes written to the serial device.
+ If this value is less than NumberOfBytes, then the write operation failed.
+
+**/
+UINTN
+EFIAPI
+SerialPortWrite (
+ IN UINT8 *Buffer,
+ IN UINTN NumberOfBytes
+ )
+{
+ UINTN SerialRegisterBase;
+ UINTN Result;
+ UINTN Index;
+ UINTN FifoSize;
+
+ if (Buffer == NULL) {
+ return 0;
+ }
+
+ SerialRegisterBase = GetSerialRegisterBase ();
+ if (SerialRegisterBase ==0) {
+ return 0;
+ }
+
+ if (NumberOfBytes == 0) {
+ //
+ // Flush the hardware
+ //
+
+ //
+ // Wait for both the transmit FIFO and shift register empty.
+ //
+ while ((SerialPortReadRegister (SerialRegisterBase, R_UART_LSR) & (B_UART_LSR_TEMT | B_UART_LSR_TXRDY)) != (B_UART_LSR_TEMT | B_UART_LSR_TXRDY));
+
+ //
+ // Wait for the hardware flow control signal
+ //
+ while (!SerialPortWritable (SerialRegisterBase));
+ return 0;
+ }
+
+ //
+ // Compute the maximum size of the Tx FIFO
+ //
+ FifoSize = 1;
+ if ((PcdGet8 (PcdSerialFifoControl) & B_UART_FCR_FIFOE) != 0) {
+ if ((PcdGet8 (PcdSerialFifoControl) & B_UART_FCR_FIFO64) == 0) {
+ FifoSize = 16;
+ } else {
+ FifoSize = PcdGet32 (PcdSerialExtendedTxFifoSize);
+ }
+ }
+
+ Result = NumberOfBytes;
+ while (NumberOfBytes != 0) {
+ //
+ // Wait for the serial port to be ready, to make sure both the transmit FIFO
+ // and shift register empty.
+ //
+ while ((SerialPortReadRegister (SerialRegisterBase, R_UART_LSR) & B_UART_LSR_TEMT) == 0);
+
+ //
+ // Fill then entire Tx FIFO
+ //
+ for (Index = 0; Index < FifoSize && NumberOfBytes != 0; Index++, NumberOfBytes--, Buffer++) {
+ //
+ // Wait for the hardware flow control signal
+ //
+ while (!SerialPortWritable (SerialRegisterBase));
+
+ //
+ // Write byte to the transmit buffer.
+ //
+ SerialPortWriteRegister (SerialRegisterBase, R_UART_TXBUF, *Buffer);
+ }
+ }
+ return Result;
+}
+
+/**
+ Reads data from a serial device into a buffer.
+
+ @param Buffer Pointer to the data buffer to store the data read from the serial device.
+ @param NumberOfBytes Number of bytes to read from the serial device.
+
+ @retval 0 NumberOfBytes is 0.
+ @retval >0 The number of bytes read from the serial device.
+ If this value is less than NumberOfBytes, then the read operation failed.
+
+**/
+UINTN
+EFIAPI
+SerialPortRead (
+ OUT UINT8 *Buffer,
+ IN UINTN NumberOfBytes
+ )
+{
+ UINTN SerialRegisterBase;
+ UINTN Result;
+ UINT8 Mcr;
+
+ if (NULL == Buffer) {
+ return 0;
+ }
+
+ SerialRegisterBase = GetSerialRegisterBase ();
+ if (SerialRegisterBase ==0) {
+ return 0;
+ }
+
+ Mcr = (UINT8)(SerialPortReadRegister (SerialRegisterBase, R_UART_MCR) & ~B_UART_MCR_RTS);
+
+ for (Result = 0; NumberOfBytes-- != 0; Result++, Buffer++) {
+ //
+ // Wait for the serial port to have some data.
+ //
+ while ((SerialPortReadRegister (SerialRegisterBase, R_UART_LSR) & B_UART_LSR_RXRDY) == 0) {
+ if (PcdGetBool (PcdSerialUseHardwareFlowControl)) {
+ //
+ // Set RTS to let the peer send some data
+ //
+ SerialPortWriteRegister (SerialRegisterBase, R_UART_MCR, (UINT8)(Mcr | B_UART_MCR_RTS));
+ }
+ }
+ if (PcdGetBool (PcdSerialUseHardwareFlowControl)) {
+ //
+ // Clear RTS to prevent peer from sending data
+ //
+ SerialPortWriteRegister (SerialRegisterBase, R_UART_MCR, Mcr);
+ }
+
+ //
+ // Read byte from the receive buffer.
+ //
+ *Buffer = SerialPortReadRegister (SerialRegisterBase, R_UART_RXBUF);
+ }
+
+ return Result;
+}
+
+
+/**
+ Polls a serial device to see if there is any data waiting to be read.
+
+ Polls aserial device to see if there is any data waiting to be read.
+ If there is data waiting to be read from the serial device, then TRUE is returned.
+ If there is no data waiting to be read from the serial device, then FALSE is returned.
+
+ @retval TRUE Data is waiting to be read from the serial device.
+ @retval FALSE There is no data waiting to be read from the serial device.
+
+**/
+BOOLEAN
+EFIAPI
+SerialPortPoll (
+ VOID
+ )
+{
+ UINTN SerialRegisterBase;
+
+ SerialRegisterBase = GetSerialRegisterBase ();
+ if (SerialRegisterBase ==0) {
+ return FALSE;
+ }
+
+ //
+ // Read the serial port status
+ //
+ if ((SerialPortReadRegister (SerialRegisterBase, R_UART_LSR) & B_UART_LSR_RXRDY) != 0) {
+ if (PcdGetBool (PcdSerialUseHardwareFlowControl)) {
+ //
+ // Clear RTS to prevent peer from sending data
+ //
+ SerialPortWriteRegister (SerialRegisterBase, R_UART_MCR, (UINT8)(SerialPortReadRegister (SerialRegisterBase, R_UART_MCR) & ~B_UART_MCR_RTS));
+ }
+ return TRUE;
+ }
+
+ if (PcdGetBool (PcdSerialUseHardwareFlowControl)) {
+ //
+ // Set RTS to let the peer send some data
+ //
+ SerialPortWriteRegister (SerialRegisterBase, R_UART_MCR, (UINT8)(SerialPortReadRegister (SerialRegisterBase, R_UART_MCR) | B_UART_MCR_RTS));
+ }
+
+ return FALSE;
+}
+
+/**
+ Sets the control bits on a serial device.
+
+ @param Control Sets the bits of Control that are settable.
+
+ @retval RETURN_SUCCESS The new control bits were set on the serial device.
+ @retval RETURN_UNSUPPORTED The serial device does not support this operation.
+ @retval RETURN_DEVICE_ERROR The serial device is not functioning correctly.
+
+**/
+RETURN_STATUS
+EFIAPI
+SerialPortSetControl (
+ IN UINT32 Control
+ )
+{
+ UINTN SerialRegisterBase;
+ UINT8 Mcr;
+
+ //
+ // First determine the parameter is invalid.
+ //
+ if ((Control & (~(EFI_SERIAL_REQUEST_TO_SEND | EFI_SERIAL_DATA_TERMINAL_READY |
+ EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE))) != 0) {
+ return RETURN_UNSUPPORTED;
+ }
+
+ SerialRegisterBase = GetSerialRegisterBase ();
+ if (SerialRegisterBase ==0) {
+ return RETURN_UNSUPPORTED;
+ }
+
+ //
+ // Read the Modem Control Register.
+ //
+ Mcr = SerialPortReadRegister (SerialRegisterBase, R_UART_MCR);
+ Mcr &= (~(B_UART_MCR_DTRC | B_UART_MCR_RTS));
+
+ if ((Control & EFI_SERIAL_DATA_TERMINAL_READY) == EFI_SERIAL_DATA_TERMINAL_READY) {
+ Mcr |= B_UART_MCR_DTRC;
+ }
+
+ if ((Control & EFI_SERIAL_REQUEST_TO_SEND) == EFI_SERIAL_REQUEST_TO_SEND) {
+ Mcr |= B_UART_MCR_RTS;
+ }
+
+ //
+ // Write the Modem Control Register.
+ //
+ SerialPortWriteRegister (SerialRegisterBase, R_UART_MCR, Mcr);
+
+ return RETURN_SUCCESS;
+}
+
+/**
+ Retrieve the status of the control bits on a serial device.
+
+ @param Control A pointer to return the current control signals from the serial device.
+
+ @retval RETURN_SUCCESS The control bits were read from the serial device.
+ @retval RETURN_UNSUPPORTED The serial device does not support this operation.
+ @retval RETURN_DEVICE_ERROR The serial device is not functioning correctly.
+
+**/
+RETURN_STATUS
+EFIAPI
+SerialPortGetControl (
+ OUT UINT32 *Control
+ )
+{
+ UINTN SerialRegisterBase;
+ UINT8 Msr;
+ UINT8 Mcr;
+ UINT8 Lsr;
+
+ SerialRegisterBase = GetSerialRegisterBase ();
+ if (SerialRegisterBase ==0) {
+ return RETURN_UNSUPPORTED;
+ }
+
+ *Control = 0;
+
+ //
+ // Read the Modem Status Register.
+ //
+ Msr = SerialPortReadRegister (SerialRegisterBase, R_UART_MSR);
+
+ if ((Msr & B_UART_MSR_CTS) == B_UART_MSR_CTS) {
+ *Control |= EFI_SERIAL_CLEAR_TO_SEND;
+ }
+
+ if ((Msr & B_UART_MSR_DSR) == B_UART_MSR_DSR) {
+ *Control |= EFI_SERIAL_DATA_SET_READY;
+ }
+
+ if ((Msr & B_UART_MSR_RI) == B_UART_MSR_RI) {
+ *Control |= EFI_SERIAL_RING_INDICATE;
+ }
+
+ if ((Msr & B_UART_MSR_DCD) == B_UART_MSR_DCD) {
+ *Control |= EFI_SERIAL_CARRIER_DETECT;
+ }
+
+ //
+ // Read the Modem Control Register.
+ //
+ Mcr = SerialPortReadRegister (SerialRegisterBase, R_UART_MCR);
+
+ if ((Mcr & B_UART_MCR_DTRC) == B_UART_MCR_DTRC) {
+ *Control |= EFI_SERIAL_DATA_TERMINAL_READY;
+ }
+
+ if ((Mcr & B_UART_MCR_RTS) == B_UART_MCR_RTS) {
+ *Control |= EFI_SERIAL_REQUEST_TO_SEND;
+ }
+
+ if (PcdGetBool (PcdSerialUseHardwareFlowControl)) {
+ *Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;
+ }
+
+ //
+ // Read the Line Status Register.
+ //
+ Lsr = SerialPortReadRegister (SerialRegisterBase, R_UART_LSR);
+
+ if ((Lsr & (B_UART_LSR_TEMT | B_UART_LSR_TXRDY)) == (B_UART_LSR_TEMT | B_UART_LSR_TXRDY)) {
+ *Control |= EFI_SERIAL_OUTPUT_BUFFER_EMPTY;
+ }
+
+ if ((Lsr & B_UART_LSR_RXRDY) == 0) {
+ *Control |= EFI_SERIAL_INPUT_BUFFER_EMPTY;
+ }
+
+ return RETURN_SUCCESS;
+}
+
+/**
+ Sets the baud rate, receive FIFO depth, transmit/receice time out, parity,
+ data bits, and stop bits on a serial device.
+
+ @param BaudRate The requested baud rate. A BaudRate value of 0 will use the
+ device's default interface speed.
+ On output, the value actually set.
+ @param ReveiveFifoDepth The requested depth of the FIFO on the receive side of the
+ serial interface. A ReceiveFifoDepth value of 0 will use
+ the device's default FIFO depth.
+ On output, the value actually set.
+ @param Timeout The requested time out for a single character in microseconds.
+ This timeout applies to both the transmit and receive side of the
+ interface. A Timeout value of 0 will use the device's default time
+ out value.
+ On output, the value actually set.
+ @param Parity The type of parity to use on this serial device. A Parity value of
+ DefaultParity will use the device's default parity value.
+ On output, the value actually set.
+ @param DataBits The number of data bits to use on the serial device. A DataBits
+ vaule of 0 will use the device's default data bit setting.
+ On output, the value actually set.
+ @param StopBits The number of stop bits to use on this serial device. A StopBits
+ value of DefaultStopBits will use the device's default number of
+ stop bits.
+ On output, the value actually set.
+
+ @retval RETURN_SUCCESS The new attributes were set on the serial device.
+ @retval RETURN_UNSUPPORTED The serial device does not support this operation.
+ @retval RETURN_INVALID_PARAMETER One or more of the attributes has an unsupported value.
+ @retval RETURN_DEVICE_ERROR The serial device is not functioning correctly.
+
+**/
+RETURN_STATUS
+EFIAPI
+SerialPortSetAttributes (
+ IN OUT UINT64 *BaudRate,
+ IN OUT UINT32 *ReceiveFifoDepth,
+ IN OUT UINT32 *Timeout,
+ IN OUT EFI_PARITY_TYPE *Parity,
+ IN OUT UINT8 *DataBits,
+ IN OUT EFI_STOP_BITS_TYPE *StopBits
+ )
+{
+ UINTN SerialRegisterBase;
+ UINT32 SerialBaudRate;
+ UINTN Divisor;
+ UINT8 Lcr;
+ UINT8 LcrData;
+ UINT8 LcrParity;
+ UINT8 LcrStop;
+
+ SerialRegisterBase = GetSerialRegisterBase ();
+ if (SerialRegisterBase ==0) {
+ return RETURN_UNSUPPORTED;
+ }
+
+ //
+ // Check for default settings and fill in actual values.
+ //
+ if (*BaudRate == 0) {
+ *BaudRate = PcdGet32 (PcdSerialBaudRate);
+ }
+ SerialBaudRate = (UINT32) *BaudRate;
+
+ if (*DataBits == 0) {
+ LcrData = (UINT8) (PcdGet8 (PcdSerialLineControl) & 0x3);
+ *DataBits = LcrData + 5;
+ } else {
+ if ((*DataBits < 5) || (*DataBits > 8)) {
+ return RETURN_INVALID_PARAMETER;
+ }
+ //
+ // Map 5..8 to 0..3
+ //
+ LcrData = (UINT8) (*DataBits - (UINT8) 5);
+ }
+
+ if (*Parity == DefaultParity) {
+ LcrParity = (UINT8) ((PcdGet8 (PcdSerialLineControl) >> 3) & 0x7);
+ switch (LcrParity) {
+ case 0:
+ *Parity = NoParity;
+ break;
+
+ case 3:
+ *Parity = EvenParity;
+ break;
+
+ case 1:
+ *Parity = OddParity;
+ break;
+
+ case 7:
+ *Parity = SpaceParity;
+ break;
+
+ case 5:
+ *Parity = MarkParity;
+ break;
+
+ default:
+ break;
+ }
+ } else {
+ if ((*Parity < NoParity) || (*Parity > SpaceParity)) {
+ return RETURN_INVALID_PARAMETER;
+ }
+ switch (*Parity) {
+ case NoParity:
+ LcrParity = 0;
+ break;
+
+ case EvenParity:
+ LcrParity = 3;
+ break;
+
+ case OddParity:
+ LcrParity = 1;
+ break;
+
+ case SpaceParity:
+ LcrParity = 7;
+ break;
+
+ case MarkParity:
+ LcrParity = 5;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (*StopBits == DefaultStopBits) {
+ LcrStop = (UINT8) ((PcdGet8 (PcdSerialLineControl) >> 2) & 0x1);
+ switch (LcrStop) {
+ case 0:
+ *StopBits = OneStopBit;
+ break;
+
+ case 1:
+ if (*DataBits == 5) {
+ *StopBits = OneFiveStopBits;
+ } else {
+ *StopBits = TwoStopBits;
+ }
+ break;
+
+ default:
+ break;
+ }
+ } else {
+ if ((*StopBits < OneStopBit) || (*StopBits > TwoStopBits)) {
+ return RETURN_INVALID_PARAMETER;
+ }
+ switch (*StopBits) {
+ case OneStopBit:
+ LcrStop = 0;
+ break;
+
+ case OneFiveStopBits:
+ case TwoStopBits:
+ LcrStop = 1;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ //
+ // Calculate divisor for baud generator
+ // Ref_Clk_Rate / Baud_Rate / 16
+ //
+ Divisor = PcdGet32 (PcdSerialClockRate) / (SerialBaudRate * 16);
+ if ((PcdGet32 (PcdSerialClockRate) % (SerialBaudRate * 16)) >= SerialBaudRate * 8) {
+ Divisor++;
+ }
+
+ //
+ // Configure baud rate
+ //
+ SerialPortWriteRegister (SerialRegisterBase, R_UART_LCR, B_UART_LCR_DLAB);
+ SerialPortWriteRegister (SerialRegisterBase, R_UART_BAUD_HIGH, (UINT8) (Divisor >> 8));
+ SerialPortWriteRegister (SerialRegisterBase, R_UART_BAUD_LOW, (UINT8) (Divisor & 0xff));
+
+ //
+ // Clear DLAB and configure Data Bits, Parity, and Stop Bits.
+ // Strip reserved bits from line control value
+ //
+ Lcr = (UINT8) ((LcrParity << 3) | (LcrStop << 2) | LcrData);
+ SerialPortWriteRegister (SerialRegisterBase, R_UART_LCR, (UINT8) (Lcr & 0x3F));
+
+ return RETURN_SUCCESS;
+}
+
diff --git a/Core/MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.inf b/Core/MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.inf
new file mode 100644
index 0000000000..bb42f89676
--- /dev/null
+++ b/Core/MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.inf
@@ -0,0 +1,48 @@
+## @file
+# SerialPortLib instance for 16550 UART.
+#
+# Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = BaseSerialPortLib16550
+ MODULE_UNI_FILE = BaseSerialPortLib16550.uni
+ FILE_GUID = 9E7C00CF-355A-4d4e-BF60-0428CFF95540
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.1
+ LIBRARY_CLASS = SerialPortLib
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ PcdLib
+ IoLib
+ PlatformHookLib
+ PciLib
+
+[Sources]
+ BaseSerialPortLib16550.c
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialUseMmio ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialUseHardwareFlowControl ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialDetectCable ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialRegisterBase ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialBaudRate ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialLineControl ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialFifoControl ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialClockRate ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialPciDeviceInfo ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialExtendedTxFifoSize ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialRegisterStride ## CONSUMES
diff --git a/Core/MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.uni b/Core/MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.uni
new file mode 100644
index 0000000000..641a86efc7
--- /dev/null
+++ b/Core/MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.uni
Binary files differ
diff --git a/Core/MdeModulePkg/Library/BaseSortLib/BaseSortLib.c b/Core/MdeModulePkg/Library/BaseSortLib/BaseSortLib.c
new file mode 100644
index 0000000000..ab8a60585e
--- /dev/null
+++ b/Core/MdeModulePkg/Library/BaseSortLib/BaseSortLib.c
@@ -0,0 +1,238 @@
+/** @file
+ Library used for sorting routines.
+
+ Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved. <BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+#include <Uefi.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/SortLib.h>
+
+/**
+ Worker function for QuickSorting. This function is identical to PerformQuickSort,
+ except that is uses the pre-allocated buffer so the in place sorting does not need to
+ allocate and free buffers constantly.
+
+ Each element must be equal sized.
+
+ if BufferToSort is NULL, then ASSERT.
+ if CompareFunction is NULL, then ASSERT.
+ if Buffer is NULL, then ASSERT.
+
+ if Count is < 2 then perform no action.
+ if Size is < 1 then perform no action.
+
+ @param[in, out] BufferToSort on call a Buffer of (possibly sorted) elements
+ on return a buffer of sorted elements
+ @param[in] Count the number of elements in the buffer to sort
+ @param[in] ElementSize Size of an element in bytes
+ @param[in] CompareFunction The function to call to perform the comparison
+ of any 2 elements
+ @param[in] Buffer Buffer of size ElementSize for use in swapping
+**/
+VOID
+EFIAPI
+QuickSortWorker (
+ IN OUT VOID *BufferToSort,
+ IN CONST UINTN Count,
+ IN CONST UINTN ElementSize,
+ IN SORT_COMPARE CompareFunction,
+ IN VOID *Buffer
+ )
+{
+ VOID *Pivot;
+ UINTN LoopCount;
+ UINTN NextSwapLocation;
+
+ ASSERT(BufferToSort != NULL);
+ ASSERT(CompareFunction != NULL);
+ ASSERT(Buffer != NULL);
+
+ if ( Count < 2
+ || ElementSize < 1
+ ){
+ return;
+ }
+
+ NextSwapLocation = 0;
+
+ //
+ // pick a pivot (we choose last element)
+ //
+ Pivot = ((UINT8*)BufferToSort+((Count-1)*ElementSize));
+
+ //
+ // Now get the pivot such that all on "left" are below it
+ // and everything "right" are above it
+ //
+ for ( LoopCount = 0
+ ; LoopCount < Count -1
+ ; LoopCount++
+ ){
+ //
+ // if the element is less than the pivot
+ //
+ if (CompareFunction((VOID*)((UINT8*)BufferToSort+((LoopCount)*ElementSize)),Pivot) <= 0){
+ //
+ // swap
+ //
+ CopyMem (Buffer, (UINT8*)BufferToSort+(NextSwapLocation*ElementSize), ElementSize);
+ CopyMem ((UINT8*)BufferToSort+(NextSwapLocation*ElementSize), (UINT8*)BufferToSort+((LoopCount)*ElementSize), ElementSize);
+ CopyMem ((UINT8*)BufferToSort+((LoopCount)*ElementSize), Buffer, ElementSize);
+
+ //
+ // increment NextSwapLocation
+ //
+ NextSwapLocation++;
+ }
+ }
+ //
+ // swap pivot to it's final position (NextSwapLocaiton)
+ //
+ CopyMem (Buffer, Pivot, ElementSize);
+ CopyMem (Pivot, (UINT8*)BufferToSort+(NextSwapLocation*ElementSize), ElementSize);
+ CopyMem ((UINT8*)BufferToSort+(NextSwapLocation*ElementSize), Buffer, ElementSize);
+
+ //
+ // Now recurse on 2 paritial lists. neither of these will have the 'pivot' element
+ // IE list is sorted left half, pivot element, sorted right half...
+ //
+ if (NextSwapLocation >= 2) {
+ QuickSortWorker(
+ BufferToSort,
+ NextSwapLocation,
+ ElementSize,
+ CompareFunction,
+ Buffer);
+ }
+
+ if ((Count - NextSwapLocation - 1) >= 2) {
+ QuickSortWorker(
+ (UINT8 *)BufferToSort + (NextSwapLocation+1) * ElementSize,
+ Count - NextSwapLocation - 1,
+ ElementSize,
+ CompareFunction,
+ Buffer);
+ }
+ return;
+}
+/**
+ Function to perform a Quick Sort alogrithm on a buffer of comparable elements.
+
+ Each element must be equal sized.
+
+ if BufferToSort is NULL, then ASSERT.
+ if CompareFunction is NULL, then ASSERT.
+
+ if Count is < 2 then perform no action.
+ if Size is < 1 then perform no action.
+
+ @param[in, out] BufferToSort on call a Buffer of (possibly sorted) elements
+ on return a buffer of sorted elements
+ @param[in] Count the number of elements in the buffer to sort
+ @param[in] ElementSize Size of an element in bytes
+ @param[in] CompareFunction The function to call to perform the comparison
+ of any 2 elements
+**/
+VOID
+EFIAPI
+PerformQuickSort (
+ IN OUT VOID *BufferToSort,
+ IN CONST UINTN Count,
+ IN CONST UINTN ElementSize,
+ IN SORT_COMPARE CompareFunction
+ )
+{
+ VOID *Buffer;
+
+ ASSERT(BufferToSort != NULL);
+ ASSERT(CompareFunction != NULL);
+
+ Buffer = AllocateZeroPool(ElementSize);
+ ASSERT(Buffer != NULL);
+
+ QuickSortWorker(
+ BufferToSort,
+ Count,
+ ElementSize,
+ CompareFunction,
+ Buffer);
+
+ FreePool(Buffer);
+ return;
+}
+
+/**
+ Not supported in Base version.
+
+ @param[in] Buffer1 Ignored.
+ @param[in] Buffer2 Ignored.
+
+ ASSERT and return 0.
+**/
+INTN
+EFIAPI
+DevicePathCompare (
+ IN CONST VOID *Buffer1,
+ IN CONST VOID *Buffer2
+ )
+{
+ ASSERT(FALSE);
+ return 0;
+}
+
+/**
+ Function to compare 2 strings without regard to case of the characters.
+
+ @param[in] Buffer1 Pointer to String to compare.
+ @param[in] Buffer2 Pointer to second String to compare.
+
+ @retval 0 Buffer1 equal to Buffer2.
+ @return < 0 Buffer1 is less than Buffer2.
+ @return > 0 Buffer1 is greater than Buffer2.
+**/
+INTN
+EFIAPI
+StringNoCaseCompare (
+ IN CONST VOID *Buffer1,
+ IN CONST VOID *Buffer2
+ )
+{
+ ASSERT(FALSE);
+ return 0;
+}
+
+
+/**
+ Function to compare 2 strings.
+
+ @param[in] Buffer1 Pointer to String to compare (CHAR16**).
+ @param[in] Buffer2 Pointer to second String to compare (CHAR16**).
+
+ @retval 0 Buffer1 equal to Buffer2.
+ @return < 0 Buffer1 is less than Buffer2.
+ @return > 0 Buffer1 is greater than Buffer2.
+**/
+INTN
+EFIAPI
+StringCompare (
+ IN CONST VOID *Buffer1,
+ IN CONST VOID *Buffer2
+ )
+{
+ ASSERT(FALSE);
+ return 0;
+}
+
+
diff --git a/Core/MdeModulePkg/Library/BaseSortLib/BaseSortLib.inf b/Core/MdeModulePkg/Library/BaseSortLib/BaseSortLib.inf
new file mode 100644
index 0000000000..4b493f4eb6
--- /dev/null
+++ b/Core/MdeModulePkg/Library/BaseSortLib/BaseSortLib.inf
@@ -0,0 +1,40 @@
+## @file
+# Library used for sorting routines.
+#
+# Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved. <BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010006
+ BASE_NAME = BaseSortLib
+ MODULE_UNI_FILE = BaseSortLib.uni
+ FILE_GUID = 03F3331B-F12D-494f-BF37-E55A657F2497
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = SortLib|DXE_DRIVER DXE_RUNTIME_DRIVER UEFI_APPLICATION UEFI_DRIVER
+
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources.common]
+ BaseSortLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ MemoryAllocationLib
+ BaseLib
+ BaseMemoryLib
+ DebugLib
diff --git a/Core/MdeModulePkg/Library/BaseSortLib/BaseSortLib.uni b/Core/MdeModulePkg/Library/BaseSortLib/BaseSortLib.uni
new file mode 100644
index 0000000000..2163301c42
--- /dev/null
+++ b/Core/MdeModulePkg/Library/BaseSortLib/BaseSortLib.uni
Binary files differ
diff --git a/Core/MdeModulePkg/Library/CpuExceptionHandlerLibNull/CpuExceptionHandlerLibNull.c b/Core/MdeModulePkg/Library/CpuExceptionHandlerLibNull/CpuExceptionHandlerLibNull.c
new file mode 100644
index 0000000000..2fea24ac31
--- /dev/null
+++ b/Core/MdeModulePkg/Library/CpuExceptionHandlerLibNull/CpuExceptionHandlerLibNull.c
@@ -0,0 +1,99 @@
+/** @file
+ CPU Exception Handler library implementition with empty functions.
+
+ Copyright (c) 2012 - 2013, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+#include <PiPei.h>
+#include <Library/CpuExceptionHandlerLib.h>
+
+/**
+ Initializes all CPU exceptions entries and provides the default exception handlers.
+
+ Caller should try to get an array of interrupt and/or exception vectors that are in use and need to
+ persist by EFI_VECTOR_HANDOFF_INFO defined in PI 1.3 specification.
+ If caller cannot get reserved vector list or it does not exists, set VectorInfo to NULL.
+ If VectorInfo is not NULL, the exception vectors will be initialized per vector attribute accordingly.
+
+ @param[in] VectorInfo Pointer to reserved vector list.
+
+ @retval EFI_SUCCESS CPU Exception Entries have been successfully initialized
+ with default exception handlers.
+ @retval EFI_INVALID_PARAMETER VectorInfo includes the invalid content if VectorInfo is not NULL.
+ @retval EFI_UNSUPPORTED This function is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeCpuExceptionHandlers (
+ IN EFI_VECTOR_HANDOFF_INFO *VectorInfo OPTIONAL
+ )
+{
+ return EFI_SUCCESS;
+}
+
+/**
+ Initializes all CPU interrupt/exceptions entries and provides the default interrupt/exception handlers.
+
+ Caller should try to get an array of interrupt and/or exception vectors that are in use and need to
+ persist by EFI_VECTOR_HANDOFF_INFO defined in PI 1.3 specification.
+ If caller cannot get reserved vector list or it does not exists, set VectorInfo to NULL.
+ If VectorInfo is not NULL, the exception vectors will be initialized per vector attribute accordingly.
+
+ @param[in] VectorInfo Pointer to reserved vector list.
+
+ @retval EFI_SUCCESS All CPU interrupt/exception entries have been successfully initialized
+ with default interrupt/exception handlers.
+ @retval EFI_INVALID_PARAMETER VectorInfo includes the invalid content if VectorInfo is not NULL.
+ @retval EFI_UNSUPPORTED This function is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeCpuInterruptHandlers (
+ IN EFI_VECTOR_HANDOFF_INFO *VectorInfo OPTIONAL
+ )
+{
+ return EFI_SUCCESS;
+}
+
+/**
+ Registers a function to be called from the processor interrupt handler.
+
+ This function registers and enables the handler specified by InterruptHandler for a processor
+ interrupt or exception type specified by InterruptType. If InterruptHandler is NULL, then the
+ handler for the processor interrupt or exception type specified by InterruptType is uninstalled.
+ The installed handler is called once for each processor interrupt or exception.
+ NOTE: This function should be invoked after InitializeCpuExceptionHandlers() or
+ InitializeCpuInterruptHandlers() invoked, otherwise EFI_UNSUPPORTED returned.
+
+ @param[in] InterruptType Defines which interrupt or exception to hook.
+ @param[in] InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called
+ when a processor interrupt occurs. If this parameter is NULL, then the handler
+ will be uninstalled.
+
+ @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled.
+ @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was
+ previously installed.
+ @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not
+ previously installed.
+ @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported,
+ or this function is not supported.
+**/
+EFI_STATUS
+EFIAPI
+RegisterCpuInterruptHandler (
+ IN EFI_EXCEPTION_TYPE InterruptType,
+ IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler
+ )
+{
+ return EFI_SUCCESS;
+}
+
diff --git a/Core/MdeModulePkg/Library/CpuExceptionHandlerLibNull/CpuExceptionHandlerLibNull.inf b/Core/MdeModulePkg/Library/CpuExceptionHandlerLibNull/CpuExceptionHandlerLibNull.inf
new file mode 100644
index 0000000000..c79c5a76ee
--- /dev/null
+++ b/Core/MdeModulePkg/Library/CpuExceptionHandlerLibNull/CpuExceptionHandlerLibNull.inf
@@ -0,0 +1,36 @@
+## @file
+# Null instance of CPU Exception Handler Library with empty functions.
+#
+# Copyright (c) 2012 - 2014, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = CpuExceptionHandlerLibNull
+ MODULE_UNI_FILE = CpuExceptionHandlerLibNull.uni
+ FILE_GUID = 3175E6B9-4B01-496a-9A2B-64AF02D87E34
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = CpuExceptionHandlerLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources.common]
+ CpuExceptionHandlerLibNull.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
diff --git a/Core/MdeModulePkg/Library/CpuExceptionHandlerLibNull/CpuExceptionHandlerLibNull.uni b/Core/MdeModulePkg/Library/CpuExceptionHandlerLibNull/CpuExceptionHandlerLibNull.uni
new file mode 100644
index 0000000000..9dfc23603f
--- /dev/null
+++ b/Core/MdeModulePkg/Library/CpuExceptionHandlerLibNull/CpuExceptionHandlerLibNull.uni
Binary files differ
diff --git a/Core/MdeModulePkg/Library/CustomizedDisplayLib/Colors.h b/Core/MdeModulePkg/Library/CustomizedDisplayLib/Colors.h
new file mode 100644
index 0000000000..2db8b99614
--- /dev/null
+++ b/Core/MdeModulePkg/Library/CustomizedDisplayLib/Colors.h
@@ -0,0 +1,44 @@
+/** @file
+MACRO definitions for color used in Setup Browser.
+
+Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+//
+// Unicode collation protocol in
+
+#ifndef _COLORS_H_
+#define _COLORS_H_
+
+//
+// Screen Color Settings
+//
+#define PICKLIST_HIGHLIGHT_TEXT EFI_WHITE
+#define PICKLIST_HIGHLIGHT_BACKGROUND EFI_BACKGROUND_CYAN
+#define TITLE_TEXT EFI_WHITE
+#define TITLE_BACKGROUND EFI_BACKGROUND_BLUE
+#define KEYHELP_TEXT EFI_LIGHTGRAY
+#define KEYHELP_BACKGROUND EFI_BACKGROUND_BLACK
+#define SUBTITLE_BACKGROUND EFI_BACKGROUND_LIGHTGRAY
+#define BANNER_TEXT EFI_BLUE
+#define BANNER_BACKGROUND EFI_BACKGROUND_LIGHTGRAY
+#define FIELD_TEXT_GRAYED EFI_DARKGRAY
+#define FIELD_BACKGROUND EFI_BACKGROUND_LIGHTGRAY
+#define POPUP_TEXT EFI_LIGHTGRAY
+#define POPUP_BACKGROUND EFI_BACKGROUND_BLUE
+#define POPUP_INVERSE_TEXT EFI_LIGHTGRAY
+#define POPUP_INVERSE_BACKGROUND EFI_BACKGROUND_BLACK
+#define HELP_TEXT EFI_BLUE
+#define ERROR_TEXT EFI_RED | EFI_BRIGHT
+#define INFO_TEXT EFI_YELLOW | EFI_BRIGHT
+#define ARROW_TEXT EFI_RED | EFI_BRIGHT
+#define ARROW_BACKGROUND EFI_BACKGROUND_LIGHTGRAY
+
+#endif
diff --git a/Core/MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.c b/Core/MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.c
new file mode 100644
index 0000000000..622410359c
--- /dev/null
+++ b/Core/MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.c
@@ -0,0 +1,958 @@
+/** @file
+
+ This library class defines a set of interfaces to customize Display module
+
+Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+#include "CustomizedDisplayLibInternal.h"
+
+EFI_GUID gCustomizedDisplayLibGuid = { 0x99fdc8fd, 0x849b, 0x4eba, { 0xad, 0x13, 0xfb, 0x96, 0x99, 0xc9, 0xa, 0x4d } };
+
+EFI_HII_HANDLE mCDLStringPackHandle;
+UINT16 gClassOfVfr; // Formset class information
+BOOLEAN gLibIsFirstForm = TRUE;
+BANNER_DATA *gBannerData;
+
+UINTN gFooterHeight;
+
+/**
++------------------------------------------------------------------------------+
+| Setup Page |
++------------------------------------------------------------------------------+
+
+Statement
+Statement
+Statement
+
+
+
+
+
++------------------------------------------------------------------------------+
+| F9=Reset to Defaults F10=Save |
+| ^"=Move Highlight <Spacebar> Toggles Checkbox Esc=Exit |
++------------------------------------------------------------------------------+
+ StatusBar
+**/
+
+/**
+ This funtion defines Page Frame and Backgroud.
+
+ Based on the above layout, it will be responsible for HeaderHeight, FooterHeight,
+ StatusBarHeight and Backgroud. And, it will reserve Screen for Statement.
+
+ @param[in] FormData Form Data to be shown in Page.
+ @param[out] ScreenForStatement Screen to be used for Statement. (Prompt, Value and Help)
+
+ @return Status
+**/
+EFI_STATUS
+EFIAPI
+DisplayPageFrame (
+ IN FORM_DISPLAY_ENGINE_FORM *FormData,
+ OUT EFI_SCREEN_DESCRIPTOR *ScreenForStatement
+ )
+{
+ EFI_STATUS Status;
+
+ ASSERT (FormData != NULL && ScreenForStatement != NULL);
+ if (FormData == NULL || ScreenForStatement == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = ScreenDiemensionInfoValidate (FormData);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ gClassOfVfr = FORMSET_CLASS_PLATFORM_SETUP;
+
+ ProcessExternedOpcode(FormData);
+
+ //
+ // Calculate the ScreenForStatement.
+ //
+ ScreenForStatement->BottomRow = gScreenDimensions.BottomRow - STATUS_BAR_HEIGHT - gFooterHeight;
+ if (gClassOfVfr == FORMSET_CLASS_FRONT_PAGE) {
+ ScreenForStatement->TopRow = gScreenDimensions.TopRow + FRONT_PAGE_HEADER_HEIGHT;
+ } else {
+ ScreenForStatement->TopRow = gScreenDimensions.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT;
+ }
+ ScreenForStatement->LeftColumn = gScreenDimensions.LeftColumn;
+ ScreenForStatement->RightColumn = gScreenDimensions.RightColumn;
+
+ if ((gLibIsFirstForm) || ((FormData->Attribute & HII_DISPLAY_MODAL) != 0)) {
+ //
+ // Ensure we are in Text mode
+ //
+ gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
+ ClearLines (0, gScreenDimensions.RightColumn, 0, gScreenDimensions.BottomRow, KEYHELP_BACKGROUND);
+ gLibIsFirstForm = FALSE;
+ }
+
+ //
+ // Don't print frame for modal form.
+ //
+ if ((FormData->Attribute & HII_DISPLAY_MODAL) != 0) {
+ return EFI_SUCCESS;
+ }
+
+ if (gClassOfVfr == FORMSET_CLASS_FRONT_PAGE) {
+ PrintBannerInfo (FormData);
+ }
+
+ PrintFramework (FormData);
+
+ UpdateStatusBar(NV_UPDATE_REQUIRED, FormData->SettingChangedFlag);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function updates customized key panel's help information.
+ The library will prepare those Strings for the basic key, ESC, Enter, Up/Down/Left/Right, +/-.
+ and arrange them in Footer panel.
+
+ @param[in] FormData Form Data to be shown in Page. FormData has the highlighted statement.
+ @param[in] Statement The statement current selected.
+ @param[in] Selected Whether or not a tag be selected. TRUE means Enter has hit this question.
+**/
+VOID
+EFIAPI
+RefreshKeyHelp (
+ IN FORM_DISPLAY_ENGINE_FORM *FormData,
+ IN FORM_DISPLAY_ENGINE_STATEMENT *Statement,
+ IN BOOLEAN Selected
+ )
+{
+ UINTN SecCol;
+ UINTN ThdCol;
+ UINTN RightColumnOfHelp;
+ UINTN TopRowOfHelp;
+ UINTN BottomRowOfHelp;
+ UINTN StartColumnOfHelp;
+ EFI_IFR_NUMERIC *NumericOp;
+ EFI_IFR_DATE *DateOp;
+ EFI_IFR_TIME *TimeOp;
+ BOOLEAN HexDisplay;
+ UINTN ColumnWidth1;
+ UINTN ColumnWidth2;
+ UINTN ColumnWidth3;
+ CHAR16 *ColumnStr1;
+ CHAR16 *ColumnStr2;
+ CHAR16 *ColumnStr3;
+
+ ASSERT (FormData != NULL);
+ if (FormData == NULL) {
+ return;
+ }
+
+ gST->ConOut->SetAttribute (gST->ConOut, KEYHELP_TEXT | KEYHELP_BACKGROUND);
+
+ if ((FormData->Attribute & HII_DISPLAY_MODAL) != 0) {
+ return;
+ }
+
+ SecCol = gScreenDimensions.LeftColumn + (gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn) / 3;
+ ThdCol = gScreenDimensions.LeftColumn + (gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn) / 3 * 2;
+
+ //
+ // + 2 means leave 1 space before the first hotkey info.
+ //
+ StartColumnOfHelp = gScreenDimensions.LeftColumn + 2;
+ RightColumnOfHelp = gScreenDimensions.RightColumn - 1;
+ TopRowOfHelp = gScreenDimensions.BottomRow - STATUS_BAR_HEIGHT - gFooterHeight + 1;
+ BottomRowOfHelp = gScreenDimensions.BottomRow - STATUS_BAR_HEIGHT - 2;
+
+ ColumnWidth1 = SecCol - StartColumnOfHelp;
+ ColumnWidth2 = ThdCol - SecCol;
+ ColumnWidth3 = RightColumnOfHelp - ThdCol;
+ ColumnStr1 = gLibEmptyString;
+ ColumnStr2 = gLibEmptyString;
+ ColumnStr3 = gLibEmptyString;
+
+ //
+ // Clean the space at gScreenDimensions.LeftColumn + 1.
+ //
+ PrintStringAtWithWidth (StartColumnOfHelp - 1, BottomRowOfHelp, gLibEmptyString, 1);
+ PrintStringAtWithWidth (StartColumnOfHelp - 1, TopRowOfHelp, gLibEmptyString, 1);
+
+ if (Statement == NULL) {
+ //
+ // Print Key for Form without showable statement.
+ //
+ PrintHotKeyHelpString (FormData, TRUE);
+ PrintStringAtWithWidth (StartColumnOfHelp, BottomRowOfHelp, gLibEmptyString, ColumnWidth1);
+ PrintStringAtWithWidth (SecCol, BottomRowOfHelp, gLibEmptyString, ColumnWidth2);
+ PrintStringAtWithWidth (StartColumnOfHelp, TopRowOfHelp, gLibEmptyString, ColumnWidth1);
+ if (gClassOfVfr == FORMSET_CLASS_PLATFORM_SETUP) {
+ ColumnStr3 = gEscapeString;
+ }
+ PrintStringAtWithWidth (ThdCol, BottomRowOfHelp, ColumnStr3, ColumnWidth3);
+
+ return;
+ }
+
+ HexDisplay = FALSE;
+ NumericOp = NULL;
+ DateOp = NULL;
+ TimeOp = NULL;
+ if (Statement->OpCode->OpCode == EFI_IFR_NUMERIC_OP) {
+ NumericOp = (EFI_IFR_NUMERIC *) Statement->OpCode;
+ HexDisplay = (NumericOp->Flags & EFI_IFR_DISPLAY_UINT_HEX) == EFI_IFR_DISPLAY_UINT_HEX;
+ } else if (Statement->OpCode->OpCode == EFI_IFR_DATE_OP) {
+ DateOp = (EFI_IFR_DATE *) Statement->OpCode;
+ HexDisplay = (DateOp->Flags & EFI_IFR_DISPLAY_UINT_HEX) == EFI_IFR_DISPLAY_UINT_HEX;
+ } else if (Statement->OpCode->OpCode == EFI_IFR_TIME_OP) {
+ TimeOp = (EFI_IFR_TIME *) Statement->OpCode;
+ HexDisplay = (TimeOp->Flags & EFI_IFR_DISPLAY_UINT_HEX) == EFI_IFR_DISPLAY_UINT_HEX;
+ }
+ switch (Statement->OpCode->OpCode) {
+ case EFI_IFR_ORDERED_LIST_OP:
+ case EFI_IFR_ONE_OF_OP:
+ case EFI_IFR_NUMERIC_OP:
+ case EFI_IFR_TIME_OP:
+ case EFI_IFR_DATE_OP:
+ if (!Selected) {
+ PrintHotKeyHelpString (FormData, TRUE);
+
+ if (gClassOfVfr == FORMSET_CLASS_PLATFORM_SETUP) {
+ ColumnStr3 = gEscapeString;
+ }
+ PrintStringAtWithWidth (ThdCol, BottomRowOfHelp, ColumnStr3, ColumnWidth3);
+
+ if ((Statement->OpCode->OpCode == EFI_IFR_DATE_OP) ||
+ (Statement->OpCode->OpCode == EFI_IFR_TIME_OP)) {
+ PrintAt (
+ ColumnWidth1,
+ StartColumnOfHelp,
+ BottomRowOfHelp,
+ L"%c%c%c%c%s",
+ ARROW_UP,
+ ARROW_DOWN,
+ ARROW_RIGHT,
+ ARROW_LEFT,
+ gMoveHighlight
+ );
+ PrintStringAtWithWidth (SecCol, BottomRowOfHelp, gEnterString, ColumnWidth2);
+ PrintStringAtWithWidth (StartColumnOfHelp, TopRowOfHelp, gAdjustNumber, ColumnWidth1);
+ } else {
+ PrintAt (ColumnWidth1, StartColumnOfHelp, BottomRowOfHelp, L"%c%c%s", ARROW_UP, ARROW_DOWN, gMoveHighlight);
+ if (Statement->OpCode->OpCode == EFI_IFR_NUMERIC_OP && NumericOp != NULL && LibGetFieldFromNum(Statement->OpCode) != 0) {
+ ColumnStr1 = gAdjustNumber;
+ }
+ PrintStringAtWithWidth (StartColumnOfHelp, TopRowOfHelp, ColumnStr1, ColumnWidth1);
+ PrintStringAtWithWidth (SecCol, BottomRowOfHelp, gEnterString, ColumnWidth2);
+ }
+ } else {
+ PrintHotKeyHelpString (FormData, FALSE);
+ PrintStringAtWithWidth (SecCol, BottomRowOfHelp, gEnterCommitString, ColumnWidth2);
+
+ //
+ // If it is a selected numeric with manual input, display different message
+ //
+ if ((Statement->OpCode->OpCode == EFI_IFR_NUMERIC_OP) ||
+ (Statement->OpCode->OpCode == EFI_IFR_DATE_OP) ||
+ (Statement->OpCode->OpCode == EFI_IFR_TIME_OP)) {
+ ColumnStr2 = HexDisplay ? gHexNumericInput : gDecNumericInput;
+ PrintStringAtWithWidth (StartColumnOfHelp, BottomRowOfHelp, gLibEmptyString, ColumnWidth1);
+ } else {
+ PrintAt (ColumnWidth1, StartColumnOfHelp, BottomRowOfHelp, L"%c%c%s", ARROW_UP, ARROW_DOWN, gMoveHighlight);
+ }
+
+ if (Statement->OpCode->OpCode == EFI_IFR_ORDERED_LIST_OP) {
+ ColumnStr1 = gPlusString;
+ ColumnStr3 = gMinusString;
+ }
+ PrintStringAtWithWidth (StartColumnOfHelp, TopRowOfHelp, ColumnStr1, ColumnWidth1);
+ PrintStringAtWithWidth (ThdCol, TopRowOfHelp, ColumnStr3, ColumnWidth3);
+ PrintStringAtWithWidth (SecCol, TopRowOfHelp, ColumnStr2, ColumnWidth2);
+
+ PrintStringAtWithWidth (ThdCol, BottomRowOfHelp, gEnterEscapeString, ColumnWidth3);
+ }
+ break;
+
+ case EFI_IFR_CHECKBOX_OP:
+ PrintHotKeyHelpString (FormData, TRUE);
+
+ if (gClassOfVfr == FORMSET_CLASS_PLATFORM_SETUP) {
+ ColumnStr3 = gEscapeString;
+ }
+ PrintStringAtWithWidth (ThdCol, BottomRowOfHelp, ColumnStr3, ColumnWidth3);
+
+ PrintAt (ColumnWidth1, StartColumnOfHelp, BottomRowOfHelp, L"%c%c%s", ARROW_UP, ARROW_DOWN, gMoveHighlight);
+ PrintStringAtWithWidth (SecCol, BottomRowOfHelp, gToggleCheckBox, ColumnWidth2);
+ PrintStringAtWithWidth (StartColumnOfHelp, TopRowOfHelp, gLibEmptyString, ColumnWidth1);
+ break;
+
+ case EFI_IFR_REF_OP:
+ case EFI_IFR_PASSWORD_OP:
+ case EFI_IFR_STRING_OP:
+ case EFI_IFR_TEXT_OP:
+ case EFI_IFR_ACTION_OP:
+ case EFI_IFR_RESET_BUTTON_OP:
+ case EFI_IFR_SUBTITLE_OP:
+ if (!Selected) {
+ PrintHotKeyHelpString (FormData, TRUE);
+
+ if (gClassOfVfr == FORMSET_CLASS_PLATFORM_SETUP) {
+ ColumnStr3 = gEscapeString;
+ }
+ PrintStringAtWithWidth (ThdCol, BottomRowOfHelp, ColumnStr3, ColumnWidth3);
+
+ PrintAt (ColumnWidth1, StartColumnOfHelp, BottomRowOfHelp, L"%c%c%s", ARROW_UP, ARROW_DOWN, gMoveHighlight);
+ if (Statement->OpCode->OpCode != EFI_IFR_TEXT_OP && Statement->OpCode->OpCode != EFI_IFR_SUBTITLE_OP) {
+ ColumnStr2 = gEnterString;
+ }
+ PrintStringAtWithWidth (SecCol, BottomRowOfHelp, ColumnStr2, ColumnWidth2);
+ PrintStringAtWithWidth (StartColumnOfHelp, TopRowOfHelp, ColumnStr1, ColumnWidth1);
+ } else {
+ PrintHotKeyHelpString (FormData, FALSE);
+ if (Statement->OpCode->OpCode != EFI_IFR_REF_OP) {
+ ColumnStr2 = gEnterCommitString;
+ ColumnStr3 = gEnterEscapeString;
+ }
+ PrintStringAtWithWidth (StartColumnOfHelp, TopRowOfHelp, ColumnStr1, ColumnWidth1);
+ PrintStringAtWithWidth (StartColumnOfHelp, BottomRowOfHelp, ColumnStr1, ColumnWidth1);
+ PrintStringAtWithWidth (SecCol, BottomRowOfHelp, ColumnStr2, ColumnWidth2);
+ PrintStringAtWithWidth (ThdCol, BottomRowOfHelp, ColumnStr3, ColumnWidth3);
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+/**
+ Update status bar.
+
+ This function updates the status bar on the bottom of menu screen. It just shows StatusBar.
+ Original logic in this function should be splitted out.
+
+ @param[in] MessageType The type of message to be shown. InputError or Configuration Changed.
+ @param[in] State Show or Clear Message.
+**/
+VOID
+EFIAPI
+UpdateStatusBar (
+ IN UINTN MessageType,
+ IN BOOLEAN State
+ )
+{
+ UINTN Index;
+ CHAR16 OptionWidth;
+
+ OptionWidth = (CHAR16) ((gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn) / 3);
+
+ switch (MessageType) {
+ case INPUT_ERROR:
+ if (State) {
+ gST->ConOut->SetAttribute (gST->ConOut, ERROR_TEXT);
+ PrintStringAt (
+ gScreenDimensions.LeftColumn + OptionWidth,
+ gScreenDimensions.BottomRow - 1,
+ gInputErrorMessage
+ );
+ } else {
+ gST->ConOut->SetAttribute (gST->ConOut, KEYHELP_BACKGROUND);
+ for (Index = 0; Index < (LibGetStringWidth (gInputErrorMessage) - 2) / 2; Index++) {
+ PrintStringAt (gScreenDimensions.LeftColumn + OptionWidth + Index, gScreenDimensions.BottomRow - 1, L" ");
+ }
+ }
+ break;
+
+ case NV_UPDATE_REQUIRED:
+ //
+ // Global setting support. Show configuration change on every form.
+ //
+ if (State) {
+ gST->ConOut->SetAttribute (gST->ConOut, INFO_TEXT);
+ PrintStringAt (
+ gScreenDimensions.LeftColumn + OptionWidth * 2,
+ gScreenDimensions.BottomRow - 1,
+ gNvUpdateMessage
+ );
+ } else {
+ gST->ConOut->SetAttribute (gST->ConOut, KEYHELP_BACKGROUND);
+ for (Index = 0; Index < (LibGetStringWidth (gNvUpdateMessage) - 2) / 2; Index++) {
+ PrintStringAt (
+ (gScreenDimensions.LeftColumn + OptionWidth * 2 + Index),
+ gScreenDimensions.BottomRow - 1,
+ L" "
+ );
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+/**
+ Create popup window. It will replace CreateDialog().
+
+ This function draws OEM/Vendor specific pop up windows.
+
+ @param[out] Key User Input Key
+ @param ... String to be shown in Popup. The variable argument list is terminated by a NULL.
+
+**/
+VOID
+EFIAPI
+CreateDialog (
+ OUT EFI_INPUT_KEY *Key, OPTIONAL
+ ...
+ )
+{
+ VA_LIST Marker;
+ EFI_INPUT_KEY KeyValue;
+ EFI_STATUS Status;
+ UINTN LargestString;
+ UINTN LineNum;
+ UINTN Index;
+ UINTN Count;
+ CHAR16 Character;
+ UINTN Start;
+ UINTN End;
+ UINTN Top;
+ UINTN Bottom;
+ CHAR16 *String;
+ UINTN DimensionsWidth;
+ UINTN DimensionsHeight;
+ UINTN CurrentAttribute;
+ BOOLEAN CursorVisible;
+
+ //
+ // If screen dimension info is not ready, get it from console.
+ //
+ if (gScreenDimensions.RightColumn == 0 || gScreenDimensions.BottomRow == 0) {
+ ZeroMem (&gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));
+ gST->ConOut->QueryMode (
+ gST->ConOut,
+ gST->ConOut->Mode->Mode,
+ &gScreenDimensions.RightColumn,
+ &gScreenDimensions.BottomRow
+ );
+ }
+
+ DimensionsWidth = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn;
+ DimensionsHeight = gScreenDimensions.BottomRow - gScreenDimensions.TopRow;
+
+ LargestString = 0;
+ LineNum = 0;
+ VA_START (Marker, Key);
+ while ((String = VA_ARG (Marker, CHAR16 *)) != NULL) {
+ LineNum ++;
+
+ if ((LibGetStringWidth (String) / 2) > LargestString) {
+ LargestString = (LibGetStringWidth (String) / 2);
+ }
+ }
+ VA_END (Marker);
+
+ if ((LargestString + 2) > DimensionsWidth) {
+ LargestString = DimensionsWidth - 2;
+ }
+
+ CurrentAttribute = gST->ConOut->Mode->Attribute;
+ CursorVisible = gST->ConOut->Mode->CursorVisible;
+ gST->ConOut->EnableCursor (gST->ConOut, FALSE);
+ gST->ConOut->SetAttribute (gST->ConOut, GetPopupColor ());
+
+ //
+ // Subtract the PopUp width from total Columns, allow for one space extra on
+ // each end plus a border.
+ //
+ Start = (DimensionsWidth - LargestString - 2) / 2 + gScreenDimensions.LeftColumn + 1;
+ End = Start + LargestString + 1;
+
+ Top = ((DimensionsHeight - LineNum - 2) / 2) + gScreenDimensions.TopRow - 1;
+ Bottom = Top + LineNum + 2;
+
+ Character = BOXDRAW_DOWN_RIGHT;
+ PrintCharAt (Start, Top, Character);
+ Character = BOXDRAW_HORIZONTAL;
+ for (Index = Start; Index + 2 < End; Index++) {
+ PrintCharAt ((UINTN)-1, (UINTN)-1, Character);
+ }
+
+ Character = BOXDRAW_DOWN_LEFT;
+ PrintCharAt ((UINTN)-1, (UINTN)-1, Character);
+ Character = BOXDRAW_VERTICAL;
+
+ Count = 0;
+ VA_START (Marker, Key);
+ for (Index = Top; Index + 2 < Bottom; Index++, Count++) {
+ String = VA_ARG (Marker, CHAR16*);
+
+ if (String[0] == CHAR_NULL) {
+ //
+ // Passing in a NULL results in a blank space
+ //
+ ClearLines (Start, End, Index + 1, Index + 1, GetPopupColor ());
+ } else if (String[0] == L' ') {
+ //
+ // Passing in a space results in the assumption that this is where typing will occur
+ //
+ ClearLines (Start + 1, End - 1, Index + 1, Index + 1, POPUP_INVERSE_TEXT | POPUP_INVERSE_BACKGROUND);
+ PrintStringAt (
+ ((DimensionsWidth - LibGetStringWidth (String) / 2) / 2) + gScreenDimensions.LeftColumn + 1,
+ Index + 1,
+ String + 1
+ );
+ } else {
+ //
+ // This will clear the background of the line - we never know who might have been
+ // here before us. This differs from the next clear in that it used the non-reverse
+ // video for normal printing.
+ //
+ ClearLines (Start, End, Index + 1, Index + 1, GetPopupColor ());
+ PrintStringAt (
+ ((DimensionsWidth - LibGetStringWidth (String) / 2) / 2) + gScreenDimensions.LeftColumn + 1,
+ Index + 1,
+ String
+ );
+ }
+
+ gST->ConOut->SetAttribute (gST->ConOut, GetPopupColor ());
+ PrintCharAt (Start, Index + 1, Character);
+ PrintCharAt (End - 1, Index + 1, Character);
+ }
+ VA_END (Marker);
+
+ Character = BOXDRAW_UP_RIGHT;
+ PrintCharAt (Start, Bottom - 1, Character);
+ Character = BOXDRAW_HORIZONTAL;
+ for (Index = Start; Index + 2 < End; Index++) {
+ PrintCharAt ((UINTN)-1, (UINTN) -1, Character);
+ }
+
+ Character = BOXDRAW_UP_LEFT;
+ PrintCharAt ((UINTN)-1, (UINTN) -1, Character);
+
+ if (Key != NULL) {
+ Status = WaitForKeyStroke (&KeyValue);
+ ASSERT_EFI_ERROR (Status);
+ CopyMem (Key, &KeyValue, sizeof (EFI_INPUT_KEY));
+ }
+
+ gST->ConOut->SetAttribute (gST->ConOut, CurrentAttribute);
+ gST->ConOut->EnableCursor (gST->ConOut, CursorVisible);
+}
+
+/**
+ Confirm how to handle the changed data.
+
+ @return Action BROWSER_ACTION_SUBMIT, BROWSER_ACTION_DISCARD or other values.
+**/
+UINTN
+EFIAPI
+ConfirmDataChange (
+ VOID
+ )
+{
+ CHAR16 YesResponse;
+ CHAR16 NoResponse;
+ EFI_INPUT_KEY Key;
+
+ gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
+
+ YesResponse = gYesResponse[0];
+ NoResponse = gNoResponse[0];
+
+ //
+ // If NV flag is up, prompt user
+ //
+ do {
+ CreateDialog (&Key, gLibEmptyString, gSaveChanges, gAreYouSure, gLibEmptyString, NULL);
+ } while
+ (
+ (Key.ScanCode != SCAN_ESC) &&
+ ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (NoResponse | UPPER_LOWER_CASE_OFFSET)) &&
+ ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (YesResponse | UPPER_LOWER_CASE_OFFSET))
+ );
+
+ if (Key.ScanCode == SCAN_ESC) {
+ return BROWSER_ACTION_NONE;
+ } else if ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (YesResponse | UPPER_LOWER_CASE_OFFSET)) {
+ return BROWSER_ACTION_SUBMIT;
+ } else {
+ return BROWSER_ACTION_DISCARD;
+ }
+}
+
+/**
+ OEM specifies whether Setup exits Page by ESC key.
+
+ This function customized the behavior that whether Setup exits Page so that
+ system able to boot when configuration is not changed.
+
+ @retval TRUE Exits FrontPage
+ @retval FALSE Don't exit FrontPage.
+**/
+BOOLEAN
+EFIAPI
+FormExitPolicy (
+ VOID
+ )
+{
+ return gClassOfVfr == FORMSET_CLASS_FRONT_PAGE ? FALSE : TRUE;
+}
+
+/**
+ Set Timeout value for a ceratain Form to get user response.
+
+ This function allows to set timeout value on a ceratain form if necessary.
+ If timeout is not zero, the form will exit if user has no response in timeout.
+
+ @param[in] FormData Form Data to be shown in Page
+
+ @return 0 No timeout for this form.
+ @return > 0 Timeout value in 100 ns units.
+**/
+UINT64
+EFIAPI
+FormExitTimeout (
+ IN FORM_DISPLAY_ENGINE_FORM *FormData
+ )
+{
+ return 0;
+}
+//
+// Print Functions
+//
+/**
+ Prints a unicode string to the default console, at
+ the supplied cursor position, using L"%s" format.
+
+ @param Column The cursor position to print the string at. When it is -1, use current Position.
+ @param Row The cursor position to print the string at. When it is -1, use current Position.
+ @param String String pointer.
+
+ @return Length of string printed to the console
+
+**/
+UINTN
+EFIAPI
+PrintStringAt (
+ IN UINTN Column,
+ IN UINTN Row,
+ IN CHAR16 *String
+ )
+{
+ return PrintAt (0, Column, Row, L"%s", String);
+}
+
+/**
+ Prints a unicode string to the default console, at
+ the supplied cursor position, using L"%s" format.
+
+ @param Column The cursor position to print the string at. When it is -1, use current Position.
+ @param Row The cursor position to print the string at. When it is -1, use current Position.
+ @param String String pointer.
+ @param Width Width for String.
+
+ @return Length of string printed to the console
+
+**/
+UINTN
+EFIAPI
+PrintStringAtWithWidth (
+ IN UINTN Column,
+ IN UINTN Row,
+ IN CHAR16 *String,
+ IN UINTN Width
+ )
+{
+ return PrintAt (Width, Column, Row, L"%s", String);
+}
+
+/**
+ Prints a chracter to the default console, at
+ the supplied cursor position, using L"%c" format.
+
+ @param Column The cursor position to print the string at. When it is -1, use current Position.
+ @param Row The cursor position to print the string at. When it is -1, use current Position.
+ @param Character Character to print.
+
+ @return Length of string printed to the console.
+
+**/
+UINTN
+EFIAPI
+PrintCharAt (
+ IN UINTN Column,
+ IN UINTN Row,
+ CHAR16 Character
+ )
+{
+ return PrintAt (0, Column, Row, L"%c", Character);
+}
+
+/**
+ Clear retangle with specified text attribute.
+
+ @param LeftColumn Left column of retangle.
+ @param RightColumn Right column of retangle.
+ @param TopRow Start row of retangle.
+ @param BottomRow End row of retangle.
+ @param TextAttribute The character foreground and background.
+
+**/
+VOID
+EFIAPI
+ClearLines (
+ IN UINTN LeftColumn,
+ IN UINTN RightColumn,
+ IN UINTN TopRow,
+ IN UINTN BottomRow,
+ IN UINTN TextAttribute
+ )
+{
+ CHAR16 *Buffer;
+ UINTN Row;
+
+ //
+ // For now, allocate an arbitrarily long buffer
+ //
+ Buffer = AllocateZeroPool (0x10000);
+ ASSERT (Buffer != NULL);
+
+ //
+ // Set foreground and background as defined
+ //
+ gST->ConOut->SetAttribute (gST->ConOut, TextAttribute);
+
+ //
+ // Much faster to buffer the long string instead of print it a character at a time
+ //
+ LibSetUnicodeMem (Buffer, RightColumn - LeftColumn, L' ');
+
+ //
+ // Clear the desired area with the appropriate foreground/background
+ //
+ for (Row = TopRow; Row <= BottomRow; Row++) {
+ PrintStringAt (LeftColumn, Row, Buffer);
+ }
+
+ gST->ConOut->SetCursorPosition (gST->ConOut, LeftColumn, TopRow);
+
+ FreePool (Buffer);
+}
+
+//
+// Color Setting Functions
+//
+
+/**
+ Get OEM/Vendor specific popup attribute colors.
+
+ @retval Byte code color setting for popup color.
+**/
+UINT8
+EFIAPI
+GetPopupColor (
+ VOID
+ )
+{
+ return POPUP_TEXT | POPUP_BACKGROUND;
+}
+
+/**
+ Get OEM/Vendor specific popup attribute colors.
+
+ @retval Byte code color setting for popup inverse color.
+**/
+UINT8
+EFIAPI
+GetPopupInverseColor (
+ VOID
+ )
+{
+ return POPUP_INVERSE_TEXT | POPUP_INVERSE_BACKGROUND;
+}
+
+/**
+ Get OEM/Vendor specific PickList color attribute.
+
+ @retval Byte code color setting for pick list color.
+**/
+UINT8
+EFIAPI
+GetPickListColor (
+ VOID
+ )
+{
+ return PICKLIST_HIGHLIGHT_TEXT | PICKLIST_HIGHLIGHT_BACKGROUND;
+}
+
+/**
+ Get OEM/Vendor specific arrow color attribute.
+
+ @retval Byte code color setting for arrow color.
+**/
+UINT8
+EFIAPI
+GetArrowColor (
+ VOID
+ )
+{
+ return ARROW_TEXT | ARROW_BACKGROUND;
+}
+
+/**
+ Get OEM/Vendor specific info text color attribute.
+
+ @retval Byte code color setting for info text color.
+**/
+UINT8
+EFIAPI
+GetInfoTextColor (
+ VOID
+ )
+{
+ return INFO_TEXT | FIELD_BACKGROUND;
+}
+
+/**
+ Get OEM/Vendor specific help text color attribute.
+
+ @retval Byte code color setting for help text color.
+**/
+UINT8
+EFIAPI
+GetHelpTextColor (
+ VOID
+ )
+{
+ return HELP_TEXT | FIELD_BACKGROUND;
+}
+
+/**
+ Get OEM/Vendor specific grayed out text color attribute.
+
+ @retval Byte code color setting for grayed out text color.
+**/
+UINT8
+EFIAPI
+GetGrayedTextColor (
+ VOID
+ )
+{
+ return FIELD_TEXT_GRAYED | FIELD_BACKGROUND;
+}
+
+/**
+ Get OEM/Vendor specific highlighted text color attribute.
+
+ @retval Byte code color setting for highlight text color.
+**/
+UINT8
+EFIAPI
+GetHighlightTextColor (
+ VOID
+ )
+{
+ return PcdGet8 (PcdBrowserFieldTextHighlightColor) | PcdGet8 (PcdBrowserFieldBackgroundHighlightColor);
+}
+
+/**
+ Get OEM/Vendor specific field text color attribute.
+
+ @retval Byte code color setting for field text color.
+**/
+UINT8
+EFIAPI
+GetFieldTextColor (
+ VOID
+ )
+{
+ return PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND;
+}
+
+/**
+ Get OEM/Vendor specific subtitle text color attribute.
+
+ @retval Byte code color setting for subtitle text color.
+**/
+UINT8
+EFIAPI
+GetSubTitleTextColor (
+ VOID
+ )
+{
+ return PcdGet8 (PcdBrowserSubtitleTextColor) | FIELD_BACKGROUND;
+}
+
+/**
+ Clear Screen to the initial state.
+**/
+VOID
+EFIAPI
+ClearDisplayPage (
+ VOID
+ )
+{
+ gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
+ gST->ConOut->ClearScreen (gST->ConOut);
+ gLibIsFirstForm = TRUE;
+}
+
+/**
+ Constructor of Customized Display Library Instance.
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
+
+**/
+EFI_STATUS
+EFIAPI
+CustomizedDisplayLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ mCDLStringPackHandle = HiiAddPackages (&gCustomizedDisplayLibGuid, ImageHandle, CustomizedDisplayLibStrings, NULL);
+ ASSERT (mCDLStringPackHandle != NULL);
+
+ InitializeLibStrings();
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Destructor of Customized Display Library Instance.
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The destructor completed successfully.
+ @retval Other value The destructor did not complete successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+CustomizedDisplayLibDestructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ HiiRemovePackages(mCDLStringPackHandle);
+
+ FreeLibStrings ();
+
+ return EFI_SUCCESS;
+}
+
diff --git a/Core/MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.inf b/Core/MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.inf
new file mode 100644
index 0000000000..23528948a3
--- /dev/null
+++ b/Core/MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.inf
@@ -0,0 +1,65 @@
+## @file
+# Customize display library used by display engine.
+#
+# Copyright (c) 2013 - 2015, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = CustomizedDisplayLib
+ MODULE_UNI_FILE = CustomizedDisplayLibModStrs.uni
+ FILE_GUID = 80B92017-EC64-4923-938D-94FAEE85832E
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = CustomizedDisplayLib|DXE_DRIVER UEFI_APPLICATION
+ CONSTRUCTOR = CustomizedDisplayLibConstructor
+ DESTRUCTOR = CustomizedDisplayLibDestructor
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ CustomizedDisplayLib.c
+ Colors.h
+ CustomizedDisplayLibInternal.h
+ CustomizedDisplayLibInternal.c
+ CustomizedDisplayLib.uni
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ MemoryAllocationLib
+ BaseLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ UefiRuntimeServicesTableLib
+ BaseMemoryLib
+ DebugLib
+ PrintLib
+ HiiLib
+ DevicePathLib
+ PcdLib
+
+[Guids]
+ gEfiIfrTianoGuid ## SOMETIMES_CONSUMES ## UNDEFINED
+
+[Protocols]
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdBrowserSubtitleTextColor ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdBrowserFieldTextColor ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdBrowserFieldTextHighlightColor ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdBrowserFieldBackgroundHighlightColor ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFrontPageFormSetGuid ## CONSUMES \ No newline at end of file
diff --git a/Core/MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.uni b/Core/MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.uni
new file mode 100644
index 0000000000..18a5c3b563
--- /dev/null
+++ b/Core/MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.uni
Binary files differ
diff --git a/Core/MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLibInternal.c b/Core/MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLibInternal.c
new file mode 100644
index 0000000000..bc14a9dd76
--- /dev/null
+++ b/Core/MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLibInternal.c
@@ -0,0 +1,984 @@
+/** @file
+
+ This library class defines a set of interfaces to customize Display module
+
+Copyright (c) 2013-2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+#include "CustomizedDisplayLibInternal.h"
+
+EFI_SCREEN_DESCRIPTOR gScreenDimensions;
+CHAR16 *mLibUnknownString;
+extern EFI_HII_HANDLE mCDLStringPackHandle;
+CHAR16 *mSpaceBuffer;
+#define SPACE_BUFFER_SIZE 1000
+
+//
+// Browser Global Strings
+//
+CHAR16 *gEnterString;
+CHAR16 *gEnterCommitString;
+CHAR16 *gEnterEscapeString;
+CHAR16 *gEscapeString;
+CHAR16 *gMoveHighlight;
+CHAR16 *gDecNumericInput;
+CHAR16 *gHexNumericInput;
+CHAR16 *gToggleCheckBox;
+CHAR16 *gLibEmptyString;
+CHAR16 *gAreYouSure;
+CHAR16 *gYesResponse;
+CHAR16 *gNoResponse;
+CHAR16 *gPlusString;
+CHAR16 *gMinusString;
+CHAR16 *gAdjustNumber;
+CHAR16 *gSaveChanges;
+CHAR16 *gNvUpdateMessage;
+CHAR16 *gInputErrorMessage;
+
+/**
+
+ Print banner info for front page.
+
+ @param[in] FormData Form Data to be shown in Page
+
+**/
+VOID
+PrintBannerInfo (
+ IN FORM_DISPLAY_ENGINE_FORM *FormData
+ )
+{
+ UINT8 Line;
+ UINT8 Alignment;
+ CHAR16 *StrFrontPageBanner;
+ UINT8 RowIdx;
+ UINT8 ColumnIdx;
+
+ //
+ // ClearLines(0, LocalScreen.RightColumn, 0, BANNER_HEIGHT-1, BANNER_TEXT | BANNER_BACKGROUND);
+ //
+ ClearLines (
+ gScreenDimensions.LeftColumn,
+ gScreenDimensions.RightColumn,
+ gScreenDimensions.TopRow,
+ FRONT_PAGE_HEADER_HEIGHT - 1 + gScreenDimensions.TopRow,
+ BANNER_TEXT | BANNER_BACKGROUND
+ );
+
+ //
+ // for (Line = 0; Line < BANNER_HEIGHT; Line++) {
+ //
+ for (Line = (UINT8) gScreenDimensions.TopRow; Line < BANNER_HEIGHT + (UINT8) gScreenDimensions.TopRow; Line++) {
+ //
+ // for (Alignment = 0; Alignment < BANNER_COLUMNS; Alignment++) {
+ //
+ for (Alignment = (UINT8) gScreenDimensions.LeftColumn;
+ Alignment < BANNER_COLUMNS + (UINT8) gScreenDimensions.LeftColumn;
+ Alignment++
+ ) {
+ RowIdx = (UINT8) (Line - (UINT8) gScreenDimensions.TopRow);
+ ColumnIdx = (UINT8) (Alignment - (UINT8) gScreenDimensions.LeftColumn);
+
+ ASSERT (RowIdx < BANNER_HEIGHT && ColumnIdx < BANNER_COLUMNS);
+
+ if (gBannerData!= NULL && gBannerData->Banner[RowIdx][ColumnIdx] != 0x0000) {
+ StrFrontPageBanner = LibGetToken (gBannerData->Banner[RowIdx][ColumnIdx], FormData->HiiHandle);
+ } else {
+ continue;
+ }
+
+ switch (Alignment - gScreenDimensions.LeftColumn) {
+ case 0:
+ //
+ // Handle left column
+ //
+ PrintStringAt (gScreenDimensions.LeftColumn + BANNER_LEFT_COLUMN_INDENT, Line, StrFrontPageBanner);
+ break;
+
+ case 1:
+ //
+ // Handle center column
+ //
+ PrintStringAt (
+ gScreenDimensions.LeftColumn + (gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn) / 3,
+ Line,
+ StrFrontPageBanner
+ );
+ break;
+
+ case 2:
+ //
+ // Handle right column
+ //
+ PrintStringAt (
+ gScreenDimensions.LeftColumn + (gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn) * 2 / 3,
+ Line,
+ StrFrontPageBanner
+ );
+ break;
+ }
+
+ FreePool (StrFrontPageBanner);
+ }
+ }
+}
+
+/**
+ Print framework and form title for a page.
+
+ @param[in] FormData Form Data to be shown in Page
+**/
+VOID
+PrintFramework (
+ IN FORM_DISPLAY_ENGINE_FORM *FormData
+ )
+{
+ UINTN Index;
+ CHAR16 Character;
+ CHAR16 *Buffer;
+ UINTN Row;
+ CHAR16 *TitleStr;
+ UINTN TitleColumn;
+
+ if (gClassOfVfr != FORMSET_CLASS_PLATFORM_SETUP) {
+ //
+ // Only Setup page needs Framework
+ //
+ ClearLines (
+ gScreenDimensions.LeftColumn,
+ gScreenDimensions.RightColumn,
+ gScreenDimensions.BottomRow - STATUS_BAR_HEIGHT - gFooterHeight,
+ gScreenDimensions.BottomRow - STATUS_BAR_HEIGHT - 1,
+ KEYHELP_TEXT | KEYHELP_BACKGROUND
+ );
+ return;
+ }
+
+ Buffer = AllocateZeroPool (0x10000);
+ ASSERT (Buffer != NULL);
+ Character = BOXDRAW_HORIZONTAL;
+ for (Index = 0; Index + 2 < (gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn); Index++) {
+ Buffer[Index] = Character;
+ }
+
+ //
+ // Print Top border line
+ // +------------------------------------------------------------------------------+
+ // ? ?
+ // +------------------------------------------------------------------------------+
+ //
+ gST->ConOut->SetAttribute (gST->ConOut, TITLE_TEXT | TITLE_BACKGROUND);
+ Character = BOXDRAW_DOWN_RIGHT;
+
+ PrintCharAt (gScreenDimensions.LeftColumn, gScreenDimensions.TopRow, Character);
+ PrintStringAt ((UINTN) -1, (UINTN) -1, Buffer);
+
+ Character = BOXDRAW_DOWN_LEFT;
+ PrintCharAt ((UINTN) -1, (UINTN) -1, Character);
+
+ Character = BOXDRAW_VERTICAL;
+ for (Row = gScreenDimensions.TopRow + 1; Row <= gScreenDimensions.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT - 2; Row++) {
+ PrintCharAt (gScreenDimensions.LeftColumn, Row, Character);
+ PrintCharAt (gScreenDimensions.RightColumn - 1, Row, Character);
+ }
+
+ //
+ // Print Form Title
+ //
+ TitleStr = LibGetToken (FormData->FormTitle, FormData->HiiHandle);
+ ASSERT (TitleStr != NULL);
+ TitleColumn = (gScreenDimensions.RightColumn + gScreenDimensions.LeftColumn - LibGetStringWidth (TitleStr) / 2) / 2;
+ PrintStringAtWithWidth (gScreenDimensions.LeftColumn + 1, gScreenDimensions.TopRow + 1, gLibEmptyString, TitleColumn - gScreenDimensions.LeftColumn - 1);
+ PrintStringAtWithWidth (
+ TitleColumn,
+ gScreenDimensions.TopRow + 1,
+ TitleStr,
+ gScreenDimensions.RightColumn - 1 - TitleColumn
+ );
+ FreePool (TitleStr);
+
+ Character = BOXDRAW_UP_RIGHT;
+ PrintCharAt (gScreenDimensions.LeftColumn, gScreenDimensions.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT - 1, Character);
+ PrintStringAt ((UINTN) -1, (UINTN) -1, Buffer);
+
+ Character = BOXDRAW_UP_LEFT;
+ PrintCharAt ((UINTN) -1, (UINTN) -1, Character);
+
+ //
+ // Print Bottom border line
+ // +------------------------------------------------------------------------------+
+ // ? ?
+ // +------------------------------------------------------------------------------+
+ //
+ Character = BOXDRAW_DOWN_RIGHT;
+ PrintCharAt (gScreenDimensions.LeftColumn, gScreenDimensions.BottomRow - STATUS_BAR_HEIGHT - gFooterHeight, Character);
+
+ PrintStringAt ((UINTN) -1, (UINTN) -1, Buffer);
+
+ Character = BOXDRAW_DOWN_LEFT;
+ PrintCharAt ((UINTN) -1, (UINTN) -1, Character);
+ Character = BOXDRAW_VERTICAL;
+ for (Row = gScreenDimensions.BottomRow - STATUS_BAR_HEIGHT - gFooterHeight + 1;
+ Row <= gScreenDimensions.BottomRow - STATUS_BAR_HEIGHT - 2;
+ Row++
+ ) {
+ PrintCharAt (gScreenDimensions.LeftColumn, Row, Character);
+ PrintCharAt (gScreenDimensions.RightColumn - 1, Row, Character);
+ }
+
+ Character = BOXDRAW_UP_RIGHT;
+ PrintCharAt (gScreenDimensions.LeftColumn, gScreenDimensions.BottomRow - STATUS_BAR_HEIGHT - 1, Character);
+
+ PrintStringAt ((UINTN) -1, (UINTN) -1, Buffer);
+
+ Character = BOXDRAW_UP_LEFT;
+ PrintCharAt ((UINTN) -1, (UINTN) -1, Character);
+
+ FreePool (Buffer);
+}
+
+/**
+ Process some op code which is not recognized by browser core.
+
+ @param OpCodeData The pointer to the op code buffer.
+
+ @return EFI_SUCCESS Pass the statement success.
+
+**/
+VOID
+ProcessUserOpcode(
+ IN EFI_IFR_OP_HEADER *OpCodeData
+ )
+{
+ EFI_GUID * ClassGuid;
+ UINT8 ClassGuidNum;
+
+ ClassGuid = NULL;
+ ClassGuidNum = 0;
+
+ switch (OpCodeData->OpCode) {
+ case EFI_IFR_FORM_SET_OP:
+ //
+ // process the statement outside of form,if it is formset op, get its formsetguid or classguid and compared with gFrontPageFormSetGuid
+ //
+ if (CompareMem (PcdGetPtr (PcdFrontPageFormSetGuid), &((EFI_IFR_FORM_SET *) OpCodeData)->Guid, sizeof (EFI_GUID)) == 0){
+ gClassOfVfr = FORMSET_CLASS_FRONT_PAGE;
+ } else{
+ ClassGuidNum = (UINT8)(((EFI_IFR_FORM_SET *)OpCodeData)->Flags & 0x3);
+ ClassGuid = (EFI_GUID *)(VOID *)((UINT8 *)OpCodeData + sizeof (EFI_IFR_FORM_SET));
+ while (ClassGuidNum-- > 0){
+ if (CompareGuid((EFI_GUID*)PcdGetPtr (PcdFrontPageFormSetGuid),ClassGuid)){
+ gClassOfVfr = FORMSET_CLASS_FRONT_PAGE;
+ break;
+ }
+ ClassGuid ++;
+ }
+ }
+ break;
+
+ case EFI_IFR_GUID_OP:
+ if (CompareGuid (&gEfiIfrTianoGuid, (EFI_GUID *)((CHAR8*) OpCodeData + sizeof (EFI_IFR_OP_HEADER)))) {
+ //
+ // Tiano specific GUIDed opcodes
+ //
+ switch (((EFI_IFR_GUID_LABEL *) OpCodeData)->ExtendOpCode) {
+ case EFI_IFR_EXTEND_OP_LABEL:
+ //
+ // just ignore label
+ //
+ break;
+
+ case EFI_IFR_EXTEND_OP_BANNER:
+ //
+ // Only in front page form set, we care about the banner data.
+ //
+ if (gClassOfVfr == FORMSET_CLASS_FRONT_PAGE) {
+ //
+ // Initialize Driver private data
+ //
+ if (gBannerData == NULL) {
+ gBannerData = AllocateZeroPool (sizeof (BANNER_DATA));
+ ASSERT (gBannerData != NULL);
+ }
+
+ CopyMem (
+ &gBannerData->Banner[((EFI_IFR_GUID_BANNER *) OpCodeData)->LineNumber][
+ ((EFI_IFR_GUID_BANNER *) OpCodeData)->Alignment],
+ &((EFI_IFR_GUID_BANNER *) OpCodeData)->Title,
+ sizeof (EFI_STRING_ID)
+ );
+ }
+ break;
+
+ case EFI_IFR_EXTEND_OP_SUBCLASS:
+ if (((EFI_IFR_GUID_SUBCLASS *) OpCodeData)->SubClass == EFI_FRONT_PAGE_SUBCLASS) {
+ gClassOfVfr = FORMSET_CLASS_FRONT_PAGE;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+/**
+ Process some op codes which is out side of current form.
+
+ @param FormData Pointer to the form data.
+
+ @return EFI_SUCCESS Pass the statement success.
+
+**/
+VOID
+ProcessExternedOpcode (
+ IN FORM_DISPLAY_ENGINE_FORM *FormData
+ )
+{
+ LIST_ENTRY *Link;
+ LIST_ENTRY *NestLink;
+ FORM_DISPLAY_ENGINE_STATEMENT *Statement;
+ FORM_DISPLAY_ENGINE_STATEMENT *NestStatement;
+
+ Link = GetFirstNode (&FormData->StatementListOSF);
+ while (!IsNull (&FormData->StatementListOSF, Link)) {
+ Statement = FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK (Link);
+ Link = GetNextNode (&FormData->StatementListOSF, Link);
+
+ ProcessUserOpcode(Statement->OpCode);
+ }
+
+ Link = GetFirstNode (&FormData->StatementListHead);
+ while (!IsNull (&FormData->StatementListHead, Link)) {
+ Statement = FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK (Link);
+ Link = GetNextNode (&FormData->StatementListHead, Link);
+
+ ProcessUserOpcode(Statement->OpCode);
+
+ NestLink = GetFirstNode (&Statement->NestStatementList);
+ while (!IsNull (&Statement->NestStatementList, NestLink)) {
+ NestStatement = FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK (NestLink);
+ NestLink = GetNextNode (&Statement->NestStatementList, NestLink);
+
+ ProcessUserOpcode(NestStatement->OpCode);
+ }
+
+ }
+}
+
+/**
+ Validate the input screen diemenstion info.
+
+ @param FormData The input form data info.
+
+ @return EFI_SUCCESS The input screen info is acceptable.
+ @return EFI_INVALID_PARAMETER The input screen info is not acceptable.
+
+**/
+EFI_STATUS
+ScreenDiemensionInfoValidate (
+ IN FORM_DISPLAY_ENGINE_FORM *FormData
+ )
+{
+ LIST_ENTRY *Link;
+ UINTN Index;
+
+ //
+ // Calculate total number of Register HotKeys.
+ //
+ Index = 0;
+ if (!IsListEmpty (&FormData->HotKeyListHead)){
+ Link = GetFirstNode (&FormData->HotKeyListHead);
+ while (!IsNull (&FormData->HotKeyListHead, Link)) {
+ Link = GetNextNode (&FormData->HotKeyListHead, Link);
+ Index ++;
+ }
+ }
+
+ //
+ // Show three HotKeys help information on one row.
+ //
+ gFooterHeight = FOOTER_HEIGHT + (Index / 3);
+
+
+ ZeroMem (&gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));
+ gST->ConOut->QueryMode (
+ gST->ConOut,
+ gST->ConOut->Mode->Mode,
+ &gScreenDimensions.RightColumn,
+ &gScreenDimensions.BottomRow
+ );
+
+ //
+ // Check local dimension vs. global dimension.
+ //
+ if (FormData->ScreenDimensions != NULL) {
+ if ((gScreenDimensions.RightColumn < FormData->ScreenDimensions->RightColumn) ||
+ (gScreenDimensions.BottomRow < FormData->ScreenDimensions->BottomRow)
+ ) {
+ return EFI_INVALID_PARAMETER;
+ } else {
+ //
+ // Local dimension validation.
+ //
+ if ((FormData->ScreenDimensions->RightColumn > FormData->ScreenDimensions->LeftColumn) &&
+ (FormData->ScreenDimensions->BottomRow > FormData->ScreenDimensions->TopRow) &&
+ ((FormData->ScreenDimensions->RightColumn - FormData->ScreenDimensions->LeftColumn) > 2) &&
+ ((FormData->ScreenDimensions->BottomRow - FormData->ScreenDimensions->TopRow) > STATUS_BAR_HEIGHT +
+ FRONT_PAGE_HEADER_HEIGHT + gFooterHeight + 3)) {
+ CopyMem (&gScreenDimensions, (VOID *) FormData->ScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));
+ } else {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get the string based on the StringId and HII Package List Handle.
+
+ @param Token The String's ID.
+ @param HiiHandle The package list in the HII database to search for
+ the specified string.
+
+ @return The output string.
+
+**/
+CHAR16 *
+LibGetToken (
+ IN EFI_STRING_ID Token,
+ IN EFI_HII_HANDLE HiiHandle
+ )
+{
+ EFI_STRING String;
+
+ String = HiiGetString (HiiHandle, Token, NULL);
+ if (String == NULL) {
+ String = AllocateCopyPool (StrSize (mLibUnknownString), mLibUnknownString);
+ ASSERT (String != NULL);
+ }
+
+ return (CHAR16 *) String;
+}
+
+
+/**
+ Count the storage space of a Unicode string.
+
+ This function handles the Unicode string with NARROW_CHAR
+ and WIDE_CHAR control characters. NARROW_HCAR and WIDE_CHAR
+ does not count in the resultant output. If a WIDE_CHAR is
+ hit, then 2 Unicode character will consume an output storage
+ space with size of CHAR16 till a NARROW_CHAR is hit.
+
+ If String is NULL, then ASSERT ().
+
+ @param String The input string to be counted.
+
+ @return Storage space for the input string.
+
+**/
+UINTN
+LibGetStringWidth (
+ IN CHAR16 *String
+ )
+{
+ UINTN Index;
+ UINTN Count;
+ UINTN IncrementValue;
+
+ ASSERT (String != NULL);
+ if (String == NULL) {
+ return 0;
+ }
+
+ Index = 0;
+ Count = 0;
+ IncrementValue = 1;
+
+ do {
+ //
+ // Advance to the null-terminator or to the first width directive
+ //
+ for (;
+ (String[Index] != NARROW_CHAR) && (String[Index] != WIDE_CHAR) && (String[Index] != 0);
+ Index++, Count = Count + IncrementValue
+ )
+ ;
+
+ //
+ // We hit the null-terminator, we now have a count
+ //
+ if (String[Index] == 0) {
+ break;
+ }
+ //
+ // We encountered a narrow directive - strip it from the size calculation since it doesn't get printed
+ // and also set the flag that determines what we increment by.(if narrow, increment by 1, if wide increment by 2)
+ //
+ if (String[Index] == NARROW_CHAR) {
+ //
+ // Skip to the next character
+ //
+ Index++;
+ IncrementValue = 1;
+ } else {
+ //
+ // Skip to the next character
+ //
+ Index++;
+ IncrementValue = 2;
+ }
+ } while (String[Index] != 0);
+
+ //
+ // Increment by one to include the null-terminator in the size
+ //
+ Count++;
+
+ return Count * sizeof (CHAR16);
+}
+
+/**
+ Show all registered HotKey help strings on bottom Rows.
+
+ @param FormData The curent input form data info.
+ @param SetState Set HotKey or Clear HotKey
+
+**/
+VOID
+PrintHotKeyHelpString (
+ IN FORM_DISPLAY_ENGINE_FORM *FormData,
+ IN BOOLEAN SetState
+ )
+{
+ UINTN CurrentCol;
+ UINTN CurrentRow;
+ UINTN BottomRowOfHotKeyHelp;
+ UINTN ColumnIndexWidth;
+ UINTN ColumnWidth;
+ UINTN ColumnIndex;
+ UINTN Index;
+ EFI_SCREEN_DESCRIPTOR LocalScreen;
+ LIST_ENTRY *Link;
+ BROWSER_HOT_KEY *HotKey;
+ CHAR16 BakChar;
+ CHAR16 *ColumnStr;
+
+ CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));
+ ColumnWidth = (LocalScreen.RightColumn - LocalScreen.LeftColumn) / 3;
+ BottomRowOfHotKeyHelp = LocalScreen.BottomRow - STATUS_BAR_HEIGHT - 3;
+ ColumnStr = gLibEmptyString;
+
+ //
+ // Calculate total number of Register HotKeys.
+ //
+ Index = 0;
+ Link = GetFirstNode (&FormData->HotKeyListHead);
+ while (!IsNull (&FormData->HotKeyListHead, Link)) {
+ HotKey = BROWSER_HOT_KEY_FROM_LINK (Link);
+ //
+ // Calculate help information Column and Row.
+ //
+ ColumnIndex = Index % 3;
+ if (ColumnIndex == 0) {
+ CurrentCol = LocalScreen.LeftColumn + 2 * ColumnWidth;
+ ColumnIndexWidth = ColumnWidth - 1;
+ } else if (ColumnIndex == 1) {
+ CurrentCol = LocalScreen.LeftColumn + ColumnWidth;
+ ColumnIndexWidth = ColumnWidth;
+ } else {
+ CurrentCol = LocalScreen.LeftColumn + 2;
+ ColumnIndexWidth = ColumnWidth - 2;
+ }
+ CurrentRow = BottomRowOfHotKeyHelp - Index / 3;
+
+ //
+ // Help string can't exceed ColumnWidth. One Row will show three Help information.
+ //
+ BakChar = L'\0';
+ if (StrLen (HotKey->HelpString) > ColumnIndexWidth) {
+ BakChar = HotKey->HelpString[ColumnIndexWidth];
+ HotKey->HelpString[ColumnIndexWidth] = L'\0';
+ }
+
+ //
+ // Print HotKey help string on bottom Row.
+ //
+ if (SetState) {
+ ColumnStr = HotKey->HelpString;
+ }
+ PrintStringAtWithWidth (CurrentCol, CurrentRow, ColumnStr, ColumnIndexWidth);
+
+ if (BakChar != L'\0') {
+ HotKey->HelpString[ColumnIndexWidth] = BakChar;
+ }
+ //
+ // Get Next Hot Key.
+ //
+ Link = GetNextNode (&FormData->HotKeyListHead, Link);
+ Index ++;
+ }
+
+ if (SetState) {
+ //
+ // Clear KeyHelp
+ //
+ CurrentRow = BottomRowOfHotKeyHelp - Index / 3;
+ ColumnIndex = Index % 3;
+ if (ColumnIndex == 0) {
+ CurrentCol = LocalScreen.LeftColumn + 2 * ColumnWidth;
+ ColumnIndexWidth = ColumnWidth - 1;
+ ColumnIndex ++;
+ PrintStringAtWithWidth (CurrentCol, CurrentRow, gLibEmptyString, ColumnIndexWidth);
+ }
+ if (ColumnIndex == 1) {
+ CurrentCol = LocalScreen.LeftColumn + ColumnWidth;
+ ColumnIndexWidth = ColumnWidth;
+ PrintStringAtWithWidth (CurrentCol, CurrentRow, gLibEmptyString, ColumnIndexWidth);
+ }
+ }
+
+ return;
+}
+
+/**
+ Get step info from numeric opcode.
+
+ @param[in] OpCode The input numeric op code.
+
+ @return step info for this opcode.
+**/
+UINT64
+LibGetFieldFromNum (
+ IN EFI_IFR_OP_HEADER *OpCode
+ )
+{
+ EFI_IFR_NUMERIC *NumericOp;
+ UINT64 Step;
+
+ NumericOp = (EFI_IFR_NUMERIC *) OpCode;
+
+ switch (NumericOp->Flags & EFI_IFR_NUMERIC_SIZE) {
+ case EFI_IFR_NUMERIC_SIZE_1:
+ Step = NumericOp->data.u8.Step;
+ break;
+
+ case EFI_IFR_NUMERIC_SIZE_2:
+ Step = NumericOp->data.u16.Step;
+ break;
+
+ case EFI_IFR_NUMERIC_SIZE_4:
+ Step = NumericOp->data.u32.Step;
+ break;
+
+ case EFI_IFR_NUMERIC_SIZE_8:
+ Step = NumericOp->data.u64.Step;
+ break;
+
+ default:
+ Step = 0;
+ break;
+ }
+
+ return Step;
+}
+
+/**
+ Initialize the HII String Token to the correct values.
+
+**/
+VOID
+InitializeLibStrings (
+ VOID
+ )
+{
+ mLibUnknownString = L"!";
+
+ gEnterString = LibGetToken (STRING_TOKEN (ENTER_STRING), mCDLStringPackHandle);
+ gEnterCommitString = LibGetToken (STRING_TOKEN (ENTER_COMMIT_STRING), mCDLStringPackHandle);
+ gEnterEscapeString = LibGetToken (STRING_TOKEN (ENTER_ESCAPE_STRING), mCDLStringPackHandle);
+ gEscapeString = LibGetToken (STRING_TOKEN (ESCAPE_STRING), mCDLStringPackHandle);
+ gMoveHighlight = LibGetToken (STRING_TOKEN (MOVE_HIGHLIGHT), mCDLStringPackHandle);
+ gDecNumericInput = LibGetToken (STRING_TOKEN (DEC_NUMERIC_INPUT), mCDLStringPackHandle);
+ gHexNumericInput = LibGetToken (STRING_TOKEN (HEX_NUMERIC_INPUT), mCDLStringPackHandle);
+ gToggleCheckBox = LibGetToken (STRING_TOKEN (TOGGLE_CHECK_BOX), mCDLStringPackHandle);
+
+ gAreYouSure = LibGetToken (STRING_TOKEN (ARE_YOU_SURE), mCDLStringPackHandle);
+ gYesResponse = LibGetToken (STRING_TOKEN (ARE_YOU_SURE_YES), mCDLStringPackHandle);
+ gNoResponse = LibGetToken (STRING_TOKEN (ARE_YOU_SURE_NO), mCDLStringPackHandle);
+ gPlusString = LibGetToken (STRING_TOKEN (PLUS_STRING), mCDLStringPackHandle);
+ gMinusString = LibGetToken (STRING_TOKEN (MINUS_STRING), mCDLStringPackHandle);
+ gAdjustNumber = LibGetToken (STRING_TOKEN (ADJUST_NUMBER), mCDLStringPackHandle);
+ gSaveChanges = LibGetToken (STRING_TOKEN (SAVE_CHANGES), mCDLStringPackHandle);
+
+ gLibEmptyString = LibGetToken (STRING_TOKEN (EMPTY_STRING), mCDLStringPackHandle);
+
+ gNvUpdateMessage = LibGetToken (STRING_TOKEN (NV_UPDATE_MESSAGE), mCDLStringPackHandle);
+ gInputErrorMessage = LibGetToken (STRING_TOKEN (INPUT_ERROR_MESSAGE), mCDLStringPackHandle);
+
+ //
+ // SpaceBuffer;
+ //
+ mSpaceBuffer = AllocatePool ((SPACE_BUFFER_SIZE + 1) * sizeof (CHAR16));
+ ASSERT (mSpaceBuffer != NULL);
+ LibSetUnicodeMem (mSpaceBuffer, SPACE_BUFFER_SIZE, L' ');
+ mSpaceBuffer[SPACE_BUFFER_SIZE] = L'\0';
+}
+
+
+/**
+ Free the HII String.
+
+**/
+VOID
+FreeLibStrings (
+ VOID
+ )
+{
+ FreePool (gEnterString);
+ FreePool (gEnterCommitString);
+ FreePool (gEnterEscapeString);
+ FreePool (gEscapeString);
+ FreePool (gMoveHighlight);
+ FreePool (gDecNumericInput);
+ FreePool (gHexNumericInput);
+ FreePool (gToggleCheckBox);
+
+ FreePool (gAreYouSure);
+ FreePool (gYesResponse);
+ FreePool (gNoResponse);
+ FreePool (gPlusString);
+ FreePool (gMinusString);
+ FreePool (gAdjustNumber);
+ FreePool (gSaveChanges);
+
+ FreePool (gLibEmptyString);
+
+ FreePool (gNvUpdateMessage);
+ FreePool (gInputErrorMessage);
+
+ FreePool (mSpaceBuffer);
+}
+
+/**
+ Wait for a key to be pressed by user.
+
+ @param Key The key which is pressed by user.
+
+ @retval EFI_SUCCESS The function always completed successfully.
+
+**/
+EFI_STATUS
+WaitForKeyStroke (
+ OUT EFI_INPUT_KEY *Key
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+
+ while (TRUE) {
+ Status = gST->ConIn->ReadKeyStroke (gST->ConIn, Key);
+ if (!EFI_ERROR (Status)) {
+ break;
+ }
+
+ if (Status != EFI_NOT_READY) {
+ continue;
+ }
+
+ gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &Index);
+ }
+ return Status;
+}
+
+
+/**
+ Set Buffer to Value for Size bytes.
+
+ @param Buffer Memory to set.
+ @param Size Number of bytes to set
+ @param Value Value of the set operation.
+
+**/
+VOID
+LibSetUnicodeMem (
+ IN VOID *Buffer,
+ IN UINTN Size,
+ IN CHAR16 Value
+ )
+{
+ CHAR16 *Ptr;
+
+ Ptr = Buffer;
+ while ((Size--) != 0) {
+ *(Ptr++) = Value;
+ }
+}
+
+/**
+ The internal function prints to the EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
+ protocol instance.
+
+ @param Width Width of string to be print.
+ @param Column The position of the output string.
+ @param Row The position of the output string.
+ @param Out The EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL instance.
+ @param Fmt The format string.
+ @param Args The additional argument for the variables in the format string.
+
+ @return Number of Unicode character printed.
+
+**/
+UINTN
+PrintInternal (
+ IN UINTN Width,
+ IN UINTN Column,
+ IN UINTN Row,
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *Out,
+ IN CHAR16 *Fmt,
+ IN VA_LIST Args
+ )
+{
+ CHAR16 *Buffer;
+ CHAR16 *BackupBuffer;
+ UINTN Index;
+ UINTN PreviousIndex;
+ UINTN Count;
+ UINTN TotalCount;
+ UINTN PrintWidth;
+ UINTN CharWidth;
+
+ //
+ // For now, allocate an arbitrarily long buffer
+ //
+ Buffer = AllocateZeroPool (0x10000);
+ BackupBuffer = AllocateZeroPool (0x10000);
+ ASSERT (Buffer);
+ ASSERT (BackupBuffer);
+
+ if (Column != (UINTN) -1) {
+ Out->SetCursorPosition (Out, Column, Row);
+ }
+
+ UnicodeVSPrint (Buffer, 0x10000, Fmt, Args);
+
+ Out->Mode->Attribute = Out->Mode->Attribute & 0x7f;
+
+ Out->SetAttribute (Out, Out->Mode->Attribute);
+
+ Index = 0;
+ PreviousIndex = 0;
+ Count = 0;
+ TotalCount = 0;
+ PrintWidth = 0;
+ CharWidth = 1;
+
+ do {
+ for (; (Buffer[Index] != NARROW_CHAR) && (Buffer[Index] != WIDE_CHAR) && (Buffer[Index] != 0); Index++) {
+ BackupBuffer[Index] = Buffer[Index];
+ }
+
+ if (Buffer[Index] == 0) {
+ break;
+ }
+
+ //
+ // Print this out, we are about to switch widths
+ //
+ Out->OutputString (Out, &BackupBuffer[PreviousIndex]);
+ Count = StrLen (&BackupBuffer[PreviousIndex]);
+ PrintWidth += Count * CharWidth;
+ TotalCount += Count;
+
+ //
+ // Preserve the current index + 1, since this is where we will start printing from next
+ //
+ PreviousIndex = Index + 1;
+
+ //
+ // We are at a narrow or wide character directive. Set attributes and strip it and print it
+ //
+ if (Buffer[Index] == NARROW_CHAR) {
+ //
+ // Preserve bits 0 - 6 and zero out the rest
+ //
+ Out->Mode->Attribute = Out->Mode->Attribute & 0x7f;
+ Out->SetAttribute (Out, Out->Mode->Attribute);
+ CharWidth = 1;
+ } else {
+ //
+ // Must be wide, set bit 7 ON
+ //
+ Out->Mode->Attribute = Out->Mode->Attribute | EFI_WIDE_ATTRIBUTE;
+ Out->SetAttribute (Out, Out->Mode->Attribute);
+ CharWidth = 2;
+ }
+
+ Index++;
+
+ } while (Buffer[Index] != 0);
+
+ //
+ // We hit the end of the string - print it
+ //
+ Out->OutputString (Out, &BackupBuffer[PreviousIndex]);
+ Count = StrLen (&BackupBuffer[PreviousIndex]);
+ PrintWidth += Count * CharWidth;
+ TotalCount += Count;
+ if (PrintWidth < Width) {
+ Out->Mode->Attribute = Out->Mode->Attribute & 0x7f;
+ Out->SetAttribute (Out, Out->Mode->Attribute);
+ Out->OutputString (Out, &mSpaceBuffer[SPACE_BUFFER_SIZE - Width + PrintWidth]);
+ }
+
+ FreePool (Buffer);
+ FreePool (BackupBuffer);
+ return TotalCount;
+}
+
+/**
+ Prints a formatted unicode string to the default console, at
+ the supplied cursor position.
+
+ @param Width Width of String to be printed.
+ @param Column The cursor position to print the string at.
+ @param Row The cursor position to print the string at.
+ @param Fmt Format string.
+ @param ... Variable argument list for format string.
+
+ @return Length of string printed to the console
+
+**/
+UINTN
+EFIAPI
+PrintAt (
+ IN UINTN Width,
+ IN UINTN Column,
+ IN UINTN Row,
+ IN CHAR16 *Fmt,
+ ...
+ )
+{
+ VA_LIST Args;
+ UINTN LengthOfPrinted;
+
+ VA_START (Args, Fmt);
+ LengthOfPrinted = PrintInternal (Width, Column, Row, gST->ConOut, Fmt, Args);
+ VA_END (Args);
+ return LengthOfPrinted;
+}
+
diff --git a/Core/MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLibInternal.h b/Core/MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLibInternal.h
new file mode 100644
index 0000000000..7342b508b0
--- /dev/null
+++ b/Core/MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLibInternal.h
@@ -0,0 +1,297 @@
+/** @file
+
+ This library class defines a set of interfaces to customize Display module
+
+Copyright (c) 2013, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __CUSTOMIZED_DISPLAY_LIB_INTERNAL_H__
+#define __CUSTOMIZED_DISPLAY_LIB_INTERNAL_H__
+
+
+
+#include <PiDxe.h>
+
+#include <Protocol/SimpleTextOut.h>
+#include <Protocol/SimpleTextIn.h>
+#include <Protocol/FormBrowser2.h>
+#include <Protocol/FormBrowserEx2.h>
+#include <Protocol/DisplayProtocol.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/UnicodeCollation.h>
+#include <Protocol/HiiConfigAccess.h>
+#include <Protocol/HiiConfigRouting.h>
+#include <Protocol/HiiDatabase.h>
+#include <Protocol/HiiString.h>
+#include <Protocol/UserManager.h>
+#include <Protocol/DevicePathFromText.h>
+
+#include <Guid/MdeModuleHii.h>
+#include <Guid/HiiPlatformSetupFormset.h>
+#include <Guid/HiiFormMapMethodGuid.h>
+
+#include <Library/PrintLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/BaseLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/HiiLib.h>
+#include <Library/PcdLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/CustomizedDisplayLib.h>
+
+#include "Colors.h"
+
+
+
+#define FORMSET_CLASS_PLATFORM_SETUP 0x0001
+#define FORMSET_CLASS_FRONT_PAGE 0x0002
+
+
+#define FRONT_PAGE_HEADER_HEIGHT 6
+#define NONE_FRONT_PAGE_HEADER_HEIGHT 3
+#define FOOTER_HEIGHT 4
+#define STATUS_BAR_HEIGHT 1
+
+//
+// Screen definitions
+//
+#define BANNER_HEIGHT 6
+#define BANNER_COLUMNS 3
+#define BANNER_LEFT_COLUMN_INDENT 1
+
+//
+// Character definitions
+//
+#define UPPER_LOWER_CASE_OFFSET 0x20
+
+//
+// This is the Input Error Message
+//
+#define INPUT_ERROR 1
+
+//
+// This is the NV RAM update required Message
+//
+#define NV_UPDATE_REQUIRED 2
+
+typedef struct {
+ EFI_STRING_ID Banner[BANNER_HEIGHT][BANNER_COLUMNS];
+} BANNER_DATA;
+
+extern UINT16 gClassOfVfr; // Formset class information
+extern BANNER_DATA *gBannerData;
+extern EFI_SCREEN_DESCRIPTOR gScreenDimensions;
+extern UINTN gFooterHeight;
+
+//
+// Browser Global Strings
+//
+extern CHAR16 *gEnterString;
+extern CHAR16 *gEnterCommitString;
+extern CHAR16 *gEnterEscapeString;
+extern CHAR16 *gEscapeString;
+extern CHAR16 *gMoveHighlight;
+extern CHAR16 *gDecNumericInput;
+extern CHAR16 *gHexNumericInput;
+extern CHAR16 *gToggleCheckBox;
+extern CHAR16 *gLibEmptyString;
+extern CHAR16 *gAreYouSure;
+extern CHAR16 *gYesResponse;
+extern CHAR16 *gNoResponse;
+extern CHAR16 *gPlusString;
+extern CHAR16 *gMinusString;
+extern CHAR16 *gAdjustNumber;
+extern CHAR16 *gSaveChanges;
+extern CHAR16 *gNvUpdateMessage;
+extern CHAR16 *gInputErrorMessage;
+/**
+
+ Print banner info for front page.
+
+ @param[in] FormData Form Data to be shown in Page
+
+**/
+VOID
+PrintBannerInfo (
+ IN FORM_DISPLAY_ENGINE_FORM *FormData
+ );
+
+/**
+ Print framework and form title for a page.
+
+ @param[in] FormData Form Data to be shown in Page
+**/
+VOID
+PrintFramework (
+ IN FORM_DISPLAY_ENGINE_FORM *FormData
+ );
+
+/**
+ Validate the input screen diemenstion info.
+
+ @param FormData The input form data info.
+
+ @return EFI_SUCCESS The input screen info is acceptable.
+ @return EFI_INVALID_PARAMETER The input screen info is not acceptable.
+
+**/
+EFI_STATUS
+ScreenDiemensionInfoValidate (
+ IN FORM_DISPLAY_ENGINE_FORM *FormData
+ );
+
+/**
+ Get the string based on the StringId and HII Package List Handle.
+
+ @param Token The String's ID.
+ @param HiiHandle The package list in the HII database to search for
+ the specified string.
+
+ @return The output string.
+
+**/
+CHAR16 *
+LibGetToken (
+ IN EFI_STRING_ID Token,
+ IN EFI_HII_HANDLE HiiHandle
+ );
+
+/**
+ Count the storage space of a Unicode string.
+
+ This function handles the Unicode string with NARROW_CHAR
+ and WIDE_CHAR control characters. NARROW_HCAR and WIDE_CHAR
+ does not count in the resultant output. If a WIDE_CHAR is
+ hit, then 2 Unicode character will consume an output storage
+ space with size of CHAR16 till a NARROW_CHAR is hit.
+
+ If String is NULL, then ASSERT ().
+
+ @param String The input string to be counted.
+
+ @return Storage space for the input string.
+
+**/
+UINTN
+LibGetStringWidth (
+ IN CHAR16 *String
+ );
+
+/**
+ Show all registered HotKey help strings on bottom Rows.
+
+ @param FormData The curent input form data info.
+ @param SetState Set HotKey or Clear HotKey
+
+**/
+VOID
+PrintHotKeyHelpString (
+ IN FORM_DISPLAY_ENGINE_FORM *FormData,
+ IN BOOLEAN SetState
+ );
+
+/**
+ Get step info from numeric opcode.
+
+ @param[in] OpCode The input numeric op code.
+
+ @return step info for this opcode.
+**/
+UINT64
+LibGetFieldFromNum (
+ IN EFI_IFR_OP_HEADER *OpCode
+ );
+
+/**
+ Initialize the HII String Token to the correct values.
+
+**/
+VOID
+InitializeLibStrings (
+ VOID
+ );
+
+/**
+ Free the HII String.
+
+**/
+VOID
+FreeLibStrings (
+ VOID
+ );
+
+/**
+ Wait for a key to be pressed by user.
+
+ @param Key The key which is pressed by user.
+
+ @retval EFI_SUCCESS The function always completed successfully.
+
+**/
+EFI_STATUS
+WaitForKeyStroke (
+ OUT EFI_INPUT_KEY *Key
+ );
+
+/**
+ Set Buffer to Value for Size bytes.
+
+ @param Buffer Memory to set.
+ @param Size Number of bytes to set
+ @param Value Value of the set operation.
+
+**/
+VOID
+LibSetUnicodeMem (
+ IN VOID *Buffer,
+ IN UINTN Size,
+ IN CHAR16 Value
+ );
+
+/**
+ Prints a formatted unicode string to the default console, at
+ the supplied cursor position.
+
+ @param Width Width of String to be printed.
+ @param Column The cursor position to print the string at.
+ @param Row The cursor position to print the string at.
+ @param Fmt Format string.
+ @param ... Variable argument list for format string.
+
+ @return Length of string printed to the console
+
+**/
+UINTN
+EFIAPI
+PrintAt (
+ IN UINTN Width,
+ IN UINTN Column,
+ IN UINTN Row,
+ IN CHAR16 *Fmt,
+ ...
+ );
+
+/**
+ Process some op codes which is out side of current form.
+
+ @param FormData Pointer to the form data.
+
+**/
+VOID
+ProcessExternedOpcode (
+ IN FORM_DISPLAY_ENGINE_FORM *FormData
+ );
+
+#endif
diff --git a/Core/MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLibModStrs.uni b/Core/MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLibModStrs.uni
new file mode 100644
index 0000000000..64046df4c0
--- /dev/null
+++ b/Core/MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLibModStrs.uni
Binary files differ
diff --git a/Core/MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.c b/Core/MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.c
new file mode 100644
index 0000000000..09e1366189
--- /dev/null
+++ b/Core/MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.c
@@ -0,0 +1,72 @@
+/** @file
+ Debug Agent library implementition with empty functions.
+
+ Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Library/DebugAgentLib.h>
+
+/**
+ Initialize debug agent.
+
+ This function is used to set up debug environment to support source level debugging.
+ If certain Debug Agent Library instance has to save some private data in the stack,
+ this function must work on the mode that doesn't return to the caller, then
+ the caller needs to wrap up all rest of logic after InitializeDebugAgent() into one
+ function and pass it into InitializeDebugAgent(). InitializeDebugAgent() is
+ responsible to invoke the passing-in function at the end of InitializeDebugAgent().
+
+ If the parameter Function is not NULL, Debug Agent Libary instance will invoke it by
+ passing in the Context to be its parameter.
+
+ If Function() is NULL, Debug Agent Library instance will return after setup debug
+ environment.
+
+ @param[in] InitFlag Init flag is used to decide the initialize process.
+ @param[in] Context Context needed according to InitFlag; it was optional.
+ @param[in] Function Continue function called by debug agent library; it was
+ optional.
+
+**/
+VOID
+EFIAPI
+InitializeDebugAgent (
+ IN UINT32 InitFlag,
+ IN VOID *Context, OPTIONAL
+ IN DEBUG_AGENT_CONTINUE Function OPTIONAL
+ )
+{
+ if (Function != NULL) {
+ Function (Context);
+ }
+}
+
+/**
+ Enable/Disable the interrupt of debug timer and return the interrupt state
+ prior to the operation.
+
+ If EnableStatus is TRUE, enable the interrupt of debug timer.
+ If EnableStatus is FALSE, disable the interrupt of debug timer.
+
+ @param[in] EnableStatus Enable/Disable.
+
+ @return FALSE always.
+
+**/
+BOOLEAN
+EFIAPI
+SaveAndSetDebugTimerInterrupt (
+ IN BOOLEAN EnableStatus
+ )
+{
+ return FALSE;
+}
+
diff --git a/Core/MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.inf b/Core/MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.inf
new file mode 100644
index 0000000000..ce1eab2623
--- /dev/null
+++ b/Core/MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.inf
@@ -0,0 +1,36 @@
+## @file
+# Null instance of Debug Agent Library with empty functions.
+#
+# Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DebugAgentLibNull
+ MODULE_UNI_FILE = DebugAgentLibNull.uni
+ FILE_GUID = 4904B42F-9FC0-4c2e-BB3F-A2AB35123530
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = DebugAgentLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources.common]
+ DebugAgentLibNull.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
diff --git a/Core/MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.uni b/Core/MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.uni
new file mode 100644
index 0000000000..797c0f4076
--- /dev/null
+++ b/Core/MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.uni
Binary files differ
diff --git a/Core/MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.c b/Core/MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.c
new file mode 100644
index 0000000000..fb5c25536f
--- /dev/null
+++ b/Core/MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.c
@@ -0,0 +1,51 @@
+/** @file
+ Null Dxe Capsule Library instance does nothing and returns unsupport status.
+
+Copyright (c) 2007 - 2008, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+#include <Uefi.h>
+#include <Library/CapsuleLib.h>
+
+/**
+ The firmware checks whether the capsule image is supported
+ by the CapsuleGuid in CapsuleHeader or other specific information in capsule image.
+
+ @param CapsuleHeader Point to the UEFI capsule image to be checked.
+
+ @retval EFI_UNSUPPORTED Input capsule is not supported by the firmware.
+**/
+EFI_STATUS
+EFIAPI
+SupportCapsuleImage (
+ IN EFI_CAPSULE_HEADER *CapsuleHeader
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ The firmware specific implementation processes the capsule image
+ if it recognized the format of this capsule image.
+
+ @param CapsuleHeader Point to the UEFI capsule image to be processed.
+
+ @retval EFI_UNSUPPORTED Capsule image is not supported by the firmware.
+**/
+EFI_STATUS
+EFIAPI
+ProcessCapsuleImage (
+ IN EFI_CAPSULE_HEADER *CapsuleHeader
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+
diff --git a/Core/MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.inf b/Core/MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.inf
new file mode 100644
index 0000000000..b836607aae
--- /dev/null
+++ b/Core/MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.inf
@@ -0,0 +1,38 @@
+## @file
+# NULL Dxe Capsule library instance.
+# It can make core modules pass package level build.
+#
+# Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxeCapsuleLibNull
+ MODULE_UNI_FILE = DxeCapsuleLibNull.uni
+ FILE_GUID = 4004de5a-09a5-4f0c-94d7-82322e096aa7
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = CapsuleLib|DXE_DRIVER DXE_RUNTIME_DRIVER UEFI_APPLICATION
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ DxeCapsuleLibNull.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
diff --git a/Core/MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.uni b/Core/MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.uni
new file mode 100644
index 0000000000..f669eccc71
--- /dev/null
+++ b/Core/MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.uni
Binary files differ
diff --git a/Core/MdeModulePkg/Library/DxeCoreMemoryAllocationLib/DxeCoreMemoryAllocationLib.inf b/Core/MdeModulePkg/Library/DxeCoreMemoryAllocationLib/DxeCoreMemoryAllocationLib.inf
new file mode 100644
index 0000000000..0747f6e697
--- /dev/null
+++ b/Core/MdeModulePkg/Library/DxeCoreMemoryAllocationLib/DxeCoreMemoryAllocationLib.inf
@@ -0,0 +1,46 @@
+## @file
+# Memory Allocation Library instance dedicated to DXE Core.
+# The implementation borrows the DxeCore Memory Allocation services as the primitive
+# for memory allocation instead of using UEFI boot servces in an indirect way.
+# It is assumed that this library instance must be linked with DxeCore in this package.
+#
+# Copyright (c) 2008 - 2014, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxeCoreMemoryAllocationLib
+ MODULE_UNI_FILE = DxeCoreMemoryAllocationLib.uni
+ FILE_GUID = 632F3FAC-1CA4-4725-BAA2-BDECCF9A111C
+ MODULE_TYPE = DXE_CORE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = MemoryAllocationLib|DXE_CORE
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ MemoryAllocationLib.c
+ DxeCoreMemoryAllocationServices.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+
+[LibraryClasses]
+ DebugLib
+ BaseMemoryLib
+
+
diff --git a/Core/MdeModulePkg/Library/DxeCoreMemoryAllocationLib/DxeCoreMemoryAllocationLib.uni b/Core/MdeModulePkg/Library/DxeCoreMemoryAllocationLib/DxeCoreMemoryAllocationLib.uni
new file mode 100644
index 0000000000..6fffafc5ed
--- /dev/null
+++ b/Core/MdeModulePkg/Library/DxeCoreMemoryAllocationLib/DxeCoreMemoryAllocationLib.uni
Binary files differ
diff --git a/Core/MdeModulePkg/Library/DxeCoreMemoryAllocationLib/DxeCoreMemoryAllocationServices.h b/Core/MdeModulePkg/Library/DxeCoreMemoryAllocationLib/DxeCoreMemoryAllocationServices.h
new file mode 100644
index 0000000000..04ad3d6da3
--- /dev/null
+++ b/Core/MdeModulePkg/Library/DxeCoreMemoryAllocationLib/DxeCoreMemoryAllocationServices.h
@@ -0,0 +1,106 @@
+/** @file
+ Contains function prototypes for Memory Services in DxeCore.
+
+ This header file borrows the DxeCore Memory Allocation services as the primitive
+ for memory allocation.
+
+ Copyright (c) 2008, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _DXE_CORE_MEMORY_ALLOCATION_SERVICES_H_
+#define _DXE_CORE_MEMORY_ALLOCATION_SERVICES_H_
+
+
+/**
+ 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
+
+ @return Status. On success, Memory is filled in with the base address allocated
+ @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
+CoreAllocatePages (
+ IN EFI_ALLOCATE_TYPE Type,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN NumberOfPages,
+ IN 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
+CoreFreePages (
+ 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
+CoreAllocatePool (
+ 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
+CoreFreePool (
+ IN VOID *Buffer
+ );
+
+#endif
diff --git a/Core/MdeModulePkg/Library/DxeCoreMemoryAllocationLib/MemoryAllocationLib.c b/Core/MdeModulePkg/Library/DxeCoreMemoryAllocationLib/MemoryAllocationLib.c
new file mode 100644
index 0000000000..d7d9ff311e
--- /dev/null
+++ b/Core/MdeModulePkg/Library/DxeCoreMemoryAllocationLib/MemoryAllocationLib.c
@@ -0,0 +1,823 @@
+/** @file
+ Support routines for memory allocation routines based
+ on boot services for Dxe phase drivers.
+
+ Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+
+#include <PiDxe.h>
+
+
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include "DxeCoreMemoryAllocationServices.h"
+
+/**
+ Allocates one or more 4KB pages of a certain memory type.
+
+ Allocates the number of 4KB pages of a certain memory type and returns a pointer to the allocated
+ buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL is returned.
+ If there is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ @param MemoryType The type of memory to allocate.
+ @param Pages The number of 4 KB pages to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+InternalAllocatePages (
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN Pages
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS Memory;
+
+ if (Pages == 0) {
+ return NULL;
+ }
+
+ Status = CoreAllocatePages (AllocateAnyPages, MemoryType, Pages, &Memory);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+ return (VOID *) (UINTN) Memory;
+}
+
+/**
+ Allocates one or more 4KB pages of type EfiBootServicesData.
+
+ Allocates the number of 4KB pages of type EfiBootServicesData and returns a pointer to the
+ allocated buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL
+ is returned. If there is not enough memory remaining to satisfy the request, then NULL is
+ returned.
+
+ @param Pages The number of 4 KB pages to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocatePages (
+ IN UINTN Pages
+ )
+{
+ return InternalAllocatePages (EfiBootServicesData, Pages);
+}
+
+/**
+ Allocates one or more 4KB pages of type EfiRuntimeServicesData.
+
+ Allocates the number of 4KB pages of type EfiRuntimeServicesData and returns a pointer to the
+ allocated buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL
+ is returned. If there is not enough memory remaining to satisfy the request, then NULL is
+ returned.
+
+ @param Pages The number of 4 KB pages to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateRuntimePages (
+ IN UINTN Pages
+ )
+{
+ return InternalAllocatePages (EfiRuntimeServicesData, Pages);
+}
+
+/**
+ Allocates one or more 4KB pages of type EfiReservedMemoryType.
+
+ Allocates the number of 4KB pages of type EfiReservedMemoryType and returns a pointer to the
+ allocated buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL
+ is returned. If there is not enough memory remaining to satisfy the request, then NULL is
+ returned.
+
+ @param Pages The number of 4 KB pages to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateReservedPages (
+ IN UINTN Pages
+ )
+{
+ return InternalAllocatePages (EfiReservedMemoryType, Pages);
+}
+
+/**
+ Frees one or more 4KB pages that were previously allocated with one of the page allocation
+ functions in the Memory Allocation Library.
+
+ Frees the number of 4KB pages specified by Pages from the buffer specified by Buffer. Buffer
+ must have been allocated on a previous call to the page allocation services of the Memory
+ Allocation Library. If it is not possible to free allocated pages, then this function will
+ perform no actions.
+
+ If Buffer was not allocated with a page allocation function in the Memory Allocation Library,
+ then ASSERT().
+ If Pages is zero, then ASSERT().
+
+ @param Buffer Pointer to the buffer of pages to free.
+ @param Pages The number of 4 KB pages to free.
+
+**/
+VOID
+EFIAPI
+FreePages (
+ IN VOID *Buffer,
+ IN UINTN Pages
+ )
+{
+ EFI_STATUS Status;
+
+ ASSERT (Pages != 0);
+ Status = CoreFreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) Buffer, Pages);
+ ASSERT_EFI_ERROR (Status);
+}
+
+/**
+ Allocates one or more 4KB pages of a certain memory type at a specified alignment.
+
+ Allocates the number of 4KB pages specified by Pages of a certain memory type with an alignment
+ specified by Alignment. The allocated buffer is returned. If Pages is 0, then NULL is returned.
+ If there is not enough memory at the specified alignment remaining to satisfy the request, then
+ NULL is returned.
+ If Alignment is not a power of two and Alignment is not zero, then ASSERT().
+ If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT().
+
+ @param MemoryType The type of memory to allocate.
+ @param Pages The number of 4 KB pages to allocate.
+ @param Alignment The requested alignment of the allocation. Must be a power of two.
+ If Alignment is zero, then byte alignment is used.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+InternalAllocateAlignedPages (
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN Pages,
+ IN UINTN Alignment
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS Memory;
+ UINTN AlignedMemory;
+ UINTN AlignmentMask;
+ UINTN UnalignedPages;
+ UINTN RealPages;
+
+ //
+ // Alignment must be a power of two or zero.
+ //
+ ASSERT ((Alignment & (Alignment - 1)) == 0);
+
+ if (Pages == 0) {
+ return NULL;
+ }
+ if (Alignment > EFI_PAGE_SIZE) {
+ //
+ // Calculate the total number of pages since alignment is larger than page size.
+ //
+ AlignmentMask = Alignment - 1;
+ RealPages = Pages + EFI_SIZE_TO_PAGES (Alignment);
+ //
+ // Make sure that Pages plus EFI_SIZE_TO_PAGES (Alignment) does not overflow.
+ //
+ ASSERT (RealPages > Pages);
+
+ Status = CoreAllocatePages (AllocateAnyPages, MemoryType, RealPages, &Memory);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+ AlignedMemory = ((UINTN) Memory + AlignmentMask) & ~AlignmentMask;
+ UnalignedPages = EFI_SIZE_TO_PAGES (AlignedMemory - (UINTN) Memory);
+ if (UnalignedPages > 0) {
+ //
+ // Free first unaligned page(s).
+ //
+ Status = CoreFreePages (Memory, UnalignedPages);
+ ASSERT_EFI_ERROR (Status);
+ }
+ Memory = (EFI_PHYSICAL_ADDRESS) (AlignedMemory + EFI_PAGES_TO_SIZE (Pages));
+ UnalignedPages = RealPages - Pages - UnalignedPages;
+ if (UnalignedPages > 0) {
+ //
+ // Free last unaligned page(s).
+ //
+ Status = CoreFreePages (Memory, UnalignedPages);
+ ASSERT_EFI_ERROR (Status);
+ }
+ } else {
+ //
+ // Do not over-allocate pages in this case.
+ //
+ Status = CoreAllocatePages (AllocateAnyPages, MemoryType, Pages, &Memory);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+ AlignedMemory = (UINTN) Memory;
+ }
+ return (VOID *) AlignedMemory;
+}
+
+/**
+ Allocates one or more 4KB pages of type EfiBootServicesData at a specified alignment.
+
+ Allocates the number of 4KB pages specified by Pages of type EfiBootServicesData with an
+ alignment specified by Alignment. The allocated buffer is returned. If Pages is 0, then NULL is
+ returned. If there is not enough memory at the specified alignment remaining to satisfy the
+ request, then NULL is returned.
+
+ If Alignment is not a power of two and Alignment is not zero, then ASSERT().
+ If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT().
+
+ @param Pages The number of 4 KB pages to allocate.
+ @param Alignment The requested alignment of the allocation. Must be a power of two.
+ If Alignment is zero, then byte alignment is used.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateAlignedPages (
+ IN UINTN Pages,
+ IN UINTN Alignment
+ )
+{
+ return InternalAllocateAlignedPages (EfiBootServicesData, Pages, Alignment);
+}
+
+/**
+ Allocates one or more 4KB pages of type EfiRuntimeServicesData at a specified alignment.
+
+ Allocates the number of 4KB pages specified by Pages of type EfiRuntimeServicesData with an
+ alignment specified by Alignment. The allocated buffer is returned. If Pages is 0, then NULL is
+ returned. If there is not enough memory at the specified alignment remaining to satisfy the
+ request, then NULL is returned.
+
+ If Alignment is not a power of two and Alignment is not zero, then ASSERT().
+ If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT().
+
+ @param Pages The number of 4 KB pages to allocate.
+ @param Alignment The requested alignment of the allocation. Must be a power of two.
+ If Alignment is zero, then byte alignment is used.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateAlignedRuntimePages (
+ IN UINTN Pages,
+ IN UINTN Alignment
+ )
+{
+ return InternalAllocateAlignedPages (EfiRuntimeServicesData, Pages, Alignment);
+}
+
+/**
+ Allocates one or more 4KB pages of type EfiReservedMemoryType at a specified alignment.
+
+ Allocates the number of 4KB pages specified by Pages of type EfiReservedMemoryType with an
+ alignment specified by Alignment. The allocated buffer is returned. If Pages is 0, then NULL is
+ returned. If there is not enough memory at the specified alignment remaining to satisfy the
+ request, then NULL is returned.
+
+ If Alignment is not a power of two and Alignment is not zero, then ASSERT().
+ If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT().
+
+ @param Pages The number of 4 KB pages to allocate.
+ @param Alignment The requested alignment of the allocation. Must be a power of two.
+ If Alignment is zero, then byte alignment is used.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateAlignedReservedPages (
+ IN UINTN Pages,
+ IN UINTN Alignment
+ )
+{
+ return InternalAllocateAlignedPages (EfiReservedMemoryType, Pages, Alignment);
+}
+
+/**
+ Frees one or more 4KB pages that were previously allocated with one of the aligned page
+ allocation functions in the Memory Allocation Library.
+
+ Frees the number of 4KB pages specified by Pages from the buffer specified by Buffer. Buffer
+ must have been allocated on a previous call to the aligned page allocation services of the Memory
+ Allocation Library. If it is not possible to free allocated pages, then this function will
+ perform no actions.
+
+ If Buffer was not allocated with an aligned page allocation function in the Memory Allocation
+ Library, then ASSERT().
+ If Pages is zero, then ASSERT().
+
+ @param Buffer Pointer to the buffer of pages to free.
+ @param Pages The number of 4 KB pages to free.
+
+**/
+VOID
+EFIAPI
+FreeAlignedPages (
+ IN VOID *Buffer,
+ IN UINTN Pages
+ )
+{
+ EFI_STATUS Status;
+
+ ASSERT (Pages != 0);
+ Status = CoreFreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) Buffer, Pages);
+ ASSERT_EFI_ERROR (Status);
+}
+
+/**
+ Allocates a buffer of a certain pool type.
+
+ Allocates the number bytes specified by AllocationSize of a certain pool type and returns a
+ pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is
+ returned. If there is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ @param MemoryType The type of memory to allocate.
+ @param AllocationSize The number of bytes to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+InternalAllocatePool (
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN AllocationSize
+ )
+{
+ EFI_STATUS Status;
+ VOID *Memory;
+
+ Memory = NULL;
+
+ Status = CoreAllocatePool (MemoryType, AllocationSize, &Memory);
+ if (EFI_ERROR (Status)) {
+ Memory = NULL;
+ }
+ return Memory;
+}
+
+/**
+ Allocates a buffer of type EfiBootServicesData.
+
+ Allocates the number bytes specified by AllocationSize of type EfiBootServicesData and returns a
+ pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is
+ returned. If there is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ @param AllocationSize The number of bytes to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocatePool (
+ IN UINTN AllocationSize
+ )
+{
+ return InternalAllocatePool (EfiBootServicesData, AllocationSize);
+}
+
+/**
+ Allocates a buffer of type EfiRuntimeServicesData.
+
+ Allocates the number bytes specified by AllocationSize of type EfiRuntimeServicesData and returns
+ a pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is
+ returned. If there is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ @param AllocationSize The number of bytes to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateRuntimePool (
+ IN UINTN AllocationSize
+ )
+{
+ return InternalAllocatePool (EfiRuntimeServicesData, AllocationSize);
+}
+
+/**
+ Allocates a buffer of type EfiReservedMemoryType.
+
+ Allocates the number bytes specified by AllocationSize of type EfiReservedMemoryType and returns
+ a pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is
+ returned. If there is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ @param AllocationSize The number of bytes to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateReservedPool (
+ IN UINTN AllocationSize
+ )
+{
+ return InternalAllocatePool (EfiReservedMemoryType, AllocationSize);
+}
+
+/**
+ Allocates and zeros a buffer of a certain pool type.
+
+ Allocates the number bytes specified by AllocationSize of a certain pool type, clears the buffer
+ with zeros, and returns a pointer to the allocated buffer. If AllocationSize is 0, then a valid
+ buffer of 0 size is returned. If there is not enough memory remaining to satisfy the request,
+ then NULL is returned.
+
+ @param PoolType The type of memory to allocate.
+ @param AllocationSize The number of bytes to allocate and zero.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+InternalAllocateZeroPool (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN AllocationSize
+ )
+{
+ VOID *Memory;
+
+ Memory = InternalAllocatePool (PoolType, AllocationSize);
+ if (Memory != NULL) {
+ Memory = ZeroMem (Memory, AllocationSize);
+ }
+ return Memory;
+}
+
+/**
+ Allocates and zeros a buffer of type EfiBootServicesData.
+
+ Allocates the number bytes specified by AllocationSize of type EfiBootServicesData, clears the
+ buffer with zeros, and returns a pointer to the allocated buffer. If AllocationSize is 0, then a
+ valid buffer of 0 size is returned. If there is not enough memory remaining to satisfy the
+ request, then NULL is returned.
+
+ @param AllocationSize The number of bytes to allocate and zero.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateZeroPool (
+ IN UINTN AllocationSize
+ )
+{
+ return InternalAllocateZeroPool (EfiBootServicesData, AllocationSize);
+}
+
+/**
+ Allocates and zeros a buffer of type EfiRuntimeServicesData.
+
+ Allocates the number bytes specified by AllocationSize of type EfiRuntimeServicesData, clears the
+ buffer with zeros, and returns a pointer to the allocated buffer. If AllocationSize is 0, then a
+ valid buffer of 0 size is returned. If there is not enough memory remaining to satisfy the
+ request, then NULL is returned.
+
+ @param AllocationSize The number of bytes to allocate and zero.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateRuntimeZeroPool (
+ IN UINTN AllocationSize
+ )
+{
+ return InternalAllocateZeroPool (EfiRuntimeServicesData, AllocationSize);
+}
+
+/**
+ Allocates and zeros a buffer of type EfiReservedMemoryType.
+
+ Allocates the number bytes specified by AllocationSize of type EfiReservedMemoryType, clears the
+ buffer with zeros, and returns a pointer to the allocated buffer. If AllocationSize is 0, then a
+ valid buffer of 0 size is returned. If there is not enough memory remaining to satisfy the
+ request, then NULL is returned.
+
+ @param AllocationSize The number of bytes to allocate and zero.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateReservedZeroPool (
+ IN UINTN AllocationSize
+ )
+{
+ return InternalAllocateZeroPool (EfiReservedMemoryType, AllocationSize);
+}
+
+/**
+ Copies a buffer to an allocated buffer of a certain pool type.
+
+ Allocates the number bytes specified by AllocationSize of a certain pool type, copies
+ AllocationSize bytes from Buffer to the newly allocated buffer, and returns a pointer to the
+ allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned. If there
+ is not enough memory remaining to satisfy the request, then NULL is returned.
+ If Buffer is NULL, then ASSERT().
+ If AllocationSize is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
+
+ @param PoolType The type of pool to allocate.
+ @param AllocationSize The number of bytes to allocate and zero.
+ @param Buffer The buffer to copy to the allocated buffer.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+InternalAllocateCopyPool (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN AllocationSize,
+ IN CONST VOID *Buffer
+ )
+{
+ VOID *Memory;
+
+ ASSERT (Buffer != NULL);
+ ASSERT (AllocationSize <= (MAX_ADDRESS - (UINTN) Buffer + 1));
+
+ Memory = InternalAllocatePool (PoolType, AllocationSize);
+ if (Memory != NULL) {
+ Memory = CopyMem (Memory, Buffer, AllocationSize);
+ }
+ return Memory;
+}
+
+/**
+ Copies a buffer to an allocated buffer of type EfiBootServicesData.
+
+ Allocates the number bytes specified by AllocationSize of type EfiBootServicesData, copies
+ AllocationSize bytes from Buffer to the newly allocated buffer, and returns a pointer to the
+ allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned. If there
+ is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ If Buffer is NULL, then ASSERT().
+ If AllocationSize is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
+
+ @param AllocationSize The number of bytes to allocate and zero.
+ @param Buffer The buffer to copy to the allocated buffer.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateCopyPool (
+ IN UINTN AllocationSize,
+ IN CONST VOID *Buffer
+ )
+{
+ return InternalAllocateCopyPool (EfiBootServicesData, AllocationSize, Buffer);
+}
+
+/**
+ Copies a buffer to an allocated buffer of type EfiRuntimeServicesData.
+
+ Allocates the number bytes specified by AllocationSize of type EfiRuntimeServicesData, copies
+ AllocationSize bytes from Buffer to the newly allocated buffer, and returns a pointer to the
+ allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned. If there
+ is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ If Buffer is NULL, then ASSERT().
+ If AllocationSize is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
+
+ @param AllocationSize The number of bytes to allocate and zero.
+ @param Buffer The buffer to copy to the allocated buffer.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateRuntimeCopyPool (
+ IN UINTN AllocationSize,
+ IN CONST VOID *Buffer
+ )
+{
+ return InternalAllocateCopyPool (EfiRuntimeServicesData, AllocationSize, Buffer);
+}
+
+/**
+ Copies a buffer to an allocated buffer of type EfiReservedMemoryType.
+
+ Allocates the number bytes specified by AllocationSize of type EfiReservedMemoryType, copies
+ AllocationSize bytes from Buffer to the newly allocated buffer, and returns a pointer to the
+ allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned. If there
+ is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ If Buffer is NULL, then ASSERT().
+ If AllocationSize is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
+
+ @param AllocationSize The number of bytes to allocate and zero.
+ @param Buffer The buffer to copy to the allocated buffer.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateReservedCopyPool (
+ IN UINTN AllocationSize,
+ IN CONST VOID *Buffer
+ )
+{
+ return InternalAllocateCopyPool (EfiReservedMemoryType, AllocationSize, Buffer);
+}
+
+/**
+ Reallocates a buffer of a specified memory type.
+
+ Allocates and zeros the number bytes specified by NewSize from memory of the type
+ specified by PoolType. If OldBuffer is not NULL, then the smaller of OldSize and
+ NewSize bytes are copied from OldBuffer to the newly allocated buffer, and
+ OldBuffer is freed. A pointer to the newly allocated buffer is returned.
+ If NewSize is 0, then a valid buffer of 0 size is returned. If there is not
+ enough memory remaining to satisfy the request, then NULL is returned.
+
+ If the allocation of the new buffer is successful and the smaller of NewSize and OldSize
+ is greater than (MAX_ADDRESS - OldBuffer + 1), then ASSERT().
+
+ @param PoolType The type of pool to allocate.
+ @param OldSize The size, in bytes, of OldBuffer.
+ @param NewSize The size, in bytes, of the buffer to reallocate.
+ @param OldBuffer The buffer to copy to the allocated buffer. This is an optional
+ parameter that may be NULL.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+InternalReallocatePool (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN OldSize,
+ IN UINTN NewSize,
+ IN VOID *OldBuffer OPTIONAL
+ )
+{
+ VOID *NewBuffer;
+
+ NewBuffer = InternalAllocateZeroPool (PoolType, NewSize);
+ if (NewBuffer != NULL && OldBuffer != NULL) {
+ CopyMem (NewBuffer, OldBuffer, MIN (OldSize, NewSize));
+ FreePool (OldBuffer);
+ }
+ return NewBuffer;
+}
+
+/**
+ Reallocates a buffer of type EfiBootServicesData.
+
+ Allocates and zeros the number bytes specified by NewSize from memory of type
+ EfiBootServicesData. If OldBuffer is not NULL, then the smaller of OldSize and
+ NewSize bytes are copied from OldBuffer to the newly allocated buffer, and
+ OldBuffer is freed. A pointer to the newly allocated buffer is returned.
+ If NewSize is 0, then a valid buffer of 0 size is returned. If there is not
+ enough memory remaining to satisfy the request, then NULL is returned.
+
+ If the allocation of the new buffer is successful and the smaller of NewSize and OldSize
+ is greater than (MAX_ADDRESS - OldBuffer + 1), then ASSERT().
+
+ @param OldSize The size, in bytes, of OldBuffer.
+ @param NewSize The size, in bytes, of the buffer to reallocate.
+ @param OldBuffer The buffer to copy to the allocated buffer. This is an optional
+ parameter that may be NULL.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+ReallocatePool (
+ IN UINTN OldSize,
+ IN UINTN NewSize,
+ IN VOID *OldBuffer OPTIONAL
+ )
+{
+ return InternalReallocatePool (EfiBootServicesData, OldSize, NewSize, OldBuffer);
+}
+
+/**
+ Reallocates a buffer of type EfiRuntimeServicesData.
+
+ Allocates and zeros the number bytes specified by NewSize from memory of type
+ EfiRuntimeServicesData. If OldBuffer is not NULL, then the smaller of OldSize and
+ NewSize bytes are copied from OldBuffer to the newly allocated buffer, and
+ OldBuffer is freed. A pointer to the newly allocated buffer is returned.
+ If NewSize is 0, then a valid buffer of 0 size is returned. If there is not
+ enough memory remaining to satisfy the request, then NULL is returned.
+
+ If the allocation of the new buffer is successful and the smaller of NewSize and OldSize
+ is greater than (MAX_ADDRESS - OldBuffer + 1), then ASSERT().
+
+ @param OldSize The size, in bytes, of OldBuffer.
+ @param NewSize The size, in bytes, of the buffer to reallocate.
+ @param OldBuffer The buffer to copy to the allocated buffer. This is an optional
+ parameter that may be NULL.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+ReallocateRuntimePool (
+ IN UINTN OldSize,
+ IN UINTN NewSize,
+ IN VOID *OldBuffer OPTIONAL
+ )
+{
+ return InternalReallocatePool (EfiRuntimeServicesData, OldSize, NewSize, OldBuffer);
+}
+
+/**
+ Reallocates a buffer of type EfiReservedMemoryType.
+
+ Allocates and zeros the number bytes specified by NewSize from memory of type
+ EfiReservedMemoryType. If OldBuffer is not NULL, then the smaller of OldSize and
+ NewSize bytes are copied from OldBuffer to the newly allocated buffer, and
+ OldBuffer is freed. A pointer to the newly allocated buffer is returned.
+ If NewSize is 0, then a valid buffer of 0 size is returned. If there is not
+ enough memory remaining to satisfy the request, then NULL is returned.
+
+ If the allocation of the new buffer is successful and the smaller of NewSize and OldSize
+ is greater than (MAX_ADDRESS - OldBuffer + 1), then ASSERT().
+
+ @param OldSize The size, in bytes, of OldBuffer.
+ @param NewSize The size, in bytes, of the buffer to reallocate.
+ @param OldBuffer The buffer to copy to the allocated buffer. This is an optional
+ parameter that may be NULL.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+ReallocateReservedPool (
+ IN UINTN OldSize,
+ IN UINTN NewSize,
+ IN VOID *OldBuffer OPTIONAL
+ )
+{
+ return InternalReallocatePool (EfiReservedMemoryType, OldSize, NewSize, OldBuffer);
+}
+
+/**
+ Frees a buffer that was previously allocated with one of the pool allocation functions in the
+ Memory Allocation Library.
+
+ Frees the buffer specified by Buffer. Buffer must have been allocated on a previous call to the
+ pool allocation services of the Memory Allocation Library. If it is not possible to free pool
+ resources, then this function will perform no actions.
+
+ If Buffer was not allocated with a pool allocation function in the Memory Allocation Library,
+ then ASSERT().
+
+ @param Buffer Pointer to the buffer to free.
+
+**/
+VOID
+EFIAPI
+FreePool (
+ IN VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+
+ Status = CoreFreePool (Buffer);
+ ASSERT_EFI_ERROR (Status);
+}
+
diff --git a/Core/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.c b/Core/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.c
new file mode 100644
index 0000000000..0eb8e579d7
--- /dev/null
+++ b/Core/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.c
@@ -0,0 +1,847 @@
+/** @file
+ Performance library instance mainly used by DxeCore.
+
+ This library provides the performance measurement interfaces and initializes performance
+ logging for DXE phase. It first initializes its private global data structure for
+ performance logging and saves the performance GUIDed HOB passed from PEI phase.
+ It initializes DXE phase performance logging by publishing the Performance and PerformanceEx Protocol,
+ which are consumed by DxePerformanceLib to logging performance data in DXE phase.
+
+ This library is mainly used by DxeCore to start performance logging to ensure that
+ Performance Protocol is installed at the very beginning of DXE phase.
+
+Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+
+#include "DxeCorePerformanceLibInternal.h"
+
+
+//
+// The data structure to hold global performance data.
+//
+GAUGE_DATA_HEADER *mGaugeData;
+
+//
+// The current maximum number of logging entries. If current number of
+// entries exceeds this value, it will re-allocate a larger array and
+// migration the old data to the larger array.
+//
+UINT32 mMaxGaugeRecords;
+
+//
+// The handle to install Performance Protocol instance.
+//
+EFI_HANDLE mHandle = NULL;
+
+//
+// Interfaces for Performance Protocol.
+//
+PERFORMANCE_PROTOCOL mPerformanceInterface = {
+ StartGauge,
+ EndGauge,
+ GetGauge
+ };
+
+//
+// Interfaces for PerformanceEx Protocol.
+//
+PERFORMANCE_EX_PROTOCOL mPerformanceExInterface = {
+ StartGaugeEx,
+ EndGaugeEx,
+ GetGaugeEx
+ };
+
+/**
+ Searches in the gauge array with keyword Handle, Token, Module and Identifier.
+
+ This internal function searches for the gauge entry in the gauge array.
+ If there is an entry that exactly matches the given keywords
+ and its end time stamp is zero, then the index of that gauge entry is returned;
+ otherwise, the the number of gauge entries in the array is returned.
+
+ @param Handle Pointer to environment specific context used
+ to identify the component being measured.
+ @param Token Pointer to a Null-terminated ASCII string
+ that identifies the component being measured.
+ @param Module Pointer to a Null-terminated ASCII string
+ that identifies the module being measured.
+ @param Identifier 32-bit identifier.
+
+ @retval The index of gauge entry in the array.
+
+**/
+UINT32
+InternalSearchForGaugeEntry (
+ IN CONST VOID *Handle, OPTIONAL
+ IN CONST CHAR8 *Token, OPTIONAL
+ IN CONST CHAR8 *Module, OPTIONAL
+ IN UINT32 Identifier
+ )
+{
+ UINT32 Index;
+ UINT32 Index2;
+ UINT32 NumberOfEntries;
+ GAUGE_DATA_ENTRY_EX *GaugeEntryExArray;
+
+ if (Token == NULL) {
+ Token = "";
+ }
+ if (Module == NULL) {
+ Module = "";
+ }
+
+ NumberOfEntries = mGaugeData->NumberOfEntries;
+ GaugeEntryExArray = (GAUGE_DATA_ENTRY_EX *) (mGaugeData + 1);
+
+ Index2 = 0;
+
+ for (Index = 0; Index < NumberOfEntries; Index++) {
+ Index2 = NumberOfEntries - 1 - Index;
+ if (GaugeEntryExArray[Index2].EndTimeStamp == 0 &&
+ (GaugeEntryExArray[Index2].Handle == (EFI_PHYSICAL_ADDRESS) (UINTN) Handle) &&
+ AsciiStrnCmp (GaugeEntryExArray[Index2].Token, Token, DXE_PERFORMANCE_STRING_LENGTH) == 0 &&
+ AsciiStrnCmp (GaugeEntryExArray[Index2].Module, Module, DXE_PERFORMANCE_STRING_LENGTH) == 0 &&
+ (GaugeEntryExArray[Index2].Identifier == Identifier)) {
+ Index = Index2;
+ break;
+ }
+ }
+
+ return Index;
+}
+
+/**
+ Adds a record at the end of the performance measurement log
+ that records the start time of a performance measurement.
+
+ Adds a record to the end of the performance measurement log
+ that contains the Handle, Token, Module and Identifier.
+ The end time of the new record must be set to zero.
+ If TimeStamp is not zero, then TimeStamp is used to fill in the start time in the record.
+ If TimeStamp is zero, the start time in the record is filled in with the value
+ read from the current time stamp.
+
+ @param Handle Pointer to environment specific context used
+ to identify the component being measured.
+ @param Token Pointer to a Null-terminated ASCII string
+ that identifies the component being measured.
+ @param Module Pointer to a Null-terminated ASCII string
+ that identifies the module being measured.
+ @param TimeStamp 64-bit time stamp.
+ @param Identifier 32-bit identifier. If the value is 0, the created record
+ is same as the one created by StartGauge of PERFORMANCE_PROTOCOL.
+
+ @retval EFI_SUCCESS The data was read correctly from the device.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources to record the measurement.
+
+**/
+EFI_STATUS
+EFIAPI
+StartGaugeEx (
+ IN CONST VOID *Handle, OPTIONAL
+ IN CONST CHAR8 *Token, OPTIONAL
+ IN CONST CHAR8 *Module, OPTIONAL
+ IN UINT64 TimeStamp,
+ IN UINT32 Identifier
+ )
+{
+ GAUGE_DATA_ENTRY_EX *GaugeEntryExArray;
+ UINTN GaugeDataSize;
+ GAUGE_DATA_HEADER *NewGaugeData;
+ UINTN OldGaugeDataSize;
+ GAUGE_DATA_HEADER *OldGaugeData;
+ UINT32 Index;
+
+ Index = mGaugeData->NumberOfEntries;
+ if (Index >= mMaxGaugeRecords) {
+ //
+ // Try to enlarge the scale of gauge array.
+ //
+ OldGaugeData = mGaugeData;
+ OldGaugeDataSize = sizeof (GAUGE_DATA_HEADER) + sizeof (GAUGE_DATA_ENTRY_EX) * mMaxGaugeRecords;
+
+ GaugeDataSize = sizeof (GAUGE_DATA_HEADER) + sizeof (GAUGE_DATA_ENTRY_EX) * mMaxGaugeRecords * 2;
+
+ NewGaugeData = AllocateZeroPool (GaugeDataSize);
+ if (NewGaugeData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ mGaugeData = NewGaugeData;
+ mMaxGaugeRecords *= 2;
+
+ //
+ // Initialize new data array and migrate old data one.
+ //
+ mGaugeData = CopyMem (mGaugeData, OldGaugeData, OldGaugeDataSize);
+
+ FreePool (OldGaugeData);
+ }
+
+ GaugeEntryExArray = (GAUGE_DATA_ENTRY_EX *) (mGaugeData + 1);
+ GaugeEntryExArray[Index].Handle = (EFI_PHYSICAL_ADDRESS) (UINTN) Handle;
+
+ if (Token != NULL) {
+ AsciiStrnCpyS (GaugeEntryExArray[Index].Token, DXE_PERFORMANCE_STRING_SIZE, Token, DXE_PERFORMANCE_STRING_LENGTH);
+ }
+ if (Module != NULL) {
+ AsciiStrnCpyS (GaugeEntryExArray[Index].Module, DXE_PERFORMANCE_STRING_SIZE, Module, DXE_PERFORMANCE_STRING_LENGTH);
+ }
+
+ GaugeEntryExArray[Index].EndTimeStamp = 0;
+ GaugeEntryExArray[Index].Identifier = Identifier;
+
+ if (TimeStamp == 0) {
+ TimeStamp = GetPerformanceCounter ();
+ }
+ GaugeEntryExArray[Index].StartTimeStamp = TimeStamp;
+
+ mGaugeData->NumberOfEntries++;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Searches the performance measurement log from the beginning of the log
+ for the first matching record that contains a zero end time and fills in a valid end time.
+
+ Searches the performance measurement log from the beginning of the log
+ for the first record that matches Handle, Token, Module and Identifier and has an end time value of zero.
+ If the record can not be found then return EFI_NOT_FOUND.
+ If the record is found and TimeStamp is not zero,
+ then the end time in the record is filled in with the value specified by TimeStamp.
+ If the record is found and TimeStamp is zero, then the end time in the matching record
+ is filled in with the current time stamp value.
+
+ @param Handle Pointer to environment specific context used
+ to identify the component being measured.
+ @param Token Pointer to a Null-terminated ASCII string
+ that identifies the component being measured.
+ @param Module Pointer to a Null-terminated ASCII string
+ that identifies the module being measured.
+ @param TimeStamp 64-bit time stamp.
+ @param Identifier 32-bit identifier. If the value is 0, the found record
+ is same as the one found by EndGauge of PERFORMANCE_PROTOCOL.
+
+ @retval EFI_SUCCESS The end of the measurement was recorded.
+ @retval EFI_NOT_FOUND The specified measurement record could not be found.
+
+**/
+EFI_STATUS
+EFIAPI
+EndGaugeEx (
+ IN CONST VOID *Handle, OPTIONAL
+ IN CONST CHAR8 *Token, OPTIONAL
+ IN CONST CHAR8 *Module, OPTIONAL
+ IN UINT64 TimeStamp,
+ IN UINT32 Identifier
+ )
+{
+ GAUGE_DATA_ENTRY_EX *GaugeEntryExArray;
+ UINT32 Index;
+
+ if (TimeStamp == 0) {
+ TimeStamp = GetPerformanceCounter ();
+ }
+
+ Index = InternalSearchForGaugeEntry (Handle, Token, Module, Identifier);
+ if (Index >= mGaugeData->NumberOfEntries) {
+ return EFI_NOT_FOUND;
+ }
+ GaugeEntryExArray = (GAUGE_DATA_ENTRY_EX *) (mGaugeData + 1);
+ GaugeEntryExArray[Index].EndTimeStamp = TimeStamp;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Retrieves a previously logged performance measurement.
+ It can also retrieve the log created by StartGauge and EndGauge of PERFORMANCE_PROTOCOL,
+ and then assign the Identifier with 0.
+
+ Retrieves the performance log entry from the performance log specified by LogEntryKey.
+ If it stands for a valid entry, then EFI_SUCCESS is returned and
+ GaugeDataEntryEx stores the pointer to that entry.
+
+ @param LogEntryKey The key for the previous performance measurement log entry.
+ If 0, then the first performance measurement log entry is retrieved.
+ @param GaugeDataEntryEx The indirect pointer to the extended gauge data entry specified by LogEntryKey
+ if the retrieval is successful.
+
+ @retval EFI_SUCCESS The GuageDataEntryEx is successfully found based on LogEntryKey.
+ @retval EFI_NOT_FOUND The LogEntryKey is the last entry (equals to the total entry number).
+ @retval EFI_INVALIDE_PARAMETER The LogEntryKey is not a valid entry (greater than the total entry number).
+ @retval EFI_INVALIDE_PARAMETER GaugeDataEntryEx is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+GetGaugeEx (
+ IN UINTN LogEntryKey,
+ OUT GAUGE_DATA_ENTRY_EX **GaugeDataEntryEx
+ )
+{
+ UINTN NumberOfEntries;
+ GAUGE_DATA_ENTRY_EX *GaugeEntryExArray;
+
+ NumberOfEntries = (UINTN) (mGaugeData->NumberOfEntries);
+ if (LogEntryKey > NumberOfEntries) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (LogEntryKey == NumberOfEntries) {
+ return EFI_NOT_FOUND;
+ }
+
+ GaugeEntryExArray = (GAUGE_DATA_ENTRY_EX *) (mGaugeData + 1);
+
+ if (GaugeDataEntryEx == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ *GaugeDataEntryEx = &GaugeEntryExArray[LogEntryKey];
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Adds a record at the end of the performance measurement log
+ that records the start time of a performance measurement.
+
+ Adds a record to the end of the performance measurement log
+ that contains the Handle, Token, and Module.
+ The end time of the new record must be set to zero.
+ If TimeStamp is not zero, then TimeStamp is used to fill in the start time in the record.
+ If TimeStamp is zero, the start time in the record is filled in with the value
+ read from the current time stamp.
+
+ @param Handle Pointer to environment specific context used
+ to identify the component being measured.
+ @param Token Pointer to a Null-terminated ASCII string
+ that identifies the component being measured.
+ @param Module Pointer to a Null-terminated ASCII string
+ that identifies the module being measured.
+ @param TimeStamp 64-bit time stamp.
+
+ @retval EFI_SUCCESS The data was read correctly from the device.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources to record the measurement.
+
+**/
+EFI_STATUS
+EFIAPI
+StartGauge (
+ IN CONST VOID *Handle, OPTIONAL
+ IN CONST CHAR8 *Token, OPTIONAL
+ IN CONST CHAR8 *Module, OPTIONAL
+ IN UINT64 TimeStamp
+ )
+{
+ return StartGaugeEx (Handle, Token, Module, TimeStamp, 0);
+}
+
+/**
+ Searches the performance measurement log from the beginning of the log
+ for the first matching record that contains a zero end time and fills in a valid end time.
+
+ Searches the performance measurement log from the beginning of the log
+ for the first record that matches Handle, Token, and Module and has an end time value of zero.
+ If the record can not be found then return EFI_NOT_FOUND.
+ If the record is found and TimeStamp is not zero,
+ then the end time in the record is filled in with the value specified by TimeStamp.
+ If the record is found and TimeStamp is zero, then the end time in the matching record
+ is filled in with the current time stamp value.
+
+ @param Handle Pointer to environment specific context used
+ to identify the component being measured.
+ @param Token Pointer to a Null-terminated ASCII string
+ that identifies the component being measured.
+ @param Module Pointer to a Null-terminated ASCII string
+ that identifies the module being measured.
+ @param TimeStamp 64-bit time stamp.
+
+ @retval EFI_SUCCESS The end of the measurement was recorded.
+ @retval EFI_NOT_FOUND The specified measurement record could not be found.
+
+**/
+EFI_STATUS
+EFIAPI
+EndGauge (
+ IN CONST VOID *Handle, OPTIONAL
+ IN CONST CHAR8 *Token, OPTIONAL
+ IN CONST CHAR8 *Module, OPTIONAL
+ IN UINT64 TimeStamp
+ )
+{
+ return EndGaugeEx (Handle, Token, Module, TimeStamp, 0);
+}
+
+/**
+ Retrieves a previously logged performance measurement.
+ It can also retrieve the log created by StartGaugeEx and EndGaugeEx of PERFORMANCE_EX_PROTOCOL,
+ and then eliminate the Identifier.
+
+ Retrieves the performance log entry from the performance log specified by LogEntryKey.
+ If it stands for a valid entry, then EFI_SUCCESS is returned and
+ GaugeDataEntry stores the pointer to that entry.
+
+ @param LogEntryKey The key for the previous performance measurement log entry.
+ If 0, then the first performance measurement log entry is retrieved.
+ @param GaugeDataEntry The indirect pointer to the gauge data entry specified by LogEntryKey
+ if the retrieval is successful.
+
+ @retval EFI_SUCCESS The GuageDataEntry is successfully found based on LogEntryKey.
+ @retval EFI_NOT_FOUND The LogEntryKey is the last entry (equals to the total entry number).
+ @retval EFI_INVALIDE_PARAMETER The LogEntryKey is not a valid entry (greater than the total entry number).
+ @retval EFI_INVALIDE_PARAMETER GaugeDataEntry is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+GetGauge (
+ IN UINTN LogEntryKey,
+ OUT GAUGE_DATA_ENTRY **GaugeDataEntry
+ )
+{
+ EFI_STATUS Status;
+ GAUGE_DATA_ENTRY_EX *GaugeEntryEx;
+
+ GaugeEntryEx = NULL;
+
+ Status = GetGaugeEx (LogEntryKey, &GaugeEntryEx);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (GaugeDataEntry == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *GaugeDataEntry = (GAUGE_DATA_ENTRY *) GaugeEntryEx;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Dumps all the PEI performance log to DXE performance gauge array.
+
+ This internal function dumps all the PEI performance log to the DXE performance gauge array.
+ It retrieves the optional GUID HOB for PEI performance and then saves the performance data
+ to DXE performance data structures.
+
+**/
+VOID
+InternalGetPeiPerformance (
+ VOID
+ )
+{
+ EFI_HOB_GUID_TYPE *GuidHob;
+ PEI_PERFORMANCE_LOG_HEADER *LogHob;
+ PEI_PERFORMANCE_LOG_ENTRY *LogEntryArray;
+ UINT32 *LogIdArray;
+ GAUGE_DATA_ENTRY_EX *GaugeEntryExArray;
+ UINT32 Index;
+ UINT32 NumberOfEntries;
+
+ NumberOfEntries = 0;
+ GaugeEntryExArray = (GAUGE_DATA_ENTRY_EX *) (mGaugeData + 1);
+
+ //
+ // Dump PEI Log Entries to DXE Guage Data structure.
+ //
+ GuidHob = GetFirstGuidHob (&gPerformanceProtocolGuid);
+ if (GuidHob != NULL) {
+ LogHob = GET_GUID_HOB_DATA (GuidHob);
+ LogEntryArray = (PEI_PERFORMANCE_LOG_ENTRY *) (LogHob + 1);
+
+ NumberOfEntries = LogHob->NumberOfEntries;
+ for (Index = 0; Index < NumberOfEntries; Index++) {
+ GaugeEntryExArray[Index].Handle = LogEntryArray[Index].Handle;
+ AsciiStrCpyS (GaugeEntryExArray[Index].Token, DXE_PERFORMANCE_STRING_SIZE, LogEntryArray[Index].Token);
+ AsciiStrCpyS (GaugeEntryExArray[Index].Module, DXE_PERFORMANCE_STRING_SIZE, LogEntryArray[Index].Module);
+ GaugeEntryExArray[Index].StartTimeStamp = LogEntryArray[Index].StartTimeStamp;
+ GaugeEntryExArray[Index].EndTimeStamp = LogEntryArray[Index].EndTimeStamp;
+ GaugeEntryExArray[Index].Identifier = 0;
+ }
+
+ GuidHob = GetFirstGuidHob (&gPerformanceExProtocolGuid);
+ if (GuidHob != NULL) {
+ LogIdArray = GET_GUID_HOB_DATA (GuidHob);
+ for (Index = 0; Index < NumberOfEntries; Index++) {
+ GaugeEntryExArray[Index].Identifier = LogIdArray[Index];
+ }
+ }
+ }
+ mGaugeData->NumberOfEntries = NumberOfEntries;
+}
+
+/**
+ The constructor function initializes Performance infrastructure for DXE phase.
+
+ The constructor function publishes Performance and PerformanceEx protocol, allocates memory to log DXE performance
+ and merges PEI performance data to DXE performance log.
+ It will ASSERT() if one of these operations fails and it will always return EFI_SUCCESS.
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
+
+**/
+EFI_STATUS
+EFIAPI
+DxeCorePerformanceLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ if (!PerformanceMeasurementEnabled ()) {
+ //
+ // Do not initialize performance infrastructure if not required.
+ //
+ return EFI_SUCCESS;
+ }
+ //
+ // Install the protocol interfaces.
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mHandle,
+ &gPerformanceProtocolGuid,
+ &mPerformanceInterface,
+ &gPerformanceExProtocolGuid,
+ &mPerformanceExInterface,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ mMaxGaugeRecords = INIT_DXE_GAUGE_DATA_ENTRIES + PcdGet8 (PcdMaxPeiPerformanceLogEntries);
+
+ mGaugeData = AllocateZeroPool (sizeof (GAUGE_DATA_HEADER) + (sizeof (GAUGE_DATA_ENTRY_EX) * mMaxGaugeRecords));
+ ASSERT (mGaugeData != NULL);
+
+ InternalGetPeiPerformance ();
+
+ return Status;
+}
+
+/**
+ Adds a record at the end of the performance measurement log
+ that records the start time of a performance measurement.
+
+ Adds a record to the end of the performance measurement log
+ that contains the Handle, Token, Module and Identifier.
+ The end time of the new record must be set to zero.
+ If TimeStamp is not zero, then TimeStamp is used to fill in the start time in the record.
+ If TimeStamp is zero, the start time in the record is filled in with the value
+ read from the current time stamp.
+
+ @param Handle Pointer to environment specific context used
+ to identify the component being measured.
+ @param Token Pointer to a Null-terminated ASCII string
+ that identifies the component being measured.
+ @param Module Pointer to a Null-terminated ASCII string
+ that identifies the module being measured.
+ @param TimeStamp 64-bit time stamp.
+ @param Identifier 32-bit identifier. If the value is 0, the created record
+ is same as the one created by StartPerformanceMeasurement.
+
+ @retval RETURN_SUCCESS The start of the measurement was recorded.
+ @retval RETURN_OUT_OF_RESOURCES There are not enough resources to record the measurement.
+
+**/
+RETURN_STATUS
+EFIAPI
+StartPerformanceMeasurementEx (
+ IN CONST VOID *Handle, OPTIONAL
+ IN CONST CHAR8 *Token, OPTIONAL
+ IN CONST CHAR8 *Module, OPTIONAL
+ IN UINT64 TimeStamp,
+ IN UINT32 Identifier
+ )
+{
+ return (RETURN_STATUS) StartGaugeEx (Handle, Token, Module, TimeStamp, Identifier);
+}
+
+/**
+ Searches the performance measurement log from the beginning of the log
+ for the first matching record that contains a zero end time and fills in a valid end time.
+
+ Searches the performance measurement log from the beginning of the log
+ for the first record that matches Handle, Token, Module and Identifier and has an end time value of zero.
+ If the record can not be found then return RETURN_NOT_FOUND.
+ If the record is found and TimeStamp is not zero,
+ then the end time in the record is filled in with the value specified by TimeStamp.
+ If the record is found and TimeStamp is zero, then the end time in the matching record
+ is filled in with the current time stamp value.
+
+ @param Handle Pointer to environment specific context used
+ to identify the component being measured.
+ @param Token Pointer to a Null-terminated ASCII string
+ that identifies the component being measured.
+ @param Module Pointer to a Null-terminated ASCII string
+ that identifies the module being measured.
+ @param TimeStamp 64-bit time stamp.
+ @param Identifier 32-bit identifier. If the value is 0, the found record
+ is same as the one found by EndPerformanceMeasurement.
+
+ @retval RETURN_SUCCESS The end of the measurement was recorded.
+ @retval RETURN_NOT_FOUND The specified measurement record could not be found.
+
+**/
+RETURN_STATUS
+EFIAPI
+EndPerformanceMeasurementEx (
+ IN CONST VOID *Handle, OPTIONAL
+ IN CONST CHAR8 *Token, OPTIONAL
+ IN CONST CHAR8 *Module, OPTIONAL
+ IN UINT64 TimeStamp,
+ IN UINT32 Identifier
+ )
+{
+ return (RETURN_STATUS) EndGaugeEx (Handle, Token, Module, TimeStamp, Identifier);
+}
+
+/**
+ Attempts to retrieve a performance measurement log entry from the performance measurement log.
+ It can also retrieve the log created by StartPerformanceMeasurement and EndPerformanceMeasurement,
+ and then assign the Identifier with 0.
+
+ Attempts to retrieve the performance log entry specified by LogEntryKey. If LogEntryKey is
+ zero on entry, then an attempt is made to retrieve the first entry from the performance log,
+ and the key for the second entry in the log is returned. If the performance log is empty,
+ then no entry is retrieved and zero is returned. If LogEntryKey is not zero, then the performance
+ log entry associated with LogEntryKey is retrieved, and the key for the next entry in the log is
+ returned. If LogEntryKey is the key for the last entry in the log, then the last log entry is
+ retrieved and an implementation specific non-zero key value that specifies the end of the performance
+ log is returned. If LogEntryKey is equal this implementation specific non-zero key value, then no entry
+ is retrieved and zero is returned. In the cases where a performance log entry can be returned,
+ the log entry is returned in Handle, Token, Module, StartTimeStamp, EndTimeStamp and Identifier.
+ If LogEntryKey is not a valid log entry key for the performance measurement log, then ASSERT().
+ If Handle is NULL, then ASSERT().
+ If Token is NULL, then ASSERT().
+ If Module is NULL, then ASSERT().
+ If StartTimeStamp is NULL, then ASSERT().
+ If EndTimeStamp is NULL, then ASSERT().
+ If Identifier is NULL, then ASSERT().
+
+ @param LogEntryKey On entry, the key of the performance measurement log entry to retrieve.
+ 0, then the first performance measurement log entry is retrieved.
+ On exit, the key of the next performance log entry.
+ @param Handle Pointer to environment specific context used to identify the component
+ being measured.
+ @param Token Pointer to a Null-terminated ASCII string that identifies the component
+ being measured.
+ @param Module Pointer to a Null-terminated ASCII string that identifies the module
+ being measured.
+ @param StartTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
+ was started.
+ @param EndTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
+ was ended.
+ @param Identifier Pointer to the 32-bit identifier that was recorded.
+
+ @return The key for the next performance log entry (in general case).
+
+**/
+UINTN
+EFIAPI
+GetPerformanceMeasurementEx (
+ IN UINTN LogEntryKey,
+ OUT CONST VOID **Handle,
+ OUT CONST CHAR8 **Token,
+ OUT CONST CHAR8 **Module,
+ OUT UINT64 *StartTimeStamp,
+ OUT UINT64 *EndTimeStamp,
+ OUT UINT32 *Identifier
+ )
+{
+ EFI_STATUS Status;
+ GAUGE_DATA_ENTRY_EX *GaugeData;
+
+ GaugeData = NULL;
+
+ ASSERT (Handle != NULL);
+ ASSERT (Token != NULL);
+ ASSERT (Module != NULL);
+ ASSERT (StartTimeStamp != NULL);
+ ASSERT (EndTimeStamp != NULL);
+ ASSERT (Identifier != NULL);
+
+ Status = GetGaugeEx (LogEntryKey++, &GaugeData);
+
+ //
+ // Make sure that LogEntryKey is a valid log entry key,
+ //
+ ASSERT (Status != EFI_INVALID_PARAMETER);
+
+ if (EFI_ERROR (Status)) {
+ //
+ // The LogEntryKey is the last entry (equals to the total entry number).
+ //
+ return 0;
+ }
+
+ ASSERT (GaugeData != NULL);
+
+ *Handle = (VOID *) (UINTN) GaugeData->Handle;
+ *Token = GaugeData->Token;
+ *Module = GaugeData->Module;
+ *StartTimeStamp = GaugeData->StartTimeStamp;
+ *EndTimeStamp = GaugeData->EndTimeStamp;
+ *Identifier = GaugeData->Identifier;
+
+ return LogEntryKey;
+}
+
+/**
+ Adds a record at the end of the performance measurement log
+ that records the start time of a performance measurement.
+
+ Adds a record to the end of the performance measurement log
+ that contains the Handle, Token, and Module.
+ The end time of the new record must be set to zero.
+ If TimeStamp is not zero, then TimeStamp is used to fill in the start time in the record.
+ If TimeStamp is zero, the start time in the record is filled in with the value
+ read from the current time stamp.
+
+ @param Handle Pointer to environment specific context used
+ to identify the component being measured.
+ @param Token Pointer to a Null-terminated ASCII string
+ that identifies the component being measured.
+ @param Module Pointer to a Null-terminated ASCII string
+ that identifies the module being measured.
+ @param TimeStamp 64-bit time stamp.
+
+ @retval RETURN_SUCCESS The start of the measurement was recorded.
+ @retval RETURN_OUT_OF_RESOURCES There are not enough resources to record the measurement.
+
+**/
+RETURN_STATUS
+EFIAPI
+StartPerformanceMeasurement (
+ IN CONST VOID *Handle, OPTIONAL
+ IN CONST CHAR8 *Token, OPTIONAL
+ IN CONST CHAR8 *Module, OPTIONAL
+ IN UINT64 TimeStamp
+ )
+{
+ return StartPerformanceMeasurementEx (Handle, Token, Module, TimeStamp, 0);
+}
+
+/**
+ Searches the performance measurement log from the beginning of the log
+ for the first matching record that contains a zero end time and fills in a valid end time.
+
+ Searches the performance measurement log from the beginning of the log
+ for the first record that matches Handle, Token, and Module and has an end time value of zero.
+ If the record can not be found then return RETURN_NOT_FOUND.
+ If the record is found and TimeStamp is not zero,
+ then the end time in the record is filled in with the value specified by TimeStamp.
+ If the record is found and TimeStamp is zero, then the end time in the matching record
+ is filled in with the current time stamp value.
+
+ @param Handle Pointer to environment specific context used
+ to identify the component being measured.
+ @param Token Pointer to a Null-terminated ASCII string
+ that identifies the component being measured.
+ @param Module Pointer to a Null-terminated ASCII string
+ that identifies the module being measured.
+ @param TimeStamp 64-bit time stamp.
+
+ @retval RETURN_SUCCESS The end of the measurement was recorded.
+ @retval RETURN_NOT_FOUND The specified measurement record could not be found.
+
+**/
+RETURN_STATUS
+EFIAPI
+EndPerformanceMeasurement (
+ IN CONST VOID *Handle, OPTIONAL
+ IN CONST CHAR8 *Token, OPTIONAL
+ IN CONST CHAR8 *Module, OPTIONAL
+ IN UINT64 TimeStamp
+ )
+{
+ return EndPerformanceMeasurementEx (Handle, Token, Module, TimeStamp, 0);
+}
+
+/**
+ Attempts to retrieve a performance measurement log entry from the performance measurement log.
+ It can also retrieve the log created by StartPerformanceMeasurementEx and EndPerformanceMeasurementEx,
+ and then eliminate the Identifier.
+
+ Attempts to retrieve the performance log entry specified by LogEntryKey. If LogEntryKey is
+ zero on entry, then an attempt is made to retrieve the first entry from the performance log,
+ and the key for the second entry in the log is returned. If the performance log is empty,
+ then no entry is retrieved and zero is returned. If LogEntryKey is not zero, then the performance
+ log entry associated with LogEntryKey is retrieved, and the key for the next entry in the log is
+ returned. If LogEntryKey is the key for the last entry in the log, then the last log entry is
+ retrieved and an implementation specific non-zero key value that specifies the end of the performance
+ log is returned. If LogEntryKey is equal this implementation specific non-zero key value, then no entry
+ is retrieved and zero is returned. In the cases where a performance log entry can be returned,
+ the log entry is returned in Handle, Token, Module, StartTimeStamp, and EndTimeStamp.
+ If LogEntryKey is not a valid log entry key for the performance measurement log, then ASSERT().
+ If Handle is NULL, then ASSERT().
+ If Token is NULL, then ASSERT().
+ If Module is NULL, then ASSERT().
+ If StartTimeStamp is NULL, then ASSERT().
+ If EndTimeStamp is NULL, then ASSERT().
+
+ @param LogEntryKey On entry, the key of the performance measurement log entry to retrieve.
+ 0, then the first performance measurement log entry is retrieved.
+ On exit, the key of the next performance log entry.
+ @param Handle Pointer to environment specific context used to identify the component
+ being measured.
+ @param Token Pointer to a Null-terminated ASCII string that identifies the component
+ being measured.
+ @param Module Pointer to a Null-terminated ASCII string that identifies the module
+ being measured.
+ @param StartTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
+ was started.
+ @param EndTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
+ was ended.
+
+ @return The key for the next performance log entry (in general case).
+
+**/
+UINTN
+EFIAPI
+GetPerformanceMeasurement (
+ IN UINTN LogEntryKey,
+ OUT CONST VOID **Handle,
+ OUT CONST CHAR8 **Token,
+ OUT CONST CHAR8 **Module,
+ OUT UINT64 *StartTimeStamp,
+ OUT UINT64 *EndTimeStamp
+ )
+{
+ UINT32 Identifier;
+ return GetPerformanceMeasurementEx (LogEntryKey, Handle, Token, Module, StartTimeStamp, EndTimeStamp, &Identifier);
+}
+
+/**
+ Returns TRUE if the performance measurement macros are enabled.
+
+ This function returns TRUE if the PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
+ PcdPerformanceLibraryPropertyMask is set. Otherwise FALSE is returned.
+
+ @retval TRUE The PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
+ PcdPerformanceLibraryPropertyMask is set.
+ @retval FALSE The PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
+ PcdPerformanceLibraryPropertyMask is clear.
+
+**/
+BOOLEAN
+EFIAPI
+PerformanceMeasurementEnabled (
+ VOID
+ )
+{
+ return (BOOLEAN) ((PcdGet8(PcdPerformanceLibraryPropertyMask) & PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED) != 0);
+}
diff --git a/Core/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.inf b/Core/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.inf
new file mode 100644
index 0000000000..5f290634c5
--- /dev/null
+++ b/Core/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.inf
@@ -0,0 +1,70 @@
+## @file
+# Performance library instance mainly for DxeCore usage.
+#
+# This library provides the performance measurement interfaces and initializes performance
+# logging for DXE phase. It first initializes its private global data structure for
+# performance logging and saves the performance GUIDed HOB passed from PEI phase.
+# It initializes DXE phase performance logging by publishing the Performance and PerformanceEx Protocol,
+# which is consumed by DxePerformanceLib to logging performance data in DXE phase.
+# This library is mainly used by DxeCore to start performance logging to ensure that
+# Performance and PerformanceEx Protocol are installed at the very beginning of DXE phase.
+#
+# Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxeCorePerformanceLib
+ MODULE_UNI_FILE = DxeCorePerformanceLib.uni
+ FILE_GUID = D0F78BBF-0A30-4c63-8A48-0F618A4AFACD
+ MODULE_TYPE = DXE_CORE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = PerformanceLib|DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SAL_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER
+
+ CONSTRUCTOR = DxeCorePerformanceLibConstructor
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ DxeCorePerformanceLib.c
+ DxeCorePerformanceLibInternal.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+
+[LibraryClasses]
+ MemoryAllocationLib
+ UefiBootServicesTableLib
+ PcdLib
+ TimerLib
+ BaseMemoryLib
+ BaseLib
+ HobLib
+ DebugLib
+
+
+[Guids]
+ ## SOMETIMES_CONSUMES ## HOB
+ ## PRODUCES ## UNDEFINED # Install protocol
+ gPerformanceProtocolGuid
+ ## SOMETIMES_CONSUMES ## HOB
+ ## PRODUCES ## UNDEFINED # Install protocol
+ gPerformanceExProtocolGuid
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxPeiPerformanceLogEntries ## CONSUMES
+ gEfiMdePkgTokenSpaceGuid.PcdPerformanceLibraryPropertyMask ## CONSUMES
diff --git a/Core/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.uni b/Core/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.uni
new file mode 100644
index 0000000000..094a214862
--- /dev/null
+++ b/Core/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.uni
Binary files differ
diff --git a/Core/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLibInternal.h b/Core/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLibInternal.h
new file mode 100644
index 0000000000..2b9ccd2fee
--- /dev/null
+++ b/Core/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLibInternal.h
@@ -0,0 +1,233 @@
+/** @file
+ Master header files for DxeCorePerformanceLib instance.
+
+ This header file holds the prototypes of the Performance and PerformanceEx Protocol published by this
+ library instance at its constructor.
+
+Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _DXE_CORE_PERFORMANCE_LIB_INTERNAL_H_
+#define _DXE_CORE_PERFORMANCE_LIB_INTERNAL_H_
+
+
+#include <PiDxe.h>
+
+#include <Guid/Performance.h>
+
+#include <Library/PerformanceLib.h>
+#include <Library/DebugLib.h>
+#include <Library/HobLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/TimerLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+//
+// Interface declarations for PerformanceEx Protocol.
+//
+/**
+ Adds a record at the end of the performance measurement log
+ that records the start time of a performance measurement.
+
+ Adds a record to the end of the performance measurement log
+ that contains the Handle, Token, Module and Identifier.
+ The end time of the new record must be set to zero.
+ If TimeStamp is not zero, then TimeStamp is used to fill in the start time in the record.
+ If TimeStamp is zero, the start time in the record is filled in with the value
+ read from the current time stamp.
+
+ @param Handle Pointer to environment specific context used
+ to identify the component being measured.
+ @param Token Pointer to a Null-terminated ASCII string
+ that identifies the component being measured.
+ @param Module Pointer to a Null-terminated ASCII string
+ that identifies the module being measured.
+ @param TimeStamp 64-bit time stamp.
+ @param Identifier 32-bit identifier. If the value is 0, the created record
+ is same as the one created by StartGauge of PERFORMANCE_PROTOCOL.
+
+ @retval EFI_SUCCESS The data was read correctly from the device.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources to record the measurement.
+
+**/
+EFI_STATUS
+EFIAPI
+StartGaugeEx (
+ IN CONST VOID *Handle, OPTIONAL
+ IN CONST CHAR8 *Token, OPTIONAL
+ IN CONST CHAR8 *Module, OPTIONAL
+ IN UINT64 TimeStamp,
+ IN UINT32 Identifier
+ );
+
+/**
+ Searches the performance measurement log from the beginning of the log
+ for the first matching record that contains a zero end time and fills in a valid end time.
+
+ Searches the performance measurement log from the beginning of the log
+ for the first record that matches Handle, Token, Module and Identifier and has an end time value of zero.
+ If the record can not be found then return EFI_NOT_FOUND.
+ If the record is found and TimeStamp is not zero,
+ then the end time in the record is filled in with the value specified by TimeStamp.
+ If the record is found and TimeStamp is zero, then the end time in the matching record
+ is filled in with the current time stamp value.
+
+ @param Handle Pointer to environment specific context used
+ to identify the component being measured.
+ @param Token Pointer to a Null-terminated ASCII string
+ that identifies the component being measured.
+ @param Module Pointer to a Null-terminated ASCII string
+ that identifies the module being measured.
+ @param TimeStamp 64-bit time stamp.
+ @param Identifier 32-bit identifier. If the value is 0, the found record
+ is same as the one found by EndGauge of PERFORMANCE_PROTOCOL.
+
+ @retval EFI_SUCCESS The end of the measurement was recorded.
+ @retval EFI_NOT_FOUND The specified measurement record could not be found.
+
+**/
+EFI_STATUS
+EFIAPI
+EndGaugeEx (
+ IN CONST VOID *Handle, OPTIONAL
+ IN CONST CHAR8 *Token, OPTIONAL
+ IN CONST CHAR8 *Module, OPTIONAL
+ IN UINT64 TimeStamp,
+ IN UINT32 Identifier
+ );
+
+/**
+ Retrieves a previously logged performance measurement.
+ It can also retrieve the log created by StartGauge and EndGauge of PERFORMANCE_PROTOCOL,
+ and then assign the Identifier with 0.
+
+ Retrieves the performance log entry from the performance log specified by LogEntryKey.
+ If it stands for a valid entry, then EFI_SUCCESS is returned and
+ GaugeDataEntryEx stores the pointer to that entry.
+
+ @param LogEntryKey The key for the previous performance measurement log entry.
+ If 0, then the first performance measurement log entry is retrieved.
+ @param GaugeDataEntryEx The indirect pointer to the extended gauge data entry specified by LogEntryKey
+ if the retrieval is successful.
+
+ @retval EFI_SUCCESS The GuageDataEntryEx is successfully found based on LogEntryKey.
+ @retval EFI_NOT_FOUND The LogEntryKey is the last entry (equals to the total entry number).
+ @retval EFI_INVALIDE_PARAMETER The LogEntryKey is not a valid entry (greater than the total entry number).
+ @retval EFI_INVALIDE_PARAMETER GaugeDataEntryEx is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+GetGaugeEx (
+ IN UINTN LogEntryKey,
+ OUT GAUGE_DATA_ENTRY_EX **GaugeDataEntryEx
+ );
+
+//
+// Interface declarations for Performance Protocol.
+//
+/**
+ Adds a record at the end of the performance measurement log
+ that records the start time of a performance measurement.
+
+ Adds a record to the end of the performance measurement log
+ that contains the Handle, Token, and Module.
+ The end time of the new record must be set to zero.
+ If TimeStamp is not zero, then TimeStamp is used to fill in the start time in the record.
+ If TimeStamp is zero, the start time in the record is filled in with the value
+ read from the current time stamp.
+
+ @param Handle Pointer to environment specific context used
+ to identify the component being measured.
+ @param Token Pointer to a Null-terminated ASCII string
+ that identifies the component being measured.
+ @param Module Pointer to a Null-terminated ASCII string
+ that identifies the module being measured.
+ @param TimeStamp 64-bit time stamp.
+
+ @retval EFI_SUCCESS The data was read correctly from the device.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources to record the measurement.
+
+**/
+EFI_STATUS
+EFIAPI
+StartGauge (
+ IN CONST VOID *Handle, OPTIONAL
+ IN CONST CHAR8 *Token, OPTIONAL
+ IN CONST CHAR8 *Module, OPTIONAL
+ IN UINT64 TimeStamp
+ );
+
+/**
+ Searches the performance measurement log from the beginning of the log
+ for the first matching record that contains a zero end time and fills in a valid end time.
+
+ Searches the performance measurement log from the beginning of the log
+ for the first record that matches Handle, Token, and Module and has an end time value of zero.
+ If the record can not be found then return EFI_NOT_FOUND.
+ If the record is found and TimeStamp is not zero,
+ then the end time in the record is filled in with the value specified by TimeStamp.
+ If the record is found and TimeStamp is zero, then the end time in the matching record
+ is filled in with the current time stamp value.
+
+ @param Handle Pointer to environment specific context used
+ to identify the component being measured.
+ @param Token Pointer to a Null-terminated ASCII string
+ that identifies the component being measured.
+ @param Module Pointer to a Null-terminated ASCII string
+ that identifies the module being measured.
+ @param TimeStamp 64-bit time stamp.
+
+ @retval EFI_SUCCESS The end of the measurement was recorded.
+ @retval EFI_NOT_FOUND The specified measurement record could not be found.
+
+**/
+EFI_STATUS
+EFIAPI
+EndGauge (
+ IN CONST VOID *Handle, OPTIONAL
+ IN CONST CHAR8 *Token, OPTIONAL
+ IN CONST CHAR8 *Module, OPTIONAL
+ IN UINT64 TimeStamp
+ );
+
+/**
+ Retrieves a previously logged performance measurement.
+ It can also retrieve the log created by StartGaugeEx and EndGaugeEx of PERFORMANCE_EX_PROTOCOL,
+ and then eliminate the Identifier.
+
+ Retrieves the performance log entry from the performance log specified by LogEntryKey.
+ If it stands for a valid entry, then EFI_SUCCESS is returned and
+ GaugeDataEntry stores the pointer to that entry.
+
+ @param LogEntryKey The key for the previous performance measurement log entry.
+ If 0, then the first performance measurement log entry is retrieved.
+ @param GaugeDataEntry The indirect pointer to the gauge data entry specified by LogEntryKey
+ if the retrieval is successful.
+
+ @retval EFI_SUCCESS The GuageDataEntry is successfully found based on LogEntryKey.
+ @retval EFI_NOT_FOUND The LogEntryKey is the last entry (equals to the total entry number).
+ @retval EFI_INVALIDE_PARAMETER The LogEntryKey is not a valid entry (greater than the total entry number).
+ @retval EFI_INVALIDE_PARAMETER GaugeDataEntry is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+GetGauge (
+ IN UINTN LogEntryKey,
+ OUT GAUGE_DATA_ENTRY **GaugeDataEntry
+ );
+
+
+#endif
diff --git a/Core/MdeModulePkg/Library/DxeCrc32GuidedSectionExtractLib/DxeCrc32GuidedSectionExtractLib.c b/Core/MdeModulePkg/Library/DxeCrc32GuidedSectionExtractLib/DxeCrc32GuidedSectionExtractLib.c
new file mode 100644
index 0000000000..de1b1368da
--- /dev/null
+++ b/Core/MdeModulePkg/Library/DxeCrc32GuidedSectionExtractLib/DxeCrc32GuidedSectionExtractLib.c
@@ -0,0 +1,236 @@
+/** @file
+
+ This library registers CRC32 guided section handler
+ to parse CRC32 encapsulation section and extract raw data.
+ It uses UEFI boot service CalculateCrc32 to authenticate 32 bit CRC value.
+
+Copyright (c) 2007 - 2011, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiDxe.h>
+#include <Guid/Crc32GuidedSectionExtraction.h>
+#include <Protocol/SecurityPolicy.h>
+#include <Library/ExtractGuidedSectionLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+///
+/// CRC32 Guided Section header
+///
+typedef struct {
+ EFI_GUID_DEFINED_SECTION GuidedSectionHeader; ///< EFI guided section header
+ UINT32 CRC32Checksum; ///< 32bit CRC check sum
+} CRC32_SECTION_HEADER;
+
+typedef struct {
+ EFI_GUID_DEFINED_SECTION2 GuidedSectionHeader; ///< EFI guided section header
+ UINT32 CRC32Checksum; ///< 32bit CRC check sum
+} CRC32_SECTION2_HEADER;
+
+/**
+
+ GetInfo gets raw data size and attribute of the input guided section.
+ It first checks whether the input guid section is supported.
+ If not, EFI_INVALID_PARAMETER will return.
+
+ @param InputSection Buffer containing the input GUIDed section to be processed.
+ @param OutputBufferSize The size of OutputBuffer.
+ @param ScratchBufferSize The size of ScratchBuffer.
+ @param SectionAttribute The attribute of the input guided section.
+
+ @retval EFI_SUCCESS The size of destination buffer, the size of scratch buffer and
+ the attribute of the input section are successull retrieved.
+ @retval EFI_INVALID_PARAMETER The GUID in InputSection does not match this instance guid.
+
+**/
+EFI_STATUS
+EFIAPI
+Crc32GuidedSectionGetInfo (
+ IN CONST VOID *InputSection,
+ OUT UINT32 *OutputBufferSize,
+ OUT UINT32 *ScratchBufferSize,
+ OUT UINT16 *SectionAttribute
+ )
+{
+ if (IS_SECTION2 (InputSection)) {
+ //
+ // Check whether the input guid section is recognized.
+ //
+ if (!CompareGuid (
+ &gEfiCrc32GuidedSectionExtractionGuid,
+ &(((EFI_GUID_DEFINED_SECTION2 *) InputSection)->SectionDefinitionGuid))) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Retrieve the size and attribute of the input section data.
+ //
+ *SectionAttribute = ((EFI_GUID_DEFINED_SECTION2 *) InputSection)->Attributes;
+ *ScratchBufferSize = 0;
+ *OutputBufferSize = SECTION2_SIZE (InputSection) - ((EFI_GUID_DEFINED_SECTION2 *) InputSection)->DataOffset;
+ } else {
+ //
+ // Check whether the input guid section is recognized.
+ //
+ if (!CompareGuid (
+ &gEfiCrc32GuidedSectionExtractionGuid,
+ &(((EFI_GUID_DEFINED_SECTION *) InputSection)->SectionDefinitionGuid))) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Retrieve the size and attribute of the input section data.
+ //
+ *SectionAttribute = ((EFI_GUID_DEFINED_SECTION *) InputSection)->Attributes;
+ *ScratchBufferSize = 0;
+ *OutputBufferSize = SECTION_SIZE (InputSection) - ((EFI_GUID_DEFINED_SECTION *) InputSection)->DataOffset;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Extraction handler tries to extract raw data from the input guided section.
+ It also does authentication check for 32bit CRC value in the input guided section.
+ It first checks whether the input guid section is supported.
+ If not, EFI_INVALID_PARAMETER will return.
+
+ @param InputSection Buffer containing the input GUIDed section to be processed.
+ @param OutputBuffer Buffer to contain the output raw data allocated by the caller.
+ @param ScratchBuffer A pointer to a caller-allocated buffer for function internal use.
+ @param AuthenticationStatus A pointer to a caller-allocated UINT32 that indicates the
+ authentication status of the output buffer.
+
+ @retval EFI_SUCCESS Section Data and Auth Status is extracted successfully.
+ @retval EFI_INVALID_PARAMETER The GUID in InputSection does not match this instance guid.
+
+**/
+EFI_STATUS
+EFIAPI
+Crc32GuidedSectionHandler (
+ IN CONST VOID *InputSection,
+ OUT VOID **OutputBuffer,
+ IN VOID *ScratchBuffer, OPTIONAL
+ OUT UINT32 *AuthenticationStatus
+ )
+{
+ EFI_STATUS Status;
+ UINT32 SectionCrc32Checksum;
+ UINT32 Crc32Checksum;
+ UINT32 OutputBufferSize;
+ VOID *DummyInterface;
+
+ if (IS_SECTION2 (InputSection)) {
+ //
+ // Check whether the input guid section is recognized.
+ //
+ if (!CompareGuid (
+ &gEfiCrc32GuidedSectionExtractionGuid,
+ &(((EFI_GUID_DEFINED_SECTION2 *) InputSection)->SectionDefinitionGuid))) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Get section Crc32 checksum.
+ //
+ SectionCrc32Checksum = ((CRC32_SECTION2_HEADER *) InputSection)->CRC32Checksum;
+ *OutputBuffer = (UINT8 *) InputSection + ((EFI_GUID_DEFINED_SECTION2 *) InputSection)->DataOffset;
+ OutputBufferSize = SECTION2_SIZE (InputSection) - ((EFI_GUID_DEFINED_SECTION2 *) InputSection)->DataOffset;
+
+ //
+ // Implicitly CRC32 GUIDed section should have STATUS_VALID bit set
+ //
+ ASSERT (((EFI_GUID_DEFINED_SECTION2 *) InputSection)->Attributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID);
+ *AuthenticationStatus = EFI_AUTH_STATUS_IMAGE_SIGNED;
+ } else {
+ //
+ // Check whether the input guid section is recognized.
+ //
+ if (!CompareGuid (
+ &gEfiCrc32GuidedSectionExtractionGuid,
+ &(((EFI_GUID_DEFINED_SECTION *) InputSection)->SectionDefinitionGuid))) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Get section Crc32 checksum.
+ //
+ SectionCrc32Checksum = ((CRC32_SECTION_HEADER *) InputSection)->CRC32Checksum;
+ *OutputBuffer = (UINT8 *) InputSection + ((EFI_GUID_DEFINED_SECTION *) InputSection)->DataOffset;
+ OutputBufferSize = SECTION_SIZE (InputSection) - ((EFI_GUID_DEFINED_SECTION *) InputSection)->DataOffset;
+
+ //
+ // Implicitly CRC32 GUIDed section should have STATUS_VALID bit set
+ //
+ ASSERT (((EFI_GUID_DEFINED_SECTION *) InputSection)->Attributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID);
+ *AuthenticationStatus = EFI_AUTH_STATUS_IMAGE_SIGNED;
+ }
+
+ //
+ // Init Checksum value to Zero.
+ //
+ Crc32Checksum = 0;
+
+ //
+ // Check whether there exists EFI_SECURITY_POLICY_PROTOCOL_GUID.
+ //
+ Status = gBS->LocateProtocol (&gEfiSecurityPolicyProtocolGuid, NULL, &DummyInterface);
+ if (!EFI_ERROR (Status)) {
+ //
+ // If SecurityPolicy Protocol exist, AUTH platform override bit is set.
+ //
+ *AuthenticationStatus |= EFI_AUTH_STATUS_PLATFORM_OVERRIDE;
+ } else {
+ //
+ // Calculate CRC32 Checksum of Image
+ //
+ Status = gBS->CalculateCrc32 (*OutputBuffer, OutputBufferSize, &Crc32Checksum);
+ if (Status == EFI_SUCCESS) {
+ if (Crc32Checksum != SectionCrc32Checksum) {
+ //
+ // If Crc32 checksum is not matched, AUTH tested failed bit is set.
+ //
+ *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED;
+ }
+ } else {
+ //
+ // If Crc32 checksum is not calculated, AUTH not tested bit is set.
+ //
+ *AuthenticationStatus |= EFI_AUTH_STATUS_NOT_TESTED;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Register the handler to extract CRC32 guided section.
+
+ @param ImageHandle ImageHandle of the loaded driver.
+ @param SystemTable Pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS Register successfully.
+ @retval EFI_OUT_OF_RESOURCES No enough memory to register this handler.
+**/
+EFI_STATUS
+EFIAPI
+DxeCrc32GuidedSectionExtractLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ return ExtractGuidedSectionRegisterHandlers (
+ &gEfiCrc32GuidedSectionExtractionGuid,
+ Crc32GuidedSectionGetInfo,
+ Crc32GuidedSectionHandler
+ );
+}
+
diff --git a/Core/MdeModulePkg/Library/DxeCrc32GuidedSectionExtractLib/DxeCrc32GuidedSectionExtractLib.inf b/Core/MdeModulePkg/Library/DxeCrc32GuidedSectionExtractLib/DxeCrc32GuidedSectionExtractLib.inf
new file mode 100644
index 0000000000..d244897ab6
--- /dev/null
+++ b/Core/MdeModulePkg/Library/DxeCrc32GuidedSectionExtractLib/DxeCrc32GuidedSectionExtractLib.inf
@@ -0,0 +1,55 @@
+## @file
+# Dxe Crc32 Guided Section Extract library.
+#
+# This library doesn't produce any library class. The constructor function uses
+# ExtractGuidedSectionLib service to register CRC32 guided section handler
+# that parses CRC32 encapsulation section and extracts raw data.
+#
+# It uses UEFI boot service CalculateCrc32 to authenticate 32 bit CRC value.
+#
+# Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxeCrc32GuidedSectionExtractLib
+ MODULE_UNI_FILE = DxeCrc32GuidedSectionExtractLib.uni
+ FILE_GUID = 387A2490-81FC-4E7C-8E0A-3E58C30FCD0B
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = NULL|DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SAL_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER
+
+ CONSTRUCTOR = DxeCrc32GuidedSectionExtractLibConstructor
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ DxeCrc32GuidedSectionExtractLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ ExtractGuidedSectionLib
+ UefiBootServicesTableLib
+ DebugLib
+ BaseMemoryLib
+
+[Guids]
+ gEfiCrc32GuidedSectionExtractionGuid ## PRODUCES ## UNDEFINED
+
+[Protocols]
+ gEfiSecurityPolicyProtocolGuid ## SOMETIMES_CONSUMES # Set platform override AUTH status if exist
diff --git a/Core/MdeModulePkg/Library/DxeCrc32GuidedSectionExtractLib/DxeCrc32GuidedSectionExtractLib.uni b/Core/MdeModulePkg/Library/DxeCrc32GuidedSectionExtractLib/DxeCrc32GuidedSectionExtractLib.uni
new file mode 100644
index 0000000000..7e6e0c4e8e
--- /dev/null
+++ b/Core/MdeModulePkg/Library/DxeCrc32GuidedSectionExtractLib/DxeCrc32GuidedSectionExtractLib.uni
Binary files differ
diff --git a/Core/MdeModulePkg/Library/DxeDebugPrintErrorLevelLib/DxeDebugPrintErrorLevelLib.c b/Core/MdeModulePkg/Library/DxeDebugPrintErrorLevelLib/DxeDebugPrintErrorLevelLib.c
new file mode 100644
index 0000000000..cad57024cd
--- /dev/null
+++ b/Core/MdeModulePkg/Library/DxeDebugPrintErrorLevelLib/DxeDebugPrintErrorLevelLib.c
@@ -0,0 +1,388 @@
+/** @file
+ Debug Print Error Level library instance that provide compatibility with the
+ "err" shell command. This includes support for the Debug Mask Protocol
+ supports for global debug print error level mask stored in an EFI Variable.
+ This library instance only support DXE Phase modules.
+
+ Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiDxe.h>
+
+#include <Library/DebugPrintErrorLevelLib.h>
+#include <Library/PcdLib.h>
+#include <Library/HobLib.h>
+
+#include <Guid/DebugMask.h>
+
+///
+/// Debug Mask Protocol function prototypes
+///
+
+/**
+ Retrieves the current debug print error level mask for a module are returns
+ it in CurrentDebugMask.
+
+ @param This The protocol instance pointer.
+ @param CurrentDebugMask Pointer to the debug print error level mask that
+ is returned.
+
+ @retval EFI_SUCCESS The current debug print error level mask was
+ returned in CurrentDebugMask.
+ @retval EFI_INVALID_PARAMETER CurrentDebugMask is NULL.
+ @retval EFI_DEVICE_ERROR The current debug print error level mask could
+ not be retrieved.
+
+**/
+EFI_STATUS
+EFIAPI
+GetDebugMask (
+ IN EFI_DEBUG_MASK_PROTOCOL *This,
+ IN OUT UINTN *CurrentDebugMask
+ );
+
+/**
+ Sets the current debug print error level mask for a module to the value
+ specified by NewDebugMask.
+
+ @param This The protocol instance pointer.
+ @param NewDebugMask The new debug print error level mask for this module.
+
+ @retval EFI_SUCCESS The current debug print error level mask was
+ set to the value specified by NewDebugMask.
+ @retval EFI_DEVICE_ERROR The current debug print error level mask could
+ not be set to the value specified by NewDebugMask.
+
+**/
+EFI_STATUS
+EFIAPI
+SetDebugMask (
+ IN EFI_DEBUG_MASK_PROTOCOL *This,
+ IN UINTN NewDebugMask
+ );
+
+///
+/// Debug Mask Protocol instance
+///
+EFI_DEBUG_MASK_PROTOCOL mDebugMaskProtocol = {
+ EFI_DEBUG_MASK_REVISION,
+ GetDebugMask,
+ SetDebugMask
+};
+
+///
+/// Global variable that is set to TRUE after the first attempt is made to
+/// retrieve the global error level mask through the EFI Varibale Services.
+/// This variable prevents the EFI Variable Services from being called fort
+/// every DEBUG() macro.
+///
+BOOLEAN mGlobalErrorLevelInitialized = FALSE;
+
+///
+/// Global variable that contains the current debug error level mask for the
+/// module that is using this library instance. This variable is initially
+/// set to the PcdDebugPrintErrorLevel value. If the EFI Variable exists that
+/// contains the global debug print error level mask, then that overrides the
+/// PcdDebugPrintErrorLevel value. The EFI Variable can optionally be
+/// discovered via a HOB so early DXE drivers can access the variable. If the
+/// Debug Mask Protocol SetDebugMask() service is called, then that overrides
+/// the PcdDebugPrintErrorLevel and the EFI Variable setting.
+///
+UINT32 mDebugPrintErrorLevel = 0;
+
+///
+/// Global variable that is used to cache a pointer to the EFI System Table
+/// that is required to access the EFI Variable Services to get and set
+/// the global debug print error level mask value. The UefiBootServicesTableLib
+/// is not used to prevent a circular dependency between these libraries.
+///
+EFI_SYSTEM_TABLE *mSystemTable = NULL;
+
+/**
+ The constructor function caches the PCI Express Base Address and creates a
+ Set Virtual Address Map event to convert physical address to virtual addresses.
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The constructor completed successfully.
+ @retval Other value The constructor did not complete successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+DxeDebugPrintErrorLevelLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Initialize the error level mask from PCD setting.
+ //
+ mDebugPrintErrorLevel = PcdGet32 (PcdDebugPrintErrorLevel);
+
+ //
+ // Install Debug Mask Protocol onto ImageHandle
+ //
+ mSystemTable = SystemTable;
+ Status = SystemTable->BootServices->InstallMultipleProtocolInterfaces (
+ &ImageHandle,
+ &gEfiDebugMaskProtocolGuid, &mDebugMaskProtocol,
+ NULL
+ );
+
+ //
+ // Attempt to retrieve the global debug print error level mask from the EFI Variable
+ // If the EFI Variable can not be accessed when this module's library constructors are
+ // executed a HOB can be used to set the global debug print error level. If no value
+ // was found then the EFI Variable access will be reattempted on every DEBUG() print
+ // from this module until the EFI Variable services are available.
+ //
+ GetDebugPrintErrorLevel ();
+
+ return Status;
+}
+
+/**
+ The destructor function frees any allocated buffers and closes the Set Virtual
+ Address Map event.
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The destructor completed successfully.
+ @retval Other value The destructor did not complete successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+DxeDebugPrintErrorLevelLibDestructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ //
+ // Uninstall the Debug Mask Protocol from ImageHandle
+ //
+ return SystemTable->BootServices->UninstallMultipleProtocolInterfaces (
+ ImageHandle,
+ &gEfiDebugMaskProtocolGuid, &mDebugMaskProtocol,
+ NULL
+ );
+}
+
+/**
+ Returns the debug print error level mask for the current module.
+
+ @return Debug print error level mask for the current module.
+
+**/
+UINT32
+EFIAPI
+GetDebugPrintErrorLevel (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_TPL CurrentTpl;
+ UINTN Size;
+ UINTN GlobalErrorLevel;
+ VOID *Hob;
+
+ //
+ // If the constructor has not been executed yet, then just return the PCD value.
+ // This case should only occur if debug print is generated by a library
+ // constructor for this module
+ //
+ if (mSystemTable == NULL) {
+ return PcdGet32 (PcdDebugPrintErrorLevel);
+ }
+
+ //
+ // Check to see if an attempt has been made to retrieve the global debug print
+ // error level mask. Since this library instance stores the global debug print
+ // error level mask in an EFI Variable, the EFI Variable should only be accessed
+ // once to reduce the overhead of reading the EFI Variable on every debug print
+ //
+ if (!mGlobalErrorLevelInitialized) {
+ //
+ // Make sure the TPL Level is low enough for EFI Variable Services to be called
+ //
+ CurrentTpl = mSystemTable->BootServices->RaiseTPL (TPL_HIGH_LEVEL);
+ mSystemTable->BootServices->RestoreTPL (CurrentTpl);
+ if (CurrentTpl <= TPL_CALLBACK) {
+ //
+ // Attempt to retrieve the global debug print error level mask from the
+ // EFI Variable
+ //
+ Size = sizeof (GlobalErrorLevel);
+ Status = mSystemTable->RuntimeServices->GetVariable (
+ DEBUG_MASK_VARIABLE_NAME,
+ &gEfiGenericVariableGuid,
+ NULL,
+ &Size,
+ &GlobalErrorLevel
+ );
+ if (Status != EFI_NOT_AVAILABLE_YET) {
+ //
+ // If EFI Variable Services are available, then set a flag so the EFI
+ // Variable will not be read again by this module.
+ //
+ mGlobalErrorLevelInitialized = TRUE;
+ if (!EFI_ERROR (Status)) {
+ //
+ // If the EFI Varible exists, then set this module's module's mask to
+ // the global debug print error level mask value.
+ //
+ mDebugPrintErrorLevel = (UINT32)GlobalErrorLevel;
+ }
+ } else {
+ //
+ // If variable services are not yet availible optionally get the global
+ // debug print error level mask from a HOB.
+ //
+ Hob = GetFirstGuidHob (&gEfiGenericVariableGuid);
+ if (Hob != NULL) {
+ if (GET_GUID_HOB_DATA_SIZE (Hob) == sizeof (UINT32)) {
+ mDebugPrintErrorLevel = *(UINT32 *)GET_GUID_HOB_DATA (Hob);
+ mGlobalErrorLevelInitialized = TRUE;
+ }
+ }
+ }
+ }
+ }
+
+ //
+ // Return the current mask value for this module.
+ //
+ return mDebugPrintErrorLevel;
+}
+
+/**
+ Sets the global debug print error level mask fpr the entire platform.
+
+ @param ErrorLevel Global debug print error level
+
+ @retval TRUE The debug print error level mask was sucessfully set.
+ @retval FALSE The debug print error level mask could not be set.
+
+**/
+BOOLEAN
+EFIAPI
+SetDebugPrintErrorLevel (
+ UINT32 ErrorLevel
+ )
+{
+ EFI_STATUS Status;
+ EFI_TPL CurrentTpl;
+ UINTN Size;
+ UINTN GlobalErrorLevel;
+
+ //
+ // Make sure the constructor has been executed
+ //
+ if (mSystemTable != NULL) {
+ //
+ // Make sure the TPL Level is low enough for EFI Variable Services
+ //
+ CurrentTpl = mSystemTable->BootServices->RaiseTPL (TPL_HIGH_LEVEL);
+ mSystemTable->BootServices->RestoreTPL (CurrentTpl);
+ if (CurrentTpl <= TPL_CALLBACK) {
+ //
+ // Attempt to store the global debug print error level mask in an EFI Variable
+ //
+ GlobalErrorLevel = (UINTN)ErrorLevel;
+ Size = sizeof (GlobalErrorLevel);
+ Status = mSystemTable->RuntimeServices->SetVariable (
+ DEBUG_MASK_VARIABLE_NAME,
+ &gEfiGenericVariableGuid,
+ (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS),
+ Size,
+ &GlobalErrorLevel
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // If the EFI Variable was updated, then update the mask value for this
+ // module and return TRUE.
+ //
+ mGlobalErrorLevelInitialized = TRUE;
+ mDebugPrintErrorLevel = ErrorLevel;
+ return TRUE;
+ }
+ }
+ }
+ //
+ // Return FALSE since the EFI Variable could not be updated.
+ //
+ return FALSE;
+}
+
+/**
+ Retrieves the current debug print error level mask for a module are returns
+ it in CurrentDebugMask.
+
+ @param This The protocol instance pointer.
+ @param CurrentDebugMask Pointer to the debug print error level mask that
+ is returned.
+
+ @retval EFI_SUCCESS The current debug print error level mask was
+ returned in CurrentDebugMask.
+ @retval EFI_INVALID_PARAMETER CurrentDebugMask is NULL.
+ @retval EFI_DEVICE_ERROR The current debug print error level mask could
+ not be retrieved.
+
+**/
+EFI_STATUS
+EFIAPI
+GetDebugMask (
+ IN EFI_DEBUG_MASK_PROTOCOL *This,
+ IN OUT UINTN *CurrentDebugMask
+ )
+{
+ if (CurrentDebugMask == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Retrieve the current debug mask from mDebugPrintErrorLevel
+ //
+ *CurrentDebugMask = (UINTN)mDebugPrintErrorLevel;
+ return EFI_SUCCESS;
+}
+
+/**
+ Sets the current debug print error level mask for a module to the value
+ specified by NewDebugMask.
+
+ @param This The protocol instance pointer.
+ @param NewDebugMask The new debug print error level mask for this module.
+
+ @retval EFI_SUCCESS The current debug print error level mask was
+ set to the value specified by NewDebugMask.
+ @retval EFI_DEVICE_ERROR The current debug print error level mask could
+ not be set to the value specified by NewDebugMask.
+
+**/
+EFI_STATUS
+EFIAPI
+SetDebugMask (
+ IN EFI_DEBUG_MASK_PROTOCOL *This,
+ IN UINTN NewDebugMask
+ )
+{
+ //
+ // Store the new debug mask into mDebugPrintErrorLevel
+ //
+ mDebugPrintErrorLevel = (UINT32)NewDebugMask;
+ return EFI_SUCCESS;
+}
diff --git a/Core/MdeModulePkg/Library/DxeDebugPrintErrorLevelLib/DxeDebugPrintErrorLevelLib.inf b/Core/MdeModulePkg/Library/DxeDebugPrintErrorLevelLib/DxeDebugPrintErrorLevelLib.inf
new file mode 100644
index 0000000000..b471af7a88
--- /dev/null
+++ b/Core/MdeModulePkg/Library/DxeDebugPrintErrorLevelLib/DxeDebugPrintErrorLevelLib.inf
@@ -0,0 +1,54 @@
+## @file
+# Debug Print Error Level library instance that provide compatibility with the "err" shell command.
+# This includes support for the Debug Mask Protocol supports for global debug print error level mask
+# stored in an EFI Variable. This library instance only support DXE Phase modules.
+#
+# Copyright (c) 2011 - 2014, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php.
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxeDebugPrintErrorLevelLib
+ MODULE_UNI_FILE = DxeDebugPrintErrorLevelLib.uni
+ FILE_GUID = 1D564EC9-9373-49a4-9E3F-E4D7B9974C84
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = DebugPrintErrorLevelLib|DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SAL_DRIVER UEFI_APPLICATION UEFI_DRIVER
+ CONSTRUCTOR = DxeDebugPrintErrorLevelLibConstructor
+ DESTRUCTOR = DxeDebugPrintErrorLevelLibDestructor
+
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ DxeDebugPrintErrorLevelLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ PcdLib
+ HobLib
+
+[Protocols]
+ gEfiDebugMaskProtocolGuid ## PRODUCES
+
+[Guids]
+ ## SOMETIMES_PRODUCES ## Variable:L"EFIDebug"
+ ## SOMETIMES_CONSUMES ## Variable:L"EFIDebug"
+ ## SOMETIMES_CONSUMES ## HOB
+ gEfiGenericVariableGuid
+
+[Pcd]
+ gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevel ## CONSUMES
diff --git a/Core/MdeModulePkg/Library/DxeDebugPrintErrorLevelLib/DxeDebugPrintErrorLevelLib.uni b/Core/MdeModulePkg/Library/DxeDebugPrintErrorLevelLib/DxeDebugPrintErrorLevelLib.uni
new file mode 100644
index 0000000000..b1e53686ae
--- /dev/null
+++ b/Core/MdeModulePkg/Library/DxeDebugPrintErrorLevelLib/DxeDebugPrintErrorLevelLib.uni
Binary files differ
diff --git a/Core/MdeModulePkg/Library/DxeDpcLib/DpcLib.c b/Core/MdeModulePkg/Library/DxeDpcLib/DpcLib.c
new file mode 100644
index 0000000000..6eda8ca0fb
--- /dev/null
+++ b/Core/MdeModulePkg/Library/DxeDpcLib/DpcLib.c
@@ -0,0 +1,100 @@
+/** @file
+ Help functions to access UDP service.
+
+Copyright (c) 2005 - 2007, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+**/
+
+#include <Uefi.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Protocol/Dpc.h>
+
+//
+// Pointer to the DPC Protocol
+//
+EFI_DPC_PROTOCOL *mDpc;
+
+/**
+ This constructor function caches the EFI_DPC_PROTOCOL pointer.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The constructor always return EFI_SUCCESS.
+
+**/
+EFI_STATUS
+EFIAPI
+DpcLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Locate the EFI_DPC_PROTOCOL in the handle database
+ //
+ Status = gBS->LocateProtocol (&gEfiDpcProtocolGuid, NULL, (VOID **)&mDpc);
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Add a Deferred Procedure Call to the end of the DPC queue.
+
+ @param[in] DpcTpl The EFI_TPL that the DPC should be invoked.
+ @param[in] DpcProcedure Pointer to the DPC's function.
+ @param[in] DpcContext Pointer to the DPC's context. Passed to DpcProcedure
+ when DpcProcedure is invoked.
+
+ @retval EFI_SUCCESS The DPC was queued.
+ @retval EFI_INVALID_PARAMETER DpcTpl is not a valid EFI_TPL.
+ @retval EFI_INVALID_PARAMETER DpcProcedure is NULL.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources available to
+ add the DPC to the queue.
+
+**/
+EFI_STATUS
+EFIAPI
+QueueDpc (
+ IN EFI_TPL DpcTpl,
+ IN EFI_DPC_PROCEDURE DpcProcedure,
+ IN VOID *DpcContext OPTIONAL
+ )
+{
+ //
+ // Call the EFI_DPC_PROTOCOL to queue the DPC
+ //
+ return mDpc->QueueDpc (mDpc, DpcTpl, DpcProcedure, DpcContext);
+}
+
+/**
+ Dispatch the queue of DPCs. ALL DPCs that have been queued with a DpcTpl
+ value greater than or equal to the current TPL are invoked in the order that
+ they were queued. DPCs with higher DpcTpl values are invoked before DPCs with
+ lower DpcTpl values.
+
+ @retval EFI_SUCCESS One or more DPCs were invoked.
+ @retval EFI_NOT_FOUND No DPCs were invoked.
+
+**/
+EFI_STATUS
+EFIAPI
+DispatchDpc (
+ VOID
+ )
+{
+ //
+ // Call the EFI_DPC_PROTOCOL to dispatch previously queued DPCs
+ //
+ return mDpc->DispatchDpc (mDpc);
+}
diff --git a/Core/MdeModulePkg/Library/DxeDpcLib/DxeDpcLib.inf b/Core/MdeModulePkg/Library/DxeDpcLib/DxeDpcLib.inf
new file mode 100644
index 0000000000..d541acd5a9
--- /dev/null
+++ b/Core/MdeModulePkg/Library/DxeDpcLib/DxeDpcLib.inf
@@ -0,0 +1,46 @@
+## @file
+# This library instance provides DPC service by consuming EFI DPC Protocol.
+#
+# Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxeDpcLib
+ MODULE_UNI_FILE = DxeDpcLib.uni
+ FILE_GUID = 38897D86-FF36-4472-AE64-1DB9AE715C81
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = DpcLib|DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SAL_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER
+ CONSTRUCTOR = DpcLibConstructor
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ DpcLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ DebugLib
+ UefiBootServicesTableLib
+
+[Protocols]
+ gEfiDpcProtocolGuid ## CONSUMES
+
+[Depex.common.DXE_DRIVER, Depex.common.DXE_RUNTIME_DRIVER, Depex.common.DXE_SAL_DRIVER, Depex.common.DXE_SMM_DRIVER]
+ gEfiDpcProtocolGuid
diff --git a/Core/MdeModulePkg/Library/DxeDpcLib/DxeDpcLib.uni b/Core/MdeModulePkg/Library/DxeDpcLib/DxeDpcLib.uni
new file mode 100644
index 0000000000..3624f669f8
--- /dev/null
+++ b/Core/MdeModulePkg/Library/DxeDpcLib/DxeDpcLib.uni
Binary files differ
diff --git a/Core/MdeModulePkg/Library/DxeHttpLib/DxeHttpLib.c b/Core/MdeModulePkg/Library/DxeHttpLib/DxeHttpLib.c
new file mode 100644
index 0000000000..143baabdec
--- /dev/null
+++ b/Core/MdeModulePkg/Library/DxeHttpLib/DxeHttpLib.c
@@ -0,0 +1,1427 @@
+/** @file
+ This library is used to share code between UEFI network stack modules.
+ It provides the helper routines to parse the HTTP message byte stream.
+
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at<BR>
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Uefi.h>
+#include <Library/NetLib.h>
+#include <Library/HttpLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+#define BIT(x) (1 << x)
+
+#define NET_IS_HEX_CHAR(Ch) \
+ ((('0' <= (Ch)) && ((Ch) <= '9')) || \
+ (('A' <= (Ch)) && ((Ch) <= 'F')) || \
+ (('a' <= (Ch)) && ((Ch) <= 'f')))
+
+//
+// Field index of the HTTP URL parse result.
+//
+#define HTTP_URI_FIELD_SCHEME 0
+#define HTTP_URI_FIELD_AUTHORITY 1
+#define HTTP_URI_FIELD_PATH 2
+#define HTTP_URI_FIELD_QUERY 3
+#define HTTP_URI_FIELD_FRAGMENT 4
+#define HTTP_URI_FIELD_USERINFO 5
+#define HTTP_URI_FIELD_HOST 6
+#define HTTP_URI_FIELD_PORT 7
+#define HTTP_URI_FIELD_MAX 8
+
+//
+// Structure to store the parse result of a HTTP URL.
+//
+typedef struct {
+ UINT32 Offset;
+ UINT32 Length;
+} HTTP_URL_FILED_DATA;
+
+typedef struct {
+ UINT16 FieldBitMap;
+ HTTP_URL_FILED_DATA FieldData[HTTP_URI_FIELD_MAX];
+} HTTP_URL_PARSER;
+
+typedef enum {
+ UrlParserUrlStart,
+ UrlParserScheme,
+ UrlParserSchemeColon, // ":"
+ UrlParserSchemeColonSlash, // ":/"
+ UrlParserSchemeColonSlashSlash, // "://"
+ UrlParserAuthority,
+ UrlParserAtInAuthority,
+ UrlParserPath,
+ UrlParserQueryStart, // "?"
+ UrlParserQuery,
+ UrlParserFragmentStart, // "#"
+ UrlParserFragment,
+ UrlParserUserInfo,
+ UrlParserHostStart, // "@"
+ UrlParserHost,
+ UrlParserHostIpv6, // "["(Ipv6 address) "]"
+ UrlParserPortStart, // ":"
+ UrlParserPort,
+ UrlParserStateMax
+} HTTP_URL_PARSE_STATE;
+
+/**
+ Decode a percent-encoded URI component to the ASCII character.
+
+ Decode the input component in Buffer according to RFC 3986. The caller is responsible to make
+ sure ResultBuffer points to a buffer with size equal or greater than ((AsciiStrSize (Buffer))
+ in bytes.
+
+ @param[in] Buffer The pointer to a percent-encoded URI component.
+ @param[in] BufferLength Length of Buffer in bytes.
+ @param[out] ResultBuffer Point to the buffer to store the decode result.
+ @param[out] ResultLength Length of decoded string in ResultBuffer in bytes.
+
+ @retval EFI_SUCCESS Successfully decoded the URI.
+ @retval EFI_INVALID_PARAMETER Buffer is not a valid percent-encoded string.
+
+**/
+EFI_STATUS
+EFIAPI
+UriPercentDecode (
+ IN CHAR8 *Buffer,
+ IN UINT32 BufferLength,
+ OUT CHAR8 *ResultBuffer,
+ OUT UINT32 *ResultLength
+ )
+{
+ UINTN Index;
+ UINTN Offset;
+ CHAR8 HexStr[3];
+
+ if (Buffer == NULL || BufferLength == 0 || ResultBuffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Index = 0;
+ Offset = 0;
+ HexStr[2] = '\0';
+ while (Index < BufferLength) {
+ if (Buffer[Index] == '%') {
+ if (!NET_IS_HEX_CHAR (Buffer[Index+1]) || !NET_IS_HEX_CHAR (Buffer[Index+2])) {
+ return EFI_INVALID_PARAMETER;
+ }
+ HexStr[0] = Buffer[Index+1];
+ HexStr[1] = Buffer[Index+2];
+ ResultBuffer[Offset] = (CHAR8) AsciiStrHexToUintn (HexStr);
+ Index += 3;
+ } else {
+ ResultBuffer[Offset] = Buffer[Index];
+ Index++;
+ }
+ Offset++;
+ }
+
+ *ResultLength = (UINT32) Offset;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function return the updated state accroding to the input state and next character of
+ the authority.
+
+ @param[in] Char Next character.
+ @param[in] State Current value of the parser state machine.
+ @param[in] IsRightBracket TRUE if there is an sign ']' in the authority component and
+ indicates the next part is ':' before Port.
+
+ @return Updated state value.
+**/
+HTTP_URL_PARSE_STATE
+NetHttpParseAuthorityChar (
+ IN CHAR8 Char,
+ IN HTTP_URL_PARSE_STATE State,
+ IN BOOLEAN *IsRightBracket
+ )
+{
+
+ //
+ // RFC 3986:
+ // The authority component is preceded by a double slash ("//") and is
+ // terminated by the next slash ("/"), question mark ("?"), or number
+ // sign ("#") character, or by the end of the URI.
+ //
+ if (Char == ' ' || Char == '\r' || Char == '\n') {
+ return UrlParserStateMax;
+ }
+
+ //
+ // authority = [ userinfo "@" ] host [ ":" port ]
+ //
+ switch (State) {
+ case UrlParserUserInfo:
+ if (Char == '@') {
+ return UrlParserHostStart;
+ }
+ break;
+
+ case UrlParserHost:
+ case UrlParserHostStart:
+ if (Char == '[') {
+ return UrlParserHostIpv6;
+ }
+
+ if (Char == ':') {
+ return UrlParserPortStart;
+ }
+
+ return UrlParserHost;
+
+ case UrlParserHostIpv6:
+ if (Char == ']') {
+ *IsRightBracket = TRUE;
+ }
+
+ if (Char == ':' && *IsRightBracket) {
+ return UrlParserPortStart;
+ }
+ return UrlParserHostIpv6;
+
+ case UrlParserPort:
+ case UrlParserPortStart:
+ return UrlParserPort;
+
+ default:
+ break;
+ }
+
+ return State;
+}
+
+/**
+ This function parse the authority component of the input URL and update the parser.
+
+ @param[in] Url The pointer to a HTTP URL string.
+ @param[in] FoundAt TRUE if there is an at sign ('@') in the authority component.
+ @param[in, out] UrlParser Pointer to the buffer of the parse result.
+
+ @retval EFI_SUCCESS Successfully parse the authority.
+ @retval Other Error happened.
+
+**/
+EFI_STATUS
+NetHttpParseAuthority (
+ IN CHAR8 *Url,
+ IN BOOLEAN FoundAt,
+ IN OUT HTTP_URL_PARSER *UrlParser
+ )
+{
+ CHAR8 *Char;
+ CHAR8 *Authority;
+ UINT32 Length;
+ HTTP_URL_PARSE_STATE State;
+ UINT32 Field;
+ UINT32 OldField;
+ BOOLEAN IsrightBracket;
+
+ ASSERT ((UrlParser->FieldBitMap & BIT (HTTP_URI_FIELD_AUTHORITY)) != 0);
+
+ //
+ // authority = [ userinfo "@" ] host [ ":" port ]
+ //
+ if (FoundAt) {
+ State = UrlParserUserInfo;
+ } else {
+ State = UrlParserHost;
+ }
+
+ IsrightBracket = FALSE;
+ Field = HTTP_URI_FIELD_MAX;
+ OldField = Field;
+ Authority = Url + UrlParser->FieldData[HTTP_URI_FIELD_AUTHORITY].Offset;
+ Length = UrlParser->FieldData[HTTP_URI_FIELD_AUTHORITY].Length;
+ for (Char = Authority; Char < Authority + Length; Char++) {
+ State = NetHttpParseAuthorityChar (*Char, State, &IsrightBracket);
+ switch (State) {
+ case UrlParserStateMax:
+ return EFI_INVALID_PARAMETER;
+
+ case UrlParserHostStart:
+ case UrlParserPortStart:
+ continue;
+
+ case UrlParserUserInfo:
+ Field = HTTP_URI_FIELD_USERINFO;
+ break;
+
+ case UrlParserHost:
+ Field = HTTP_URI_FIELD_HOST;
+ break;
+
+ case UrlParserHostIpv6:
+ Field = HTTP_URI_FIELD_HOST;
+ break;
+
+ case UrlParserPort:
+ Field = HTTP_URI_FIELD_PORT;
+ break;
+
+ default:
+ ASSERT (FALSE);
+ }
+
+ //
+ // Field not changed, count the length.
+ //
+ ASSERT (Field < HTTP_URI_FIELD_MAX);
+ if (Field == OldField) {
+ UrlParser->FieldData[Field].Length++;
+ continue;
+ }
+
+ //
+ // New field start
+ //
+ UrlParser->FieldBitMap |= BIT (Field);
+ UrlParser->FieldData[Field].Offset = (UINT32) (Char - Url);
+ UrlParser->FieldData[Field].Length = 1;
+ OldField = Field;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function return the updated state accroding to the input state and next character of a URL.
+
+ @param[in] Char Next character.
+ @param[in] State Current value of the parser state machine.
+
+ @return Updated state value.
+
+**/
+HTTP_URL_PARSE_STATE
+NetHttpParseUrlChar (
+ IN CHAR8 Char,
+ IN HTTP_URL_PARSE_STATE State
+ )
+{
+ if (Char == ' ' || Char == '\r' || Char == '\n') {
+ return UrlParserStateMax;
+ }
+
+ //
+ // http_URL = "http:" "//" host [ ":" port ] [ abs_path [ "?" query ]]
+ //
+ // Request-URI = "*" | absolute-URI | path-absolute | authority
+ //
+ // absolute-URI = scheme ":" hier-part [ "?" query ]
+ // path-absolute = "/" [ segment-nz *( "/" segment ) ]
+ // authority = [ userinfo "@" ] host [ ":" port ]
+ //
+ switch (State) {
+ case UrlParserUrlStart:
+ if (Char == '*' || Char == '/') {
+ return UrlParserPath;
+ }
+ return UrlParserScheme;
+
+ case UrlParserScheme:
+ if (Char == ':') {
+ return UrlParserSchemeColon;
+ }
+ break;
+
+ case UrlParserSchemeColon:
+ if (Char == '/') {
+ return UrlParserSchemeColonSlash;
+ }
+ break;
+
+ case UrlParserSchemeColonSlash:
+ if (Char == '/') {
+ return UrlParserSchemeColonSlashSlash;
+ }
+ break;
+
+ case UrlParserAtInAuthority:
+ if (Char == '@') {
+ return UrlParserStateMax;
+ }
+
+ case UrlParserAuthority:
+ case UrlParserSchemeColonSlashSlash:
+ if (Char == '@') {
+ return UrlParserAtInAuthority;
+ }
+ if (Char == '/') {
+ return UrlParserPath;
+ }
+ if (Char == '?') {
+ return UrlParserQueryStart;
+ }
+ if (Char == '#') {
+ return UrlParserFragmentStart;
+ }
+ return UrlParserAuthority;
+
+ case UrlParserPath:
+ if (Char == '?') {
+ return UrlParserQueryStart;
+ }
+ if (Char == '#') {
+ return UrlParserFragmentStart;
+ }
+ break;
+
+ case UrlParserQuery:
+ case UrlParserQueryStart:
+ if (Char == '#') {
+ return UrlParserFragmentStart;
+ }
+ return UrlParserQuery;
+
+ case UrlParserFragmentStart:
+ return UrlParserFragment;
+
+ default:
+ break;
+ }
+
+ return State;
+}
+/**
+ Create a URL parser for the input URL string.
+
+ This function will parse and dereference the input HTTP URL into it components. The original
+ content of the URL won't be modified and the result will be returned in UrlParser, which can
+ be used in other functions like NetHttpUrlGetHostName().
+
+ @param[in] Url The pointer to a HTTP URL string.
+ @param[in] Length Length of Url in bytes.
+ @param[in] IsConnectMethod Whether the Url is used in HTTP CONNECT method or not.
+ @param[out] UrlParser Pointer to the returned buffer to store the parse result.
+
+ @retval EFI_SUCCESS Successfully dereferenced the HTTP URL.
+ @retval EFI_INVALID_PARAMETER UrlParser is NULL or Url is not a valid HTTP URL.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources.
+
+**/
+EFI_STATUS
+EFIAPI
+HttpParseUrl (
+ IN CHAR8 *Url,
+ IN UINT32 Length,
+ IN BOOLEAN IsConnectMethod,
+ OUT VOID **UrlParser
+ )
+{
+ HTTP_URL_PARSE_STATE State;
+ CHAR8 *Char;
+ UINT32 Field;
+ UINT32 OldField;
+ BOOLEAN FoundAt;
+ EFI_STATUS Status;
+ HTTP_URL_PARSER *Parser;
+
+ if (Url == NULL || Length == 0 || UrlParser == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Parser = AllocateZeroPool (sizeof (HTTP_URL_PARSER));
+ if (Parser == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (IsConnectMethod) {
+ //
+ // According to RFC 2616, the authority form is only used by the CONNECT method.
+ //
+ State = UrlParserAuthority;
+ } else {
+ State = UrlParserUrlStart;
+ }
+
+ Field = HTTP_URI_FIELD_MAX;
+ OldField = Field;
+ FoundAt = FALSE;
+ for (Char = Url; Char < Url + Length; Char++) {
+ //
+ // Update state machine accoring to next char.
+ //
+ State = NetHttpParseUrlChar (*Char, State);
+
+ switch (State) {
+ case UrlParserStateMax:
+ return EFI_INVALID_PARAMETER;
+
+ case UrlParserSchemeColon:
+ case UrlParserSchemeColonSlash:
+ case UrlParserSchemeColonSlashSlash:
+ case UrlParserQueryStart:
+ case UrlParserFragmentStart:
+ //
+ // Skip all the delimiting char: "://" "?" "@"
+ //
+ continue;
+
+ case UrlParserScheme:
+ Field = HTTP_URI_FIELD_SCHEME;
+ break;
+
+ case UrlParserAtInAuthority:
+ FoundAt = TRUE;
+ case UrlParserAuthority:
+ Field = HTTP_URI_FIELD_AUTHORITY;
+ break;
+
+ case UrlParserPath:
+ Field = HTTP_URI_FIELD_PATH;
+ break;
+
+ case UrlParserQuery:
+ Field = HTTP_URI_FIELD_QUERY;
+ break;
+
+ case UrlParserFragment:
+ Field = HTTP_URI_FIELD_FRAGMENT;
+ break;
+
+ default:
+ ASSERT (FALSE);
+ }
+
+ //
+ // Field not changed, count the length.
+ //
+ ASSERT (Field < HTTP_URI_FIELD_MAX);
+ if (Field == OldField) {
+ Parser->FieldData[Field].Length++;
+ continue;
+ }
+
+ //
+ // New field start
+ //
+ Parser->FieldBitMap |= BIT (Field);
+ Parser->FieldData[Field].Offset = (UINT32) (Char - Url);
+ Parser->FieldData[Field].Length = 1;
+ OldField = Field;
+ }
+
+ //
+ // If has authority component, continue to parse the username, host and port.
+ //
+ if ((Parser->FieldBitMap & BIT (HTTP_URI_FIELD_AUTHORITY)) != 0) {
+ Status = NetHttpParseAuthority (Url, FoundAt, Parser);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ *UrlParser = Parser;
+ return EFI_SUCCESS;
+}
+
+/**
+ Get the Hostname from a HTTP URL.
+
+ This function will return the HostName according to the Url and previous parse result ,and
+ it is the caller's responsibility to free the buffer returned in *HostName.
+
+ @param[in] Url The pointer to a HTTP URL string.
+ @param[in] UrlParser URL Parse result returned by NetHttpParseUrl().
+ @param[out] HostName Pointer to a buffer to store the HostName.
+
+ @retval EFI_SUCCESS Successfully get the required component.
+ @retval EFI_INVALID_PARAMETER Uri is NULL or HostName is NULL or UrlParser is invalid.
+ @retval EFI_NOT_FOUND No hostName component in the URL.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources.
+
+**/
+EFI_STATUS
+EFIAPI
+HttpUrlGetHostName (
+ IN CHAR8 *Url,
+ IN VOID *UrlParser,
+ OUT CHAR8 **HostName
+ )
+{
+ CHAR8 *Name;
+ EFI_STATUS Status;
+ UINT32 ResultLength;
+ HTTP_URL_PARSER *Parser;
+
+ if (Url == NULL || UrlParser == NULL || HostName == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Parser = (HTTP_URL_PARSER*) UrlParser;
+
+ if ((Parser->FieldBitMap & BIT (HTTP_URI_FIELD_HOST)) == 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ Name = AllocatePool (Parser->FieldData[HTTP_URI_FIELD_HOST].Length + 1);
+ if (Name == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = UriPercentDecode (
+ Url + Parser->FieldData[HTTP_URI_FIELD_HOST].Offset,
+ Parser->FieldData[HTTP_URI_FIELD_HOST].Length,
+ Name,
+ &ResultLength
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Name[ResultLength] = '\0';
+ *HostName = Name;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Get the IPv4 address from a HTTP URL.
+
+ This function will return the IPv4 address according to the Url and previous parse result.
+
+ @param[in] Url The pointer to a HTTP URL string.
+ @param[in] UrlParser URL Parse result returned by NetHttpParseUrl().
+ @param[out] Ip4Address Pointer to a buffer to store the IP address.
+
+ @retval EFI_SUCCESS Successfully get the required component.
+ @retval EFI_INVALID_PARAMETER Uri is NULL or Ip4Address is NULL or UrlParser is invalid.
+ @retval EFI_NOT_FOUND No IPv4 address component in the URL.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources.
+
+**/
+EFI_STATUS
+EFIAPI
+HttpUrlGetIp4 (
+ IN CHAR8 *Url,
+ IN VOID *UrlParser,
+ OUT EFI_IPv4_ADDRESS *Ip4Address
+ )
+{
+ CHAR8 *Ip4String;
+ EFI_STATUS Status;
+ UINT32 ResultLength;
+ HTTP_URL_PARSER *Parser;
+
+ if (Url == NULL || UrlParser == NULL || Ip4Address == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Parser = (HTTP_URL_PARSER*) UrlParser;
+
+ if ((Parser->FieldBitMap & BIT (HTTP_URI_FIELD_HOST)) == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Ip4String = AllocatePool (Parser->FieldData[HTTP_URI_FIELD_HOST].Length + 1);
+ if (Ip4String == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = UriPercentDecode (
+ Url + Parser->FieldData[HTTP_URI_FIELD_HOST].Offset,
+ Parser->FieldData[HTTP_URI_FIELD_HOST].Length,
+ Ip4String,
+ &ResultLength
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Ip4String[ResultLength] = '\0';
+ Status = NetLibAsciiStrToIp4 (Ip4String, Ip4Address);
+ FreePool (Ip4String);
+
+ return Status;
+}
+
+/**
+ Get the IPv6 address from a HTTP URL.
+
+ This function will return the IPv6 address according to the Url and previous parse result.
+
+ @param[in] Url The pointer to a HTTP URL string.
+ @param[in] UrlParser URL Parse result returned by NetHttpParseUrl().
+ @param[out] Ip6Address Pointer to a buffer to store the IP address.
+
+ @retval EFI_SUCCESS Successfully get the required component.
+ @retval EFI_INVALID_PARAMETER Uri is NULL or Ip6Address is NULL or UrlParser is invalid.
+ @retval EFI_NOT_FOUND No IPv6 address component in the URL.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources.
+
+**/
+EFI_STATUS
+EFIAPI
+HttpUrlGetIp6 (
+ IN CHAR8 *Url,
+ IN VOID *UrlParser,
+ OUT EFI_IPv6_ADDRESS *Ip6Address
+ )
+{
+ CHAR8 *Ip6String;
+ CHAR8 *Ptr;
+ UINT32 Length;
+ EFI_STATUS Status;
+ UINT32 ResultLength;
+ HTTP_URL_PARSER *Parser;
+
+ if (Url == NULL || UrlParser == NULL || Ip6Address == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Parser = (HTTP_URL_PARSER*) UrlParser;
+
+ if ((Parser->FieldBitMap & BIT (HTTP_URI_FIELD_HOST)) == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // IP-literal = "[" ( IPv6address / IPvFuture ) "]"
+ //
+ Length = Parser->FieldData[HTTP_URI_FIELD_HOST].Length;
+ if (Length < 2) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Ptr = Url + Parser->FieldData[HTTP_URI_FIELD_HOST].Offset;
+ if ((Ptr[0] != '[') || (Ptr[Length - 1] != ']')) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Ip6String = AllocatePool (Length);
+ if (Ip6String == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = UriPercentDecode (
+ Ptr + 1,
+ Length - 2,
+ Ip6String,
+ &ResultLength
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Ip6String[ResultLength] = '\0';
+ Status = NetLibAsciiStrToIp6 (Ip6String, Ip6Address);
+ FreePool (Ip6String);
+
+ return Status;
+}
+
+/**
+ Get the port number from a HTTP URL.
+
+ This function will return the port number according to the Url and previous parse result.
+
+ @param[in] Url The pointer to a HTTP URL string.
+ @param[in] UrlParser URL Parse result returned by NetHttpParseUrl().
+ @param[out] Port Pointer to a buffer to store the port number.
+
+ @retval EFI_SUCCESS Successfully get the required component.
+ @retval EFI_INVALID_PARAMETER Uri is NULL or Port is NULL or UrlParser is invalid.
+ @retval EFI_NOT_FOUND No port number in the URL.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources.
+
+**/
+EFI_STATUS
+EFIAPI
+HttpUrlGetPort (
+ IN CHAR8 *Url,
+ IN VOID *UrlParser,
+ OUT UINT16 *Port
+ )
+{
+ CHAR8 *PortString;
+ EFI_STATUS Status;
+ UINT32 ResultLength;
+ HTTP_URL_PARSER *Parser;
+
+ if (Url == NULL || UrlParser == NULL || Port == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Parser = (HTTP_URL_PARSER*) UrlParser;
+
+ if ((Parser->FieldBitMap & BIT (HTTP_URI_FIELD_PORT)) == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ PortString = AllocatePool (Parser->FieldData[HTTP_URI_FIELD_PORT].Length + 1);
+ if (PortString == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = UriPercentDecode (
+ Url + Parser->FieldData[HTTP_URI_FIELD_PORT].Offset,
+ Parser->FieldData[HTTP_URI_FIELD_PORT].Length,
+ PortString,
+ &ResultLength
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ PortString[ResultLength] = '\0';
+ *Port = (UINT16) AsciiStrDecimalToUintn (Url + Parser->FieldData[HTTP_URI_FIELD_PORT].Offset);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Release the resource of the URL parser.
+
+ @param[in] UrlParser Pointer to the parser.
+
+**/
+VOID
+EFIAPI
+HttpUrlFreeParser (
+ IN VOID *UrlParser
+ )
+{
+ FreePool (UrlParser);
+}
+
+/**
+ Find a specified header field according to the field name.
+
+ @param[in] HeaderCount Number of HTTP header structures in Headers list.
+ @param[in] Headers Array containing list of HTTP headers.
+ @param[in] FieldName Null terminated string which describes a field name.
+
+ @return Pointer to the found header or NULL.
+
+**/
+EFI_HTTP_HEADER *
+HttpIoFindHeader (
+ IN UINTN HeaderCount,
+ IN EFI_HTTP_HEADER *Headers,
+ IN CHAR8 *FieldName
+ )
+{
+ UINTN Index;
+
+ if (HeaderCount == 0 || Headers == NULL || FieldName == NULL) {
+ return NULL;
+ }
+
+ for (Index = 0; Index < HeaderCount; Index++){
+ //
+ // Field names are case-insensitive (RFC 2616).
+ //
+ if (AsciiStriCmp (Headers[Index].FieldName, FieldName) == 0) {
+ return &Headers[Index];
+ }
+ }
+ return NULL;
+}
+
+typedef enum {
+ BodyParserBodyStart,
+ BodyParserBodyIdentity,
+ BodyParserChunkSizeStart,
+ BodyParserChunkSize,
+ BodyParserChunkSizeEndCR,
+ BodyParserChunkExtStart,
+ BodyParserChunkDataStart,
+ BodyParserChunkDataEnd,
+ BodyParserChunkDataEndCR,
+ BodyParserTrailer,
+ BodyParserLastCRLF,
+ BodyParserLastCRLFEnd,
+ BodyParserComplete,
+ BodyParserStateMax
+} HTTP_BODY_PARSE_STATE;
+
+typedef struct {
+ BOOLEAN IgnoreBody; // "MUST NOT" include a message-body
+ BOOLEAN IsChunked; // "chunked" transfer-coding.
+ BOOLEAN ContentLengthIsValid;
+ UINTN ContentLength; // Entity length (not the message-body length), invalid until ContentLengthIsValid is TRUE
+
+ HTTP_BODY_PARSER_CALLBACK Callback;
+ VOID *Context;
+ UINTN ParsedBodyLength;
+ HTTP_BODY_PARSE_STATE State;
+ UINTN CurrentChunkSize;
+ UINTN CurrentChunkParsedSize;
+} HTTP_BODY_PARSER;
+
+/**
+
+ Convert an Ascii char to its uppercase.
+
+ @param[in] Char Ascii character.
+
+ @return Uppercase value of the input Char.
+
+**/
+CHAR8
+HttpIoCharToUpper (
+ IN CHAR8 Char
+ )
+{
+ if (Char >= 'a' && Char <= 'z') {
+ return Char - ('a' - 'A');
+ }
+
+ return Char;
+}
+
+/**
+ Convert an hexadecimal char to a value of type UINTN.
+
+ @param[in] Char Ascii character.
+
+ @return Value translated from Char.
+
+**/
+UINTN
+HttpIoHexCharToUintn (
+ IN CHAR8 Char
+ )
+{
+ if (Char >= '0' && Char <= '9') {
+ return Char - '0';
+ }
+
+ return (10 + HttpIoCharToUpper (Char) - 'A');
+}
+
+/**
+ Get the value of the content length if there is a "Content-Length" header.
+
+ @param[in] HeaderCount Number of HTTP header structures in Headers.
+ @param[in] Headers Array containing list of HTTP headers.
+ @param[out] ContentLength Pointer to save the value of the content length.
+
+ @retval EFI_SUCCESS Successfully get the content length.
+ @retval EFI_NOT_FOUND No "Content-Length" header in the Headers.
+
+**/
+EFI_STATUS
+HttpIoParseContentLengthHeader (
+ IN UINTN HeaderCount,
+ IN EFI_HTTP_HEADER *Headers,
+ OUT UINTN *ContentLength
+ )
+{
+ EFI_HTTP_HEADER *Header;
+
+ Header = HttpIoFindHeader (HeaderCount, Headers, "Content-Length");
+ if (Header == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ *ContentLength = AsciiStrDecimalToUintn (Header->FieldValue);
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Check whether the HTTP message is using the "chunked" transfer-coding.
+
+ @param[in] HeaderCount Number of HTTP header structures in Headers.
+ @param[in] Headers Array containing list of HTTP headers.
+
+ @return The message is "chunked" transfer-coding (TRUE) or not (FALSE).
+
+**/
+BOOLEAN
+HttpIoIsChunked (
+ IN UINTN HeaderCount,
+ IN EFI_HTTP_HEADER *Headers
+ )
+{
+ EFI_HTTP_HEADER *Header;
+
+
+ Header = HttpIoFindHeader (HeaderCount, Headers, "Transfer-Encoding");
+ if (Header == NULL) {
+ return FALSE;
+ }
+
+ if (AsciiStriCmp (Header->FieldValue, "identity") != 0) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Check whether the HTTP message should have a message-body.
+
+ @param[in] Method The HTTP method (e.g. GET, POST) for this HTTP message.
+ @param[in] StatusCode Response status code returned by the remote host.
+
+ @return The message should have a message-body (FALSE) or not (TRUE).
+
+**/
+BOOLEAN
+HttpIoNoMessageBody (
+ IN EFI_HTTP_METHOD Method,
+ IN EFI_HTTP_STATUS_CODE StatusCode
+ )
+{
+ //
+ // RFC 2616:
+ // All responses to the HEAD request method
+ // MUST NOT include a message-body, even though the presence of entity-
+ // header fields might lead one to believe they do. All 1xx
+ // (informational), 204 (no content), and 304 (not modified) responses
+ // MUST NOT include a message-body. All other responses do include a
+ // message-body, although it MAY be of zero length.
+ //
+ if (Method == HttpMethodHead) {
+ return TRUE;
+ }
+
+ if ((StatusCode == HTTP_STATUS_100_CONTINUE) ||
+ (StatusCode == HTTP_STATUS_101_SWITCHING_PROTOCOLS) ||
+ (StatusCode == HTTP_STATUS_204_NO_CONTENT) ||
+ (StatusCode == HTTP_STATUS_304_NOT_MODIFIED))
+ {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Initialize a HTTP message-body parser.
+
+ This function will create and initialize a HTTP message parser according to caller provided HTTP message
+ header information. It is the caller's responsibility to free the buffer returned in *UrlParser by HttpFreeMsgParser().
+
+ @param[in] Method The HTTP method (e.g. GET, POST) for this HTTP message.
+ @param[in] StatusCode Response status code returned by the remote host.
+ @param[in] HeaderCount Number of HTTP header structures in Headers.
+ @param[in] Headers Array containing list of HTTP headers.
+ @param[in] Callback Callback function that is invoked when parsing the HTTP message-body,
+ set to NULL to ignore all events.
+ @param[in] Context Pointer to the context that will be passed to Callback.
+ @param[out] MsgParser Pointer to the returned buffer to store the message parser.
+
+ @retval EFI_SUCCESS Successfully initialized the parser.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources.
+ @retval EFI_INVALID_PARAMETER MsgParser is NULL or HeaderCount is not NULL but Headers is NULL.
+ @retval Others Failed to initialize the parser.
+
+**/
+EFI_STATUS
+EFIAPI
+HttpInitMsgParser (
+ IN EFI_HTTP_METHOD Method,
+ IN EFI_HTTP_STATUS_CODE StatusCode,
+ IN UINTN HeaderCount,
+ IN EFI_HTTP_HEADER *Headers,
+ IN HTTP_BODY_PARSER_CALLBACK Callback,
+ IN VOID *Context,
+ OUT VOID **MsgParser
+ )
+{
+ EFI_STATUS Status;
+ HTTP_BODY_PARSER *Parser;
+
+ if (HeaderCount != 0 && Headers == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (MsgParser == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Parser = AllocateZeroPool (sizeof (HTTP_BODY_PARSER));
+ if (Parser == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Parser->State = BodyParserBodyStart;
+
+ //
+ // Determine the message length accroding to RFC 2616.
+ // 1. Check whether the message "MUST NOT" have a message-body.
+ //
+ Parser->IgnoreBody = HttpIoNoMessageBody (Method, StatusCode);
+ //
+ // 2. Check whether the message using "chunked" transfer-coding.
+ //
+ Parser->IsChunked = HttpIoIsChunked (HeaderCount, Headers);
+ //
+ // 3. Check whether the message has a Content-Length header field.
+ //
+ Status = HttpIoParseContentLengthHeader (HeaderCount, Headers, &Parser->ContentLength);
+ if (!EFI_ERROR (Status)) {
+ Parser->ContentLengthIsValid = TRUE;
+ }
+ //
+ // 4. Range header is not supported now, so we won't meet media type "multipart/byteranges".
+ // 5. By server closing the connection
+ //
+
+ //
+ // Set state to skip body parser if the message shouldn't have a message body.
+ //
+ if (Parser->IgnoreBody) {
+ Parser->State = BodyParserComplete;
+ } else {
+ Parser->Callback = Callback;
+ Parser->Context = Context;
+ }
+
+ *MsgParser = Parser;
+ return EFI_SUCCESS;
+}
+
+/**
+ Parse message body.
+
+ Parse BodyLength of message-body. This function can be called repeatedly to parse the message-body partially.
+
+ @param[in, out] MsgParser Pointer to the message parser.
+ @param[in] BodyLength Length in bytes of the Body.
+ @param[in] Body Pointer to the buffer of the message-body to be parsed.
+
+ @retval EFI_SUCCESS Successfully parse the message-body.
+ @retval EFI_INVALID_PARAMETER MsgParser is NULL or Body is NULL or BodyLength is 0.
+ @retval Others Operation aborted.
+
+**/
+EFI_STATUS
+EFIAPI
+HttpParseMessageBody (
+ IN OUT VOID *MsgParser,
+ IN UINTN BodyLength,
+ IN CHAR8 *Body
+ )
+{
+ CHAR8 *Char;
+ UINTN RemainderLengthInThis;
+ UINTN LengthForCallback;
+ EFI_STATUS Status;
+ HTTP_BODY_PARSER *Parser;
+
+ if (BodyLength == 0 || Body == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (MsgParser == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Parser = (HTTP_BODY_PARSER*) MsgParser;
+
+ if (Parser->IgnoreBody) {
+ Parser->State = BodyParserComplete;
+ if (Parser->Callback != NULL) {
+ Status = Parser->Callback (
+ BodyParseEventOnComplete,
+ Body,
+ 0,
+ Parser->Context
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+ return EFI_SUCCESS;
+ }
+
+ if (Parser->State == BodyParserBodyStart) {
+ Parser->ParsedBodyLength = 0;
+ if (Parser->IsChunked) {
+ Parser->State = BodyParserChunkSizeStart;
+ } else {
+ Parser->State = BodyParserBodyIdentity;
+ }
+ }
+
+ //
+ // The message body might be truncated in anywhere, so we need to parse is byte-by-byte.
+ //
+ for (Char = Body; Char < Body + BodyLength; ) {
+
+ switch (Parser->State) {
+ case BodyParserStateMax:
+ return EFI_ABORTED;
+
+ case BodyParserBodyIdentity:
+ //
+ // Identity transfer-coding, just notify user to save the body data.
+ //
+ if (Parser->Callback != NULL) {
+ Status = Parser->Callback (
+ BodyParseEventOnData,
+ Char,
+ MIN (BodyLength, Parser->ContentLength - Parser->ParsedBodyLength),
+ Parser->Context
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+ Char += MIN (BodyLength, Parser->ContentLength - Parser->ParsedBodyLength);
+ Parser->ParsedBodyLength += MIN (BodyLength, Parser->ContentLength - Parser->ParsedBodyLength);
+ if (Parser->ParsedBodyLength == Parser->ContentLength) {
+ Parser->State = BodyParserComplete;
+ if (Parser->Callback != NULL) {
+ Status = Parser->Callback (
+ BodyParseEventOnComplete,
+ Char,
+ 0,
+ Parser->Context
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+ }
+ break;
+
+ case BodyParserChunkSizeStart:
+ //
+ // First byte of chunk-size, the chunk-size might be truncated.
+ //
+ Parser->CurrentChunkSize = 0;
+ Parser->State = BodyParserChunkSize;
+ case BodyParserChunkSize:
+ if (!NET_IS_HEX_CHAR (*Char)) {
+ if (*Char == ';') {
+ Parser->State = BodyParserChunkExtStart;
+ Char++;
+ } else if (*Char == '\r') {
+ Parser->State = BodyParserChunkSizeEndCR;
+ Char++;
+ } else {
+ Parser->State = BodyParserStateMax;
+ }
+ break;
+ }
+
+ if (Parser->CurrentChunkSize > (((~((UINTN) 0)) - 16) / 16)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ Parser->CurrentChunkSize = Parser->CurrentChunkSize * 16 + HttpIoHexCharToUintn (*Char);
+ Char++;
+ break;
+
+ case BodyParserChunkExtStart:
+ //
+ // Ignore all the chunk extensions.
+ //
+ if (*Char == '\r') {
+ Parser->State = BodyParserChunkSizeEndCR;
+ }
+ Char++;
+ break;
+
+ case BodyParserChunkSizeEndCR:
+ if (*Char != '\n') {
+ Parser->State = BodyParserStateMax;
+ break;
+ }
+ Char++;
+ if (Parser->CurrentChunkSize == 0) {
+ //
+ // The last chunk has been parsed and now assumed the state
+ // of HttpBodyParse is ParserLastCRLF. So it need to decide
+ // whether the rest message is trailer or last CRLF in the next round.
+ //
+ Parser->ContentLengthIsValid = TRUE;
+ Parser->State = BodyParserLastCRLF;
+ break;
+ }
+ Parser->State = BodyParserChunkDataStart;
+ Parser->CurrentChunkParsedSize = 0;
+ break;
+
+ case BodyParserLastCRLF:
+ //
+ // Judge the byte is belong to the Last CRLF or trailer, and then
+ // configure the state of HttpBodyParse to corresponding state.
+ //
+ if (*Char == '\r') {
+ Char++;
+ Parser->State = BodyParserLastCRLFEnd;
+ break;
+ } else {
+ Parser->State = BodyParserTrailer;
+ break;
+ }
+
+ case BodyParserLastCRLFEnd:
+ if (*Char == '\n') {
+ Parser->State = BodyParserComplete;
+ Char++;
+ if (Parser->Callback != NULL) {
+ Status = Parser->Callback (
+ BodyParseEventOnComplete,
+ Char,
+ 0,
+ Parser->Context
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+ break;
+ } else {
+ Parser->State = BodyParserStateMax;
+ break;
+ }
+
+ case BodyParserTrailer:
+ if (*Char == '\r') {
+ Parser->State = BodyParserChunkSizeEndCR;
+ }
+ Char++;
+ break;
+
+ case BodyParserChunkDataStart:
+ //
+ // First byte of chunk-data, the chunk data also might be truncated.
+ //
+ RemainderLengthInThis = BodyLength - (Char - Body);
+ LengthForCallback = MIN (Parser->CurrentChunkSize - Parser->CurrentChunkParsedSize, RemainderLengthInThis);
+ if (Parser->Callback != NULL) {
+ Status = Parser->Callback (
+ BodyParseEventOnData,
+ Char,
+ LengthForCallback,
+ Parser->Context
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+ Char += LengthForCallback;
+ Parser->ContentLength += LengthForCallback;
+ Parser->CurrentChunkParsedSize += LengthForCallback;
+ if (Parser->CurrentChunkParsedSize == Parser->CurrentChunkSize) {
+ Parser->State = BodyParserChunkDataEnd;
+ }
+ break;
+
+ case BodyParserChunkDataEnd:
+ if (*Char == '\r') {
+ Parser->State = BodyParserChunkDataEndCR;
+ } else {
+ Parser->State = BodyParserStateMax;
+ }
+ Char++;
+ break;
+
+ case BodyParserChunkDataEndCR:
+ if (*Char != '\n') {
+ Parser->State = BodyParserStateMax;
+ break;
+ }
+ Char++;
+ Parser->State = BodyParserChunkSizeStart;
+ break;
+
+ default:
+ break;
+ }
+
+ }
+
+ if (Parser->State == BodyParserStateMax) {
+ return EFI_ABORTED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Check whether the message-body is complete or not.
+
+ @param[in] MsgParser Pointer to the message parser.
+
+ @retval TRUE Message-body is complete.
+ @retval FALSE Message-body is not complete.
+
+**/
+BOOLEAN
+EFIAPI
+HttpIsMessageComplete (
+ IN VOID *MsgParser
+ )
+{
+ HTTP_BODY_PARSER *Parser;
+
+ Parser = (HTTP_BODY_PARSER*) MsgParser;
+
+ if (Parser->State == BodyParserComplete) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ Get the content length of the entity.
+
+ Note that in trunk transfer, the entity length is not valid until the whole message body is received.
+
+ @param[in] MsgParser Pointer to the message parser.
+ @param[out] ContentLength Pointer to store the length of the entity.
+
+ @retval EFI_SUCCESS Successfully to get the entity length.
+ @retval EFI_NOT_READY Entity length is not valid yet.
+ @retval EFI_INVALID_PARAMETER MsgParser is NULL or ContentLength is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+HttpGetEntityLength (
+ IN VOID *MsgParser,
+ OUT UINTN *ContentLength
+ )
+{
+ HTTP_BODY_PARSER *Parser;
+
+ if (MsgParser == NULL || ContentLength == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Parser = (HTTP_BODY_PARSER*) MsgParser;
+
+ if (!Parser->ContentLengthIsValid) {
+ return EFI_NOT_READY;
+ }
+
+ *ContentLength = Parser->ContentLength;
+ return EFI_SUCCESS;
+}
+
+/**
+ Release the resource of the message parser.
+
+ @param[in] MsgParser Pointer to the message parser.
+
+**/
+VOID
+EFIAPI
+HttpFreeMsgParser (
+ IN VOID *MsgParser
+ )
+{
+ FreePool (MsgParser);
+}
diff --git a/Core/MdeModulePkg/Library/DxeHttpLib/DxeHttpLib.inf b/Core/MdeModulePkg/Library/DxeHttpLib/DxeHttpLib.inf
new file mode 100644
index 0000000000..e26f6fa691
--- /dev/null
+++ b/Core/MdeModulePkg/Library/DxeHttpLib/DxeHttpLib.inf
@@ -0,0 +1,42 @@
+## @file
+# It provides the helper routines to parse the HTTP message byte stream.
+#
+# Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxeHttpLib
+ MODULE_UNI_FILE = DxeHttpLib.uni
+ FILE_GUID = ABBAB4CD-EA88-45b9-8234-C8A7450531FC
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = HttpLib|DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SAL_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ DxeHttpLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ DebugLib
+ UefiBootServicesTableLib
+ MemoryAllocationLib
diff --git a/Core/MdeModulePkg/Library/DxeHttpLib/DxeHttpLib.uni b/Core/MdeModulePkg/Library/DxeHttpLib/DxeHttpLib.uni
new file mode 100644
index 0000000000..806c443929
--- /dev/null
+++ b/Core/MdeModulePkg/Library/DxeHttpLib/DxeHttpLib.uni
Binary files differ
diff --git a/Core/MdeModulePkg/Library/DxeIpIoLib/DxeIpIoLib.c b/Core/MdeModulePkg/Library/DxeIpIoLib/DxeIpIoLib.c
new file mode 100644
index 0000000000..cc93c2b89c
--- /dev/null
+++ b/Core/MdeModulePkg/Library/DxeIpIoLib/DxeIpIoLib.c
@@ -0,0 +1,2150 @@
+/** @file
+ IpIo Library.
+
+(C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>
+Copyright (c) 2005 - 2009, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+**/
+
+#include <Uefi.h>
+
+#include <Protocol/Udp4.h>
+
+#include <Library/IpIoLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DpcLib.h>
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED LIST_ENTRY mActiveIpIoList = {
+ &mActiveIpIoList,
+ &mActiveIpIoList
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_IP4_CONFIG_DATA mIp4IoDefaultIpConfigData = {
+ EFI_IP_PROTO_UDP,
+ FALSE,
+ TRUE,
+ FALSE,
+ FALSE,
+ FALSE,
+ {{0, 0, 0, 0}},
+ {{0, 0, 0, 0}},
+ 0,
+ 255,
+ FALSE,
+ FALSE,
+ 0,
+ 0
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_IP6_CONFIG_DATA mIp6IoDefaultIpConfigData = {
+ EFI_IP_PROTO_UDP,
+ FALSE,
+ TRUE,
+ FALSE,
+ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
+ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
+ 0,
+ 255,
+ 0,
+ 0,
+ 0
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED ICMP_ERROR_INFO mIcmpErrMap[10] = {
+ {FALSE, TRUE }, // ICMP_ERR_UNREACH_NET
+ {FALSE, TRUE }, // ICMP_ERR_UNREACH_HOST
+ {TRUE, TRUE }, // ICMP_ERR_UNREACH_PROTOCOL
+ {TRUE, TRUE }, // ICMP_ERR_UNREACH_PORT
+ {TRUE, TRUE }, // ICMP_ERR_MSGSIZE
+ {FALSE, TRUE }, // ICMP_ERR_UNREACH_SRCFAIL
+ {FALSE, TRUE }, // ICMP_ERR_TIMXCEED_INTRANS
+ {FALSE, TRUE }, // ICMP_ERR_TIMEXCEED_REASS
+ {FALSE, FALSE}, // ICMP_ERR_QUENCH
+ {FALSE, TRUE } // ICMP_ERR_PARAMPROB
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED ICMP_ERROR_INFO mIcmp6ErrMap[10] = {
+ {FALSE, TRUE}, // ICMP6_ERR_UNREACH_NET
+ {FALSE, TRUE}, // ICMP6_ERR_UNREACH_HOST
+ {TRUE, TRUE}, // ICMP6_ERR_UNREACH_PROTOCOL
+ {TRUE, TRUE}, // ICMP6_ERR_UNREACH_PORT
+ {TRUE, TRUE}, // ICMP6_ERR_PACKAGE_TOOBIG
+ {FALSE, TRUE}, // ICMP6_ERR_TIMXCEED_HOPLIMIT
+ {FALSE, TRUE}, // ICMP6_ERR_TIMXCEED_REASS
+ {FALSE, TRUE}, // ICMP6_ERR_PARAMPROB_HEADER
+ {FALSE, TRUE}, // ICMP6_ERR_PARAMPROB_NEXHEADER
+ {FALSE, TRUE} // ICMP6_ERR_PARAMPROB_IPV6OPTION
+};
+
+
+/**
+ Notify function for IP transmit token.
+
+ @param[in] Context The context passed in by the event notifier.
+
+**/
+VOID
+EFIAPI
+IpIoTransmitHandlerDpc (
+ IN VOID *Context
+ );
+
+
+/**
+ Notify function for IP transmit token.
+
+ @param[in] Event The event signaled.
+ @param[in] Context The context passed in by the event notifier.
+
+**/
+VOID
+EFIAPI
+IpIoTransmitHandler (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+
+/**
+ This function create an IP child ,open the IP protocol, and return the opened
+ IP protocol as Interface.
+
+ @param[in] ControllerHandle The controller handle.
+ @param[in] ImageHandle The image handle.
+ @param[in] ChildHandle Pointer to the buffer to save the IP child handle.
+ @param[in] IpVersion The version of the IP protocol to use, either
+ IPv4 or IPv6.
+ @param[out] Interface Pointer used to get the IP protocol interface.
+
+ @retval EFI_SUCCESS The IP child is created and the IP protocol
+ interface is retrieved.
+ @retval Others The required operation failed.
+
+**/
+EFI_STATUS
+IpIoCreateIpChildOpenProtocol (
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_HANDLE *ChildHandle,
+ IN UINT8 IpVersion,
+ OUT VOID **Interface
+ )
+{
+ EFI_STATUS Status;
+ EFI_GUID *ServiceBindingGuid;
+ EFI_GUID *IpProtocolGuid;
+
+ if (IpVersion == IP_VERSION_4) {
+ ServiceBindingGuid = &gEfiIp4ServiceBindingProtocolGuid;
+ IpProtocolGuid = &gEfiIp4ProtocolGuid;
+ } else if (IpVersion == IP_VERSION_6){
+ ServiceBindingGuid = &gEfiIp6ServiceBindingProtocolGuid;
+ IpProtocolGuid = &gEfiIp6ProtocolGuid;
+ } else {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Create an IP child.
+ //
+ Status = NetLibCreateServiceChild (
+ ControllerHandle,
+ ImageHandle,
+ ServiceBindingGuid,
+ ChildHandle
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Open the IP protocol installed on the *ChildHandle.
+ //
+ Status = gBS->OpenProtocol (
+ *ChildHandle,
+ IpProtocolGuid,
+ Interface,
+ ImageHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // On failure, destroy the IP child.
+ //
+ NetLibDestroyServiceChild (
+ ControllerHandle,
+ ImageHandle,
+ ServiceBindingGuid,
+ *ChildHandle
+ );
+ }
+
+ return Status;
+}
+
+
+/**
+ This function close the previously openned IP protocol and destroy the IP child.
+
+ @param[in] ControllerHandle The controller handle.
+ @param[in] ImageHandle The image handle.
+ @param[in] ChildHandle The child handle of the IP child.
+ @param[in] IpVersion The version of the IP protocol to use, either
+ IPv4 or IPv6.
+
+ @retval EFI_SUCCESS The IP protocol is closed and the relevant IP child
+ is destroyed.
+ @retval Others The required operation failed.
+
+**/
+EFI_STATUS
+IpIoCloseProtocolDestroyIpChild (
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_HANDLE ChildHandle,
+ IN UINT8 IpVersion
+ )
+{
+ EFI_STATUS Status;
+ EFI_GUID *ServiceBindingGuid;
+ EFI_GUID *IpProtocolGuid;
+
+ if (IpVersion == IP_VERSION_4) {
+ ServiceBindingGuid = &gEfiIp4ServiceBindingProtocolGuid;
+ IpProtocolGuid = &gEfiIp4ProtocolGuid;
+ } else if (IpVersion == IP_VERSION_6) {
+ ServiceBindingGuid = &gEfiIp6ServiceBindingProtocolGuid;
+ IpProtocolGuid = &gEfiIp6ProtocolGuid;
+ } else {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Close the previously openned IP protocol.
+ //
+ gBS->CloseProtocol (
+ ChildHandle,
+ IpProtocolGuid,
+ ImageHandle,
+ ControllerHandle
+ );
+
+ //
+ // Destroy the IP child.
+ //
+ Status = NetLibDestroyServiceChild (
+ ControllerHandle,
+ ImageHandle,
+ ServiceBindingGuid,
+ ChildHandle
+ );
+
+ return Status;
+}
+
+/**
+ This function handles ICMPv4 packets. It is the worker function of
+ IpIoIcmpHandler.
+
+ @param[in] IpIo Pointer to the IP_IO instance.
+ @param[in, out] Pkt Pointer to the ICMPv4 packet.
+ @param[in] Session Pointer to the net session of this ICMPv4 packet.
+
+ @retval EFI_SUCCESS The ICMPv4 packet is handled successfully.
+ @retval EFI_ABORTED This type of ICMPv4 packet is not supported.
+
+**/
+EFI_STATUS
+IpIoIcmpv4Handler (
+ IN IP_IO *IpIo,
+ IN OUT NET_BUF *Pkt,
+ IN EFI_NET_SESSION_DATA *Session
+ )
+{
+ IP4_ICMP_ERROR_HEAD *IcmpHdr;
+ EFI_IP4_HEADER *IpHdr;
+ UINT8 IcmpErr;
+ UINT8 *PayLoadHdr;
+ UINT8 Type;
+ UINT8 Code;
+ UINT32 TrimBytes;
+
+ ASSERT (IpIo->IpVersion == IP_VERSION_4);
+
+ IcmpHdr = NET_PROTO_HDR (Pkt, IP4_ICMP_ERROR_HEAD);
+ IpHdr = (EFI_IP4_HEADER *) (&IcmpHdr->IpHead);
+
+ //
+ // Check the ICMP packet length.
+ //
+ if (Pkt->TotalSize < ICMP_ERRLEN (IpHdr)) {
+
+ return EFI_ABORTED;
+ }
+
+ Type = IcmpHdr->Head.Type;
+ Code = IcmpHdr->Head.Code;
+
+ //
+ // Analyze the ICMP Error in this ICMP pkt
+ //
+ switch (Type) {
+ case ICMP_TYPE_UNREACH:
+ switch (Code) {
+ case ICMP_CODE_UNREACH_NET:
+ case ICMP_CODE_UNREACH_HOST:
+ case ICMP_CODE_UNREACH_PROTOCOL:
+ case ICMP_CODE_UNREACH_PORT:
+ case ICMP_CODE_UNREACH_SRCFAIL:
+ IcmpErr = (UINT8) (ICMP_ERR_UNREACH_NET + Code);
+
+ break;
+
+ case ICMP_CODE_UNREACH_NEEDFRAG:
+ IcmpErr = ICMP_ERR_MSGSIZE;
+
+ break;
+
+ case ICMP_CODE_UNREACH_NET_UNKNOWN:
+ case ICMP_CODE_UNREACH_NET_PROHIB:
+ case ICMP_CODE_UNREACH_TOSNET:
+ IcmpErr = ICMP_ERR_UNREACH_NET;
+
+ break;
+
+ case ICMP_CODE_UNREACH_HOST_UNKNOWN:
+ case ICMP_CODE_UNREACH_ISOLATED:
+ case ICMP_CODE_UNREACH_HOST_PROHIB:
+ case ICMP_CODE_UNREACH_TOSHOST:
+ IcmpErr = ICMP_ERR_UNREACH_HOST;
+
+ break;
+
+ default:
+ return EFI_ABORTED;
+ }
+
+ break;
+
+ case ICMP_TYPE_TIMXCEED:
+ if (Code > 1) {
+ return EFI_ABORTED;
+ }
+
+ IcmpErr = (UINT8) (Code + ICMP_ERR_TIMXCEED_INTRANS);
+
+ break;
+
+ case ICMP_TYPE_PARAMPROB:
+ if (Code > 1) {
+ return EFI_ABORTED;
+ }
+
+ IcmpErr = ICMP_ERR_PARAMPROB;
+
+ break;
+
+ case ICMP_TYPE_SOURCEQUENCH:
+ if (Code != 0) {
+ return EFI_ABORTED;
+ }
+
+ IcmpErr = ICMP_ERR_QUENCH;
+
+ break;
+
+ default:
+ return EFI_ABORTED;
+ }
+
+ //
+ // Notify user the ICMP pkt only containing payload except
+ // IP and ICMP header
+ //
+ PayLoadHdr = (UINT8 *) ((UINT8 *) IpHdr + EFI_IP4_HEADER_LEN (IpHdr));
+ TrimBytes = (UINT32) (PayLoadHdr - (UINT8 *) IcmpHdr);
+
+ NetbufTrim (Pkt, TrimBytes, TRUE);
+
+ IpIo->PktRcvdNotify (EFI_ICMP_ERROR, IcmpErr, Session, Pkt, IpIo->RcvdContext);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function handles ICMPv6 packets. It is the worker function of
+ IpIoIcmpHandler.
+
+ @param[in] IpIo Pointer to the IP_IO instance.
+ @param[in, out] Pkt Pointer to the ICMPv6 packet.
+ @param[in] Session Pointer to the net session of this ICMPv6 packet.
+
+ @retval EFI_SUCCESS The ICMPv6 packet is handled successfully.
+ @retval EFI_ABORTED This type of ICMPv6 packet is not supported.
+
+**/
+EFI_STATUS
+IpIoIcmpv6Handler (
+ IN IP_IO *IpIo,
+ IN OUT NET_BUF *Pkt,
+ IN EFI_NET_SESSION_DATA *Session
+ )
+{
+ IP6_ICMP_ERROR_HEAD *IcmpHdr;
+ EFI_IP6_HEADER *IpHdr;
+ UINT8 IcmpErr;
+ UINT8 *PayLoadHdr;
+ UINT8 Type;
+ UINT8 Code;
+ UINT8 NextHeader;
+ UINT32 TrimBytes;
+ BOOLEAN Flag;
+
+ ASSERT (IpIo->IpVersion == IP_VERSION_6);
+
+ //
+ // Check the ICMPv6 packet length.
+ //
+ if (Pkt->TotalSize < sizeof (IP6_ICMP_ERROR_HEAD)) {
+
+ return EFI_ABORTED;
+ }
+
+ IcmpHdr = NET_PROTO_HDR (Pkt, IP6_ICMP_ERROR_HEAD);
+ Type = IcmpHdr->Head.Type;
+ Code = IcmpHdr->Head.Code;
+
+ //
+ // Analyze the ICMPv6 Error in this ICMPv6 packet
+ //
+ switch (Type) {
+ case ICMP_V6_DEST_UNREACHABLE:
+ switch (Code) {
+ case ICMP_V6_NO_ROUTE_TO_DEST:
+ case ICMP_V6_BEYOND_SCOPE:
+ case ICMP_V6_ROUTE_REJECTED:
+ IcmpErr = ICMP6_ERR_UNREACH_NET;
+
+ break;
+
+ case ICMP_V6_COMM_PROHIBITED:
+ case ICMP_V6_ADDR_UNREACHABLE:
+ case ICMP_V6_SOURCE_ADDR_FAILED:
+ IcmpErr = ICMP6_ERR_UNREACH_HOST;
+
+ break;
+
+ case ICMP_V6_PORT_UNREACHABLE:
+ IcmpErr = ICMP6_ERR_UNREACH_PORT;
+
+ break;
+
+ default:
+ return EFI_ABORTED;
+ }
+
+ break;
+
+ case ICMP_V6_PACKET_TOO_BIG:
+ if (Code >= 1) {
+ return EFI_ABORTED;
+ }
+
+ IcmpErr = ICMP6_ERR_PACKAGE_TOOBIG;
+
+ break;
+
+ case ICMP_V6_TIME_EXCEEDED:
+ if (Code > 1) {
+ return EFI_ABORTED;
+ }
+
+ IcmpErr = (UINT8) (ICMP6_ERR_TIMXCEED_HOPLIMIT + Code);
+
+ break;
+
+ case ICMP_V6_PARAMETER_PROBLEM:
+ if (Code > 3) {
+ return EFI_ABORTED;
+ }
+
+ IcmpErr = (UINT8) (ICMP6_ERR_PARAMPROB_HEADER + Code);
+
+ break;
+
+ default:
+
+ return EFI_ABORTED;
+ }
+
+ //
+ // Notify user the ICMPv6 packet only containing payload except
+ // IPv6 basic header, extension header and ICMP header
+ //
+
+ IpHdr = (EFI_IP6_HEADER *) (&IcmpHdr->IpHead);
+ NextHeader = IpHdr->NextHeader;
+ PayLoadHdr = (UINT8 *) ((UINT8 *) IcmpHdr + sizeof (IP6_ICMP_ERROR_HEAD));
+ Flag = TRUE;
+
+ do {
+ switch (NextHeader) {
+ case EFI_IP_PROTO_UDP:
+ case EFI_IP_PROTO_TCP:
+ case EFI_IP_PROTO_ICMP:
+ case IP6_NO_NEXT_HEADER:
+ Flag = FALSE;
+
+ break;
+
+ case IP6_HOP_BY_HOP:
+ case IP6_DESTINATION:
+ //
+ // The Hdr Ext Len is 8-bit unsigned integer in 8-octet units, not including
+ // the first 8 octets.
+ //
+ NextHeader = *(PayLoadHdr);
+ PayLoadHdr = (UINT8 *) (PayLoadHdr + (*(PayLoadHdr + 1) + 1) * 8);
+
+ break;
+
+ case IP6_FRAGMENT:
+ //
+ // The Fragment Header Length is 8 octets.
+ //
+ NextHeader = *(PayLoadHdr);
+ PayLoadHdr = (UINT8 *) (PayLoadHdr + 8);
+
+ break;
+
+ default:
+
+ return EFI_ABORTED;
+ }
+ } while (Flag);
+
+ TrimBytes = (UINT32) (PayLoadHdr - (UINT8 *) IcmpHdr);
+
+ NetbufTrim (Pkt, TrimBytes, TRUE);
+
+ IpIo->PktRcvdNotify (EFI_ICMP_ERROR, IcmpErr, Session, Pkt, IpIo->RcvdContext);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function handles ICMP packets.
+
+ @param[in] IpIo Pointer to the IP_IO instance.
+ @param[in, out] Pkt Pointer to the ICMP packet.
+ @param[in] Session Pointer to the net session of this ICMP packet.
+
+ @retval EFI_SUCCESS The ICMP packet is handled successfully.
+ @retval EFI_ABORTED This type of ICMP packet is not supported.
+ @retval EFI_UNSUPPORTED The IP protocol version in IP_IO is not supported.
+
+**/
+EFI_STATUS
+IpIoIcmpHandler (
+ IN IP_IO *IpIo,
+ IN OUT NET_BUF *Pkt,
+ IN EFI_NET_SESSION_DATA *Session
+ )
+{
+
+ if (IpIo->IpVersion == IP_VERSION_4) {
+
+ return IpIoIcmpv4Handler (IpIo, Pkt, Session);
+
+ } else if (IpIo->IpVersion == IP_VERSION_6) {
+
+ return IpIoIcmpv6Handler (IpIo, Pkt, Session);
+
+ } else {
+
+ return EFI_UNSUPPORTED;
+ }
+}
+
+
+/**
+ Free function for receive token of IP_IO. It is used to
+ signal the recycle event to notify IP to recycle the
+ data buffer.
+
+ @param[in] Event The event to be signaled.
+
+**/
+VOID
+EFIAPI
+IpIoExtFree (
+ IN VOID *Event
+ )
+{
+ gBS->SignalEvent ((EFI_EVENT) Event);
+}
+
+
+/**
+ Create a send entry to wrap a packet before sending
+ out it through IP.
+
+ @param[in, out] IpIo Pointer to the IP_IO instance.
+ @param[in, out] Pkt Pointer to the packet.
+ @param[in] Sender Pointer to the IP sender.
+ @param[in] Context Pointer to the context.
+ @param[in] NotifyData Pointer to the notify data.
+ @param[in] Dest Pointer to the destination IP address.
+ @param[in] Override Pointer to the overriden IP_IO data.
+
+ @return Pointer to the data structure created to wrap the packet. If NULL,
+ @return resource limit occurred.
+
+**/
+IP_IO_SEND_ENTRY *
+IpIoCreateSndEntry (
+ IN OUT IP_IO *IpIo,
+ IN OUT NET_BUF *Pkt,
+ IN IP_IO_IP_PROTOCOL Sender,
+ IN VOID *Context OPTIONAL,
+ IN VOID *NotifyData OPTIONAL,
+ IN EFI_IP_ADDRESS *Dest OPTIONAL,
+ IN IP_IO_OVERRIDE *Override
+ )
+{
+ IP_IO_SEND_ENTRY *SndEntry;
+ EFI_EVENT Event;
+ EFI_STATUS Status;
+ NET_FRAGMENT *ExtFragment;
+ UINT32 FragmentCount;
+ IP_IO_OVERRIDE *OverrideData;
+ IP_IO_IP_TX_DATA *TxData;
+ EFI_IP4_TRANSMIT_DATA *Ip4TxData;
+ EFI_IP6_TRANSMIT_DATA *Ip6TxData;
+
+ if ((IpIo->IpVersion != IP_VERSION_4) && (IpIo->IpVersion != IP_VERSION_6)) {
+ return NULL;
+ }
+
+ Event = NULL;
+ TxData = NULL;
+ OverrideData = NULL;
+
+ //
+ // Allocate resource for SndEntry
+ //
+ SndEntry = AllocatePool (sizeof (IP_IO_SEND_ENTRY));
+ if (NULL == SndEntry) {
+ return NULL;
+ }
+
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ IpIoTransmitHandler,
+ SndEntry,
+ &Event
+ );
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+
+ FragmentCount = Pkt->BlockOpNum;
+
+ //
+ // Allocate resource for TxData
+ //
+ TxData = (IP_IO_IP_TX_DATA *) AllocatePool (
+ sizeof (IP_IO_IP_TX_DATA) + sizeof (NET_FRAGMENT) * (FragmentCount - 1)
+ );
+
+ if (NULL == TxData) {
+ goto ON_ERROR;
+ }
+
+ //
+ // Build a fragment table to contain the fragments in the packet.
+ //
+ if (IpIo->IpVersion == IP_VERSION_4) {
+ ExtFragment = (NET_FRAGMENT *) TxData->Ip4TxData.FragmentTable;
+ } else {
+ ExtFragment = (NET_FRAGMENT *) TxData->Ip6TxData.FragmentTable;
+ }
+
+ NetbufBuildExt (Pkt, ExtFragment, &FragmentCount);
+
+
+ //
+ // Allocate resource for OverrideData if needed
+ //
+ if (NULL != Override) {
+
+ OverrideData = AllocateCopyPool (sizeof (IP_IO_OVERRIDE), Override);
+ if (NULL == OverrideData) {
+ goto ON_ERROR;
+ }
+ }
+
+ //
+ // Set other fields of TxData except the fragment table
+ //
+ if (IpIo->IpVersion == IP_VERSION_4) {
+
+ Ip4TxData = &TxData->Ip4TxData;
+
+ IP4_COPY_ADDRESS (&Ip4TxData->DestinationAddress, Dest);
+
+ Ip4TxData->OverrideData = &OverrideData->Ip4OverrideData;
+ Ip4TxData->OptionsLength = 0;
+ Ip4TxData->OptionsBuffer = NULL;
+ Ip4TxData->TotalDataLength = Pkt->TotalSize;
+ Ip4TxData->FragmentCount = FragmentCount;
+
+ //
+ // Set the fields of SndToken
+ //
+ SndEntry->SndToken.Ip4Token.Event = Event;
+ SndEntry->SndToken.Ip4Token.Packet.TxData = Ip4TxData;
+ } else {
+
+ Ip6TxData = &TxData->Ip6TxData;
+
+ if (Dest != NULL) {
+ CopyMem (&Ip6TxData->DestinationAddress, Dest, sizeof (EFI_IPv6_ADDRESS));
+ } else {
+ ZeroMem (&Ip6TxData->DestinationAddress, sizeof (EFI_IPv6_ADDRESS));
+ }
+
+ Ip6TxData->OverrideData = &OverrideData->Ip6OverrideData;
+ Ip6TxData->DataLength = Pkt->TotalSize;
+ Ip6TxData->FragmentCount = FragmentCount;
+ Ip6TxData->ExtHdrsLength = 0;
+ Ip6TxData->ExtHdrs = NULL;
+
+ //
+ // Set the fields of SndToken
+ //
+ SndEntry->SndToken.Ip6Token.Event = Event;
+ SndEntry->SndToken.Ip6Token.Packet.TxData = Ip6TxData;
+ }
+
+ //
+ // Set the fields of SndEntry
+ //
+ SndEntry->IpIo = IpIo;
+ SndEntry->Ip = Sender;
+ SndEntry->Context = Context;
+ SndEntry->NotifyData = NotifyData;
+
+ SndEntry->Pkt = Pkt;
+ NET_GET_REF (Pkt);
+
+ InsertTailList (&IpIo->PendingSndList, &SndEntry->Entry);
+
+ return SndEntry;
+
+ON_ERROR:
+
+ if (OverrideData != NULL) {
+ FreePool (OverrideData);
+ }
+
+ if (TxData != NULL) {
+ FreePool (TxData);
+ }
+
+ if (SndEntry != NULL) {
+ FreePool (SndEntry);
+ }
+
+ if (Event != NULL) {
+ gBS->CloseEvent (Event);
+ }
+
+ return NULL;
+}
+
+
+/**
+ Destroy the SndEntry.
+
+ This function pairs with IpIoCreateSndEntry().
+
+ @param[in] SndEntry Pointer to the send entry to be destroyed.
+
+**/
+VOID
+IpIoDestroySndEntry (
+ IN IP_IO_SEND_ENTRY *SndEntry
+ )
+{
+ EFI_EVENT Event;
+ IP_IO_IP_TX_DATA *TxData;
+ IP_IO_OVERRIDE *Override;
+
+ if (SndEntry->IpIo->IpVersion == IP_VERSION_4) {
+ Event = SndEntry->SndToken.Ip4Token.Event;
+ TxData = (IP_IO_IP_TX_DATA *) SndEntry->SndToken.Ip4Token.Packet.TxData;
+ Override = (IP_IO_OVERRIDE *) TxData->Ip4TxData.OverrideData;
+ } else if (SndEntry->IpIo->IpVersion == IP_VERSION_6) {
+ Event = SndEntry->SndToken.Ip6Token.Event;
+ TxData = (IP_IO_IP_TX_DATA *) SndEntry->SndToken.Ip6Token.Packet.TxData;
+ Override = (IP_IO_OVERRIDE *) TxData->Ip6TxData.OverrideData;
+ } else {
+ return ;
+ }
+
+ gBS->CloseEvent (Event);
+
+ FreePool (TxData);
+
+ if (NULL != Override) {
+ FreePool (Override);
+ }
+
+ NetbufFree (SndEntry->Pkt);
+
+ RemoveEntryList (&SndEntry->Entry);
+
+ FreePool (SndEntry);
+}
+
+
+/**
+ Notify function for IP transmit token.
+
+ @param[in] Context The context passed in by the event notifier.
+
+**/
+VOID
+EFIAPI
+IpIoTransmitHandlerDpc (
+ IN VOID *Context
+ )
+{
+ IP_IO *IpIo;
+ IP_IO_SEND_ENTRY *SndEntry;
+ EFI_STATUS Status;
+
+ SndEntry = (IP_IO_SEND_ENTRY *) Context;
+
+ IpIo = SndEntry->IpIo;
+
+ if (IpIo->IpVersion == IP_VERSION_4) {
+ Status = SndEntry->SndToken.Ip4Token.Status;
+ } else if (IpIo->IpVersion == IP_VERSION_6){
+ Status = SndEntry->SndToken.Ip6Token.Status;
+ } else {
+ return ;
+ }
+
+ if ((IpIo->PktSentNotify != NULL) && (SndEntry->NotifyData != NULL)) {
+ IpIo->PktSentNotify (
+ Status,
+ SndEntry->Context,
+ SndEntry->Ip,
+ SndEntry->NotifyData
+ );
+ }
+
+ IpIoDestroySndEntry (SndEntry);
+}
+
+
+/**
+ Notify function for IP transmit token.
+
+ @param[in] Event The event signaled.
+ @param[in] Context The context passed in by the event notifier.
+
+**/
+VOID
+EFIAPI
+IpIoTransmitHandler (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ //
+ // Request IpIoTransmitHandlerDpc as a DPC at TPL_CALLBACK
+ //
+ QueueDpc (TPL_CALLBACK, IpIoTransmitHandlerDpc, Context);
+}
+
+
+/**
+ The dummy handler for the dummy IP receive token.
+
+ @param[in] Context The context passed in by the event notifier.
+
+**/
+VOID
+EFIAPI
+IpIoDummyHandlerDpc (
+ IN VOID *Context
+ )
+{
+ IP_IO_IP_INFO *IpInfo;
+ EFI_STATUS Status;
+ EFI_EVENT RecycleEvent;
+
+ IpInfo = (IP_IO_IP_INFO *) Context;
+
+ if ((IpInfo->IpVersion != IP_VERSION_4) && (IpInfo->IpVersion != IP_VERSION_6)) {
+ return ;
+ }
+
+ RecycleEvent = NULL;
+
+ if (IpInfo->IpVersion == IP_VERSION_4) {
+ Status = IpInfo->DummyRcvToken.Ip4Token.Status;
+
+ if (IpInfo->DummyRcvToken.Ip4Token.Packet.RxData != NULL) {
+ RecycleEvent = IpInfo->DummyRcvToken.Ip4Token.Packet.RxData->RecycleSignal;
+ }
+ } else {
+ Status = IpInfo->DummyRcvToken.Ip6Token.Status;
+
+ if (IpInfo->DummyRcvToken.Ip6Token.Packet.RxData != NULL) {
+ RecycleEvent = IpInfo->DummyRcvToken.Ip6Token.Packet.RxData->RecycleSignal;
+ }
+ }
+
+
+
+ if (EFI_ABORTED == Status) {
+ //
+ // The reception is actively aborted by the consumer, directly return.
+ //
+ return;
+ } else if (EFI_SUCCESS == Status) {
+ //
+ // Recycle the RxData.
+ //
+ ASSERT (RecycleEvent != NULL);
+
+ gBS->SignalEvent (RecycleEvent);
+ }
+
+ //
+ // Continue the receive.
+ //
+ if (IpInfo->IpVersion == IP_VERSION_4) {
+ IpInfo->Ip.Ip4->Receive (
+ IpInfo->Ip.Ip4,
+ &IpInfo->DummyRcvToken.Ip4Token
+ );
+ } else {
+ IpInfo->Ip.Ip6->Receive (
+ IpInfo->Ip.Ip6,
+ &IpInfo->DummyRcvToken.Ip6Token
+ );
+ }
+}
+
+
+/**
+ This function add IpIoDummyHandlerDpc to the end of the DPC queue.
+
+ @param[in] Event The event signaled.
+ @param[in] Context The context passed in by the event notifier.
+
+**/
+VOID
+EFIAPI
+IpIoDummyHandler (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ //
+ // Request IpIoDummyHandlerDpc as a DPC at TPL_CALLBACK
+ //
+ QueueDpc (TPL_CALLBACK, IpIoDummyHandlerDpc, Context);
+}
+
+
+/**
+ Notify function for the IP receive token, used to process
+ the received IP packets.
+
+ @param[in] Context The context passed in by the event notifier.
+
+**/
+VOID
+EFIAPI
+IpIoListenHandlerDpc (
+ IN VOID *Context
+ )
+{
+ IP_IO *IpIo;
+ EFI_STATUS Status;
+ IP_IO_IP_RX_DATA *RxData;
+ EFI_NET_SESSION_DATA Session;
+ NET_BUF *Pkt;
+
+ IpIo = (IP_IO *) Context;
+
+ if (IpIo->IpVersion == IP_VERSION_4) {
+ Status = IpIo->RcvToken.Ip4Token.Status;
+ RxData = (IP_IO_IP_RX_DATA *) IpIo->RcvToken.Ip4Token.Packet.RxData;
+ } else if (IpIo->IpVersion == IP_VERSION_6) {
+ Status = IpIo->RcvToken.Ip6Token.Status;
+ RxData = (IP_IO_IP_RX_DATA *) IpIo->RcvToken.Ip6Token.Packet.RxData;
+ } else {
+ return;
+ }
+
+ if (EFI_ABORTED == Status) {
+ //
+ // The reception is actively aborted by the consumer, directly return.
+ //
+ return;
+ }
+
+ if (((EFI_SUCCESS != Status) && (EFI_ICMP_ERROR != Status)) || (NULL == RxData)) {
+ //
+ // @bug Only process the normal packets and the icmp error packets, if RxData is NULL
+ // @bug with Status == EFI_SUCCESS or EFI_ICMP_ERROR, just resume the receive although
+ // @bug this should be a bug of the low layer (IP).
+ //
+ goto Resume;
+ }
+
+ if (NULL == IpIo->PktRcvdNotify) {
+ goto CleanUp;
+ }
+
+ if (IpIo->IpVersion == IP_VERSION_4) {
+ if ((EFI_IP4 (RxData->Ip4RxData.Header->SourceAddress) != 0) &&
+ !NetIp4IsUnicast (EFI_NTOHL (((EFI_IP4_RECEIVE_DATA *) RxData)->Header->SourceAddress), 0)) {
+ //
+ // The source address is not zero and it's not a unicast IP address, discard it.
+ //
+ goto CleanUp;
+ }
+
+ //
+ // Create a netbuffer representing IPv4 packet
+ //
+ Pkt = NetbufFromExt (
+ (NET_FRAGMENT *) RxData->Ip4RxData.FragmentTable,
+ RxData->Ip4RxData.FragmentCount,
+ 0,
+ 0,
+ IpIoExtFree,
+ RxData->Ip4RxData.RecycleSignal
+ );
+ if (NULL == Pkt) {
+ goto CleanUp;
+ }
+
+ //
+ // Create a net session
+ //
+ Session.Source.Addr[0] = EFI_IP4 (RxData->Ip4RxData.Header->SourceAddress);
+ Session.Dest.Addr[0] = EFI_IP4 (RxData->Ip4RxData.Header->DestinationAddress);
+ Session.IpHdr.Ip4Hdr = RxData->Ip4RxData.Header;
+ Session.IpHdrLen = RxData->Ip4RxData.HeaderLength;
+ Session.IpVersion = IP_VERSION_4;
+ } else {
+
+ if (!NetIp6IsValidUnicast(&RxData->Ip6RxData.Header->SourceAddress)) {
+ goto CleanUp;
+ }
+
+ //
+ // Create a netbuffer representing IPv6 packet
+ //
+ Pkt = NetbufFromExt (
+ (NET_FRAGMENT *) RxData->Ip6RxData.FragmentTable,
+ RxData->Ip6RxData.FragmentCount,
+ 0,
+ 0,
+ IpIoExtFree,
+ RxData->Ip6RxData.RecycleSignal
+ );
+ if (NULL == Pkt) {
+ goto CleanUp;
+ }
+
+ //
+ // Create a net session
+ //
+ CopyMem (
+ &Session.Source,
+ &RxData->Ip6RxData.Header->SourceAddress,
+ sizeof(EFI_IPv6_ADDRESS)
+ );
+ CopyMem (
+ &Session.Dest,
+ &RxData->Ip6RxData.Header->DestinationAddress,
+ sizeof(EFI_IPv6_ADDRESS)
+ );
+ Session.IpHdr.Ip6Hdr = RxData->Ip6RxData.Header;
+ Session.IpHdrLen = RxData->Ip6RxData.HeaderLength;
+ Session.IpVersion = IP_VERSION_6;
+ }
+
+ if (EFI_SUCCESS == Status) {
+
+ IpIo->PktRcvdNotify (EFI_SUCCESS, 0, &Session, Pkt, IpIo->RcvdContext);
+ } else {
+ //
+ // Status is EFI_ICMP_ERROR
+ //
+ Status = IpIoIcmpHandler (IpIo, Pkt, &Session);
+ if (EFI_ERROR (Status)) {
+ NetbufFree (Pkt);
+ }
+ }
+
+ goto Resume;
+
+CleanUp:
+
+ if (IpIo->IpVersion == IP_VERSION_4){
+ gBS->SignalEvent (RxData->Ip4RxData.RecycleSignal);
+ } else {
+ gBS->SignalEvent (RxData->Ip6RxData.RecycleSignal);
+ }
+
+Resume:
+
+ if (IpIo->IpVersion == IP_VERSION_4){
+ IpIo->Ip.Ip4->Receive (IpIo->Ip.Ip4, &(IpIo->RcvToken.Ip4Token));
+ } else {
+ IpIo->Ip.Ip6->Receive (IpIo->Ip.Ip6, &(IpIo->RcvToken.Ip6Token));
+ }
+}
+
+/**
+ This function add IpIoListenHandlerDpc to the end of the DPC queue.
+
+ @param[in] Event The event signaled.
+ @param[in] Context The context passed in by the event notifier.
+
+**/
+VOID
+EFIAPI
+IpIoListenHandler (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ //
+ // Request IpIoListenHandlerDpc as a DPC at TPL_CALLBACK
+ //
+ QueueDpc (TPL_CALLBACK, IpIoListenHandlerDpc, Context);
+}
+
+
+/**
+ Create a new IP_IO instance.
+
+ This function uses IP4/IP6 service binding protocol in Controller to create
+ an IP4/IP6 child (aka IP4/IP6 instance).
+
+ @param[in] Image The image handle of the driver or application that
+ consumes IP_IO.
+ @param[in] Controller The controller handle that has IP4 or IP6 service
+ binding protocol installed.
+ @param[in] IpVersion The version of the IP protocol to use, either
+ IPv4 or IPv6.
+
+ @return Pointer to a newly created IP_IO instance, or NULL if failed.
+
+**/
+IP_IO *
+EFIAPI
+IpIoCreate (
+ IN EFI_HANDLE Image,
+ IN EFI_HANDLE Controller,
+ IN UINT8 IpVersion
+ )
+{
+ EFI_STATUS Status;
+ IP_IO *IpIo;
+ EFI_EVENT Event;
+
+ ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6));
+
+ IpIo = AllocateZeroPool (sizeof (IP_IO));
+ if (NULL == IpIo) {
+ return NULL;
+ }
+
+ InitializeListHead (&(IpIo->PendingSndList));
+ InitializeListHead (&(IpIo->IpList));
+ IpIo->Controller = Controller;
+ IpIo->Image = Image;
+ IpIo->IpVersion = IpVersion;
+ Event = NULL;
+
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ IpIoListenHandler,
+ IpIo,
+ &Event
+ );
+ if (EFI_ERROR (Status)) {
+ goto ReleaseIpIo;
+ }
+
+ if (IpVersion == IP_VERSION_4) {
+ IpIo->RcvToken.Ip4Token.Event = Event;
+ } else {
+ IpIo->RcvToken.Ip6Token.Event = Event;
+ }
+
+ //
+ // Create an IP child and open IP protocol
+ //
+ Status = IpIoCreateIpChildOpenProtocol (
+ Controller,
+ Image,
+ &IpIo->ChildHandle,
+ IpVersion,
+ (VOID **)&(IpIo->Ip)
+ );
+ if (EFI_ERROR (Status)) {
+ goto ReleaseIpIo;
+ }
+
+ return IpIo;
+
+ReleaseIpIo:
+
+ if (Event != NULL) {
+ gBS->CloseEvent (Event);
+ }
+
+ gBS->FreePool (IpIo);
+
+ return NULL;
+}
+
+
+/**
+ Open an IP_IO instance for use.
+
+ This function is called after IpIoCreate(). It is used for configuring the IP
+ instance and register the callbacks and their context data for sending and
+ receiving IP packets.
+
+ @param[in, out] IpIo Pointer to an IP_IO instance that needs
+ to open.
+ @param[in] OpenData The configuration data and callbacks for
+ the IP_IO instance.
+
+ @retval EFI_SUCCESS The IP_IO instance opened with OpenData
+ successfully.
+ @retval EFI_ACCESS_DENIED The IP_IO instance is configured, avoid to
+ reopen it.
+ @retval Others Error condition occurred.
+
+**/
+EFI_STATUS
+EFIAPI
+IpIoOpen (
+ IN OUT IP_IO *IpIo,
+ IN IP_IO_OPEN_DATA *OpenData
+ )
+{
+ EFI_STATUS Status;
+ UINT8 IpVersion;
+
+ if (IpIo->IsConfigured) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ IpVersion = IpIo->IpVersion;
+
+ ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6));
+
+ //
+ // configure ip
+ //
+ if (IpVersion == IP_VERSION_4){
+ Status = IpIo->Ip.Ip4->Configure (
+ IpIo->Ip.Ip4,
+ &OpenData->IpConfigData.Ip4CfgData
+ );
+ } else {
+
+ Status = IpIo->Ip.Ip6->Configure (
+ IpIo->Ip.Ip6,
+ &OpenData->IpConfigData.Ip6CfgData
+ );
+ }
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // @bug To delete the default route entry in this Ip, if it is:
+ // @bug (0.0.0.0, 0.0.0.0, 0.0.0.0). Delete this statement if Ip modified
+ // @bug its code
+ //
+ if (IpVersion == IP_VERSION_4){
+ Status = IpIo->Ip.Ip4->Routes (
+ IpIo->Ip.Ip4,
+ TRUE,
+ &mZeroIp4Addr,
+ &mZeroIp4Addr,
+ &mZeroIp4Addr
+ );
+
+ if (EFI_ERROR (Status) && (EFI_NOT_FOUND != Status)) {
+ return Status;
+ }
+ }
+
+ IpIo->PktRcvdNotify = OpenData->PktRcvdNotify;
+ IpIo->PktSentNotify = OpenData->PktSentNotify;
+
+ IpIo->RcvdContext = OpenData->RcvdContext;
+ IpIo->SndContext = OpenData->SndContext;
+
+ if (IpVersion == IP_VERSION_4){
+ IpIo->Protocol = OpenData->IpConfigData.Ip4CfgData.DefaultProtocol;
+
+ //
+ // start to listen incoming packet
+ //
+ Status = IpIo->Ip.Ip4->Receive (
+ IpIo->Ip.Ip4,
+ &(IpIo->RcvToken.Ip4Token)
+ );
+ if (EFI_ERROR (Status)) {
+ IpIo->Ip.Ip4->Configure (IpIo->Ip.Ip4, NULL);
+ goto ErrorExit;
+ }
+
+ } else {
+
+ IpIo->Protocol = OpenData->IpConfigData.Ip6CfgData.DefaultProtocol;
+ Status = IpIo->Ip.Ip6->Receive (
+ IpIo->Ip.Ip6,
+ &(IpIo->RcvToken.Ip6Token)
+ );
+ if (EFI_ERROR (Status)) {
+ IpIo->Ip.Ip6->Configure (IpIo->Ip.Ip6, NULL);
+ goto ErrorExit;
+ }
+ }
+
+ IpIo->IsConfigured = TRUE;
+ InsertTailList (&mActiveIpIoList, &IpIo->Entry);
+
+ErrorExit:
+
+ return Status;
+}
+
+
+/**
+ Stop an IP_IO instance.
+
+ This function is paired with IpIoOpen(). The IP_IO will be unconfigured and all
+ the pending send/receive tokens will be canceled.
+
+ @param[in, out] IpIo Pointer to the IP_IO instance that needs to stop.
+
+ @retval EFI_SUCCESS The IP_IO instance stopped successfully.
+ @retval Others Error condition occurred.
+
+**/
+EFI_STATUS
+EFIAPI
+IpIoStop (
+ IN OUT IP_IO *IpIo
+ )
+{
+ EFI_STATUS Status;
+ IP_IO_IP_INFO *IpInfo;
+ UINT8 IpVersion;
+
+ if (!IpIo->IsConfigured) {
+ return EFI_SUCCESS;
+ }
+
+ IpVersion = IpIo->IpVersion;
+
+ ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6));
+
+ //
+ // Remove the IpIo from the active IpIo list.
+ //
+ RemoveEntryList (&IpIo->Entry);
+
+ //
+ // Configure NULL Ip
+ //
+ if (IpVersion == IP_VERSION_4) {
+ Status = IpIo->Ip.Ip4->Configure (IpIo->Ip.Ip4, NULL);
+ } else {
+ Status = IpIo->Ip.Ip6->Configure (IpIo->Ip.Ip6, NULL);
+ }
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ IpIo->IsConfigured = FALSE;
+
+ //
+ // Detroy the Ip List used by IpIo
+ //
+
+ while (!IsListEmpty (&(IpIo->IpList))) {
+ IpInfo = NET_LIST_HEAD (&(IpIo->IpList), IP_IO_IP_INFO, Entry);
+
+ IpIoRemoveIp (IpIo, IpInfo);
+ }
+
+ //
+ // All pending send tokens should be flushed by reseting the IP instances.
+ //
+ ASSERT (IsListEmpty (&IpIo->PendingSndList));
+
+ //
+ // Close the receive event.
+ //
+ if (IpVersion == IP_VERSION_4){
+ gBS->CloseEvent (IpIo->RcvToken.Ip4Token.Event);
+ } else {
+ gBS->CloseEvent (IpIo->RcvToken.Ip6Token.Event);
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Destroy an IP_IO instance.
+
+ This function is paired with IpIoCreate(). The IP_IO will be closed first.
+ Resource will be freed afterwards. See IpIoCloseProtocolDestroyIpChild().
+
+ @param[in, out] IpIo Pointer to the IP_IO instance that needs to be
+ destroyed.
+
+ @retval EFI_SUCCESS The IP_IO instance destroyed successfully.
+ @retval Others Error condition occurred.
+
+**/
+EFI_STATUS
+EFIAPI
+IpIoDestroy (
+ IN OUT IP_IO *IpIo
+ )
+{
+ //
+ // Stop the IpIo.
+ //
+ IpIoStop (IpIo);
+
+ //
+ // Close the IP protocol and destroy the child.
+ //
+ IpIoCloseProtocolDestroyIpChild (
+ IpIo->Controller,
+ IpIo->Image,
+ IpIo->ChildHandle,
+ IpIo->IpVersion
+ );
+
+ gBS->FreePool (IpIo);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Send out an IP packet.
+
+ This function is called after IpIoOpen(). The data to be sent are wrapped in
+ Pkt. The IP instance wrapped in IpIo is used for sending by default but can be
+ overriden by Sender. Other sending configs, like source address and gateway
+ address etc., are specified in OverrideData.
+
+ @param[in, out] IpIo Pointer to an IP_IO instance used for sending IP
+ packet.
+ @param[in, out] Pkt Pointer to the IP packet to be sent.
+ @param[in] Sender The IP protocol instance used for sending.
+ @param[in] Context Optional context data.
+ @param[in] NotifyData Optional notify data.
+ @param[in] Dest The destination IP address to send this packet to.
+ @param[in] OverrideData The data to override some configuration of the IP
+ instance used for sending.
+
+ @retval EFI_SUCCESS The operation is completed successfully.
+ @retval EFI_NOT_STARTED The IpIo is not configured.
+ @retval EFI_OUT_OF_RESOURCES Failed due to resource limit.
+
+**/
+EFI_STATUS
+EFIAPI
+IpIoSend (
+ IN OUT IP_IO *IpIo,
+ IN OUT NET_BUF *Pkt,
+ IN IP_IO_IP_INFO *Sender OPTIONAL,
+ IN VOID *Context OPTIONAL,
+ IN VOID *NotifyData OPTIONAL,
+ IN EFI_IP_ADDRESS *Dest,
+ IN IP_IO_OVERRIDE *OverrideData OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ IP_IO_IP_PROTOCOL Ip;
+ IP_IO_SEND_ENTRY *SndEntry;
+
+ ASSERT ((IpIo->IpVersion != IP_VERSION_4) || (Dest != NULL));
+
+ if (!IpIo->IsConfigured) {
+ return EFI_NOT_STARTED;
+ }
+
+ Ip = (NULL == Sender) ? IpIo->Ip : Sender->Ip;
+
+ //
+ // create a new SndEntry
+ //
+ SndEntry = IpIoCreateSndEntry (IpIo, Pkt, Ip, Context, NotifyData, Dest, OverrideData);
+ if (NULL == SndEntry) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Send this Packet
+ //
+ if (IpIo->IpVersion == IP_VERSION_4){
+ Status = Ip.Ip4->Transmit (
+ Ip.Ip4,
+ &SndEntry->SndToken.Ip4Token
+ );
+ } else {
+ Status = Ip.Ip6->Transmit (
+ Ip.Ip6,
+ &SndEntry->SndToken.Ip6Token
+ );
+ }
+
+ if (EFI_ERROR (Status)) {
+ IpIoDestroySndEntry (SndEntry);
+ }
+
+ return Status;
+}
+
+
+/**
+ Cancel the IP transmit token which wraps this Packet.
+
+ @param[in] IpIo Pointer to the IP_IO instance.
+ @param[in] Packet Pointer to the packet of NET_BUF to cancel.
+
+**/
+VOID
+EFIAPI
+IpIoCancelTxToken (
+ IN IP_IO *IpIo,
+ IN VOID *Packet
+ )
+{
+ LIST_ENTRY *Node;
+ IP_IO_SEND_ENTRY *SndEntry;
+ IP_IO_IP_PROTOCOL Ip;
+
+ ASSERT ((IpIo != NULL) && (Packet != NULL));
+
+ NET_LIST_FOR_EACH (Node, &IpIo->PendingSndList) {
+
+ SndEntry = NET_LIST_USER_STRUCT (Node, IP_IO_SEND_ENTRY, Entry);
+
+ if (SndEntry->Pkt == Packet) {
+
+ Ip = SndEntry->Ip;
+
+ if (IpIo->IpVersion == IP_VERSION_4) {
+ Ip.Ip4->Cancel (
+ Ip.Ip4,
+ &SndEntry->SndToken.Ip4Token
+ );
+ } else {
+ Ip.Ip6->Cancel (
+ Ip.Ip6,
+ &SndEntry->SndToken.Ip6Token
+ );
+ }
+
+ break;
+ }
+ }
+
+}
+
+
+/**
+ Add a new IP instance for sending data.
+
+ The function is used to add the IP_IO to the IP_IO sending list. The caller
+ can later use IpIoFindSender() to get the IP_IO and call IpIoSend() to send
+ data.
+
+ @param[in, out] IpIo Pointer to a IP_IO instance to add a new IP
+ instance for sending purpose.
+
+ @return Pointer to the created IP_IO_IP_INFO structure, NULL if failed.
+
+**/
+IP_IO_IP_INFO *
+EFIAPI
+IpIoAddIp (
+ IN OUT IP_IO *IpIo
+ )
+{
+ EFI_STATUS Status;
+ IP_IO_IP_INFO *IpInfo;
+ EFI_EVENT Event;
+
+ ASSERT (IpIo != NULL);
+
+ IpInfo = AllocatePool (sizeof (IP_IO_IP_INFO));
+ if (IpInfo == NULL) {
+ return NULL;
+ }
+
+ //
+ // Init this IpInfo, set the Addr and SubnetMask to 0 before we configure the IP
+ // instance.
+ //
+ InitializeListHead (&IpInfo->Entry);
+ IpInfo->ChildHandle = NULL;
+ ZeroMem (&IpInfo->Addr, sizeof (IpInfo->Addr));
+ ZeroMem (&IpInfo->PreMask, sizeof (IpInfo->PreMask));
+
+ IpInfo->RefCnt = 1;
+ IpInfo->IpVersion = IpIo->IpVersion;
+
+ //
+ // Create the IP instance and open the IP protocol.
+ //
+ Status = IpIoCreateIpChildOpenProtocol (
+ IpIo->Controller,
+ IpIo->Image,
+ &IpInfo->ChildHandle,
+ IpInfo->IpVersion,
+ (VOID **) &IpInfo->Ip
+ );
+ if (EFI_ERROR (Status)) {
+ goto ReleaseIpInfo;
+ }
+
+ //
+ // Create the event for the DummyRcvToken.
+ //
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ IpIoDummyHandler,
+ IpInfo,
+ &Event
+ );
+ if (EFI_ERROR (Status)) {
+ goto ReleaseIpChild;
+ }
+
+ if (IpInfo->IpVersion == IP_VERSION_4) {
+ IpInfo->DummyRcvToken.Ip4Token.Event = Event;
+ } else {
+ IpInfo->DummyRcvToken.Ip6Token.Event = Event;
+ }
+
+ //
+ // Link this IpInfo into the IpIo.
+ //
+ InsertTailList (&IpIo->IpList, &IpInfo->Entry);
+
+ return IpInfo;
+
+ReleaseIpChild:
+
+ IpIoCloseProtocolDestroyIpChild (
+ IpIo->Controller,
+ IpIo->Image,
+ IpInfo->ChildHandle,
+ IpInfo->IpVersion
+ );
+
+ReleaseIpInfo:
+
+ gBS->FreePool (IpInfo);
+
+ return NULL;
+}
+
+
+/**
+ Configure the IP instance of this IpInfo and start the receiving if IpConfigData
+ is not NULL.
+
+ @param[in, out] IpInfo Pointer to the IP_IO_IP_INFO instance.
+ @param[in, out] IpConfigData The IP configure data used to configure the IP
+ instance, if NULL the IP instance is reset. If
+ UseDefaultAddress is set to TRUE, and the configure
+ operation succeeds, the default address information
+ is written back in this IpConfigData.
+
+ @retval EFI_SUCCESS The IP instance of this IpInfo is configured successfully
+ or no need to reconfigure it.
+ @retval Others Configuration fails.
+
+**/
+EFI_STATUS
+EFIAPI
+IpIoConfigIp (
+ IN OUT IP_IO_IP_INFO *IpInfo,
+ IN OUT VOID *IpConfigData OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ IP_IO_IP_PROTOCOL Ip;
+ UINT8 IpVersion;
+ EFI_IP4_MODE_DATA Ip4ModeData;
+ EFI_IP6_MODE_DATA Ip6ModeData;
+
+ ASSERT (IpInfo != NULL);
+
+ if (IpInfo->RefCnt > 1) {
+ //
+ // This IP instance is shared, don't reconfigure it until it has only one
+ // consumer. Currently, only the tcp children cloned from their passive parent
+ // will share the same IP. So this cases only happens while IpConfigData is NULL,
+ // let the last consumer clean the IP instance.
+ //
+ return EFI_SUCCESS;
+ }
+
+ IpVersion = IpInfo->IpVersion;
+ ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6));
+
+ Ip = IpInfo->Ip;
+
+ if (IpInfo->IpVersion == IP_VERSION_4) {
+ Status = Ip.Ip4->Configure (Ip.Ip4, IpConfigData);
+ } else {
+ Status = Ip.Ip6->Configure (Ip.Ip6, IpConfigData);
+ }
+
+ if (EFI_ERROR (Status)) {
+ goto OnExit;
+ }
+
+ if (IpConfigData != NULL) {
+ if (IpInfo->IpVersion == IP_VERSION_4){
+
+ if (((EFI_IP4_CONFIG_DATA *) IpConfigData)->UseDefaultAddress) {
+ Ip.Ip4->GetModeData (
+ Ip.Ip4,
+ &Ip4ModeData,
+ NULL,
+ NULL
+ );
+
+ IP4_COPY_ADDRESS (&((EFI_IP4_CONFIG_DATA*) IpConfigData)->StationAddress, &Ip4ModeData.ConfigData.StationAddress);
+ IP4_COPY_ADDRESS (&((EFI_IP4_CONFIG_DATA*) IpConfigData)->SubnetMask, &Ip4ModeData.ConfigData.SubnetMask);
+ }
+
+ CopyMem (
+ &IpInfo->Addr.Addr,
+ &((EFI_IP4_CONFIG_DATA *) IpConfigData)->StationAddress,
+ sizeof (IP4_ADDR)
+ );
+ CopyMem (
+ &IpInfo->PreMask.SubnetMask,
+ &((EFI_IP4_CONFIG_DATA *) IpConfigData)->SubnetMask,
+ sizeof (IP4_ADDR)
+ );
+
+ Status = Ip.Ip4->Receive (
+ Ip.Ip4,
+ &IpInfo->DummyRcvToken.Ip4Token
+ );
+ if (EFI_ERROR (Status)) {
+ Ip.Ip4->Configure (Ip.Ip4, NULL);
+ }
+ } else {
+ Ip.Ip6->GetModeData (
+ Ip.Ip6,
+ &Ip6ModeData,
+ NULL,
+ NULL
+ );
+
+ if (Ip6ModeData.IsConfigured) {
+ CopyMem (
+ &((EFI_IP6_CONFIG_DATA *) IpConfigData)->StationAddress,
+ &Ip6ModeData.ConfigData.StationAddress,
+ sizeof (EFI_IPv6_ADDRESS)
+ );
+
+ if (Ip6ModeData.AddressList != NULL) {
+ FreePool (Ip6ModeData.AddressList);
+ }
+
+ if (Ip6ModeData.GroupTable != NULL) {
+ FreePool (Ip6ModeData.GroupTable);
+ }
+
+ if (Ip6ModeData.RouteTable != NULL) {
+ FreePool (Ip6ModeData.RouteTable);
+ }
+
+ if (Ip6ModeData.NeighborCache != NULL) {
+ FreePool (Ip6ModeData.NeighborCache);
+ }
+
+ if (Ip6ModeData.PrefixTable != NULL) {
+ FreePool (Ip6ModeData.PrefixTable);
+ }
+
+ if (Ip6ModeData.IcmpTypeList != NULL) {
+ FreePool (Ip6ModeData.IcmpTypeList);
+ }
+
+ } else {
+ Status = EFI_NO_MAPPING;
+ goto OnExit;
+ }
+
+ CopyMem (
+ &IpInfo->Addr,
+ &Ip6ModeData.ConfigData.StationAddress,
+ sizeof (EFI_IPv6_ADDRESS)
+ );
+
+ Status = Ip.Ip6->Receive (
+ Ip.Ip6,
+ &IpInfo->DummyRcvToken.Ip6Token
+ );
+ if (EFI_ERROR (Status)) {
+ Ip.Ip6->Configure (Ip.Ip6, NULL);
+ }
+ }
+ } else {
+ //
+ // The IP instance is reset, set the stored Addr and SubnetMask to zero.
+ //
+ ZeroMem (&IpInfo->Addr, sizeof (IpInfo->Addr));
+ ZeroMem (&IpInfo->PreMask, sizeof (IpInfo->PreMask));
+ }
+
+OnExit:
+
+ return Status;
+}
+
+
+/**
+ Destroy an IP instance maintained in IpIo->IpList for
+ sending purpose.
+
+ This function pairs with IpIoAddIp(). The IpInfo is previously created by
+ IpIoAddIp(). The IP_IO_IP_INFO::RefCnt is decremented and the IP instance
+ will be dstroyed if the RefCnt is zero.
+
+ @param[in] IpIo Pointer to the IP_IO instance.
+ @param[in] IpInfo Pointer to the IpInfo to be removed.
+
+**/
+VOID
+EFIAPI
+IpIoRemoveIp (
+ IN IP_IO *IpIo,
+ IN IP_IO_IP_INFO *IpInfo
+ )
+{
+
+ UINT8 IpVersion;
+
+ ASSERT (IpInfo->RefCnt > 0);
+
+ NET_PUT_REF (IpInfo);
+
+ if (IpInfo->RefCnt > 0) {
+
+ return;
+ }
+
+ IpVersion = IpIo->IpVersion;
+
+ ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6));
+
+ RemoveEntryList (&IpInfo->Entry);
+
+ if (IpVersion == IP_VERSION_4){
+ IpInfo->Ip.Ip4->Configure (
+ IpInfo->Ip.Ip4,
+ NULL
+ );
+ IpIoCloseProtocolDestroyIpChild (
+ IpIo->Controller,
+ IpIo->Image,
+ IpInfo->ChildHandle,
+ IP_VERSION_4
+ );
+
+ gBS->CloseEvent (IpInfo->DummyRcvToken.Ip4Token.Event);
+
+ } else {
+
+ IpInfo->Ip.Ip6->Configure (
+ IpInfo->Ip.Ip6,
+ NULL
+ );
+
+ IpIoCloseProtocolDestroyIpChild (
+ IpIo->Controller,
+ IpIo->Image,
+ IpInfo->ChildHandle,
+ IP_VERSION_6
+ );
+
+ gBS->CloseEvent (IpInfo->DummyRcvToken.Ip6Token.Event);
+ }
+
+ FreePool (IpInfo);
+}
+
+
+/**
+ Find the first IP protocol maintained in IpIo whose local
+ address is the same as Src.
+
+ This function is called when the caller needs the IpIo to send data to the
+ specified Src. The IpIo was added previously by IpIoAddIp().
+
+ @param[in, out] IpIo Pointer to the pointer of the IP_IO instance.
+ @param[in] IpVersion The version of the IP protocol to use, either
+ IPv4 or IPv6.
+ @param[in] Src The local IP address.
+
+ @return Pointer to the IP protocol can be used for sending purpose and its local
+ address is the same with Src.
+
+**/
+IP_IO_IP_INFO *
+EFIAPI
+IpIoFindSender (
+ IN OUT IP_IO **IpIo,
+ IN UINT8 IpVersion,
+ IN EFI_IP_ADDRESS *Src
+ )
+{
+ LIST_ENTRY *IpIoEntry;
+ IP_IO *IpIoPtr;
+ LIST_ENTRY *IpInfoEntry;
+ IP_IO_IP_INFO *IpInfo;
+
+ ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6));
+
+ NET_LIST_FOR_EACH (IpIoEntry, &mActiveIpIoList) {
+ IpIoPtr = NET_LIST_USER_STRUCT (IpIoEntry, IP_IO, Entry);
+
+ if (((*IpIo != NULL) && (*IpIo != IpIoPtr)) || (IpIoPtr->IpVersion != IpVersion)) {
+ continue;
+ }
+
+ NET_LIST_FOR_EACH (IpInfoEntry, &IpIoPtr->IpList) {
+ IpInfo = NET_LIST_USER_STRUCT (IpInfoEntry, IP_IO_IP_INFO, Entry);
+ if (IpInfo->IpVersion == IP_VERSION_4){
+
+ if (EFI_IP4_EQUAL (&IpInfo->Addr.v4, &Src->v4)) {
+ *IpIo = IpIoPtr;
+ return IpInfo;
+ }
+
+ } else {
+
+ if (EFI_IP6_EQUAL (&IpInfo->Addr.v6, &Src->v6)) {
+ *IpIo = IpIoPtr;
+ return IpInfo;
+ }
+ }
+
+ }
+ }
+
+ //
+ // No match.
+ //
+ return NULL;
+}
+
+
+/**
+ Get the ICMP error map information.
+
+ The ErrorStatus will be returned. The IsHard and Notify are optional. If they
+ are not NULL, this routine will fill them.
+
+ @param[in] IcmpError IcmpError Type.
+ @param[in] IpVersion The version of the IP protocol to use,
+ either IPv4 or IPv6.
+ @param[out] IsHard If TRUE, indicates that it is a hard error.
+ @param[out] Notify If TRUE, SockError needs to be notified.
+
+ @return ICMP Error Status, such as EFI_NETWORK_UNREACHABLE.
+
+**/
+EFI_STATUS
+EFIAPI
+IpIoGetIcmpErrStatus (
+ IN UINT8 IcmpError,
+ IN UINT8 IpVersion,
+ OUT BOOLEAN *IsHard OPTIONAL,
+ OUT BOOLEAN *Notify OPTIONAL
+ )
+{
+ if (IpVersion == IP_VERSION_4 ) {
+ ASSERT (IcmpError <= ICMP_ERR_PARAMPROB);
+
+ if (IsHard != NULL) {
+ *IsHard = mIcmpErrMap[IcmpError].IsHard;
+ }
+
+ if (Notify != NULL) {
+ *Notify = mIcmpErrMap[IcmpError].Notify;
+ }
+
+ switch (IcmpError) {
+ case ICMP_ERR_UNREACH_NET:
+ return EFI_NETWORK_UNREACHABLE;
+
+ case ICMP_ERR_TIMXCEED_INTRANS:
+ case ICMP_ERR_TIMXCEED_REASS:
+ case ICMP_ERR_UNREACH_HOST:
+ return EFI_HOST_UNREACHABLE;
+
+ case ICMP_ERR_UNREACH_PROTOCOL:
+ return EFI_PROTOCOL_UNREACHABLE;
+
+ case ICMP_ERR_UNREACH_PORT:
+ return EFI_PORT_UNREACHABLE;
+
+ case ICMP_ERR_MSGSIZE:
+ case ICMP_ERR_UNREACH_SRCFAIL:
+ case ICMP_ERR_QUENCH:
+ case ICMP_ERR_PARAMPROB:
+ return EFI_ICMP_ERROR;
+
+ default:
+ ASSERT (FALSE);
+ return EFI_UNSUPPORTED;
+ }
+
+ } else if (IpVersion == IP_VERSION_6) {
+
+ ASSERT (IcmpError <= ICMP6_ERR_PARAMPROB_IPV6OPTION);
+
+ if (IsHard != NULL) {
+ *IsHard = mIcmp6ErrMap[IcmpError].IsHard;
+ }
+
+ if (Notify != NULL) {
+ *Notify = mIcmp6ErrMap[IcmpError].Notify;
+ }
+
+ switch (IcmpError) {
+ case ICMP6_ERR_UNREACH_NET:
+ return EFI_NETWORK_UNREACHABLE;
+
+ case ICMP6_ERR_UNREACH_HOST:
+ case ICMP6_ERR_TIMXCEED_HOPLIMIT:
+ case ICMP6_ERR_TIMXCEED_REASS:
+ return EFI_HOST_UNREACHABLE;
+
+ case ICMP6_ERR_UNREACH_PROTOCOL:
+ return EFI_PROTOCOL_UNREACHABLE;
+
+ case ICMP6_ERR_UNREACH_PORT:
+ return EFI_PORT_UNREACHABLE;
+
+ case ICMP6_ERR_PACKAGE_TOOBIG:
+ case ICMP6_ERR_PARAMPROB_HEADER:
+ case ICMP6_ERR_PARAMPROB_NEXHEADER:
+ case ICMP6_ERR_PARAMPROB_IPV6OPTION:
+ return EFI_ICMP_ERROR;
+
+ default:
+ ASSERT (FALSE);
+ return EFI_UNSUPPORTED;
+ }
+
+ } else {
+ //
+ // Should never be here
+ //
+ ASSERT (FALSE);
+ return EFI_UNSUPPORTED;
+ }
+}
+
+
+/**
+ Refresh the remote peer's Neighbor Cache entries.
+
+ This function is called when the caller needs the IpIo to refresh the existing
+ IPv6 neighbor cache entries since the neighbor is considered reachable by the
+ node has recently received a confirmation that packets sent recently to the
+ neighbor were received by its IP layer.
+
+ @param[in] IpIo Pointer to an IP_IO instance
+ @param[in] Neighbor The IP address of the neighbor
+ @param[in] Timeout Time in 100-ns units that this entry will
+ remain in the neighbor cache. A value of
+ zero means that the entry is permanent.
+ A value of non-zero means that the entry is
+ dynamic and will be deleted after Timeout.
+
+ @retval EFI_SUCCESS The operation is completed successfully.
+ @retval EFI_NOT_STARTED The IpIo is not configured.
+ @retval EFI_INVALID_PARAMETER Neighbor Address is invalid.
+ @retval EFI_NOT_FOUND The neighbor cache entry is not in the
+ neighbor table.
+ @retval EFI_OUT_OF_RESOURCES Failed due to resource limit.
+
+**/
+EFI_STATUS
+IpIoRefreshNeighbor (
+ IN IP_IO *IpIo,
+ IN EFI_IP_ADDRESS *Neighbor,
+ IN UINT32 Timeout
+ )
+{
+ EFI_IP6_PROTOCOL *Ip;
+
+ if (!IpIo->IsConfigured || IpIo->IpVersion != IP_VERSION_6) {
+ return EFI_NOT_STARTED;
+ }
+
+ Ip = IpIo->Ip.Ip6;
+
+ return Ip->Neighbors (Ip, FALSE, &Neighbor->v6, NULL, Timeout, TRUE);
+}
+
diff --git a/Core/MdeModulePkg/Library/DxeIpIoLib/DxeIpIoLib.inf b/Core/MdeModulePkg/Library/DxeIpIoLib/DxeIpIoLib.inf
new file mode 100644
index 0000000000..f62a36fd50
--- /dev/null
+++ b/Core/MdeModulePkg/Library/DxeIpIoLib/DxeIpIoLib.inf
@@ -0,0 +1,53 @@
+## @file
+# This library instance provides IP services upon EFI IPv4/IPv6 Protocols.
+#
+# Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxeIpIoLib
+ MODULE_UNI_FILE = DxeIpIoLib.uni
+ FILE_GUID = A302F877-8625-425c-B1EC-7487B62C4FDA
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = IpIoLib|DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SAL_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ DxeIpIoLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+
+[LibraryClasses]
+ IpIoLib
+ BaseLib
+ DebugLib
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ BaseMemoryLib
+ DpcLib
+
+[Protocols]
+ gEfiIp4ProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiIp4ServiceBindingProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiIp6ProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiIp6ServiceBindingProtocolGuid ## SOMETIMES_CONSUMES
+
diff --git a/Core/MdeModulePkg/Library/DxeIpIoLib/DxeIpIoLib.uni b/Core/MdeModulePkg/Library/DxeIpIoLib/DxeIpIoLib.uni
new file mode 100644
index 0000000000..5545a50671
--- /dev/null
+++ b/Core/MdeModulePkg/Library/DxeIpIoLib/DxeIpIoLib.uni
Binary files differ
diff --git a/Core/MdeModulePkg/Library/DxeIpmiLibIpmiProtocol/DxeIpmiLibIpmiProtocol.c b/Core/MdeModulePkg/Library/DxeIpmiLibIpmiProtocol/DxeIpmiLibIpmiProtocol.c
new file mode 100644
index 0000000000..d15c6bd561
--- /dev/null
+++ b/Core/MdeModulePkg/Library/DxeIpmiLibIpmiProtocol/DxeIpmiLibIpmiProtocol.c
@@ -0,0 +1,81 @@
+/** @file
+ Implementation of Ipmi Library in DXE Phase for SMS.
+
+ Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiDxe.h>
+#include <Protocol/IpmiProtocol.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DebugLib.h>
+
+IPMI_PROTOCOL *mIpmiProtocol = NULL;
+
+/**
+ This service enables submitting commands via Ipmi.
+
+ @param[in] NetFunction Net function of the command.
+ @param[in] Command IPMI Command.
+ @param[in] RequestData Command Request Data.
+ @param[in] RequestDataSize Size of Command Request Data.
+ @param[out] ResponseData Command Response Data. The completion code is the first byte of response data.
+ @param[in, out] ResponseDataSize Size of Command Response Data.
+
+ @retval EFI_SUCCESS The command byte stream was successfully submit to the device and a response was successfully received.
+ @retval EFI_NOT_FOUND The command was not successfully sent to the device or a response was not successfully received from the device.
+ @retval EFI_NOT_READY Ipmi Device is not ready for Ipmi command access.
+ @retval EFI_DEVICE_ERROR Ipmi Device hardware error.
+ @retval EFI_TIMEOUT The command time out.
+ @retval EFI_UNSUPPORTED The command was not successfully sent to the device.
+ @retval EFI_OUT_OF_RESOURCES The resource allcation is out of resource or data size error.
+**/
+EFI_STATUS
+EFIAPI
+IpmiSubmitCommand (
+ IN UINT8 NetFunction,
+ IN UINT8 Command,
+ IN UINT8 *RequestData,
+ IN UINT32 RequestDataSize,
+ OUT UINT8 *ResponseData,
+ IN OUT UINT32 *ResponseDataSize
+ )
+{
+ EFI_STATUS Status;
+
+ if (mIpmiProtocol == NULL) {
+ Status = gBS->LocateProtocol (
+ &gIpmiProtocolGuid,
+ NULL,
+ (VOID **) &mIpmiProtocol
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Dxe Ipmi Protocol is not installed. So, IPMI device is not present.
+ //
+ DEBUG ((EFI_D_ERROR, "IpmiSubmitCommand in Dxe Phase under SMS Status - %r\n", Status));
+ return EFI_NOT_FOUND;
+ }
+ }
+
+ Status = mIpmiProtocol->IpmiSubmitCommand (
+ mIpmiProtocol,
+ NetFunction,
+ Command,
+ RequestData,
+ RequestDataSize,
+ ResponseData,
+ ResponseDataSize
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ return EFI_SUCCESS;
+}
diff --git a/Core/MdeModulePkg/Library/DxeIpmiLibIpmiProtocol/DxeIpmiLibIpmiProtocol.inf b/Core/MdeModulePkg/Library/DxeIpmiLibIpmiProtocol/DxeIpmiLibIpmiProtocol.inf
new file mode 100644
index 0000000000..5b56b39656
--- /dev/null
+++ b/Core/MdeModulePkg/Library/DxeIpmiLibIpmiProtocol/DxeIpmiLibIpmiProtocol.inf
@@ -0,0 +1,40 @@
+## @file
+# Instance of IPMI Library in DXE phase for SMS.
+#
+# Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php.
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxeIpmiLibIpmiProtocol
+ FILE_GUID = 62408AD5-4EAC-432B-AB9B-C4B85BFAED02
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = IpmiLib|DXE_RUNTIME_DRIVER DXE_DRIVER DXE_CORE UEFI_DRIVER UEFI_APPLICATION
+
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ DxeIpmiLibIpmiProtocol.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiBootServicesTableLib
+ DebugLib
+
+[Protocols]
+ gIpmiProtocolGuid ## SOMETIMES_CONSUMES
diff --git a/Core/MdeModulePkg/Library/DxeNetLib/DxeNetLib.c b/Core/MdeModulePkg/Library/DxeNetLib/DxeNetLib.c
new file mode 100644
index 0000000000..6a84847039
--- /dev/null
+++ b/Core/MdeModulePkg/Library/DxeNetLib/DxeNetLib.c
@@ -0,0 +1,3334 @@
+/** @file
+ Network library.
+
+Copyright (c) 2005 - 2015, Intel Corporation. All rights reserved.<BR>
+(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+**/
+
+#include <Uefi.h>
+
+#include <IndustryStandard/SmBios.h>
+
+#include <Protocol/DriverBinding.h>
+#include <Protocol/ServiceBinding.h>
+#include <Protocol/SimpleNetwork.h>
+#include <Protocol/ManagedNetwork.h>
+#include <Protocol/Ip4Config2.h>
+#include <Protocol/ComponentName.h>
+#include <Protocol/ComponentName2.h>
+
+#include <Guid/SmBios.h>
+
+#include <Library/NetLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/PrintLib.h>
+#include <Library/UefiLib.h>
+
+#define NIC_ITEM_CONFIG_SIZE sizeof (NIC_IP4_CONFIG_INFO) + sizeof (EFI_IP4_ROUTE_TABLE) * MAX_IP4_CONFIG_IN_VARIABLE
+#define DEFAULT_ZERO_START ((UINTN) ~0)
+
+//
+// All the supported IP4 maskes in host byte order.
+//
+GLOBAL_REMOVE_IF_UNREFERENCED IP4_ADDR gIp4AllMasks[IP4_MASK_NUM] = {
+ 0x00000000,
+ 0x80000000,
+ 0xC0000000,
+ 0xE0000000,
+ 0xF0000000,
+ 0xF8000000,
+ 0xFC000000,
+ 0xFE000000,
+
+ 0xFF000000,
+ 0xFF800000,
+ 0xFFC00000,
+ 0xFFE00000,
+ 0xFFF00000,
+ 0xFFF80000,
+ 0xFFFC0000,
+ 0xFFFE0000,
+
+ 0xFFFF0000,
+ 0xFFFF8000,
+ 0xFFFFC000,
+ 0xFFFFE000,
+ 0xFFFFF000,
+ 0xFFFFF800,
+ 0xFFFFFC00,
+ 0xFFFFFE00,
+
+ 0xFFFFFF00,
+ 0xFFFFFF80,
+ 0xFFFFFFC0,
+ 0xFFFFFFE0,
+ 0xFFFFFFF0,
+ 0xFFFFFFF8,
+ 0xFFFFFFFC,
+ 0xFFFFFFFE,
+ 0xFFFFFFFF,
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_IPv4_ADDRESS mZeroIp4Addr = {{0, 0, 0, 0}};
+
+//
+// Any error level digitally larger than mNetDebugLevelMax
+// will be silently discarded.
+//
+GLOBAL_REMOVE_IF_UNREFERENCED UINTN mNetDebugLevelMax = NETDEBUG_LEVEL_ERROR;
+GLOBAL_REMOVE_IF_UNREFERENCED UINT32 mSyslogPacketSeq = 0xDEADBEEF;
+
+//
+// You can change mSyslogDstMac mSyslogDstIp and mSyslogSrcIp
+// here to direct the syslog packets to the syslog deamon. The
+// default is broadcast to both the ethernet and IP.
+//
+GLOBAL_REMOVE_IF_UNREFERENCED UINT8 mSyslogDstMac[NET_ETHER_ADDR_LEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+GLOBAL_REMOVE_IF_UNREFERENCED UINT32 mSyslogDstIp = 0xffffffff;
+GLOBAL_REMOVE_IF_UNREFERENCED UINT32 mSyslogSrcIp = 0;
+
+GLOBAL_REMOVE_IF_UNREFERENCED CHAR8 *mMonthName[] = {
+ "Jan",
+ "Feb",
+ "Mar",
+ "Apr",
+ "May",
+ "Jun",
+ "Jul",
+ "Aug",
+ "Sep",
+ "Oct",
+ "Nov",
+ "Dec"
+};
+
+//
+// VLAN device path node template
+//
+GLOBAL_REMOVE_IF_UNREFERENCED VLAN_DEVICE_PATH mNetVlanDevicePathTemplate = {
+ {
+ MESSAGING_DEVICE_PATH,
+ MSG_VLAN_DP,
+ {
+ (UINT8) (sizeof (VLAN_DEVICE_PATH)),
+ (UINT8) ((sizeof (VLAN_DEVICE_PATH)) >> 8)
+ }
+ },
+ 0
+};
+
+/**
+ Locate the handles that support SNP, then open one of them
+ to send the syslog packets. The caller isn't required to close
+ the SNP after use because the SNP is opened by HandleProtocol.
+
+ @return The point to SNP if one is properly openned. Otherwise NULL
+
+**/
+EFI_SIMPLE_NETWORK_PROTOCOL *
+SyslogLocateSnp (
+ VOID
+ )
+{
+ EFI_SIMPLE_NETWORK_PROTOCOL *Snp;
+ EFI_STATUS Status;
+ EFI_HANDLE *Handles;
+ UINTN HandleCount;
+ UINTN Index;
+
+ //
+ // Locate the handles which has SNP installed.
+ //
+ Handles = NULL;
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiSimpleNetworkProtocolGuid,
+ NULL,
+ &HandleCount,
+ &Handles
+ );
+
+ if (EFI_ERROR (Status) || (HandleCount == 0)) {
+ return NULL;
+ }
+
+ //
+ // Try to open one of the ethernet SNP protocol to send packet
+ //
+ Snp = NULL;
+
+ for (Index = 0; Index < HandleCount; Index++) {
+ Status = gBS->HandleProtocol (
+ Handles[Index],
+ &gEfiSimpleNetworkProtocolGuid,
+ (VOID **) &Snp
+ );
+
+ if ((Status == EFI_SUCCESS) && (Snp != NULL) &&
+ (Snp->Mode->IfType == NET_IFTYPE_ETHERNET) &&
+ (Snp->Mode->MaxPacketSize >= NET_SYSLOG_PACKET_LEN)) {
+
+ break;
+ }
+
+ Snp = NULL;
+ }
+
+ FreePool (Handles);
+ return Snp;
+}
+
+/**
+ Transmit a syslog packet synchronously through SNP. The Packet
+ already has the ethernet header prepended. This function should
+ fill in the source MAC because it will try to locate a SNP each
+ time it is called to avoid the problem if SNP is unloaded.
+ This code snip is copied from MNP.
+
+ @param[in] Packet The Syslog packet
+ @param[in] Length The length of the packet
+
+ @retval EFI_DEVICE_ERROR Failed to locate a usable SNP protocol
+ @retval EFI_TIMEOUT Timeout happened to send the packet.
+ @retval EFI_SUCCESS Packet is sent.
+
+**/
+EFI_STATUS
+SyslogSendPacket (
+ IN CHAR8 *Packet,
+ IN UINT32 Length
+ )
+{
+ EFI_SIMPLE_NETWORK_PROTOCOL *Snp;
+ ETHER_HEAD *Ether;
+ EFI_STATUS Status;
+ EFI_EVENT TimeoutEvent;
+ UINT8 *TxBuf;
+
+ Snp = SyslogLocateSnp ();
+
+ if (Snp == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ Ether = (ETHER_HEAD *) Packet;
+ CopyMem (Ether->SrcMac, Snp->Mode->CurrentAddress.Addr, NET_ETHER_ADDR_LEN);
+
+ //
+ // Start the timeout event.
+ //
+ Status = gBS->CreateEvent (
+ EVT_TIMER,
+ TPL_NOTIFY,
+ NULL,
+ NULL,
+ &TimeoutEvent
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gBS->SetTimer (TimeoutEvent, TimerRelative, NET_SYSLOG_TX_TIMEOUT);
+
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+
+ for (;;) {
+ //
+ // Transmit the packet through SNP.
+ //
+ Status = Snp->Transmit (Snp, 0, Length, Packet, NULL, NULL, NULL);
+
+ if ((Status != EFI_SUCCESS) && (Status != EFI_NOT_READY)) {
+ Status = EFI_DEVICE_ERROR;
+ break;
+ }
+
+ //
+ // If Status is EFI_SUCCESS, the packet is put in the transmit queue.
+ // if Status is EFI_NOT_READY, the transmit engine of the network
+ // interface is busy. Both need to sync SNP.
+ //
+ TxBuf = NULL;
+
+ do {
+ //
+ // Get the recycled transmit buffer status.
+ //
+ Snp->GetStatus (Snp, NULL, (VOID **) &TxBuf);
+
+ if (!EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) {
+ Status = EFI_TIMEOUT;
+ break;
+ }
+
+ } while (TxBuf == NULL);
+
+ if ((Status == EFI_SUCCESS) || (Status == EFI_TIMEOUT)) {
+ break;
+ }
+
+ //
+ // Status is EFI_NOT_READY. Restart the timer event and
+ // call Snp->Transmit again.
+ //
+ gBS->SetTimer (TimeoutEvent, TimerRelative, NET_SYSLOG_TX_TIMEOUT);
+ }
+
+ gBS->SetTimer (TimeoutEvent, TimerCancel, 0);
+
+ON_EXIT:
+ gBS->CloseEvent (TimeoutEvent);
+ return Status;
+}
+
+/**
+ Build a syslog packet, including the Ethernet/Ip/Udp headers
+ and user's message.
+
+ @param[in] Level Syslog servity level
+ @param[in] Module The module that generates the log
+ @param[in] File The file that contains the current log
+ @param[in] Line The line of code in the File that contains the current log
+ @param[in] Message The log message
+ @param[in] BufLen The lenght of the Buf
+ @param[out] Buf The buffer to put the packet data
+
+ @return The length of the syslog packet built.
+
+**/
+UINT32
+SyslogBuildPacket (
+ IN UINT32 Level,
+ IN UINT8 *Module,
+ IN UINT8 *File,
+ IN UINT32 Line,
+ IN UINT8 *Message,
+ IN UINT32 BufLen,
+ OUT CHAR8 *Buf
+ )
+{
+ ETHER_HEAD *Ether;
+ IP4_HEAD *Ip4;
+ EFI_UDP_HEADER *Udp4;
+ EFI_TIME Time;
+ UINT32 Pri;
+ UINT32 Len;
+
+ //
+ // Fill in the Ethernet header. Leave alone the source MAC.
+ // SyslogSendPacket will fill in the address for us.
+ //
+ Ether = (ETHER_HEAD *) Buf;
+ CopyMem (Ether->DstMac, mSyslogDstMac, NET_ETHER_ADDR_LEN);
+ ZeroMem (Ether->SrcMac, NET_ETHER_ADDR_LEN);
+
+ Ether->EtherType = HTONS (0x0800); // IPv4 protocol
+
+ Buf += sizeof (ETHER_HEAD);
+ BufLen -= sizeof (ETHER_HEAD);
+
+ //
+ // Fill in the IP header
+ //
+ Ip4 = (IP4_HEAD *) Buf;
+ Ip4->HeadLen = 5;
+ Ip4->Ver = 4;
+ Ip4->Tos = 0;
+ Ip4->TotalLen = 0;
+ Ip4->Id = (UINT16) mSyslogPacketSeq;
+ Ip4->Fragment = 0;
+ Ip4->Ttl = 16;
+ Ip4->Protocol = 0x11;
+ Ip4->Checksum = 0;
+ Ip4->Src = mSyslogSrcIp;
+ Ip4->Dst = mSyslogDstIp;
+
+ Buf += sizeof (IP4_HEAD);
+ BufLen -= sizeof (IP4_HEAD);
+
+ //
+ // Fill in the UDP header, Udp checksum is optional. Leave it zero.
+ //
+ Udp4 = (EFI_UDP_HEADER *) Buf;
+ Udp4->SrcPort = HTONS (514);
+ Udp4->DstPort = HTONS (514);
+ Udp4->Length = 0;
+ Udp4->Checksum = 0;
+
+ Buf += sizeof (EFI_UDP_HEADER);
+ BufLen -= sizeof (EFI_UDP_HEADER);
+
+ //
+ // Build the syslog message body with <PRI> Timestamp machine module Message
+ //
+ Pri = ((NET_SYSLOG_FACILITY & 31) << 3) | (Level & 7);
+ gRT->GetTime (&Time, NULL);
+ ASSERT ((Time.Month <= 12) && (Time.Month >= 1));
+
+ //
+ // Use %a to format the ASCII strings, %s to format UNICODE strings
+ //
+ Len = 0;
+ Len += (UINT32) AsciiSPrint (
+ Buf,
+ BufLen,
+ "<%d> %a %d %d:%d:%d ",
+ Pri,
+ mMonthName [Time.Month-1],
+ Time.Day,
+ Time.Hour,
+ Time.Minute,
+ Time.Second
+ );
+ Len--;
+
+ Len += (UINT32) AsciiSPrint (
+ Buf + Len,
+ BufLen - Len,
+ "Tiano %a: %a (Line: %d File: %a)",
+ Module,
+ Message,
+ Line,
+ File
+ );
+ Len--;
+
+ //
+ // OK, patch the IP length/checksum and UDP length fields.
+ //
+ Len += sizeof (EFI_UDP_HEADER);
+ Udp4->Length = HTONS ((UINT16) Len);
+
+ Len += sizeof (IP4_HEAD);
+ Ip4->TotalLen = HTONS ((UINT16) Len);
+ Ip4->Checksum = (UINT16) (~NetblockChecksum ((UINT8 *) Ip4, sizeof (IP4_HEAD)));
+
+ return Len + sizeof (ETHER_HEAD);
+}
+
+/**
+ Allocate a buffer, then format the message to it. This is a
+ help function for the NET_DEBUG_XXX macros. The PrintArg of
+ these macros treats the variable length print parameters as a
+ single parameter, and pass it to the NetDebugASPrint. For
+ example, NET_DEBUG_TRACE ("Tcp", ("State transit to %a\n", Name))
+ if extracted to:
+
+ NetDebugOutput (
+ NETDEBUG_LEVEL_TRACE,
+ "Tcp",
+ __FILE__,
+ __LINE__,
+ NetDebugASPrint ("State transit to %a\n", Name)
+ )
+
+ @param Format The ASCII format string.
+ @param ... The variable length parameter whose format is determined
+ by the Format string.
+
+ @return The buffer containing the formatted message,
+ or NULL if failed to allocate memory.
+
+**/
+CHAR8 *
+EFIAPI
+NetDebugASPrint (
+ IN CHAR8 *Format,
+ ...
+ )
+{
+ VA_LIST Marker;
+ CHAR8 *Buf;
+
+ Buf = (CHAR8 *) AllocatePool (NET_DEBUG_MSG_LEN);
+
+ if (Buf == NULL) {
+ return NULL;
+ }
+
+ VA_START (Marker, Format);
+ AsciiVSPrint (Buf, NET_DEBUG_MSG_LEN, Format, Marker);
+ VA_END (Marker);
+
+ return Buf;
+}
+
+/**
+ Builds an UDP4 syslog packet and send it using SNP.
+
+ This function will locate a instance of SNP then send the message through it.
+ Because it isn't open the SNP BY_DRIVER, apply caution when using it.
+
+ @param Level The servity level of the message.
+ @param Module The Moudle that generates the log.
+ @param File The file that contains the log.
+ @param Line The exact line that contains the log.
+ @param Message The user message to log.
+
+ @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for the packet
+ @retval EFI_SUCCESS The log is discard because that it is more verbose
+ than the mNetDebugLevelMax. Or, it has been sent out.
+**/
+EFI_STATUS
+EFIAPI
+NetDebugOutput (
+ IN UINT32 Level,
+ IN UINT8 *Module,
+ IN UINT8 *File,
+ IN UINT32 Line,
+ IN UINT8 *Message
+ )
+{
+ CHAR8 *Packet;
+ UINT32 Len;
+ EFI_STATUS Status;
+
+ //
+ // Check whether the message should be sent out
+ //
+ if (Message == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Level > mNetDebugLevelMax) {
+ Status = EFI_SUCCESS;
+ goto ON_EXIT;
+ }
+
+ //
+ // Allocate a maxium of 1024 bytes, the caller should ensure
+ // that the message plus the ethernet/ip/udp header is shorter
+ // than this
+ //
+ Packet = (CHAR8 *) AllocatePool (NET_SYSLOG_PACKET_LEN);
+
+ if (Packet == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_EXIT;
+ }
+
+ //
+ // Build the message: Ethernet header + IP header + Udp Header + user data
+ //
+ Len = SyslogBuildPacket (
+ Level,
+ Module,
+ File,
+ Line,
+ Message,
+ NET_SYSLOG_PACKET_LEN,
+ Packet
+ );
+
+ mSyslogPacketSeq++;
+ Status = SyslogSendPacket (Packet, Len);
+ FreePool (Packet);
+
+ON_EXIT:
+ FreePool (Message);
+ return Status;
+}
+/**
+ Return the length of the mask.
+
+ Return the length of the mask, the correct value is from 0 to 32.
+ If the mask is invalid, return the invalid length 33, which is IP4_MASK_NUM.
+ NetMask is in the host byte order.
+
+ @param[in] NetMask The netmask to get the length from.
+
+ @return The length of the netmask, IP4_MASK_NUM if the mask is invalid.
+
+**/
+INTN
+EFIAPI
+NetGetMaskLength (
+ IN IP4_ADDR NetMask
+ )
+{
+ INTN Index;
+
+ for (Index = 0; Index < IP4_MASK_NUM; Index++) {
+ if (NetMask == gIp4AllMasks[Index]) {
+ break;
+ }
+ }
+
+ return Index;
+}
+
+
+
+/**
+ Return the class of the IP address, such as class A, B, C.
+ Addr is in host byte order.
+
+ The address of class A starts with 0.
+ If the address belong to class A, return IP4_ADDR_CLASSA.
+ The address of class B starts with 10.
+ If the address belong to class B, return IP4_ADDR_CLASSB.
+ The address of class C starts with 110.
+ If the address belong to class C, return IP4_ADDR_CLASSC.
+ The address of class D starts with 1110.
+ If the address belong to class D, return IP4_ADDR_CLASSD.
+ The address of class E starts with 1111.
+ If the address belong to class E, return IP4_ADDR_CLASSE.
+
+
+ @param[in] Addr The address to get the class from.
+
+ @return IP address class, such as IP4_ADDR_CLASSA.
+
+**/
+INTN
+EFIAPI
+NetGetIpClass (
+ IN IP4_ADDR Addr
+ )
+{
+ UINT8 ByteOne;
+
+ ByteOne = (UINT8) (Addr >> 24);
+
+ if ((ByteOne & 0x80) == 0) {
+ return IP4_ADDR_CLASSA;
+
+ } else if ((ByteOne & 0xC0) == 0x80) {
+ return IP4_ADDR_CLASSB;
+
+ } else if ((ByteOne & 0xE0) == 0xC0) {
+ return IP4_ADDR_CLASSC;
+
+ } else if ((ByteOne & 0xF0) == 0xE0) {
+ return IP4_ADDR_CLASSD;
+
+ } else {
+ return IP4_ADDR_CLASSE;
+
+ }
+}
+
+
+/**
+ Check whether the IP is a valid unicast address according to
+ the netmask. If NetMask is zero, use the IP address's class to get the default mask.
+
+ If Ip is 0, IP is not a valid unicast address.
+ Class D address is used for multicasting and class E address is reserved for future. If Ip
+ belongs to class D or class E, IP is not a valid unicast address.
+ If all bits of the host address of IP are 0 or 1, IP is also not a valid unicast address.
+
+ @param[in] Ip The IP to check against.
+ @param[in] NetMask The mask of the IP.
+
+ @return TRUE if IP is a valid unicast address on the network, otherwise FALSE.
+
+**/
+BOOLEAN
+EFIAPI
+NetIp4IsUnicast (
+ IN IP4_ADDR Ip,
+ IN IP4_ADDR NetMask
+ )
+{
+ INTN Class;
+
+ Class = NetGetIpClass (Ip);
+
+ if ((Ip == 0) || (Class >= IP4_ADDR_CLASSD)) {
+ return FALSE;
+ }
+
+ if (NetMask == 0) {
+ NetMask = gIp4AllMasks[Class << 3];
+ }
+
+ if (((Ip &~NetMask) == ~NetMask) || ((Ip &~NetMask) == 0)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ Check whether the incoming IPv6 address is a valid unicast address.
+
+ If the address is a multicast address has binary 0xFF at the start, it is not
+ a valid unicast address. If the address is unspecified ::, it is not a valid
+ unicast address to be assigned to any node. If the address is loopback address
+ ::1, it is also not a valid unicast address to be assigned to any physical
+ interface.
+
+ @param[in] Ip6 The IPv6 address to check against.
+
+ @return TRUE if Ip6 is a valid unicast address on the network, otherwise FALSE.
+
+**/
+BOOLEAN
+EFIAPI
+NetIp6IsValidUnicast (
+ IN EFI_IPv6_ADDRESS *Ip6
+ )
+{
+ UINT8 Byte;
+ UINT8 Index;
+
+ if (Ip6->Addr[0] == 0xFF) {
+ return FALSE;
+ }
+
+ for (Index = 0; Index < 15; Index++) {
+ if (Ip6->Addr[Index] != 0) {
+ return TRUE;
+ }
+ }
+
+ Byte = Ip6->Addr[Index];
+
+ if (Byte == 0x0 || Byte == 0x1) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ Check whether the incoming Ipv6 address is the unspecified address or not.
+
+ @param[in] Ip6 - Ip6 address, in network order.
+
+ @retval TRUE - Yes, unspecified
+ @retval FALSE - No
+
+**/
+BOOLEAN
+EFIAPI
+NetIp6IsUnspecifiedAddr (
+ IN EFI_IPv6_ADDRESS *Ip6
+ )
+{
+ UINT8 Index;
+
+ for (Index = 0; Index < 16; Index++) {
+ if (Ip6->Addr[Index] != 0) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+/**
+ Check whether the incoming Ipv6 address is a link-local address.
+
+ @param[in] Ip6 - Ip6 address, in network order.
+
+ @retval TRUE - Yes, link-local address
+ @retval FALSE - No
+
+**/
+BOOLEAN
+EFIAPI
+NetIp6IsLinkLocalAddr (
+ IN EFI_IPv6_ADDRESS *Ip6
+ )
+{
+ UINT8 Index;
+
+ ASSERT (Ip6 != NULL);
+
+ if (Ip6->Addr[0] != 0xFE) {
+ return FALSE;
+ }
+
+ if (Ip6->Addr[1] != 0x80) {
+ return FALSE;
+ }
+
+ for (Index = 2; Index < 8; Index++) {
+ if (Ip6->Addr[Index] != 0) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+/**
+ Check whether the Ipv6 address1 and address2 are on the connected network.
+
+ @param[in] Ip1 - Ip6 address1, in network order.
+ @param[in] Ip2 - Ip6 address2, in network order.
+ @param[in] PrefixLength - The prefix length of the checking net.
+
+ @retval TRUE - Yes, connected.
+ @retval FALSE - No.
+
+**/
+BOOLEAN
+EFIAPI
+NetIp6IsNetEqual (
+ EFI_IPv6_ADDRESS *Ip1,
+ EFI_IPv6_ADDRESS *Ip2,
+ UINT8 PrefixLength
+ )
+{
+ UINT8 Byte;
+ UINT8 Bit;
+ UINT8 Mask;
+
+ ASSERT ((Ip1 != NULL) && (Ip2 != NULL) && (PrefixLength < IP6_PREFIX_NUM));
+
+ if (PrefixLength == 0) {
+ return TRUE;
+ }
+
+ Byte = (UINT8) (PrefixLength / 8);
+ Bit = (UINT8) (PrefixLength % 8);
+
+ if (CompareMem (Ip1, Ip2, Byte) != 0) {
+ return FALSE;
+ }
+
+ if (Bit > 0) {
+ Mask = (UINT8) (0xFF << (8 - Bit));
+
+ ASSERT (Byte < 16);
+ if ((Ip1->Addr[Byte] & Mask) != (Ip2->Addr[Byte] & Mask)) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+/**
+ Switches the endianess of an IPv6 address
+
+ This function swaps the bytes in a 128-bit IPv6 address to switch the value
+ from little endian to big endian or vice versa. The byte swapped value is
+ returned.
+
+ @param Ip6 Points to an IPv6 address
+
+ @return The byte swapped IPv6 address.
+
+**/
+EFI_IPv6_ADDRESS *
+EFIAPI
+Ip6Swap128 (
+ EFI_IPv6_ADDRESS *Ip6
+ )
+{
+ UINT64 High;
+ UINT64 Low;
+
+ CopyMem (&High, Ip6, sizeof (UINT64));
+ CopyMem (&Low, &Ip6->Addr[8], sizeof (UINT64));
+
+ High = SwapBytes64 (High);
+ Low = SwapBytes64 (Low);
+
+ CopyMem (Ip6, &Low, sizeof (UINT64));
+ CopyMem (&Ip6->Addr[8], &High, sizeof (UINT64));
+
+ return Ip6;
+}
+
+/**
+ Initialize a random seed using current time and monotonic count.
+
+ Get current time and monotonic count first. Then initialize a random seed
+ based on some basic mathematics operation on the hour, day, minute, second,
+ nanosecond and year of the current time and the monotonic count value.
+
+ @return The random seed initialized with current time.
+
+**/
+UINT32
+EFIAPI
+NetRandomInitSeed (
+ VOID
+ )
+{
+ EFI_TIME Time;
+ UINT32 Seed;
+ UINT64 MonotonicCount;
+
+ gRT->GetTime (&Time, NULL);
+ Seed = (~Time.Hour << 24 | Time.Day << 16 | Time.Minute << 8 | Time.Second);
+ Seed ^= Time.Nanosecond;
+ Seed ^= Time.Year << 7;
+
+ gBS->GetNextMonotonicCount (&MonotonicCount);
+ Seed += (UINT32) MonotonicCount;
+
+ return Seed;
+}
+
+
+/**
+ Extract a UINT32 from a byte stream.
+
+ Copy a UINT32 from a byte stream, then converts it from Network
+ byte order to host byte order. Use this function to avoid alignment error.
+
+ @param[in] Buf The buffer to extract the UINT32.
+
+ @return The UINT32 extracted.
+
+**/
+UINT32
+EFIAPI
+NetGetUint32 (
+ IN UINT8 *Buf
+ )
+{
+ UINT32 Value;
+
+ CopyMem (&Value, Buf, sizeof (UINT32));
+ return NTOHL (Value);
+}
+
+
+/**
+ Put a UINT32 to the byte stream in network byte order.
+
+ Converts a UINT32 from host byte order to network byte order. Then copy it to the
+ byte stream.
+
+ @param[in, out] Buf The buffer to put the UINT32.
+ @param[in] Data The data to be converted and put into the byte stream.
+
+**/
+VOID
+EFIAPI
+NetPutUint32 (
+ IN OUT UINT8 *Buf,
+ IN UINT32 Data
+ )
+{
+ Data = HTONL (Data);
+ CopyMem (Buf, &Data, sizeof (UINT32));
+}
+
+
+/**
+ Remove the first node entry on the list, and return the removed node entry.
+
+ Removes the first node Entry from a doubly linked list. It is up to the caller of
+ this function to release the memory used by the first node if that is required. On
+ exit, the removed node is returned.
+
+ If Head is NULL, then ASSERT().
+ If Head was not initialized, then ASSERT().
+ If PcdMaximumLinkedListLength is not zero, and the number of nodes in the
+ linked list including the head node is greater than or equal to PcdMaximumLinkedListLength,
+ then ASSERT().
+
+ @param[in, out] Head The list header.
+
+ @return The first node entry that is removed from the list, NULL if the list is empty.
+
+**/
+LIST_ENTRY *
+EFIAPI
+NetListRemoveHead (
+ IN OUT LIST_ENTRY *Head
+ )
+{
+ LIST_ENTRY *First;
+
+ ASSERT (Head != NULL);
+
+ if (IsListEmpty (Head)) {
+ return NULL;
+ }
+
+ First = Head->ForwardLink;
+ Head->ForwardLink = First->ForwardLink;
+ First->ForwardLink->BackLink = Head;
+
+ DEBUG_CODE (
+ First->ForwardLink = (LIST_ENTRY *) NULL;
+ First->BackLink = (LIST_ENTRY *) NULL;
+ );
+
+ return First;
+}
+
+
+/**
+ Remove the last node entry on the list and and return the removed node entry.
+
+ Removes the last node entry from a doubly linked list. It is up to the caller of
+ this function to release the memory used by the first node if that is required. On
+ exit, the removed node is returned.
+
+ If Head is NULL, then ASSERT().
+ If Head was not initialized, then ASSERT().
+ If PcdMaximumLinkedListLength is not zero, and the number of nodes in the
+ linked list including the head node is greater than or equal to PcdMaximumLinkedListLength,
+ then ASSERT().
+
+ @param[in, out] Head The list head.
+
+ @return The last node entry that is removed from the list, NULL if the list is empty.
+
+**/
+LIST_ENTRY *
+EFIAPI
+NetListRemoveTail (
+ IN OUT LIST_ENTRY *Head
+ )
+{
+ LIST_ENTRY *Last;
+
+ ASSERT (Head != NULL);
+
+ if (IsListEmpty (Head)) {
+ return NULL;
+ }
+
+ Last = Head->BackLink;
+ Head->BackLink = Last->BackLink;
+ Last->BackLink->ForwardLink = Head;
+
+ DEBUG_CODE (
+ Last->ForwardLink = (LIST_ENTRY *) NULL;
+ Last->BackLink = (LIST_ENTRY *) NULL;
+ );
+
+ return Last;
+}
+
+
+/**
+ Insert a new node entry after a designated node entry of a doubly linked list.
+
+ Inserts a new node entry donated by NewEntry after the node entry donated by PrevEntry
+ of the doubly linked list.
+
+ @param[in, out] PrevEntry The previous entry to insert after.
+ @param[in, out] NewEntry The new entry to insert.
+
+**/
+VOID
+EFIAPI
+NetListInsertAfter (
+ IN OUT LIST_ENTRY *PrevEntry,
+ IN OUT LIST_ENTRY *NewEntry
+ )
+{
+ NewEntry->BackLink = PrevEntry;
+ NewEntry->ForwardLink = PrevEntry->ForwardLink;
+ PrevEntry->ForwardLink->BackLink = NewEntry;
+ PrevEntry->ForwardLink = NewEntry;
+}
+
+
+/**
+ Insert a new node entry before a designated node entry of a doubly linked list.
+
+ Inserts a new node entry donated by NewEntry after the node entry donated by PostEntry
+ of the doubly linked list.
+
+ @param[in, out] PostEntry The entry to insert before.
+ @param[in, out] NewEntry The new entry to insert.
+
+**/
+VOID
+EFIAPI
+NetListInsertBefore (
+ IN OUT LIST_ENTRY *PostEntry,
+ IN OUT LIST_ENTRY *NewEntry
+ )
+{
+ NewEntry->ForwardLink = PostEntry;
+ NewEntry->BackLink = PostEntry->BackLink;
+ PostEntry->BackLink->ForwardLink = NewEntry;
+ PostEntry->BackLink = NewEntry;
+}
+
+/**
+ Safe destroy nodes in a linked list, and return the length of the list after all possible operations finished.
+
+ Destroy network child instance list by list traversals is not safe due to graph dependencies between nodes.
+ This function performs a safe traversal to destroy these nodes by checking to see if the node being destroyed
+ has been removed from the list or not.
+ If it has been removed, then restart the traversal from the head.
+ If it hasn't been removed, then continue with the next node directly.
+ This function will end the iterate and return the CallBack's last return value if error happens,
+ or retrun EFI_SUCCESS if 2 complete passes are made with no changes in the number of children in the list.
+
+ @param[in] List The head of the list.
+ @param[in] CallBack Pointer to the callback function to destroy one node in the list.
+ @param[in] Context Pointer to the callback function's context: corresponds to the
+ parameter Context in NET_DESTROY_LINK_LIST_CALLBACK.
+ @param[out] ListLength The length of the link list if the function returns successfully.
+
+ @retval EFI_SUCCESS Two complete passes are made with no changes in the number of children.
+ @retval EFI_INVALID_PARAMETER The input parameter is invalid.
+ @retval Others Return the CallBack's last return value.
+
+**/
+EFI_STATUS
+EFIAPI
+NetDestroyLinkList (
+ IN LIST_ENTRY *List,
+ IN NET_DESTROY_LINK_LIST_CALLBACK CallBack,
+ IN VOID *Context, OPTIONAL
+ OUT UINTN *ListLength OPTIONAL
+ )
+{
+ UINTN PreviousLength;
+ LIST_ENTRY *Entry;
+ LIST_ENTRY *Ptr;
+ UINTN Length;
+ EFI_STATUS Status;
+
+ if (List == NULL || CallBack == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Length = 0;
+ do {
+ PreviousLength = Length;
+ Entry = GetFirstNode (List);
+ while (!IsNull (List, Entry)) {
+ Status = CallBack (Entry, Context);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Walk through the list to see whether the Entry has been removed or not.
+ // If the Entry still exists, just try to destroy the next one.
+ // If not, go back to the start point to iterate the list again.
+ //
+ for (Ptr = List->ForwardLink; Ptr != List; Ptr = Ptr->ForwardLink) {
+ if (Ptr == Entry) {
+ break;
+ }
+ }
+ if (Ptr == Entry) {
+ Entry = GetNextNode (List, Entry);
+ } else {
+ Entry = GetFirstNode (List);
+ }
+ }
+ for (Length = 0, Ptr = List->ForwardLink; Ptr != List; Length++, Ptr = Ptr->ForwardLink);
+ } while (Length != PreviousLength);
+
+ if (ListLength != NULL) {
+ *ListLength = Length;
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ This function checks the input Handle to see if it's one of these handles in ChildHandleBuffer.
+
+ @param[in] Handle Handle to be checked.
+ @param[in] NumberOfChildren Number of Handles in ChildHandleBuffer.
+ @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL
+ if NumberOfChildren is 0.
+
+ @retval TURE Found the input Handle in ChildHandleBuffer.
+ @retval FALSE Can't find the input Handle in ChildHandleBuffer.
+
+**/
+BOOLEAN
+EFIAPI
+NetIsInHandleBuffer (
+ IN EFI_HANDLE Handle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
+ )
+{
+ UINTN Index;
+
+ if (NumberOfChildren == 0 || ChildHandleBuffer == NULL) {
+ return FALSE;
+ }
+
+ for (Index = 0; Index < NumberOfChildren; Index++) {
+ if (Handle == ChildHandleBuffer[Index]) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+
+/**
+ Initialize the netmap. Netmap is a reposity to keep the <Key, Value> pairs.
+
+ Initialize the forward and backward links of two head nodes donated by Map->Used
+ and Map->Recycled of two doubly linked lists.
+ Initializes the count of the <Key, Value> pairs in the netmap to zero.
+
+ If Map is NULL, then ASSERT().
+ If the address of Map->Used is NULL, then ASSERT().
+ If the address of Map->Recycled is NULl, then ASSERT().
+
+ @param[in, out] Map The netmap to initialize.
+
+**/
+VOID
+EFIAPI
+NetMapInit (
+ IN OUT NET_MAP *Map
+ )
+{
+ ASSERT (Map != NULL);
+
+ InitializeListHead (&Map->Used);
+ InitializeListHead (&Map->Recycled);
+ Map->Count = 0;
+}
+
+
+/**
+ To clean up the netmap, that is, release allocated memories.
+
+ Removes all nodes of the Used doubly linked list and free memory of all related netmap items.
+ Removes all nodes of the Recycled doubly linked list and free memory of all related netmap items.
+ The number of the <Key, Value> pairs in the netmap is set to be zero.
+
+ If Map is NULL, then ASSERT().
+
+ @param[in, out] Map The netmap to clean up.
+
+**/
+VOID
+EFIAPI
+NetMapClean (
+ IN OUT NET_MAP *Map
+ )
+{
+ NET_MAP_ITEM *Item;
+ LIST_ENTRY *Entry;
+ LIST_ENTRY *Next;
+
+ ASSERT (Map != NULL);
+
+ NET_LIST_FOR_EACH_SAFE (Entry, Next, &Map->Used) {
+ Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link);
+
+ RemoveEntryList (&Item->Link);
+ Map->Count--;
+
+ gBS->FreePool (Item);
+ }
+
+ ASSERT ((Map->Count == 0) && IsListEmpty (&Map->Used));
+
+ NET_LIST_FOR_EACH_SAFE (Entry, Next, &Map->Recycled) {
+ Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link);
+
+ RemoveEntryList (&Item->Link);
+ gBS->FreePool (Item);
+ }
+
+ ASSERT (IsListEmpty (&Map->Recycled));
+}
+
+
+/**
+ Test whether the netmap is empty and return true if it is.
+
+ If the number of the <Key, Value> pairs in the netmap is zero, return TRUE.
+
+ If Map is NULL, then ASSERT().
+
+
+ @param[in] Map The net map to test.
+
+ @return TRUE if the netmap is empty, otherwise FALSE.
+
+**/
+BOOLEAN
+EFIAPI
+NetMapIsEmpty (
+ IN NET_MAP *Map
+ )
+{
+ ASSERT (Map != NULL);
+ return (BOOLEAN) (Map->Count == 0);
+}
+
+
+/**
+ Return the number of the <Key, Value> pairs in the netmap.
+
+ @param[in] Map The netmap to get the entry number.
+
+ @return The entry number in the netmap.
+
+**/
+UINTN
+EFIAPI
+NetMapGetCount (
+ IN NET_MAP *Map
+ )
+{
+ return Map->Count;
+}
+
+
+/**
+ Return one allocated item.
+
+ If the Recycled doubly linked list of the netmap is empty, it will try to allocate
+ a batch of items if there are enough resources and add corresponding nodes to the begining
+ of the Recycled doubly linked list of the netmap. Otherwise, it will directly remove
+ the fist node entry of the Recycled doubly linked list and return the corresponding item.
+
+ If Map is NULL, then ASSERT().
+
+ @param[in, out] Map The netmap to allocate item for.
+
+ @return The allocated item. If NULL, the
+ allocation failed due to resource limit.
+
+**/
+NET_MAP_ITEM *
+NetMapAllocItem (
+ IN OUT NET_MAP *Map
+ )
+{
+ NET_MAP_ITEM *Item;
+ LIST_ENTRY *Head;
+ UINTN Index;
+
+ ASSERT (Map != NULL);
+
+ Head = &Map->Recycled;
+
+ if (IsListEmpty (Head)) {
+ for (Index = 0; Index < NET_MAP_INCREAMENT; Index++) {
+ Item = AllocatePool (sizeof (NET_MAP_ITEM));
+
+ if (Item == NULL) {
+ if (Index == 0) {
+ return NULL;
+ }
+
+ break;
+ }
+
+ InsertHeadList (Head, &Item->Link);
+ }
+ }
+
+ Item = NET_LIST_HEAD (Head, NET_MAP_ITEM, Link);
+ NetListRemoveHead (Head);
+
+ return Item;
+}
+
+
+/**
+ Allocate an item to save the <Key, Value> pair to the head of the netmap.
+
+ Allocate an item to save the <Key, Value> pair and add corresponding node entry
+ to the beginning of the Used doubly linked list. The number of the <Key, Value>
+ pairs in the netmap increase by 1.
+
+ If Map is NULL, then ASSERT().
+
+ @param[in, out] Map The netmap to insert into.
+ @param[in] Key The user's key.
+ @param[in] Value The user's value for the key.
+
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate the memory for the item.
+ @retval EFI_SUCCESS The item is inserted to the head.
+
+**/
+EFI_STATUS
+EFIAPI
+NetMapInsertHead (
+ IN OUT NET_MAP *Map,
+ IN VOID *Key,
+ IN VOID *Value OPTIONAL
+ )
+{
+ NET_MAP_ITEM *Item;
+
+ ASSERT (Map != NULL);
+
+ Item = NetMapAllocItem (Map);
+
+ if (Item == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Item->Key = Key;
+ Item->Value = Value;
+ InsertHeadList (&Map->Used, &Item->Link);
+
+ Map->Count++;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Allocate an item to save the <Key, Value> pair to the tail of the netmap.
+
+ Allocate an item to save the <Key, Value> pair and add corresponding node entry
+ to the tail of the Used doubly linked list. The number of the <Key, Value>
+ pairs in the netmap increase by 1.
+
+ If Map is NULL, then ASSERT().
+
+ @param[in, out] Map The netmap to insert into.
+ @param[in] Key The user's key.
+ @param[in] Value The user's value for the key.
+
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate the memory for the item.
+ @retval EFI_SUCCESS The item is inserted to the tail.
+
+**/
+EFI_STATUS
+EFIAPI
+NetMapInsertTail (
+ IN OUT NET_MAP *Map,
+ IN VOID *Key,
+ IN VOID *Value OPTIONAL
+ )
+{
+ NET_MAP_ITEM *Item;
+
+ ASSERT (Map != NULL);
+
+ Item = NetMapAllocItem (Map);
+
+ if (Item == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Item->Key = Key;
+ Item->Value = Value;
+ InsertTailList (&Map->Used, &Item->Link);
+
+ Map->Count++;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Check whether the item is in the Map and return TRUE if it is.
+
+ @param[in] Map The netmap to search within.
+ @param[in] Item The item to search.
+
+ @return TRUE if the item is in the netmap, otherwise FALSE.
+
+**/
+BOOLEAN
+NetItemInMap (
+ IN NET_MAP *Map,
+ IN NET_MAP_ITEM *Item
+ )
+{
+ LIST_ENTRY *ListEntry;
+
+ NET_LIST_FOR_EACH (ListEntry, &Map->Used) {
+ if (ListEntry == &Item->Link) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+
+/**
+ Find the key in the netmap and returns the point to the item contains the Key.
+
+ Iterate the Used doubly linked list of the netmap to get every item. Compare the key of every
+ item with the key to search. It returns the point to the item contains the Key if found.
+
+ If Map is NULL, then ASSERT().
+
+ @param[in] Map The netmap to search within.
+ @param[in] Key The key to search.
+
+ @return The point to the item contains the Key, or NULL if Key isn't in the map.
+
+**/
+NET_MAP_ITEM *
+EFIAPI
+NetMapFindKey (
+ IN NET_MAP *Map,
+ IN VOID *Key
+ )
+{
+ LIST_ENTRY *Entry;
+ NET_MAP_ITEM *Item;
+
+ ASSERT (Map != NULL);
+
+ NET_LIST_FOR_EACH (Entry, &Map->Used) {
+ Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link);
+
+ if (Item->Key == Key) {
+ return Item;
+ }
+ }
+
+ return NULL;
+}
+
+
+/**
+ Remove the node entry of the item from the netmap and return the key of the removed item.
+
+ Remove the node entry of the item from the Used doubly linked list of the netmap.
+ The number of the <Key, Value> pairs in the netmap decrease by 1. Then add the node
+ entry of the item to the Recycled doubly linked list of the netmap. If Value is not NULL,
+ Value will point to the value of the item. It returns the key of the removed item.
+
+ If Map is NULL, then ASSERT().
+ If Item is NULL, then ASSERT().
+ if item in not in the netmap, then ASSERT().
+
+ @param[in, out] Map The netmap to remove the item from.
+ @param[in, out] Item The item to remove.
+ @param[out] Value The variable to receive the value if not NULL.
+
+ @return The key of the removed item.
+
+**/
+VOID *
+EFIAPI
+NetMapRemoveItem (
+ IN OUT NET_MAP *Map,
+ IN OUT NET_MAP_ITEM *Item,
+ OUT VOID **Value OPTIONAL
+ )
+{
+ ASSERT ((Map != NULL) && (Item != NULL));
+ ASSERT (NetItemInMap (Map, Item));
+
+ RemoveEntryList (&Item->Link);
+ Map->Count--;
+ InsertHeadList (&Map->Recycled, &Item->Link);
+
+ if (Value != NULL) {
+ *Value = Item->Value;
+ }
+
+ return Item->Key;
+}
+
+
+/**
+ Remove the first node entry on the netmap and return the key of the removed item.
+
+ Remove the first node entry from the Used doubly linked list of the netmap.
+ The number of the <Key, Value> pairs in the netmap decrease by 1. Then add the node
+ entry to the Recycled doubly linked list of the netmap. If parameter Value is not NULL,
+ parameter Value will point to the value of the item. It returns the key of the removed item.
+
+ If Map is NULL, then ASSERT().
+ If the Used doubly linked list is empty, then ASSERT().
+
+ @param[in, out] Map The netmap to remove the head from.
+ @param[out] Value The variable to receive the value if not NULL.
+
+ @return The key of the item removed.
+
+**/
+VOID *
+EFIAPI
+NetMapRemoveHead (
+ IN OUT NET_MAP *Map,
+ OUT VOID **Value OPTIONAL
+ )
+{
+ NET_MAP_ITEM *Item;
+
+ //
+ // Often, it indicates a programming error to remove
+ // the first entry in an empty list
+ //
+ ASSERT (Map && !IsListEmpty (&Map->Used));
+
+ Item = NET_LIST_HEAD (&Map->Used, NET_MAP_ITEM, Link);
+ RemoveEntryList (&Item->Link);
+ Map->Count--;
+ InsertHeadList (&Map->Recycled, &Item->Link);
+
+ if (Value != NULL) {
+ *Value = Item->Value;
+ }
+
+ return Item->Key;
+}
+
+
+/**
+ Remove the last node entry on the netmap and return the key of the removed item.
+
+ Remove the last node entry from the Used doubly linked list of the netmap.
+ The number of the <Key, Value> pairs in the netmap decrease by 1. Then add the node
+ entry to the Recycled doubly linked list of the netmap. If parameter Value is not NULL,
+ parameter Value will point to the value of the item. It returns the key of the removed item.
+
+ If Map is NULL, then ASSERT().
+ If the Used doubly linked list is empty, then ASSERT().
+
+ @param[in, out] Map The netmap to remove the tail from.
+ @param[out] Value The variable to receive the value if not NULL.
+
+ @return The key of the item removed.
+
+**/
+VOID *
+EFIAPI
+NetMapRemoveTail (
+ IN OUT NET_MAP *Map,
+ OUT VOID **Value OPTIONAL
+ )
+{
+ NET_MAP_ITEM *Item;
+
+ //
+ // Often, it indicates a programming error to remove
+ // the last entry in an empty list
+ //
+ ASSERT (Map && !IsListEmpty (&Map->Used));
+
+ Item = NET_LIST_TAIL (&Map->Used, NET_MAP_ITEM, Link);
+ RemoveEntryList (&Item->Link);
+ Map->Count--;
+ InsertHeadList (&Map->Recycled, &Item->Link);
+
+ if (Value != NULL) {
+ *Value = Item->Value;
+ }
+
+ return Item->Key;
+}
+
+
+/**
+ Iterate through the netmap and call CallBack for each item.
+
+ It will contiue the traverse if CallBack returns EFI_SUCCESS, otherwise, break
+ from the loop. It returns the CallBack's last return value. This function is
+ delete safe for the current item.
+
+ If Map is NULL, then ASSERT().
+ If CallBack is NULL, then ASSERT().
+
+ @param[in] Map The Map to iterate through.
+ @param[in] CallBack The callback function to call for each item.
+ @param[in] Arg The opaque parameter to the callback.
+
+ @retval EFI_SUCCESS There is no item in the netmap or CallBack for each item
+ return EFI_SUCCESS.
+ @retval Others It returns the CallBack's last return value.
+
+**/
+EFI_STATUS
+EFIAPI
+NetMapIterate (
+ IN NET_MAP *Map,
+ IN NET_MAP_CALLBACK CallBack,
+ IN VOID *Arg OPTIONAL
+ )
+{
+
+ LIST_ENTRY *Entry;
+ LIST_ENTRY *Next;
+ LIST_ENTRY *Head;
+ NET_MAP_ITEM *Item;
+ EFI_STATUS Result;
+
+ ASSERT ((Map != NULL) && (CallBack != NULL));
+
+ Head = &Map->Used;
+
+ if (IsListEmpty (Head)) {
+ return EFI_SUCCESS;
+ }
+
+ NET_LIST_FOR_EACH_SAFE (Entry, Next, Head) {
+ Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link);
+ Result = CallBack (Map, Item, Arg);
+
+ if (EFI_ERROR (Result)) {
+ return Result;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This is the default unload handle for all the network drivers.
+
+ Disconnect the driver specified by ImageHandle from all the devices in the handle database.
+ Uninstall all the protocols installed in the driver entry point.
+
+ @param[in] ImageHandle The drivers' driver image.
+
+ @retval EFI_SUCCESS The image is unloaded.
+ @retval Others Failed to unload the image.
+
+**/
+EFI_STATUS
+EFIAPI
+NetLibDefaultUnload (
+ IN EFI_HANDLE ImageHandle
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE *DeviceHandleBuffer;
+ UINTN DeviceHandleCount;
+ UINTN Index;
+ UINTN Index2;
+ EFI_DRIVER_BINDING_PROTOCOL *DriverBinding;
+ EFI_COMPONENT_NAME_PROTOCOL *ComponentName;
+ EFI_COMPONENT_NAME2_PROTOCOL *ComponentName2;
+
+ //
+ // Get the list of all the handles in the handle database.
+ // If there is an error getting the list, then the unload
+ // operation fails.
+ //
+ Status = gBS->LocateHandleBuffer (
+ AllHandles,
+ NULL,
+ NULL,
+ &DeviceHandleCount,
+ &DeviceHandleBuffer
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ for (Index = 0; Index < DeviceHandleCount; Index++) {
+ Status = gBS->HandleProtocol (
+ DeviceHandleBuffer[Index],
+ &gEfiDriverBindingProtocolGuid,
+ (VOID **) &DriverBinding
+ );
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ if (DriverBinding->ImageHandle != ImageHandle) {
+ continue;
+ }
+
+ //
+ // Disconnect the driver specified by ImageHandle from all
+ // the devices in the handle database.
+ //
+ for (Index2 = 0; Index2 < DeviceHandleCount; Index2++) {
+ Status = gBS->DisconnectController (
+ DeviceHandleBuffer[Index2],
+ DriverBinding->DriverBindingHandle,
+ NULL
+ );
+ }
+
+ //
+ // Uninstall all the protocols installed in the driver entry point
+ //
+ gBS->UninstallProtocolInterface (
+ DriverBinding->DriverBindingHandle,
+ &gEfiDriverBindingProtocolGuid,
+ DriverBinding
+ );
+
+ Status = gBS->HandleProtocol (
+ DeviceHandleBuffer[Index],
+ &gEfiComponentNameProtocolGuid,
+ (VOID **) &ComponentName
+ );
+ if (!EFI_ERROR (Status)) {
+ gBS->UninstallProtocolInterface (
+ DriverBinding->DriverBindingHandle,
+ &gEfiComponentNameProtocolGuid,
+ ComponentName
+ );
+ }
+
+ Status = gBS->HandleProtocol (
+ DeviceHandleBuffer[Index],
+ &gEfiComponentName2ProtocolGuid,
+ (VOID **) &ComponentName2
+ );
+ if (!EFI_ERROR (Status)) {
+ gBS->UninstallProtocolInterface (
+ DriverBinding->DriverBindingHandle,
+ &gEfiComponentName2ProtocolGuid,
+ ComponentName2
+ );
+ }
+ }
+
+ //
+ // Free the buffer containing the list of handles from the handle database
+ //
+ if (DeviceHandleBuffer != NULL) {
+ gBS->FreePool (DeviceHandleBuffer);
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+
+/**
+ Create a child of the service that is identified by ServiceBindingGuid.
+
+ Get the ServiceBinding Protocol first, then use it to create a child.
+
+ If ServiceBindingGuid is NULL, then ASSERT().
+ If ChildHandle is NULL, then ASSERT().
+
+ @param[in] Controller The controller which has the service installed.
+ @param[in] Image The image handle used to open service.
+ @param[in] ServiceBindingGuid The service's Guid.
+ @param[in, out] ChildHandle The handle to receive the create child.
+
+ @retval EFI_SUCCESS The child is successfully created.
+ @retval Others Failed to create the child.
+
+**/
+EFI_STATUS
+EFIAPI
+NetLibCreateServiceChild (
+ IN EFI_HANDLE Controller,
+ IN EFI_HANDLE Image,
+ IN EFI_GUID *ServiceBindingGuid,
+ IN OUT EFI_HANDLE *ChildHandle
+ )
+{
+ EFI_STATUS Status;
+ EFI_SERVICE_BINDING_PROTOCOL *Service;
+
+
+ ASSERT ((ServiceBindingGuid != NULL) && (ChildHandle != NULL));
+
+ //
+ // Get the ServiceBinding Protocol
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ ServiceBindingGuid,
+ (VOID **) &Service,
+ Image,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Create a child
+ //
+ Status = Service->CreateChild (Service, ChildHandle);
+ return Status;
+}
+
+
+/**
+ Destroy a child of the service that is identified by ServiceBindingGuid.
+
+ Get the ServiceBinding Protocol first, then use it to destroy a child.
+
+ If ServiceBindingGuid is NULL, then ASSERT().
+
+ @param[in] Controller The controller which has the service installed.
+ @param[in] Image The image handle used to open service.
+ @param[in] ServiceBindingGuid The service's Guid.
+ @param[in] ChildHandle The child to destroy.
+
+ @retval EFI_SUCCESS The child is successfully destroyed.
+ @retval Others Failed to destroy the child.
+
+**/
+EFI_STATUS
+EFIAPI
+NetLibDestroyServiceChild (
+ IN EFI_HANDLE Controller,
+ IN EFI_HANDLE Image,
+ IN EFI_GUID *ServiceBindingGuid,
+ IN EFI_HANDLE ChildHandle
+ )
+{
+ EFI_STATUS Status;
+ EFI_SERVICE_BINDING_PROTOCOL *Service;
+
+ ASSERT (ServiceBindingGuid != NULL);
+
+ //
+ // Get the ServiceBinding Protocol
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ ServiceBindingGuid,
+ (VOID **) &Service,
+ Image,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // destroy the child
+ //
+ Status = Service->DestroyChild (Service, ChildHandle);
+ return Status;
+}
+
+/**
+ Get handle with Simple Network Protocol installed on it.
+
+ There should be MNP Service Binding Protocol installed on the input ServiceHandle.
+ If Simple Network Protocol is already installed on the ServiceHandle, the
+ ServiceHandle will be returned. If SNP is not installed on the ServiceHandle,
+ try to find its parent handle with SNP installed.
+
+ @param[in] ServiceHandle The handle where network service binding protocols are
+ installed on.
+ @param[out] Snp The pointer to store the address of the SNP instance.
+ This is an optional parameter that may be NULL.
+
+ @return The SNP handle, or NULL if not found.
+
+**/
+EFI_HANDLE
+EFIAPI
+NetLibGetSnpHandle (
+ IN EFI_HANDLE ServiceHandle,
+ OUT EFI_SIMPLE_NETWORK_PROTOCOL **Snp OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_NETWORK_PROTOCOL *SnpInstance;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_HANDLE SnpHandle;
+
+ //
+ // Try to open SNP from ServiceHandle
+ //
+ SnpInstance = NULL;
+ Status = gBS->HandleProtocol (ServiceHandle, &gEfiSimpleNetworkProtocolGuid, (VOID **) &SnpInstance);
+ if (!EFI_ERROR (Status)) {
+ if (Snp != NULL) {
+ *Snp = SnpInstance;
+ }
+ return ServiceHandle;
+ }
+
+ //
+ // Failed to open SNP, try to get SNP handle by LocateDevicePath()
+ //
+ DevicePath = DevicePathFromHandle (ServiceHandle);
+ if (DevicePath == NULL) {
+ return NULL;
+ }
+
+ SnpHandle = NULL;
+ Status = gBS->LocateDevicePath (&gEfiSimpleNetworkProtocolGuid, &DevicePath, &SnpHandle);
+ if (EFI_ERROR (Status)) {
+ //
+ // Failed to find SNP handle
+ //
+ return NULL;
+ }
+
+ Status = gBS->HandleProtocol (SnpHandle, &gEfiSimpleNetworkProtocolGuid, (VOID **) &SnpInstance);
+ if (!EFI_ERROR (Status)) {
+ if (Snp != NULL) {
+ *Snp = SnpInstance;
+ }
+ return SnpHandle;
+ }
+
+ return NULL;
+}
+
+/**
+ Retrieve VLAN ID of a VLAN device handle.
+
+ Search VLAN device path node in Device Path of specified ServiceHandle and
+ return its VLAN ID. If no VLAN device path node found, then this ServiceHandle
+ is not a VLAN device handle, and 0 will be returned.
+
+ @param[in] ServiceHandle The handle where network service binding protocols are
+ installed on.
+
+ @return VLAN ID of the device handle, or 0 if not a VLAN device.
+
+**/
+UINT16
+EFIAPI
+NetLibGetVlanId (
+ IN EFI_HANDLE ServiceHandle
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *Node;
+
+ DevicePath = DevicePathFromHandle (ServiceHandle);
+ if (DevicePath == NULL) {
+ return 0;
+ }
+
+ Node = DevicePath;
+ while (!IsDevicePathEnd (Node)) {
+ if (Node->Type == MESSAGING_DEVICE_PATH && Node->SubType == MSG_VLAN_DP) {
+ return ((VLAN_DEVICE_PATH *) Node)->VlanId;
+ }
+ Node = NextDevicePathNode (Node);
+ }
+
+ return 0;
+}
+
+/**
+ Find VLAN device handle with specified VLAN ID.
+
+ The VLAN child device handle is created by VLAN Config Protocol on ControllerHandle.
+ This function will append VLAN device path node to the parent device path,
+ and then use LocateDevicePath() to find the correct VLAN device handle.
+
+ @param[in] ControllerHandle The handle where network service binding protocols are
+ installed on.
+ @param[in] VlanId The configured VLAN ID for the VLAN device.
+
+ @return The VLAN device handle, or NULL if not found.
+
+**/
+EFI_HANDLE
+EFIAPI
+NetLibGetVlanHandle (
+ IN EFI_HANDLE ControllerHandle,
+ IN UINT16 VlanId
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *VlanDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ VLAN_DEVICE_PATH VlanNode;
+ EFI_HANDLE Handle;
+
+ ParentDevicePath = DevicePathFromHandle (ControllerHandle);
+ if (ParentDevicePath == NULL) {
+ return NULL;
+ }
+
+ //
+ // Construct VLAN device path
+ //
+ CopyMem (&VlanNode, &mNetVlanDevicePathTemplate, sizeof (VLAN_DEVICE_PATH));
+ VlanNode.VlanId = VlanId;
+ VlanDevicePath = AppendDevicePathNode (
+ ParentDevicePath,
+ (EFI_DEVICE_PATH_PROTOCOL *) &VlanNode
+ );
+ if (VlanDevicePath == NULL) {
+ return NULL;
+ }
+
+ //
+ // Find VLAN device handle
+ //
+ Handle = NULL;
+ DevicePath = VlanDevicePath;
+ gBS->LocateDevicePath (
+ &gEfiDevicePathProtocolGuid,
+ &DevicePath,
+ &Handle
+ );
+ if (!IsDevicePathEnd (DevicePath)) {
+ //
+ // Device path is not exactly match
+ //
+ Handle = NULL;
+ }
+
+ FreePool (VlanDevicePath);
+ return Handle;
+}
+
+/**
+ Get MAC address associated with the network service handle.
+
+ There should be MNP Service Binding Protocol installed on the input ServiceHandle.
+ If SNP is installed on the ServiceHandle or its parent handle, MAC address will
+ be retrieved from SNP. If no SNP found, try to get SNP mode data use MNP.
+
+ @param[in] ServiceHandle The handle where network service binding protocols are
+ installed on.
+ @param[out] MacAddress The pointer to store the returned MAC address.
+ @param[out] AddressSize The length of returned MAC address.
+
+ @retval EFI_SUCCESS MAC address is returned successfully.
+ @retval Others Failed to get SNP mode data.
+
+**/
+EFI_STATUS
+EFIAPI
+NetLibGetMacAddress (
+ IN EFI_HANDLE ServiceHandle,
+ OUT EFI_MAC_ADDRESS *MacAddress,
+ OUT UINTN *AddressSize
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_NETWORK_PROTOCOL *Snp;
+ EFI_SIMPLE_NETWORK_MODE *SnpMode;
+ EFI_SIMPLE_NETWORK_MODE SnpModeData;
+ EFI_MANAGED_NETWORK_PROTOCOL *Mnp;
+ EFI_SERVICE_BINDING_PROTOCOL *MnpSb;
+ EFI_HANDLE *SnpHandle;
+ EFI_HANDLE MnpChildHandle;
+
+ ASSERT (MacAddress != NULL);
+ ASSERT (AddressSize != NULL);
+
+ //
+ // Try to get SNP handle
+ //
+ Snp = NULL;
+ SnpHandle = NetLibGetSnpHandle (ServiceHandle, &Snp);
+ if (SnpHandle != NULL) {
+ //
+ // SNP found, use it directly
+ //
+ SnpMode = Snp->Mode;
+ } else {
+ //
+ // Failed to get SNP handle, try to get MAC address from MNP
+ //
+ MnpChildHandle = NULL;
+ Status = gBS->HandleProtocol (
+ ServiceHandle,
+ &gEfiManagedNetworkServiceBindingProtocolGuid,
+ (VOID **) &MnpSb
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Create a MNP child
+ //
+ Status = MnpSb->CreateChild (MnpSb, &MnpChildHandle);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Open MNP protocol
+ //
+ Status = gBS->HandleProtocol (
+ MnpChildHandle,
+ &gEfiManagedNetworkProtocolGuid,
+ (VOID **) &Mnp
+ );
+ if (EFI_ERROR (Status)) {
+ MnpSb->DestroyChild (MnpSb, MnpChildHandle);
+ return Status;
+ }
+
+ //
+ // Try to get SNP mode from MNP
+ //
+ Status = Mnp->GetModeData (Mnp, NULL, &SnpModeData);
+ if (EFI_ERROR (Status) && (Status != EFI_NOT_STARTED)) {
+ MnpSb->DestroyChild (MnpSb, MnpChildHandle);
+ return Status;
+ }
+ SnpMode = &SnpModeData;
+
+ //
+ // Destroy the MNP child
+ //
+ MnpSb->DestroyChild (MnpSb, MnpChildHandle);
+ }
+
+ *AddressSize = SnpMode->HwAddressSize;
+ CopyMem (MacAddress->Addr, SnpMode->CurrentAddress.Addr, SnpMode->HwAddressSize);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Convert MAC address of the NIC associated with specified Service Binding Handle
+ to a unicode string. Callers are responsible for freeing the string storage.
+
+ Locate simple network protocol associated with the Service Binding Handle and
+ get the mac address from SNP. Then convert the mac address into a unicode
+ string. It takes 2 unicode characters to represent a 1 byte binary buffer.
+ Plus one unicode character for the null-terminator.
+
+ @param[in] ServiceHandle The handle where network service binding protocol is
+ installed on.
+ @param[in] ImageHandle The image handle used to act as the agent handle to
+ get the simple network protocol. This parameter is
+ optional and may be NULL.
+ @param[out] MacString The pointer to store the address of the string
+ representation of the mac address.
+
+ @retval EFI_SUCCESS Convert the mac address a unicode string successfully.
+ @retval EFI_OUT_OF_RESOURCES There are not enough memory resource.
+ @retval Others Failed to open the simple network protocol.
+
+**/
+EFI_STATUS
+EFIAPI
+NetLibGetMacString (
+ IN EFI_HANDLE ServiceHandle,
+ IN EFI_HANDLE ImageHandle, OPTIONAL
+ OUT CHAR16 **MacString
+ )
+{
+ EFI_STATUS Status;
+ EFI_MAC_ADDRESS MacAddress;
+ UINT8 *HwAddress;
+ UINTN HwAddressSize;
+ UINT16 VlanId;
+ CHAR16 *String;
+ UINTN Index;
+
+ ASSERT (MacString != NULL);
+
+ //
+ // Get MAC address of the network device
+ //
+ Status = NetLibGetMacAddress (ServiceHandle, &MacAddress, &HwAddressSize);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // It takes 2 unicode characters to represent a 1 byte binary buffer.
+ // If VLAN is configured, it will need extra 5 characters like "\0005".
+ // Plus one unicode character for the null-terminator.
+ //
+ String = AllocateZeroPool ((2 * HwAddressSize + 5 + 1) * sizeof (CHAR16));
+ if (String == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ *MacString = String;
+
+ //
+ // Convert the MAC address into a unicode string.
+ //
+ HwAddress = &MacAddress.Addr[0];
+ for (Index = 0; Index < HwAddressSize; Index++) {
+ String += UnicodeValueToString (String, PREFIX_ZERO | RADIX_HEX, *(HwAddress++), 2);
+ }
+
+ //
+ // Append VLAN ID if any
+ //
+ VlanId = NetLibGetVlanId (ServiceHandle);
+ if (VlanId != 0) {
+ *String++ = L'\\';
+ String += UnicodeValueToString (String, PREFIX_ZERO | RADIX_HEX, VlanId, 4);
+ }
+
+ //
+ // Null terminate the Unicode string
+ //
+ *String = L'\0';
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Detect media status for specified network device.
+
+ The underlying UNDI driver may or may not support reporting media status from
+ GET_STATUS command (PXE_STATFLAGS_GET_STATUS_NO_MEDIA_SUPPORTED). This routine
+ will try to invoke Snp->GetStatus() to get the media status: if media already
+ present, it return directly; if media not present, it will stop SNP and then
+ restart SNP to get the latest media status, this give chance to get the correct
+ media status for old UNDI driver which doesn't support reporting media status
+ from GET_STATUS command.
+ Note: there will be two limitations for current algorithm:
+ 1) for UNDI with this capability, in case of cable is not attached, there will
+ be an redundant Stop/Start() process;
+ 2) for UNDI without this capability, in case that network cable is attached when
+ Snp->Initialize() is invoked while network cable is unattached later,
+ NetLibDetectMedia() will report MediaPresent as TRUE, causing upper layer
+ apps to wait for timeout time.
+
+ @param[in] ServiceHandle The handle where network service binding protocols are
+ installed on.
+ @param[out] MediaPresent The pointer to store the media status.
+
+ @retval EFI_SUCCESS Media detection success.
+ @retval EFI_INVALID_PARAMETER ServiceHandle is not valid network device handle.
+ @retval EFI_UNSUPPORTED Network device does not support media detection.
+ @retval EFI_DEVICE_ERROR SNP is in unknown state.
+
+**/
+EFI_STATUS
+EFIAPI
+NetLibDetectMedia (
+ IN EFI_HANDLE ServiceHandle,
+ OUT BOOLEAN *MediaPresent
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE SnpHandle;
+ EFI_SIMPLE_NETWORK_PROTOCOL *Snp;
+ UINT32 InterruptStatus;
+ UINT32 OldState;
+ EFI_MAC_ADDRESS *MCastFilter;
+ UINT32 MCastFilterCount;
+ UINT32 EnableFilterBits;
+ UINT32 DisableFilterBits;
+ BOOLEAN ResetMCastFilters;
+
+ ASSERT (MediaPresent != NULL);
+
+ //
+ // Get SNP handle
+ //
+ Snp = NULL;
+ SnpHandle = NetLibGetSnpHandle (ServiceHandle, &Snp);
+ if (SnpHandle == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check whether SNP support media detection
+ //
+ if (!Snp->Mode->MediaPresentSupported) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Invoke Snp->GetStatus() to refresh MediaPresent field in SNP mode data
+ //
+ Status = Snp->GetStatus (Snp, &InterruptStatus, NULL);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (Snp->Mode->MediaPresent) {
+ //
+ // Media is present, return directly
+ //
+ *MediaPresent = TRUE;
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Till now, GetStatus() report no media; while, in case UNDI not support
+ // reporting media status from GetStatus(), this media status may be incorrect.
+ // So, we will stop SNP and then restart it to get the correct media status.
+ //
+ OldState = Snp->Mode->State;
+ if (OldState >= EfiSimpleNetworkMaxState) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ MCastFilter = NULL;
+
+ if (OldState == EfiSimpleNetworkInitialized) {
+ //
+ // SNP is already in use, need Shutdown/Stop and then Start/Initialize
+ //
+
+ //
+ // Backup current SNP receive filter settings
+ //
+ EnableFilterBits = Snp->Mode->ReceiveFilterSetting;
+ DisableFilterBits = Snp->Mode->ReceiveFilterMask ^ EnableFilterBits;
+
+ ResetMCastFilters = TRUE;
+ MCastFilterCount = Snp->Mode->MCastFilterCount;
+ if (MCastFilterCount != 0) {
+ MCastFilter = AllocateCopyPool (
+ MCastFilterCount * sizeof (EFI_MAC_ADDRESS),
+ Snp->Mode->MCastFilter
+ );
+ ASSERT (MCastFilter != NULL);
+
+ ResetMCastFilters = FALSE;
+ }
+
+ //
+ // Shutdown/Stop the simple network
+ //
+ Status = Snp->Shutdown (Snp);
+ if (!EFI_ERROR (Status)) {
+ Status = Snp->Stop (Snp);
+ }
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ //
+ // Start/Initialize the simple network
+ //
+ Status = Snp->Start (Snp);
+ if (!EFI_ERROR (Status)) {
+ Status = Snp->Initialize (Snp, 0, 0);
+ }
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ //
+ // Here we get the correct media status
+ //
+ *MediaPresent = Snp->Mode->MediaPresent;
+
+ //
+ // Restore SNP receive filter settings
+ //
+ Status = Snp->ReceiveFilters (
+ Snp,
+ EnableFilterBits,
+ DisableFilterBits,
+ ResetMCastFilters,
+ MCastFilterCount,
+ MCastFilter
+ );
+
+ if (MCastFilter != NULL) {
+ FreePool (MCastFilter);
+ }
+
+ return Status;
+ }
+
+ //
+ // SNP is not in use, it's in state of EfiSimpleNetworkStopped or EfiSimpleNetworkStarted
+ //
+ if (OldState == EfiSimpleNetworkStopped) {
+ //
+ // SNP not start yet, start it
+ //
+ Status = Snp->Start (Snp);
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+ }
+
+ //
+ // Initialize the simple network
+ //
+ Status = Snp->Initialize (Snp, 0, 0);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ //
+ // Here we get the correct media status
+ //
+ *MediaPresent = Snp->Mode->MediaPresent;
+
+ //
+ // Shut down the simple network
+ //
+ Snp->Shutdown (Snp);
+
+Exit:
+ if (OldState == EfiSimpleNetworkStopped) {
+ //
+ // Original SNP sate is Stopped, restore to original state
+ //
+ Snp->Stop (Snp);
+ }
+
+ if (MCastFilter != NULL) {
+ FreePool (MCastFilter);
+ }
+
+ return Status;
+}
+
+/**
+ Check the default address used by the IPv4 driver is static or dynamic (acquired
+ from DHCP).
+
+ If the controller handle does not have the EFI_IP4_CONFIG2_PROTOCOL installed, the
+ default address is static. If failed to get the policy from Ip4 Config2 Protocol,
+ the default address is static. Otherwise, get the result from Ip4 Config2 Protocol.
+
+ @param[in] Controller The controller handle which has the EFI_IP4_CONFIG2_PROTOCOL
+ relative with the default address to judge.
+
+ @retval TRUE If the default address is static.
+ @retval FALSE If the default address is acquired from DHCP.
+
+**/
+BOOLEAN
+NetLibDefaultAddressIsStatic (
+ IN EFI_HANDLE Controller
+ )
+{
+ EFI_STATUS Status;
+ EFI_IP4_CONFIG2_PROTOCOL *Ip4Config2;
+ UINTN DataSize;
+ EFI_IP4_CONFIG2_POLICY Policy;
+ BOOLEAN IsStatic;
+
+ Ip4Config2 = NULL;
+
+ DataSize = sizeof (EFI_IP4_CONFIG2_POLICY);
+
+ IsStatic = TRUE;
+
+ //
+ // Get Ip4Config2 policy.
+ //
+ Status = gBS->HandleProtocol (Controller, &gEfiIp4Config2ProtocolGuid, (VOID **) &Ip4Config2);
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+
+ Status = Ip4Config2->GetData (Ip4Config2, Ip4Config2DataTypePolicy, &DataSize, &Policy);
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+
+ IsStatic = (BOOLEAN) (Policy == Ip4Config2PolicyStatic);
+
+ON_EXIT:
+
+ return IsStatic;
+}
+
+/**
+ Create an IPv4 device path node.
+
+ The header type of IPv4 device path node is MESSAGING_DEVICE_PATH.
+ The header subtype of IPv4 device path node is MSG_IPv4_DP.
+ Get other info from parameters to make up the whole IPv4 device path node.
+
+ @param[in, out] Node Pointer to the IPv4 device path node.
+ @param[in] Controller The controller handle.
+ @param[in] LocalIp The local IPv4 address.
+ @param[in] LocalPort The local port.
+ @param[in] RemoteIp The remote IPv4 address.
+ @param[in] RemotePort The remote port.
+ @param[in] Protocol The protocol type in the IP header.
+ @param[in] UseDefaultAddress Whether this instance is using default address or not.
+
+**/
+VOID
+EFIAPI
+NetLibCreateIPv4DPathNode (
+ IN OUT IPv4_DEVICE_PATH *Node,
+ IN EFI_HANDLE Controller,
+ IN IP4_ADDR LocalIp,
+ IN UINT16 LocalPort,
+ IN IP4_ADDR RemoteIp,
+ IN UINT16 RemotePort,
+ IN UINT16 Protocol,
+ IN BOOLEAN UseDefaultAddress
+ )
+{
+ Node->Header.Type = MESSAGING_DEVICE_PATH;
+ Node->Header.SubType = MSG_IPv4_DP;
+ SetDevicePathNodeLength (&Node->Header, sizeof (IPv4_DEVICE_PATH));
+
+ CopyMem (&Node->LocalIpAddress, &LocalIp, sizeof (EFI_IPv4_ADDRESS));
+ CopyMem (&Node->RemoteIpAddress, &RemoteIp, sizeof (EFI_IPv4_ADDRESS));
+
+ Node->LocalPort = LocalPort;
+ Node->RemotePort = RemotePort;
+
+ Node->Protocol = Protocol;
+
+ if (!UseDefaultAddress) {
+ Node->StaticIpAddress = TRUE;
+ } else {
+ Node->StaticIpAddress = NetLibDefaultAddressIsStatic (Controller);
+ }
+
+ //
+ // Set the Gateway IP address to default value 0:0:0:0.
+ // Set the Subnet mask to default value 255:255:255:0.
+ //
+ ZeroMem (&Node->GatewayIpAddress, sizeof (EFI_IPv4_ADDRESS));
+ SetMem (&Node->SubnetMask, sizeof (EFI_IPv4_ADDRESS), 0xff);
+ Node->SubnetMask.Addr[3] = 0;
+}
+
+/**
+ Create an IPv6 device path node.
+
+ The header type of IPv6 device path node is MESSAGING_DEVICE_PATH.
+ The header subtype of IPv6 device path node is MSG_IPv6_DP.
+ Get other info from parameters to make up the whole IPv6 device path node.
+
+ @param[in, out] Node Pointer to the IPv6 device path node.
+ @param[in] Controller The controller handle.
+ @param[in] LocalIp The local IPv6 address.
+ @param[in] LocalPort The local port.
+ @param[in] RemoteIp The remote IPv6 address.
+ @param[in] RemotePort The remote port.
+ @param[in] Protocol The protocol type in the IP header.
+
+**/
+VOID
+EFIAPI
+NetLibCreateIPv6DPathNode (
+ IN OUT IPv6_DEVICE_PATH *Node,
+ IN EFI_HANDLE Controller,
+ IN EFI_IPv6_ADDRESS *LocalIp,
+ IN UINT16 LocalPort,
+ IN EFI_IPv6_ADDRESS *RemoteIp,
+ IN UINT16 RemotePort,
+ IN UINT16 Protocol
+ )
+{
+ Node->Header.Type = MESSAGING_DEVICE_PATH;
+ Node->Header.SubType = MSG_IPv6_DP;
+ SetDevicePathNodeLength (&Node->Header, sizeof (IPv6_DEVICE_PATH));
+
+ CopyMem (&Node->LocalIpAddress, LocalIp, sizeof (EFI_IPv6_ADDRESS));
+ CopyMem (&Node->RemoteIpAddress, RemoteIp, sizeof (EFI_IPv6_ADDRESS));
+
+ Node->LocalPort = LocalPort;
+ Node->RemotePort = RemotePort;
+
+ Node->Protocol = Protocol;
+
+ //
+ // Set default value to IPAddressOrigin, PrefixLength.
+ // Set the Gateway IP address to unspecified address.
+ //
+ Node->IpAddressOrigin = 0;
+ Node->PrefixLength = IP6_PREFIX_LENGTH;
+ ZeroMem (&Node->GatewayIpAddress, sizeof (EFI_IPv6_ADDRESS));
+}
+
+/**
+ Find the UNDI/SNP handle from controller and protocol GUID.
+
+ For example, IP will open a MNP child to transmit/receive
+ packets, when MNP is stopped, IP should also be stopped. IP
+ needs to find its own private data which is related the IP's
+ service binding instance that is install on UNDI/SNP handle.
+ Now, the controller is either a MNP or ARP child handle. But
+ IP opens these handle BY_DRIVER, use that info, we can get the
+ UNDI/SNP handle.
+
+ @param[in] Controller Then protocol handle to check.
+ @param[in] ProtocolGuid The protocol that is related with the handle.
+
+ @return The UNDI/SNP handle or NULL for errors.
+
+**/
+EFI_HANDLE
+EFIAPI
+NetLibGetNicHandle (
+ IN EFI_HANDLE Controller,
+ IN EFI_GUID *ProtocolGuid
+ )
+{
+ EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenBuffer;
+ EFI_HANDLE Handle;
+ EFI_STATUS Status;
+ UINTN OpenCount;
+ UINTN Index;
+
+ Status = gBS->OpenProtocolInformation (
+ Controller,
+ ProtocolGuid,
+ &OpenBuffer,
+ &OpenCount
+ );
+
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ Handle = NULL;
+
+ for (Index = 0; Index < OpenCount; Index++) {
+ if ((OpenBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) != 0) {
+ Handle = OpenBuffer[Index].ControllerHandle;
+ break;
+ }
+ }
+
+ gBS->FreePool (OpenBuffer);
+ return Handle;
+}
+
+/**
+ Convert one Null-terminated ASCII string (decimal dotted) to EFI_IPv4_ADDRESS.
+
+ @param[in] String The pointer to the Ascii string.
+ @param[out] Ip4Address The pointer to the converted IPv4 address.
+
+ @retval EFI_SUCCESS Convert to IPv4 address successfully.
+ @retval EFI_INVALID_PARAMETER The string is mal-formated or Ip4Address is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+NetLibAsciiStrToIp4 (
+ IN CONST CHAR8 *String,
+ OUT EFI_IPv4_ADDRESS *Ip4Address
+ )
+{
+ UINT8 Index;
+ CHAR8 *Ip4Str;
+ CHAR8 *TempStr;
+ UINTN NodeVal;
+
+ if ((String == NULL) || (Ip4Address == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Ip4Str = (CHAR8 *) String;
+
+ for (Index = 0; Index < 4; Index++) {
+ TempStr = Ip4Str;
+
+ while ((*Ip4Str != '\0') && (*Ip4Str != '.')) {
+ Ip4Str++;
+ }
+
+ //
+ // The IPv4 address is X.X.X.X
+ //
+ if (*Ip4Str == '.') {
+ if (Index == 3) {
+ return EFI_INVALID_PARAMETER;
+ }
+ } else {
+ if (Index != 3) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ //
+ // Convert the string to IPv4 address. AsciiStrDecimalToUintn stops at the
+ // first character that is not a valid decimal character, '.' or '\0' here.
+ //
+ NodeVal = AsciiStrDecimalToUintn (TempStr);
+ if (NodeVal > 0xFF) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Ip4Address->Addr[Index] = (UINT8) NodeVal;
+
+ Ip4Str++;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Convert one Null-terminated ASCII string to EFI_IPv6_ADDRESS. The format of the
+ string is defined in RFC 4291 - Text Pepresentation of Addresses.
+
+ @param[in] String The pointer to the Ascii string.
+ @param[out] Ip6Address The pointer to the converted IPv6 address.
+
+ @retval EFI_SUCCESS Convert to IPv6 address successfully.
+ @retval EFI_INVALID_PARAMETER The string is mal-formated or Ip6Address is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+NetLibAsciiStrToIp6 (
+ IN CONST CHAR8 *String,
+ OUT EFI_IPv6_ADDRESS *Ip6Address
+ )
+{
+ UINT8 Index;
+ CHAR8 *Ip6Str;
+ CHAR8 *TempStr;
+ CHAR8 *TempStr2;
+ UINT8 NodeCnt;
+ UINT8 TailNodeCnt;
+ UINT8 AllowedCnt;
+ UINTN NodeVal;
+ BOOLEAN Short;
+ BOOLEAN Update;
+ BOOLEAN LeadZero;
+ UINT8 LeadZeroCnt;
+ UINT8 Cnt;
+
+ if ((String == NULL) || (Ip6Address == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Ip6Str = (CHAR8 *) String;
+ AllowedCnt = 6;
+ LeadZeroCnt = 0;
+
+ //
+ // An IPv6 address leading with : looks strange.
+ //
+ if (*Ip6Str == ':') {
+ if (*(Ip6Str + 1) != ':') {
+ return EFI_INVALID_PARAMETER;
+ } else {
+ AllowedCnt = 7;
+ }
+ }
+
+ ZeroMem (Ip6Address, sizeof (EFI_IPv6_ADDRESS));
+
+ NodeCnt = 0;
+ TailNodeCnt = 0;
+ Short = FALSE;
+ Update = FALSE;
+ LeadZero = FALSE;
+
+ for (Index = 0; Index < 15; Index = (UINT8) (Index + 2)) {
+ TempStr = Ip6Str;
+
+ while ((*Ip6Str != '\0') && (*Ip6Str != ':')) {
+ Ip6Str++;
+ }
+
+ if ((*Ip6Str == '\0') && (Index != 14)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (*Ip6Str == ':') {
+ if (*(Ip6Str + 1) == ':') {
+ if ((NodeCnt > 6) ||
+ ((*(Ip6Str + 2) != '\0') && (AsciiStrHexToUintn (Ip6Str + 2) == 0))) {
+ //
+ // ::0 looks strange. report error to user.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+ if ((NodeCnt == 6) && (*(Ip6Str + 2) != '\0') &&
+ (AsciiStrHexToUintn (Ip6Str + 2) != 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Skip the abbreviation part of IPv6 address.
+ //
+ TempStr2 = Ip6Str + 2;
+ while ((*TempStr2 != '\0')) {
+ if (*TempStr2 == ':') {
+ if (*(TempStr2 + 1) == ':') {
+ //
+ // :: can only appear once in IPv6 address.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+
+ TailNodeCnt++;
+ if (TailNodeCnt >= (AllowedCnt - NodeCnt)) {
+ //
+ // :: indicates one or more groups of 16 bits of zeros.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ TempStr2++;
+ }
+
+ Short = TRUE;
+ Update = TRUE;
+
+ Ip6Str = Ip6Str + 2;
+ } else {
+ if (*(Ip6Str + 1) == '\0') {
+ return EFI_INVALID_PARAMETER;
+ }
+ Ip6Str++;
+ NodeCnt++;
+ if ((Short && (NodeCnt > 6)) || (!Short && (NodeCnt > 7))) {
+ //
+ // There are more than 8 groups of 16 bits of zeros.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ }
+
+ //
+ // Convert the string to IPv6 address. AsciiStrHexToUintn stops at the first
+ // character that is not a valid hexadecimal character, ':' or '\0' here.
+ //
+ NodeVal = AsciiStrHexToUintn (TempStr);
+ if ((NodeVal > 0xFFFF) || (Index > 14)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (NodeVal != 0) {
+ if ((*TempStr == '0') &&
+ ((*(TempStr + 2) == ':') || (*(TempStr + 3) == ':') ||
+ (*(TempStr + 2) == '\0') || (*(TempStr + 3) == '\0'))) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if ((*TempStr == '0') && (*(TempStr + 4) != '\0') &&
+ (*(TempStr + 4) != ':')) {
+ return EFI_INVALID_PARAMETER;
+ }
+ } else {
+ if (((*TempStr == '0') && (*(TempStr + 1) == '0') &&
+ ((*(TempStr + 2) == ':') || (*(TempStr + 2) == '\0'))) ||
+ ((*TempStr == '0') && (*(TempStr + 1) == '0') && (*(TempStr + 2) == '0') &&
+ ((*(TempStr + 3) == ':') || (*(TempStr + 3) == '\0')))) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ Cnt = 0;
+ while ((TempStr[Cnt] != ':') && (TempStr[Cnt] != '\0')) {
+ Cnt++;
+ }
+ if (LeadZeroCnt == 0) {
+ if ((Cnt == 4) && (*TempStr == '0')) {
+ LeadZero = TRUE;
+ LeadZeroCnt++;
+ }
+ if ((Cnt != 0) && (Cnt < 4)) {
+ LeadZero = FALSE;
+ LeadZeroCnt++;
+ }
+ } else {
+ if ((Cnt == 4) && (*TempStr == '0') && !LeadZero) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if ((Cnt != 0) && (Cnt < 4) && LeadZero) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ Ip6Address->Addr[Index] = (UINT8) (NodeVal >> 8);
+ Ip6Address->Addr[Index + 1] = (UINT8) (NodeVal & 0xFF);
+
+ //
+ // Skip the groups of zeros by ::
+ //
+ if (Short && Update) {
+ Index = (UINT8) (16 - (TailNodeCnt + 2) * 2);
+ Update = FALSE;
+ }
+ }
+
+ if ((!Short && Index != 16) || (*Ip6Str != '\0')) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Convert one Null-terminated Unicode string (decimal dotted) to EFI_IPv4_ADDRESS.
+
+ @param[in] String The pointer to the Ascii string.
+ @param[out] Ip4Address The pointer to the converted IPv4 address.
+
+ @retval EFI_SUCCESS Convert to IPv4 address successfully.
+ @retval EFI_INVALID_PARAMETER The string is mal-formated or Ip4Address is NULL.
+ @retval EFI_OUT_OF_RESOURCES Fail to perform the operation due to lack of resource.
+
+**/
+EFI_STATUS
+EFIAPI
+NetLibStrToIp4 (
+ IN CONST CHAR16 *String,
+ OUT EFI_IPv4_ADDRESS *Ip4Address
+ )
+{
+ CHAR8 *Ip4Str;
+ UINTN StringSize;
+ EFI_STATUS Status;
+
+ if ((String == NULL) || (Ip4Address == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ StringSize = StrLen (String) + 1;
+ Ip4Str = (CHAR8 *) AllocatePool (StringSize * sizeof (CHAR8));
+ if (Ip4Str == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ UnicodeStrToAsciiStrS (String, Ip4Str, StringSize);
+
+ Status = NetLibAsciiStrToIp4 (Ip4Str, Ip4Address);
+
+ FreePool (Ip4Str);
+
+ return Status;
+}
+
+
+/**
+ Convert one Null-terminated Unicode string to EFI_IPv6_ADDRESS. The format of
+ the string is defined in RFC 4291 - Text Pepresentation of Addresses.
+
+ @param[in] String The pointer to the Ascii string.
+ @param[out] Ip6Address The pointer to the converted IPv6 address.
+
+ @retval EFI_SUCCESS Convert to IPv6 address successfully.
+ @retval EFI_INVALID_PARAMETER The string is mal-formated or Ip6Address is NULL.
+ @retval EFI_OUT_OF_RESOURCES Fail to perform the operation due to lack of resource.
+
+**/
+EFI_STATUS
+EFIAPI
+NetLibStrToIp6 (
+ IN CONST CHAR16 *String,
+ OUT EFI_IPv6_ADDRESS *Ip6Address
+ )
+{
+ CHAR8 *Ip6Str;
+ UINTN StringSize;
+ EFI_STATUS Status;
+
+ if ((String == NULL) || (Ip6Address == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ StringSize = StrLen (String) + 1;
+ Ip6Str = (CHAR8 *) AllocatePool (StringSize * sizeof (CHAR8));
+ if (Ip6Str == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ UnicodeStrToAsciiStrS (String, Ip6Str, StringSize);
+
+ Status = NetLibAsciiStrToIp6 (Ip6Str, Ip6Address);
+
+ FreePool (Ip6Str);
+
+ return Status;
+}
+
+/**
+ Convert one Null-terminated Unicode string to EFI_IPv6_ADDRESS and prefix length.
+ The format of the string is defined in RFC 4291 - Text Pepresentation of Addresses
+ Prefixes: ipv6-address/prefix-length.
+
+ @param[in] String The pointer to the Ascii string.
+ @param[out] Ip6Address The pointer to the converted IPv6 address.
+ @param[out] PrefixLength The pointer to the converted prefix length.
+
+ @retval EFI_SUCCESS Convert to IPv6 address successfully.
+ @retval EFI_INVALID_PARAMETER The string is mal-formated or Ip6Address is NULL.
+ @retval EFI_OUT_OF_RESOURCES Fail to perform the operation due to lack of resource.
+
+**/
+EFI_STATUS
+EFIAPI
+NetLibStrToIp6andPrefix (
+ IN CONST CHAR16 *String,
+ OUT EFI_IPv6_ADDRESS *Ip6Address,
+ OUT UINT8 *PrefixLength
+ )
+{
+ CHAR8 *Ip6Str;
+ UINTN StringSize;
+ CHAR8 *PrefixStr;
+ CHAR8 *TempStr;
+ EFI_STATUS Status;
+ UINT8 Length;
+
+ if ((String == NULL) || (Ip6Address == NULL) || (PrefixLength == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ StringSize = StrLen (String) + 1;
+ Ip6Str = (CHAR8 *) AllocatePool (StringSize * sizeof (CHAR8));
+ if (Ip6Str == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ UnicodeStrToAsciiStrS (String, Ip6Str, StringSize);
+
+ //
+ // Get the sub string describing prefix length.
+ //
+ TempStr = Ip6Str;
+ while (*TempStr != '\0' && (*TempStr != '/')) {
+ TempStr++;
+ }
+
+ if (*TempStr == '/') {
+ PrefixStr = TempStr + 1;
+ } else {
+ PrefixStr = NULL;
+ }
+
+ //
+ // Get the sub string describing IPv6 address and convert it.
+ //
+ *TempStr = '\0';
+
+ Status = NetLibAsciiStrToIp6 (Ip6Str, Ip6Address);
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ //
+ // If input string doesn't indicate the prefix length, return 0xff.
+ //
+ Length = 0xFF;
+
+ //
+ // Convert the string to prefix length
+ //
+ if (PrefixStr != NULL) {
+
+ Status = EFI_INVALID_PARAMETER;
+ Length = 0;
+ while (*PrefixStr != '\0') {
+ if (NET_IS_DIGIT (*PrefixStr)) {
+ Length = (UINT8) (Length * 10 + (*PrefixStr - '0'));
+ if (Length >= IP6_PREFIX_NUM) {
+ goto Exit;
+ }
+ } else {
+ goto Exit;
+ }
+
+ PrefixStr++;
+ }
+ }
+
+ *PrefixLength = Length;
+ Status = EFI_SUCCESS;
+
+Exit:
+
+ FreePool (Ip6Str);
+ return Status;
+}
+
+/**
+
+ Convert one EFI_IPv6_ADDRESS to Null-terminated Unicode string.
+ The text representation of address is defined in RFC 4291.
+
+ @param[in] Ip6Address The pointer to the IPv6 address.
+ @param[out] String The buffer to return the converted string.
+ @param[in] StringSize The length in bytes of the input String.
+
+ @retval EFI_SUCCESS Convert to string successfully.
+ @retval EFI_INVALID_PARAMETER The input parameter is invalid.
+ @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small for the result. BufferSize has been
+ updated with the size needed to complete the request.
+**/
+EFI_STATUS
+EFIAPI
+NetLibIp6ToStr (
+ IN EFI_IPv6_ADDRESS *Ip6Address,
+ OUT CHAR16 *String,
+ IN UINTN StringSize
+ )
+{
+ UINT16 Ip6Addr[8];
+ UINTN Index;
+ UINTN LongestZerosStart;
+ UINTN LongestZerosLength;
+ UINTN CurrentZerosStart;
+ UINTN CurrentZerosLength;
+ CHAR16 Buffer[sizeof"ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"];
+ CHAR16 *Ptr;
+
+ if (Ip6Address == NULL || String == NULL || StringSize == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Convert the UINT8 array to an UINT16 array for easy handling.
+ //
+ ZeroMem (Ip6Addr, sizeof (Ip6Addr));
+ for (Index = 0; Index < 16; Index++) {
+ Ip6Addr[Index / 2] |= (Ip6Address->Addr[Index] << ((1 - (Index % 2)) << 3));
+ }
+
+ //
+ // Find the longest zeros and mark it.
+ //
+ CurrentZerosStart = DEFAULT_ZERO_START;
+ CurrentZerosLength = 0;
+ LongestZerosStart = DEFAULT_ZERO_START;
+ LongestZerosLength = 0;
+ for (Index = 0; Index < 8; Index++) {
+ if (Ip6Addr[Index] == 0) {
+ if (CurrentZerosStart == DEFAULT_ZERO_START) {
+ CurrentZerosStart = Index;
+ CurrentZerosLength = 1;
+ } else {
+ CurrentZerosLength++;
+ }
+ } else {
+ if (CurrentZerosStart != DEFAULT_ZERO_START) {
+ if (CurrentZerosLength > 2 && (LongestZerosStart == (DEFAULT_ZERO_START) || CurrentZerosLength > LongestZerosLength)) {
+ LongestZerosStart = CurrentZerosStart;
+ LongestZerosLength = CurrentZerosLength;
+ }
+ CurrentZerosStart = DEFAULT_ZERO_START;
+ CurrentZerosLength = 0;
+ }
+ }
+ }
+
+ if (CurrentZerosStart != DEFAULT_ZERO_START && CurrentZerosLength > 2) {
+ if (LongestZerosStart == DEFAULT_ZERO_START || LongestZerosLength < CurrentZerosLength) {
+ LongestZerosStart = CurrentZerosStart;
+ LongestZerosLength = CurrentZerosLength;
+ }
+ }
+
+ Ptr = Buffer;
+ for (Index = 0; Index < 8; Index++) {
+ if (LongestZerosStart != DEFAULT_ZERO_START && Index >= LongestZerosStart && Index < LongestZerosStart + LongestZerosLength) {
+ if (Index == LongestZerosStart) {
+ *Ptr++ = L':';
+ }
+ continue;
+ }
+ if (Index != 0) {
+ *Ptr++ = L':';
+ }
+ Ptr += UnicodeSPrint(Ptr, 10, L"%x", Ip6Addr[Index]);
+ }
+
+ if (LongestZerosStart != DEFAULT_ZERO_START && LongestZerosStart + LongestZerosLength == 8) {
+ *Ptr++ = L':';
+ }
+ *Ptr = L'\0';
+
+ if ((UINTN)Ptr - (UINTN)Buffer > StringSize) {
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ StrCpyS (String, StringSize / sizeof (CHAR16), Buffer);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function obtains the system guid from the smbios table.
+
+ @param[out] SystemGuid The pointer of the returned system guid.
+
+ @retval EFI_SUCCESS Successfully obtained the system guid.
+ @retval EFI_NOT_FOUND Did not find the SMBIOS table.
+
+**/
+EFI_STATUS
+EFIAPI
+NetLibGetSystemGuid (
+ OUT EFI_GUID *SystemGuid
+ )
+{
+ EFI_STATUS Status;
+ SMBIOS_TABLE_ENTRY_POINT *SmbiosTable;
+ SMBIOS_TABLE_3_0_ENTRY_POINT *Smbios30Table;
+ SMBIOS_STRUCTURE_POINTER Smbios;
+ SMBIOS_STRUCTURE_POINTER SmbiosEnd;
+ CHAR8 *String;
+
+ SmbiosTable = NULL;
+ Status = EfiGetSystemConfigurationTable (&gEfiSmbios3TableGuid, (VOID **) &Smbios30Table);
+ if (!(EFI_ERROR (Status) || Smbios30Table == NULL)) {
+ Smbios.Hdr = (SMBIOS_STRUCTURE *) (UINTN) Smbios30Table->TableAddress;
+ SmbiosEnd.Raw = (UINT8 *) (UINTN) (Smbios30Table->TableAddress + Smbios30Table->TableMaximumSize);
+ } else {
+ Status = EfiGetSystemConfigurationTable (&gEfiSmbiosTableGuid, (VOID **) &SmbiosTable);
+ if (EFI_ERROR (Status) || SmbiosTable == NULL) {
+ return EFI_NOT_FOUND;
+ }
+ Smbios.Hdr = (SMBIOS_STRUCTURE *) (UINTN) SmbiosTable->TableAddress;
+ SmbiosEnd.Raw = (UINT8 *) (UINTN) (SmbiosTable->TableAddress + SmbiosTable->TableLength);
+ }
+
+ do {
+ if (Smbios.Hdr->Type == 1) {
+ if (Smbios.Hdr->Length < 0x19) {
+ //
+ // Older version did not support UUID.
+ //
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // SMBIOS tables are byte packed so we need to do a byte copy to
+ // prevend alignment faults on Itanium-based platform.
+ //
+ CopyMem (SystemGuid, &Smbios.Type1->Uuid, sizeof (EFI_GUID));
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Go to the next SMBIOS structure. Each SMBIOS structure may include 2 parts:
+ // 1. Formatted section; 2. Unformatted string section. So, 2 steps are needed
+ // to skip one SMBIOS structure.
+ //
+
+ //
+ // Step 1: Skip over formatted section.
+ //
+ String = (CHAR8 *) (Smbios.Raw + Smbios.Hdr->Length);
+
+ //
+ // Step 2: Skip over unformated string section.
+ //
+ do {
+ //
+ // Each string is terminated with a NULL(00h) BYTE and the sets of strings
+ // is terminated with an additional NULL(00h) BYTE.
+ //
+ for ( ; *String != 0; String++) {
+ }
+
+ if (*(UINT8*)++String == 0) {
+ //
+ // Pointer to the next SMBIOS structure.
+ //
+ Smbios.Raw = (UINT8 *)++String;
+ break;
+ }
+ } while (TRUE);
+ } while (Smbios.Raw < SmbiosEnd.Raw);
+ return EFI_NOT_FOUND;
+}
diff --git a/Core/MdeModulePkg/Library/DxeNetLib/DxeNetLib.inf b/Core/MdeModulePkg/Library/DxeNetLib/DxeNetLib.inf
new file mode 100644
index 0000000000..1ff3a4fe55
--- /dev/null
+++ b/Core/MdeModulePkg/Library/DxeNetLib/DxeNetLib.inf
@@ -0,0 +1,65 @@
+## @file
+# This library instance provides the basic network services.
+#
+# Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+# (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxeNetLib
+ MODULE_UNI_FILE = DxeNetLib.uni
+ FILE_GUID = db6dcef3-9f4e-4340-9351-fc35aa8a5888
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = NetLib|DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SAL_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ DxeNetLib.c
+ NetBuffer.c
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+
+[LibraryClasses]
+ BaseLib
+ DebugLib
+ BaseMemoryLib
+ UefiBootServicesTableLib
+ UefiRuntimeServicesTableLib
+ UefiLib
+ MemoryAllocationLib
+ DevicePathLib
+ PrintLib
+
+
+[Guids]
+ gEfiSmbiosTableGuid ## SOMETIMES_CONSUMES ## SystemTable
+ gEfiSmbios3TableGuid ## SOMETIMES_CONSUMES ## SystemTable
+
+
+[Protocols]
+ gEfiSimpleNetworkProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiManagedNetworkProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiManagedNetworkServiceBindingProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiIp4Config2ProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiComponentNameProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiComponentName2ProtocolGuid ## SOMETIMES_CONSUMES
diff --git a/Core/MdeModulePkg/Library/DxeNetLib/DxeNetLib.uni b/Core/MdeModulePkg/Library/DxeNetLib/DxeNetLib.uni
new file mode 100644
index 0000000000..bd74cfacbd
--- /dev/null
+++ b/Core/MdeModulePkg/Library/DxeNetLib/DxeNetLib.uni
Binary files differ
diff --git a/Core/MdeModulePkg/Library/DxeNetLib/NetBuffer.c b/Core/MdeModulePkg/Library/DxeNetLib/NetBuffer.c
new file mode 100644
index 0000000000..bbbdbc048a
--- /dev/null
+++ b/Core/MdeModulePkg/Library/DxeNetLib/NetBuffer.c
@@ -0,0 +1,1892 @@
+/** @file
+ Network library functions providing net buffer operation support.
+
+Copyright (c) 2005 - 2010, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+**/
+
+#include <Uefi.h>
+
+#include <Library/NetLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+
+/**
+ Allocate and build up the sketch for a NET_BUF.
+
+ The net buffer allocated has the BlockOpNum's NET_BLOCK_OP, and its associated
+ NET_VECTOR has the BlockNum's NET_BLOCK. But all the NET_BLOCK_OP and
+ NET_BLOCK remain un-initialized.
+
+ @param[in] BlockNum The number of NET_BLOCK in the vector of net buffer
+ @param[in] BlockOpNum The number of NET_BLOCK_OP in the net buffer
+
+ @return Pointer to the allocated NET_BUF, or NULL if the
+ allocation failed due to resource limit.
+
+**/
+NET_BUF *
+NetbufAllocStruct (
+ IN UINT32 BlockNum,
+ IN UINT32 BlockOpNum
+ )
+{
+ NET_BUF *Nbuf;
+ NET_VECTOR *Vector;
+
+ ASSERT (BlockOpNum >= 1);
+
+ //
+ // Allocate three memory blocks.
+ //
+ Nbuf = AllocateZeroPool (NET_BUF_SIZE (BlockOpNum));
+
+ if (Nbuf == NULL) {
+ return NULL;
+ }
+
+ Nbuf->Signature = NET_BUF_SIGNATURE;
+ Nbuf->RefCnt = 1;
+ Nbuf->BlockOpNum = BlockOpNum;
+ InitializeListHead (&Nbuf->List);
+
+ if (BlockNum != 0) {
+ Vector = AllocateZeroPool (NET_VECTOR_SIZE (BlockNum));
+
+ if (Vector == NULL) {
+ goto FreeNbuf;
+ }
+
+ Vector->Signature = NET_VECTOR_SIGNATURE;
+ Vector->RefCnt = 1;
+ Vector->BlockNum = BlockNum;
+ Nbuf->Vector = Vector;
+ }
+
+ return Nbuf;
+
+FreeNbuf:
+
+ FreePool (Nbuf);
+ return NULL;
+}
+
+
+/**
+ Allocate a single block NET_BUF. Upon allocation, all the
+ free space is in the tail room.
+
+ @param[in] Len The length of the block.
+
+ @return Pointer to the allocated NET_BUF, or NULL if the
+ allocation failed due to resource limit.
+
+**/
+NET_BUF *
+EFIAPI
+NetbufAlloc (
+ IN UINT32 Len
+ )
+{
+ NET_BUF *Nbuf;
+ NET_VECTOR *Vector;
+ UINT8 *Bulk;
+
+ ASSERT (Len > 0);
+
+ Nbuf = NetbufAllocStruct (1, 1);
+
+ if (Nbuf == NULL) {
+ return NULL;
+ }
+
+ Bulk = AllocatePool (Len);
+
+ if (Bulk == NULL) {
+ goto FreeNBuf;
+ }
+
+ Vector = Nbuf->Vector;
+ Vector->Len = Len;
+
+ Vector->Block[0].Bulk = Bulk;
+ Vector->Block[0].Len = Len;
+
+ Nbuf->BlockOp[0].BlockHead = Bulk;
+ Nbuf->BlockOp[0].BlockTail = Bulk + Len;
+
+ Nbuf->BlockOp[0].Head = Bulk;
+ Nbuf->BlockOp[0].Tail = Bulk;
+ Nbuf->BlockOp[0].Size = 0;
+
+ return Nbuf;
+
+FreeNBuf:
+ FreePool (Nbuf);
+ return NULL;
+}
+
+/**
+ Free the net vector.
+
+ Decrease the reference count of the net vector by one. The real resource free
+ operation isn't performed until the reference count of the net vector is
+ decreased to 0.
+
+ @param[in] Vector Pointer to the NET_VECTOR to be freed.
+
+**/
+VOID
+NetbufFreeVector (
+ IN NET_VECTOR *Vector
+ )
+{
+ UINT32 Index;
+
+ ASSERT (Vector != NULL);
+ NET_CHECK_SIGNATURE (Vector, NET_VECTOR_SIGNATURE);
+ ASSERT (Vector->RefCnt > 0);
+
+ Vector->RefCnt--;
+
+ if (Vector->RefCnt > 0) {
+ return;
+ }
+
+ if (Vector->Free != NULL) {
+ //
+ // Call external free function to free the vector if it
+ // isn't NULL. If NET_VECTOR_OWN_FIRST is set, release the
+ // first block since it is allocated by us
+ //
+ if ((Vector->Flag & NET_VECTOR_OWN_FIRST) != 0) {
+ gBS->FreePool (Vector->Block[0].Bulk);
+ }
+
+ Vector->Free (Vector->Arg);
+
+ } else {
+ //
+ // Free each memory block associated with the Vector
+ //
+ for (Index = 0; Index < Vector->BlockNum; Index++) {
+ gBS->FreePool (Vector->Block[Index].Bulk);
+ }
+ }
+
+ FreePool (Vector);
+}
+
+
+/**
+ Free the net buffer and its associated NET_VECTOR.
+
+ Decrease the reference count of the net buffer by one. Free the associated net
+ vector and itself if the reference count of the net buffer is decreased to 0.
+ The net vector free operation just decrease the reference count of the net
+ vector by one and do the real resource free operation when the reference count
+ of the net vector is 0.
+
+ @param[in] Nbuf Pointer to the NET_BUF to be freed.
+
+**/
+VOID
+EFIAPI
+NetbufFree (
+ IN NET_BUF *Nbuf
+ )
+{
+ ASSERT (Nbuf != NULL);
+ NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
+ ASSERT (Nbuf->RefCnt > 0);
+
+ Nbuf->RefCnt--;
+
+ if (Nbuf->RefCnt == 0) {
+ //
+ // Update Vector only when NBuf is to be released. That is,
+ // all the sharing of Nbuf increse Vector's RefCnt by one
+ //
+ NetbufFreeVector (Nbuf->Vector);
+ FreePool (Nbuf);
+ }
+}
+
+
+/**
+ Create a copy of the net buffer that shares the associated net vector.
+
+ The reference count of the newly created net buffer is set to 1. The reference
+ count of the associated net vector is increased by one.
+
+ @param[in] Nbuf Pointer to the net buffer to be cloned.
+
+ @return Pointer to the cloned net buffer, or NULL if the
+ allocation failed due to resource limit.
+
+**/
+NET_BUF *
+EFIAPI
+NetbufClone (
+ IN NET_BUF *Nbuf
+ )
+{
+ NET_BUF *Clone;
+
+ NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
+
+ Clone = AllocatePool (NET_BUF_SIZE (Nbuf->BlockOpNum));
+
+ if (Clone == NULL) {
+ return NULL;
+ }
+
+ Clone->Signature = NET_BUF_SIGNATURE;
+ Clone->RefCnt = 1;
+ InitializeListHead (&Clone->List);
+
+ Clone->Ip = Nbuf->Ip;
+ Clone->Tcp = Nbuf->Tcp;
+
+ CopyMem (Clone->ProtoData, Nbuf->ProtoData, NET_PROTO_DATA);
+
+ NET_GET_REF (Nbuf->Vector);
+
+ Clone->Vector = Nbuf->Vector;
+ Clone->BlockOpNum = Nbuf->BlockOpNum;
+ Clone->TotalSize = Nbuf->TotalSize;
+ CopyMem (Clone->BlockOp, Nbuf->BlockOp, sizeof (NET_BLOCK_OP) * Nbuf->BlockOpNum);
+
+ return Clone;
+}
+
+
+/**
+ Create a duplicated copy of the net buffer with data copied and HeadSpace
+ bytes of head space reserved.
+
+ The duplicated net buffer will allocate its own memory to hold the data of the
+ source net buffer.
+
+ @param[in] Nbuf Pointer to the net buffer to be duplicated from.
+ @param[in, out] Duplicate Pointer to the net buffer to duplicate to, if
+ NULL a new net buffer is allocated.
+ @param[in] HeadSpace Length of the head space to reserve.
+
+ @return Pointer to the duplicated net buffer, or NULL if
+ the allocation failed due to resource limit.
+
+**/
+NET_BUF *
+EFIAPI
+NetbufDuplicate (
+ IN NET_BUF *Nbuf,
+ IN OUT NET_BUF *Duplicate OPTIONAL,
+ IN UINT32 HeadSpace
+ )
+{
+ UINT8 *Dst;
+
+ NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
+
+ if (Duplicate == NULL) {
+ Duplicate = NetbufAlloc (Nbuf->TotalSize + HeadSpace);
+ }
+
+ if (Duplicate == NULL) {
+ return NULL;
+ }
+
+ //
+ // Don't set the IP and TCP head point, since it is most
+ // like that they are pointing to the memory of Nbuf.
+ //
+ CopyMem (Duplicate->ProtoData, Nbuf->ProtoData, NET_PROTO_DATA);
+ NetbufReserve (Duplicate, HeadSpace);
+
+ Dst = NetbufAllocSpace (Duplicate, Nbuf->TotalSize, NET_BUF_TAIL);
+ NetbufCopy (Nbuf, 0, Nbuf->TotalSize, Dst);
+
+ return Duplicate;
+}
+
+
+/**
+ Free a list of net buffers.
+
+ @param[in, out] Head Pointer to the head of linked net buffers.
+
+**/
+VOID
+EFIAPI
+NetbufFreeList (
+ IN OUT LIST_ENTRY *Head
+ )
+{
+ LIST_ENTRY *Entry;
+ LIST_ENTRY *Next;
+ NET_BUF *Nbuf;
+
+ Entry = Head->ForwardLink;
+
+ NET_LIST_FOR_EACH_SAFE (Entry, Next, Head) {
+ Nbuf = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);
+ NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
+
+ RemoveEntryList (Entry);
+ NetbufFree (Nbuf);
+ }
+
+ ASSERT (IsListEmpty (Head));
+}
+
+
+/**
+ Get the index of NET_BLOCK_OP that contains the byte at Offset in the net
+ buffer.
+
+ This can be used to, for example, retrieve the IP header in the packet. It
+ also can be used to get the fragment that contains the byte which is used
+ mainly by the library implementation itself.
+
+ @param[in] Nbuf Pointer to the net buffer.
+ @param[in] Offset The offset of the byte.
+ @param[out] Index Index of the NET_BLOCK_OP that contains the byte at
+ Offset.
+
+ @return Pointer to the Offset'th byte of data in the net buffer, or NULL
+ if there is no such data in the net buffer.
+
+**/
+UINT8 *
+EFIAPI
+NetbufGetByte (
+ IN NET_BUF *Nbuf,
+ IN UINT32 Offset,
+ OUT UINT32 *Index OPTIONAL
+ )
+{
+ NET_BLOCK_OP *BlockOp;
+ UINT32 Loop;
+ UINT32 Len;
+
+ NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
+
+ if (Offset >= Nbuf->TotalSize) {
+ return NULL;
+ }
+
+ BlockOp = Nbuf->BlockOp;
+ Len = 0;
+
+ for (Loop = 0; Loop < Nbuf->BlockOpNum; Loop++) {
+
+ if (Len + BlockOp[Loop].Size <= Offset) {
+ Len += BlockOp[Loop].Size;
+ continue;
+ }
+
+ if (Index != NULL) {
+ *Index = Loop;
+ }
+
+ return BlockOp[Loop].Head + (Offset - Len);
+ }
+
+ return NULL;
+}
+
+
+
+/**
+ Set the NET_BLOCK and corresponding NET_BLOCK_OP in the net buffer and
+ corresponding net vector according to the bulk pointer and bulk length.
+
+ All the pointers in the Index'th NET_BLOCK and NET_BLOCK_OP are set to the
+ bulk's head and tail respectively. So, this function alone can't be used by
+ NetbufAlloc.
+
+ @param[in, out] Nbuf Pointer to the net buffer.
+ @param[in] Bulk Pointer to the data.
+ @param[in] Len Length of the bulk data.
+ @param[in] Index The data block index in the net buffer the bulk
+ data should belong to.
+
+**/
+VOID
+NetbufSetBlock (
+ IN OUT NET_BUF *Nbuf,
+ IN UINT8 *Bulk,
+ IN UINT32 Len,
+ IN UINT32 Index
+ )
+{
+ NET_BLOCK_OP *BlockOp;
+ NET_BLOCK *Block;
+
+ NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
+ NET_CHECK_SIGNATURE (Nbuf->Vector, NET_VECTOR_SIGNATURE);
+ ASSERT (Index < Nbuf->BlockOpNum);
+
+ Block = &(Nbuf->Vector->Block[Index]);
+ BlockOp = &(Nbuf->BlockOp[Index]);
+ Block->Len = Len;
+ Block->Bulk = Bulk;
+ BlockOp->BlockHead = Bulk;
+ BlockOp->BlockTail = Bulk + Len;
+ BlockOp->Head = Bulk;
+ BlockOp->Tail = Bulk + Len;
+ BlockOp->Size = Len;
+}
+
+
+
+/**
+ Set the NET_BLOCK_OP in the net buffer. The corresponding NET_BLOCK
+ structure is left untouched.
+
+ Some times, there is no 1:1 relationship between NET_BLOCK and NET_BLOCK_OP.
+ For example, that in NetbufGetFragment.
+
+ @param[in, out] Nbuf Pointer to the net buffer.
+ @param[in] Bulk Pointer to the data.
+ @param[in] Len Length of the bulk data.
+ @param[in] Index The data block index in the net buffer the bulk
+ data should belong to.
+
+**/
+VOID
+NetbufSetBlockOp (
+ IN OUT NET_BUF *Nbuf,
+ IN UINT8 *Bulk,
+ IN UINT32 Len,
+ IN UINT32 Index
+ )
+{
+ NET_BLOCK_OP *BlockOp;
+
+ NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
+ ASSERT (Index < Nbuf->BlockOpNum);
+
+ BlockOp = &(Nbuf->BlockOp[Index]);
+ BlockOp->BlockHead = Bulk;
+ BlockOp->BlockTail = Bulk + Len;
+ BlockOp->Head = Bulk;
+ BlockOp->Tail = Bulk + Len;
+ BlockOp->Size = Len;
+}
+
+
+/**
+ Helper function for NetbufGetFragment. NetbufGetFragment may allocate the
+ first block to reserve HeadSpace bytes header space. So it needs to create a
+ new net vector for the first block and can avoid copy for the remaining data
+ by sharing the old net vector.
+
+ @param[in] Arg Point to the old NET_VECTOR.
+
+**/
+VOID
+EFIAPI
+NetbufGetFragmentFree (
+ IN VOID *Arg
+ )
+{
+ NET_VECTOR *Vector;
+
+ Vector = (NET_VECTOR *)Arg;
+ NetbufFreeVector (Vector);
+}
+
+
+/**
+ Create a NET_BUF structure which contains Len byte data of Nbuf starting from
+ Offset.
+
+ A new NET_BUF structure will be created but the associated data in NET_VECTOR
+ is shared. This function exists to do IP packet fragmentation.
+
+ @param[in] Nbuf Pointer to the net buffer to be extracted.
+ @param[in] Offset Starting point of the data to be included in the new
+ net buffer.
+ @param[in] Len Bytes of data to be included in the new net buffer.
+ @param[in] HeadSpace Bytes of head space to reserve for protocol header.
+
+ @return Pointer to the cloned net buffer, or NULL if the
+ allocation failed due to resource limit.
+
+**/
+NET_BUF *
+EFIAPI
+NetbufGetFragment (
+ IN NET_BUF *Nbuf,
+ IN UINT32 Offset,
+ IN UINT32 Len,
+ IN UINT32 HeadSpace
+ )
+{
+ NET_BUF *Child;
+ NET_VECTOR *Vector;
+ NET_BLOCK_OP *BlockOp;
+ UINT32 CurBlockOp;
+ UINT32 BlockOpNum;
+ UINT8 *FirstBulk;
+ UINT32 Index;
+ UINT32 First;
+ UINT32 Last;
+ UINT32 FirstSkip;
+ UINT32 FirstLen;
+ UINT32 LastLen;
+ UINT32 Cur;
+
+ NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
+
+ if ((Len == 0) || (Offset + Len > Nbuf->TotalSize)) {
+ return NULL;
+ }
+
+ //
+ // First find the first and last BlockOp that contains
+ // the valid data, and compute the offset of the first
+ // BlockOp and length of the last BlockOp
+ //
+ BlockOp = Nbuf->BlockOp;
+ Cur = 0;
+
+ for (Index = 0; Index < Nbuf->BlockOpNum; Index++) {
+ if (Offset < Cur + BlockOp[Index].Size) {
+ break;
+ }
+
+ Cur += BlockOp[Index].Size;
+ }
+
+ //
+ // First is the index of the first BlockOp, FirstSkip is
+ // the offset of the first byte in the first BlockOp.
+ //
+ First = Index;
+ FirstSkip = Offset - Cur;
+ FirstLen = BlockOp[Index].Size - FirstSkip;
+
+ Last = 0;
+ LastLen = 0;
+
+ if (Len > FirstLen) {
+ Cur += BlockOp[Index].Size;
+ Index++;
+
+ for (; Index < Nbuf->BlockOpNum; Index++) {
+ if (Offset + Len <= Cur + BlockOp[Index].Size) {
+ Last = Index;
+ LastLen = Offset + Len - Cur;
+ break;
+ }
+
+ Cur += BlockOp[Index].Size;
+ }
+
+ } else {
+ Last = First;
+ LastLen = Len;
+ FirstLen = Len;
+ }
+
+ ASSERT (Last >= First);
+ BlockOpNum = Last - First + 1;
+ CurBlockOp = 0;
+
+ if (HeadSpace != 0) {
+ //
+ // Allocate an extra block to accomdate the head space.
+ //
+ BlockOpNum++;
+
+ Child = NetbufAllocStruct (1, BlockOpNum);
+
+ if (Child == NULL) {
+ return NULL;
+ }
+
+ FirstBulk = AllocatePool (HeadSpace);
+
+ if (FirstBulk == NULL) {
+ goto FreeChild;
+ }
+
+ Vector = Child->Vector;
+ Vector->Free = NetbufGetFragmentFree;
+ Vector->Arg = Nbuf->Vector;
+ Vector->Flag = NET_VECTOR_OWN_FIRST;
+ Vector->Len = HeadSpace;
+
+ //
+ // Reserve the head space in the first block
+ //
+ NetbufSetBlock (Child, FirstBulk, HeadSpace, 0);
+ Child->BlockOp[0].Head += HeadSpace;
+ Child->BlockOp[0].Size = 0;
+ CurBlockOp++;
+
+ } else {
+ Child = NetbufAllocStruct (0, BlockOpNum);
+
+ if (Child == NULL) {
+ return NULL;
+ }
+
+ Child->Vector = Nbuf->Vector;
+ }
+
+ NET_GET_REF (Nbuf->Vector);
+ Child->TotalSize = Len;
+
+ //
+ // Set all the BlockOp up, the first and last one are special
+ // and need special process.
+ //
+ NetbufSetBlockOp (
+ Child,
+ Nbuf->BlockOp[First].Head + FirstSkip,
+ FirstLen,
+ CurBlockOp++
+ );
+
+ for (Index = First + 1; Index < Last; Index++) {
+ NetbufSetBlockOp (
+ Child,
+ BlockOp[Index].Head,
+ BlockOp[Index].Size,
+ CurBlockOp++
+ );
+ }
+
+ if (First != Last) {
+ NetbufSetBlockOp (
+ Child,
+ BlockOp[Last].Head,
+ LastLen,
+ CurBlockOp
+ );
+ }
+
+ CopyMem (Child->ProtoData, Nbuf->ProtoData, NET_PROTO_DATA);
+ return Child;
+
+FreeChild:
+
+ FreePool (Child);
+ return NULL;
+}
+
+
+
+/**
+ Build a NET_BUF from external blocks.
+
+ A new NET_BUF structure will be created from external blocks. Additional block
+ of memory will be allocated to hold reserved HeadSpace bytes of header room
+ and existing HeadLen bytes of header but the external blocks are shared by the
+ net buffer to avoid data copying.
+
+ @param[in] ExtFragment Pointer to the data block.
+ @param[in] ExtNum The number of the data blocks.
+ @param[in] HeadSpace The head space to be reserved.
+ @param[in] HeadLen The length of the protocol header, This function
+ will pull that number of data into a linear block.
+ @param[in] ExtFree Pointer to the caller provided free function.
+ @param[in] Arg The argument passed to ExtFree when ExtFree is
+ called.
+
+ @return Pointer to the net buffer built from the data blocks,
+ or NULL if the allocation failed due to resource
+ limit.
+
+**/
+NET_BUF *
+EFIAPI
+NetbufFromExt (
+ IN NET_FRAGMENT *ExtFragment,
+ IN UINT32 ExtNum,
+ IN UINT32 HeadSpace,
+ IN UINT32 HeadLen,
+ IN NET_VECTOR_EXT_FREE ExtFree,
+ IN VOID *Arg OPTIONAL
+ )
+{
+ NET_BUF *Nbuf;
+ NET_VECTOR *Vector;
+ NET_FRAGMENT SavedFragment;
+ UINT32 SavedIndex;
+ UINT32 TotalLen;
+ UINT32 BlockNum;
+ UINT8 *FirstBlock;
+ UINT32 FirstBlockLen;
+ UINT8 *Header;
+ UINT32 CurBlock;
+ UINT32 Index;
+ UINT32 Len;
+ UINT32 Copied;
+
+ ASSERT ((ExtFragment != NULL) && (ExtNum > 0) && (ExtFree != NULL));
+
+ SavedFragment.Bulk = NULL;
+ SavedFragment.Len = 0;
+
+ FirstBlockLen = 0;
+ FirstBlock = NULL;
+ BlockNum = ExtNum;
+ Index = 0;
+ TotalLen = 0;
+ SavedIndex = 0;
+ Len = 0;
+ Copied = 0;
+
+ //
+ // No need to consolidate the header if the first block is
+ // longer than the header length or there is only one block.
+ //
+ if ((ExtFragment[0].Len >= HeadLen) || (ExtNum == 1)) {
+ HeadLen = 0;
+ }
+
+ //
+ // Allocate an extra block if we need to:
+ // 1. Allocate some header space
+ // 2. aggreate the packet header
+ //
+ if ((HeadSpace != 0) || (HeadLen != 0)) {
+ FirstBlockLen = HeadLen + HeadSpace;
+ FirstBlock = AllocatePool (FirstBlockLen);
+
+ if (FirstBlock == NULL) {
+ return NULL;
+ }
+
+ BlockNum++;
+ }
+
+ //
+ // Copy the header to the first block, reduce the NET_BLOCK
+ // to allocate by one for each block that is completely covered
+ // by the first bulk.
+ //
+ if (HeadLen != 0) {
+ Len = HeadLen;
+ Header = FirstBlock + HeadSpace;
+
+ for (Index = 0; Index < ExtNum; Index++) {
+ if (Len >= ExtFragment[Index].Len) {
+ CopyMem (Header, ExtFragment[Index].Bulk, ExtFragment[Index].Len);
+
+ Copied += ExtFragment[Index].Len;
+ Len -= ExtFragment[Index].Len;
+ Header += ExtFragment[Index].Len;
+ TotalLen += ExtFragment[Index].Len;
+ BlockNum--;
+
+ if (Len == 0) {
+ //
+ // Increament the index number to point to the next
+ // non-empty fragment.
+ //
+ Index++;
+ break;
+ }
+
+ } else {
+ CopyMem (Header, ExtFragment[Index].Bulk, Len);
+
+ Copied += Len;
+ TotalLen += Len;
+
+ //
+ // Adjust the block structure to exclude the data copied,
+ // So, the left-over block can be processed as other blocks.
+ // But it must be recovered later. (SavedIndex > 0) always
+ // holds since we don't aggreate the header if the first block
+ // is bigger enough that the header is continuous
+ //
+ SavedIndex = Index;
+ SavedFragment = ExtFragment[Index];
+ ExtFragment[Index].Bulk += Len;
+ ExtFragment[Index].Len -= Len;
+ break;
+ }
+ }
+ }
+
+ Nbuf = NetbufAllocStruct (BlockNum, BlockNum);
+
+ if (Nbuf == NULL) {
+ goto FreeFirstBlock;
+ }
+
+ Vector = Nbuf->Vector;
+ Vector->Free = ExtFree;
+ Vector->Arg = Arg;
+ Vector->Flag = ((FirstBlockLen != 0) ? NET_VECTOR_OWN_FIRST : 0);
+
+ //
+ // Set the first block up which may contain
+ // some head space and aggregated header
+ //
+ CurBlock = 0;
+
+ if (FirstBlockLen != 0) {
+ NetbufSetBlock (Nbuf, FirstBlock, HeadSpace + Copied, 0);
+ Nbuf->BlockOp[0].Head += HeadSpace;
+ Nbuf->BlockOp[0].Size = Copied;
+
+ CurBlock++;
+ }
+
+ for (; Index < ExtNum; Index++) {
+ NetbufSetBlock (Nbuf, ExtFragment[Index].Bulk, ExtFragment[Index].Len, CurBlock);
+ TotalLen += ExtFragment[Index].Len;
+ CurBlock++;
+ }
+
+ Vector->Len = TotalLen + HeadSpace;
+ Nbuf->TotalSize = TotalLen;
+
+ if (SavedIndex != 0) {
+ ExtFragment[SavedIndex] = SavedFragment;
+ }
+
+ return Nbuf;
+
+FreeFirstBlock:
+ if (FirstBlock != NULL) {
+ FreePool (FirstBlock);
+ }
+ return NULL;
+}
+
+
+/**
+ Build a fragment table to contain the fragments in the net buffer. This is the
+ opposite operation of the NetbufFromExt.
+
+ @param[in] Nbuf Point to the net buffer.
+ @param[in, out] ExtFragment Pointer to the data block.
+ @param[in, out] ExtNum The number of the data blocks.
+
+ @retval EFI_BUFFER_TOO_SMALL The number of non-empty block is bigger than
+ ExtNum.
+ @retval EFI_SUCCESS Fragment table is built successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+NetbufBuildExt (
+ IN NET_BUF *Nbuf,
+ IN OUT NET_FRAGMENT *ExtFragment,
+ IN OUT UINT32 *ExtNum
+ )
+{
+ UINT32 Index;
+ UINT32 Current;
+
+ Current = 0;
+
+ for (Index = 0; (Index < Nbuf->BlockOpNum); Index++) {
+ if (Nbuf->BlockOp[Index].Size == 0) {
+ continue;
+ }
+
+ if (Current < *ExtNum) {
+ ExtFragment[Current].Bulk = Nbuf->BlockOp[Index].Head;
+ ExtFragment[Current].Len = Nbuf->BlockOp[Index].Size;
+ Current++;
+ } else {
+ return EFI_BUFFER_TOO_SMALL;
+ }
+ }
+
+ *ExtNum = Current;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Build a net buffer from a list of net buffers.
+
+ All the fragments will be collected from the list of NEW_BUF and then a new
+ net buffer will be created through NetbufFromExt.
+
+ @param[in] BufList A List of the net buffer.
+ @param[in] HeadSpace The head space to be reserved.
+ @param[in] HeaderLen The length of the protocol header, This function
+ will pull that number of data into a linear block.
+ @param[in] ExtFree Pointer to the caller provided free function.
+ @param[in] Arg The argument passed to ExtFree when ExtFree is called.
+
+ @return Pointer to the net buffer built from the list of net
+ buffers.
+
+**/
+NET_BUF *
+EFIAPI
+NetbufFromBufList (
+ IN LIST_ENTRY *BufList,
+ IN UINT32 HeadSpace,
+ IN UINT32 HeaderLen,
+ IN NET_VECTOR_EXT_FREE ExtFree,
+ IN VOID *Arg OPTIONAL
+ )
+{
+ NET_FRAGMENT *Fragment;
+ UINT32 FragmentNum;
+ LIST_ENTRY *Entry;
+ NET_BUF *Nbuf;
+ UINT32 Index;
+ UINT32 Current;
+
+ //
+ //Compute how many blocks are there
+ //
+ FragmentNum = 0;
+
+ NET_LIST_FOR_EACH (Entry, BufList) {
+ Nbuf = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);
+ NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
+ FragmentNum += Nbuf->BlockOpNum;
+ }
+
+ //
+ //Allocate and copy block points
+ //
+ Fragment = AllocatePool (sizeof (NET_FRAGMENT) * FragmentNum);
+
+ if (Fragment == NULL) {
+ return NULL;
+ }
+
+ Current = 0;
+
+ NET_LIST_FOR_EACH (Entry, BufList) {
+ Nbuf = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);
+ NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
+
+ for (Index = 0; Index < Nbuf->BlockOpNum; Index++) {
+ if (Nbuf->BlockOp[Index].Size != 0) {
+ Fragment[Current].Bulk = Nbuf->BlockOp[Index].Head;
+ Fragment[Current].Len = Nbuf->BlockOp[Index].Size;
+ Current++;
+ }
+ }
+ }
+
+ Nbuf = NetbufFromExt (Fragment, Current, HeadSpace, HeaderLen, ExtFree, Arg);
+ FreePool (Fragment);
+
+ return Nbuf;
+}
+
+
+/**
+ Reserve some space in the header room of the net buffer.
+
+ Upon allocation, all the space are in the tail room of the buffer. Call this
+ function to move some space to the header room. This function is quite limited
+ in that it can only reserve space from the first block of an empty NET_BUF not
+ built from the external. But it should be enough for the network stack.
+
+ @param[in, out] Nbuf Pointer to the net buffer.
+ @param[in] Len The length of buffer to be reserved from the header.
+
+**/
+VOID
+EFIAPI
+NetbufReserve (
+ IN OUT NET_BUF *Nbuf,
+ IN UINT32 Len
+ )
+{
+ NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
+ NET_CHECK_SIGNATURE (Nbuf->Vector, NET_VECTOR_SIGNATURE);
+
+ ASSERT ((Nbuf->BlockOpNum == 1) && (Nbuf->TotalSize == 0));
+ ASSERT ((Nbuf->Vector->Free == NULL) && (Nbuf->Vector->Len >= Len));
+
+ Nbuf->BlockOp[0].Head += Len;
+ Nbuf->BlockOp[0].Tail += Len;
+
+ ASSERT (Nbuf->BlockOp[0].Tail <= Nbuf->BlockOp[0].BlockTail);
+}
+
+
+/**
+ Allocate Len bytes of space from the header or tail of the buffer.
+
+ @param[in, out] Nbuf Pointer to the net buffer.
+ @param[in] Len The length of the buffer to be allocated.
+ @param[in] FromHead The flag to indicate whether reserve the data
+ from head (TRUE) or tail (FALSE).
+
+ @return Pointer to the first byte of the allocated buffer,
+ or NULL if there is no sufficient space.
+
+**/
+UINT8*
+EFIAPI
+NetbufAllocSpace (
+ IN OUT NET_BUF *Nbuf,
+ IN UINT32 Len,
+ IN BOOLEAN FromHead
+ )
+{
+ NET_BLOCK_OP *BlockOp;
+ UINT32 Index;
+ UINT8 *SavedTail;
+
+ Index = 0;
+
+ NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
+ NET_CHECK_SIGNATURE (Nbuf->Vector, NET_VECTOR_SIGNATURE);
+
+ ASSERT (Len > 0);
+
+ if (FromHead) {
+ //
+ // Allocate some space from head. If the buffer is empty,
+ // allocate from the first block. If it isn't, allocate
+ // from the first non-empty block, or the block before that.
+ //
+ if (Nbuf->TotalSize == 0) {
+ Index = 0;
+ } else {
+ NetbufGetByte (Nbuf, 0, &Index);
+
+ if ((NET_HEADSPACE(&(Nbuf->BlockOp[Index])) < Len) && (Index > 0)) {
+ Index--;
+ }
+ }
+
+ BlockOp = &(Nbuf->BlockOp[Index]);
+
+ if (NET_HEADSPACE (BlockOp) < Len) {
+ return NULL;
+ }
+
+ BlockOp->Head -= Len;
+ BlockOp->Size += Len;
+ Nbuf->TotalSize += Len;
+
+ return BlockOp->Head;
+
+ } else {
+ //
+ // Allocate some space from the tail. If the buffer is empty,
+ // allocate from the first block. If it isn't, allocate
+ // from the last non-empty block, or the block after that.
+ //
+ if (Nbuf->TotalSize == 0) {
+ Index = 0;
+ } else {
+ NetbufGetByte (Nbuf, Nbuf->TotalSize - 1, &Index);
+
+ if ((NET_TAILSPACE(&(Nbuf->BlockOp[Index])) < Len) &&
+ (Index < Nbuf->BlockOpNum - 1)) {
+
+ Index++;
+ }
+ }
+
+ BlockOp = &(Nbuf->BlockOp[Index]);
+
+ if (NET_TAILSPACE (BlockOp) < Len) {
+ return NULL;
+ }
+
+ SavedTail = BlockOp->Tail;
+
+ BlockOp->Tail += Len;
+ BlockOp->Size += Len;
+ Nbuf->TotalSize += Len;
+
+ return SavedTail;
+ }
+}
+
+
+/**
+ Trim a single NET_BLOCK by Len bytes from the header or tail.
+
+ @param[in, out] BlockOp Pointer to the NET_BLOCK.
+ @param[in] Len The length of the data to be trimmed.
+ @param[in] FromHead The flag to indicate whether trim data from head
+ (TRUE) or tail (FALSE).
+
+**/
+VOID
+NetblockTrim (
+ IN OUT NET_BLOCK_OP *BlockOp,
+ IN UINT32 Len,
+ IN BOOLEAN FromHead
+ )
+{
+ ASSERT ((BlockOp != NULL) && (BlockOp->Size >= Len));
+
+ BlockOp->Size -= Len;
+
+ if (FromHead) {
+ BlockOp->Head += Len;
+ } else {
+ BlockOp->Tail -= Len;
+ }
+}
+
+
+/**
+ Trim Len bytes from the header or tail of the net buffer.
+
+ @param[in, out] Nbuf Pointer to the net buffer.
+ @param[in] Len The length of the data to be trimmed.
+ @param[in] FromHead The flag to indicate whether trim data from head
+ (TRUE) or tail (FALSE).
+
+ @return Length of the actually trimmed data, which is possible to be less
+ than Len because the TotalSize of Nbuf is less than Len.
+
+**/
+UINT32
+EFIAPI
+NetbufTrim (
+ IN OUT NET_BUF *Nbuf,
+ IN UINT32 Len,
+ IN BOOLEAN FromHead
+ )
+{
+ NET_BLOCK_OP *BlockOp;
+ UINT32 Index;
+ UINT32 Trimmed;
+
+ NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
+
+ if (Len > Nbuf->TotalSize) {
+ Len = Nbuf->TotalSize;
+ }
+
+ //
+ // If FromTail is true, iterate backward. That
+ // is, init Index to NBuf->BlockNum - 1, and
+ // decrease it by 1 during each loop. Otherwise,
+ // iterate forward. That is, init Index to 0, and
+ // increase it by 1 during each loop.
+ //
+ Trimmed = 0;
+ Nbuf->TotalSize -= Len;
+
+ Index = (FromHead ? 0 : Nbuf->BlockOpNum - 1);
+ BlockOp = Nbuf->BlockOp;
+
+ for (;;) {
+ if (BlockOp[Index].Size == 0) {
+ Index += (FromHead ? 1 : -1);
+ continue;
+ }
+
+ if (Len > BlockOp[Index].Size) {
+ Len -= BlockOp[Index].Size;
+ Trimmed += BlockOp[Index].Size;
+ NetblockTrim (&BlockOp[Index], BlockOp[Index].Size, FromHead);
+ } else {
+ Trimmed += Len;
+ NetblockTrim (&BlockOp[Index], Len, FromHead);
+ break;
+ }
+
+ Index += (FromHead ? 1 : -1);
+ }
+
+ return Trimmed;
+}
+
+
+/**
+ Copy Len bytes of data from the specific offset of the net buffer to the
+ destination memory.
+
+ The Len bytes of data may cross the several fragments of the net buffer.
+
+ @param[in] Nbuf Pointer to the net buffer.
+ @param[in] Offset The sequence number of the first byte to copy.
+ @param[in] Len Length of the data to copy.
+ @param[in] Dest The destination of the data to copy to.
+
+ @return The length of the actual copied data, or 0 if the offset
+ specified exceeds the total size of net buffer.
+
+**/
+UINT32
+EFIAPI
+NetbufCopy (
+ IN NET_BUF *Nbuf,
+ IN UINT32 Offset,
+ IN UINT32 Len,
+ IN UINT8 *Dest
+ )
+{
+ NET_BLOCK_OP *BlockOp;
+ UINT32 Skip;
+ UINT32 Left;
+ UINT32 Copied;
+ UINT32 Index;
+ UINT32 Cur;
+
+ NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
+ ASSERT (Dest);
+
+ if ((Len == 0) || (Nbuf->TotalSize <= Offset)) {
+ return 0;
+ }
+
+ if (Nbuf->TotalSize - Offset < Len) {
+ Len = Nbuf->TotalSize - Offset;
+ }
+
+ BlockOp = Nbuf->BlockOp;
+
+ //
+ // Skip to the offset. Don't make "Offset-By-One" error here.
+ // Cur + BLOCK.SIZE is the first sequence number of next block.
+ // So, (Offset < Cur + BLOCK.SIZE) means that the first byte
+ // is in the current block. if (Offset == Cur + BLOCK.SIZE), the
+ // first byte is the next block's first byte.
+ //
+ Cur = 0;
+
+ for (Index = 0; Index < Nbuf->BlockOpNum; Index++) {
+ if (BlockOp[Index].Size == 0) {
+ continue;
+ }
+
+ if (Offset < Cur + BlockOp[Index].Size) {
+ break;
+ }
+
+ Cur += BlockOp[Index].Size;
+ }
+
+ //
+ // Cur is the sequence number of the first byte in the block
+ // Offset - Cur is the number of bytes before first byte to
+ // to copy in the current block.
+ //
+ Skip = Offset - Cur;
+ Left = BlockOp[Index].Size - Skip;
+
+ if (Len <= Left) {
+ CopyMem (Dest, BlockOp[Index].Head + Skip, Len);
+ return Len;
+ }
+
+ CopyMem (Dest, BlockOp[Index].Head + Skip, Left);
+
+ Dest += Left;
+ Len -= Left;
+ Copied = Left;
+
+ Index++;
+
+ for (; Index < Nbuf->BlockOpNum; Index++) {
+ if (Len > BlockOp[Index].Size) {
+ Len -= BlockOp[Index].Size;
+ Copied += BlockOp[Index].Size;
+
+ CopyMem (Dest, BlockOp[Index].Head, BlockOp[Index].Size);
+ Dest += BlockOp[Index].Size;
+ } else {
+ Copied += Len;
+ CopyMem (Dest, BlockOp[Index].Head, Len);
+ break;
+ }
+ }
+
+ return Copied;
+}
+
+
+/**
+ Initiate the net buffer queue.
+
+ @param[in, out] NbufQue Pointer to the net buffer queue to be initialized.
+
+**/
+VOID
+EFIAPI
+NetbufQueInit (
+ IN OUT NET_BUF_QUEUE *NbufQue
+ )
+{
+ NbufQue->Signature = NET_QUE_SIGNATURE;
+ NbufQue->RefCnt = 1;
+ InitializeListHead (&NbufQue->List);
+
+ InitializeListHead (&NbufQue->BufList);
+ NbufQue->BufSize = 0;
+ NbufQue->BufNum = 0;
+}
+
+
+/**
+ Allocate and initialize a net buffer queue.
+
+ @return Pointer to the allocated net buffer queue, or NULL if the
+ allocation failed due to resource limit.
+
+**/
+NET_BUF_QUEUE *
+EFIAPI
+NetbufQueAlloc (
+ VOID
+ )
+{
+ NET_BUF_QUEUE *NbufQue;
+
+ NbufQue = AllocatePool (sizeof (NET_BUF_QUEUE));
+ if (NbufQue == NULL) {
+ return NULL;
+ }
+
+ NetbufQueInit (NbufQue);
+
+ return NbufQue;
+}
+
+
+/**
+ Free a net buffer queue.
+
+ Decrease the reference count of the net buffer queue by one. The real resource
+ free operation isn't performed until the reference count of the net buffer
+ queue is decreased to 0.
+
+ @param[in] NbufQue Pointer to the net buffer queue to be freed.
+
+**/
+VOID
+EFIAPI
+NetbufQueFree (
+ IN NET_BUF_QUEUE *NbufQue
+ )
+{
+ ASSERT (NbufQue != NULL);
+ NET_CHECK_SIGNATURE (NbufQue, NET_QUE_SIGNATURE);
+
+ NbufQue->RefCnt--;
+
+ if (NbufQue->RefCnt == 0) {
+ NetbufQueFlush (NbufQue);
+ FreePool (NbufQue);
+ }
+}
+
+
+/**
+ Append a net buffer to the net buffer queue.
+
+ @param[in, out] NbufQue Pointer to the net buffer queue.
+ @param[in, out] Nbuf Pointer to the net buffer to be appended.
+
+**/
+VOID
+EFIAPI
+NetbufQueAppend (
+ IN OUT NET_BUF_QUEUE *NbufQue,
+ IN OUT NET_BUF *Nbuf
+ )
+{
+ NET_CHECK_SIGNATURE (NbufQue, NET_QUE_SIGNATURE);
+ NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
+
+ InsertTailList (&NbufQue->BufList, &Nbuf->List);
+
+ NbufQue->BufSize += Nbuf->TotalSize;
+ NbufQue->BufNum++;
+}
+
+
+/**
+ Remove a net buffer from the head in the specific queue and return it.
+
+ @param[in, out] NbufQue Pointer to the net buffer queue.
+
+ @return Pointer to the net buffer removed from the specific queue,
+ or NULL if there is no net buffer in the specific queue.
+
+**/
+NET_BUF *
+EFIAPI
+NetbufQueRemove (
+ IN OUT NET_BUF_QUEUE *NbufQue
+ )
+{
+ NET_BUF *First;
+
+ NET_CHECK_SIGNATURE (NbufQue, NET_QUE_SIGNATURE);
+
+ if (NbufQue->BufNum == 0) {
+ return NULL;
+ }
+
+ First = NET_LIST_USER_STRUCT (NbufQue->BufList.ForwardLink, NET_BUF, List);
+
+ NetListRemoveHead (&NbufQue->BufList);
+
+ NbufQue->BufSize -= First->TotalSize;
+ NbufQue->BufNum--;
+ return First;
+}
+
+
+/**
+ Copy Len bytes of data from the net buffer queue at the specific offset to the
+ destination memory.
+
+ The copying operation is the same as NetbufCopy but applies to the net buffer
+ queue instead of the net buffer.
+
+ @param[in] NbufQue Pointer to the net buffer queue.
+ @param[in] Offset The sequence number of the first byte to copy.
+ @param[in] Len Length of the data to copy.
+ @param[out] Dest The destination of the data to copy to.
+
+ @return The length of the actual copied data, or 0 if the offset
+ specified exceeds the total size of net buffer queue.
+
+**/
+UINT32
+EFIAPI
+NetbufQueCopy (
+ IN NET_BUF_QUEUE *NbufQue,
+ IN UINT32 Offset,
+ IN UINT32 Len,
+ OUT UINT8 *Dest
+ )
+{
+ LIST_ENTRY *Entry;
+ NET_BUF *Nbuf;
+ UINT32 Skip;
+ UINT32 Left;
+ UINT32 Cur;
+ UINT32 Copied;
+
+ NET_CHECK_SIGNATURE (NbufQue, NET_QUE_SIGNATURE);
+ ASSERT (Dest != NULL);
+
+ if ((Len == 0) || (NbufQue->BufSize <= Offset)) {
+ return 0;
+ }
+
+ if (NbufQue->BufSize - Offset < Len) {
+ Len = NbufQue->BufSize - Offset;
+ }
+
+ //
+ // skip to the Offset
+ //
+ Cur = 0;
+ Nbuf = NULL;
+
+ NET_LIST_FOR_EACH (Entry, &NbufQue->BufList) {
+ Nbuf = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);
+
+ if (Offset < Cur + Nbuf->TotalSize) {
+ break;
+ }
+
+ Cur += Nbuf->TotalSize;
+ }
+
+ ASSERT (Nbuf != NULL);
+
+ //
+ // Copy the data in the first buffer.
+ //
+ Skip = Offset - Cur;
+ Left = Nbuf->TotalSize - Skip;
+
+ if (Len < Left) {
+ return NetbufCopy (Nbuf, Skip, Len, Dest);
+ }
+
+ NetbufCopy (Nbuf, Skip, Left, Dest);
+ Dest += Left;
+ Len -= Left;
+ Copied = Left;
+
+ //
+ // Iterate over the others
+ //
+ Entry = Entry->ForwardLink;
+
+ while ((Len > 0) && (Entry != &NbufQue->BufList)) {
+ Nbuf = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);
+
+ if (Len > Nbuf->TotalSize) {
+ Len -= Nbuf->TotalSize;
+ Copied += Nbuf->TotalSize;
+
+ NetbufCopy (Nbuf, 0, Nbuf->TotalSize, Dest);
+ Dest += Nbuf->TotalSize;
+
+ } else {
+ NetbufCopy (Nbuf, 0, Len, Dest);
+ Copied += Len;
+ break;
+ }
+
+ Entry = Entry->ForwardLink;
+ }
+
+ return Copied;
+}
+
+
+/**
+ Trim Len bytes of data from the buffer queue and free any net buffer
+ that is completely trimmed.
+
+ The trimming operation is the same as NetbufTrim but applies to the net buffer
+ queue instead of the net buffer.
+
+ @param[in, out] NbufQue Pointer to the net buffer queue.
+ @param[in] Len Length of the data to trim.
+
+ @return The actual length of the data trimmed.
+
+**/
+UINT32
+EFIAPI
+NetbufQueTrim (
+ IN OUT NET_BUF_QUEUE *NbufQue,
+ IN UINT32 Len
+ )
+{
+ LIST_ENTRY *Entry;
+ LIST_ENTRY *Next;
+ NET_BUF *Nbuf;
+ UINT32 Trimmed;
+
+ NET_CHECK_SIGNATURE (NbufQue, NET_QUE_SIGNATURE);
+
+ if (Len == 0) {
+ return 0;
+ }
+
+ if (Len > NbufQue->BufSize) {
+ Len = NbufQue->BufSize;
+ }
+
+ NbufQue->BufSize -= Len;
+ Trimmed = 0;
+
+ NET_LIST_FOR_EACH_SAFE (Entry, Next, &NbufQue->BufList) {
+ Nbuf = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);
+
+ if (Len >= Nbuf->TotalSize) {
+ Trimmed += Nbuf->TotalSize;
+ Len -= Nbuf->TotalSize;
+
+ RemoveEntryList (Entry);
+ NetbufFree (Nbuf);
+
+ NbufQue->BufNum--;
+
+ if (Len == 0) {
+ break;
+ }
+
+ } else {
+ Trimmed += NetbufTrim (Nbuf, Len, NET_BUF_HEAD);
+ break;
+ }
+ }
+
+ return Trimmed;
+}
+
+
+/**
+ Flush the net buffer queue.
+
+ @param[in, out] NbufQue Pointer to the queue to be flushed.
+
+**/
+VOID
+EFIAPI
+NetbufQueFlush (
+ IN OUT NET_BUF_QUEUE *NbufQue
+ )
+{
+ NET_CHECK_SIGNATURE (NbufQue, NET_QUE_SIGNATURE);
+
+ NetbufFreeList (&NbufQue->BufList);
+
+ NbufQue->BufNum = 0;
+ NbufQue->BufSize = 0;
+}
+
+
+/**
+ Compute the checksum for a bulk of data.
+
+ @param[in] Bulk Pointer to the data.
+ @param[in] Len Length of the data, in bytes.
+
+ @return The computed checksum.
+
+**/
+UINT16
+EFIAPI
+NetblockChecksum (
+ IN UINT8 *Bulk,
+ IN UINT32 Len
+ )
+{
+ register UINT32 Sum;
+
+ Sum = 0;
+
+ while (Len > 1) {
+ Sum += *(UINT16 *) Bulk;
+ Bulk += 2;
+ Len -= 2;
+ }
+
+ //
+ // Add left-over byte, if any
+ //
+ if (Len > 0) {
+ Sum += *(UINT8 *) Bulk;
+ }
+
+ //
+ // Fold 32-bit sum to 16 bits
+ //
+ while ((Sum >> 16) != 0) {
+ Sum = (Sum & 0xffff) + (Sum >> 16);
+
+ }
+
+ return (UINT16) Sum;
+}
+
+
+/**
+ Add two checksums.
+
+ @param[in] Checksum1 The first checksum to be added.
+ @param[in] Checksum2 The second checksum to be added.
+
+ @return The new checksum.
+
+**/
+UINT16
+EFIAPI
+NetAddChecksum (
+ IN UINT16 Checksum1,
+ IN UINT16 Checksum2
+ )
+{
+ UINT32 Sum;
+
+ Sum = Checksum1 + Checksum2;
+
+ //
+ // two UINT16 can only add up to a carry of 1.
+ //
+ if ((Sum >> 16) != 0) {
+ Sum = (Sum & 0xffff) + 1;
+
+ }
+
+ return (UINT16) Sum;
+}
+
+
+/**
+ Compute the checksum for a NET_BUF.
+
+ @param[in] Nbuf Pointer to the net buffer.
+
+ @return The computed checksum.
+
+**/
+UINT16
+EFIAPI
+NetbufChecksum (
+ IN NET_BUF *Nbuf
+ )
+{
+ NET_BLOCK_OP *BlockOp;
+ UINT32 Offset;
+ UINT16 TotalSum;
+ UINT16 BlockSum;
+ UINT32 Index;
+
+ NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
+
+ TotalSum = 0;
+ Offset = 0;
+ BlockOp = Nbuf->BlockOp;
+
+ for (Index = 0; Index < Nbuf->BlockOpNum; Index++) {
+ if (BlockOp[Index].Size == 0) {
+ continue;
+ }
+
+ BlockSum = NetblockChecksum (BlockOp[Index].Head, BlockOp[Index].Size);
+
+ if ((Offset & 0x01) != 0) {
+ //
+ // The checksum starts with an odd byte, swap
+ // the checksum before added to total checksum
+ //
+ BlockSum = SwapBytes16 (BlockSum);
+ }
+
+ TotalSum = NetAddChecksum (BlockSum, TotalSum);
+ Offset += BlockOp[Index].Size;
+ }
+
+ return TotalSum;
+}
+
+
+/**
+ Compute the checksum for TCP/UDP pseudo header.
+
+ Src and Dst are in network byte order, and Len is in host byte order.
+
+ @param[in] Src The source address of the packet.
+ @param[in] Dst The destination address of the packet.
+ @param[in] Proto The protocol type of the packet.
+ @param[in] Len The length of the packet.
+
+ @return The computed checksum.
+
+**/
+UINT16
+EFIAPI
+NetPseudoHeadChecksum (
+ IN IP4_ADDR Src,
+ IN IP4_ADDR Dst,
+ IN UINT8 Proto,
+ IN UINT16 Len
+ )
+{
+ NET_PSEUDO_HDR Hdr;
+
+ //
+ // Zero the memory to relieve align problems
+ //
+ ZeroMem (&Hdr, sizeof (Hdr));
+
+ Hdr.SrcIp = Src;
+ Hdr.DstIp = Dst;
+ Hdr.Protocol = Proto;
+ Hdr.Len = HTONS (Len);
+
+ return NetblockChecksum ((UINT8 *) &Hdr, sizeof (Hdr));
+}
+
+/**
+ Compute the checksum for TCP6/UDP6 pseudo header.
+
+ Src and Dst are in network byte order, and Len is in host byte order.
+
+ @param[in] Src The source address of the packet.
+ @param[in] Dst The destination address of the packet.
+ @param[in] NextHeader The protocol type of the packet.
+ @param[in] Len The length of the packet.
+
+ @return The computed checksum.
+
+**/
+UINT16
+EFIAPI
+NetIp6PseudoHeadChecksum (
+ IN EFI_IPv6_ADDRESS *Src,
+ IN EFI_IPv6_ADDRESS *Dst,
+ IN UINT8 NextHeader,
+ IN UINT32 Len
+ )
+{
+ NET_IP6_PSEUDO_HDR Hdr;
+
+ //
+ // Zero the memory to relieve align problems
+ //
+ ZeroMem (&Hdr, sizeof (Hdr));
+
+ IP6_COPY_ADDRESS (&Hdr.SrcIp, Src);
+ IP6_COPY_ADDRESS (&Hdr.DstIp, Dst);
+
+ Hdr.NextHeader = NextHeader;
+ Hdr.Len = HTONL (Len);
+
+ return NetblockChecksum ((UINT8 *) &Hdr, sizeof (Hdr));
+}
+
+/**
+ The function frees the net buffer which allocated by the IP protocol. It releases
+ only the net buffer and doesn't call the external free function.
+
+ This function should be called after finishing the process of mIpSec->ProcessExt()
+ for outbound traffic. The (EFI_IPSEC2_PROTOCOL)->ProcessExt() allocates a new
+ buffer for the ESP, so there needs a function to free the old net buffer.
+
+ @param[in] Nbuf The network buffer to be freed.
+
+**/
+VOID
+NetIpSecNetbufFree (
+ NET_BUF *Nbuf
+ )
+{
+ NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
+ ASSERT (Nbuf->RefCnt > 0);
+
+ Nbuf->RefCnt--;
+
+ if (Nbuf->RefCnt == 0) {
+
+ //
+ // Update Vector only when NBuf is to be released. That is,
+ // all the sharing of Nbuf increse Vector's RefCnt by one
+ //
+ NET_CHECK_SIGNATURE (Nbuf->Vector, NET_VECTOR_SIGNATURE);
+ ASSERT (Nbuf->Vector->RefCnt > 0);
+
+ Nbuf->Vector->RefCnt--;
+
+ if (Nbuf->Vector->RefCnt > 0) {
+ return;
+ }
+
+ //
+ // If NET_VECTOR_OWN_FIRST is set, release the first block since it is
+ // allocated by us
+ //
+ if ((Nbuf->Vector->Flag & NET_VECTOR_OWN_FIRST) != 0) {
+ FreePool (Nbuf->Vector->Block[0].Bulk);
+ }
+ FreePool (Nbuf->Vector);
+ FreePool (Nbuf);
+ }
+}
+
diff --git a/Core/MdeModulePkg/Library/DxePerformanceLib/DxePerformanceLib.c b/Core/MdeModulePkg/Library/DxePerformanceLib/DxePerformanceLib.c
new file mode 100644
index 0000000000..2ddd983126
--- /dev/null
+++ b/Core/MdeModulePkg/Library/DxePerformanceLib/DxePerformanceLib.c
@@ -0,0 +1,429 @@
+/** @file
+ Performance Library
+
+ This library instance provides infrastructure for DXE phase drivers to log performance
+ data. It consumes PerformanceEx or Performance Protocol published by DxeCorePerformanceLib
+ to log performance data. If both PerformanceEx and Performance Protocol is not available, it does not log any
+ performance information.
+
+ Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+
+#include <PiDxe.h>
+
+#include <Guid/Performance.h>
+
+#include <Library/PerformanceLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/PcdLib.h>
+
+//
+// The cached Performance Protocol and PerformanceEx Protocol interface.
+//
+PERFORMANCE_PROTOCOL *mPerformance = NULL;
+PERFORMANCE_EX_PROTOCOL *mPerformanceEx = NULL;
+
+/**
+ The function caches the pointers to PerformanceEx protocol and Performance Protocol.
+
+ The function locates PerformanceEx protocol and Performance Protocol from protocol database.
+
+ @retval EFI_SUCCESS PerformanceEx protocol or Performance Protocol is successfully located.
+ @retval EFI_NOT_FOUND Both PerformanceEx protocol and Performance Protocol are not located to log performance.
+
+**/
+EFI_STATUS
+GetPerformanceProtocol (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ PERFORMANCE_PROTOCOL *Performance;
+ PERFORMANCE_EX_PROTOCOL *PerformanceEx;
+
+ if (mPerformanceEx != NULL || mPerformance != NULL) {
+ return EFI_SUCCESS;
+ }
+
+ Status = gBS->LocateProtocol (&gPerformanceExProtocolGuid, NULL, (VOID **) &PerformanceEx);
+ if (!EFI_ERROR (Status)) {
+ ASSERT (PerformanceEx != NULL);
+ //
+ // Cache PerformanceEx Protocol.
+ //
+ mPerformanceEx = PerformanceEx;
+ return EFI_SUCCESS;
+ }
+
+ Status = gBS->LocateProtocol (&gPerformanceProtocolGuid, NULL, (VOID **) &Performance);
+ if (!EFI_ERROR (Status)) {
+ ASSERT (Performance != NULL);
+ //
+ // Cache performance protocol.
+ //
+ mPerformance = Performance;
+ return EFI_SUCCESS;
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Creates a record for the beginning of a performance measurement.
+
+ Creates a record that contains the Handle, Token, Module and Identifier.
+ If TimeStamp is not zero, then TimeStamp is added to the record as the start time.
+ If TimeStamp is zero, then this function reads the current time stamp
+ and adds that time stamp value to the record as the start time.
+
+ @param Handle Pointer to environment specific context used
+ to identify the component being measured.
+ @param Token Pointer to a Null-terminated ASCII string
+ that identifies the component being measured.
+ @param Module Pointer to a Null-terminated ASCII string
+ that identifies the module being measured.
+ @param TimeStamp 64-bit time stamp.
+ @param Identifier 32-bit identifier. If the value is 0, the created record
+ is same as the one created by StartPerformanceMeasurement.
+
+ @retval RETURN_SUCCESS The start of the measurement was recorded.
+ @retval RETURN_OUT_OF_RESOURCES There are not enough resources to record the measurement.
+
+**/
+RETURN_STATUS
+EFIAPI
+StartPerformanceMeasurementEx (
+ IN CONST VOID *Handle, OPTIONAL
+ IN CONST CHAR8 *Token, OPTIONAL
+ IN CONST CHAR8 *Module, OPTIONAL
+ IN UINT64 TimeStamp,
+ IN UINT32 Identifier
+ )
+{
+ EFI_STATUS Status;
+
+ Status = GetPerformanceProtocol ();
+ if (EFI_ERROR (Status)) {
+ return RETURN_OUT_OF_RESOURCES;
+ }
+
+ if (mPerformanceEx != NULL) {
+ Status = mPerformanceEx->StartGaugeEx (Handle, Token, Module, TimeStamp, Identifier);
+ } else if (mPerformance != NULL) {
+ Status = mPerformance->StartGauge (Handle, Token, Module, TimeStamp);
+ } else {
+ ASSERT (FALSE);
+ }
+
+ return (RETURN_STATUS) Status;
+}
+
+/**
+ Fills in the end time of a performance measurement.
+
+ Looks up the record that matches Handle, Token, Module and Identifier.
+ If the record can not be found then return RETURN_NOT_FOUND.
+ If the record is found and TimeStamp is not zero,
+ then TimeStamp is added to the record as the end time.
+ If the record is found and TimeStamp is zero, then this function reads
+ the current time stamp and adds that time stamp value to the record as the end time.
+
+ @param Handle Pointer to environment specific context used
+ to identify the component being measured.
+ @param Token Pointer to a Null-terminated ASCII string
+ that identifies the component being measured.
+ @param Module Pointer to a Null-terminated ASCII string
+ that identifies the module being measured.
+ @param TimeStamp 64-bit time stamp.
+ @param Identifier 32-bit identifier. If the value is 0, the found record
+ is same as the one found by EndPerformanceMeasurement.
+
+ @retval RETURN_SUCCESS The end of the measurement was recorded.
+ @retval RETURN_NOT_FOUND The specified measurement record could not be found.
+
+**/
+RETURN_STATUS
+EFIAPI
+EndPerformanceMeasurementEx (
+ IN CONST VOID *Handle, OPTIONAL
+ IN CONST CHAR8 *Token, OPTIONAL
+ IN CONST CHAR8 *Module, OPTIONAL
+ IN UINT64 TimeStamp,
+ IN UINT32 Identifier
+ )
+{
+ EFI_STATUS Status;
+
+ Status = GetPerformanceProtocol ();
+ if (EFI_ERROR (Status)) {
+ return RETURN_NOT_FOUND;
+ }
+
+ if (mPerformanceEx != NULL) {
+ Status = mPerformanceEx->EndGaugeEx (Handle, Token, Module, TimeStamp, Identifier);
+ } else if (mPerformance != NULL) {
+ Status = mPerformance->EndGauge (Handle, Token, Module, TimeStamp);
+ } else {
+ ASSERT (FALSE);
+ }
+
+ return (RETURN_STATUS) Status;
+}
+
+/**
+ Attempts to retrieve a performance measurement log entry from the performance measurement log.
+ It can also retrieve the log created by StartPerformanceMeasurement and EndPerformanceMeasurement,
+ and then assign the Identifier with 0.
+
+ Attempts to retrieve the performance log entry specified by LogEntryKey. If LogEntryKey is
+ zero on entry, then an attempt is made to retrieve the first entry from the performance log,
+ and the key for the second entry in the log is returned. If the performance log is empty,
+ then no entry is retrieved and zero is returned. If LogEntryKey is not zero, then the performance
+ log entry associated with LogEntryKey is retrieved, and the key for the next entry in the log is
+ returned. If LogEntryKey is the key for the last entry in the log, then the last log entry is
+ retrieved and an implementation specific non-zero key value that specifies the end of the performance
+ log is returned. If LogEntryKey is equal this implementation specific non-zero key value, then no entry
+ is retrieved and zero is returned. In the cases where a performance log entry can be returned,
+ the log entry is returned in Handle, Token, Module, StartTimeStamp, EndTimeStamp and Identifier.
+ If LogEntryKey is not a valid log entry key for the performance measurement log, then ASSERT().
+ If Handle is NULL, then ASSERT().
+ If Token is NULL, then ASSERT().
+ If Module is NULL, then ASSERT().
+ If StartTimeStamp is NULL, then ASSERT().
+ If EndTimeStamp is NULL, then ASSERT().
+ If Identifier is NULL, then ASSERT().
+
+ @param LogEntryKey On entry, the key of the performance measurement log entry to retrieve.
+ 0, then the first performance measurement log entry is retrieved.
+ On exit, the key of the next performance log entry.
+ @param Handle Pointer to environment specific context used to identify the component
+ being measured.
+ @param Token Pointer to a Null-terminated ASCII string that identifies the component
+ being measured.
+ @param Module Pointer to a Null-terminated ASCII string that identifies the module
+ being measured.
+ @param StartTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
+ was started.
+ @param EndTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
+ was ended.
+ @param Identifier Pointer to the 32-bit identifier that was recorded.
+
+ @return The key for the next performance log entry (in general case).
+
+**/
+UINTN
+EFIAPI
+GetPerformanceMeasurementEx (
+ IN UINTN LogEntryKey,
+ OUT CONST VOID **Handle,
+ OUT CONST CHAR8 **Token,
+ OUT CONST CHAR8 **Module,
+ OUT UINT64 *StartTimeStamp,
+ OUT UINT64 *EndTimeStamp,
+ OUT UINT32 *Identifier
+ )
+{
+ EFI_STATUS Status;
+ GAUGE_DATA_ENTRY_EX *GaugeData;
+
+ GaugeData = NULL;
+
+ ASSERT (Handle != NULL);
+ ASSERT (Token != NULL);
+ ASSERT (Module != NULL);
+ ASSERT (StartTimeStamp != NULL);
+ ASSERT (EndTimeStamp != NULL);
+ ASSERT (Identifier != NULL);
+
+ Status = GetPerformanceProtocol ();
+ if (EFI_ERROR (Status)) {
+ return 0;
+ }
+
+ if (mPerformanceEx != NULL) {
+ Status = mPerformanceEx->GetGaugeEx (LogEntryKey++, &GaugeData);
+ } else if (mPerformance != NULL) {
+ Status = mPerformance->GetGauge (LogEntryKey++, (GAUGE_DATA_ENTRY **) &GaugeData);
+ } else {
+ ASSERT (FALSE);
+ return 0;
+ }
+
+ //
+ // Make sure that LogEntryKey is a valid log entry key,
+ //
+ ASSERT (Status != EFI_INVALID_PARAMETER);
+
+ if (EFI_ERROR (Status)) {
+ //
+ // The LogEntryKey is the last entry (equals to the total entry number).
+ //
+ return 0;
+ }
+
+ ASSERT (GaugeData != NULL);
+
+ *Handle = (VOID *) (UINTN) GaugeData->Handle;
+ *Token = GaugeData->Token;
+ *Module = GaugeData->Module;
+ *StartTimeStamp = GaugeData->StartTimeStamp;
+ *EndTimeStamp = GaugeData->EndTimeStamp;
+ if (mPerformanceEx != NULL) {
+ *Identifier = GaugeData->Identifier;
+ } else {
+ *Identifier = 0;
+ }
+
+ return LogEntryKey;
+}
+
+/**
+ Creates a record for the beginning of a performance measurement.
+
+ Creates a record that contains the Handle, Token, and Module.
+ If TimeStamp is not zero, then TimeStamp is added to the record as the start time.
+ If TimeStamp is zero, then this function reads the current time stamp
+ and adds that time stamp value to the record as the start time.
+
+ @param Handle Pointer to environment specific context used
+ to identify the component being measured.
+ @param Token Pointer to a Null-terminated ASCII string
+ that identifies the component being measured.
+ @param Module Pointer to a Null-terminated ASCII string
+ that identifies the module being measured.
+ @param TimeStamp 64-bit time stamp.
+
+ @retval RETURN_SUCCESS The start of the measurement was recorded.
+ @retval RETURN_OUT_OF_RESOURCES There are not enough resources to record the measurement.
+
+**/
+RETURN_STATUS
+EFIAPI
+StartPerformanceMeasurement (
+ IN CONST VOID *Handle, OPTIONAL
+ IN CONST CHAR8 *Token, OPTIONAL
+ IN CONST CHAR8 *Module, OPTIONAL
+ IN UINT64 TimeStamp
+ )
+{
+ return StartPerformanceMeasurementEx (Handle, Token, Module, TimeStamp, 0);
+}
+
+/**
+ Fills in the end time of a performance measurement.
+
+ Looks up the record that matches Handle, Token, and Module.
+ If the record can not be found then return RETURN_NOT_FOUND.
+ If the record is found and TimeStamp is not zero,
+ then TimeStamp is added to the record as the end time.
+ If the record is found and TimeStamp is zero, then this function reads
+ the current time stamp and adds that time stamp value to the record as the end time.
+
+ @param Handle Pointer to environment specific context used
+ to identify the component being measured.
+ @param Token Pointer to a Null-terminated ASCII string
+ that identifies the component being measured.
+ @param Module Pointer to a Null-terminated ASCII string
+ that identifies the module being measured.
+ @param TimeStamp 64-bit time stamp.
+
+ @retval RETURN_SUCCESS The end of the measurement was recorded.
+ @retval RETURN_NOT_FOUND The specified measurement record could not be found.
+
+**/
+RETURN_STATUS
+EFIAPI
+EndPerformanceMeasurement (
+ IN CONST VOID *Handle, OPTIONAL
+ IN CONST CHAR8 *Token, OPTIONAL
+ IN CONST CHAR8 *Module, OPTIONAL
+ IN UINT64 TimeStamp
+ )
+{
+ return EndPerformanceMeasurementEx (Handle, Token, Module, TimeStamp, 0);
+}
+
+/**
+ Attempts to retrieve a performance measurement log entry from the performance measurement log.
+ It can also retrieve the log created by StartPerformanceMeasurementEx and EndPerformanceMeasurementEx,
+ and then eliminate the Identifier.
+
+ Attempts to retrieve the performance log entry specified by LogEntryKey. If LogEntryKey is
+ zero on entry, then an attempt is made to retrieve the first entry from the performance log,
+ and the key for the second entry in the log is returned. If the performance log is empty,
+ then no entry is retrieved and zero is returned. If LogEntryKey is not zero, then the performance
+ log entry associated with LogEntryKey is retrieved, and the key for the next entry in the log is
+ returned. If LogEntryKey is the key for the last entry in the log, then the last log entry is
+ retrieved and an implementation specific non-zero key value that specifies the end of the performance
+ log is returned. If LogEntryKey is equal this implementation specific non-zero key value, then no entry
+ is retrieved and zero is returned. In the cases where a performance log entry can be returned,
+ the log entry is returned in Handle, Token, Module, StartTimeStamp, and EndTimeStamp.
+ If LogEntryKey is not a valid log entry key for the performance measurement log, then ASSERT().
+ If Handle is NULL, then ASSERT().
+ If Token is NULL, then ASSERT().
+ If Module is NULL, then ASSERT().
+ If StartTimeStamp is NULL, then ASSERT().
+ If EndTimeStamp is NULL, then ASSERT().
+
+ @param LogEntryKey On entry, the key of the performance measurement log entry to retrieve.
+ 0, then the first performance measurement log entry is retrieved.
+ On exit, the key of the next performance log entry.
+ @param Handle Pointer to environment specific context used to identify the component
+ being measured.
+ @param Token Pointer to a Null-terminated ASCII string that identifies the component
+ being measured.
+ @param Module Pointer to a Null-terminated ASCII string that identifies the module
+ being measured.
+ @param StartTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
+ was started.
+ @param EndTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
+ was ended.
+
+ @return The key for the next performance log entry (in general case).
+
+**/
+UINTN
+EFIAPI
+GetPerformanceMeasurement (
+ IN UINTN LogEntryKey,
+ OUT CONST VOID **Handle,
+ OUT CONST CHAR8 **Token,
+ OUT CONST CHAR8 **Module,
+ OUT UINT64 *StartTimeStamp,
+ OUT UINT64 *EndTimeStamp
+ )
+{
+ UINT32 Identifier;
+ return GetPerformanceMeasurementEx (LogEntryKey, Handle, Token, Module, StartTimeStamp, EndTimeStamp, &Identifier);
+}
+
+/**
+ Returns TRUE if the performance measurement macros are enabled.
+
+ This function returns TRUE if the PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
+ PcdPerformanceLibraryPropertyMask is set. Otherwise FALSE is returned.
+
+ @retval TRUE The PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
+ PcdPerformanceLibraryPropertyMask is set.
+ @retval FALSE The PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
+ PcdPerformanceLibraryPropertyMask is clear.
+
+**/
+BOOLEAN
+EFIAPI
+PerformanceMeasurementEnabled (
+ VOID
+ )
+{
+ return (BOOLEAN) ((PcdGet8(PcdPerformanceLibraryPropertyMask) & PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED) != 0);
+}
diff --git a/Core/MdeModulePkg/Library/DxePerformanceLib/DxePerformanceLib.inf b/Core/MdeModulePkg/Library/DxePerformanceLib/DxePerformanceLib.inf
new file mode 100644
index 0000000000..edc63c6f0b
--- /dev/null
+++ b/Core/MdeModulePkg/Library/DxePerformanceLib/DxePerformanceLib.inf
@@ -0,0 +1,57 @@
+## @file
+# Performance library instance used in DXE phase.
+#
+# This library instance provides infrastructure for DXE phase drivers to log performance
+# data. It consumes PerformanceEx or Performance Protocol published by DxeCorePerformanceLib
+# to log performance data. If both PerformanceEx and Performance Protocol are not available,
+# it does not log any performance information.
+#
+# Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxePerformanceLib
+ MODULE_UNI_FILE = DxePerformanceLib.uni
+ FILE_GUID = 8B8B4CCC-65FC-41a5-8067-308B8E42CCF2
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = PerformanceLib|DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SAL_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ DxePerformanceLib.c
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+
+[LibraryClasses]
+ PcdLib
+ UefiBootServicesTableLib
+ DebugLib
+
+
+[Guids]
+ gPerformanceProtocolGuid ## SOMETIMES_CONSUMES ## UNDEFINED # Locate protocol
+ gPerformanceExProtocolGuid ## SOMETIMES_CONSUMES ## UNDEFINED # Locate protocol
+
+
+[Pcd]
+ gEfiMdePkgTokenSpaceGuid.PcdPerformanceLibraryPropertyMask ## CONSUMES
+
diff --git a/Core/MdeModulePkg/Library/DxePerformanceLib/DxePerformanceLib.uni b/Core/MdeModulePkg/Library/DxePerformanceLib/DxePerformanceLib.uni
new file mode 100644
index 0000000000..d2997bce98
--- /dev/null
+++ b/Core/MdeModulePkg/Library/DxePerformanceLib/DxePerformanceLib.uni
Binary files differ
diff --git a/Core/MdeModulePkg/Library/DxePrintLibPrint2Protocol/DxePrintLibPrint2Protocol.inf b/Core/MdeModulePkg/Library/DxePrintLibPrint2Protocol/DxePrintLibPrint2Protocol.inf
new file mode 100644
index 0000000000..3d09b4be4d
--- /dev/null
+++ b/Core/MdeModulePkg/Library/DxePrintLibPrint2Protocol/DxePrintLibPrint2Protocol.inf
@@ -0,0 +1,41 @@
+## @file
+# Library instance that implements Print Library class based on protocol gEfiPrint2ProtocolGuid.
+#
+# Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxePrintLibPrint2Protocol
+ MODULE_UNI_FILE = DxePrintLibPrint2Protocol.uni
+ FILE_GUID = 55D460DB-8FEA-415a-B95D-70145AE0675C
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = PrintLib|DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SAL_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER
+ CONSTRUCTOR = PrintLibConstructor
+
+[Sources]
+ PrintLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ DebugLib
+
+[Protocols]
+ gEfiPrint2ProtocolGuid ## CONSUMES
+
+[Depex.common.DXE_DRIVER, Depex.common.DXE_RUNTIME_DRIVER, Depex.common.DXE_SAL_DRIVER, Depex.common.DXE_SMM_DRIVER]
+ gEfiPrint2ProtocolGuid
diff --git a/Core/MdeModulePkg/Library/DxePrintLibPrint2Protocol/DxePrintLibPrint2Protocol.uni b/Core/MdeModulePkg/Library/DxePrintLibPrint2Protocol/DxePrintLibPrint2Protocol.uni
new file mode 100644
index 0000000000..96a8bd0a09
--- /dev/null
+++ b/Core/MdeModulePkg/Library/DxePrintLibPrint2Protocol/DxePrintLibPrint2Protocol.uni
Binary files differ
diff --git a/Core/MdeModulePkg/Library/DxePrintLibPrint2Protocol/PrintLib.c b/Core/MdeModulePkg/Library/DxePrintLibPrint2Protocol/PrintLib.c
new file mode 100644
index 0000000000..4acdcb8714
--- /dev/null
+++ b/Core/MdeModulePkg/Library/DxePrintLibPrint2Protocol/PrintLib.c
@@ -0,0 +1,1921 @@
+/** @file
+ Instance of Print Library based on gEfiPrint2ProtocolGuid.
+
+ Implement the print library instance by wrap the interface
+ provided in the Print2 protocol. This protocol is defined as the internal
+ protocol related to this implementation, not in the public spec. So, this
+ library instance is only for this code base.
+
+Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Uefi.h>
+#include <Base.h>
+#include <Protocol/Print2.h>
+
+#include <Library/PrintLib.h>
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+
+EFI_PRINT2_PROTOCOL *mPrint2Protocol = NULL;
+
+/**
+ The constructor function caches the pointer to Print2 protocol.
+
+ The constructor function locates Print2 protocol from protocol database.
+ It will ASSERT() if that operation fails and it will always return EFI_SUCCESS.
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
+
+**/
+EFI_STATUS
+EFIAPI
+PrintLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ Status = SystemTable->BootServices->LocateProtocol (
+ &gEfiPrint2ProtocolGuid,
+ NULL,
+ (VOID**) &mPrint2Protocol
+ );
+ ASSERT_EFI_ERROR (Status);
+ ASSERT (mPrint2Protocol != NULL);
+
+ return Status;
+}
+
+
+/**
+ Worker function that converts a VA_LIST to a BASE_LIST based on a Null-terminated
+ format string.
+
+ @param AsciiFormat TRUE if Format is an ASCII string. FALSE if Format is a Unicode string.
+ @param Format Null-terminated format string.
+ @param VaListMarker VA_LIST style variable argument list consumed by processing Format.
+ @param BaseListMarker BASE_LIST style variable argument list consumed by processing Format.
+ @param Size The size, in bytes, of the BaseListMarker buffer.
+
+ @return The number of bytes in BaseListMarker. 0 if BaseListMarker is too small.
+
+**/
+BOOLEAN
+DxePrintLibPrint2ProtocolVaListToBaseList (
+ IN BOOLEAN AsciiFormat,
+ IN CONST CHAR8 *Format,
+ IN VA_LIST VaListMarker,
+ OUT BASE_LIST BaseListMarker,
+ IN UINTN Size
+ )
+{
+ BASE_LIST BaseListStart;
+ UINTN BytesPerFormatCharacter;
+ UINTN FormatMask;
+ UINTN FormatCharacter;
+ BOOLEAN Long;
+ BOOLEAN Done;
+
+ ASSERT (Format != NULL);
+ ASSERT (BaseListMarker != NULL);
+
+ BaseListStart = BaseListMarker;
+
+ if (AsciiFormat) {
+ ASSERT (AsciiStrSize (Format) != 0);
+ BytesPerFormatCharacter = 1;
+ FormatMask = 0xff;
+ } else {
+ ASSERT (StrSize ((CHAR16 *) Format) != 0);
+ BytesPerFormatCharacter = 2;
+ FormatMask = 0xffff;
+ }
+
+ //
+ // Get the first character from the format string
+ //
+ FormatCharacter = ((*Format & 0xff) | (*(Format + 1) << 8)) & FormatMask;
+
+ while (FormatCharacter != 0) {
+ if (FormatCharacter == '%') {
+ Long = FALSE;
+
+ //
+ // Parse Flags and Width
+ //
+ for (Done = FALSE; !Done; ) {
+ //
+ // Get the next character from the format string
+ //
+ Format += BytesPerFormatCharacter;
+
+ //
+ // Get the next character from the format string
+ //
+ FormatCharacter = ((*Format & 0xff) | (*(Format + 1) << 8)) & FormatMask;
+
+ switch (FormatCharacter) {
+ case '.':
+ case '-':
+ case '+':
+ case ' ':
+ case ',':
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ break;
+ case 'L':
+ case 'l':
+ Long = TRUE;
+ break;
+ case '*':
+ BASE_ARG (BaseListMarker, UINTN) = VA_ARG (VaListMarker, UINTN);
+ break;
+ case '\0':
+ //
+ // Make no output if Format string terminates unexpectedly when
+ // looking up for flag, width, precision and type.
+ //
+ Format -= BytesPerFormatCharacter;
+ //
+ // break skipped on purpose.
+ //
+ default:
+ Done = TRUE;
+ break;
+ }
+ }
+
+ //
+ // Handle each argument type
+ //
+ switch (FormatCharacter) {
+ case 'p':
+ if (sizeof (VOID *) > 4) {
+ Long = TRUE;
+ }
+ case 'X':
+ case 'x':
+ case 'u':
+ case 'd':
+ if (Long) {
+ BASE_ARG (BaseListMarker, INT64) = VA_ARG (VaListMarker, INT64);
+ } else {
+ BASE_ARG (BaseListMarker, int) = VA_ARG (VaListMarker, int);
+ }
+ break;
+ case 's':
+ case 'S':
+ case 'a':
+ case 'g':
+ case 't':
+ BASE_ARG (BaseListMarker, VOID *) = VA_ARG (VaListMarker, VOID *);
+ break;
+ case 'c':
+ BASE_ARG (BaseListMarker, UINTN) = VA_ARG (VaListMarker, UINTN);
+ break;
+ case 'r':
+ BASE_ARG (BaseListMarker, RETURN_STATUS) = VA_ARG (VaListMarker, RETURN_STATUS);
+ break;
+ }
+ }
+
+ //
+ // If BASE_LIST is larger than Size, then return FALSE
+ //
+ if ((UINTN)((UINT8 *)BaseListMarker - (UINT8 *)BaseListStart) > Size) {
+ return FALSE;
+ }
+
+ //
+ // Get the next character from the format string
+ //
+ Format += BytesPerFormatCharacter;
+
+ //
+ // Get the next character from the format string
+ //
+ FormatCharacter = ((*Format & 0xff) | (*(Format + 1) << 8)) & FormatMask;
+ }
+ return TRUE;
+}
+
+/**
+ Produces a Null-terminated Unicode string in an output buffer based on
+ a Null-terminated Unicode format string and a VA_LIST argument list
+
+ Produces a Null-terminated Unicode string in the output buffer specified by StartOfBuffer
+ and BufferSize.
+ The Unicode string is produced by parsing the format string specified by FormatString.
+ Arguments are pulled from the variable argument list specified by Marker based on the
+ contents of the format string.
+ The number of Unicode characters in the produced output buffer is returned not including
+ the Null-terminator.
+ If BufferSize is 0 or 1, then no output buffer is produced and 0 is returned.
+
+ If BufferSize > 1 and StartOfBuffer is NULL, then ASSERT().
+ If BufferSize > 1 and StartOfBuffer is not aligned on a 16-bit boundary, then ASSERT().
+ If BufferSize > 1 and FormatString is NULL, then ASSERT().
+ If BufferSize > 1 and FormatString is not aligned on a 16-bit boundary, then ASSERT().
+ If PcdMaximumUnicodeStringLength is not zero, and FormatString contains more than
+ PcdMaximumUnicodeStringLength Unicode characters not including the Null-terminator, then
+ ASSERT().
+ If PcdMaximumUnicodeStringLength is not zero, and produced Null-terminated Unicode string
+ contains more than PcdMaximumUnicodeStringLength Unicode characters not including the
+ Null-terminator, then ASSERT().
+
+ @param StartOfBuffer A pointer to the output buffer for the produced Null-terminated
+ Unicode string.
+ @param BufferSize The size, in bytes, of the output buffer specified by StartOfBuffer.
+ @param FormatString Null-terminated Unicode format string.
+ @param Marker VA_LIST marker for the variable argument list.
+
+ @return The number of Unicode characters in the produced output buffer not including the
+ Null-terminator.
+
+**/
+UINTN
+EFIAPI
+UnicodeVSPrint (
+ OUT CHAR16 *StartOfBuffer,
+ IN UINTN BufferSize,
+ IN CONST CHAR16 *FormatString,
+ IN VA_LIST Marker
+ )
+{
+ UINT64 BaseListMarker[256 / sizeof (UINT64)];
+
+ DxePrintLibPrint2ProtocolVaListToBaseList (
+ FALSE,
+ (CHAR8 *)FormatString,
+ Marker,
+ (BASE_LIST)BaseListMarker,
+ sizeof (BaseListMarker) - 8
+ );
+
+ return UnicodeBSPrint (StartOfBuffer, BufferSize, FormatString, (BASE_LIST)BaseListMarker);
+}
+
+/**
+ Produces a Null-terminated Unicode string in an output buffer based on
+ a Null-terminated Unicode format string and a BASE_LIST argument list
+
+ Produces a Null-terminated Unicode string in the output buffer specified by StartOfBuffer
+ and BufferSize.
+ The Unicode string is produced by parsing the format string specified by FormatString.
+ Arguments are pulled from the variable argument list specified by Marker based on the
+ contents of the format string.
+ The number of Unicode characters in the produced output buffer is returned not including
+ the Null-terminator.
+ If BufferSize is 0 or 1, then no output buffer is produced and 0 is returned.
+
+ If BufferSize > 1 and StartOfBuffer is NULL, then ASSERT().
+ If BufferSize > 1 and StartOfBuffer is not aligned on a 16-bit boundary, then ASSERT().
+ If BufferSize > 1 and FormatString is NULL, then ASSERT().
+ If BufferSize > 1 and FormatString is not aligned on a 16-bit boundary, then ASSERT().
+ If PcdMaximumUnicodeStringLength is not zero, and FormatString contains more than
+ PcdMaximumUnicodeStringLength Unicode characters not including the Null-terminator, then
+ ASSERT().
+ If PcdMaximumUnicodeStringLength is not zero, and produced Null-terminated Unicode string
+ contains more than PcdMaximumUnicodeStringLength Unicode characters not including the
+ Null-terminator, then ASSERT().
+
+ @param StartOfBuffer A pointer to the output buffer for the produced Null-terminated
+ Unicode string.
+ @param BufferSize The size, in bytes, of the output buffer specified by StartOfBuffer.
+ @param FormatString Null-terminated Unicode format string.
+ @param Marker BASE_LIST marker for the variable argument list.
+
+ @return The number of Unicode characters in the produced output buffer not including the
+ Null-terminator.
+
+**/
+UINTN
+EFIAPI
+UnicodeBSPrint (
+ OUT CHAR16 *StartOfBuffer,
+ IN UINTN BufferSize,
+ IN CONST CHAR16 *FormatString,
+ IN BASE_LIST Marker
+ )
+{
+ return mPrint2Protocol->UnicodeBSPrint (StartOfBuffer, BufferSize, FormatString, Marker);
+}
+
+/**
+ Produces a Null-terminated Unicode string in an output buffer based on a Null-terminated
+ Unicode format string and variable argument list.
+
+ Produces a Null-terminated Unicode string in the output buffer specified by StartOfBuffer
+ and BufferSize.
+ The Unicode string is produced by parsing the format string specified by FormatString.
+ Arguments are pulled from the variable argument list based on the contents of the format string.
+ The number of Unicode characters in the produced output buffer is returned not including
+ the Null-terminator.
+ If BufferSize is 0 or 1, then no output buffer is produced and 0 is returned.
+
+ If BufferSize > 1 and StartOfBuffer is NULL, then ASSERT().
+ If BufferSize > 1 and StartOfBuffer is not aligned on a 16-bit boundary, then ASSERT().
+ If BufferSize > 1 and FormatString is NULL, then ASSERT().
+ If BufferSize > 1 and FormatString is not aligned on a 16-bit boundary, then ASSERT().
+ If PcdMaximumUnicodeStringLength is not zero, and FormatString contains more than
+ PcdMaximumUnicodeStringLength Unicode characters not including the Null-terminator, then
+ ASSERT().
+ If PcdMaximumUnicodeStringLength is not zero, and produced Null-terminated Unicode string
+ contains more than PcdMaximumUnicodeStringLength Unicode characters not including the
+ Null-terminator, then ASSERT().
+
+ @param StartOfBuffer A pointer to the output buffer for the produced Null-terminated
+ Unicode string.
+ @param BufferSize The size, in bytes, of the output buffer specified by StartOfBuffer.
+ @param FormatString Null-terminated Unicode format string.
+ @param ... Variable argument list whose contents are accessed based on the
+ format string specified by FormatString.
+
+ @return The number of Unicode characters in the produced output buffer not including the
+ Null-terminator.
+
+**/
+UINTN
+EFIAPI
+UnicodeSPrint (
+ OUT CHAR16 *StartOfBuffer,
+ IN UINTN BufferSize,
+ IN CONST CHAR16 *FormatString,
+ ...
+ )
+{
+ VA_LIST Marker;
+ UINTN NumberOfPrinted;
+
+ VA_START (Marker, FormatString);
+ NumberOfPrinted = UnicodeVSPrint (StartOfBuffer, BufferSize, FormatString, Marker);
+ VA_END (Marker);
+ return NumberOfPrinted;
+}
+
+/**
+ Produces a Null-terminated Unicode string in an output buffer based on a Null-terminated
+ ASCII format string and a VA_LIST argument list
+
+ Produces a Null-terminated Unicode string in the output buffer specified by StartOfBuffer
+ and BufferSize.
+ The Unicode string is produced by parsing the format string specified by FormatString.
+ Arguments are pulled from the variable argument list specified by Marker based on the
+ contents of the format string.
+ The number of Unicode characters in the produced output buffer is returned not including
+ the Null-terminator.
+ If BufferSize is 0 or 1, then no output buffer is produced and 0 is returned.
+
+ If BufferSize > 1 and StartOfBuffer is NULL, then ASSERT().
+ If BufferSize > 1 and StartOfBuffer is not aligned on a 16-bit boundary, then ASSERT().
+ If BufferSize > 1 and FormatString is NULL, then ASSERT().
+ If PcdMaximumAsciiStringLength is not zero, and FormatString contains more than
+ PcdMaximumAsciiStringLength ASCII characters not including the Null-terminator, then
+ ASSERT().
+ If PcdMaximumUnicodeStringLength is not zero, and produced Null-terminated Unicode string
+ contains more than PcdMaximumUnicodeStringLength Unicode characters not including the
+ Null-terminator, then ASSERT().
+
+ @param StartOfBuffer A pointer to the output buffer for the produced Null-terminated
+ Unicode string.
+ @param BufferSize The size, in bytes, of the output buffer specified by StartOfBuffer.
+ @param FormatString Null-terminated Unicode format string.
+ @param Marker VA_LIST marker for the variable argument list.
+
+ @return The number of Unicode characters in the produced output buffer not including the
+ Null-terminator.
+
+**/
+UINTN
+EFIAPI
+UnicodeVSPrintAsciiFormat (
+ OUT CHAR16 *StartOfBuffer,
+ IN UINTN BufferSize,
+ IN CONST CHAR8 *FormatString,
+ IN VA_LIST Marker
+ )
+{
+ UINT64 BaseListMarker[256 / sizeof (UINT64)];
+
+ DxePrintLibPrint2ProtocolVaListToBaseList (
+ TRUE,
+ FormatString,
+ Marker,
+ (BASE_LIST)BaseListMarker,
+ sizeof (BaseListMarker) - 8
+ );
+
+ return UnicodeBSPrintAsciiFormat (StartOfBuffer, BufferSize, FormatString, (BASE_LIST)BaseListMarker);
+}
+
+/**
+ Produces a Null-terminated Unicode string in an output buffer based on a Null-terminated
+ ASCII format string and a BASE_LIST argument list
+
+ Produces a Null-terminated Unicode string in the output buffer specified by StartOfBuffer
+ and BufferSize.
+ The Unicode string is produced by parsing the format string specified by FormatString.
+ Arguments are pulled from the variable argument list specified by Marker based on the
+ contents of the format string.
+ The number of Unicode characters in the produced output buffer is returned not including
+ the Null-terminator.
+ If BufferSize is 0 or 1, then no output buffer is produced and 0 is returned.
+
+ If BufferSize > 1 and StartOfBuffer is NULL, then ASSERT().
+ If BufferSize > 1 and StartOfBuffer is not aligned on a 16-bit boundary, then ASSERT().
+ If BufferSize > 1 and FormatString is NULL, then ASSERT().
+ If PcdMaximumAsciiStringLength is not zero, and FormatString contains more than
+ PcdMaximumAsciiStringLength ASCII characters not including the Null-terminator, then
+ ASSERT().
+ If PcdMaximumUnicodeStringLength is not zero, and produced Null-terminated Unicode string
+ contains more than PcdMaximumUnicodeStringLength Unicode characters not including the
+ Null-terminator, then ASSERT().
+
+ @param StartOfBuffer A pointer to the output buffer for the produced Null-terminated
+ Unicode string.
+ @param BufferSize The size, in bytes, of the output buffer specified by StartOfBuffer.
+ @param FormatString Null-terminated Unicode format string.
+ @param Marker BASE_LIST marker for the variable argument list.
+
+ @return The number of Unicode characters in the produced output buffer not including the
+ Null-terminator.
+
+**/
+UINTN
+EFIAPI
+UnicodeBSPrintAsciiFormat (
+ OUT CHAR16 *StartOfBuffer,
+ IN UINTN BufferSize,
+ IN CONST CHAR8 *FormatString,
+ IN BASE_LIST Marker
+ )
+{
+ return mPrint2Protocol->UnicodeBSPrintAsciiFormat (StartOfBuffer, BufferSize, FormatString, Marker);
+}
+
+/**
+ Produces a Null-terminated Unicode string in an output buffer based on a Null-terminated
+ ASCII format string and variable argument list.
+
+ Produces a Null-terminated Unicode string in the output buffer specified by StartOfBuffer
+ and BufferSize.
+ The Unicode string is produced by parsing the format string specified by FormatString.
+ Arguments are pulled from the variable argument list based on the contents of the
+ format string.
+ The number of Unicode characters in the produced output buffer is returned not including
+ the Null-terminator.
+ If BufferSize is 0 or 1, then no output buffer is produced and 0 is returned.
+
+ If BufferSize > 1 and StartOfBuffer is NULL, then ASSERT().
+ If BufferSize > 1 and StartOfBuffer is not aligned on a 16-bit boundary, then ASSERT().
+ If BufferSize > 1 and FormatString is NULL, then ASSERT().
+ If PcdMaximumAsciiStringLength is not zero, and FormatString contains more than
+ PcdMaximumAsciiStringLength ASCII characters not including the Null-terminator, then
+ ASSERT().
+ If PcdMaximumUnicodeStringLength is not zero, and produced Null-terminated Unicode string
+ contains more than PcdMaximumUnicodeStringLength Unicode characters not including the
+ Null-terminator, then ASSERT().
+
+ @param StartOfBuffer A pointer to the output buffer for the produced Null-terminated
+ Unicode string.
+ @param BufferSize The size, in bytes, of the output buffer specified by StartOfBuffer.
+ @param FormatString Null-terminated Unicode format string.
+ @param ... Variable argument list whose contents are accessed based on the
+ format string specified by FormatString.
+
+ @return The number of Unicode characters in the produced output buffer not including the
+ Null-terminator.
+
+**/
+UINTN
+EFIAPI
+UnicodeSPrintAsciiFormat (
+ OUT CHAR16 *StartOfBuffer,
+ IN UINTN BufferSize,
+ IN CONST CHAR8 *FormatString,
+ ...
+ )
+{
+ VA_LIST Marker;
+ UINTN NumberOfPrinted;
+
+ VA_START (Marker, FormatString);
+ NumberOfPrinted = UnicodeVSPrintAsciiFormat (StartOfBuffer, BufferSize, FormatString, Marker);
+ VA_END (Marker);
+ return NumberOfPrinted;
+}
+
+/**
+ Converts a decimal value to a Null-terminated Unicode string.
+
+ Converts the decimal number specified by Value to a Null-terminated Unicode
+ string specified by Buffer containing at most Width characters. No padding of spaces
+ is ever performed. If Width is 0 then a width of MAXIMUM_VALUE_CHARACTERS is assumed.
+ The number of Unicode characters in Buffer is returned not including the Null-terminator.
+ If the conversion contains more than Width characters, then only the first
+ Width characters are returned, and the total number of characters
+ required to perform the conversion is returned.
+ Additional conversion parameters are specified in Flags.
+
+ The Flags bit LEFT_JUSTIFY is always ignored.
+ All conversions are left justified in Buffer.
+ If Width is 0, PREFIX_ZERO is ignored in Flags.
+ If COMMA_TYPE is set in Flags, then PREFIX_ZERO is ignored in Flags, and commas
+ are inserted every 3rd digit starting from the right.
+ If RADIX_HEX is set in Flags, then the output buffer will be
+ formatted in hexadecimal format.
+ If Value is < 0 and RADIX_HEX is not set in Flags, then the fist character in Buffer is a '-'.
+ If PREFIX_ZERO is set in Flags and PREFIX_ZERO is not being ignored,
+ then Buffer is padded with '0' characters so the combination of the optional '-'
+ sign character, '0' characters, digit characters for Value, and the Null-terminator
+ add up to Width characters.
+ If both COMMA_TYPE and RADIX_HEX are set in Flags, then ASSERT().
+ If Buffer is NULL, then ASSERT().
+ If Buffer is not aligned on a 16-bit boundary, then ASSERT().
+ If unsupported bits are set in Flags, then ASSERT().
+ If both COMMA_TYPE and RADIX_HEX are set in Flags, then ASSERT().
+ If Width >= MAXIMUM_VALUE_CHARACTERS, then ASSERT()
+
+ @param Buffer Pointer to the output buffer for the produced Null-terminated
+ Unicode string.
+ @param Flags The bitmask of flags that specify left justification, zero pad, and commas.
+ @param Value The 64-bit signed value to convert to a string.
+ @param Width The maximum number of Unicode characters to place in Buffer, not including
+ the Null-terminator.
+
+ @return The number of Unicode characters in Buffer not including the Null-terminator.
+
+**/
+UINTN
+EFIAPI
+UnicodeValueToString (
+ IN OUT CHAR16 *Buffer,
+ IN UINTN Flags,
+ IN INT64 Value,
+ IN UINTN Width
+ )
+{
+ return mPrint2Protocol->UnicodeValueToString (Buffer, Flags, Value, Width);
+}
+
+/**
+ Produces a Null-terminated ASCII string in an output buffer based on a Null-terminated
+ ASCII format string and a VA_LIST argument list.
+
+ Produces a Null-terminated ASCII string in the output buffer specified by StartOfBuffer
+ and BufferSize.
+ The ASCII string is produced by parsing the format string specified by FormatString.
+ Arguments are pulled from the variable argument list specified by Marker based on
+ the contents of the format string.
+ The number of ASCII characters in the produced output buffer is returned not including
+ the Null-terminator.
+ If BufferSize is 0, then no output buffer is produced and 0 is returned.
+
+ If BufferSize > 0 and StartOfBuffer is NULL, then ASSERT().
+ If BufferSize > 0 and FormatString is NULL, then ASSERT().
+ If PcdMaximumAsciiStringLength is not zero, and FormatString contains more than
+ PcdMaximumAsciiStringLength ASCII characters not including the Null-terminator, then
+ ASSERT().
+ If PcdMaximumAsciiStringLength is not zero, and produced Null-terminated ASCII string
+ contains more than PcdMaximumAsciiStringLength ASCII characters not including the
+ Null-terminator, then ASSERT().
+
+ @param StartOfBuffer A pointer to the output buffer for the produced Null-terminated
+ ASCII string.
+ @param BufferSize The size, in bytes, of the output buffer specified by StartOfBuffer.
+ @param FormatString Null-terminated Unicode format string.
+ @param Marker VA_LIST marker for the variable argument list.
+
+ @return The number of ASCII characters in the produced output buffer not including the
+ Null-terminator.
+
+**/
+UINTN
+EFIAPI
+AsciiVSPrint (
+ OUT CHAR8 *StartOfBuffer,
+ IN UINTN BufferSize,
+ IN CONST CHAR8 *FormatString,
+ IN VA_LIST Marker
+ )
+{
+ UINT64 BaseListMarker[256 / sizeof (UINT64)];
+
+ DxePrintLibPrint2ProtocolVaListToBaseList (
+ TRUE,
+ FormatString,
+ Marker,
+ (BASE_LIST)BaseListMarker,
+ sizeof (BaseListMarker) - 8
+ );
+
+ return AsciiBSPrint (StartOfBuffer, BufferSize, FormatString, (BASE_LIST)BaseListMarker);
+}
+
+/**
+ Produces a Null-terminated ASCII string in an output buffer based on a Null-terminated
+ ASCII format string and a BASE_LIST argument list.
+
+ Produces a Null-terminated ASCII string in the output buffer specified by StartOfBuffer
+ and BufferSize.
+ The ASCII string is produced by parsing the format string specified by FormatString.
+ Arguments are pulled from the variable argument list specified by Marker based on
+ the contents of the format string.
+ The number of ASCII characters in the produced output buffer is returned not including
+ the Null-terminator.
+ If BufferSize is 0, then no output buffer is produced and 0 is returned.
+
+ If BufferSize > 0 and StartOfBuffer is NULL, then ASSERT().
+ If BufferSize > 0 and FormatString is NULL, then ASSERT().
+ If PcdMaximumAsciiStringLength is not zero, and FormatString contains more than
+ PcdMaximumAsciiStringLength ASCII characters not including the Null-terminator, then
+ ASSERT().
+ If PcdMaximumAsciiStringLength is not zero, and produced Null-terminated ASCII string
+ contains more than PcdMaximumAsciiStringLength ASCII characters not including the
+ Null-terminator, then ASSERT().
+
+ @param StartOfBuffer A pointer to the output buffer for the produced Null-terminated
+ ASCII string.
+ @param BufferSize The size, in bytes, of the output buffer specified by StartOfBuffer.
+ @param FormatString Null-terminated Unicode format string.
+ @param Marker BASE_LIST marker for the variable argument list.
+
+ @return The number of ASCII characters in the produced output buffer not including the
+ Null-terminator.
+
+**/
+UINTN
+EFIAPI
+AsciiBSPrint (
+ OUT CHAR8 *StartOfBuffer,
+ IN UINTN BufferSize,
+ IN CONST CHAR8 *FormatString,
+ IN BASE_LIST Marker
+ )
+{
+ return mPrint2Protocol->AsciiBSPrint (StartOfBuffer, BufferSize, FormatString, Marker);
+}
+
+/**
+ Produces a Null-terminated ASCII string in an output buffer based on a Null-terminated
+ ASCII format string and variable argument list.
+
+ Produces a Null-terminated ASCII string in the output buffer specified by StartOfBuffer
+ and BufferSize.
+ The ASCII string is produced by parsing the format string specified by FormatString.
+ Arguments are pulled from the variable argument list based on the contents of the
+ format string.
+ The number of ASCII characters in the produced output buffer is returned not including
+ the Null-terminator.
+ If BufferSize is 0, then no output buffer is produced and 0 is returned.
+
+ If BufferSize > 0 and StartOfBuffer is NULL, then ASSERT().
+ If BufferSize > 0 and FormatString is NULL, then ASSERT().
+ If PcdMaximumAsciiStringLength is not zero, and FormatString contains more than
+ PcdMaximumAsciiStringLength ASCII characters not including the Null-terminator, then
+ ASSERT().
+ If PcdMaximumAsciiStringLength is not zero, and produced Null-terminated ASCII string
+ contains more than PcdMaximumAsciiStringLength ASCII characters not including the
+ Null-terminator, then ASSERT().
+
+ @param StartOfBuffer A pointer to the output buffer for the produced Null-terminated
+ ASCII string.
+ @param BufferSize The size, in bytes, of the output buffer specified by StartOfBuffer.
+ @param FormatString Null-terminated Unicode format string.
+ @param ... Variable argument list whose contents are accessed based on the
+ format string specified by FormatString.
+
+ @return The number of ASCII characters in the produced output buffer not including the
+ Null-terminator.
+
+**/
+UINTN
+EFIAPI
+AsciiSPrint (
+ OUT CHAR8 *StartOfBuffer,
+ IN UINTN BufferSize,
+ IN CONST CHAR8 *FormatString,
+ ...
+ )
+{
+ VA_LIST Marker;
+ UINTN NumberOfPrinted;
+
+ VA_START (Marker, FormatString);
+ NumberOfPrinted = AsciiVSPrint (StartOfBuffer, BufferSize, FormatString, Marker);
+ VA_END (Marker);
+ return NumberOfPrinted;
+}
+
+/**
+ Produces a Null-terminated ASCII string in an output buffer based on a Null-terminated
+ ASCII format string and a VA_LIST argument list.
+
+ Produces a Null-terminated ASCII string in the output buffer specified by StartOfBuffer
+ and BufferSize.
+ The ASCII string is produced by parsing the format string specified by FormatString.
+ Arguments are pulled from the variable argument list specified by Marker based on
+ the contents of the format string.
+ The number of ASCII characters in the produced output buffer is returned not including
+ the Null-terminator.
+ If BufferSize is 0, then no output buffer is produced and 0 is returned.
+
+ If BufferSize > 0 and StartOfBuffer is NULL, then ASSERT().
+ If BufferSize > 0 and FormatString is NULL, then ASSERT().
+ If BufferSize > 0 and FormatString is not aligned on a 16-bit boundary, then ASSERT().
+ If PcdMaximumUnicodeStringLength is not zero, and FormatString contains more than
+ PcdMaximumUnicodeStringLength Unicode characters not including the Null-terminator, then
+ ASSERT().
+ If PcdMaximumAsciiStringLength is not zero, and produced Null-terminated ASCII string
+ contains more than PcdMaximumAsciiStringLength ASCII characters not including the
+ Null-terminator, then ASSERT().
+
+ @param StartOfBuffer A pointer to the output buffer for the produced Null-terminated
+ ASCII string.
+ @param BufferSize The size, in bytes, of the output buffer specified by StartOfBuffer.
+ @param FormatString Null-terminated Unicode format string.
+ @param Marker VA_LIST marker for the variable argument list.
+
+ @return The number of ASCII characters in the produced output buffer not including the
+ Null-terminator.
+
+**/
+UINTN
+EFIAPI
+AsciiVSPrintUnicodeFormat (
+ OUT CHAR8 *StartOfBuffer,
+ IN UINTN BufferSize,
+ IN CONST CHAR16 *FormatString,
+ IN VA_LIST Marker
+ )
+{
+ UINT64 BaseListMarker[256 / sizeof (UINT64)];
+
+ DxePrintLibPrint2ProtocolVaListToBaseList (
+ FALSE,
+ (CHAR8 *)FormatString,
+ Marker,
+ (BASE_LIST)BaseListMarker,
+ sizeof (BaseListMarker) - 8
+ );
+
+ return AsciiBSPrintUnicodeFormat (StartOfBuffer, BufferSize, FormatString, (BASE_LIST)BaseListMarker);
+}
+
+/**
+ Produces a Null-terminated ASCII string in an output buffer based on a Null-terminated
+ ASCII format string and a BASE_LIST argument list.
+
+ Produces a Null-terminated ASCII string in the output buffer specified by StartOfBuffer
+ and BufferSize.
+ The ASCII string is produced by parsing the format string specified by FormatString.
+ Arguments are pulled from the variable argument list specified by Marker based on
+ the contents of the format string.
+ The number of ASCII characters in the produced output buffer is returned not including
+ the Null-terminator.
+ If BufferSize is 0, then no output buffer is produced and 0 is returned.
+
+ If BufferSize > 0 and StartOfBuffer is NULL, then ASSERT().
+ If BufferSize > 0 and FormatString is NULL, then ASSERT().
+ If BufferSize > 0 and FormatString is not aligned on a 16-bit boundary, then ASSERT().
+ If PcdMaximumUnicodeStringLength is not zero, and FormatString contains more than
+ PcdMaximumUnicodeStringLength Unicode characters not including the Null-terminator, then
+ ASSERT().
+ If PcdMaximumAsciiStringLength is not zero, and produced Null-terminated ASCII string
+ contains more than PcdMaximumAsciiStringLength ASCII characters not including the
+ Null-terminator, then ASSERT().
+
+ @param StartOfBuffer A pointer to the output buffer for the produced Null-terminated
+ ASCII string.
+ @param BufferSize The size, in bytes, of the output buffer specified by StartOfBuffer.
+ @param FormatString Null-terminated Unicode format string.
+ @param Marker BASE_LIST marker for the variable argument list.
+
+ @return The number of ASCII characters in the produced output buffer not including the
+ Null-terminator.
+
+**/
+UINTN
+EFIAPI
+AsciiBSPrintUnicodeFormat (
+ OUT CHAR8 *StartOfBuffer,
+ IN UINTN BufferSize,
+ IN CONST CHAR16 *FormatString,
+ IN BASE_LIST Marker
+ )
+{
+ return mPrint2Protocol->AsciiBSPrintUnicodeFormat (StartOfBuffer, BufferSize, FormatString, Marker);
+}
+
+/**
+ Produces a Null-terminated ASCII string in an output buffer based on a Null-terminated
+ ASCII format string and variable argument list.
+
+ Produces a Null-terminated ASCII string in the output buffer specified by StartOfBuffer
+ and BufferSize.
+ The ASCII string is produced by parsing the format string specified by FormatString.
+ Arguments are pulled from the variable argument list based on the contents of the
+ format string.
+ The number of ASCII characters in the produced output buffer is returned not including
+ the Null-terminator.
+ If BufferSize is 0, then no output buffer is produced and 0 is returned.
+
+ If BufferSize > 0 and StartOfBuffer is NULL, then ASSERT().
+ If BufferSize > 0 and FormatString is NULL, then ASSERT().
+ If BufferSize > 0 and FormatString is not aligned on a 16-bit boundary, then ASSERT().
+ If PcdMaximumUnicodeStringLength is not zero, and FormatString contains more than
+ PcdMaximumUnicodeStringLength Unicode characters not including the Null-terminator, then
+ ASSERT().
+ If PcdMaximumAsciiStringLength is not zero, and produced Null-terminated ASCII string
+ contains more than PcdMaximumAsciiStringLength ASCII characters not including the
+ Null-terminator, then ASSERT().
+
+ @param StartOfBuffer A pointer to the output buffer for the produced Null-terminated
+ ASCII string.
+ @param BufferSize The size, in bytes, of the output buffer specified by StartOfBuffer.
+ @param FormatString Null-terminated Unicode format string.
+ @param ... Variable argument list whose contents are accessed based on the
+ format string specified by FormatString.
+
+ @return The number of ASCII characters in the produced output buffer not including the
+ Null-terminator.
+
+**/
+UINTN
+EFIAPI
+AsciiSPrintUnicodeFormat (
+ OUT CHAR8 *StartOfBuffer,
+ IN UINTN BufferSize,
+ IN CONST CHAR16 *FormatString,
+ ...
+ )
+{
+ VA_LIST Marker;
+ UINTN NumberOfPrinted;
+
+ VA_START (Marker, FormatString);
+ NumberOfPrinted = AsciiVSPrintUnicodeFormat (StartOfBuffer, BufferSize, FormatString, Marker);
+ VA_END (Marker);
+ return NumberOfPrinted;
+}
+
+
+/**
+ Converts a decimal value to a Null-terminated ASCII string.
+
+ Converts the decimal number specified by Value to a Null-terminated ASCII string
+ specified by Buffer containing at most Width characters. No padding of spaces
+ is ever performed.
+ If Width is 0 then a width of MAXIMUM_VALUE_CHARACTERS is assumed.
+ The number of ASCII characters in Buffer is returned not including the Null-terminator.
+ If the conversion contains more than Width characters, then only the first Width
+ characters are returned, and the total number of characters required to perform
+ the conversion is returned.
+ Additional conversion parameters are specified in Flags.
+ The Flags bit LEFT_JUSTIFY is always ignored.
+ All conversions are left justified in Buffer.
+ If Width is 0, PREFIX_ZERO is ignored in Flags.
+ If COMMA_TYPE is set in Flags, then PREFIX_ZERO is ignored in Flags, and commas
+ are inserted every 3rd digit starting from the right.
+ If RADIX_HEX is set in Flags, then the output buffer will be
+ formatted in hexadecimal format.
+ If Value is < 0 and RADIX_HEX is not set in Flags, then the fist character in Buffer is a '-'.
+ If PREFIX_ZERO is set in Flags and PREFIX_ZERO is not being ignored,
+ then Buffer is padded with '0' characters so the combination of the optional '-'
+ sign character, '0' characters, digit characters for Value, and the Null-terminator
+ add up to Width characters.
+
+ If Buffer is NULL, then ASSERT().
+ If unsupported bits are set in Flags, then ASSERT().
+ If both COMMA_TYPE and RADIX_HEX are set in Flags, then ASSERT().
+ If Width >= MAXIMUM_VALUE_CHARACTERS, then ASSERT()
+
+ @param Buffer Pointer to the output buffer for the produced Null-terminated
+ ASCII string.
+ @param Flags The bitmask of flags that specify left justification, zero pad, and commas.
+ @param Value The 64-bit signed value to convert to a string.
+ @param Width The maximum number of ASCII characters to place in Buffer, not including
+ the Null-terminator.
+
+ @return The number of ASCII characters in Buffer not including the Null-terminator.
+
+**/
+UINTN
+EFIAPI
+AsciiValueToString (
+ OUT CHAR8 *Buffer,
+ IN UINTN Flags,
+ IN INT64 Value,
+ IN UINTN Width
+ )
+{
+ return mPrint2Protocol->AsciiValueToString (Buffer, Flags, Value, Width);
+}
+
+#define PREFIX_SIGN BIT1
+#define PREFIX_BLANK BIT2
+#define LONG_TYPE BIT4
+#define OUTPUT_UNICODE BIT6
+#define FORMAT_UNICODE BIT8
+#define PAD_TO_WIDTH BIT9
+#define ARGUMENT_UNICODE BIT10
+#define PRECISION BIT11
+#define ARGUMENT_REVERSED BIT12
+#define COUNT_ONLY_NO_PRINT BIT13
+#define UNSIGNED_TYPE BIT14
+
+//
+// Record date and time information
+//
+typedef struct {
+ UINT16 Year;
+ UINT8 Month;
+ UINT8 Day;
+ UINT8 Hour;
+ UINT8 Minute;
+ UINT8 Second;
+ UINT8 Pad1;
+ UINT32 Nanosecond;
+ INT16 TimeZone;
+ UINT8 Daylight;
+ UINT8 Pad2;
+} TIME;
+
+GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 mHexStr[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
+
+/**
+ Internal function that convert a number to a string in Buffer.
+
+ Print worker function that converts a decimal or hexadecimal number to an ASCII string in Buffer.
+
+ @param Buffer Location to place the ASCII string of Value.
+ @param Value The value to convert to a Decimal or Hexadecimal string in Buffer.
+ @param Radix Radix of the value
+
+ @return A pointer to the end of buffer filled with ASCII string.
+
+**/
+CHAR8 *
+InternalPrintLibValueToString (
+ IN OUT CHAR8 *Buffer,
+ IN INT64 Value,
+ IN UINTN Radix
+ )
+{
+ UINT32 Remainder;
+
+ //
+ // Loop to convert one digit at a time in reverse order
+ //
+ *Buffer = 0;
+ do {
+ Value = (INT64)DivU64x32Remainder ((UINT64)Value, (UINT32)Radix, &Remainder);
+ *(++Buffer) = mHexStr[Remainder];
+ } while (Value != 0);
+
+ //
+ // Return pointer of the end of filled buffer.
+ //
+ return Buffer;
+}
+
+/**
+ Worker function that produces a Null-terminated string in an output buffer
+ based on a Null-terminated format string and a VA_LIST argument list.
+
+ VSPrint function to process format and place the results in Buffer. Since a
+ VA_LIST is used this routine allows the nesting of Vararg routines. Thus
+ this is the main print working routine.
+
+ If COUNT_ONLY_NO_PRINT is set in Flags, Buffer will not be modified at all.
+
+ @param[out] Buffer The character buffer to print the results of the
+ parsing of Format into.
+ @param[in] BufferSize The maximum number of characters to put into
+ buffer.
+ @param[in] Flags Initial flags value.
+ Can only have FORMAT_UNICODE, OUTPUT_UNICODE,
+ and COUNT_ONLY_NO_PRINT set.
+ @param[in] Format A Null-terminated format string.
+ @param[in] VaListMarker VA_LIST style variable argument list consumed by
+ processing Format.
+ @param[in] BaseListMarker BASE_LIST style variable argument list consumed
+ by processing Format.
+
+ @return The number of characters printed not including the Null-terminator.
+ If COUNT_ONLY_NO_PRINT was set returns the same, but without any
+ modification to Buffer.
+
+**/
+UINTN
+InternalPrintLibSPrintMarker (
+ OUT CHAR8 *Buffer,
+ IN UINTN BufferSize,
+ IN UINTN Flags,
+ IN CONST CHAR8 *Format,
+ IN VA_LIST VaListMarker, OPTIONAL
+ IN BASE_LIST BaseListMarker OPTIONAL
+ );
+
+/**
+ Worker function that produces a Null-terminated string in an output buffer
+ based on a Null-terminated format string and variable argument list.
+
+ VSPrint function to process format and place the results in Buffer. Since a
+ VA_LIST is used this routine allows the nesting of Vararg routines. Thus
+ this is the main print working routine
+
+ @param StartOfBuffer The character buffer to print the results of the parsing
+ of Format into.
+ @param BufferSize The maximum number of characters to put into buffer.
+ Zero means no limit.
+ @param Flags Initial flags value.
+ Can only have FORMAT_UNICODE and OUTPUT_UNICODE set
+ @param FormatString A Null-terminated format string.
+ @param ... The variable argument list.
+
+ @return The number of characters printed.
+
+**/
+UINTN
+EFIAPI
+InternalPrintLibSPrint (
+ OUT CHAR8 *StartOfBuffer,
+ IN UINTN BufferSize,
+ IN UINTN Flags,
+ IN CONST CHAR8 *FormatString,
+ ...
+ )
+{
+ VA_LIST Marker;
+ UINTN NumberOfPrinted;
+
+ VA_START (Marker, FormatString);
+ NumberOfPrinted = InternalPrintLibSPrintMarker (StartOfBuffer, BufferSize, Flags, FormatString, Marker, NULL);
+ VA_END (Marker);
+ return NumberOfPrinted;
+}
+
+#define WARNING_STATUS_NUMBER 5
+#define ERROR_STATUS_NUMBER 33
+
+GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 * CONST mStatusString[] = {
+ "Success", // RETURN_SUCCESS = 0
+ "Warning Unknown Glyph", // RETURN_WARN_UNKNOWN_GLYPH = 1
+ "Warning Delete Failure", // RETURN_WARN_DELETE_FAILURE = 2
+ "Warning Write Failure", // RETURN_WARN_WRITE_FAILURE = 3
+ "Warning Buffer Too Small", // RETURN_WARN_BUFFER_TOO_SMALL = 4
+ "Warning Stale Data", // RETURN_WARN_STALE_DATA = 5
+ "Load Error", // RETURN_LOAD_ERROR = 1 | MAX_BIT
+ "Invalid Parameter", // RETURN_INVALID_PARAMETER = 2 | MAX_BIT
+ "Unsupported", // RETURN_UNSUPPORTED = 3 | MAX_BIT
+ "Bad Buffer Size", // RETURN_BAD_BUFFER_SIZE = 4 | MAX_BIT
+ "Buffer Too Small", // RETURN_BUFFER_TOO_SMALL, = 5 | MAX_BIT
+ "Not Ready", // RETURN_NOT_READY = 6 | MAX_BIT
+ "Device Error", // RETURN_DEVICE_ERROR = 7 | MAX_BIT
+ "Write Protected", // RETURN_WRITE_PROTECTED = 8 | MAX_BIT
+ "Out of Resources", // RETURN_OUT_OF_RESOURCES = 9 | MAX_BIT
+ "Volume Corrupt", // RETURN_VOLUME_CORRUPTED = 10 | MAX_BIT
+ "Volume Full", // RETURN_VOLUME_FULL = 11 | MAX_BIT
+ "No Media", // RETURN_NO_MEDIA = 12 | MAX_BIT
+ "Media changed", // RETURN_MEDIA_CHANGED = 13 | MAX_BIT
+ "Not Found", // RETURN_NOT_FOUND = 14 | MAX_BIT
+ "Access Denied", // RETURN_ACCESS_DENIED = 15 | MAX_BIT
+ "No Response", // RETURN_NO_RESPONSE = 16 | MAX_BIT
+ "No mapping", // RETURN_NO_MAPPING = 17 | MAX_BIT
+ "Time out", // RETURN_TIMEOUT = 18 | MAX_BIT
+ "Not started", // RETURN_NOT_STARTED = 19 | MAX_BIT
+ "Already started", // RETURN_ALREADY_STARTED = 20 | MAX_BIT
+ "Aborted", // RETURN_ABORTED = 21 | MAX_BIT
+ "ICMP Error", // RETURN_ICMP_ERROR = 22 | MAX_BIT
+ "TFTP Error", // RETURN_TFTP_ERROR = 23 | MAX_BIT
+ "Protocol Error", // RETURN_PROTOCOL_ERROR = 24 | MAX_BIT
+ "Incompatible Version", // RETURN_INCOMPATIBLE_VERSION = 25 | MAX_BIT
+ "Security Violation", // RETURN_SECURITY_VIOLATION = 26 | MAX_BIT
+ "CRC Error", // RETURN_CRC_ERROR = 27 | MAX_BIT
+ "End of Media", // RETURN_END_OF_MEDIA = 28 | MAX_BIT
+ "Reserved (29)", // RESERVED = 29 | MAX_BIT
+ "Reserved (30)", // RESERVED = 30 | MAX_BIT
+ "End of File", // RETURN_END_OF_FILE = 31 | MAX_BIT
+ "Invalid Language", // RETURN_INVALID_LANGUAGE = 32 | MAX_BIT
+ "Compromised Data" // RETURN_COMPROMISED_DATA = 33 | MAX_BIT
+};
+
+/**
+ Internal function that places the character into the Buffer.
+
+ Internal function that places ASCII or Unicode character into the Buffer.
+
+ @param Buffer The buffer to place the Unicode or ASCII string.
+ @param EndBuffer The end of the input Buffer. No characters will be
+ placed after that.
+ @param Length The count of character to be placed into Buffer.
+ (Negative value indicates no buffer fill.)
+ @param Character The character to be placed into Buffer.
+ @param Increment The character increment in Buffer.
+
+ @return Buffer.
+
+**/
+CHAR8 *
+InternalPrintLibFillBuffer (
+ OUT CHAR8 *Buffer,
+ IN CHAR8 *EndBuffer,
+ IN INTN Length,
+ IN UINTN Character,
+ IN INTN Increment
+ )
+{
+ INTN Index;
+
+ for (Index = 0; Index < Length && Buffer < EndBuffer; Index++) {
+ *Buffer = (CHAR8) Character;
+ if (Increment != 1) {
+ *(Buffer + 1) = (CHAR8)(Character >> 8);
+ }
+ Buffer += Increment;
+ }
+
+ return Buffer;
+}
+
+/**
+ Worker function that produces a Null-terminated string in an output buffer
+ based on a Null-terminated format string and a VA_LIST argument list.
+
+ VSPrint function to process format and place the results in Buffer. Since a
+ VA_LIST is used this routine allows the nesting of Vararg routines. Thus
+ this is the main print working routine.
+
+ If COUNT_ONLY_NO_PRINT is set in Flags, Buffer will not be modified at all.
+
+ @param[out] Buffer The character buffer to print the results of the
+ parsing of Format into.
+ @param[in] BufferSize The maximum number of characters to put into
+ buffer.
+ @param[in] Flags Initial flags value.
+ Can only have FORMAT_UNICODE, OUTPUT_UNICODE,
+ and COUNT_ONLY_NO_PRINT set.
+ @param[in] Format A Null-terminated format string.
+ @param[in] VaListMarker VA_LIST style variable argument list consumed by
+ processing Format.
+ @param[in] BaseListMarker BASE_LIST style variable argument list consumed
+ by processing Format.
+
+ @return The number of characters printed not including the Null-terminator.
+ If COUNT_ONLY_NO_PRINT was set returns the same, but without any
+ modification to Buffer.
+
+**/
+UINTN
+InternalPrintLibSPrintMarker (
+ OUT CHAR8 *Buffer,
+ IN UINTN BufferSize,
+ IN UINTN Flags,
+ IN CONST CHAR8 *Format,
+ IN VA_LIST VaListMarker, OPTIONAL
+ IN BASE_LIST BaseListMarker OPTIONAL
+ )
+{
+ CHAR8 *OriginalBuffer;
+ CHAR8 *EndBuffer;
+ CHAR8 ValueBuffer[MAXIMUM_VALUE_CHARACTERS];
+ UINT32 BytesPerOutputCharacter;
+ UINTN BytesPerFormatCharacter;
+ UINTN FormatMask;
+ UINTN FormatCharacter;
+ UINTN Width;
+ UINTN Precision;
+ INT64 Value;
+ CONST CHAR8 *ArgumentString;
+ UINTN Character;
+ GUID *TmpGuid;
+ TIME *TmpTime;
+ UINTN Count;
+ UINTN ArgumentMask;
+ INTN BytesPerArgumentCharacter;
+ UINTN ArgumentCharacter;
+ BOOLEAN Done;
+ UINTN Index;
+ CHAR8 Prefix;
+ BOOLEAN ZeroPad;
+ BOOLEAN Comma;
+ UINTN Digits;
+ UINTN Radix;
+ RETURN_STATUS Status;
+ UINT32 GuidData1;
+ UINT16 GuidData2;
+ UINT16 GuidData3;
+ UINTN LengthToReturn;
+
+ //
+ // If you change this code be sure to match the 2 versions of this function.
+ // Nearly identical logic is found in the BasePrintLib and
+ // DxePrintLibPrint2Protocol (both PrintLib instances).
+ //
+
+ if ((Flags & COUNT_ONLY_NO_PRINT) != 0) {
+ if (BufferSize == 0) {
+ Buffer = NULL;
+ }
+ } else {
+ //
+ // We can run without a Buffer for counting only.
+ //
+ if (BufferSize == 0) {
+ return 0;
+ }
+ ASSERT (Buffer != NULL);
+ }
+
+ if ((Flags & OUTPUT_UNICODE) != 0) {
+ BytesPerOutputCharacter = 2;
+ } else {
+ BytesPerOutputCharacter = 1;
+ }
+
+ LengthToReturn = 0;
+ EndBuffer = NULL;
+ OriginalBuffer = NULL;
+
+ //
+ // Reserve space for the Null terminator.
+ //
+ if (Buffer != NULL) {
+ BufferSize--;
+ OriginalBuffer = Buffer;
+
+ //
+ // Set the tag for the end of the input Buffer.
+ //
+ EndBuffer = Buffer + BufferSize * BytesPerOutputCharacter;
+ }
+
+ if ((Flags & FORMAT_UNICODE) != 0) {
+ //
+ // Make sure format string cannot contain more than PcdMaximumUnicodeStringLength
+ // Unicode characters if PcdMaximumUnicodeStringLength is not zero.
+ //
+ ASSERT (StrSize ((CHAR16 *) Format) != 0);
+ BytesPerFormatCharacter = 2;
+ FormatMask = 0xffff;
+ } else {
+ //
+ // Make sure format string cannot contain more than PcdMaximumAsciiStringLength
+ // Ascii characters if PcdMaximumAsciiStringLength is not zero.
+ //
+ ASSERT (AsciiStrSize (Format) != 0);
+ BytesPerFormatCharacter = 1;
+ FormatMask = 0xff;
+ }
+
+ //
+ // Get the first character from the format string
+ //
+ FormatCharacter = ((*Format & 0xff) | (*(Format + 1) << 8)) & FormatMask;
+
+ //
+ // Loop until the end of the format string is reached or the output buffer is full
+ //
+ while (FormatCharacter != 0) {
+ if ((Buffer != NULL) && (Buffer >= EndBuffer)) {
+ break;
+ }
+ //
+ // Clear all the flag bits except those that may have been passed in
+ //
+ Flags &= (UINTN) (OUTPUT_UNICODE | FORMAT_UNICODE | COUNT_ONLY_NO_PRINT);
+
+ //
+ // Set the default width to zero, and the default precision to 1
+ //
+ Width = 0;
+ Precision = 1;
+ Prefix = 0;
+ Comma = FALSE;
+ ZeroPad = FALSE;
+ Count = 0;
+ Digits = 0;
+
+ switch (FormatCharacter) {
+ case '%':
+ //
+ // Parse Flags and Width
+ //
+ for (Done = FALSE; !Done; ) {
+ Format += BytesPerFormatCharacter;
+ FormatCharacter = ((*Format & 0xff) | (*(Format + 1) << 8)) & FormatMask;
+ switch (FormatCharacter) {
+ case '.':
+ Flags |= PRECISION;
+ break;
+ case '-':
+ Flags |= LEFT_JUSTIFY;
+ break;
+ case '+':
+ Flags |= PREFIX_SIGN;
+ break;
+ case ' ':
+ Flags |= PREFIX_BLANK;
+ break;
+ case ',':
+ Flags |= COMMA_TYPE;
+ break;
+ case 'L':
+ case 'l':
+ Flags |= LONG_TYPE;
+ break;
+ case '*':
+ if ((Flags & PRECISION) == 0) {
+ Flags |= PAD_TO_WIDTH;
+ if (BaseListMarker == NULL) {
+ Width = VA_ARG (VaListMarker, UINTN);
+ } else {
+ Width = BASE_ARG (BaseListMarker, UINTN);
+ }
+ } else {
+ if (BaseListMarker == NULL) {
+ Precision = VA_ARG (VaListMarker, UINTN);
+ } else {
+ Precision = BASE_ARG (BaseListMarker, UINTN);
+ }
+ }
+ break;
+ case '0':
+ if ((Flags & PRECISION) == 0) {
+ Flags |= PREFIX_ZERO;
+ }
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ for (Count = 0; ((FormatCharacter >= '0') && (FormatCharacter <= '9')); ){
+ Count = (Count * 10) + FormatCharacter - '0';
+ Format += BytesPerFormatCharacter;
+ FormatCharacter = ((*Format & 0xff) | (*(Format + 1) << 8)) & FormatMask;
+ }
+ Format -= BytesPerFormatCharacter;
+ if ((Flags & PRECISION) == 0) {
+ Flags |= PAD_TO_WIDTH;
+ Width = Count;
+ } else {
+ Precision = Count;
+ }
+ break;
+
+ case '\0':
+ //
+ // Make no output if Format string terminates unexpectedly when
+ // looking up for flag, width, precision and type.
+ //
+ Format -= BytesPerFormatCharacter;
+ Precision = 0;
+ //
+ // break skipped on purpose.
+ //
+ default:
+ Done = TRUE;
+ break;
+ }
+ }
+
+ //
+ // Handle each argument type
+ //
+ switch (FormatCharacter) {
+ case 'p':
+ //
+ // Flag space, +, 0, L & l are invalid for type p.
+ //
+ Flags &= ~((UINTN) (PREFIX_BLANK | PREFIX_SIGN | PREFIX_ZERO | LONG_TYPE));
+ if (sizeof (VOID *) > 4) {
+ Flags |= LONG_TYPE;
+ }
+ //
+ // break skipped on purpose
+ //
+ case 'X':
+ Flags |= PREFIX_ZERO;
+ //
+ // break skipped on purpose
+ //
+ case 'x':
+ Flags |= RADIX_HEX;
+ //
+ // break skipped on purpose
+ //
+ case 'u':
+ if ((Flags & RADIX_HEX) == 0) {
+ Flags &= ~((UINTN) (PREFIX_SIGN));
+ Flags |= UNSIGNED_TYPE;
+ }
+ //
+ // break skipped on purpose
+ //
+ case 'd':
+ if ((Flags & LONG_TYPE) == 0) {
+ //
+ // 'd', 'u', 'x', and 'X' that are not preceded by 'l' or 'L' are assumed to be type "int".
+ // This assumption is made so the format string definition is compatible with the ANSI C
+ // Specification for formatted strings. It is recommended that the Base Types be used
+ // everywhere, but in this one case, compliance with ANSI C is more important, and
+ // provides an implementation that is compatible with that largest possible set of CPU
+ // architectures. This is why the type "int" is used in this one case.
+ //
+ if (BaseListMarker == NULL) {
+ Value = VA_ARG (VaListMarker, int);
+ } else {
+ Value = BASE_ARG (BaseListMarker, int);
+ }
+ } else {
+ if (BaseListMarker == NULL) {
+ Value = VA_ARG (VaListMarker, INT64);
+ } else {
+ Value = BASE_ARG (BaseListMarker, INT64);
+ }
+ }
+ if ((Flags & PREFIX_BLANK) != 0) {
+ Prefix = ' ';
+ }
+ if ((Flags & PREFIX_SIGN) != 0) {
+ Prefix = '+';
+ }
+ if ((Flags & COMMA_TYPE) != 0) {
+ Comma = TRUE;
+ }
+ if ((Flags & RADIX_HEX) == 0) {
+ Radix = 10;
+ if (Comma) {
+ Flags &= ~((UINTN) PREFIX_ZERO);
+ Precision = 1;
+ }
+ if (Value < 0 && (Flags & UNSIGNED_TYPE) == 0) {
+ Flags |= PREFIX_SIGN;
+ Prefix = '-';
+ Value = -Value;
+ } else if ((Flags & UNSIGNED_TYPE) != 0 && (Flags & LONG_TYPE) == 0) {
+ //
+ // 'd', 'u', 'x', and 'X' that are not preceded by 'l' or 'L' are assumed to be type "int".
+ // This assumption is made so the format string definition is compatible with the ANSI C
+ // Specification for formatted strings. It is recommended that the Base Types be used
+ // everywhere, but in this one case, compliance with ANSI C is more important, and
+ // provides an implementation that is compatible with that largest possible set of CPU
+ // architectures. This is why the type "unsigned int" is used in this one case.
+ //
+ Value = (unsigned int)Value;
+ }
+ } else {
+ Radix = 16;
+ Comma = FALSE;
+ if ((Flags & LONG_TYPE) == 0 && Value < 0) {
+ //
+ // 'd', 'u', 'x', and 'X' that are not preceded by 'l' or 'L' are assumed to be type "int".
+ // This assumption is made so the format string definition is compatible with the ANSI C
+ // Specification for formatted strings. It is recommended that the Base Types be used
+ // everywhere, but in this one case, compliance with ANSI C is more important, and
+ // provides an implementation that is compatible with that largest possible set of CPU
+ // architectures. This is why the type "unsigned int" is used in this one case.
+ //
+ Value = (unsigned int)Value;
+ }
+ }
+ //
+ // Convert Value to a reversed string
+ //
+ Count = InternalPrintLibValueToString (ValueBuffer, Value, Radix) - ValueBuffer;
+ if (Value == 0 && Precision == 0) {
+ Count = 0;
+ }
+ ArgumentString = (CHAR8 *)ValueBuffer + Count;
+
+ Digits = Count % 3;
+ if (Digits != 0) {
+ Digits = 3 - Digits;
+ }
+ if (Comma && Count != 0) {
+ Count += ((Count - 1) / 3);
+ }
+ if (Prefix != 0) {
+ Count++;
+ Precision++;
+ }
+ Flags |= ARGUMENT_REVERSED;
+ ZeroPad = TRUE;
+ if ((Flags & PREFIX_ZERO) != 0) {
+ if ((Flags & LEFT_JUSTIFY) == 0) {
+ if ((Flags & PAD_TO_WIDTH) != 0) {
+ if ((Flags & PRECISION) == 0) {
+ Precision = Width;
+ }
+ }
+ }
+ }
+ break;
+
+ case 's':
+ case 'S':
+ Flags |= ARGUMENT_UNICODE;
+ //
+ // break skipped on purpose
+ //
+ case 'a':
+ if (BaseListMarker == NULL) {
+ ArgumentString = VA_ARG (VaListMarker, CHAR8 *);
+ } else {
+ ArgumentString = BASE_ARG (BaseListMarker, CHAR8 *);
+ }
+ if (ArgumentString == NULL) {
+ Flags &= (~(UINTN)ARGUMENT_UNICODE);
+ ArgumentString = "<null string>";
+ }
+ //
+ // Set the default precision for string to be zero if not specified.
+ //
+ if ((Flags & PRECISION) == 0) {
+ Precision = 0;
+ }
+ break;
+
+ case 'c':
+ if (BaseListMarker == NULL) {
+ Character = VA_ARG (VaListMarker, UINTN) & 0xffff;
+ } else {
+ Character = BASE_ARG (BaseListMarker, UINTN) & 0xffff;
+ }
+ ArgumentString = (CHAR8 *)&Character;
+ Flags |= ARGUMENT_UNICODE;
+ break;
+
+ case 'g':
+ if (BaseListMarker == NULL) {
+ TmpGuid = VA_ARG (VaListMarker, GUID *);
+ } else {
+ TmpGuid = BASE_ARG (BaseListMarker, GUID *);
+ }
+ if (TmpGuid == NULL) {
+ ArgumentString = "<null guid>";
+ } else {
+ GuidData1 = ReadUnaligned32 (&(TmpGuid->Data1));
+ GuidData2 = ReadUnaligned16 (&(TmpGuid->Data2));
+ GuidData3 = ReadUnaligned16 (&(TmpGuid->Data3));
+ InternalPrintLibSPrint (
+ ValueBuffer,
+ MAXIMUM_VALUE_CHARACTERS,
+ 0,
+ "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+ GuidData1,
+ GuidData2,
+ GuidData3,
+ TmpGuid->Data4[0],
+ TmpGuid->Data4[1],
+ TmpGuid->Data4[2],
+ TmpGuid->Data4[3],
+ TmpGuid->Data4[4],
+ TmpGuid->Data4[5],
+ TmpGuid->Data4[6],
+ TmpGuid->Data4[7]
+ );
+ ArgumentString = ValueBuffer;
+ }
+ break;
+
+ case 't':
+ if (BaseListMarker == NULL) {
+ TmpTime = VA_ARG (VaListMarker, TIME *);
+ } else {
+ TmpTime = BASE_ARG (BaseListMarker, TIME *);
+ }
+ if (TmpTime == NULL) {
+ ArgumentString = "<null time>";
+ } else {
+ InternalPrintLibSPrint (
+ ValueBuffer,
+ MAXIMUM_VALUE_CHARACTERS,
+ 0,
+ "%02d/%02d/%04d %02d:%02d",
+ TmpTime->Month,
+ TmpTime->Day,
+ TmpTime->Year,
+ TmpTime->Hour,
+ TmpTime->Minute
+ );
+ ArgumentString = ValueBuffer;
+ }
+ break;
+
+ case 'r':
+ if (BaseListMarker == NULL) {
+ Status = VA_ARG (VaListMarker, RETURN_STATUS);
+ } else {
+ Status = BASE_ARG (BaseListMarker, RETURN_STATUS);
+ }
+ ArgumentString = ValueBuffer;
+ if (RETURN_ERROR (Status)) {
+ //
+ // Clear error bit
+ //
+ Index = Status & ~MAX_BIT;
+ if (Index > 0 && Index <= ERROR_STATUS_NUMBER) {
+ ArgumentString = mStatusString [Index + WARNING_STATUS_NUMBER];
+ }
+ } else {
+ Index = Status;
+ if (Index <= WARNING_STATUS_NUMBER) {
+ ArgumentString = mStatusString [Index];
+ }
+ }
+ if (ArgumentString == ValueBuffer) {
+ InternalPrintLibSPrint ((CHAR8 *) ValueBuffer, MAXIMUM_VALUE_CHARACTERS, 0, "%08X", Status);
+ }
+ break;
+
+ case '\r':
+ Format += BytesPerFormatCharacter;
+ FormatCharacter = ((*Format & 0xff) | (*(Format + 1) << 8)) & FormatMask;
+ if (FormatCharacter == '\n') {
+ //
+ // Translate '\r\n' to '\r\n'
+ //
+ ArgumentString = "\r\n";
+ } else {
+ //
+ // Translate '\r' to '\r'
+ //
+ ArgumentString = "\r";
+ Format -= BytesPerFormatCharacter;
+ }
+ break;
+
+ case '\n':
+ //
+ // Translate '\n' to '\r\n' and '\n\r' to '\r\n'
+ //
+ ArgumentString = "\r\n";
+ Format += BytesPerFormatCharacter;
+ FormatCharacter = ((*Format & 0xff) | (*(Format + 1) << 8)) & FormatMask;
+ if (FormatCharacter != '\r') {
+ Format -= BytesPerFormatCharacter;
+ }
+ break;
+
+ case '%':
+ default:
+ //
+ // if the type is '%' or unknown, then print it to the screen
+ //
+ ArgumentString = (CHAR8 *)&FormatCharacter;
+ Flags |= ARGUMENT_UNICODE;
+ break;
+ }
+ break;
+
+ case '\r':
+ Format += BytesPerFormatCharacter;
+ FormatCharacter = ((*Format & 0xff) | (*(Format + 1) << 8)) & FormatMask;
+ if (FormatCharacter == '\n') {
+ //
+ // Translate '\r\n' to '\r\n'
+ //
+ ArgumentString = "\r\n";
+ } else {
+ //
+ // Translate '\r' to '\r'
+ //
+ ArgumentString = "\r";
+ Format -= BytesPerFormatCharacter;
+ }
+ break;
+
+ case '\n':
+ //
+ // Translate '\n' to '\r\n' and '\n\r' to '\r\n'
+ //
+ ArgumentString = "\r\n";
+ Format += BytesPerFormatCharacter;
+ FormatCharacter = ((*Format & 0xff) | (*(Format + 1) << 8)) & FormatMask;
+ if (FormatCharacter != '\r') {
+ Format -= BytesPerFormatCharacter;
+ }
+ break;
+
+ default:
+ ArgumentString = (CHAR8 *)&FormatCharacter;
+ Flags |= ARGUMENT_UNICODE;
+ break;
+ }
+
+ //
+ // Retrieve the ArgumentString attriubutes
+ //
+ if ((Flags & ARGUMENT_UNICODE) != 0) {
+ ArgumentMask = 0xffff;
+ BytesPerArgumentCharacter = 2;
+ } else {
+ ArgumentMask = 0xff;
+ BytesPerArgumentCharacter = 1;
+ }
+ if ((Flags & ARGUMENT_REVERSED) != 0) {
+ BytesPerArgumentCharacter = -BytesPerArgumentCharacter;
+ } else {
+ //
+ // Compute the number of characters in ArgumentString and store it in Count
+ // ArgumentString is either null-terminated, or it contains Precision characters
+ //
+ for (Count = 0; Count < Precision || ((Flags & PRECISION) == 0); Count++) {
+ ArgumentCharacter = ((ArgumentString[Count * BytesPerArgumentCharacter] & 0xff) | ((ArgumentString[Count * BytesPerArgumentCharacter + 1]) << 8)) & ArgumentMask;
+ if (ArgumentCharacter == 0) {
+ break;
+ }
+ }
+ }
+
+ if (Precision < Count) {
+ Precision = Count;
+ }
+
+ //
+ // Pad before the string
+ //
+ if ((Flags & (PAD_TO_WIDTH | LEFT_JUSTIFY)) == (PAD_TO_WIDTH)) {
+ LengthToReturn += ((Width - Precision) * BytesPerOutputCharacter);
+ if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {
+ Buffer = InternalPrintLibFillBuffer (Buffer, EndBuffer, Width - Precision, ' ', BytesPerOutputCharacter);
+ }
+ }
+
+ if (ZeroPad) {
+ if (Prefix != 0) {
+ LengthToReturn += (1 * BytesPerOutputCharacter);
+ if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {
+ Buffer = InternalPrintLibFillBuffer (Buffer, EndBuffer, 1, Prefix, BytesPerOutputCharacter);
+ }
+ }
+ LengthToReturn += ((Precision - Count) * BytesPerOutputCharacter);
+ if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {
+ Buffer = InternalPrintLibFillBuffer (Buffer, EndBuffer, Precision - Count, '0', BytesPerOutputCharacter);
+ }
+ } else {
+ LengthToReturn += ((Precision - Count) * BytesPerOutputCharacter);
+ if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {
+ Buffer = InternalPrintLibFillBuffer (Buffer, EndBuffer, Precision - Count, ' ', BytesPerOutputCharacter);
+ }
+ if (Prefix != 0) {
+ LengthToReturn += (1 * BytesPerOutputCharacter);
+ if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {
+ Buffer = InternalPrintLibFillBuffer (Buffer, EndBuffer, 1, Prefix, BytesPerOutputCharacter);
+ }
+ }
+ }
+
+ //
+ // Output the Prefix character if it is present
+ //
+ Index = 0;
+ if (Prefix != 0) {
+ Index++;
+ }
+
+ //
+ // Copy the string into the output buffer performing the required type conversions
+ //
+ while (Index < Count) {
+ ArgumentCharacter = ((*ArgumentString & 0xff) | (*(ArgumentString + 1) << 8)) & ArgumentMask;
+
+ LengthToReturn += (1 * BytesPerOutputCharacter);
+ if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {
+ Buffer = InternalPrintLibFillBuffer (Buffer, EndBuffer, 1, ArgumentCharacter, BytesPerOutputCharacter);
+ }
+ ArgumentString += BytesPerArgumentCharacter;
+ Index++;
+ if (Comma) {
+ Digits++;
+ if (Digits == 3) {
+ Digits = 0;
+ Index++;
+ if (Index < Count) {
+ LengthToReturn += (1 * BytesPerOutputCharacter);
+ if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {
+ Buffer = InternalPrintLibFillBuffer (Buffer, EndBuffer, 1, ',', BytesPerOutputCharacter);
+ }
+ }
+ }
+ }
+ }
+
+ //
+ // Pad after the string
+ //
+ if ((Flags & (PAD_TO_WIDTH | LEFT_JUSTIFY)) == (PAD_TO_WIDTH | LEFT_JUSTIFY)) {
+ LengthToReturn += ((Width - Precision) * BytesPerOutputCharacter);
+ if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {
+ Buffer = InternalPrintLibFillBuffer (Buffer, EndBuffer, Width - Precision, ' ', BytesPerOutputCharacter);
+ }
+ }
+
+ //
+ // Get the next character from the format string
+ //
+ Format += BytesPerFormatCharacter;
+
+ //
+ // Get the next character from the format string
+ //
+ FormatCharacter = ((*Format & 0xff) | (*(Format + 1) << 8)) & FormatMask;
+ }
+
+ if ((Flags & COUNT_ONLY_NO_PRINT) != 0) {
+ return (LengthToReturn / BytesPerOutputCharacter);
+ }
+
+ ASSERT (Buffer != NULL);
+ //
+ // Null terminate the Unicode or ASCII string
+ //
+ InternalPrintLibFillBuffer (Buffer, EndBuffer + BytesPerOutputCharacter, 1, 0, BytesPerOutputCharacter);
+ //
+ // Make sure output buffer cannot contain more than PcdMaximumUnicodeStringLength
+ // Unicode characters if PcdMaximumUnicodeStringLength is not zero.
+ //
+ ASSERT ((((Flags & OUTPUT_UNICODE) == 0)) || (StrSize ((CHAR16 *) OriginalBuffer) != 0));
+ //
+ // Make sure output buffer cannot contain more than PcdMaximumAsciiStringLength
+ // ASCII characters if PcdMaximumAsciiStringLength is not zero.
+ //
+ ASSERT ((((Flags & OUTPUT_UNICODE) != 0)) || (AsciiStrSize (OriginalBuffer) != 0));
+
+ return ((Buffer - OriginalBuffer) / BytesPerOutputCharacter);
+}
+
+/**
+ Returns the number of characters that would be produced by if the formatted
+ output were produced not including the Null-terminator.
+
+ If FormatString is NULL, then ASSERT().
+ If FormatString is not aligned on a 16-bit boundary, then ASSERT().
+
+ @param[in] FormatString A Null-terminated Unicode format string.
+ @param[in] Marker VA_LIST marker for the variable argument list.
+
+ @return The number of characters that would be produced, not including the
+ Null-terminator.
+**/
+UINTN
+EFIAPI
+SPrintLength (
+ IN CONST CHAR16 *FormatString,
+ IN VA_LIST Marker
+ )
+{
+ ASSERT(FormatString != NULL);
+ return InternalPrintLibSPrintMarker (NULL, 0, FORMAT_UNICODE | OUTPUT_UNICODE | COUNT_ONLY_NO_PRINT, (CHAR8 *)FormatString, Marker, NULL);
+}
+
+/**
+ Returns the number of characters that would be produced by if the formatted
+ output were produced not including the Null-terminator.
+
+ If FormatString is NULL, then ASSERT().
+
+ @param[in] FormatString A Null-terminated ASCII format string.
+ @param[in] Marker VA_LIST marker for the variable argument list.
+
+ @return The number of characters that would be produced, not including the
+ Null-terminator.
+**/
+UINTN
+EFIAPI
+SPrintLengthAsciiFormat (
+ IN CONST CHAR8 *FormatString,
+ IN VA_LIST Marker
+ )
+{
+ ASSERT(FormatString != NULL);
+ return InternalPrintLibSPrintMarker (NULL, 0, OUTPUT_UNICODE | COUNT_ONLY_NO_PRINT, (CHAR8 *)FormatString, Marker, NULL);
+}
diff --git a/Core/MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.inf b/Core/MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.inf
new file mode 100644
index 0000000000..962cf8b05b
--- /dev/null
+++ b/Core/MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.inf
@@ -0,0 +1,57 @@
+## @file
+# DXE report status code library.
+#
+# Retrieve status code and report status code in DXE phase.
+#
+# Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxeReportStatusCodeLib
+ MODULE_UNI_FILE = DxeReportStatusCodeLib.uni
+ FILE_GUID = EBF144C8-70F5-4e09-ADE2-F41F5C59AFDA
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = ReportStatusCodeLib|DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SAL_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER SMM_CORE
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ ReportStatusCodeLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ DebugLib
+ UefiBootServicesTableLib
+ BaseMemoryLib
+ PcdLib
+ DevicePathLib
+
+[Guids]
+ gEfiStatusCodeSpecificDataGuid ## SOMETIMES_CONSUMES ## UNDEFINED
+ gEfiStatusCodeDataTypeDebugGuid ## SOMETIMES_CONSUMES ## UNDEFINED
+
+[Protocols]
+ gEfiStatusCodeRuntimeProtocolGuid ## CONSUMES
+
+[Pcd]
+ gEfiMdePkgTokenSpaceGuid.PcdReportStatusCodePropertyMask ## CONSUMES
+
diff --git a/Core/MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.uni b/Core/MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.uni
new file mode 100644
index 0000000000..61da4060f5
--- /dev/null
+++ b/Core/MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.uni
Binary files differ
diff --git a/Core/MdeModulePkg/Library/DxeReportStatusCodeLib/ReportStatusCodeLib.c b/Core/MdeModulePkg/Library/DxeReportStatusCodeLib/ReportStatusCodeLib.c
new file mode 100644
index 0000000000..ce843cc47f
--- /dev/null
+++ b/Core/MdeModulePkg/Library/DxeReportStatusCodeLib/ReportStatusCodeLib.c
@@ -0,0 +1,631 @@
+/** @file
+ Report Status Code Library for DXE Phase.
+
+ Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PcdLib.h>
+#include <Library/DevicePathLib.h>
+
+#include <Protocol/StatusCode.h>
+
+#include <Guid/StatusCodeDataTypeId.h>
+#include <Guid/StatusCodeDataTypeDebug.h>
+
+//
+// Define the maximum extended data size that is supported when a status code is
+// reported at TPL_HIGH_LEVEL.
+//
+#define MAX_EXTENDED_DATA_SIZE 0x200
+
+EFI_STATUS_CODE_PROTOCOL *mReportStatusCodeLibStatusCodeProtocol = NULL;
+
+/**
+ Locate the report status code service.
+
+ Retrieve ReportStatusCode() API of Report Status Code Protocol.
+
+**/
+VOID
+InternalGetReportStatusCode (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+
+ if (mReportStatusCodeLibStatusCodeProtocol != NULL) {
+ return;
+ }
+
+ //
+ // Check gBS just in case ReportStatusCode is called before gBS is initialized.
+ //
+ if (gBS != NULL && gBS->LocateProtocol != NULL) {
+ Status = gBS->LocateProtocol (&gEfiStatusCodeRuntimeProtocolGuid, NULL, (VOID**) &mReportStatusCodeLibStatusCodeProtocol);
+ if (EFI_ERROR (Status)) {
+ mReportStatusCodeLibStatusCodeProtocol = NULL;
+ }
+ }
+}
+
+/**
+ Internal worker function that reports a status code through the Report Status Code Protocol.
+
+ If status code service is not cached, then this function checks if Report Status Code
+ Protocol is available in system. If Report Status Code Protocol is not available, then
+ EFI_UNSUPPORTED is returned. If Report Status Code Protocol is present, then it is
+ cached in mReportStatusCodeLibStatusCodeProtocol. Finally this function reports status
+ code through the Report Status Code Protocol.
+
+ @param Type Status code type.
+ @param Value Status code value.
+ @param Instance Status code instance number.
+ @param CallerId Pointer to a GUID that identifies the caller of this
+ function. This is an optional parameter that may be
+ NULL.
+ @param Data Pointer to the extended data buffer. This is an
+ optional parameter that may be NULL.
+
+ @retval EFI_SUCCESS The status code was reported.
+ @retval EFI_UNSUPPORTED Report Status Code Protocol is not available.
+ @retval EFI_UNSUPPORTED Status code type is not supported.
+
+**/
+EFI_STATUS
+InternalReportStatusCode (
+ IN EFI_STATUS_CODE_TYPE Type,
+ IN EFI_STATUS_CODE_VALUE Value,
+ IN UINT32 Instance,
+ IN CONST EFI_GUID *CallerId OPTIONAL,
+ IN EFI_STATUS_CODE_DATA *Data OPTIONAL
+ )
+{
+ if ((ReportProgressCodeEnabled() && ((Type) & EFI_STATUS_CODE_TYPE_MASK) == EFI_PROGRESS_CODE) ||
+ (ReportErrorCodeEnabled() && ((Type) & EFI_STATUS_CODE_TYPE_MASK) == EFI_ERROR_CODE) ||
+ (ReportDebugCodeEnabled() && ((Type) & EFI_STATUS_CODE_TYPE_MASK) == EFI_DEBUG_CODE)) {
+ //
+ // If mReportStatusCodeLibStatusCodeProtocol is NULL, then check if Report Status Code Protocol is available in system.
+ //
+ InternalGetReportStatusCode ();
+ if (mReportStatusCodeLibStatusCodeProtocol == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // A Report Status Code Protocol is present in system, so pass in all the parameters to the service.
+ //
+ return mReportStatusCodeLibStatusCodeProtocol->ReportStatusCode (Type, Value, Instance, (EFI_GUID *)CallerId, Data);
+ }
+
+ return EFI_UNSUPPORTED;
+}
+
+
+/**
+ Converts a status code to an 8-bit POST code value.
+
+ Converts the status code specified by CodeType and Value to an 8-bit POST code
+ and returns the 8-bit POST code in PostCode. If CodeType is an
+ EFI_PROGRESS_CODE or CodeType is an EFI_ERROR_CODE, then bits 0..4 of PostCode
+ are set to bits 16..20 of Value, and bits 5..7 of PostCode are set to bits
+ 24..26 of Value., and TRUE is returned. Otherwise, FALSE is returned.
+
+ If PostCode is NULL, then ASSERT().
+
+ @param CodeType The type of status code being converted.
+ @param Value The status code value being converted.
+ @param PostCode A pointer to the 8-bit POST code value to return.
+
+ @retval TRUE The status code specified by CodeType and Value was converted
+ to an 8-bit POST code and returned in PostCode.
+ @retval FALSE The status code specified by CodeType and Value could not be
+ converted to an 8-bit POST code value.
+
+**/
+BOOLEAN
+EFIAPI
+CodeTypeToPostCode (
+ IN EFI_STATUS_CODE_TYPE CodeType,
+ IN EFI_STATUS_CODE_VALUE Value,
+ OUT UINT8 *PostCode
+ )
+{
+ //
+ // If PostCode is NULL, then ASSERT()
+ //
+ ASSERT (PostCode != NULL);
+
+ //
+ // Convert Value to an 8 bit post code
+ //
+ if (((CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_PROGRESS_CODE) ||
+ ((CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_ERROR_CODE) ) {
+ *PostCode = (UINT8) ((((Value & EFI_STATUS_CODE_CLASS_MASK) >> 24) << 5) |
+ (((Value & EFI_STATUS_CODE_SUBCLASS_MASK) >> 16) & 0x1f));
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+/**
+ Extracts ASSERT() information from a status code structure.
+
+ Converts the status code specified by CodeType, Value, and Data to the ASSERT()
+ arguments specified by Filename, Description, and LineNumber. If CodeType is
+ an EFI_ERROR_CODE, and CodeType has a severity of EFI_ERROR_UNRECOVERED, and
+ Value has an operation mask of EFI_SW_EC_ILLEGAL_SOFTWARE_STATE, extract
+ Filename, Description, and LineNumber from the optional data area of the
+ status code buffer specified by Data. The optional data area of Data contains
+ a Null-terminated ASCII string for the FileName, followed by a Null-terminated
+ ASCII string for the Description, followed by a 32-bit LineNumber. If the
+ ASSERT() information could be extracted from Data, then return TRUE.
+ Otherwise, FALSE is returned.
+
+ If Data is NULL, then ASSERT().
+ If Filename is NULL, then ASSERT().
+ If Description is NULL, then ASSERT().
+ If LineNumber is NULL, then ASSERT().
+
+ @param CodeType The type of status code being converted.
+ @param Value The status code value being converted.
+ @param Data Pointer to status code data buffer.
+ @param Filename Pointer to the source file name that generated the ASSERT().
+ @param Description Pointer to the description of the ASSERT().
+ @param LineNumber Pointer to source line number that generated the ASSERT().
+
+ @retval TRUE The status code specified by CodeType, Value, and Data was
+ converted ASSERT() arguments specified by Filename, Description,
+ and LineNumber.
+ @retval FALSE The status code specified by CodeType, Value, and Data could
+ not be converted to ASSERT() arguments.
+
+**/
+BOOLEAN
+EFIAPI
+ReportStatusCodeExtractAssertInfo (
+ IN EFI_STATUS_CODE_TYPE CodeType,
+ IN EFI_STATUS_CODE_VALUE Value,
+ IN CONST EFI_STATUS_CODE_DATA *Data,
+ OUT CHAR8 **Filename,
+ OUT CHAR8 **Description,
+ OUT UINT32 *LineNumber
+ )
+{
+ EFI_DEBUG_ASSERT_DATA *AssertData;
+
+ ASSERT (Data != NULL);
+ ASSERT (Filename != NULL);
+ ASSERT (Description != NULL);
+ ASSERT (LineNumber != NULL);
+
+ if (((CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_ERROR_CODE) &&
+ ((CodeType & EFI_STATUS_CODE_SEVERITY_MASK) == EFI_ERROR_UNRECOVERED) &&
+ ((Value & EFI_STATUS_CODE_OPERATION_MASK) == EFI_SW_EC_ILLEGAL_SOFTWARE_STATE)) {
+ AssertData = (EFI_DEBUG_ASSERT_DATA *)(Data + 1);
+ *Filename = (CHAR8 *)(AssertData + 1);
+ *Description = *Filename + AsciiStrLen (*Filename) + 1;
+ *LineNumber = AssertData->LineNumber;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+/**
+ Extracts DEBUG() information from a status code structure.
+
+ Converts the status code specified by Data to the DEBUG() arguments specified
+ by ErrorLevel, Marker, and Format. If type GUID in Data is
+ EFI_STATUS_CODE_DATA_TYPE_DEBUG_GUID, then extract ErrorLevel, Marker, and
+ Format from the optional data area of the status code buffer specified by Data.
+ The optional data area of Data contains a 32-bit ErrorLevel followed by Marker
+ which is 12 UINTN parameters, followed by a Null-terminated ASCII string for
+ the Format. If the DEBUG() information could be extracted from Data, then
+ return TRUE. Otherwise, FALSE is returned.
+
+ If Data is NULL, then ASSERT().
+ If ErrorLevel is NULL, then ASSERT().
+ If Marker is NULL, then ASSERT().
+ If Format is NULL, then ASSERT().
+
+ @param Data Pointer to status code data buffer.
+ @param ErrorLevel Pointer to error level mask for a debug message.
+ @param Marker Pointer to the variable argument list associated with Format.
+ @param Format Pointer to a Null-terminated ASCII format string of a
+ debug message.
+
+ @retval TRUE The status code specified by Data was converted DEBUG() arguments
+ specified by ErrorLevel, Marker, and Format.
+ @retval FALSE The status code specified by Data could not be converted to
+ DEBUG() arguments.
+
+**/
+BOOLEAN
+EFIAPI
+ReportStatusCodeExtractDebugInfo (
+ IN CONST EFI_STATUS_CODE_DATA *Data,
+ OUT UINT32 *ErrorLevel,
+ OUT BASE_LIST *Marker,
+ OUT CHAR8 **Format
+ )
+{
+ EFI_DEBUG_INFO *DebugInfo;
+
+ ASSERT (Data != NULL);
+ ASSERT (ErrorLevel != NULL);
+ ASSERT (Marker != NULL);
+ ASSERT (Format != NULL);
+
+ //
+ // If the GUID type is not EFI_STATUS_CODE_DATA_TYPE_DEBUG_GUID then return FALSE
+ //
+ if (!CompareGuid (&Data->Type, &gEfiStatusCodeDataTypeDebugGuid)) {
+ return FALSE;
+ }
+
+ //
+ // Retrieve the debug information from the status code record
+ //
+ DebugInfo = (EFI_DEBUG_INFO *)(Data + 1);
+
+ *ErrorLevel = DebugInfo->ErrorLevel;
+
+ //
+ // The first 12 * sizeof (UINT64) bytes following EFI_DEBUG_INFO are for variable arguments
+ // of format in DEBUG string. Its address is returned in Marker and has to be 64-bit aligned.
+ // It must be noticed that EFI_DEBUG_INFO follows EFI_STATUS_CODE_DATA, whose size is
+ // 20 bytes. The size of EFI_DEBUG_INFO is 4 bytes, so we can ensure that Marker
+ // returned is 64-bit aligned.
+ // 64-bit aligned is a must, otherwise retrieving 64-bit parameter from BASE_LIST will
+ // cause unalignment exception.
+ //
+ *Marker = (BASE_LIST) (DebugInfo + 1);
+ *Format = (CHAR8 *)(((UINT64 *)*Marker) + 12);
+
+ return TRUE;
+}
+
+
+/**
+ Reports a status code.
+
+ Reports the status code specified by the parameters Type and Value. Status
+ code also require an instance, caller ID, and extended data. This function
+ passed in a zero instance, NULL extended data, and a caller ID of
+ gEfiCallerIdGuid, which is the GUID for the module.
+
+ ReportStatusCode()must actively prevent recusrsion. If ReportStatusCode()
+ is called while processing another any other Report Status Code Library function,
+ then ReportStatusCode() must return immediately.
+
+ @param Type Status code type.
+ @param Value Status code value.
+
+ @retval EFI_SUCCESS The status code was reported.
+ @retval EFI_DEVICE_ERROR There status code could not be reported due to a
+ device error.
+ @retval EFI_UNSUPPORTED Report status code is not supported
+
+**/
+EFI_STATUS
+EFIAPI
+ReportStatusCode (
+ IN EFI_STATUS_CODE_TYPE Type,
+ IN EFI_STATUS_CODE_VALUE Value
+ )
+{
+ return InternalReportStatusCode (Type, Value, 0, &gEfiCallerIdGuid, NULL);
+}
+
+
+/**
+ Reports a status code with a Device Path Protocol as the extended data.
+
+ Allocates and fills in the extended data section of a status code with the
+ Device Path Protocol specified by DevicePath. This function is responsible
+ for allocating a buffer large enough for the standard header and the device
+ path. The standard header is filled in with a GUID of
+ gEfiStatusCodeSpecificDataGuid. The status code is reported with a zero
+ instance and a caller ID of gEfiCallerIdGuid.
+
+ ReportStatusCodeWithDevicePath()must actively prevent recursion. If
+ ReportStatusCodeWithDevicePath() is called while processing another any other
+ Report Status Code Library function, then ReportStatusCodeWithDevicePath()
+ must return EFI_DEVICE_ERROR immediately.
+
+ If DevicePath is NULL, then ASSERT().
+
+ @param Type Status code type.
+ @param Value Status code value.
+ @param DevicePath Pointer to the Device Path Protocol to be reported.
+
+ @retval EFI_SUCCESS The status code was reported with the extended
+ data specified by DevicePath.
+ @retval EFI_OUT_OF_RESOURCES There were not enough resources to allocate the
+ extended data section.
+ @retval EFI_UNSUPPORTED Report status code is not supported
+
+**/
+EFI_STATUS
+EFIAPI
+ReportStatusCodeWithDevicePath (
+ IN EFI_STATUS_CODE_TYPE Type,
+ IN EFI_STATUS_CODE_VALUE Value,
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ ASSERT (DevicePath != NULL);
+ return ReportStatusCodeWithExtendedData (
+ Type,
+ Value,
+ (VOID *)DevicePath,
+ GetDevicePathSize (DevicePath)
+ );
+}
+
+
+/**
+ Reports a status code with an extended data buffer.
+
+ Allocates and fills in the extended data section of a status code with the
+ extended data specified by ExtendedData and ExtendedDataSize. ExtendedData
+ is assumed to be one of the data structures specified in Related Definitions.
+ These data structure do not have the standard header, so this function is
+ responsible for allocating a buffer large enough for the standard header and
+ the extended data passed into this function. The standard header is filled
+ in with a GUID of gEfiStatusCodeSpecificDataGuid. The status code is reported
+ with a zero instance and a caller ID of gEfiCallerIdGuid.
+
+ ReportStatusCodeWithExtendedData()must actively prevent recursion. If
+ ReportStatusCodeWithExtendedData() is called while processing another any other
+ Report Status Code Library function, then ReportStatusCodeWithExtendedData()
+ must return EFI_DEVICE_ERROR immediately.
+
+ If ExtendedData is NULL, then ASSERT().
+ If ExtendedDataSize is 0, then ASSERT().
+
+ @param Type Status code type.
+ @param Value Status code value.
+ @param ExtendedData Pointer to the extended data buffer to be reported.
+ @param ExtendedDataSize The size, in bytes, of the extended data buffer to
+ be reported.
+
+ @retval EFI_SUCCESS The status code was reported with the extended
+ data specified by ExtendedData and ExtendedDataSize.
+ @retval EFI_OUT_OF_RESOURCES There were not enough resources to allocate the
+ extended data section.
+ @retval EFI_UNSUPPORTED Report status code is not supported
+
+**/
+EFI_STATUS
+EFIAPI
+ReportStatusCodeWithExtendedData (
+ IN EFI_STATUS_CODE_TYPE Type,
+ IN EFI_STATUS_CODE_VALUE Value,
+ IN CONST VOID *ExtendedData,
+ IN UINTN ExtendedDataSize
+ )
+{
+ ASSERT (ExtendedData != NULL);
+ ASSERT (ExtendedDataSize != 0);
+ return ReportStatusCodeEx (
+ Type,
+ Value,
+ 0,
+ NULL,
+ NULL,
+ ExtendedData,
+ ExtendedDataSize
+ );
+}
+
+
+/**
+ Reports a status code with full parameters.
+
+ The function reports a status code. If ExtendedData is NULL and ExtendedDataSize
+ is 0, then an extended data buffer is not reported. If ExtendedData is not
+ NULL and ExtendedDataSize is not 0, then an extended data buffer is allocated.
+ ExtendedData is assumed not have the standard status code header, so this function
+ is responsible for allocating a buffer large enough for the standard header and
+ the extended data passed into this function. The standard header is filled in
+ with a GUID specified by ExtendedDataGuid. If ExtendedDataGuid is NULL, then a
+ GUID of gEfiStatusCodeSpecificDataGuid is used. The status code is reported with
+ an instance specified by Instance and a caller ID specified by CallerId. If
+ CallerId is NULL, then a caller ID of gEfiCallerIdGuid is used.
+
+ ReportStatusCodeEx()must actively prevent recursion. If
+ ReportStatusCodeEx() is called while processing another any
+ other Report Status Code Library function, then
+ ReportStatusCodeEx() must return EFI_DEVICE_ERROR immediately.
+
+ If ExtendedData is NULL and ExtendedDataSize is not zero, then ASSERT().
+ If ExtendedData is not NULL and ExtendedDataSize is zero, then ASSERT().
+
+ @param Type Status code type.
+ @param Value Status code value.
+ @param Instance Status code instance number.
+ @param CallerId Pointer to a GUID that identifies the caller of this
+ function. If this parameter is NULL, then a caller
+ ID of gEfiCallerIdGuid is used.
+ @param ExtendedDataGuid Pointer to the GUID for the extended data buffer.
+ If this parameter is NULL, then a the status code
+ standard header is filled in with
+ gEfiStatusCodeSpecificDataGuid.
+ @param ExtendedData Pointer to the extended data buffer. This is an
+ optional parameter that may be NULL.
+ @param ExtendedDataSize The size, in bytes, of the extended data buffer.
+
+ @retval EFI_SUCCESS The status code was reported.
+ @retval EFI_OUT_OF_RESOURCES There were not enough resources to allocate
+ the extended data section if it was specified.
+ @retval EFI_UNSUPPORTED Report status code is not supported
+
+**/
+EFI_STATUS
+EFIAPI
+ReportStatusCodeEx (
+ IN EFI_STATUS_CODE_TYPE Type,
+ IN EFI_STATUS_CODE_VALUE Value,
+ IN UINT32 Instance,
+ IN CONST EFI_GUID *CallerId OPTIONAL,
+ IN CONST EFI_GUID *ExtendedDataGuid OPTIONAL,
+ IN CONST VOID *ExtendedData OPTIONAL,
+ IN UINTN ExtendedDataSize
+ )
+{
+ EFI_STATUS Status;
+ EFI_STATUS_CODE_DATA *StatusCodeData;
+ EFI_TPL Tpl;
+ UINT64 Buffer[(MAX_EXTENDED_DATA_SIZE / sizeof (UINT64)) + 1];
+
+ ASSERT (!((ExtendedData == NULL) && (ExtendedDataSize != 0)));
+ ASSERT (!((ExtendedData != NULL) && (ExtendedDataSize == 0)));
+
+ if (gBS == NULL || gBS->AllocatePool == NULL || gBS->FreePool == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Retrieve the current TPL
+ //
+ Tpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
+ gBS->RestoreTPL (Tpl);
+
+ StatusCodeData = NULL;
+ if (Tpl <= TPL_NOTIFY) {
+ //
+ // Allocate space for the Status Code Header and its buffer
+ //
+ gBS->AllocatePool (EfiBootServicesData, sizeof (EFI_STATUS_CODE_DATA) + ExtendedDataSize, (VOID **)&StatusCodeData);
+ }
+
+ if (StatusCodeData == NULL) {
+ //
+ // If a buffer could not be allocated, then see if the local variable Buffer can be used
+ //
+ if (ExtendedDataSize > (MAX_EXTENDED_DATA_SIZE - sizeof (EFI_STATUS_CODE_DATA))) {
+ //
+ // The local variable Buffer not large enough to hold the extended data associated
+ // with the status code being reported.
+ //
+ DEBUG ((EFI_D_ERROR, "Status code extended data is too large to be reported!\n"));
+ return EFI_OUT_OF_RESOURCES;
+ }
+ StatusCodeData = (EFI_STATUS_CODE_DATA *)Buffer;
+ }
+
+ //
+ // Fill in the extended data header
+ //
+ StatusCodeData->HeaderSize = (UINT16) sizeof (EFI_STATUS_CODE_DATA);
+ StatusCodeData->Size = (UINT16) ExtendedDataSize;
+ if (ExtendedDataGuid == NULL) {
+ ExtendedDataGuid = &gEfiStatusCodeSpecificDataGuid;
+ }
+ CopyGuid (&StatusCodeData->Type, ExtendedDataGuid);
+
+ //
+ // Fill in the extended data buffer
+ //
+ if (ExtendedData != NULL) {
+ CopyMem (StatusCodeData + 1, ExtendedData, ExtendedDataSize);
+ }
+
+ //
+ // Report the status code
+ //
+ if (CallerId == NULL) {
+ CallerId = &gEfiCallerIdGuid;
+ }
+ Status = InternalReportStatusCode (Type, Value, Instance, CallerId, StatusCodeData);
+
+ //
+ // Free the allocated buffer
+ //
+ if (StatusCodeData != (EFI_STATUS_CODE_DATA *)Buffer) {
+ gBS->FreePool (StatusCodeData);
+ }
+
+ return Status;
+}
+
+
+/**
+ Returns TRUE if status codes of type EFI_PROGRESS_CODE are enabled
+
+ This function returns TRUE if the REPORT_STATUS_CODE_PROPERTY_PROGRESS_CODE_ENABLED
+ bit of PcdReportStatusCodeProperyMask is set. Otherwise FALSE is returned.
+
+ @retval TRUE The REPORT_STATUS_CODE_PROPERTY_PROGRESS_CODE_ENABLED bit of
+ PcdReportStatusCodeProperyMask is set.
+ @retval FALSE The REPORT_STATUS_CODE_PROPERTY_PROGRESS_CODE_ENABLED bit of
+ PcdReportStatusCodeProperyMask is clear.
+
+**/
+BOOLEAN
+EFIAPI
+ReportProgressCodeEnabled (
+ VOID
+ )
+{
+ return (BOOLEAN) ((PcdGet8 (PcdReportStatusCodePropertyMask) & REPORT_STATUS_CODE_PROPERTY_PROGRESS_CODE_ENABLED) != 0);
+}
+
+
+/**
+ Returns TRUE if status codes of type EFI_ERROR_CODE are enabled
+
+ This function returns TRUE if the REPORT_STATUS_CODE_PROPERTY_ERROR_CODE_ENABLED
+ bit of PcdReportStatusCodeProperyMask is set. Otherwise FALSE is returned.
+
+ @retval TRUE The REPORT_STATUS_CODE_PROPERTY_ERROR_CODE_ENABLED bit of
+ PcdReportStatusCodeProperyMask is set.
+ @retval FALSE The REPORT_STATUS_CODE_PROPERTY_ERROR_CODE_ENABLED bit of
+ PcdReportStatusCodeProperyMask is clear.
+
+**/
+BOOLEAN
+EFIAPI
+ReportErrorCodeEnabled (
+ VOID
+ )
+{
+ return (BOOLEAN) ((PcdGet8 (PcdReportStatusCodePropertyMask) & REPORT_STATUS_CODE_PROPERTY_ERROR_CODE_ENABLED) != 0);
+}
+
+
+/**
+ Returns TRUE if status codes of type EFI_DEBUG_CODE are enabled
+
+ This function returns TRUE if the REPORT_STATUS_CODE_PROPERTY_DEBUG_CODE_ENABLED
+ bit of PcdReportStatusCodeProperyMask is set. Otherwise FALSE is returned.
+
+ @retval TRUE The REPORT_STATUS_CODE_PROPERTY_DEBUG_CODE_ENABLED bit of
+ PcdReportStatusCodeProperyMask is set.
+ @retval FALSE The REPORT_STATUS_CODE_PROPERTY_DEBUG_CODE_ENABLED bit of
+ PcdReportStatusCodeProperyMask is clear.
+
+**/
+BOOLEAN
+EFIAPI
+ReportDebugCodeEnabled (
+ VOID
+ )
+{
+ return (BOOLEAN) ((PcdGet8 (PcdReportStatusCodePropertyMask) & REPORT_STATUS_CODE_PROPERTY_DEBUG_CODE_ENABLED) != 0);
+}
diff --git a/Core/MdeModulePkg/Library/DxeSecurityManagementLib/DxeSecurityManagementLib.c b/Core/MdeModulePkg/Library/DxeSecurityManagementLib/DxeSecurityManagementLib.c
new file mode 100644
index 0000000000..b96d78664d
--- /dev/null
+++ b/Core/MdeModulePkg/Library/DxeSecurityManagementLib/DxeSecurityManagementLib.c
@@ -0,0 +1,533 @@
+/** @file
+ Provides generic security measurement functions for DXE module.
+
+Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiDxe.h>
+#include <Protocol/LoadFile.h>
+#include <Library/DebugLib.h>
+#include <Library/DxeServicesLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/SecurityManagementLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+#define SECURITY_HANDLER_TABLE_SIZE 0x10
+
+//
+// Secruity Operation on Image and none Image.
+//
+#define EFI_AUTH_IMAGE_OPERATION_MASK (EFI_AUTH_OPERATION_VERIFY_IMAGE \
+ | EFI_AUTH_OPERATION_DEFER_IMAGE_LOAD \
+ | EFI_AUTH_OPERATION_MEASURE_IMAGE)
+#define EFI_AUTH_NONE_IMAGE_OPERATION_MASK (EFI_AUTH_OPERATION_CONNECT_POLICY \
+ | EFI_AUTH_OPERATION_AUTHENTICATION_STATE)
+
+typedef struct {
+ UINT32 SecurityOperation;
+ SECURITY_FILE_AUTHENTICATION_STATE_HANDLER SecurityHandler;
+} SECURITY_INFO;
+
+typedef struct {
+ UINT32 Security2Operation;
+ SECURITY2_FILE_AUTHENTICATION_HANDLER Security2Handler;
+} SECURITY2_INFO;
+
+UINT32 mCurrentAuthOperation = 0;
+UINT32 mNumberOfSecurityHandler = 0;
+UINT32 mMaxNumberOfSecurityHandler = 0;
+SECURITY_INFO *mSecurityTable = NULL;
+
+UINT32 mCurrentAuthOperation2 = 0;
+UINT32 mNumberOfSecurity2Handler = 0;
+UINT32 mMaxNumberOfSecurity2Handler = 0;
+SECURITY2_INFO *mSecurity2Table = NULL;
+
+/**
+ Reallocates more global memory to store the registered Handler list.
+
+ @retval RETURN_SUCCESS Reallocate memory successfully.
+ @retval RETURN_OUT_OF_RESOURCES No enough memory to allocated.
+**/
+RETURN_STATUS
+EFIAPI
+ReallocateSecurityHandlerTable (
+ )
+{
+ //
+ // Reallocate memory for security info structure.
+ //
+ mSecurityTable = ReallocatePool (
+ mMaxNumberOfSecurityHandler * sizeof (SECURITY_INFO),
+ (mMaxNumberOfSecurityHandler + SECURITY_HANDLER_TABLE_SIZE) * sizeof (SECURITY_INFO),
+ mSecurityTable
+ );
+
+ //
+ // No enough resource is allocated.
+ //
+ if (mSecurityTable == NULL) {
+ return RETURN_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Increase max handler number
+ //
+ mMaxNumberOfSecurityHandler = mMaxNumberOfSecurityHandler + SECURITY_HANDLER_TABLE_SIZE;
+ return RETURN_SUCCESS;
+}
+
+/**
+ Check whether an operation is valid according to the requirement of current operation,
+ which must make sure that the measure image operation is the last one.
+
+ @param CurrentAuthOperation Current operation.
+ @param CheckAuthOperation Operation to be checked.
+
+ @retval TRUE Operation is valid for current operation.
+ @retval FALSE Operation is invalid for current operation.
+**/
+BOOLEAN
+CheckAuthenticationOperation (
+ IN UINT32 CurrentAuthOperation,
+ IN UINT32 CheckAuthOperation
+ )
+{
+ //
+ // Make sure new auth operation can be recognized.
+ //
+ ASSERT ((CheckAuthOperation & ~(EFI_AUTH_IMAGE_OPERATION_MASK | EFI_AUTH_OPERATION_AUTHENTICATION_STATE | EFI_AUTH_OPERATION_IMAGE_REQUIRED)) == 0);
+
+ //
+ // When current operation includes measure image operation,
+ // only another measure image operation or none operation will be allowed.
+ //
+ if ((CurrentAuthOperation & EFI_AUTH_OPERATION_MEASURE_IMAGE) == EFI_AUTH_OPERATION_MEASURE_IMAGE) {
+ if (((CheckAuthOperation & EFI_AUTH_OPERATION_MEASURE_IMAGE) == EFI_AUTH_OPERATION_MEASURE_IMAGE) ||
+ ((CheckAuthOperation & EFI_AUTH_IMAGE_OPERATION_MASK) == EFI_AUTH_OPERATION_NONE)) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+ }
+
+ //
+ // When current operation doesn't include measure image operation,
+ // any new operation will be allowed.
+ //
+ return TRUE;
+}
+
+/**
+ Register security measurement handler with its operation type. The different
+ handler with the same operation can all be registered.
+
+ If SecurityHandler is NULL, then ASSERT().
+ If no enough resources available to register new handler, then ASSERT().
+ If AuthenticationOperation is not recongnized, then ASSERT().
+ If the previous register handler can't be executed before the later register handler, then ASSERT().
+
+ @param[in] SecurityHandler Security measurement service handler to be registered.
+ @param[in] AuthenticationOperation Operation type is specified for the registered handler.
+
+ @retval EFI_SUCCESS The handlers were registered successfully.
+**/
+EFI_STATUS
+EFIAPI
+RegisterSecurityHandler (
+ IN SECURITY_FILE_AUTHENTICATION_STATE_HANDLER SecurityHandler,
+ IN UINT32 AuthenticationOperation
+ )
+{
+ EFI_STATUS Status;
+
+ ASSERT (SecurityHandler != NULL);
+
+ //
+ // Make sure AuthenticationOperation is valid in the register order.
+ //
+ ASSERT (CheckAuthenticationOperation (mCurrentAuthOperation, AuthenticationOperation));
+ mCurrentAuthOperation = mCurrentAuthOperation | AuthenticationOperation;
+
+ //
+ // Check whether the handler lists is enough to store new handler.
+ //
+ if (mNumberOfSecurityHandler == mMaxNumberOfSecurityHandler) {
+ //
+ // Allocate more resources for new handler.
+ //
+ Status = ReallocateSecurityHandlerTable();
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ //
+ // Register new handler into the handler list.
+ //
+ mSecurityTable[mNumberOfSecurityHandler].SecurityOperation = AuthenticationOperation;
+ mSecurityTable[mNumberOfSecurityHandler].SecurityHandler = SecurityHandler;
+ mNumberOfSecurityHandler ++;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Execute registered handlers until one returns an error and that error is returned.
+ If none of the handlers return an error, then EFI_SUCCESS is returned.
+
+ Before exectue handler, get the image buffer by file device path if a handler
+ requires the image file. And return the image buffer to each handler when exectue handler.
+
+ The handlers are executed in same order to their registered order.
+
+ @param[in] AuthenticationStatus
+ This is the authentication type returned from the Section
+ Extraction protocol. See the Section Extraction Protocol
+ Specification for details on this type.
+ @param[in] FilePath This is a pointer to the device path of the file that is
+ being dispatched. This will optionally be used for logging.
+
+ @retval EFI_SUCCESS The file specified by File did authenticate when more
+ than one security handler services were registered,
+ or the file did not authenticate when no security
+ handler service was registered. And the platform policy
+ dictates that the DXE Core may use File.
+ @retval EFI_INVALID_PARAMETER File is NULL.
+ @retval EFI_SECURITY_VIOLATION The file specified by File did not authenticate, and
+ the platform policy dictates that File should be placed
+ in the untrusted state. A file may be promoted from
+ the untrusted to the trusted state at a future time
+ with a call to the Trust() DXE Service.
+ @retval EFI_ACCESS_DENIED The file specified by File did not authenticate, and
+ the platform policy dictates that File should not be
+ used for any purpose.
+**/
+EFI_STATUS
+EFIAPI
+ExecuteSecurityHandlers (
+ IN UINT32 AuthenticationStatus,
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *FilePath
+ )
+{
+ UINT32 Index;
+ EFI_STATUS Status;
+ UINT32 HandlerAuthenticationStatus;
+ VOID *FileBuffer;
+ UINTN FileSize;
+ EFI_HANDLE Handle;
+ EFI_DEVICE_PATH_PROTOCOL *Node;
+ EFI_DEVICE_PATH_PROTOCOL *FilePathToVerfiy;
+
+ if (FilePath == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Directly return successfully when no handler is registered.
+ //
+ if (mNumberOfSecurityHandler == 0) {
+ return EFI_SUCCESS;
+ }
+
+ Status = EFI_SUCCESS;
+ FileBuffer = NULL;
+ FileSize = 0;
+ HandlerAuthenticationStatus = AuthenticationStatus;
+ FilePathToVerfiy = (EFI_DEVICE_PATH_PROTOCOL *) FilePath;
+ //
+ // Run security handler in same order to their registered list
+ //
+ for (Index = 0; Index < mNumberOfSecurityHandler; Index ++) {
+ if ((mSecurityTable[Index].SecurityOperation & EFI_AUTH_OPERATION_IMAGE_REQUIRED) == EFI_AUTH_OPERATION_IMAGE_REQUIRED) {
+ //
+ // Try get file buffer when the handler requires image buffer.
+ //
+ if (FileBuffer == NULL) {
+ Node = FilePathToVerfiy;
+ Status = gBS->LocateDevicePath (&gEfiLoadFileProtocolGuid, &Node, &Handle);
+ //
+ // Try to get image by FALSE boot policy for the exact boot file path.
+ //
+ FileBuffer = GetFileBufferByFilePath (FALSE, FilePath, &FileSize, &AuthenticationStatus);
+ if (FileBuffer == NULL) {
+ //
+ // Try to get image by TRUE boot policy for the inexact boot file path.
+ //
+ FileBuffer = GetFileBufferByFilePath (TRUE, FilePath, &FileSize, &AuthenticationStatus);
+ }
+ if ((FileBuffer != NULL) && (!EFI_ERROR (Status))) {
+ //
+ // LoadFile () may cause the device path of the Handle be updated.
+ //
+ FilePathToVerfiy = AppendDevicePath (DevicePathFromHandle (Handle), Node);
+ }
+ }
+ }
+ Status = mSecurityTable[Index].SecurityHandler (
+ HandlerAuthenticationStatus,
+ FilePathToVerfiy,
+ FileBuffer,
+ FileSize
+ );
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ }
+
+ if (FileBuffer != NULL) {
+ FreePool (FileBuffer);
+ }
+ if (FilePathToVerfiy != FilePath) {
+ FreePool (FilePathToVerfiy);
+ }
+
+ return Status;
+}
+
+/**
+ Reallocates more global memory to store the registered Securit2Handler list.
+
+ @retval RETURN_SUCCESS Reallocate memory successfully.
+ @retval RETURN_OUT_OF_RESOURCES No enough memory to allocated.
+**/
+RETURN_STATUS
+EFIAPI
+ReallocateSecurity2HandlerTable (
+ )
+{
+ //
+ // Reallocate memory for security info structure.
+ //
+ mSecurity2Table = ReallocatePool (
+ mMaxNumberOfSecurity2Handler * sizeof (SECURITY2_INFO),
+ (mMaxNumberOfSecurity2Handler + SECURITY_HANDLER_TABLE_SIZE) * sizeof (SECURITY2_INFO),
+ mSecurity2Table
+ );
+
+ //
+ // No enough resource is allocated.
+ //
+ if (mSecurity2Table == NULL) {
+ return RETURN_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Increase max handler number
+ //
+ mMaxNumberOfSecurity2Handler = mMaxNumberOfSecurity2Handler + SECURITY_HANDLER_TABLE_SIZE;
+ return RETURN_SUCCESS;
+}
+
+/**
+ Check whether an operation is valid according to the requirement of current operation,
+ which must make sure that the measure image operation is the last one.
+
+ If AuthenticationOperation is not recongnized, return FALSE.
+ If AuthenticationOperation is EFI_AUTH_OPERATION_NONE, return FALSE.
+ If AuthenticationOperation includes security operation and authentication operation, return FALSE.
+ If the previous register handler can't be executed before the later register handler, return FALSE.
+
+ @param CurrentAuthOperation Current operation.
+ @param CheckAuthOperation Operation to be checked.
+
+ @retval TRUE Operation is valid for current operation.
+ @retval FALSE Operation is invalid for current operation.
+**/
+BOOLEAN
+CheckAuthentication2Operation (
+ IN UINT32 CurrentAuthOperation,
+ IN UINT32 CheckAuthOperation
+ )
+{
+ //
+ // Make sure new auth operation can be recognized.
+ //
+ if (CheckAuthOperation == EFI_AUTH_OPERATION_NONE) {
+ return FALSE;
+ }
+ if ((CheckAuthOperation & ~(EFI_AUTH_IMAGE_OPERATION_MASK |
+ EFI_AUTH_NONE_IMAGE_OPERATION_MASK |
+ EFI_AUTH_OPERATION_IMAGE_REQUIRED)) != 0) {
+ return FALSE;
+ }
+
+ //
+ // When current operation includes measure image operation,
+ // only another measure image or none image operation will be allowed.
+ //
+ if ((CurrentAuthOperation & EFI_AUTH_OPERATION_MEASURE_IMAGE) == EFI_AUTH_OPERATION_MEASURE_IMAGE) {
+ if (((CheckAuthOperation & EFI_AUTH_OPERATION_MEASURE_IMAGE) == EFI_AUTH_OPERATION_MEASURE_IMAGE) ||
+ ((CheckAuthOperation & EFI_AUTH_IMAGE_OPERATION_MASK) == 0)) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+ }
+
+ //
+ // Any other operation will be allowed.
+ //
+ return TRUE;
+}
+
+/**
+ Register security measurement handler with its operation type. Different
+ handlers with the same operation can all be registered.
+
+ If Security2Handler is NULL, then ASSERT().
+ If no enough resources available to register new handler, then ASSERT().
+ If AuthenticationOperation is not recongnized, then ASSERT().
+ If AuthenticationOperation is EFI_AUTH_OPERATION_NONE, then ASSERT().
+ If the previous register handler can't be executed before the later register handler, then ASSERT().
+
+ @param[in] Security2Handler The security measurement service handler to be registered.
+ @param[in] AuthenticationOperation The operation type is specified for the registered handler.
+
+ @retval EFI_SUCCESS The handlers were registered successfully.
+**/
+EFI_STATUS
+EFIAPI
+RegisterSecurity2Handler (
+ IN SECURITY2_FILE_AUTHENTICATION_HANDLER Security2Handler,
+ IN UINT32 AuthenticationOperation
+ )
+{
+ EFI_STATUS Status;
+
+ ASSERT (Security2Handler != NULL);
+
+ //
+ // Make sure AuthenticationOperation is valid in the register order.
+ //
+ ASSERT (CheckAuthentication2Operation (mCurrentAuthOperation2, AuthenticationOperation));
+ mCurrentAuthOperation2 = mCurrentAuthOperation2 | AuthenticationOperation;
+
+ //
+ // Check whether the handler lists is enough to store new handler.
+ //
+ if (mNumberOfSecurity2Handler == mMaxNumberOfSecurity2Handler) {
+ //
+ // Allocate more resources for new handler.
+ //
+ Status = ReallocateSecurity2HandlerTable();
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ //
+ // Register new handler into the handler list.
+ //
+ mSecurity2Table[mNumberOfSecurity2Handler].Security2Operation = AuthenticationOperation;
+ mSecurity2Table[mNumberOfSecurity2Handler].Security2Handler = Security2Handler;
+ mNumberOfSecurity2Handler ++;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Execute registered handlers based on input AuthenticationOperation until
+ one returns an error and that error is returned.
+
+ If none of the handlers return an error, then EFI_SUCCESS is returned.
+ The handlers those satisfy AuthenticationOperation will only be executed.
+ The handlers are executed in same order to their registered order.
+
+ @param[in] AuthenticationOperation
+ The operation type specifies which handlers will be executed.
+ @param[in] AuthenticationStatus
+ The authentication status for the input file.
+ @param[in] File This is a pointer to the device path of the file that is
+ being dispatched. This will optionally be used for logging.
+ @param[in] FileBuffer A pointer to the buffer with the UEFI file image
+ @param[in] FileSize The size of File buffer.
+ @param[in] BootPolicy A boot policy that was used to call LoadImage() UEFI service.
+
+ @retval EFI_SUCCESS The file specified by DevicePath and non-NULL
+ FileBuffer did authenticate, and the platform policy dictates
+ that the DXE Foundation may use the file.
+ @retval EFI_SUCCESS The device path specified by NULL device path DevicePath
+ and non-NULL FileBuffer did authenticate, and the platform
+ policy dictates that the DXE Foundation may execute the image in
+ FileBuffer.
+ @retval EFI_SUCCESS FileBuffer is NULL and current user has permission to start
+ UEFI device drivers on the device path specified by DevicePath.
+ @retval EFI_SECURITY_VIOLATION The file specified by File or FileBuffer did not
+ authenticate, and the platform policy dictates that
+ the file should be placed in the untrusted state.
+ @retval EFI_SECURITY_VIOLATION FileBuffer FileBuffer is NULL and the user has no
+ permission to start UEFI device drivers on the device path specified
+ by DevicePath.
+ @retval EFI_SECURITY_VIOLATION FileBuffer is not NULL and the user has no permission to load
+ drivers from the device path specified by DevicePath. The
+ image has been added into the list of the deferred images.
+ @retval EFI_ACCESS_DENIED The file specified by File did not authenticate, and
+ the platform policy dictates that the DXE
+ Foundation may not use File.
+ @retval EFI_INVALID_PARAMETER File and FileBuffer are both NULL.
+**/
+EFI_STATUS
+EFIAPI
+ExecuteSecurity2Handlers (
+ IN UINT32 AuthenticationOperation,
+ IN UINT32 AuthenticationStatus,
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *File,
+ IN VOID *FileBuffer,
+ IN UINTN FileSize,
+ IN BOOLEAN BootPolicy
+ )
+{
+ UINT32 Index;
+ EFI_STATUS Status;
+
+ //
+ // Invalid case if File and FileBuffer are both NULL.
+ //
+ if (File == NULL && FileBuffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Directly return successfully when no handler is registered.
+ //
+ if (mNumberOfSecurity2Handler == 0) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Run security handler in same order to their registered list
+ //
+ for (Index = 0; Index < mNumberOfSecurity2Handler; Index ++) {
+ //
+ // If FileBuffer is not NULL, the input is Image, which will be handled by EFI_AUTH_IMAGE_OPERATION_MASK operation.
+ // If FileBuffer is NULL, the input is not Image, which will be handled by EFI_AUTH_NONE_IMAGE_OPERATION_MASK operation.
+ // Other cases are ignored.
+ //
+ if ((FileBuffer != NULL && (mSecurity2Table[Index].Security2Operation & EFI_AUTH_IMAGE_OPERATION_MASK) != 0) ||
+ (FileBuffer == NULL && (mSecurity2Table[Index].Security2Operation & EFI_AUTH_NONE_IMAGE_OPERATION_MASK) != 0)) {
+ //
+ // Execute registered handlers based on input AuthenticationOperation
+ //
+ if ((mSecurity2Table[Index].Security2Operation & AuthenticationOperation) != 0) {
+ Status = mSecurity2Table[Index].Security2Handler (
+ AuthenticationStatus,
+ File,
+ FileBuffer,
+ FileSize,
+ BootPolicy
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/Core/MdeModulePkg/Library/DxeSecurityManagementLib/DxeSecurityManagementLib.inf b/Core/MdeModulePkg/Library/DxeSecurityManagementLib/DxeSecurityManagementLib.inf
new file mode 100644
index 0000000000..0f8a13b99d
--- /dev/null
+++ b/Core/MdeModulePkg/Library/DxeSecurityManagementLib/DxeSecurityManagementLib.inf
@@ -0,0 +1,48 @@
+## @file
+# Instance of SecurityManagementLib Library for DXE phase.
+#
+# This library provides generic security measurement functions for DXE module.
+#
+# Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxeSecurityManagementLib
+ MODULE_UNI_FILE = DxeSecurityManagementLib.uni
+ FILE_GUID = 7F61122C-19DF-47c3-BA0D-6C1149E30FA1
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = SecurityManagementLib|DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SAL_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ DxeSecurityManagementLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ MemoryAllocationLib
+ DebugLib
+ DxeServicesLib
+ DevicePathLib
+ UefiBootServicesTableLib
+
+[Protocols]
+ gEfiLoadFileProtocolGuid ## SOMETIMES_CONSUMES
diff --git a/Core/MdeModulePkg/Library/DxeSecurityManagementLib/DxeSecurityManagementLib.uni b/Core/MdeModulePkg/Library/DxeSecurityManagementLib/DxeSecurityManagementLib.uni
new file mode 100644
index 0000000000..6ead295caf
--- /dev/null
+++ b/Core/MdeModulePkg/Library/DxeSecurityManagementLib/DxeSecurityManagementLib.uni
Binary files differ
diff --git a/Core/MdeModulePkg/Library/DxeSmmPerformanceLib/DxeSmmPerformanceLib.c b/Core/MdeModulePkg/Library/DxeSmmPerformanceLib/DxeSmmPerformanceLib.c
new file mode 100644
index 0000000000..7af6478bec
--- /dev/null
+++ b/Core/MdeModulePkg/Library/DxeSmmPerformanceLib/DxeSmmPerformanceLib.c
@@ -0,0 +1,866 @@
+/** @file
+ Performance library instance used in DXE phase to dump both PEI/DXE and SMM performance data.
+
+ This library instance allows a DXE driver or UEFI application to dump both PEI/DXE and SMM performance data.
+ StartPerformanceMeasurement(), EndPerformanceMeasurement(), StartPerformanceMeasurementEx()
+ and EndPerformanceMeasurementEx() are not implemented.
+
+ Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+
+#include <PiDxe.h>
+
+#include <Guid/Performance.h>
+
+#include <Library/PerformanceLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/PcdLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/BaseLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+#include <Protocol/SmmCommunication.h>
+
+#include <Guid/PiSmmCommunicationRegionTable.h>
+#include <Library/UefiLib.h>
+
+#define SMM_PERFORMANCE_COMMUNICATION_BUFFER_SIZE (OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data) + sizeof (SMM_PERF_COMMUNICATE))
+
+EFI_SMM_COMMUNICATION_PROTOCOL *mSmmCommunication = NULL;
+UINT8 *mSmmPerformanceBuffer;
+GAUGE_DATA_ENTRY *mGaugeData = NULL;
+UINTN mGaugeNumberOfEntries = 0;
+GAUGE_DATA_ENTRY_EX *mGaugeDataEx = NULL;
+UINTN mGaugeNumberOfEntriesEx = 0;
+
+BOOLEAN mNoSmmPerfHandler = FALSE;
+BOOLEAN mNoSmmPerfExHandler = FALSE;
+
+//
+// The cached Performance Protocol and PerformanceEx Protocol interface.
+//
+PERFORMANCE_PROTOCOL *mPerformance = NULL;
+PERFORMANCE_EX_PROTOCOL *mPerformanceEx = NULL;
+
+/**
+ The function caches the pointer to SMM Communication protocol.
+
+ The function locates SMM Communication protocol from protocol database.
+
+ @retval EFI_SUCCESS SMM Communication protocol is successfully located.
+ @retval Other SMM Communication protocol is not located to log performance.
+
+**/
+EFI_STATUS
+GetCommunicationProtocol (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_SMM_COMMUNICATION_PROTOCOL *Communication;
+
+ if (mSmmCommunication != NULL) {
+ return EFI_SUCCESS;
+ }
+
+ Status = gBS->LocateProtocol (&gEfiSmmCommunicationProtocolGuid, NULL, (VOID **) &Communication);
+ if (!EFI_ERROR (Status)) {
+ ASSERT (Communication != NULL);
+ //
+ // Cache SMM Communication protocol.
+ //
+ mSmmCommunication = Communication;
+ }
+
+ return Status;
+}
+
+/**
+ The function caches the pointers to PerformanceEx protocol and Performance Protocol.
+
+ The function locates PerformanceEx protocol and Performance Protocol from protocol database.
+
+ @retval EFI_SUCCESS PerformanceEx protocol or Performance Protocol is successfully located.
+ @retval EFI_NOT_FOUND Both PerformanceEx protocol and Performance Protocol are not located to log performance.
+
+**/
+EFI_STATUS
+GetPerformanceProtocol (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ PERFORMANCE_PROTOCOL *Performance;
+ PERFORMANCE_EX_PROTOCOL *PerformanceEx;
+
+ if (mPerformanceEx != NULL || mPerformance != NULL) {
+ return EFI_SUCCESS;
+ }
+
+ Status = gBS->LocateProtocol (&gPerformanceExProtocolGuid, NULL, (VOID **) &PerformanceEx);
+ if (!EFI_ERROR (Status)) {
+ ASSERT (PerformanceEx != NULL);
+ //
+ // Cache PerformanceEx Protocol.
+ //
+ mPerformanceEx = PerformanceEx;
+ return EFI_SUCCESS;
+ }
+
+ Status = gBS->LocateProtocol (&gPerformanceProtocolGuid, NULL, (VOID **) &Performance);
+ if (!EFI_ERROR (Status)) {
+ ASSERT (Performance != NULL);
+ //
+ // Cache performance protocol.
+ //
+ mPerformance = Performance;
+ return EFI_SUCCESS;
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Creates a record for the beginning of a performance measurement.
+
+ Creates a record that contains the Handle, Token, Module and Identifier.
+ If TimeStamp is not zero, then TimeStamp is added to the record as the start time.
+ If TimeStamp is zero, then this function reads the current time stamp
+ and adds that time stamp value to the record as the start time.
+
+ @param Handle Pointer to environment specific context used
+ to identify the component being measured.
+ @param Token Pointer to a Null-terminated ASCII string
+ that identifies the component being measured.
+ @param Module Pointer to a Null-terminated ASCII string
+ that identifies the module being measured.
+ @param TimeStamp 64-bit time stamp.
+ @param Identifier 32-bit identifier. If the value is 0, the created record
+ is same as the one created by StartPerformanceMeasurement.
+
+ @retval RETURN_SUCCESS The start of the measurement was recorded.
+ @retval RETURN_OUT_OF_RESOURCES There are not enough resources to record the measurement.
+
+**/
+RETURN_STATUS
+EFIAPI
+StartPerformanceMeasurementEx (
+ IN CONST VOID *Handle, OPTIONAL
+ IN CONST CHAR8 *Token, OPTIONAL
+ IN CONST CHAR8 *Module, OPTIONAL
+ IN UINT64 TimeStamp,
+ IN UINT32 Identifier
+ )
+{
+ return RETURN_SUCCESS;
+}
+
+/**
+ Fills in the end time of a performance measurement.
+
+ Looks up the record that matches Handle, Token, Module and Identifier.
+ If the record can not be found then return RETURN_NOT_FOUND.
+ If the record is found and TimeStamp is not zero,
+ then TimeStamp is added to the record as the end time.
+ If the record is found and TimeStamp is zero, then this function reads
+ the current time stamp and adds that time stamp value to the record as the end time.
+
+ @param Handle Pointer to environment specific context used
+ to identify the component being measured.
+ @param Token Pointer to a Null-terminated ASCII string
+ that identifies the component being measured.
+ @param Module Pointer to a Null-terminated ASCII string
+ that identifies the module being measured.
+ @param TimeStamp 64-bit time stamp.
+ @param Identifier 32-bit identifier. If the value is 0, the found record
+ is same as the one found by EndPerformanceMeasurement.
+
+ @retval RETURN_SUCCESS The end of the measurement was recorded.
+ @retval RETURN_NOT_FOUND The specified measurement record could not be found.
+
+**/
+RETURN_STATUS
+EFIAPI
+EndPerformanceMeasurementEx (
+ IN CONST VOID *Handle, OPTIONAL
+ IN CONST CHAR8 *Token, OPTIONAL
+ IN CONST CHAR8 *Module, OPTIONAL
+ IN UINT64 TimeStamp,
+ IN UINT32 Identifier
+ )
+{
+ return RETURN_SUCCESS;
+}
+
+/**
+ Creates a record for the beginning of a performance measurement.
+
+ Creates a record that contains the Handle, Token, and Module.
+ If TimeStamp is not zero, then TimeStamp is added to the record as the start time.
+ If TimeStamp is zero, then this function reads the current time stamp
+ and adds that time stamp value to the record as the start time.
+
+ @param Handle Pointer to environment specific context used
+ to identify the component being measured.
+ @param Token Pointer to a Null-terminated ASCII string
+ that identifies the component being measured.
+ @param Module Pointer to a Null-terminated ASCII string
+ that identifies the module being measured.
+ @param TimeStamp 64-bit time stamp.
+
+ @retval RETURN_SUCCESS The start of the measurement was recorded.
+ @retval RETURN_OUT_OF_RESOURCES There are not enough resources to record the measurement.
+
+**/
+RETURN_STATUS
+EFIAPI
+StartPerformanceMeasurement (
+ IN CONST VOID *Handle, OPTIONAL
+ IN CONST CHAR8 *Token, OPTIONAL
+ IN CONST CHAR8 *Module, OPTIONAL
+ IN UINT64 TimeStamp
+ )
+{
+ return RETURN_SUCCESS;
+}
+
+/**
+ Fills in the end time of a performance measurement.
+
+ Looks up the record that matches Handle, Token, and Module.
+ If the record can not be found then return RETURN_NOT_FOUND.
+ If the record is found and TimeStamp is not zero,
+ then TimeStamp is added to the record as the end time.
+ If the record is found and TimeStamp is zero, then this function reads
+ the current time stamp and adds that time stamp value to the record as the end time.
+
+ @param Handle Pointer to environment specific context used
+ to identify the component being measured.
+ @param Token Pointer to a Null-terminated ASCII string
+ that identifies the component being measured.
+ @param Module Pointer to a Null-terminated ASCII string
+ that identifies the module being measured.
+ @param TimeStamp 64-bit time stamp.
+
+ @retval RETURN_SUCCESS The end of the measurement was recorded.
+ @retval RETURN_NOT_FOUND The specified measurement record could not be found.
+
+**/
+RETURN_STATUS
+EFIAPI
+EndPerformanceMeasurement (
+ IN CONST VOID *Handle, OPTIONAL
+ IN CONST CHAR8 *Token, OPTIONAL
+ IN CONST CHAR8 *Module, OPTIONAL
+ IN UINT64 TimeStamp
+ )
+{
+ return RETURN_SUCCESS;
+}
+
+/**
+ Attempts to retrieve a performance measurement log entry from the performance measurement log.
+ It can also retrieve the log created by StartPerformanceMeasurement and EndPerformanceMeasurement,
+ and then assign the Identifier with 0.
+
+ Attempts to retrieve the performance log entry specified by LogEntryKey. If LogEntryKey is
+ zero on entry, then an attempt is made to retrieve the first entry from the performance log,
+ and the key for the second entry in the log is returned. If the performance log is empty,
+ then no entry is retrieved and zero is returned. If LogEntryKey is not zero, then the performance
+ log entry associated with LogEntryKey is retrieved, and the key for the next entry in the log is
+ returned. If LogEntryKey is the key for the last entry in the log, then the last log entry is
+ retrieved and an implementation specific non-zero key value that specifies the end of the performance
+ log is returned. If LogEntryKey is equal this implementation specific non-zero key value, then no entry
+ is retrieved and zero is returned. In the cases where a performance log entry can be returned,
+ the log entry is returned in Handle, Token, Module, StartTimeStamp, EndTimeStamp and Identifier.
+ If LogEntryKey is not a valid log entry key for the performance measurement log, then ASSERT().
+ If Handle is NULL, then ASSERT().
+ If Token is NULL, then ASSERT().
+ If Module is NULL, then ASSERT().
+ If StartTimeStamp is NULL, then ASSERT().
+ If EndTimeStamp is NULL, then ASSERT().
+ If Identifier is NULL, then ASSERT().
+
+ @param LogEntryKey On entry, the key of the performance measurement log entry to retrieve.
+ 0, then the first performance measurement log entry is retrieved.
+ On exit, the key of the next performance log entry.
+ @param Handle Pointer to environment specific context used to identify the component
+ being measured.
+ @param Token Pointer to a Null-terminated ASCII string that identifies the component
+ being measured.
+ @param Module Pointer to a Null-terminated ASCII string that identifies the module
+ being measured.
+ @param StartTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
+ was started.
+ @param EndTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
+ was ended.
+ @param Identifier Pointer to the 32-bit identifier that was recorded.
+
+ @return The key for the next performance log entry (in general case).
+
+**/
+UINTN
+EFIAPI
+GetByPerformanceProtocol (
+ IN UINTN LogEntryKey,
+ OUT CONST VOID **Handle,
+ OUT CONST CHAR8 **Token,
+ OUT CONST CHAR8 **Module,
+ OUT UINT64 *StartTimeStamp,
+ OUT UINT64 *EndTimeStamp,
+ OUT UINT32 *Identifier
+ )
+{
+ EFI_STATUS Status;
+ GAUGE_DATA_ENTRY_EX *GaugeData;
+
+ Status = GetPerformanceProtocol ();
+ if (EFI_ERROR (Status)) {
+ return 0;
+ }
+
+ if (mPerformanceEx != NULL) {
+ Status = mPerformanceEx->GetGaugeEx (LogEntryKey++, &GaugeData);
+ } else if (mPerformance != NULL) {
+ Status = mPerformance->GetGauge (LogEntryKey++, (GAUGE_DATA_ENTRY **) &GaugeData);
+ } else {
+ ASSERT (FALSE);
+ return 0;
+ }
+
+ //
+ // Make sure that LogEntryKey is a valid log entry key,
+ //
+ ASSERT (Status != EFI_INVALID_PARAMETER);
+
+ if (EFI_ERROR (Status)) {
+ //
+ // The LogEntryKey is the last entry (equals to the total entry number).
+ //
+ return 0;
+ }
+
+ ASSERT (GaugeData != NULL);
+
+ *Handle = (VOID *) (UINTN) GaugeData->Handle;
+ *Token = GaugeData->Token;
+ *Module = GaugeData->Module;
+ *StartTimeStamp = GaugeData->StartTimeStamp;
+ *EndTimeStamp = GaugeData->EndTimeStamp;
+ if (mPerformanceEx != NULL) {
+ *Identifier = GaugeData->Identifier;
+ } else {
+ *Identifier = 0;
+ }
+
+ return LogEntryKey;
+}
+
+
+/**
+ Retrieves all previous logged performance measurement.
+ Function will use SMM communicate protocol to get all previous SMM performance measurement data.
+ If success, data buffer will be returned. If fail function will return NULL.
+
+ @param LogEntryKey On entry, the key of the performance measurement log entry to retrieve.
+ 0, then the first performance measurement log entry is retrieved.
+ On exit, the key of the next performance log entry.
+
+ @retval !NULL Get all gauge data success.
+ @retval NULL Get all gauge data failed.
+**/
+GAUGE_DATA_ENTRY *
+EFIAPI
+GetAllSmmGaugeData (
+ IN UINTN LogEntryKey
+ )
+{
+ EFI_STATUS Status;
+ EFI_SMM_COMMUNICATE_HEADER *SmmCommBufferHeader;
+ SMM_PERF_COMMUNICATE *SmmPerfCommData;
+ UINTN CommSize;
+ UINTN DataSize;
+ EDKII_PI_SMM_COMMUNICATION_REGION_TABLE *PiSmmCommunicationRegionTable;
+ UINT32 Index;
+ EFI_MEMORY_DESCRIPTOR *Entry;
+ UINT8 *Buffer;
+ UINTN Size;
+ UINTN NumberOfEntries;
+ UINTN EntriesGot;
+
+ if (mNoSmmPerfHandler) {
+ //
+ // Not try to get the SMM gauge data again
+ // if no SMM Performance handler found.
+ //
+ return NULL;
+ }
+
+ if (LogEntryKey != 0) {
+ if (mGaugeData != NULL) {
+ return mGaugeData;
+ }
+ } else {
+ //
+ // Reget the SMM gauge data at the first entry get.
+ //
+ if (mGaugeData != NULL) {
+ FreePool (mGaugeData);
+ mGaugeData = NULL;
+ mGaugeNumberOfEntries = 0;
+ }
+ }
+
+ Status = GetCommunicationProtocol ();
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ Status = EfiGetSystemConfigurationTable (
+ &gEdkiiPiSmmCommunicationRegionTableGuid,
+ (VOID **) &PiSmmCommunicationRegionTable
+ );
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+ ASSERT (PiSmmCommunicationRegionTable != NULL);
+ Entry = (EFI_MEMORY_DESCRIPTOR *) (PiSmmCommunicationRegionTable + 1);
+ Size = 0;
+ for (Index = 0; Index < PiSmmCommunicationRegionTable->NumberOfEntries; Index++) {
+ if (Entry->Type == EfiConventionalMemory) {
+ Size = EFI_PAGES_TO_SIZE ((UINTN) Entry->NumberOfPages);
+ if (Size >= (SMM_PERFORMANCE_COMMUNICATION_BUFFER_SIZE + sizeof (GAUGE_DATA_ENTRY))) {
+ break;
+ }
+ }
+ Entry = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) Entry + PiSmmCommunicationRegionTable->DescriptorSize);
+ }
+ ASSERT (Index < PiSmmCommunicationRegionTable->NumberOfEntries);
+ mSmmPerformanceBuffer = (UINT8 *) (UINTN) Entry->PhysicalStart;
+
+ //
+ // Initialize communicate buffer
+ //
+ SmmCommBufferHeader = (EFI_SMM_COMMUNICATE_HEADER *)mSmmPerformanceBuffer;
+ SmmPerfCommData = (SMM_PERF_COMMUNICATE *)SmmCommBufferHeader->Data;
+ ZeroMem((UINT8*)SmmPerfCommData, sizeof(SMM_PERF_COMMUNICATE));
+
+ CopyGuid (&SmmCommBufferHeader->HeaderGuid, &gSmmPerformanceProtocolGuid);
+ SmmCommBufferHeader->MessageLength = sizeof(SMM_PERF_COMMUNICATE);
+ CommSize = SMM_PERFORMANCE_COMMUNICATION_BUFFER_SIZE;
+
+ //
+ // Get total number of SMM gauge entries
+ //
+ SmmPerfCommData->Function = SMM_PERF_FUNCTION_GET_GAUGE_ENTRY_NUMBER;
+ Status = mSmmCommunication->Communicate (mSmmCommunication, mSmmPerformanceBuffer, &CommSize);
+ if (Status == EFI_NOT_FOUND) {
+ mNoSmmPerfHandler = TRUE;
+ }
+ if (EFI_ERROR (Status) || EFI_ERROR (SmmPerfCommData->ReturnStatus) || SmmPerfCommData->NumberOfEntries == 0) {
+ return NULL;
+ }
+
+ mGaugeNumberOfEntries = SmmPerfCommData->NumberOfEntries;
+
+ Buffer = mSmmPerformanceBuffer + SMM_PERFORMANCE_COMMUNICATION_BUFFER_SIZE;
+ NumberOfEntries = (Size - SMM_PERFORMANCE_COMMUNICATION_BUFFER_SIZE) / sizeof (GAUGE_DATA_ENTRY);
+ DataSize = mGaugeNumberOfEntries * sizeof(GAUGE_DATA_ENTRY);
+ mGaugeData = AllocateZeroPool(DataSize);
+ ASSERT (mGaugeData != NULL);
+
+ //
+ // Get all SMM gauge data
+ //
+ SmmPerfCommData->Function = SMM_PERF_FUNCTION_GET_GAUGE_DATA;
+ SmmPerfCommData->GaugeData = (GAUGE_DATA_ENTRY *) Buffer;
+ EntriesGot = 0;
+ do {
+ SmmPerfCommData->LogEntryKey = EntriesGot;
+ if ((mGaugeNumberOfEntries - EntriesGot) >= NumberOfEntries) {
+ SmmPerfCommData->NumberOfEntries = NumberOfEntries;
+ } else {
+ SmmPerfCommData->NumberOfEntries = mGaugeNumberOfEntries - EntriesGot;
+ }
+ Status = mSmmCommunication->Communicate (mSmmCommunication, mSmmPerformanceBuffer, &CommSize);
+ if (EFI_ERROR (Status) || EFI_ERROR (SmmPerfCommData->ReturnStatus)) {
+ FreePool (mGaugeData);
+ mGaugeData = NULL;
+ mGaugeNumberOfEntries = 0;
+ return NULL;
+ } else {
+ CopyMem (&mGaugeData[EntriesGot], Buffer, SmmPerfCommData->NumberOfEntries * sizeof (GAUGE_DATA_ENTRY));
+ }
+ EntriesGot += SmmPerfCommData->NumberOfEntries;
+ } while (EntriesGot < mGaugeNumberOfEntries);
+
+ return mGaugeData;
+}
+
+/**
+ Retrieves all previous logged performance measurement.
+ Function will use SMM communicate protocol to get all previous SMM performance measurement data.
+ If success, data buffer will be returned. If fail function will return NULL.
+
+ @param LogEntryKey On entry, the key of the performance measurement log entry to retrieve.
+ 0, then the first performance measurement log entry is retrieved.
+ On exit, the key of the next performance log entry.
+
+ @retval !NULL Get all gauge data success.
+ @retval NULL Get all gauge data failed.
+**/
+GAUGE_DATA_ENTRY_EX *
+EFIAPI
+GetAllSmmGaugeDataEx (
+ IN UINTN LogEntryKey
+ )
+{
+ EFI_STATUS Status;
+ EFI_SMM_COMMUNICATE_HEADER *SmmCommBufferHeader;
+ SMM_PERF_COMMUNICATE_EX *SmmPerfCommData;
+ UINTN CommSize;
+ UINTN DataSize;
+ EDKII_PI_SMM_COMMUNICATION_REGION_TABLE *PiSmmCommunicationRegionTable;
+ UINT32 Index;
+ EFI_MEMORY_DESCRIPTOR *Entry;
+ UINT8 *Buffer;
+ UINTN Size;
+ UINTN NumberOfEntries;
+ UINTN EntriesGot;
+
+ if (mNoSmmPerfExHandler) {
+ //
+ // Not try to get the SMM gauge data again
+ // if no SMM PerformanceEx handler found.
+ //
+ return NULL;
+ }
+
+ if (LogEntryKey != 0) {
+ if (mGaugeDataEx != NULL) {
+ return mGaugeDataEx;
+ }
+ } else {
+ //
+ // Reget the SMM gauge data at the first entry get.
+ //
+ if (mGaugeDataEx != NULL) {
+ FreePool (mGaugeDataEx);
+ mGaugeDataEx = NULL;
+ mGaugeNumberOfEntriesEx = 0;
+ }
+ }
+
+ Status = GetCommunicationProtocol ();
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ Status = EfiGetSystemConfigurationTable (
+ &gEdkiiPiSmmCommunicationRegionTableGuid,
+ (VOID **) &PiSmmCommunicationRegionTable
+ );
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+ ASSERT (PiSmmCommunicationRegionTable != NULL);
+ Entry = (EFI_MEMORY_DESCRIPTOR *) (PiSmmCommunicationRegionTable + 1);
+ Size = 0;
+ for (Index = 0; Index < PiSmmCommunicationRegionTable->NumberOfEntries; Index++) {
+ if (Entry->Type == EfiConventionalMemory) {
+ Size = EFI_PAGES_TO_SIZE ((UINTN) Entry->NumberOfPages);
+ if (Size >= (SMM_PERFORMANCE_COMMUNICATION_BUFFER_SIZE + sizeof (GAUGE_DATA_ENTRY_EX))) {
+ break;
+ }
+ }
+ Entry = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) Entry + PiSmmCommunicationRegionTable->DescriptorSize);
+ }
+ ASSERT (Index < PiSmmCommunicationRegionTable->NumberOfEntries);
+ mSmmPerformanceBuffer = (UINT8 *) (UINTN) Entry->PhysicalStart;
+ //
+ // Initialize communicate buffer
+ //
+ SmmCommBufferHeader = (EFI_SMM_COMMUNICATE_HEADER *)mSmmPerformanceBuffer;
+ SmmPerfCommData = (SMM_PERF_COMMUNICATE_EX *)SmmCommBufferHeader->Data;
+ ZeroMem((UINT8*)SmmPerfCommData, sizeof(SMM_PERF_COMMUNICATE_EX));
+
+ CopyGuid (&SmmCommBufferHeader->HeaderGuid, &gSmmPerformanceExProtocolGuid);
+ SmmCommBufferHeader->MessageLength = sizeof(SMM_PERF_COMMUNICATE_EX);
+ CommSize = SMM_PERFORMANCE_COMMUNICATION_BUFFER_SIZE;
+
+ //
+ // Get total number of SMM gauge entries
+ //
+ SmmPerfCommData->Function = SMM_PERF_FUNCTION_GET_GAUGE_ENTRY_NUMBER;
+ Status = mSmmCommunication->Communicate (mSmmCommunication, mSmmPerformanceBuffer, &CommSize);
+ if (Status == EFI_NOT_FOUND) {
+ mNoSmmPerfExHandler = TRUE;
+ }
+ if (EFI_ERROR (Status) || EFI_ERROR (SmmPerfCommData->ReturnStatus) || SmmPerfCommData->NumberOfEntries == 0) {
+ return NULL;
+ }
+
+ mGaugeNumberOfEntriesEx = SmmPerfCommData->NumberOfEntries;
+
+ Buffer = mSmmPerformanceBuffer + SMM_PERFORMANCE_COMMUNICATION_BUFFER_SIZE;
+ NumberOfEntries = (Size - SMM_PERFORMANCE_COMMUNICATION_BUFFER_SIZE) / sizeof (GAUGE_DATA_ENTRY_EX);
+ DataSize = mGaugeNumberOfEntriesEx * sizeof(GAUGE_DATA_ENTRY_EX);
+ mGaugeDataEx = AllocateZeroPool(DataSize);
+ ASSERT (mGaugeDataEx != NULL);
+
+ //
+ // Get all SMM gauge data
+ //
+ SmmPerfCommData->Function = SMM_PERF_FUNCTION_GET_GAUGE_DATA;
+ SmmPerfCommData->GaugeDataEx = (GAUGE_DATA_ENTRY_EX *) Buffer;
+ EntriesGot = 0;
+ do {
+ SmmPerfCommData->LogEntryKey = EntriesGot;
+ if ((mGaugeNumberOfEntriesEx - EntriesGot) >= NumberOfEntries) {
+ SmmPerfCommData->NumberOfEntries = NumberOfEntries;
+ } else {
+ SmmPerfCommData->NumberOfEntries = mGaugeNumberOfEntriesEx - EntriesGot;
+ }
+ Status = mSmmCommunication->Communicate (mSmmCommunication, mSmmPerformanceBuffer, &CommSize);
+ if (EFI_ERROR (Status) || EFI_ERROR (SmmPerfCommData->ReturnStatus)) {
+ FreePool (mGaugeDataEx);
+ mGaugeDataEx = NULL;
+ mGaugeNumberOfEntriesEx = 0;
+ return NULL;
+ } else {
+ CopyMem (&mGaugeDataEx[EntriesGot], Buffer, SmmPerfCommData->NumberOfEntries * sizeof (GAUGE_DATA_ENTRY_EX));
+ }
+ EntriesGot += SmmPerfCommData->NumberOfEntries;
+ } while (EntriesGot < mGaugeNumberOfEntriesEx);
+
+ return mGaugeDataEx;
+}
+
+/**
+ Attempts to retrieve a performance measurement log entry from the performance measurement log.
+ It can also retrieve the log created by StartPerformanceMeasurement and EndPerformanceMeasurement,
+ and then assign the Identifier with 0.
+
+ Attempts to retrieve the performance log entry specified by LogEntryKey. If LogEntryKey is
+ zero on entry, then an attempt is made to retrieve the first entry from the performance log,
+ and the key for the second entry in the log is returned. If the performance log is empty,
+ then no entry is retrieved and zero is returned. If LogEntryKey is not zero, then the performance
+ log entry associated with LogEntryKey is retrieved, and the key for the next entry in the log is
+ returned. If LogEntryKey is the key for the last entry in the log, then the last log entry is
+ retrieved and an implementation specific non-zero key value that specifies the end of the performance
+ log is returned. If LogEntryKey is equal this implementation specific non-zero key value, then no entry
+ is retrieved and zero is returned. In the cases where a performance log entry can be returned,
+ the log entry is returned in Handle, Token, Module, StartTimeStamp, EndTimeStamp and Identifier.
+ If LogEntryKey is not a valid log entry key for the performance measurement log, then ASSERT().
+ If Handle is NULL, then ASSERT().
+ If Token is NULL, then ASSERT().
+ If Module is NULL, then ASSERT().
+ If StartTimeStamp is NULL, then ASSERT().
+ If EndTimeStamp is NULL, then ASSERT().
+ If Identifier is NULL, then ASSERT().
+
+ @param LogEntryKey On entry, the key of the performance measurement log entry to retrieve.
+ 0, then the first performance measurement log entry is retrieved.
+ On exit, the key of the next performance log entry.
+ @param Handle Pointer to environment specific context used to identify the component
+ being measured.
+ @param Token Pointer to a Null-terminated ASCII string that identifies the component
+ being measured.
+ @param Module Pointer to a Null-terminated ASCII string that identifies the module
+ being measured.
+ @param StartTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
+ was started.
+ @param EndTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
+ was ended.
+ @param Identifier Pointer to the 32-bit identifier that was recorded.
+
+ @return The key for the next performance log entry (in general case).
+
+**/
+UINTN
+EFIAPI
+GetPerformanceMeasurementEx (
+ IN UINTN LogEntryKey,
+ OUT CONST VOID **Handle,
+ OUT CONST CHAR8 **Token,
+ OUT CONST CHAR8 **Module,
+ OUT UINT64 *StartTimeStamp,
+ OUT UINT64 *EndTimeStamp,
+ OUT UINT32 *Identifier
+ )
+{
+ GAUGE_DATA_ENTRY_EX *GaugeData;
+
+ GaugeData = NULL;
+
+ ASSERT (Handle != NULL);
+ ASSERT (Token != NULL);
+ ASSERT (Module != NULL);
+ ASSERT (StartTimeStamp != NULL);
+ ASSERT (EndTimeStamp != NULL);
+ ASSERT (Identifier != NULL);
+
+ mGaugeDataEx = GetAllSmmGaugeDataEx (LogEntryKey);
+ if (mGaugeDataEx != NULL) {
+ if (LogEntryKey >= mGaugeNumberOfEntriesEx) {
+ //
+ // Try to get the data by Performance Protocol.
+ //
+ LogEntryKey = LogEntryKey - mGaugeNumberOfEntriesEx;
+ LogEntryKey = GetByPerformanceProtocol (
+ LogEntryKey,
+ Handle,
+ Token,
+ Module,
+ StartTimeStamp,
+ EndTimeStamp,
+ Identifier
+ );
+ if (LogEntryKey == 0) {
+ //
+ // Last entry.
+ //
+ return LogEntryKey;
+ } else {
+ return (LogEntryKey + mGaugeNumberOfEntriesEx);
+ }
+ }
+
+ GaugeData = &mGaugeDataEx[LogEntryKey++];
+ *Identifier = GaugeData->Identifier;
+ } else {
+ mGaugeData = GetAllSmmGaugeData (LogEntryKey);
+ if (mGaugeData != NULL) {
+ if (LogEntryKey >= mGaugeNumberOfEntries) {
+ //
+ // Try to get the data by Performance Protocol.
+ //
+ LogEntryKey = LogEntryKey - mGaugeNumberOfEntries;
+ LogEntryKey = GetByPerformanceProtocol (
+ LogEntryKey,
+ Handle,
+ Token,
+ Module,
+ StartTimeStamp,
+ EndTimeStamp,
+ Identifier
+ );
+ if (LogEntryKey == 0) {
+ //
+ // Last entry.
+ //
+ return LogEntryKey;
+ } else {
+ return (LogEntryKey + mGaugeNumberOfEntries);
+ }
+ }
+
+ GaugeData = (GAUGE_DATA_ENTRY_EX *) &mGaugeData[LogEntryKey++];
+ *Identifier = 0;
+ } else {
+ return GetByPerformanceProtocol (
+ LogEntryKey,
+ Handle,
+ Token,
+ Module,
+ StartTimeStamp,
+ EndTimeStamp,
+ Identifier
+ );
+ }
+ }
+
+ *Handle = (VOID *) (UINTN) GaugeData->Handle;
+ *Token = GaugeData->Token;
+ *Module = GaugeData->Module;
+ *StartTimeStamp = GaugeData->StartTimeStamp;
+ *EndTimeStamp = GaugeData->EndTimeStamp;
+
+ return LogEntryKey;
+}
+
+/**
+ Attempts to retrieve a performance measurement log entry from the performance measurement log.
+ It can also retrieve the log created by StartPerformanceMeasurementEx and EndPerformanceMeasurementEx,
+ and then eliminate the Identifier.
+
+ Attempts to retrieve the performance log entry specified by LogEntryKey. If LogEntryKey is
+ zero on entry, then an attempt is made to retrieve the first entry from the performance log,
+ and the key for the second entry in the log is returned. If the performance log is empty,
+ then no entry is retrieved and zero is returned. If LogEntryKey is not zero, then the performance
+ log entry associated with LogEntryKey is retrieved, and the key for the next entry in the log is
+ returned. If LogEntryKey is the key for the last entry in the log, then the last log entry is
+ retrieved and an implementation specific non-zero key value that specifies the end of the performance
+ log is returned. If LogEntryKey is equal this implementation specific non-zero key value, then no entry
+ is retrieved and zero is returned. In the cases where a performance log entry can be returned,
+ the log entry is returned in Handle, Token, Module, StartTimeStamp, and EndTimeStamp.
+ If LogEntryKey is not a valid log entry key for the performance measurement log, then ASSERT().
+ If Handle is NULL, then ASSERT().
+ If Token is NULL, then ASSERT().
+ If Module is NULL, then ASSERT().
+ If StartTimeStamp is NULL, then ASSERT().
+ If EndTimeStamp is NULL, then ASSERT().
+
+ @param LogEntryKey On entry, the key of the performance measurement log entry to retrieve.
+ 0, then the first performance measurement log entry is retrieved.
+ On exit, the key of the next performance log entry.
+ @param Handle Pointer to environment specific context used to identify the component
+ being measured.
+ @param Token Pointer to a Null-terminated ASCII string that identifies the component
+ being measured.
+ @param Module Pointer to a Null-terminated ASCII string that identifies the module
+ being measured.
+ @param StartTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
+ was started.
+ @param EndTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
+ was ended.
+
+ @return The key for the next performance log entry (in general case).
+
+**/
+UINTN
+EFIAPI
+GetPerformanceMeasurement (
+ IN UINTN LogEntryKey,
+ OUT CONST VOID **Handle,
+ OUT CONST CHAR8 **Token,
+ OUT CONST CHAR8 **Module,
+ OUT UINT64 *StartTimeStamp,
+ OUT UINT64 *EndTimeStamp
+ )
+{
+ UINT32 Identifier;
+ return GetPerformanceMeasurementEx (LogEntryKey, Handle, Token, Module, StartTimeStamp, EndTimeStamp, &Identifier);
+}
+
+/**
+ Returns TRUE if the performance measurement macros are enabled.
+
+ This function returns TRUE if the PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
+ PcdPerformanceLibraryPropertyMask is set. Otherwise FALSE is returned.
+
+ @retval TRUE The PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
+ PcdPerformanceLibraryPropertyMask is set.
+ @retval FALSE The PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
+ PcdPerformanceLibraryPropertyMask is clear.
+
+**/
+BOOLEAN
+EFIAPI
+PerformanceMeasurementEnabled (
+ VOID
+ )
+{
+ return (BOOLEAN) ((PcdGet8(PcdPerformanceLibraryPropertyMask) & PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED) != 0);
+}
diff --git a/Core/MdeModulePkg/Library/DxeSmmPerformanceLib/DxeSmmPerformanceLib.inf b/Core/MdeModulePkg/Library/DxeSmmPerformanceLib/DxeSmmPerformanceLib.inf
new file mode 100644
index 0000000000..2b057704f8
--- /dev/null
+++ b/Core/MdeModulePkg/Library/DxeSmmPerformanceLib/DxeSmmPerformanceLib.inf
@@ -0,0 +1,68 @@
+## @file
+# Performance library instance used in DXE phase to dump SMM performance data.
+#
+# This library instance allows a DXE driver or UEFI application to dump both PEI/DXE and SMM performance data.
+# StartPerformanceMeasurement(), EndPerformanceMeasurement(), StartPerformanceMeasurementEx()
+# and EndPerformanceMeasurementEx() are not implemented.
+#
+# Copyright (c) 2011 - 2016, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxeSmmPerformanceLib
+ MODULE_UNI_FILE = DxeSmmPerformanceLib.uni
+ FILE_GUID = DA80C15C-0B4D-4e75-8946-4043DE559B0C
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = PerformanceLib|DXE_DRIVER DXE_RUNTIME_DRIVER UEFI_APPLICATION
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ DxeSmmPerformanceLib.c
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+
+[LibraryClasses]
+ BaseLib
+ UefiBootServicesTableLib
+ PcdLib
+ DebugLib
+ BaseMemoryLib
+ UefiRuntimeServicesTableLib
+ MemoryAllocationLib
+ UefiLib
+
+[Guids]
+ gPerformanceProtocolGuid ## SOMETIMES_CONSUMES ## UNDEFINED # Locate protocol
+ gPerformanceExProtocolGuid ## SOMETIMES_CONSUMES ## UNDEFINED # Locate protocol
+ gSmmPerformanceProtocolGuid ## SOMETIMES_PRODUCES ## UNDEFINED # Used to do smm communication
+ gSmmPerformanceExProtocolGuid ## SOMETIMES_PRODUCES ## UNDEFINED # Used to do smm communication
+ gEdkiiPiSmmCommunicationRegionTableGuid ## CONSUMES ## SystemTable
+
+[Protocols]
+ gEfiSmmCommunicationProtocolGuid ## CONSUMES
+
+
+[Pcd]
+ gEfiMdePkgTokenSpaceGuid.PcdPerformanceLibraryPropertyMask ## CONSUMES
+
+[Depex.common.DXE_DRIVER, Depex.common.DXE_RUNTIME_DRIVER]
+ gEfiSmmCommunicationProtocolGuid
diff --git a/Core/MdeModulePkg/Library/DxeSmmPerformanceLib/DxeSmmPerformanceLib.uni b/Core/MdeModulePkg/Library/DxeSmmPerformanceLib/DxeSmmPerformanceLib.uni
new file mode 100644
index 0000000000..b92de07144
--- /dev/null
+++ b/Core/MdeModulePkg/Library/DxeSmmPerformanceLib/DxeSmmPerformanceLib.uni
Binary files differ
diff --git a/Core/MdeModulePkg/Library/DxeTcpIoLib/DxeTcpIoLib.c b/Core/MdeModulePkg/Library/DxeTcpIoLib/DxeTcpIoLib.c
new file mode 100644
index 0000000000..17183e1a6c
--- /dev/null
+++ b/Core/MdeModulePkg/Library/DxeTcpIoLib/DxeTcpIoLib.c
@@ -0,0 +1,1007 @@
+/** @file
+ This library is used to share code between UEFI network stack modules.
+ It provides the helper routines to access TCP service.
+
+Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at<BR>
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Uefi.h>
+
+#include <Library/TcpIoLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseMemoryLib.h>
+
+/**
+ The common notify function associated with various TcpIo events.
+
+ @param[in] Event The event signaled.
+ @param[in] Context The context.
+
+**/
+VOID
+EFIAPI
+TcpIoCommonNotify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ if ((Event == NULL) || (Context == NULL)) {
+ return ;
+ }
+
+ *((BOOLEAN *) Context) = TRUE;
+}
+
+/**
+ The internal function for delay configuring TCP6 when IP6 driver is still in DAD.
+
+ @param[in] Tcp6 The EFI_TCP6_PROTOCOL protocol instance.
+ @param[in] Tcp6ConfigData The Tcp6 configuration data.
+
+ @retval EFI_SUCCESS The operational settings successfully
+ completed.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval Others Failed to finish the operation.
+
+**/
+EFI_STATUS
+TcpIoGetMapping (
+ IN EFI_TCP6_PROTOCOL *Tcp6,
+ IN EFI_TCP6_CONFIG_DATA *Tcp6ConfigData
+ )
+{
+ EFI_STATUS Status;
+ EFI_EVENT Event;
+
+ if ((Tcp6 == NULL) || (Tcp6ConfigData == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Event = NULL;
+ Status = gBS->CreateEvent (
+ EVT_TIMER,
+ TPL_CALLBACK,
+ NULL,
+ NULL,
+ &Event
+ );
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+
+ Status = gBS->SetTimer (
+ Event,
+ TimerRelative,
+ TCP_GET_MAPPING_TIMEOUT
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+
+ while (EFI_ERROR (gBS->CheckEvent (Event))) {
+
+ Tcp6->Poll (Tcp6);
+
+ Status = Tcp6->Configure (Tcp6, Tcp6ConfigData);
+
+ if (!EFI_ERROR (Status)) {
+ break;
+ }
+ }
+
+ON_EXIT:
+
+ if (Event != NULL) {
+ gBS->CloseEvent (Event);
+ }
+
+ return Status;
+}
+
+/**
+ Create a TCP socket with the specified configuration data.
+
+ @param[in] Image The handle of the driver image.
+ @param[in] Controller The handle of the controller.
+ @param[in] TcpVersion The version of Tcp, TCP_VERSION_4 or TCP_VERSION_6.
+ @param[in] ConfigData The Tcp configuration data.
+ @param[out] TcpIo The TcpIo.
+
+ @retval EFI_SUCCESS The TCP socket is created and configured.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_UNSUPPORTED One or more of the control options are not
+ supported in the implementation.
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
+ @retval Others Failed to create the TCP socket or configure it.
+
+**/
+EFI_STATUS
+EFIAPI
+TcpIoCreateSocket (
+ IN EFI_HANDLE Image,
+ IN EFI_HANDLE Controller,
+ IN UINT8 TcpVersion,
+ IN TCP_IO_CONFIG_DATA *ConfigData,
+ OUT TCP_IO *TcpIo
+ )
+{
+ EFI_STATUS Status;
+ EFI_EVENT Event;
+ EFI_GUID *ServiceBindingGuid;
+ EFI_GUID *ProtocolGuid;
+ VOID **Interface;
+ EFI_TCP4_OPTION ControlOption;
+ EFI_TCP4_CONFIG_DATA Tcp4ConfigData;
+ EFI_TCP4_ACCESS_POINT *AccessPoint4;
+ EFI_TCP4_PROTOCOL *Tcp4;
+ EFI_TCP6_CONFIG_DATA Tcp6ConfigData;
+ EFI_TCP6_ACCESS_POINT *AccessPoint6;
+ EFI_TCP6_PROTOCOL *Tcp6;
+ EFI_TCP4_RECEIVE_DATA *RxData;
+
+ if ((Image == NULL) || (Controller == NULL) || (ConfigData == NULL) || (TcpIo == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Tcp4 = NULL;
+ Tcp6 = NULL;
+
+ ZeroMem (TcpIo, sizeof (TCP_IO));
+
+ if (TcpVersion == TCP_VERSION_4) {
+ ServiceBindingGuid = &gEfiTcp4ServiceBindingProtocolGuid;
+ ProtocolGuid = &gEfiTcp4ProtocolGuid;
+ Interface = (VOID **) (&TcpIo->Tcp.Tcp4);
+ } else if (TcpVersion == TCP_VERSION_6) {
+ ServiceBindingGuid = &gEfiTcp6ServiceBindingProtocolGuid;
+ ProtocolGuid = &gEfiTcp6ProtocolGuid;
+ Interface = (VOID **) (&TcpIo->Tcp.Tcp6);
+ } else {
+ return EFI_UNSUPPORTED;
+ }
+
+ TcpIo->TcpVersion = TcpVersion;
+
+ //
+ // Create the TCP child instance and get the TCP protocol.
+ //
+ Status = NetLibCreateServiceChild (
+ Controller,
+ Image,
+ ServiceBindingGuid,
+ &TcpIo->Handle
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gBS->OpenProtocol (
+ TcpIo->Handle,
+ ProtocolGuid,
+ Interface,
+ Image,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status) || (*Interface == NULL)) {
+ goto ON_ERROR;
+ }
+
+ if (TcpVersion == TCP_VERSION_4) {
+ Tcp4 = TcpIo->Tcp.Tcp4;
+ } else {
+ Tcp6 = TcpIo->Tcp.Tcp6;
+ }
+
+ TcpIo->Image = Image;
+ TcpIo->Controller = Controller;
+
+ //
+ // Set the configuration parameters.
+ //
+ ControlOption.ReceiveBufferSize = 0x200000;
+ ControlOption.SendBufferSize = 0x200000;
+ ControlOption.MaxSynBackLog = 0;
+ ControlOption.ConnectionTimeout = 0;
+ ControlOption.DataRetries = 6;
+ ControlOption.FinTimeout = 0;
+ ControlOption.TimeWaitTimeout = 0;
+ ControlOption.KeepAliveProbes = 4;
+ ControlOption.KeepAliveTime = 0;
+ ControlOption.KeepAliveInterval = 0;
+ ControlOption.EnableNagle = FALSE;
+ ControlOption.EnableTimeStamp = FALSE;
+ ControlOption.EnableWindowScaling = TRUE;
+ ControlOption.EnableSelectiveAck = FALSE;
+ ControlOption.EnablePathMtuDiscovery = FALSE;
+
+ if (TcpVersion == TCP_VERSION_4) {
+ Tcp4ConfigData.TypeOfService = 8;
+ Tcp4ConfigData.TimeToLive = 255;
+ Tcp4ConfigData.ControlOption = &ControlOption;
+
+ AccessPoint4 = &Tcp4ConfigData.AccessPoint;
+
+ ZeroMem (AccessPoint4, sizeof (EFI_TCP4_ACCESS_POINT));
+ AccessPoint4->StationPort = ConfigData->Tcp4IoConfigData.StationPort;
+ AccessPoint4->RemotePort = ConfigData->Tcp4IoConfigData.RemotePort;
+ AccessPoint4->ActiveFlag = ConfigData->Tcp4IoConfigData.ActiveFlag;
+
+ CopyMem (
+ &AccessPoint4->StationAddress,
+ &ConfigData->Tcp4IoConfigData.LocalIp,
+ sizeof (EFI_IPv4_ADDRESS)
+ );
+ CopyMem (
+ &AccessPoint4->SubnetMask,
+ &ConfigData->Tcp4IoConfigData.SubnetMask,
+ sizeof (EFI_IPv4_ADDRESS)
+ );
+ CopyMem (
+ &AccessPoint4->RemoteAddress,
+ &ConfigData->Tcp4IoConfigData.RemoteIp,
+ sizeof (EFI_IPv4_ADDRESS)
+ );
+
+ ASSERT (Tcp4 != NULL);
+
+ //
+ // Configure the TCP4 protocol.
+ //
+ Status = Tcp4->Configure (Tcp4, &Tcp4ConfigData);
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+
+ if (!EFI_IP4_EQUAL (&ConfigData->Tcp4IoConfigData.Gateway, &mZeroIp4Addr)) {
+ //
+ // The gateway is not zero. Add the default route manually.
+ //
+ Status = Tcp4->Routes (
+ Tcp4,
+ FALSE,
+ &mZeroIp4Addr,
+ &mZeroIp4Addr,
+ &ConfigData->Tcp4IoConfigData.Gateway
+ );
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+ }
+ } else {
+ Tcp6ConfigData.TrafficClass = 0;
+ Tcp6ConfigData.HopLimit = 255;
+ Tcp6ConfigData.ControlOption = (EFI_TCP6_OPTION *) &ControlOption;
+
+ AccessPoint6 = &Tcp6ConfigData.AccessPoint;
+
+ ZeroMem (AccessPoint6, sizeof (EFI_TCP6_ACCESS_POINT));
+ AccessPoint6->StationPort = ConfigData->Tcp6IoConfigData.StationPort;
+ AccessPoint6->RemotePort = ConfigData->Tcp6IoConfigData.RemotePort;
+ AccessPoint6->ActiveFlag = ConfigData->Tcp6IoConfigData.ActiveFlag;
+
+ IP6_COPY_ADDRESS (&AccessPoint6->RemoteAddress, &ConfigData->Tcp6IoConfigData.RemoteIp);
+
+
+ ASSERT (Tcp6 != NULL);
+ //
+ // Configure the TCP6 protocol.
+ //
+ Status = Tcp6->Configure (Tcp6, &Tcp6ConfigData);
+ if (Status == EFI_NO_MAPPING) {
+ Status = TcpIoGetMapping (Tcp6, &Tcp6ConfigData);
+ }
+
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+ }
+
+ //
+ // Create events for variuos asynchronous operations.
+ //
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ TcpIoCommonNotify,
+ &TcpIo->IsConnDone,
+ &Event
+ );
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+
+ TcpIo->ConnToken.Tcp4Token.CompletionToken.Event = Event;
+
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ TcpIoCommonNotify,
+ &TcpIo->IsListenDone,
+ &Event
+ );
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+
+ TcpIo->ListenToken.Tcp4Token.CompletionToken.Event = Event;
+
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ TcpIoCommonNotify,
+ &TcpIo->IsTxDone,
+ &Event
+ );
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+
+ TcpIo->TxToken.Tcp4Token.CompletionToken.Event = Event;
+
+
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ TcpIoCommonNotify,
+ &TcpIo->IsRxDone,
+ &Event
+ );
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+
+ TcpIo->RxToken.Tcp4Token.CompletionToken.Event = Event;
+
+ RxData = (EFI_TCP4_RECEIVE_DATA *) AllocateZeroPool (sizeof (EFI_TCP4_RECEIVE_DATA));
+ if (RxData == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_ERROR;
+ }
+
+ TcpIo->RxToken.Tcp4Token.Packet.RxData = RxData;
+
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ TcpIoCommonNotify,
+ &TcpIo->IsCloseDone,
+ &Event
+ );
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+
+ TcpIo->CloseToken.Tcp4Token.CompletionToken.Event = Event;
+
+
+ return EFI_SUCCESS;
+
+ON_ERROR:
+
+ TcpIoDestroySocket (TcpIo);
+
+ return Status;
+}
+
+/**
+ Destroy the socket.
+
+ @param[in] TcpIo The TcpIo which wraps the socket to be destroyed.
+
+**/
+VOID
+EFIAPI
+TcpIoDestroySocket (
+ IN TCP_IO *TcpIo
+ )
+{
+ EFI_EVENT Event;
+ EFI_TCP4_PROTOCOL *Tcp4;
+ EFI_TCP6_PROTOCOL *Tcp6;
+ UINT8 TcpVersion;
+ EFI_GUID *ServiceBindingGuid;
+ EFI_GUID *ProtocolGuid;
+ EFI_HANDLE ChildHandle;
+
+ if (TcpIo == NULL) {
+ return ;
+ }
+
+ TcpVersion = TcpIo->TcpVersion;
+
+ if ((TcpVersion != TCP_VERSION_4) && (TcpVersion != TCP_VERSION_6)) {
+ return ;
+ }
+
+ Event = TcpIo->ConnToken.Tcp4Token.CompletionToken.Event;
+
+ if (Event != NULL) {
+ gBS->CloseEvent (Event);
+ }
+
+ Event = TcpIo->ListenToken.Tcp4Token.CompletionToken.Event;
+
+ if (Event != NULL) {
+ gBS->CloseEvent (Event);
+ }
+
+ Event = TcpIo->TxToken.Tcp4Token.CompletionToken.Event;
+
+ if (Event != NULL) {
+ gBS->CloseEvent (Event);
+ }
+
+ Event = TcpIo->RxToken.Tcp4Token.CompletionToken.Event;
+
+ if (Event != NULL) {
+ gBS->CloseEvent (Event);
+ }
+
+ Event = TcpIo->CloseToken.Tcp4Token.CompletionToken.Event;
+
+ if (Event != NULL) {
+ gBS->CloseEvent (Event);
+ }
+
+ if (TcpIo->RxToken.Tcp4Token.Packet.RxData != NULL) {
+ FreePool (TcpIo->RxToken.Tcp4Token.Packet.RxData);
+ }
+
+ Tcp4 = NULL;
+ Tcp6 = NULL;
+
+
+ if (TcpVersion == TCP_VERSION_4) {
+ ServiceBindingGuid = &gEfiTcp4ServiceBindingProtocolGuid;
+ ProtocolGuid = &gEfiTcp4ProtocolGuid;
+ Tcp4 = TcpIo->Tcp.Tcp4;
+ if (Tcp4 != NULL) {
+ Tcp4->Configure (Tcp4, NULL);
+ }
+ } else {
+ ServiceBindingGuid = &gEfiTcp6ServiceBindingProtocolGuid;
+ ProtocolGuid = &gEfiTcp6ProtocolGuid;
+ Tcp6 = TcpIo->Tcp.Tcp6;
+ if (Tcp6 != NULL) {
+ Tcp6->Configure (Tcp6, NULL);
+ }
+ }
+
+ if ((Tcp4 != NULL) || (Tcp6 != NULL)) {
+
+ gBS->CloseProtocol (
+ TcpIo->Handle,
+ ProtocolGuid,
+ TcpIo->Image,
+ TcpIo->Controller
+ );
+ }
+
+ ChildHandle = NULL;
+
+ if (TcpIo->IsListenDone) {
+ if (TcpVersion == TCP_VERSION_4) {
+ Tcp4 = TcpIo->NewTcp.Tcp4;
+ if (Tcp4 != NULL) {
+ Tcp4->Configure (Tcp4, NULL);
+ ChildHandle = TcpIo->ListenToken.Tcp4Token.NewChildHandle;
+ }
+ } else {
+ Tcp6 = TcpIo->NewTcp.Tcp6;
+ if (Tcp6 != NULL) {
+ Tcp6->Configure (Tcp6, NULL);
+ ChildHandle = TcpIo->ListenToken.Tcp6Token.NewChildHandle;
+ }
+ }
+
+ if (ChildHandle != NULL) {
+
+ gBS->CloseProtocol (
+ ChildHandle,
+ ProtocolGuid,
+ TcpIo->Image,
+ TcpIo->Controller
+ );
+ }
+ }
+
+ NetLibDestroyServiceChild (
+ TcpIo->Controller,
+ TcpIo->Image,
+ ServiceBindingGuid,
+ TcpIo->Handle
+ );
+}
+
+/**
+ Connect to the other endpoint of the TCP socket.
+
+ @param[in, out] TcpIo The TcpIo wrapping the TCP socket.
+ @param[in] Timeout The time to wait for connection done.
+
+ @retval EFI_SUCCESS Connect to the other endpoint of the TCP socket
+ successfully.
+ @retval EFI_TIMEOUT Failed to connect to the other endpoint of the
+ TCP socket in the specified time period.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_UNSUPPORTED One or more of the control options are not
+ supported in the implementation.
+ @retval Others Other errors as indicated.
+
+**/
+EFI_STATUS
+EFIAPI
+TcpIoConnect (
+ IN OUT TCP_IO *TcpIo,
+ IN EFI_EVENT Timeout
+ )
+{
+ EFI_TCP4_PROTOCOL *Tcp4;
+ EFI_TCP6_PROTOCOL *Tcp6;
+ EFI_STATUS Status;
+
+ if ((TcpIo == NULL) || (TcpIo->Tcp.Tcp4 == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ TcpIo->IsConnDone = FALSE;
+
+ Tcp4 = NULL;
+ Tcp6 = NULL;
+
+ if (TcpIo->TcpVersion == TCP_VERSION_4) {
+ Tcp4 = TcpIo->Tcp.Tcp4;
+ Status = Tcp4->Connect (Tcp4, &TcpIo->ConnToken.Tcp4Token);
+ } else if (TcpIo->TcpVersion == TCP_VERSION_6) {
+ Tcp6 = TcpIo->Tcp.Tcp6;
+ Status = Tcp6->Connect (Tcp6, &TcpIo->ConnToken.Tcp6Token);
+ } else {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ while (!TcpIo->IsConnDone && EFI_ERROR (gBS->CheckEvent (Timeout))) {
+ if (TcpIo->TcpVersion == TCP_VERSION_4) {
+ Tcp4->Poll (Tcp4);
+ } else {
+ Tcp6->Poll (Tcp6);
+ }
+ }
+
+ if (!TcpIo->IsConnDone) {
+ Status = EFI_TIMEOUT;
+ } else {
+ Status = TcpIo->ConnToken.Tcp4Token.CompletionToken.Status;
+ }
+
+ return Status;
+}
+
+/**
+ Accept the incomding request from the other endpoint of the TCP socket.
+
+ @param[in, out] TcpIo The TcpIo wrapping the TCP socket.
+ @param[in] Timeout The time to wait for connection done.
+
+
+ @retval EFI_SUCCESS Connect to the other endpoint of the TCP socket
+ successfully.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_UNSUPPORTED One or more of the control options are not
+ supported in the implementation.
+
+ @retval EFI_TIMEOUT Failed to connect to the other endpoint of the
+ TCP socket in the specified time period.
+ @retval Others Other errors as indicated.
+
+**/
+EFI_STATUS
+EFIAPI
+TcpIoAccept (
+ IN OUT TCP_IO *TcpIo,
+ IN EFI_EVENT Timeout
+ )
+{
+ EFI_STATUS Status;
+ EFI_GUID *ProtocolGuid;
+ EFI_TCP4_PROTOCOL *Tcp4;
+ EFI_TCP6_PROTOCOL *Tcp6;
+
+ if ((TcpIo == NULL) || (TcpIo->Tcp.Tcp4 == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ TcpIo->IsListenDone = FALSE;
+
+ Tcp4 = NULL;
+ Tcp6 = NULL;
+
+ if (TcpIo->TcpVersion == TCP_VERSION_4) {
+ Tcp4 = TcpIo->Tcp.Tcp4;
+ Status = Tcp4->Accept (Tcp4, &TcpIo->ListenToken.Tcp4Token);
+ } else if (TcpIo->TcpVersion == TCP_VERSION_6) {
+ Tcp6 = TcpIo->Tcp.Tcp6;
+ Status = Tcp6->Accept (Tcp6, &TcpIo->ListenToken.Tcp6Token);
+ } else {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ while (!TcpIo->IsListenDone && EFI_ERROR (gBS->CheckEvent (Timeout))) {
+ if (TcpIo->TcpVersion == TCP_VERSION_4) {
+ Tcp4->Poll (Tcp4);
+ } else {
+ Tcp6->Poll (Tcp6);
+ }
+ }
+
+ if (!TcpIo->IsListenDone) {
+ Status = EFI_TIMEOUT;
+ } else {
+ Status = TcpIo->ListenToken.Tcp4Token.CompletionToken.Status;
+ }
+
+ //
+ // The new TCP instance handle created for the established connection is
+ // in ListenToken.
+ //
+ if (!EFI_ERROR (Status)) {
+ if (TcpIo->TcpVersion == TCP_VERSION_4) {
+ ProtocolGuid = &gEfiTcp4ProtocolGuid;
+ } else {
+ ProtocolGuid = &gEfiTcp6ProtocolGuid;
+ }
+
+ Status = gBS->OpenProtocol (
+ TcpIo->ListenToken.Tcp4Token.NewChildHandle,
+ ProtocolGuid,
+ (VOID **) (&TcpIo->NewTcp.Tcp4),
+ TcpIo->Image,
+ TcpIo->Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ }
+
+ return Status;
+}
+
+/**
+ Reset the socket.
+
+ @param[in, out] TcpIo The TcpIo wrapping the TCP socket.
+
+**/
+VOID
+EFIAPI
+TcpIoReset (
+ IN OUT TCP_IO *TcpIo
+ )
+{
+ EFI_TCP4_PROTOCOL *Tcp4;
+ EFI_TCP6_PROTOCOL *Tcp6;
+ EFI_STATUS Status;
+
+ if ((TcpIo == NULL) || (TcpIo->Tcp.Tcp4 == NULL)) {
+ return ;
+ }
+
+ TcpIo->IsCloseDone = FALSE;
+ Tcp4 = NULL;
+ Tcp6 = NULL;
+
+ if (TcpIo->TcpVersion == TCP_VERSION_4) {
+ TcpIo->CloseToken.Tcp4Token.AbortOnClose = TRUE;
+ Tcp4 = TcpIo->Tcp.Tcp4;
+ Status = Tcp4->Close (Tcp4, &TcpIo->CloseToken.Tcp4Token);
+ } else if (TcpIo->TcpVersion == TCP_VERSION_6) {
+ TcpIo->CloseToken.Tcp6Token.AbortOnClose = TRUE;
+ Tcp6 = TcpIo->Tcp.Tcp6;
+ Status = Tcp6->Close (Tcp6, &TcpIo->CloseToken.Tcp6Token);
+ } else {
+ return ;
+ }
+
+ if (EFI_ERROR (Status)) {
+ return ;
+ }
+
+ while (!TcpIo->IsCloseDone) {
+ if (TcpIo->TcpVersion == TCP_VERSION_4) {
+ Tcp4->Poll (Tcp4);
+ } else {
+ Tcp6->Poll (Tcp6);
+ }
+ }
+}
+
+
+/**
+ Transmit the Packet to the other endpoint of the socket.
+
+ @param[in] TcpIo The TcpIo wrapping the TCP socket.
+ @param[in] Packet The packet to transmit.
+
+ @retval EFI_SUCCESS The packet is trasmitted.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_UNSUPPORTED One or more of the control options are not
+ supported in the implementation.
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
+ @retval EFI_DEVICE_ERROR An unexpected network or system error occurred.
+ @retval Others Other errors as indicated.
+
+**/
+EFI_STATUS
+EFIAPI
+TcpIoTransmit (
+ IN TCP_IO *TcpIo,
+ IN NET_BUF *Packet
+ )
+{
+ EFI_STATUS Status;
+ VOID *Data;
+ EFI_TCP4_PROTOCOL *Tcp4;
+ EFI_TCP6_PROTOCOL *Tcp6;
+ UINTN Size;
+
+ if ((TcpIo == NULL) || (TcpIo->Tcp.Tcp4 == NULL)|| (Packet == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (TcpIo->TcpVersion == TCP_VERSION_4) {
+
+ Size = sizeof (EFI_TCP4_TRANSMIT_DATA) +
+ (Packet->BlockOpNum - 1) * sizeof (EFI_TCP4_FRAGMENT_DATA);
+ } else if (TcpIo->TcpVersion == TCP_VERSION_6) {
+ Size = sizeof (EFI_TCP6_TRANSMIT_DATA) +
+ (Packet->BlockOpNum - 1) * sizeof (EFI_TCP6_FRAGMENT_DATA);
+ } else {
+ return EFI_UNSUPPORTED;
+ }
+
+ Data = AllocatePool (Size);
+ if (Data == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ ((EFI_TCP4_TRANSMIT_DATA *) Data)->Push = TRUE;
+ ((EFI_TCP4_TRANSMIT_DATA *) Data)->Urgent = FALSE;
+ ((EFI_TCP4_TRANSMIT_DATA *) Data)->DataLength = Packet->TotalSize;
+
+ //
+ // Build the fragment table.
+ //
+ ((EFI_TCP4_TRANSMIT_DATA *) Data)->FragmentCount = Packet->BlockOpNum;
+
+ NetbufBuildExt (
+ Packet,
+ (NET_FRAGMENT *) &((EFI_TCP4_TRANSMIT_DATA *) Data)->FragmentTable[0],
+ &((EFI_TCP4_TRANSMIT_DATA *) Data)->FragmentCount
+ );
+
+ Tcp4 = NULL;
+ Tcp6 = NULL;
+ Status = EFI_DEVICE_ERROR;
+
+ //
+ // Trasnmit the packet.
+ //
+ if (TcpIo->TcpVersion == TCP_VERSION_4) {
+ TcpIo->TxToken.Tcp4Token.Packet.TxData = (EFI_TCP4_TRANSMIT_DATA *) Data;
+ Tcp4 = TcpIo->Tcp.Tcp4;
+ if (TcpIo->IsListenDone) {
+ Tcp4 = TcpIo->NewTcp.Tcp4;
+ }
+
+ if (Tcp4 == NULL) {
+ goto ON_EXIT;
+ }
+
+ Status = Tcp4->Transmit (Tcp4, &TcpIo->TxToken.Tcp4Token);
+ } else {
+ TcpIo->TxToken.Tcp6Token.Packet.TxData = (EFI_TCP6_TRANSMIT_DATA *) Data;
+ Tcp6 = TcpIo->Tcp.Tcp6;
+ if (TcpIo->IsListenDone) {
+ Tcp6 = TcpIo->NewTcp.Tcp6;
+ }
+
+ if (Tcp6 == NULL) {
+ goto ON_EXIT;
+ }
+
+ Status = Tcp6->Transmit (Tcp6, &TcpIo->TxToken.Tcp6Token);
+ }
+
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+
+ while (!TcpIo->IsTxDone) {
+ if (TcpIo->TcpVersion == TCP_VERSION_4) {
+ Tcp4->Poll (Tcp4);
+ } else {
+ Tcp6->Poll (Tcp6);
+ }
+ }
+
+ TcpIo->IsTxDone = FALSE;
+ Status = TcpIo->TxToken.Tcp4Token.CompletionToken.Status;
+
+ON_EXIT:
+
+ FreePool (Data);
+
+ return Status;
+}
+
+/**
+ Receive data from the socket.
+
+ @param[in, out] TcpIo The TcpIo which wraps the socket to be destroyed.
+ @param[in] Packet The buffer to hold the data copy from the socket rx buffer.
+ @param[in] AsyncMode Is this receive asyncronous or not.
+ @param[in] Timeout The time to wait for receiving the amount of data the Packet
+ can hold.
+
+ @retval EFI_SUCCESS The required amount of data is received from the socket.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_DEVICE_ERROR An unexpected network or system error occurred.
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate momery.
+ @retval EFI_TIMEOUT Failed to receive the required amount of data in the
+ specified time period.
+ @retval Others Other errors as indicated.
+
+**/
+EFI_STATUS
+EFIAPI
+TcpIoReceive (
+ IN OUT TCP_IO *TcpIo,
+ IN NET_BUF *Packet,
+ IN BOOLEAN AsyncMode,
+ IN EFI_EVENT Timeout
+ )
+{
+ EFI_TCP4_PROTOCOL *Tcp4;
+ EFI_TCP6_PROTOCOL *Tcp6;
+ EFI_TCP4_RECEIVE_DATA *RxData;
+ EFI_STATUS Status;
+ NET_FRAGMENT *Fragment;
+ UINT32 FragmentCount;
+ UINT32 CurrentFragment;
+
+ if ((TcpIo == NULL) || (TcpIo->Tcp.Tcp4 == NULL)|| (Packet == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ RxData = TcpIo->RxToken.Tcp4Token.Packet.RxData;
+ if (RxData == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Tcp4 = NULL;
+ Tcp6 = NULL;
+
+ if (TcpIo->TcpVersion == TCP_VERSION_4) {
+ Tcp4 = TcpIo->Tcp.Tcp4;
+
+ if (TcpIo->IsListenDone) {
+ Tcp4 = TcpIo->NewTcp.Tcp4;
+ }
+
+ if (Tcp4 == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ } else if (TcpIo->TcpVersion == TCP_VERSION_6) {
+ Tcp6 = TcpIo->Tcp.Tcp6;
+
+ if (TcpIo->IsListenDone) {
+ Tcp6 = TcpIo->NewTcp.Tcp6;
+ }
+
+ if (Tcp6 == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ } else {
+ return EFI_UNSUPPORTED;
+ }
+
+ FragmentCount = Packet->BlockOpNum;
+ Fragment = AllocatePool (FragmentCount * sizeof (NET_FRAGMENT));
+ if (Fragment == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_EXIT;
+ }
+ //
+ // Build the fragment table.
+ //
+ NetbufBuildExt (Packet, Fragment, &FragmentCount);
+
+ RxData->FragmentCount = 1;
+ CurrentFragment = 0;
+ Status = EFI_SUCCESS;
+
+ while (CurrentFragment < FragmentCount) {
+ RxData->DataLength = Fragment[CurrentFragment].Len;
+ RxData->FragmentTable[0].FragmentLength = Fragment[CurrentFragment].Len;
+ RxData->FragmentTable[0].FragmentBuffer = Fragment[CurrentFragment].Bulk;
+
+ if (TcpIo->TcpVersion == TCP_VERSION_4) {
+ Status = Tcp4->Receive (Tcp4, &TcpIo->RxToken.Tcp4Token);
+ } else {
+ Status = Tcp6->Receive (Tcp6, &TcpIo->RxToken.Tcp6Token);
+ }
+
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+
+ while (!TcpIo->IsRxDone && ((Timeout == NULL) || EFI_ERROR (gBS->CheckEvent (Timeout)))) {
+ //
+ // Poll until some data is received or an error occurs.
+ //
+ if (TcpIo->TcpVersion == TCP_VERSION_4) {
+ Tcp4->Poll (Tcp4);
+ } else {
+ Tcp6->Poll (Tcp6);
+ }
+ }
+
+ if (!TcpIo->IsRxDone) {
+ //
+ // Timeout occurs, cancel the receive request.
+ //
+ if (TcpIo->TcpVersion == TCP_VERSION_4) {
+ Tcp4->Cancel (Tcp4, &TcpIo->RxToken.Tcp4Token.CompletionToken);
+ } else {
+ Tcp6->Cancel (Tcp6, &TcpIo->RxToken.Tcp6Token.CompletionToken);
+ }
+
+ Status = EFI_TIMEOUT;
+ goto ON_EXIT;
+ } else {
+ TcpIo->IsRxDone = FALSE;
+ }
+
+ Status = TcpIo->RxToken.Tcp4Token.CompletionToken.Status;
+
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+
+ Fragment[CurrentFragment].Len -= RxData->FragmentTable[0].FragmentLength;
+ if (Fragment[CurrentFragment].Len == 0) {
+ CurrentFragment++;
+ } else {
+ Fragment[CurrentFragment].Bulk += RxData->FragmentTable[0].FragmentLength;
+ }
+ }
+
+ON_EXIT:
+
+ if (Fragment != NULL) {
+ FreePool (Fragment);
+ }
+
+ return Status;
+}
diff --git a/Core/MdeModulePkg/Library/DxeTcpIoLib/DxeTcpIoLib.inf b/Core/MdeModulePkg/Library/DxeTcpIoLib/DxeTcpIoLib.inf
new file mode 100644
index 0000000000..4f11c6f0c8
--- /dev/null
+++ b/Core/MdeModulePkg/Library/DxeTcpIoLib/DxeTcpIoLib.inf
@@ -0,0 +1,51 @@
+## @file
+# This library instance provides TCP services by EFI TCPv4/TCPv6 Protocols.
+#
+# Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxeTcpIoLib
+ MODULE_UNI_FILE = DxeTcpIoLib.uni
+ FILE_GUID = D4608509-1AB0-4cc7-827A-AB8E1E7BD3E6
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = TcpIoLib|DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SAL_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ DxeTcpIoLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+
+[LibraryClasses]
+ TcpIoLib
+ BaseLib
+ DebugLib
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ BaseMemoryLib
+
+[Protocols]
+ gEfiTcp4ServiceBindingProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiTcp4ProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiTcp6ServiceBindingProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiTcp6ProtocolGuid ## SOMETIMES_CONSUMES
diff --git a/Core/MdeModulePkg/Library/DxeTcpIoLib/DxeTcpIoLib.uni b/Core/MdeModulePkg/Library/DxeTcpIoLib/DxeTcpIoLib.uni
new file mode 100644
index 0000000000..064d9e59b6
--- /dev/null
+++ b/Core/MdeModulePkg/Library/DxeTcpIoLib/DxeTcpIoLib.uni
Binary files differ
diff --git a/Core/MdeModulePkg/Library/DxeUdpIoLib/DxeUdpIoLib.c b/Core/MdeModulePkg/Library/DxeUdpIoLib/DxeUdpIoLib.c
new file mode 100644
index 0000000000..e1d72f3f1c
--- /dev/null
+++ b/Core/MdeModulePkg/Library/DxeUdpIoLib/DxeUdpIoLib.c
@@ -0,0 +1,1067 @@
+/** @file
+ Help functions to access UDP service, it is used by both the DHCP and MTFTP.
+
+Copyright (c) 2005 - 2012, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at<BR>
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+**/
+
+#include <Uefi.h>
+
+#include <Protocol/Udp4.h>
+#include <Protocol/Udp6.h>
+
+#include <Library/UdpIoLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DpcLib.h>
+
+
+/**
+ Free a UDP_TX_TOKEN. The TX event is closed.
+
+ @param[in] TxToken The UDP_TX_TOKEN to release.
+
+**/
+VOID
+UdpIoFreeTxToken (
+ IN UDP_TX_TOKEN *TxToken
+ )
+{
+
+ if (TxToken->UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
+ gBS->CloseEvent (TxToken->Token.Udp4.Event);
+ } else if (TxToken->UdpIo->UdpVersion == UDP_IO_UDP6_VERSION) {
+ gBS->CloseEvent (TxToken->Token.Udp6.Event);
+ } else {
+ ASSERT (FALSE);
+ }
+
+ FreePool (TxToken);
+}
+
+/**
+ Free a UDP_RX_TOKEN. The RX event is closed.
+
+ @param[in] RxToken The UDP_RX_TOKEN to release.
+
+**/
+VOID
+UdpIoFreeRxToken (
+ IN UDP_RX_TOKEN *RxToken
+ )
+{
+ if (RxToken->UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
+ gBS->CloseEvent (RxToken->Token.Udp4.Event);
+ } else if (RxToken->UdpIo->UdpVersion == UDP_IO_UDP6_VERSION) {
+ gBS->CloseEvent (RxToken->Token.Udp6.Event);
+ } else {
+ ASSERT (FALSE);
+ }
+
+ FreePool (RxToken);
+}
+
+/**
+ The callback function when the packet is sent by UDP.
+
+ It will remove the packet from the local list then call
+ the packet owner's callback function set by UdpIoSendDatagram.
+
+ @param[in] Context The UDP TX Token.
+
+**/
+VOID
+EFIAPI
+UdpIoOnDgramSentDpc (
+ IN VOID *Context
+ )
+{
+ UDP_TX_TOKEN *TxToken;
+
+ TxToken = (UDP_TX_TOKEN *) Context;
+ ASSERT (TxToken->Signature == UDP_IO_TX_SIGNATURE);
+ ASSERT ((TxToken->UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) ||
+ (TxToken->UdpIo->UdpVersion == UDP_IO_UDP6_VERSION));
+
+ RemoveEntryList (&TxToken->Link);
+
+ if (TxToken->UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
+ TxToken->CallBack (TxToken->Packet, NULL, TxToken->Token.Udp4.Status, TxToken->Context);
+ } else {
+ TxToken->CallBack (TxToken->Packet, NULL, TxToken->Token.Udp6.Status, TxToken->Context);
+ }
+
+ UdpIoFreeTxToken (TxToken);
+}
+
+/**
+ Request UdpIoOnDgramSentDpc as a DPC at TPL_CALLBACK.
+
+ @param[in] Event The event signaled.
+ @param[in] Context The UDP TX Token.
+
+**/
+VOID
+EFIAPI
+UdpIoOnDgramSent (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ //
+ // Request UdpIoOnDgramSentDpc as a DPC at TPL_CALLBACK
+ //
+ QueueDpc (TPL_CALLBACK, UdpIoOnDgramSentDpc, Context);
+}
+
+/**
+ Recycle the received UDP data.
+
+ @param[in] Context The UDP_RX_TOKEN.
+
+**/
+VOID
+EFIAPI
+UdpIoRecycleDgram (
+ IN VOID *Context
+ )
+{
+ UDP_RX_TOKEN *RxToken;
+
+ RxToken = (UDP_RX_TOKEN *) Context;
+
+ if (RxToken->UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
+ gBS->SignalEvent (RxToken->Token.Udp4.Packet.RxData->RecycleSignal);
+ } else if (RxToken->UdpIo->UdpVersion == UDP_IO_UDP6_VERSION) {
+ gBS->SignalEvent (RxToken->Token.Udp6.Packet.RxData->RecycleSignal);
+ } else {
+ ASSERT (FALSE);
+ }
+
+ UdpIoFreeRxToken (RxToken);
+}
+
+/**
+ The event handle for UDP receive request.
+
+ It will build a NET_BUF from the recieved UDP data, then deliver it
+ to the receiver.
+
+ @param[in] Context The UDP RX token.
+
+**/
+VOID
+EFIAPI
+UdpIoOnDgramRcvdDpc (
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ VOID *Token;
+ VOID *RxData;
+ VOID *Session;
+ UDP_RX_TOKEN *RxToken;
+ UDP_END_POINT EndPoint;
+ NET_BUF *Netbuf;
+
+ RxToken = (UDP_RX_TOKEN *) Context;
+
+ ZeroMem (&EndPoint, sizeof(UDP_END_POINT));
+
+ ASSERT ((RxToken->Signature == UDP_IO_RX_SIGNATURE) &&
+ (RxToken == RxToken->UdpIo->RecvRequest));
+
+ ASSERT ((RxToken->UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) ||
+ (RxToken->UdpIo->UdpVersion == UDP_IO_UDP6_VERSION));
+
+ //
+ // Clear the receive request first in case that the caller
+ // wants to restart the receive in the callback.
+ //
+ RxToken->UdpIo->RecvRequest = NULL;
+
+ if (RxToken->UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
+ Token = &RxToken->Token.Udp4;
+ RxData = ((EFI_UDP4_COMPLETION_TOKEN *) Token)->Packet.RxData;
+ Status = ((EFI_UDP4_COMPLETION_TOKEN *) Token)->Status;
+ } else {
+ Token = &RxToken->Token.Udp6;
+ RxData = ((EFI_UDP6_COMPLETION_TOKEN *) Token)->Packet.RxData;
+ Status = ((EFI_UDP6_COMPLETION_TOKEN *) Token)->Status;
+ }
+
+ if (EFI_ERROR (Status) || RxData == NULL) {
+ if (Status != EFI_ABORTED) {
+ //
+ // Invoke the CallBack only if the reception is not actively aborted.
+ //
+ RxToken->CallBack (NULL, NULL, Status, RxToken->Context);
+ }
+
+ UdpIoFreeRxToken (RxToken);
+ return;
+ }
+
+ //
+ // Build a NET_BUF from the UDP receive data, then deliver it up.
+ //
+ if (RxToken->UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
+
+ Netbuf = NetbufFromExt (
+ (NET_FRAGMENT *)((EFI_UDP4_RECEIVE_DATA *) RxData)->FragmentTable,
+ ((EFI_UDP4_RECEIVE_DATA *) RxData)->FragmentCount,
+ 0,
+ (UINT32) RxToken->HeadLen,
+ UdpIoRecycleDgram,
+ RxToken
+ );
+
+ if (Netbuf == NULL) {
+ gBS->SignalEvent (((EFI_UDP4_RECEIVE_DATA *) RxData)->RecycleSignal);
+ RxToken->CallBack (NULL, NULL, EFI_OUT_OF_RESOURCES, RxToken->Context);
+
+ UdpIoFreeRxToken (RxToken);
+ return;
+ }
+
+ Session = &((EFI_UDP4_RECEIVE_DATA *) RxData)->UdpSession;
+ EndPoint.LocalPort = ((EFI_UDP4_SESSION_DATA *) Session)->DestinationPort;
+ EndPoint.RemotePort = ((EFI_UDP4_SESSION_DATA *) Session)->SourcePort;
+
+ CopyMem (
+ &EndPoint.LocalAddr,
+ &((EFI_UDP4_SESSION_DATA *) Session)->DestinationAddress,
+ sizeof (EFI_IPv4_ADDRESS)
+ );
+
+ CopyMem (
+ &EndPoint.RemoteAddr,
+ &((EFI_UDP4_SESSION_DATA *) Session)->SourceAddress,
+ sizeof (EFI_IPv4_ADDRESS)
+ );
+
+ EndPoint.LocalAddr.Addr[0] = NTOHL (EndPoint.LocalAddr.Addr[0]);
+ EndPoint.RemoteAddr.Addr[0] = NTOHL (EndPoint.RemoteAddr.Addr[0]);
+ } else {
+
+ Netbuf = NetbufFromExt (
+ (NET_FRAGMENT *)((EFI_UDP6_RECEIVE_DATA *) RxData)->FragmentTable,
+ ((EFI_UDP6_RECEIVE_DATA *) RxData)->FragmentCount,
+ 0,
+ (UINT32) RxToken->HeadLen,
+ UdpIoRecycleDgram,
+ RxToken
+ );
+
+ if (Netbuf == NULL) {
+ gBS->SignalEvent (((EFI_UDP6_RECEIVE_DATA *) RxData)->RecycleSignal);
+ RxToken->CallBack (NULL, NULL, EFI_OUT_OF_RESOURCES, RxToken->Context);
+
+ UdpIoFreeRxToken (RxToken);
+ return;
+ }
+
+ Session = &((EFI_UDP6_RECEIVE_DATA *) RxData)->UdpSession;
+ EndPoint.LocalPort = ((EFI_UDP6_SESSION_DATA *) Session)->DestinationPort;
+ EndPoint.RemotePort = ((EFI_UDP6_SESSION_DATA *) Session)->SourcePort;
+
+ CopyMem (
+ &EndPoint.LocalAddr,
+ &((EFI_UDP6_SESSION_DATA *) Session)->DestinationAddress,
+ sizeof (EFI_IPv6_ADDRESS)
+ );
+
+ CopyMem (
+ &EndPoint.RemoteAddr,
+ &((EFI_UDP6_SESSION_DATA *) Session)->SourceAddress,
+ sizeof (EFI_IPv6_ADDRESS)
+ );
+
+ Ip6Swap128 (&EndPoint.LocalAddr.v6);
+ Ip6Swap128 (&EndPoint.RemoteAddr.v6);
+ }
+
+ RxToken->CallBack (Netbuf, &EndPoint, EFI_SUCCESS, RxToken->Context);
+}
+
+/**
+ Request UdpIoOnDgramRcvdDpc() as a DPC at TPL_CALLBACK.
+
+ @param[in] Event The UDP receive request event.
+ @param[in] Context The UDP RX token.
+
+**/
+VOID
+EFIAPI
+UdpIoOnDgramRcvd (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ //
+ // Request UdpIoOnDgramRcvdDpc as a DPC at TPL_CALLBACK
+ //
+ QueueDpc (TPL_CALLBACK, UdpIoOnDgramRcvdDpc, Context);
+}
+
+/**
+ Create a UDP_RX_TOKEN to wrap the request.
+
+ @param[in] UdpIo The UdpIo to receive packets from.
+ @param[in] CallBack The function to call when receive finished.
+ @param[in] Context The opaque parameter to the CallBack.
+ @param[in] HeadLen The head length to reserver for the packet.
+
+ @return The Wrapped request or NULL if failed to allocate resources or some errors happened.
+
+**/
+UDP_RX_TOKEN *
+UdpIoCreateRxToken (
+ IN UDP_IO *UdpIo,
+ IN UDP_IO_CALLBACK CallBack,
+ IN VOID *Context,
+ IN UINT32 HeadLen
+ )
+{
+ UDP_RX_TOKEN *Token;
+ EFI_STATUS Status;
+
+ ASSERT ((UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) ||
+ (UdpIo->UdpVersion == UDP_IO_UDP6_VERSION));
+
+ Token = AllocatePool (sizeof (UDP_RX_TOKEN));
+
+ if (Token == NULL) {
+ return NULL;
+ }
+
+ Token->Signature = UDP_IO_RX_SIGNATURE;
+ Token->UdpIo = UdpIo;
+ Token->CallBack = CallBack;
+ Token->Context = Context;
+ Token->HeadLen = HeadLen;
+
+ if (UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
+
+ Token->Token.Udp4.Status = EFI_NOT_READY;
+ Token->Token.Udp4.Packet.RxData = NULL;
+
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ UdpIoOnDgramRcvd,
+ Token,
+ &Token->Token.Udp4.Event
+ );
+ } else {
+
+ Token->Token.Udp6.Status = EFI_NOT_READY;
+ Token->Token.Udp6.Packet.RxData = NULL;
+
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ UdpIoOnDgramRcvd,
+ Token,
+ &Token->Token.Udp6.Event
+ );
+ }
+
+
+ if (EFI_ERROR (Status)) {
+ FreePool (Token);
+ return NULL;
+ }
+
+ return Token;
+}
+
+/**
+ Wrap a transmit request into a new created UDP_TX_TOKEN.
+
+ @param[in] UdpIo The UdpIo to send packet to.
+ @param[in] Packet The user's packet.
+ @param[in] EndPoint The local and remote access point.
+ @param[in] Gateway The overrided next hop.
+ @param[in] CallBack The function to call when transmission completed.
+ @param[in] Context The opaque parameter to the call back.
+
+ @return The wrapped transmission request or NULL if failed to allocate resources
+ or for some errors.
+
+**/
+UDP_TX_TOKEN *
+UdpIoCreateTxToken (
+ IN UDP_IO *UdpIo,
+ IN NET_BUF *Packet,
+ IN UDP_END_POINT *EndPoint OPTIONAL,
+ IN EFI_IP_ADDRESS *Gateway OPTIONAL,
+ IN UDP_IO_CALLBACK CallBack,
+ IN VOID *Context
+ )
+{
+ UDP_TX_TOKEN *TxToken;
+ VOID *Token;
+ VOID *Data;
+ EFI_STATUS Status;
+ UINT32 Count;
+ UINTN Size;
+ IP4_ADDR Ip;
+
+ ASSERT (Packet != NULL);
+ ASSERT ((UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) ||
+ (UdpIo->UdpVersion == UDP_IO_UDP6_VERSION));
+
+ if (UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
+ Size = sizeof (UDP_TX_TOKEN) + sizeof (EFI_UDP4_FRAGMENT_DATA) * (Packet->BlockOpNum - 1);
+ } else {
+ Size = sizeof (UDP_TX_TOKEN) + sizeof (EFI_UDP6_FRAGMENT_DATA) * (Packet->BlockOpNum - 1);
+ }
+
+ TxToken = AllocatePool (Size);
+
+ if (TxToken == NULL) {
+ return NULL;
+ }
+
+ TxToken->Signature = UDP_IO_TX_SIGNATURE;
+ InitializeListHead (&TxToken->Link);
+
+ TxToken->UdpIo = UdpIo;
+ TxToken->CallBack = CallBack;
+ TxToken->Packet = Packet;
+ TxToken->Context = Context;
+
+ Token = &(TxToken->Token);
+ Count = Packet->BlockOpNum;
+
+ if (UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
+
+ ((EFI_UDP4_COMPLETION_TOKEN *) Token)->Status = EFI_NOT_READY;
+
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ UdpIoOnDgramSent,
+ TxToken,
+ &((EFI_UDP4_COMPLETION_TOKEN *) Token)->Event
+ );
+
+ if (EFI_ERROR (Status)) {
+ FreePool (TxToken);
+ return NULL;
+ }
+
+ Data = &(TxToken->Data.Udp4);
+ ((EFI_UDP4_COMPLETION_TOKEN *) Token)->Packet.TxData = Data;
+
+ ((EFI_UDP4_TRANSMIT_DATA *) Data)->UdpSessionData = NULL;
+ ((EFI_UDP4_TRANSMIT_DATA *) Data)->GatewayAddress = NULL;
+ ((EFI_UDP4_TRANSMIT_DATA *) Data)->DataLength = Packet->TotalSize;
+
+ NetbufBuildExt (
+ Packet,
+ (NET_FRAGMENT *)((EFI_UDP4_TRANSMIT_DATA *) Data)->FragmentTable,
+ &Count
+ );
+
+ ((EFI_UDP4_TRANSMIT_DATA *) Data)->FragmentCount = Count;
+
+ if (EndPoint != NULL) {
+ Ip = HTONL (EndPoint->LocalAddr.Addr[0]);
+ CopyMem (
+ &TxToken->Session.Udp4.SourceAddress,
+ &Ip,
+ sizeof (EFI_IPv4_ADDRESS)
+ );
+
+ Ip = HTONL (EndPoint->RemoteAddr.Addr[0]);
+ CopyMem (
+ &TxToken->Session.Udp4.DestinationAddress,
+ &Ip,
+ sizeof (EFI_IPv4_ADDRESS)
+ );
+
+ TxToken->Session.Udp4.SourcePort = EndPoint->LocalPort;
+ TxToken->Session.Udp4.DestinationPort = EndPoint->RemotePort;
+ ((EFI_UDP4_TRANSMIT_DATA *) Data)->UdpSessionData = &(TxToken->Session.Udp4);
+ }
+
+ if (Gateway != NULL && (Gateway->Addr[0] != 0)) {
+ Ip = HTONL (Gateway->Addr[0]);
+ CopyMem (&TxToken->Gateway, &Ip, sizeof (EFI_IPv4_ADDRESS));
+ ((EFI_UDP4_TRANSMIT_DATA *) Data)->GatewayAddress = &TxToken->Gateway;
+ }
+
+ } else {
+
+ ((EFI_UDP6_COMPLETION_TOKEN *) Token)->Status = EFI_NOT_READY;
+
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ UdpIoOnDgramSent,
+ TxToken,
+ &((EFI_UDP6_COMPLETION_TOKEN *) Token)->Event
+ );
+
+ if (EFI_ERROR (Status)) {
+ FreePool (TxToken);
+ return NULL;
+ }
+
+ Data = &(TxToken->Data.Udp6);
+ ((EFI_UDP6_COMPLETION_TOKEN *) Token)->Packet.TxData = Data;
+ ((EFI_UDP6_TRANSMIT_DATA *) Data)->UdpSessionData = NULL;
+ ((EFI_UDP6_TRANSMIT_DATA *) Data)->DataLength = Packet->TotalSize;
+
+ NetbufBuildExt (
+ Packet,
+ (NET_FRAGMENT *)((EFI_UDP6_TRANSMIT_DATA *) Data)->FragmentTable,
+ &Count
+ );
+
+ ((EFI_UDP6_TRANSMIT_DATA *) Data)->FragmentCount = Count;
+
+ if (EndPoint != NULL) {
+ CopyMem (
+ &TxToken->Session.Udp6.SourceAddress,
+ &EndPoint->LocalAddr.v6,
+ sizeof(EFI_IPv6_ADDRESS)
+ );
+
+ CopyMem (
+ &TxToken->Session.Udp6.DestinationAddress,
+ &EndPoint->RemoteAddr.v6,
+ sizeof(EFI_IPv6_ADDRESS)
+ );
+
+ TxToken->Session.Udp6.SourcePort = EndPoint->LocalPort;
+ TxToken->Session.Udp6.DestinationPort = EndPoint->RemotePort;
+ ((EFI_UDP6_TRANSMIT_DATA *) Data)->UdpSessionData = &(TxToken->Session.Udp6);
+ }
+ }
+
+ return TxToken;
+}
+
+/**
+ Creates a UDP_IO to access the UDP service. It creates and configures
+ a UDP child.
+
+ It locates the UDP service binding prototype on the Controller parameter
+ uses the UDP service binding prototype to create a UDP child (also known as
+ a UDP instance) configures the UDP child by calling Configure function prototype.
+ Any failures in creating or configuring the UDP child return NULL for failure.
+
+ @param[in] Controller The controller that has the UDP service binding.
+ protocol installed.
+ @param[in] ImageHandle The image handle for the driver.
+ @param[in] Configure The function to configure the created UDP child.
+ @param[in] UdpVersion The UDP protocol version, UDP4 or UDP6.
+ @param[in] Context The opaque parameter for the Configure funtion.
+
+ @return Newly-created UDP_IO or NULL if failed.
+
+**/
+UDP_IO *
+EFIAPI
+UdpIoCreateIo (
+ IN EFI_HANDLE Controller,
+ IN EFI_HANDLE ImageHandle,
+ IN UDP_IO_CONFIG Configure,
+ IN UINT8 UdpVersion,
+ IN VOID *Context
+ )
+{
+ UDP_IO *UdpIo;
+ EFI_STATUS Status;
+
+ ASSERT (Configure != NULL);
+ ASSERT ((UdpVersion == UDP_IO_UDP4_VERSION) || (UdpVersion == UDP_IO_UDP6_VERSION));
+
+ UdpIo = AllocatePool (sizeof (UDP_IO));
+
+ if (UdpIo == NULL) {
+ return NULL;
+ }
+
+ UdpIo->UdpVersion = UdpVersion;
+ UdpIo->Signature = UDP_IO_SIGNATURE;
+ InitializeListHead (&UdpIo->Link);
+ UdpIo->RefCnt = 1;
+
+ UdpIo->Controller = Controller;
+ UdpIo->Image = ImageHandle;
+
+ InitializeListHead (&UdpIo->SentDatagram);
+ UdpIo->RecvRequest = NULL;
+ UdpIo->UdpHandle = NULL;
+
+ if (UdpVersion == UDP_IO_UDP4_VERSION) {
+ //
+ // Create a UDP child then open and configure it
+ //
+ Status = NetLibCreateServiceChild (
+ Controller,
+ ImageHandle,
+ &gEfiUdp4ServiceBindingProtocolGuid,
+ &UdpIo->UdpHandle
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto FREE_MEM;
+ }
+
+ Status = gBS->OpenProtocol (
+ UdpIo->UdpHandle,
+ &gEfiUdp4ProtocolGuid,
+ (VOID **) &UdpIo->Protocol.Udp4,
+ ImageHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto FREE_CHILD;
+ }
+
+ if (EFI_ERROR (Configure (UdpIo, Context))) {
+ goto CLOSE_PROTOCOL;
+ }
+
+ Status = UdpIo->Protocol.Udp4->GetModeData (
+ UdpIo->Protocol.Udp4,
+ NULL,
+ NULL,
+ NULL,
+ &UdpIo->SnpMode
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto CLOSE_PROTOCOL;
+ }
+
+ } else {
+
+ Status = NetLibCreateServiceChild (
+ Controller,
+ ImageHandle,
+ &gEfiUdp6ServiceBindingProtocolGuid,
+ &UdpIo->UdpHandle
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto FREE_MEM;
+ }
+
+ Status = gBS->OpenProtocol (
+ UdpIo->UdpHandle,
+ &gEfiUdp6ProtocolGuid,
+ (VOID **) &UdpIo->Protocol.Udp6,
+ ImageHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto FREE_CHILD;
+ }
+
+ if (EFI_ERROR (Configure (UdpIo, Context))) {
+ goto CLOSE_PROTOCOL;
+ }
+
+ Status = UdpIo->Protocol.Udp6->GetModeData (
+ UdpIo->Protocol.Udp6,
+ NULL,
+ NULL,
+ NULL,
+ &UdpIo->SnpMode
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto CLOSE_PROTOCOL;
+ }
+ }
+
+ return UdpIo;
+
+CLOSE_PROTOCOL:
+ if (UdpVersion == UDP_IO_UDP4_VERSION) {
+ gBS->CloseProtocol (UdpIo->UdpHandle, &gEfiUdp4ProtocolGuid, ImageHandle, Controller);
+ } else {
+ gBS->CloseProtocol (UdpIo->UdpHandle, &gEfiUdp6ProtocolGuid, ImageHandle, Controller);
+ }
+
+FREE_CHILD:
+ if (UdpVersion == UDP_IO_UDP4_VERSION) {
+ NetLibDestroyServiceChild (
+ Controller,
+ ImageHandle,
+ &gEfiUdp4ServiceBindingProtocolGuid,
+ UdpIo->UdpHandle
+ );
+ } else {
+ NetLibDestroyServiceChild (
+ Controller,
+ ImageHandle,
+ &gEfiUdp6ServiceBindingProtocolGuid,
+ UdpIo->UdpHandle
+ );
+ }
+
+FREE_MEM:
+ FreePool (UdpIo);
+ return NULL;
+}
+
+/**
+ Cancel all the sent datagram that pass the selection criteria of ToCancel.
+ If ToCancel is NULL, all the datagrams are cancelled.
+
+ @param[in] UdpIo The UDP_IO to cancel packet.
+ @param[in] IoStatus The IoStatus to return to the packet owners.
+ @param[in] ToCancel The select funtion to test whether to cancel this
+ packet or not.
+ @param[in] Context The opaque parameter to the ToCancel.
+
+**/
+VOID
+EFIAPI
+UdpIoCancelDgrams (
+ IN UDP_IO *UdpIo,
+ IN EFI_STATUS IoStatus,
+ IN UDP_IO_TO_CANCEL ToCancel, OPTIONAL
+ IN VOID *Context
+ )
+{
+ LIST_ENTRY *Entry;
+ LIST_ENTRY *Next;
+ UDP_TX_TOKEN *TxToken;
+
+ ASSERT ((UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) ||
+ (UdpIo->UdpVersion == UDP_IO_UDP6_VERSION));
+
+ NET_LIST_FOR_EACH_SAFE (Entry, Next, &UdpIo->SentDatagram) {
+ TxToken = NET_LIST_USER_STRUCT (Entry, UDP_TX_TOKEN, Link);
+
+ if ((ToCancel == NULL) || (ToCancel (TxToken, Context))) {
+
+ if (UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
+ UdpIo->Protocol.Udp4->Cancel (UdpIo->Protocol.Udp4, &TxToken->Token.Udp4);
+ } else {
+ UdpIo->Protocol.Udp6->Cancel (UdpIo->Protocol.Udp6, &TxToken->Token.Udp6);
+ }
+ }
+ }
+}
+
+/**
+ Free the UDP_IO and all its related resources.
+
+ The function will cancel all sent datagram and receive request.
+
+ @param[in] UdpIo The UDP_IO to free.
+
+ @retval EFI_SUCCESS The UDP_IO is freed.
+
+**/
+EFI_STATUS
+EFIAPI
+UdpIoFreeIo (
+ IN UDP_IO *UdpIo
+ )
+{
+ UDP_RX_TOKEN *RxToken;
+
+ ASSERT ((UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) ||
+ (UdpIo->UdpVersion == UDP_IO_UDP6_VERSION));
+
+ //
+ // Cancel all the sent datagram and receive requests. The
+ // callbacks of transmit requests are executed to allow the
+ // caller to release the resource. The callback of receive
+ // request are NOT executed. This is because it is most
+ // likely that the current user of the UDP IO port is closing
+ // itself.
+ //
+ UdpIoCancelDgrams (UdpIo, EFI_ABORTED, NULL, NULL);
+
+ if (UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
+
+ if ((RxToken = UdpIo->RecvRequest) != NULL) {
+ UdpIo->Protocol.Udp4->Cancel (UdpIo->Protocol.Udp4, &RxToken->Token.Udp4);
+ }
+
+ //
+ // Close then destroy the Udp4 child
+ //
+ gBS->CloseProtocol (
+ UdpIo->UdpHandle,
+ &gEfiUdp4ProtocolGuid,
+ UdpIo->Image,
+ UdpIo->Controller
+ );
+
+ NetLibDestroyServiceChild (
+ UdpIo->Controller,
+ UdpIo->Image,
+ &gEfiUdp4ServiceBindingProtocolGuid,
+ UdpIo->UdpHandle
+ );
+
+ } else {
+
+ if ((RxToken = UdpIo->RecvRequest) != NULL) {
+ UdpIo->Protocol.Udp6->Cancel (UdpIo->Protocol.Udp6, &RxToken->Token.Udp6);
+ }
+
+ //
+ // Close then destroy the Udp6 child
+ //
+ gBS->CloseProtocol (
+ UdpIo->UdpHandle,
+ &gEfiUdp6ProtocolGuid,
+ UdpIo->Image,
+ UdpIo->Controller
+ );
+
+ NetLibDestroyServiceChild (
+ UdpIo->Controller,
+ UdpIo->Image,
+ &gEfiUdp6ServiceBindingProtocolGuid,
+ UdpIo->UdpHandle
+ );
+ }
+
+ if (!IsListEmpty(&UdpIo->Link)) {
+ RemoveEntryList (&UdpIo->Link);
+ }
+
+ FreePool (UdpIo);
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Clean up the UDP_IO without freeing it. The function is called when
+ user wants to re-use the UDP_IO later.
+
+ It will release all the transmitted datagrams and receive request. It will
+ also configure NULL for the UDP instance.
+
+ @param[in] UdpIo The UDP_IO to clean up.
+
+**/
+VOID
+EFIAPI
+UdpIoCleanIo (
+ IN UDP_IO *UdpIo
+ )
+{
+ UDP_RX_TOKEN *RxToken;
+
+ ASSERT ((UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) ||
+ (UdpIo->UdpVersion == UDP_IO_UDP6_VERSION));
+
+ //
+ // Cancel all the sent datagram and receive requests.
+ //
+ UdpIoCancelDgrams (UdpIo, EFI_ABORTED, NULL, NULL);
+
+ if (UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
+ if ((RxToken = UdpIo->RecvRequest) != NULL) {
+ UdpIo->Protocol.Udp4->Cancel (UdpIo->Protocol.Udp4, &RxToken->Token.Udp4);
+ }
+
+ UdpIo->Protocol.Udp4->Configure (UdpIo->Protocol.Udp4, NULL);
+
+ } else {
+ if ((RxToken = UdpIo->RecvRequest) != NULL) {
+ UdpIo->Protocol.Udp6->Cancel (UdpIo->Protocol.Udp6, &RxToken->Token.Udp6);
+ }
+
+ UdpIo->Protocol.Udp6->Configure (UdpIo->Protocol.Udp6, NULL);
+ }
+}
+
+/**
+ Send a packet through the UDP_IO.
+
+ The packet will be wrapped in UDP_TX_TOKEN. Function Callback will be called
+ when the packet is sent. The optional parameter EndPoint overrides the default
+ address pair if specified.
+
+ @param[in] UdpIo The UDP_IO to send the packet through.
+ @param[in] Packet The packet to send.
+ @param[in] EndPoint The local and remote access point. Override the
+ default address pair set during configuration.
+ @param[in] Gateway The gateway to use.
+ @param[in] CallBack The function being called when packet is
+ transmitted or failed.
+ @param[in] Context The opaque parameter passed to CallBack.
+
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate resource for the packet.
+ @retval EFI_SUCCESS The packet is successfully delivered to UDP for
+ transmission.
+
+**/
+EFI_STATUS
+EFIAPI
+UdpIoSendDatagram (
+ IN UDP_IO *UdpIo,
+ IN NET_BUF *Packet,
+ IN UDP_END_POINT *EndPoint OPTIONAL,
+ IN EFI_IP_ADDRESS *Gateway OPTIONAL,
+ IN UDP_IO_CALLBACK CallBack,
+ IN VOID *Context
+ )
+{
+ UDP_TX_TOKEN *TxToken;
+ EFI_STATUS Status;
+
+ ASSERT ((UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) ||
+ (UdpIo->UdpVersion == UDP_IO_UDP6_VERSION));
+
+ TxToken = UdpIoCreateTxToken (UdpIo, Packet, EndPoint, Gateway, CallBack, Context);
+
+ if (TxToken == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Insert the tx token into SendDatagram list before transmitting it. Remove
+ // it from the list if the returned status is not EFI_SUCCESS.
+ //
+ InsertHeadList (&UdpIo->SentDatagram, &TxToken->Link);
+
+ if (UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
+ Status = UdpIo->Protocol.Udp4->Transmit (UdpIo->Protocol.Udp4, &TxToken->Token.Udp4);
+ } else {
+ Status = UdpIo->Protocol.Udp6->Transmit (UdpIo->Protocol.Udp6, &TxToken->Token.Udp6);
+ }
+
+ if (EFI_ERROR (Status)) {
+ RemoveEntryList (&TxToken->Link);
+ UdpIoFreeTxToken (TxToken);
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ The select function to cancel a single sent datagram.
+
+ @param[in] Token The UDP_TX_TOKEN to test against
+ @param[in] Context The NET_BUF of the sent datagram
+
+ @retval TRUE The packet is to be cancelled.
+ @retval FALSE The packet is not to be cancelled.
+**/
+BOOLEAN
+EFIAPI
+UdpIoCancelSingleDgram (
+ IN UDP_TX_TOKEN *Token,
+ IN VOID *Context
+ )
+{
+ NET_BUF *Packet;
+
+ Packet = (NET_BUF *) Context;
+
+ if (Token->Packet == Packet) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Cancel a single sent datagram.
+
+ @param[in] UdpIo The UDP_IO to cancel the packet from
+ @param[in] Packet The packet to cancel
+
+**/
+VOID
+EFIAPI
+UdpIoCancelSentDatagram (
+ IN UDP_IO *UdpIo,
+ IN NET_BUF *Packet
+ )
+{
+ UdpIoCancelDgrams (UdpIo, EFI_ABORTED, UdpIoCancelSingleDgram, Packet);
+}
+
+/**
+ Issue a receive request to the UDP_IO.
+
+ This function is called when upper-layer needs packet from UDP for processing.
+ Only one receive request is acceptable at a time so a common usage model is
+ to invoke this function inside its Callback function when the former packet
+ is processed.
+
+ @param[in] UdpIo The UDP_IO to receive the packet from.
+ @param[in] CallBack The call back function to execute when the packet
+ is received.
+ @param[in] Context The opaque context passed to Callback.
+ @param[in] HeadLen The length of the upper-layer's protocol header.
+
+ @retval EFI_ALREADY_STARTED There is already a pending receive request. Only
+ one receive request is supported at a time.
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate needed resources.
+ @retval EFI_SUCCESS The receive request is issued successfully.
+ @retval EFI_UNSUPPORTED The UDP version in UDP_IO is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+UdpIoRecvDatagram (
+ IN UDP_IO *UdpIo,
+ IN UDP_IO_CALLBACK CallBack,
+ IN VOID *Context,
+ IN UINT32 HeadLen
+ )
+{
+ UDP_RX_TOKEN *RxToken;
+ EFI_STATUS Status;
+
+ ASSERT ((UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) ||
+ (UdpIo->UdpVersion == UDP_IO_UDP6_VERSION));
+
+ if (UdpIo->RecvRequest != NULL) {
+ return EFI_ALREADY_STARTED;
+ }
+
+ RxToken = UdpIoCreateRxToken (UdpIo, CallBack, Context, HeadLen);
+
+ if (RxToken == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ UdpIo->RecvRequest = RxToken;
+ if (UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
+ Status = UdpIo->Protocol.Udp4->Receive (UdpIo->Protocol.Udp4, &RxToken->Token.Udp4);
+ } else {
+ Status = UdpIo->Protocol.Udp6->Receive (UdpIo->Protocol.Udp6, &RxToken->Token.Udp6);
+ }
+
+ if (EFI_ERROR (Status)) {
+ UdpIo->RecvRequest = NULL;
+ UdpIoFreeRxToken (RxToken);
+ }
+
+ return Status;
+}
diff --git a/Core/MdeModulePkg/Library/DxeUdpIoLib/DxeUdpIoLib.inf b/Core/MdeModulePkg/Library/DxeUdpIoLib/DxeUdpIoLib.inf
new file mode 100644
index 0000000000..a9683c9a74
--- /dev/null
+++ b/Core/MdeModulePkg/Library/DxeUdpIoLib/DxeUdpIoLib.inf
@@ -0,0 +1,53 @@
+## @file
+# This library instance provides UDP services by consuming EFI UDPv4/UDPv6 Protocols.
+#
+# Copyright (c) 2008 - 2014, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxeUpdIoLib
+ MODULE_UNI_FILE = DxeUpdIoLib.uni
+ FILE_GUID = 7E615AA1-41EE-49d4-B7E9-1D7A60AA5C8D
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = UdpIoLib|DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SAL_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ DxeUdpIoLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+
+[LibraryClasses]
+ UdpIoLib
+ BaseLib
+ DebugLib
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ BaseMemoryLib
+ DpcLib
+
+[Protocols]
+ gEfiUdp4ServiceBindingProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiUdp4ProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiUdp6ServiceBindingProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiUdp6ProtocolGuid ## SOMETIMES_CONSUMES
+
diff --git a/Core/MdeModulePkg/Library/DxeUdpIoLib/DxeUpdIoLib.uni b/Core/MdeModulePkg/Library/DxeUdpIoLib/DxeUpdIoLib.uni
new file mode 100644
index 0000000000..0e96b4b76b
--- /dev/null
+++ b/Core/MdeModulePkg/Library/DxeUdpIoLib/DxeUpdIoLib.uni
Binary files differ
diff --git a/Core/MdeModulePkg/Library/LockBoxNullLib/LockBoxNullLib.c b/Core/MdeModulePkg/Library/LockBoxNullLib/LockBoxNullLib.c
new file mode 100644
index 0000000000..5d7b52c06e
--- /dev/null
+++ b/Core/MdeModulePkg/Library/LockBoxNullLib/LockBoxNullLib.c
@@ -0,0 +1,139 @@
+/** @file
+
+Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Uefi.h>
+#include <Library/DebugLib.h>
+
+/**
+ This function will save confidential information to lockbox.
+
+ @param Guid the guid to identify the confidential information
+ @param Buffer the address of the confidential information
+ @param Length the length of the confidential information
+
+ @retval RETURN_SUCCESS the information is saved successfully.
+ @retval RETURN_INVALID_PARAMETER the Guid is NULL, or Buffer is NULL, or Length is 0
+ @retval RETURN_ALREADY_STARTED the requested GUID already exist.
+ @retval RETURN_OUT_OF_RESOURCES no enough resource to save the information.
+ @retval RETURN_ACCESS_DENIED it is too late to invoke this interface
+ @retval RETURN_NOT_STARTED it is too early to invoke this interface
+ @retval RETURN_UNSUPPORTED the service is not supported by implementaion.
+**/
+RETURN_STATUS
+EFIAPI
+SaveLockBox (
+ IN GUID *Guid,
+ IN VOID *Buffer,
+ IN UINTN Length
+ )
+{
+ return RETURN_SUCCESS;
+}
+
+/**
+ This function will set lockbox attributes.
+
+ @param Guid the guid to identify the confidential information
+ @param Attributes the attributes of the lockbox
+
+ @retval RETURN_SUCCESS the information is saved successfully.
+ @retval RETURN_INVALID_PARAMETER attributes is invalid.
+ @retval RETURN_NOT_FOUND the requested GUID not found.
+ @retval RETURN_ACCESS_DENIED it is too late to invoke this interface
+ @retval RETURN_NOT_STARTED it is too early to invoke this interface
+ @retval RETURN_UNSUPPORTED the service is not supported by implementaion.
+**/
+RETURN_STATUS
+EFIAPI
+SetLockBoxAttributes (
+ IN GUID *Guid,
+ IN UINT64 Attributes
+ )
+{
+ return RETURN_SUCCESS;
+}
+
+/**
+ This function will update confidential information to lockbox.
+
+ @param Guid the guid to identify the original confidential information
+ @param Offset the offset of the original confidential information
+ @param Buffer the address of the updated confidential information
+ @param Length the length of the updated confidential information
+
+ @retval RETURN_SUCCESS the information is saved successfully.
+ @retval RETURN_INVALID_PARAMETER the Guid is NULL, or Buffer is NULL, or Length is 0.
+ @retval RETURN_NOT_FOUND the requested GUID not found.
+ @retval RETURN_BUFFER_TOO_SMALL the original buffer to too small to hold new information.
+ @retval RETURN_ACCESS_DENIED it is too late to invoke this interface
+ @retval RETURN_NOT_STARTED it is too early to invoke this interface
+ @retval RETURN_UNSUPPORTED the service is not supported by implementaion.
+**/
+RETURN_STATUS
+EFIAPI
+UpdateLockBox (
+ IN GUID *Guid,
+ IN UINTN Offset,
+ IN VOID *Buffer,
+ IN UINTN Length
+ )
+{
+ return RETURN_SUCCESS;
+}
+
+/**
+ This function will restore confidential information from lockbox.
+
+ @param Guid the guid to identify the confidential information
+ @param Buffer the address of the restored confidential information
+ NULL means restored to original address, Length MUST be NULL at same time.
+ @param Length the length of the restored confidential information
+
+ @retval RETURN_SUCCESS the information is restored successfully.
+ @retval RETURN_INVALID_PARAMETER the Guid is NULL, or one of Buffer and Length is NULL.
+ @retval RETURN_WRITE_PROTECTED Buffer and Length are NULL, but the LockBox has no
+ LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE attribute.
+ @retval RETURN_BUFFER_TOO_SMALL the Length is too small to hold the confidential information.
+ @retval RETURN_NOT_FOUND the requested GUID not found.
+ @retval RETURN_NOT_STARTED it is too early to invoke this interface
+ @retval RETURN_ACCESS_DENIED not allow to restore to the address
+ @retval RETURN_UNSUPPORTED the service is not supported by implementaion.
+**/
+RETURN_STATUS
+EFIAPI
+RestoreLockBox (
+ IN GUID *Guid,
+ IN VOID *Buffer, OPTIONAL
+ IN OUT UINTN *Length OPTIONAL
+ )
+{
+ return RETURN_SUCCESS;
+}
+
+/**
+ This function will restore confidential information from all lockbox which have RestoreInPlace attribute.
+
+ @retval RETURN_SUCCESS the information is restored successfully.
+ @retval RETURN_NOT_STARTED it is too early to invoke this interface
+ @retval RETURN_UNSUPPORTED the service is not supported by implementaion.
+**/
+RETURN_STATUS
+EFIAPI
+RestoreAllLockBoxInPlace (
+ VOID
+ )
+{
+ return RETURN_SUCCESS;
+}
diff --git a/Core/MdeModulePkg/Library/LockBoxNullLib/LockBoxNullLib.inf b/Core/MdeModulePkg/Library/LockBoxNullLib/LockBoxNullLib.inf
new file mode 100644
index 0000000000..1018a69e81
--- /dev/null
+++ b/Core/MdeModulePkg/Library/LockBoxNullLib/LockBoxNullLib.inf
@@ -0,0 +1,39 @@
+## @file
+# NULL LockBox library instance.
+#
+# Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions
+# of the BSD License which accompanies this distribution. The
+# full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = LockBoxNullLib
+ MODULE_UNI_FILE = LockBoxNullLib.uni
+ FILE_GUID = 0BA38EBD-E190-4df7-8EC4-0A6E2B43772D
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = LockBoxLib|PEIM DXE_DRIVER DXE_RUNTIME_DRIVER UEFI_DRIVER UEFI_APPLICATION DXE_SMM_DRIVER
+
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ LockBoxNullLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
diff --git a/Core/MdeModulePkg/Library/LockBoxNullLib/LockBoxNullLib.uni b/Core/MdeModulePkg/Library/LockBoxNullLib/LockBoxNullLib.uni
new file mode 100644
index 0000000000..5466eb1b67
--- /dev/null
+++ b/Core/MdeModulePkg/Library/LockBoxNullLib/LockBoxNullLib.uni
Binary files differ
diff --git a/Core/MdeModulePkg/Library/LzmaCustomDecompressLib/F86GuidedSectionExtraction.c b/Core/MdeModulePkg/Library/LzmaCustomDecompressLib/F86GuidedSectionExtraction.c
new file mode 100644
index 0000000000..ada9a809fa
--- /dev/null
+++ b/Core/MdeModulePkg/Library/LzmaCustomDecompressLib/F86GuidedSectionExtraction.c
@@ -0,0 +1,218 @@
+/** @file
+ LZMA Decompress GUIDed Section Extraction Library, which produces LZMA custom
+ decompression algorithm with the converter for the different arch code.
+ It wraps Lzma decompress interfaces to GUIDed Section Extraction interfaces
+ and registers them into GUIDed handler table.
+
+ Copyright (c) 2012, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "LzmaDecompressLibInternal.h"
+#include "Sdk/C/Bra.h"
+
+/**
+ Examines a GUIDed section and returns the size of the decoded buffer and the
+ size of an scratch buffer required to actually decode the data in a GUIDed section.
+
+ Examines a GUIDed section specified by InputSection.
+ If GUID for InputSection does not match the GUID that this handler supports,
+ then RETURN_UNSUPPORTED is returned.
+ If the required information can not be retrieved from InputSection,
+ then RETURN_INVALID_PARAMETER is returned.
+ If the GUID of InputSection does match the GUID that this handler supports,
+ then the size required to hold the decoded buffer is returned in OututBufferSize,
+ the size of an optional scratch buffer is returned in ScratchSize, and the Attributes field
+ from EFI_GUID_DEFINED_SECTION header of InputSection is returned in SectionAttribute.
+
+ If InputSection is NULL, then ASSERT().
+ If OutputBufferSize is NULL, then ASSERT().
+ If ScratchBufferSize is NULL, then ASSERT().
+ If SectionAttribute is NULL, then ASSERT().
+
+
+ @param[in] InputSection A pointer to a GUIDed section of an FFS formatted file.
+ @param[out] OutputBufferSize A pointer to the size, in bytes, of an output buffer required
+ if the buffer specified by InputSection were decoded.
+ @param[out] ScratchBufferSize A pointer to the size, in bytes, required as scratch space
+ if the buffer specified by InputSection were decoded.
+ @param[out] SectionAttribute A pointer to the attributes of the GUIDed section. See the Attributes
+ field of EFI_GUID_DEFINED_SECTION in the PI Specification.
+
+ @retval RETURN_SUCCESS The information about InputSection was returned.
+ @retval RETURN_UNSUPPORTED The section specified by InputSection does not match the GUID this handler supports.
+ @retval RETURN_INVALID_PARAMETER The information can not be retrieved from the section specified by InputSection.
+
+**/
+RETURN_STATUS
+EFIAPI
+LzmaArchGuidedSectionGetInfo (
+ IN CONST VOID *InputSection,
+ OUT UINT32 *OutputBufferSize,
+ OUT UINT32 *ScratchBufferSize,
+ OUT UINT16 *SectionAttribute
+ )
+{
+ ASSERT (InputSection != NULL);
+ ASSERT (OutputBufferSize != NULL);
+ ASSERT (ScratchBufferSize != NULL);
+ ASSERT (SectionAttribute != NULL);
+
+ if (IS_SECTION2 (InputSection)) {
+ if (!CompareGuid (
+ &gLzmaF86CustomDecompressGuid,
+ &(((EFI_GUID_DEFINED_SECTION2 *) InputSection)->SectionDefinitionGuid))) {
+ return RETURN_INVALID_PARAMETER;
+ }
+
+ *SectionAttribute = ((EFI_GUID_DEFINED_SECTION2 *) InputSection)->Attributes;
+
+ return LzmaUefiDecompressGetInfo (
+ (UINT8 *) InputSection + ((EFI_GUID_DEFINED_SECTION2 *) InputSection)->DataOffset,
+ SECTION2_SIZE (InputSection) - ((EFI_GUID_DEFINED_SECTION2 *) InputSection)->DataOffset,
+ OutputBufferSize,
+ ScratchBufferSize
+ );
+ } else {
+ if (!CompareGuid (
+ &gLzmaF86CustomDecompressGuid,
+ &(((EFI_GUID_DEFINED_SECTION *) InputSection)->SectionDefinitionGuid))) {
+ return RETURN_INVALID_PARAMETER;
+ }
+
+ *SectionAttribute = ((EFI_GUID_DEFINED_SECTION *) InputSection)->Attributes;
+
+ return LzmaUefiDecompressGetInfo (
+ (UINT8 *) InputSection + ((EFI_GUID_DEFINED_SECTION *) InputSection)->DataOffset,
+ SECTION_SIZE (InputSection) - ((EFI_GUID_DEFINED_SECTION *) InputSection)->DataOffset,
+ OutputBufferSize,
+ ScratchBufferSize
+ );
+ }
+}
+
+/**
+ Decompress a LZAM compressed GUIDed section into a caller allocated output buffer.
+
+ Decodes the GUIDed section specified by InputSection.
+ If GUID for InputSection does not match the GUID that this handler supports, then RETURN_UNSUPPORTED is returned.
+ If the data in InputSection can not be decoded, then RETURN_INVALID_PARAMETER is returned.
+ If the GUID of InputSection does match the GUID that this handler supports, then InputSection
+ is decoded into the buffer specified by OutputBuffer and the authentication status of this
+ decode operation is returned in AuthenticationStatus. If the decoded buffer is identical to the
+ data in InputSection, then OutputBuffer is set to point at the data in InputSection. Otherwise,
+ the decoded data will be placed in caller allocated buffer specified by OutputBuffer.
+
+ If InputSection is NULL, then ASSERT().
+ If OutputBuffer is NULL, then ASSERT().
+ If ScratchBuffer is NULL and this decode operation requires a scratch buffer, then ASSERT().
+ If AuthenticationStatus is NULL, then ASSERT().
+
+
+ @param[in] InputSection A pointer to a GUIDed section of an FFS formatted file.
+ @param[out] OutputBuffer A pointer to a buffer that contains the result of a decode operation.
+ @param[out] ScratchBuffer A caller allocated buffer that may be required by this function
+ as a scratch buffer to perform the decode operation.
+ @param[out] AuthenticationStatus
+ A pointer to the authentication status of the decoded output buffer.
+ See the definition of authentication status in the EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI
+ section of the PI Specification. EFI_AUTH_STATUS_PLATFORM_OVERRIDE must
+ never be set by this handler.
+
+ @retval RETURN_SUCCESS The buffer specified by InputSection was decoded.
+ @retval RETURN_UNSUPPORTED The section specified by InputSection does not match the GUID this handler supports.
+ @retval RETURN_INVALID_PARAMETER The section specified by InputSection can not be decoded.
+
+**/
+RETURN_STATUS
+EFIAPI
+LzmaArchGuidedSectionExtraction (
+ IN CONST VOID *InputSection,
+ OUT VOID **OutputBuffer,
+ OUT VOID *ScratchBuffer, OPTIONAL
+ OUT UINT32 *AuthenticationStatus
+ )
+{
+ EFI_GUID *InputGuid;
+ VOID *Source;
+ UINTN SourceSize;
+ EFI_STATUS Status;
+ UINT32 X86State;
+ UINT32 OutputBufferSize;
+ UINT32 ScratchBufferSize;
+
+ ASSERT (OutputBuffer != NULL);
+ ASSERT (InputSection != NULL);
+
+ if (IS_SECTION2 (InputSection)) {
+ InputGuid = &(((EFI_GUID_DEFINED_SECTION2 *) InputSection)->SectionDefinitionGuid);
+ Source = (UINT8 *) InputSection + ((EFI_GUID_DEFINED_SECTION2 *) InputSection)->DataOffset;
+ SourceSize = SECTION2_SIZE (InputSection) - ((EFI_GUID_DEFINED_SECTION2 *) InputSection)->DataOffset;
+ } else {
+ InputGuid = &(((EFI_GUID_DEFINED_SECTION *) InputSection)->SectionDefinitionGuid);
+ Source = (UINT8 *) InputSection + ((EFI_GUID_DEFINED_SECTION *) InputSection)->DataOffset;
+ SourceSize = SECTION_SIZE (InputSection) - ((EFI_GUID_DEFINED_SECTION *) InputSection)->DataOffset;
+ }
+
+ if (!CompareGuid (&gLzmaF86CustomDecompressGuid, InputGuid)) {
+ return RETURN_INVALID_PARAMETER;
+ }
+
+ //
+ // Authentication is set to Zero, which may be ignored.
+ //
+ *AuthenticationStatus = 0;
+
+ Status = LzmaUefiDecompress (
+ Source,
+ SourceSize,
+ *OutputBuffer,
+ ScratchBuffer
+ );
+
+ //
+ // After decompress, the data need to be converted to the raw data.
+ //
+ if (!EFI_ERROR (Status)) {
+ Status = LzmaUefiDecompressGetInfo (
+ Source,
+ (UINT32) SourceSize,
+ &OutputBufferSize,
+ &ScratchBufferSize
+ );
+
+ if (!EFI_ERROR (Status)) {
+ x86_Convert_Init(X86State);
+ x86_Convert(*OutputBuffer, OutputBufferSize, 0, &X86State, 0);
+ }
+ }
+
+ return Status;
+}
+
+
+/**
+ Register LzmaArchDecompress and LzmaArchDecompressGetInfo handlers with LzmaF86CustomDecompressGuid.
+
+ @retval RETURN_SUCCESS Register successfully.
+ @retval RETURN_OUT_OF_RESOURCES No enough memory to store this handler.
+**/
+EFI_STATUS
+EFIAPI
+LzmaArchDecompressLibConstructor (
+ )
+{
+ return ExtractGuidedSectionRegisterHandlers (
+ &gLzmaF86CustomDecompressGuid,
+ LzmaArchGuidedSectionGetInfo,
+ LzmaArchGuidedSectionExtraction
+ );
+}
+
diff --git a/Core/MdeModulePkg/Library/LzmaCustomDecompressLib/GuidedSectionExtraction.c b/Core/MdeModulePkg/Library/LzmaCustomDecompressLib/GuidedSectionExtraction.c
new file mode 100644
index 0000000000..f19e0d28cd
--- /dev/null
+++ b/Core/MdeModulePkg/Library/LzmaCustomDecompressLib/GuidedSectionExtraction.c
@@ -0,0 +1,201 @@
+/** @file
+ LZMA Decompress GUIDed Section Extraction Library.
+ It wraps Lzma decompress interfaces to GUIDed Section Extraction interfaces
+ and registers them into GUIDed handler table.
+
+ Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "LzmaDecompressLibInternal.h"
+
+/**
+ Examines a GUIDed section and returns the size of the decoded buffer and the
+ size of an scratch buffer required to actually decode the data in a GUIDed section.
+
+ Examines a GUIDed section specified by InputSection.
+ If GUID for InputSection does not match the GUID that this handler supports,
+ then RETURN_UNSUPPORTED is returned.
+ If the required information can not be retrieved from InputSection,
+ then RETURN_INVALID_PARAMETER is returned.
+ If the GUID of InputSection does match the GUID that this handler supports,
+ then the size required to hold the decoded buffer is returned in OututBufferSize,
+ the size of an optional scratch buffer is returned in ScratchSize, and the Attributes field
+ from EFI_GUID_DEFINED_SECTION header of InputSection is returned in SectionAttribute.
+
+ If InputSection is NULL, then ASSERT().
+ If OutputBufferSize is NULL, then ASSERT().
+ If ScratchBufferSize is NULL, then ASSERT().
+ If SectionAttribute is NULL, then ASSERT().
+
+
+ @param[in] InputSection A pointer to a GUIDed section of an FFS formatted file.
+ @param[out] OutputBufferSize A pointer to the size, in bytes, of an output buffer required
+ if the buffer specified by InputSection were decoded.
+ @param[out] ScratchBufferSize A pointer to the size, in bytes, required as scratch space
+ if the buffer specified by InputSection were decoded.
+ @param[out] SectionAttribute A pointer to the attributes of the GUIDed section. See the Attributes
+ field of EFI_GUID_DEFINED_SECTION in the PI Specification.
+
+ @retval RETURN_SUCCESS The information about InputSection was returned.
+ @retval RETURN_UNSUPPORTED The section specified by InputSection does not match the GUID this handler supports.
+ @retval RETURN_INVALID_PARAMETER The information can not be retrieved from the section specified by InputSection.
+
+**/
+RETURN_STATUS
+EFIAPI
+LzmaGuidedSectionGetInfo (
+ IN CONST VOID *InputSection,
+ OUT UINT32 *OutputBufferSize,
+ OUT UINT32 *ScratchBufferSize,
+ OUT UINT16 *SectionAttribute
+ )
+{
+ ASSERT (InputSection != NULL);
+ ASSERT (OutputBufferSize != NULL);
+ ASSERT (ScratchBufferSize != NULL);
+ ASSERT (SectionAttribute != NULL);
+
+ if (IS_SECTION2 (InputSection)) {
+ if (!CompareGuid (
+ &gLzmaCustomDecompressGuid,
+ &(((EFI_GUID_DEFINED_SECTION2 *) InputSection)->SectionDefinitionGuid))) {
+ return RETURN_INVALID_PARAMETER;
+ }
+
+ *SectionAttribute = ((EFI_GUID_DEFINED_SECTION2 *) InputSection)->Attributes;
+
+ return LzmaUefiDecompressGetInfo (
+ (UINT8 *) InputSection + ((EFI_GUID_DEFINED_SECTION2 *) InputSection)->DataOffset,
+ SECTION2_SIZE (InputSection) - ((EFI_GUID_DEFINED_SECTION2 *) InputSection)->DataOffset,
+ OutputBufferSize,
+ ScratchBufferSize
+ );
+ } else {
+ if (!CompareGuid (
+ &gLzmaCustomDecompressGuid,
+ &(((EFI_GUID_DEFINED_SECTION *) InputSection)->SectionDefinitionGuid))) {
+ return RETURN_INVALID_PARAMETER;
+ }
+
+ *SectionAttribute = ((EFI_GUID_DEFINED_SECTION *) InputSection)->Attributes;
+
+ return LzmaUefiDecompressGetInfo (
+ (UINT8 *) InputSection + ((EFI_GUID_DEFINED_SECTION *) InputSection)->DataOffset,
+ SECTION_SIZE (InputSection) - ((EFI_GUID_DEFINED_SECTION *) InputSection)->DataOffset,
+ OutputBufferSize,
+ ScratchBufferSize
+ );
+ }
+}
+
+/**
+ Decompress a LZAM compressed GUIDed section into a caller allocated output buffer.
+
+ Decodes the GUIDed section specified by InputSection.
+ If GUID for InputSection does not match the GUID that this handler supports, then RETURN_UNSUPPORTED is returned.
+ If the data in InputSection can not be decoded, then RETURN_INVALID_PARAMETER is returned.
+ If the GUID of InputSection does match the GUID that this handler supports, then InputSection
+ is decoded into the buffer specified by OutputBuffer and the authentication status of this
+ decode operation is returned in AuthenticationStatus. If the decoded buffer is identical to the
+ data in InputSection, then OutputBuffer is set to point at the data in InputSection. Otherwise,
+ the decoded data will be placed in caller allocated buffer specified by OutputBuffer.
+
+ If InputSection is NULL, then ASSERT().
+ If OutputBuffer is NULL, then ASSERT().
+ If ScratchBuffer is NULL and this decode operation requires a scratch buffer, then ASSERT().
+ If AuthenticationStatus is NULL, then ASSERT().
+
+
+ @param[in] InputSection A pointer to a GUIDed section of an FFS formatted file.
+ @param[out] OutputBuffer A pointer to a buffer that contains the result of a decode operation.
+ @param[out] ScratchBuffer A caller allocated buffer that may be required by this function
+ as a scratch buffer to perform the decode operation.
+ @param[out] AuthenticationStatus
+ A pointer to the authentication status of the decoded output buffer.
+ See the definition of authentication status in the EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI
+ section of the PI Specification. EFI_AUTH_STATUS_PLATFORM_OVERRIDE must
+ never be set by this handler.
+
+ @retval RETURN_SUCCESS The buffer specified by InputSection was decoded.
+ @retval RETURN_UNSUPPORTED The section specified by InputSection does not match the GUID this handler supports.
+ @retval RETURN_INVALID_PARAMETER The section specified by InputSection can not be decoded.
+
+**/
+RETURN_STATUS
+EFIAPI
+LzmaGuidedSectionExtraction (
+ IN CONST VOID *InputSection,
+ OUT VOID **OutputBuffer,
+ OUT VOID *ScratchBuffer, OPTIONAL
+ OUT UINT32 *AuthenticationStatus
+ )
+{
+ ASSERT (OutputBuffer != NULL);
+ ASSERT (InputSection != NULL);
+
+ if (IS_SECTION2 (InputSection)) {
+ if (!CompareGuid (
+ &gLzmaCustomDecompressGuid,
+ &(((EFI_GUID_DEFINED_SECTION2 *) InputSection)->SectionDefinitionGuid))) {
+ return RETURN_INVALID_PARAMETER;
+ }
+
+ //
+ // Authentication is set to Zero, which may be ignored.
+ //
+ *AuthenticationStatus = 0;
+
+ return LzmaUefiDecompress (
+ (UINT8 *) InputSection + ((EFI_GUID_DEFINED_SECTION2 *) InputSection)->DataOffset,
+ SECTION2_SIZE (InputSection) - ((EFI_GUID_DEFINED_SECTION2 *) InputSection)->DataOffset,
+ *OutputBuffer,
+ ScratchBuffer
+ );
+ } else {
+ if (!CompareGuid (
+ &gLzmaCustomDecompressGuid,
+ &(((EFI_GUID_DEFINED_SECTION *) InputSection)->SectionDefinitionGuid))) {
+ return RETURN_INVALID_PARAMETER;
+ }
+
+ //
+ // Authentication is set to Zero, which may be ignored.
+ //
+ *AuthenticationStatus = 0;
+
+ return LzmaUefiDecompress (
+ (UINT8 *) InputSection + ((EFI_GUID_DEFINED_SECTION *) InputSection)->DataOffset,
+ SECTION_SIZE (InputSection) - ((EFI_GUID_DEFINED_SECTION *) InputSection)->DataOffset,
+ *OutputBuffer,
+ ScratchBuffer
+ );
+ }
+}
+
+
+/**
+ Register LzmaDecompress and LzmaDecompressGetInfo handlers with LzmaCustomerDecompressGuid.
+
+ @retval RETURN_SUCCESS Register successfully.
+ @retval RETURN_OUT_OF_RESOURCES No enough memory to store this handler.
+**/
+EFI_STATUS
+EFIAPI
+LzmaDecompressLibConstructor (
+ )
+{
+ return ExtractGuidedSectionRegisterHandlers (
+ &gLzmaCustomDecompressGuid,
+ LzmaGuidedSectionGetInfo,
+ LzmaGuidedSectionExtraction
+ );
+}
+
diff --git a/Core/MdeModulePkg/Library/LzmaCustomDecompressLib/LZMA-SDK-README.txt b/Core/MdeModulePkg/Library/LzmaCustomDecompressLib/LZMA-SDK-README.txt
new file mode 100644
index 0000000000..e05b3bb853
--- /dev/null
+++ b/Core/MdeModulePkg/Library/LzmaCustomDecompressLib/LZMA-SDK-README.txt
@@ -0,0 +1,4 @@
+LzmaCustomDecompressLib is based on the LZMA SDK 4.65.
+LZMA SDK 4.65 was placed in the public domain on
+2009-02-03. It was released on the
+http://www.7-zip.org/sdk.html website. \ No newline at end of file
diff --git a/Core/MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaArchCustomDecompressLib.inf b/Core/MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaArchCustomDecompressLib.inf
new file mode 100644
index 0000000000..ec7585d55b
--- /dev/null
+++ b/Core/MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaArchCustomDecompressLib.inf
@@ -0,0 +1,66 @@
+## @file
+# LzmaArchCustomDecompressLib produces LZMA custom decompression algorithm with the converter for the different arch code.
+#
+# It is based on the LZMA SDK 4.65.
+# LZMA SDK 4.65 was placed in the public domain on 2009-02-03.
+# It was released on the http://www.7-zip.org/sdk.html website.
+#
+# Copyright (c) 2012 - 2015, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = LzmaArchDecompressLib
+ MODULE_UNI_FILE = LzmaArchDecompressLib.uni
+ FILE_GUID = A853C1D2-E003-4cc4-9DD1-8824AD79FE48
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = NULL
+ CONSTRUCTOR = LzmaArchDecompressLibConstructor
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ LzmaDecompress.c
+ Sdk/C/Bra.h
+ Sdk/C/LzFind.c
+ Sdk/C/LzmaDec.c
+ Sdk/C/7zVersion.h
+ Sdk/C/CpuArch.h
+ Sdk/C/LzFind.h
+ Sdk/C/LzHash.h
+ Sdk/C/LzmaDec.h
+ Sdk/C/Types.h
+ UefiLzma.h
+ LzmaDecompressLibInternal.h
+
+[Sources.Ia32, Sources.X64]
+ Sdk/C/Bra86.c
+ F86GuidedSectionExtraction.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[Guids.Ia32, Guids.X64]
+ gLzmaF86CustomDecompressGuid ## PRODUCES ## GUID # specifies LZMA custom decompress algorithm with converter for x86 code.
+
+[LibraryClasses]
+ BaseLib
+ DebugLib
+ BaseMemoryLib
+ ExtractGuidedSectionLib
+
diff --git a/Core/MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaArchDecompressLib.uni b/Core/MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaArchDecompressLib.uni
new file mode 100644
index 0000000000..1830dae73c
--- /dev/null
+++ b/Core/MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaArchDecompressLib.uni
Binary files differ
diff --git a/Core/MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaCustomDecompressLib.inf b/Core/MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaCustomDecompressLib.inf
new file mode 100644
index 0000000000..f5624fd039
--- /dev/null
+++ b/Core/MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaCustomDecompressLib.inf
@@ -0,0 +1,62 @@
+## @file
+# LzmaCustomDecompressLib produces LZMA custom decompression algorithm.
+#
+# It is based on the LZMA SDK 4.65.
+# LZMA SDK 4.65 was placed in the public domain on 2009-02-03.
+# It was released on the http://www.7-zip.org/sdk.html website.
+#
+# Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = LzmaDecompressLib
+ MODULE_UNI_FILE = LzmaDecompressLib.uni
+ FILE_GUID = 35194660-7421-44ad-9636-e44885f092d1
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = NULL
+ CONSTRUCTOR = LzmaDecompressLibConstructor
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ LzmaDecompress.c
+ Sdk/C/LzFind.c
+ Sdk/C/LzmaDec.c
+ Sdk/C/7zVersion.h
+ Sdk/C/CpuArch.h
+ Sdk/C/LzFind.h
+ Sdk/C/LzHash.h
+ Sdk/C/LzmaDec.h
+ Sdk/C/Types.h
+ GuidedSectionExtraction.c
+ UefiLzma.h
+ LzmaDecompressLibInternal.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[Guids]
+ gLzmaCustomDecompressGuid ## PRODUCES ## UNDEFINED # specifies LZMA custom decompress algorithm.
+
+[LibraryClasses]
+ BaseLib
+ DebugLib
+ BaseMemoryLib
+ ExtractGuidedSectionLib
+
diff --git a/Core/MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaDecompress.c b/Core/MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaDecompress.c
new file mode 100644
index 0000000000..e32b6a3025
--- /dev/null
+++ b/Core/MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaDecompress.c
@@ -0,0 +1,220 @@
+/** @file
+ LZMA Decompress interfaces
+
+ Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "LzmaDecompressLibInternal.h"
+#include "Sdk/C/Types.h"
+#include "Sdk/C/7zVersion.h"
+#include "Sdk/C/LzmaDec.h"
+
+#define SCRATCH_BUFFER_REQUEST_SIZE SIZE_64KB
+
+typedef struct
+{
+ ISzAlloc Functions;
+ VOID *Buffer;
+ UINTN BufferSize;
+} ISzAllocWithData;
+
+/**
+ Allocation routine used by LZMA decompression.
+
+ @param P Pointer to the ISzAlloc instance
+ @param Size The size in bytes to be allocated
+
+ @return The allocated pointer address, or NULL on failure
+**/
+VOID *
+SzAlloc (
+ VOID *P,
+ size_t Size
+ )
+{
+ VOID *Addr;
+ ISzAllocWithData *Private;
+
+ Private = (ISzAllocWithData*) P;
+
+ if (Private->BufferSize >= Size) {
+ Addr = Private->Buffer;
+ Private->Buffer = (VOID*) ((UINT8*)Addr + Size);
+ Private->BufferSize -= Size;
+ return Addr;
+ } else {
+ ASSERT (FALSE);
+ return NULL;
+ }
+}
+
+/**
+ Free routine used by LZMA decompression.
+
+ @param P Pointer to the ISzAlloc instance
+ @param Address The address to be freed
+**/
+VOID
+SzFree (
+ VOID *P,
+ VOID *Address
+ )
+{
+ //
+ // We use the 'scratch buffer' for allocations, so there is no free
+ // operation required. The scratch buffer will be freed by the caller
+ // of the decompression code.
+ //
+}
+
+#define LZMA_HEADER_SIZE (LZMA_PROPS_SIZE + 8)
+
+/**
+ Get the size of the uncompressed buffer by parsing EncodeData header.
+
+ @param EncodedData Pointer to the compressed data.
+
+ @return The size of the uncompressed buffer.
+**/
+UINT64
+GetDecodedSizeOfBuf(
+ UINT8 *EncodedData
+ )
+{
+ UINT64 DecodedSize;
+ INTN Index;
+
+ /* Parse header */
+ DecodedSize = 0;
+ for (Index = LZMA_PROPS_SIZE + 7; Index >= LZMA_PROPS_SIZE; Index--)
+ DecodedSize = LShiftU64(DecodedSize, 8) + EncodedData[Index];
+
+ return DecodedSize;
+}
+
+//
+// LZMA functions and data as defined in local LzmaDecompressLibInternal.h
+//
+
+/**
+ Given a Lzma compressed source buffer, this function retrieves the size of
+ the uncompressed buffer and the size of the scratch buffer required
+ to decompress the compressed source buffer.
+
+ Retrieves the size of the uncompressed buffer and the temporary scratch buffer
+ required to decompress the buffer specified by Source and SourceSize.
+ The size of the uncompressed buffer is returned in DestinationSize,
+ the size of the scratch buffer is returned in ScratchSize, and RETURN_SUCCESS is returned.
+ This function does not have scratch buffer available to perform a thorough
+ checking of the validity of the source data. It just retrieves the "Original Size"
+ field from the LZMA_HEADER_SIZE beginning bytes of the source data and output it as DestinationSize.
+ And ScratchSize is specific to the decompression implementation.
+
+ If SourceSize is less than LZMA_HEADER_SIZE, then ASSERT().
+
+ @param Source The source buffer containing the compressed data.
+ @param SourceSize The size, in bytes, of the source buffer.
+ @param DestinationSize A pointer to the size, in bytes, of the uncompressed buffer
+ that will be generated when the compressed buffer specified
+ by Source and SourceSize is decompressed.
+ @param ScratchSize A pointer to the size, in bytes, of the scratch buffer that
+ is required to decompress the compressed buffer specified
+ by Source and SourceSize.
+
+ @retval RETURN_SUCCESS The size of the uncompressed data was returned
+ in DestinationSize and the size of the scratch
+ buffer was returned in ScratchSize.
+
+**/
+RETURN_STATUS
+EFIAPI
+LzmaUefiDecompressGetInfo (
+ IN CONST VOID *Source,
+ IN UINT32 SourceSize,
+ OUT UINT32 *DestinationSize,
+ OUT UINT32 *ScratchSize
+ )
+{
+ UInt64 DecodedSize;
+
+ ASSERT(SourceSize >= LZMA_HEADER_SIZE);
+
+ DecodedSize = GetDecodedSizeOfBuf((UINT8*)Source);
+
+ *DestinationSize = (UINT32)DecodedSize;
+ *ScratchSize = SCRATCH_BUFFER_REQUEST_SIZE;
+ return RETURN_SUCCESS;
+}
+
+/**
+ Decompresses a Lzma compressed source buffer.
+
+ Extracts decompressed data to its original form.
+ If the compressed source data specified by Source is successfully decompressed
+ into Destination, then RETURN_SUCCESS is returned. If the compressed source data
+ specified by Source is not in a valid compressed data format,
+ then RETURN_INVALID_PARAMETER is returned.
+
+ @param Source The source buffer containing the compressed data.
+ @param SourceSize The size of source buffer.
+ @param Destination The destination buffer to store the decompressed data
+ @param Scratch A temporary scratch buffer that is used to perform the decompression.
+ This is an optional parameter that may be NULL if the
+ required scratch buffer size is 0.
+
+ @retval RETURN_SUCCESS Decompression completed successfully, and
+ the uncompressed buffer is returned in Destination.
+ @retval RETURN_INVALID_PARAMETER
+ The source buffer specified by Source is corrupted
+ (not in a valid compressed format).
+**/
+RETURN_STATUS
+EFIAPI
+LzmaUefiDecompress (
+ IN CONST VOID *Source,
+ IN UINTN SourceSize,
+ IN OUT VOID *Destination,
+ IN OUT VOID *Scratch
+ )
+{
+ SRes LzmaResult;
+ ELzmaStatus Status;
+ SizeT DecodedBufSize;
+ SizeT EncodedDataSize;
+ ISzAllocWithData AllocFuncs;
+
+ AllocFuncs.Functions.Alloc = SzAlloc;
+ AllocFuncs.Functions.Free = SzFree;
+ AllocFuncs.Buffer = Scratch;
+ AllocFuncs.BufferSize = SCRATCH_BUFFER_REQUEST_SIZE;
+
+ DecodedBufSize = (SizeT)GetDecodedSizeOfBuf((UINT8*)Source);
+ EncodedDataSize = (SizeT) (SourceSize - LZMA_HEADER_SIZE);
+
+ LzmaResult = LzmaDecode(
+ Destination,
+ &DecodedBufSize,
+ (Byte*)((UINT8*)Source + LZMA_HEADER_SIZE),
+ &EncodedDataSize,
+ Source,
+ LZMA_PROPS_SIZE,
+ LZMA_FINISH_END,
+ &Status,
+ &(AllocFuncs.Functions)
+ );
+
+ if (LzmaResult == SZ_OK) {
+ return RETURN_SUCCESS;
+ } else {
+ return RETURN_INVALID_PARAMETER;
+ }
+}
+
diff --git a/Core/MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaDecompressLib.uni b/Core/MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaDecompressLib.uni
new file mode 100644
index 0000000000..498e4e1088
--- /dev/null
+++ b/Core/MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaDecompressLib.uni
Binary files differ
diff --git a/Core/MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaDecompressLibInternal.h b/Core/MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaDecompressLibInternal.h
new file mode 100644
index 0000000000..3096e91dbe
--- /dev/null
+++ b/Core/MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaDecompressLibInternal.h
@@ -0,0 +1,96 @@
+/** @file
+ LZMA Decompress Library internal header file declares Lzma decompress interfaces.
+
+ Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __LZMADECOMPRESSLIB_INTERNAL_H__
+#define __LZMADECOMPRESSLIB_INTERNAL_H__
+
+#include <PiPei.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/ExtractGuidedSectionLib.h>
+#include <Guid/LzmaDecompress.h>
+
+/**
+ Given a Lzma compressed source buffer, this function retrieves the size of
+ the uncompressed buffer and the size of the scratch buffer required
+ to decompress the compressed source buffer.
+
+ Retrieves the size of the uncompressed buffer and the temporary scratch buffer
+ required to decompress the buffer specified by Source and SourceSize.
+ The size of the uncompressed buffer is returned in DestinationSize,
+ the size of the scratch buffer is returned in ScratchSize, and RETURN_SUCCESS is returned.
+ This function does not have scratch buffer available to perform a thorough
+ checking of the validity of the source data. It just retrieves the "Original Size"
+ field from the LZMA_HEADER_SIZE beginning bytes of the source data and output it as DestinationSize.
+ And ScratchSize is specific to the decompression implementation.
+
+ If SourceSize is less than LZMA_HEADER_SIZE, then ASSERT().
+
+ @param Source The source buffer containing the compressed data.
+ @param SourceSize The size, in bytes, of the source buffer.
+ @param DestinationSize A pointer to the size, in bytes, of the uncompressed buffer
+ that will be generated when the compressed buffer specified
+ by Source and SourceSize is decompressed.
+ @param ScratchSize A pointer to the size, in bytes, of the scratch buffer that
+ is required to decompress the compressed buffer specified
+ by Source and SourceSize.
+
+ @retval RETURN_SUCCESS The size of the uncompressed data was returned
+ in DestinationSize and the size of the scratch
+ buffer was returned in ScratchSize.
+
+**/
+RETURN_STATUS
+EFIAPI
+LzmaUefiDecompressGetInfo (
+ IN CONST VOID *Source,
+ IN UINT32 SourceSize,
+ OUT UINT32 *DestinationSize,
+ OUT UINT32 *ScratchSize
+ );
+
+/**
+ Decompresses a Lzma compressed source buffer.
+
+ Extracts decompressed data to its original form.
+ If the compressed source data specified by Source is successfully decompressed
+ into Destination, then RETURN_SUCCESS is returned. If the compressed source data
+ specified by Source is not in a valid compressed data format,
+ then RETURN_INVALID_PARAMETER is returned.
+
+ @param Source The source buffer containing the compressed data.
+ @param SourceSize The size of source buffer.
+ @param Destination The destination buffer to store the decompressed data
+ @param Scratch A temporary scratch buffer that is used to perform the decompression.
+ This is an optional parameter that may be NULL if the
+ required scratch buffer size is 0.
+
+ @retval RETURN_SUCCESS Decompression completed successfully, and
+ the uncompressed buffer is returned in Destination.
+ @retval RETURN_INVALID_PARAMETER
+ The source buffer specified by Source is corrupted
+ (not in a valid compressed format).
+**/
+RETURN_STATUS
+EFIAPI
+LzmaUefiDecompress (
+ IN CONST VOID *Source,
+ IN UINTN SourceSize,
+ IN OUT VOID *Destination,
+ IN OUT VOID *Scratch
+ );
+
+#endif
+
diff --git a/Core/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/7zVersion.h b/Core/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/7zVersion.h
new file mode 100644
index 0000000000..5a6bcadac6
--- /dev/null
+++ b/Core/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/7zVersion.h
@@ -0,0 +1,7 @@
+#define MY_VER_MAJOR 4
+#define MY_VER_MINOR 65
+#define MY_VER_BUILD 0
+#define MY_VERSION "4.65"
+#define MY_DATE "2009-02-03"
+#define MY_COPYRIGHT ": Igor Pavlov : Public domain"
+#define MY_VERSION_COPYRIGHT_DATE MY_VERSION " " MY_COPYRIGHT " : " MY_DATE
diff --git a/Core/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/Bra.h b/Core/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/Bra.h
new file mode 100644
index 0000000000..b9018eb991
--- /dev/null
+++ b/Core/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/Bra.h
@@ -0,0 +1,60 @@
+/* Bra.h -- Branch converters for executables
+2008-10-04 : Igor Pavlov : Public domain */
+
+#ifndef __BRA_H
+#define __BRA_H
+
+#include "Types.h"
+
+/*
+These functions convert relative addresses to absolute addresses
+in CALL instructions to increase the compression ratio.
+
+ In:
+ data - data buffer
+ size - size of data
+ ip - current virtual Instruction Pinter (IP) value
+ state - state variable for x86 converter
+ encoding - 0 (for decoding), 1 (for encoding)
+
+ Out:
+ state - state variable for x86 converter
+
+ Returns:
+ The number of processed bytes. If you call these functions with multiple calls,
+ you must start next call with first byte after block of processed bytes.
+
+ Type Endian Alignment LookAhead
+
+ x86 little 1 4
+ ARMT little 2 2
+ ARM little 4 0
+ PPC big 4 0
+ SPARC big 4 0
+ IA64 little 16 0
+
+ size must be >= Alignment + LookAhead, if it's not last block.
+ If (size < Alignment + LookAhead), converter returns 0.
+
+ Example:
+
+ UInt32 ip = 0;
+ for ()
+ {
+ ; size must be >= Alignment + LookAhead, if it's not last block
+ SizeT processed = Convert(data, size, ip, 1);
+ data += processed;
+ size -= processed;
+ ip += processed;
+ }
+*/
+
+#define x86_Convert_Init(state) { state = 0; }
+SizeT x86_Convert(Byte *data, SizeT size, UInt32 ip, UInt32 *state, int encoding);
+SizeT ARM_Convert(Byte *data, SizeT size, UInt32 ip, int encoding);
+SizeT ARMT_Convert(Byte *data, SizeT size, UInt32 ip, int encoding);
+SizeT PPC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding);
+SizeT SPARC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding);
+SizeT IA64_Convert(Byte *data, SizeT size, UInt32 ip, int encoding);
+
+#endif
diff --git a/Core/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/Bra86.c b/Core/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/Bra86.c
new file mode 100644
index 0000000000..93566cb212
--- /dev/null
+++ b/Core/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/Bra86.c
@@ -0,0 +1,85 @@
+/* Bra86.c -- Converter for x86 code (BCJ)
+2008-10-04 : Igor Pavlov : Public domain */
+
+#include "Bra.h"
+
+#define Test86MSByte(b) ((b) == 0 || (b) == 0xFF)
+
+const Byte kMaskToAllowedStatus[8] = {1, 1, 1, 0, 1, 0, 0, 0};
+const Byte kMaskToBitNumber[8] = {0, 1, 2, 2, 3, 3, 3, 3};
+
+SizeT x86_Convert(Byte *data, SizeT size, UInt32 ip, UInt32 *state, int encoding)
+{
+ SizeT bufferPos = 0, prevPosT;
+ UInt32 prevMask = *state & 0x7;
+ if (size < 5)
+ return 0;
+ ip += 5;
+ prevPosT = (SizeT)0 - 1;
+
+ for (;;)
+ {
+ Byte *p = data + bufferPos;
+ Byte *limit = data + size - 4;
+ for (; p < limit; p++)
+ if ((*p & 0xFE) == 0xE8)
+ break;
+ bufferPos = (SizeT)(p - data);
+ if (p >= limit)
+ break;
+ prevPosT = bufferPos - prevPosT;
+ if (prevPosT > 3)
+ prevMask = 0;
+ else
+ {
+ prevMask = (prevMask << ((int)prevPosT - 1)) & 0x7;
+ if (prevMask != 0)
+ {
+ Byte b = p[4 - kMaskToBitNumber[prevMask]];
+ if (!kMaskToAllowedStatus[prevMask] || Test86MSByte(b))
+ {
+ prevPosT = bufferPos;
+ prevMask = ((prevMask << 1) & 0x7) | 1;
+ bufferPos++;
+ continue;
+ }
+ }
+ }
+ prevPosT = bufferPos;
+
+ if (Test86MSByte(p[4]))
+ {
+ UInt32 src = ((UInt32)p[4] << 24) | ((UInt32)p[3] << 16) | ((UInt32)p[2] << 8) | ((UInt32)p[1]);
+ UInt32 dest;
+ for (;;)
+ {
+ Byte b;
+ int index;
+ if (encoding)
+ dest = (ip + (UInt32)bufferPos) + src;
+ else
+ dest = src - (ip + (UInt32)bufferPos);
+ if (prevMask == 0)
+ break;
+ index = kMaskToBitNumber[prevMask] * 8;
+ b = (Byte)(dest >> (24 - index));
+ if (!Test86MSByte(b))
+ break;
+ src = dest ^ ((1 << (32 - index)) - 1);
+ }
+ p[4] = (Byte)(~(((dest >> 24) & 1) - 1));
+ p[3] = (Byte)(dest >> 16);
+ p[2] = (Byte)(dest >> 8);
+ p[1] = (Byte)dest;
+ bufferPos += 5;
+ }
+ else
+ {
+ prevMask = ((prevMask << 1) & 0x7) | 1;
+ bufferPos++;
+ }
+ }
+ prevPosT = bufferPos - prevPosT;
+ *state = ((prevPosT > 3) ? 0 : ((prevMask << ((int)prevPosT - 1)) & 0x7));
+ return bufferPos;
+}
diff --git a/Core/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/CpuArch.h b/Core/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/CpuArch.h
new file mode 100644
index 0000000000..006361f2f2
--- /dev/null
+++ b/Core/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/CpuArch.h
@@ -0,0 +1,69 @@
+/* CpuArch.h
+2008-08-05
+Igor Pavlov
+Public domain */
+
+#ifndef __CPUARCH_H
+#define __CPUARCH_H
+
+/*
+LITTLE_ENDIAN_UNALIGN means:
+ 1) CPU is LITTLE_ENDIAN
+ 2) it's allowed to make unaligned memory accesses
+if LITTLE_ENDIAN_UNALIGN is not defined, it means that we don't know
+about these properties of platform.
+*/
+
+#if defined(_M_IX86) || defined(_M_X64) || defined(_M_AMD64) || defined(__i386__) || defined(__x86_64__)
+#define LITTLE_ENDIAN_UNALIGN
+#endif
+
+#ifdef LITTLE_ENDIAN_UNALIGN
+
+#define GetUi16(p) (*(const UInt16 *)(p))
+#define GetUi32(p) (*(const UInt32 *)(p))
+#define GetUi64(p) (*(const UInt64 *)(p))
+#define SetUi32(p, d) *(UInt32 *)(p) = (d);
+
+#else
+
+#define GetUi16(p) (((const Byte *)(p))[0] | ((UInt16)((const Byte *)(p))[1] << 8))
+
+#define GetUi32(p) ( \
+ ((const Byte *)(p))[0] | \
+ ((UInt32)((const Byte *)(p))[1] << 8) | \
+ ((UInt32)((const Byte *)(p))[2] << 16) | \
+ ((UInt32)((const Byte *)(p))[3] << 24))
+
+#define GetUi64(p) (GetUi32(p) | ((UInt64)GetUi32(((const Byte *)(p)) + 4) << 32))
+
+#define SetUi32(p, d) { UInt32 _x_ = (d); \
+ ((Byte *)(p))[0] = (Byte)_x_; \
+ ((Byte *)(p))[1] = (Byte)(_x_ >> 8); \
+ ((Byte *)(p))[2] = (Byte)(_x_ >> 16); \
+ ((Byte *)(p))[3] = (Byte)(_x_ >> 24); }
+
+#endif
+
+#if defined(LITTLE_ENDIAN_UNALIGN) && defined(_WIN64) && (_MSC_VER >= 1300)
+
+#pragma intrinsic(_byteswap_ulong)
+#pragma intrinsic(_byteswap_uint64)
+#define GetBe32(p) _byteswap_ulong(*(const UInt32 *)(const Byte *)(p))
+#define GetBe64(p) _byteswap_uint64(*(const UInt64 *)(const Byte *)(p))
+
+#else
+
+#define GetBe32(p) ( \
+ ((UInt32)((const Byte *)(p))[0] << 24) | \
+ ((UInt32)((const Byte *)(p))[1] << 16) | \
+ ((UInt32)((const Byte *)(p))[2] << 8) | \
+ ((const Byte *)(p))[3] )
+
+#define GetBe64(p) (((UInt64)GetBe32(p) << 32) | GetBe32(((const Byte *)(p)) + 4))
+
+#endif
+
+#define GetBe16(p) (((UInt16)((const Byte *)(p))[0] << 8) | ((const Byte *)(p))[1])
+
+#endif
diff --git a/Core/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/LzFind.c b/Core/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/LzFind.c
new file mode 100644
index 0000000000..492cea2e41
--- /dev/null
+++ b/Core/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/LzFind.c
@@ -0,0 +1,770 @@
+/** @file
+ LzFind.c
+
+ Based on LZMA SDK 4.65:
+ LzFind.c -- Match finder for LZ algorithms
+ 2008-10-04 : Igor Pavlov : Public domain
+
+ Copyright (c) 2009, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef EFIAPI
+
+#include <string.h>
+
+#endif // !EFIAPI
+
+#include "LzFind.h"
+#include "LzHash.h"
+
+#define kEmptyHashValue 0
+#define kMaxValForNormalize ((UInt32)0xFFFFFFFF)
+#define kNormalizeStepMin (1 << 10) /* it must be power of 2 */
+#define kNormalizeMask (~(kNormalizeStepMin - 1))
+#define kMaxHistorySize ((UInt32)3 << 30)
+
+#define kStartMaxLen 3
+
+static void LzInWindow_Free(CMatchFinder *p, ISzAlloc *alloc)
+{
+ if (!p->directInput)
+ {
+ alloc->Free(alloc, p->bufferBase);
+ p->bufferBase = 0;
+ }
+}
+
+/* keepSizeBefore + keepSizeAfter + keepSizeReserv must be < 4G) */
+
+static int LzInWindow_Create(CMatchFinder *p, UInt32 keepSizeReserv, ISzAlloc *alloc)
+{
+ UInt32 blockSize = p->keepSizeBefore + p->keepSizeAfter + keepSizeReserv;
+ if (p->directInput)
+ {
+ p->blockSize = blockSize;
+ return 1;
+ }
+ if (p->bufferBase == 0 || p->blockSize != blockSize)
+ {
+ LzInWindow_Free(p, alloc);
+ p->blockSize = blockSize;
+ p->bufferBase = (Byte *)alloc->Alloc(alloc, (size_t)blockSize);
+ }
+ return (p->bufferBase != 0);
+}
+
+Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) { return p->buffer; }
+Byte MatchFinder_GetIndexByte(CMatchFinder *p, Int32 index) { return p->buffer[index]; }
+
+UInt32 MatchFinder_GetNumAvailableBytes(CMatchFinder *p) { return p->streamPos - p->pos; }
+
+void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue)
+{
+ p->posLimit -= subValue;
+ p->pos -= subValue;
+ p->streamPos -= subValue;
+}
+
+static void MatchFinder_ReadBlock(CMatchFinder *p)
+{
+ if (p->streamEndWasReached || p->result != SZ_OK)
+ return;
+ for (;;)
+ {
+ Byte *dest = p->buffer + (p->streamPos - p->pos);
+ size_t size = (p->bufferBase + p->blockSize - dest);
+ if (size == 0)
+ return;
+ p->result = p->stream->Read(p->stream, dest, &size);
+ if (p->result != SZ_OK)
+ return;
+ if (size == 0)
+ {
+ p->streamEndWasReached = 1;
+ return;
+ }
+ p->streamPos += (UInt32)size;
+ if (p->streamPos - p->pos > p->keepSizeAfter)
+ return;
+ }
+}
+
+void MatchFinder_MoveBlock(CMatchFinder *p)
+{
+ memmove(p->bufferBase,
+ p->buffer - p->keepSizeBefore,
+ (size_t)(p->streamPos - p->pos + p->keepSizeBefore));
+ p->buffer = p->bufferBase + p->keepSizeBefore;
+}
+
+int MatchFinder_NeedMove(CMatchFinder *p)
+{
+ /* if (p->streamEndWasReached) return 0; */
+ return ((size_t)(p->bufferBase + p->blockSize - p->buffer) <= p->keepSizeAfter);
+}
+
+void MatchFinder_ReadIfRequired(CMatchFinder *p)
+{
+ if (p->streamEndWasReached)
+ return;
+ if (p->keepSizeAfter >= p->streamPos - p->pos)
+ MatchFinder_ReadBlock(p);
+}
+
+static void MatchFinder_CheckAndMoveAndRead(CMatchFinder *p)
+{
+ if (MatchFinder_NeedMove(p))
+ MatchFinder_MoveBlock(p);
+ MatchFinder_ReadBlock(p);
+}
+
+static void MatchFinder_SetDefaultSettings(CMatchFinder *p)
+{
+ p->cutValue = 32;
+ p->btMode = 1;
+ p->numHashBytes = 4;
+ /* p->skipModeBits = 0; */
+ p->directInput = 0;
+ p->bigHash = 0;
+}
+
+#define kCrcPoly 0xEDB88320
+
+void MatchFinder_Construct(CMatchFinder *p)
+{
+ UInt32 i;
+ p->bufferBase = 0;
+ p->directInput = 0;
+ p->hash = 0;
+ MatchFinder_SetDefaultSettings(p);
+
+ for (i = 0; i < 256; i++)
+ {
+ UInt32 r = i;
+ int j;
+ for (j = 0; j < 8; j++)
+ r = (r >> 1) ^ (kCrcPoly & ~((r & 1) - 1));
+ p->crc[i] = r;
+ }
+}
+
+static void MatchFinder_FreeThisClassMemory(CMatchFinder *p, ISzAlloc *alloc)
+{
+ alloc->Free(alloc, p->hash);
+ p->hash = 0;
+}
+
+void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc)
+{
+ MatchFinder_FreeThisClassMemory(p, alloc);
+ LzInWindow_Free(p, alloc);
+}
+
+static CLzRef* AllocRefs(UInt32 num, ISzAlloc *alloc)
+{
+ size_t sizeInBytes = (size_t)num * sizeof(CLzRef);
+ if (sizeInBytes / sizeof(CLzRef) != num)
+ return 0;
+ return (CLzRef *)alloc->Alloc(alloc, sizeInBytes);
+}
+
+int MatchFinder_Create(CMatchFinder *p, UInt32 historySize,
+ UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter,
+ ISzAlloc *alloc)
+{
+ UInt32 sizeReserv;
+ if (historySize > kMaxHistorySize)
+ {
+ MatchFinder_Free(p, alloc);
+ return 0;
+ }
+ sizeReserv = historySize >> 1;
+ if (historySize > ((UInt32)2 << 30))
+ sizeReserv = historySize >> 2;
+ sizeReserv += (keepAddBufferBefore + matchMaxLen + keepAddBufferAfter) / 2 + (1 << 19);
+
+ p->keepSizeBefore = historySize + keepAddBufferBefore + 1;
+ p->keepSizeAfter = matchMaxLen + keepAddBufferAfter;
+ /* we need one additional byte, since we use MoveBlock after pos++ and before dictionary using */
+ if (LzInWindow_Create(p, sizeReserv, alloc))
+ {
+ UInt32 newCyclicBufferSize = (historySize /* >> p->skipModeBits */) + 1;
+ UInt32 hs;
+ p->matchMaxLen = matchMaxLen;
+ {
+ p->fixedHashSize = 0;
+ if (p->numHashBytes == 2)
+ hs = (1 << 16) - 1;
+ else
+ {
+ hs = historySize - 1;
+ hs |= (hs >> 1);
+ hs |= (hs >> 2);
+ hs |= (hs >> 4);
+ hs |= (hs >> 8);
+ hs >>= 1;
+ /* hs >>= p->skipModeBits; */
+ hs |= 0xFFFF; /* don't change it! It's required for Deflate */
+ if (hs > (1 << 24))
+ {
+ if (p->numHashBytes == 3)
+ hs = (1 << 24) - 1;
+ else
+ hs >>= 1;
+ }
+ }
+ p->hashMask = hs;
+ hs++;
+ if (p->numHashBytes > 2) p->fixedHashSize += kHash2Size;
+ if (p->numHashBytes > 3) p->fixedHashSize += kHash3Size;
+ if (p->numHashBytes > 4) p->fixedHashSize += kHash4Size;
+ hs += p->fixedHashSize;
+ }
+
+ {
+ UInt32 prevSize = p->hashSizeSum + p->numSons;
+ UInt32 newSize;
+ p->historySize = historySize;
+ p->hashSizeSum = hs;
+ p->cyclicBufferSize = newCyclicBufferSize;
+ p->numSons = (p->btMode ? newCyclicBufferSize * 2 : newCyclicBufferSize);
+ newSize = p->hashSizeSum + p->numSons;
+ if (p->hash != 0 && prevSize == newSize)
+ return 1;
+ MatchFinder_FreeThisClassMemory(p, alloc);
+ p->hash = AllocRefs(newSize, alloc);
+ if (p->hash != 0)
+ {
+ p->son = p->hash + p->hashSizeSum;
+ return 1;
+ }
+ }
+ }
+ MatchFinder_Free(p, alloc);
+ return 0;
+}
+
+static void MatchFinder_SetLimits(CMatchFinder *p)
+{
+ UInt32 limit = kMaxValForNormalize - p->pos;
+ UInt32 limit2 = p->cyclicBufferSize - p->cyclicBufferPos;
+ if (limit2 < limit)
+ limit = limit2;
+ limit2 = p->streamPos - p->pos;
+ if (limit2 <= p->keepSizeAfter)
+ {
+ if (limit2 > 0)
+ limit2 = 1;
+ }
+ else
+ limit2 -= p->keepSizeAfter;
+ if (limit2 < limit)
+ limit = limit2;
+ {
+ UInt32 lenLimit = p->streamPos - p->pos;
+ if (lenLimit > p->matchMaxLen)
+ lenLimit = p->matchMaxLen;
+ p->lenLimit = lenLimit;
+ }
+ p->posLimit = p->pos + limit;
+}
+
+void MatchFinder_Init(CMatchFinder *p)
+{
+ UInt32 i;
+ for (i = 0; i < p->hashSizeSum; i++)
+ p->hash[i] = kEmptyHashValue;
+ p->cyclicBufferPos = 0;
+ p->buffer = p->bufferBase;
+ p->pos = p->streamPos = p->cyclicBufferSize;
+ p->result = SZ_OK;
+ p->streamEndWasReached = 0;
+ MatchFinder_ReadBlock(p);
+ MatchFinder_SetLimits(p);
+}
+
+static UInt32 MatchFinder_GetSubValue(CMatchFinder *p)
+{
+ return (p->pos - p->historySize - 1) & kNormalizeMask;
+}
+
+void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems)
+{
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ {
+ UInt32 value = items[i];
+ if (value <= subValue)
+ value = kEmptyHashValue;
+ else
+ value -= subValue;
+ items[i] = value;
+ }
+}
+
+static void MatchFinder_Normalize(CMatchFinder *p)
+{
+ UInt32 subValue = MatchFinder_GetSubValue(p);
+ MatchFinder_Normalize3(subValue, p->hash, p->hashSizeSum + p->numSons);
+ MatchFinder_ReduceOffsets(p, subValue);
+}
+
+static void MatchFinder_CheckLimits(CMatchFinder *p)
+{
+ if (p->pos == kMaxValForNormalize)
+ MatchFinder_Normalize(p);
+ if (!p->streamEndWasReached && p->keepSizeAfter == p->streamPos - p->pos)
+ MatchFinder_CheckAndMoveAndRead(p);
+ if (p->cyclicBufferPos == p->cyclicBufferSize)
+ p->cyclicBufferPos = 0;
+ MatchFinder_SetLimits(p);
+}
+
+static UInt32 * Hc_GetMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
+ UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue,
+ UInt32 *distances, UInt32 maxLen)
+{
+ son[_cyclicBufferPos] = curMatch;
+ for (;;)
+ {
+ UInt32 delta = pos - curMatch;
+ if (cutValue-- == 0 || delta >= _cyclicBufferSize)
+ return distances;
+ {
+ const Byte *pb = cur - delta;
+ curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)];
+ if (pb[maxLen] == cur[maxLen] && *pb == *cur)
+ {
+ UInt32 len = 0;
+ while (++len != lenLimit)
+ if (pb[len] != cur[len])
+ break;
+ if (maxLen < len)
+ {
+ *distances++ = maxLen = len;
+ *distances++ = delta - 1;
+ if (len == lenLimit)
+ return distances;
+ }
+ }
+ }
+ }
+}
+
+UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
+ UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue,
+ UInt32 *distances, UInt32 maxLen)
+{
+ CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1;
+ CLzRef *ptr1 = son + (_cyclicBufferPos << 1);
+ UInt32 len0 = 0, len1 = 0;
+ for (;;)
+ {
+ UInt32 delta = pos - curMatch;
+ if (cutValue-- == 0 || delta >= _cyclicBufferSize)
+ {
+ *ptr0 = *ptr1 = kEmptyHashValue;
+ return distances;
+ }
+ {
+ CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1);
+ const Byte *pb = cur - delta;
+ UInt32 len = (len0 < len1 ? len0 : len1);
+ if (pb[len] == cur[len])
+ {
+ if (++len != lenLimit && pb[len] == cur[len])
+ while (++len != lenLimit)
+ if (pb[len] != cur[len])
+ break;
+ if (maxLen < len)
+ {
+ *distances++ = maxLen = len;
+ *distances++ = delta - 1;
+ if (len == lenLimit)
+ {
+ *ptr1 = pair[0];
+ *ptr0 = pair[1];
+ return distances;
+ }
+ }
+ }
+ if (pb[len] < cur[len])
+ {
+ *ptr1 = curMatch;
+ ptr1 = pair + 1;
+ curMatch = *ptr1;
+ len1 = len;
+ }
+ else
+ {
+ *ptr0 = curMatch;
+ ptr0 = pair;
+ curMatch = *ptr0;
+ len0 = len;
+ }
+ }
+ }
+}
+
+static void SkipMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
+ UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue)
+{
+ CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1;
+ CLzRef *ptr1 = son + (_cyclicBufferPos << 1);
+ UInt32 len0 = 0, len1 = 0;
+ for (;;)
+ {
+ UInt32 delta = pos - curMatch;
+ if (cutValue-- == 0 || delta >= _cyclicBufferSize)
+ {
+ *ptr0 = *ptr1 = kEmptyHashValue;
+ return;
+ }
+ {
+ CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1);
+ const Byte *pb = cur - delta;
+ UInt32 len = (len0 < len1 ? len0 : len1);
+ if (pb[len] == cur[len])
+ {
+ while (++len != lenLimit)
+ if (pb[len] != cur[len])
+ break;
+ {
+ if (len == lenLimit)
+ {
+ *ptr1 = pair[0];
+ *ptr0 = pair[1];
+ return;
+ }
+ }
+ }
+ if (pb[len] < cur[len])
+ {
+ *ptr1 = curMatch;
+ ptr1 = pair + 1;
+ curMatch = *ptr1;
+ len1 = len;
+ }
+ else
+ {
+ *ptr0 = curMatch;
+ ptr0 = pair;
+ curMatch = *ptr0;
+ len0 = len;
+ }
+ }
+ }
+}
+
+#define MOVE_POS \
+ ++p->cyclicBufferPos; \
+ p->buffer++; \
+ if (++p->pos == p->posLimit) MatchFinder_CheckLimits(p);
+
+#define MOVE_POS_RET MOVE_POS return offset;
+
+static void MatchFinder_MovePos(CMatchFinder *p) { MOVE_POS; }
+
+#define GET_MATCHES_HEADER2(minLen, ret_op) \
+ UInt32 lenLimit; UInt32 hashValue; const Byte *cur; UInt32 curMatch; \
+ lenLimit = p->lenLimit; { if (lenLimit < minLen) { MatchFinder_MovePos(p); ret_op; }} \
+ cur = p->buffer;
+
+#define GET_MATCHES_HEADER(minLen) GET_MATCHES_HEADER2(minLen, return 0)
+#define SKIP_HEADER(minLen) GET_MATCHES_HEADER2(minLen, continue)
+
+#define MF_PARAMS(p) p->pos, p->buffer, p->son, p->cyclicBufferPos, p->cyclicBufferSize, p->cutValue
+
+#define GET_MATCHES_FOOTER(offset, maxLen) \
+ offset = (UInt32)(GetMatchesSpec1(lenLimit, curMatch, MF_PARAMS(p), \
+ distances + offset, maxLen) - distances); MOVE_POS_RET;
+
+#define SKIP_FOOTER \
+ SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); MOVE_POS;
+
+static UInt32 Bt2_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+ UInt32 offset;
+ GET_MATCHES_HEADER(2)
+ HASH2_CALC;
+ curMatch = p->hash[hashValue];
+ p->hash[hashValue] = p->pos;
+ offset = 0;
+ GET_MATCHES_FOOTER(offset, 1)
+}
+
+UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+ UInt32 offset;
+ GET_MATCHES_HEADER(3)
+ HASH_ZIP_CALC;
+ curMatch = p->hash[hashValue];
+ p->hash[hashValue] = p->pos;
+ offset = 0;
+ GET_MATCHES_FOOTER(offset, 2)
+}
+
+static UInt32 Bt3_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+ UInt32 hash2Value, delta2, maxLen, offset;
+ GET_MATCHES_HEADER(3)
+
+ HASH3_CALC;
+
+ delta2 = p->pos - p->hash[hash2Value];
+ curMatch = p->hash[kFix3HashSize + hashValue];
+
+ p->hash[hash2Value] =
+ p->hash[kFix3HashSize + hashValue] = p->pos;
+
+
+ maxLen = 2;
+ offset = 0;
+ if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
+ {
+ for (; maxLen != lenLimit; maxLen++)
+ if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
+ break;
+ distances[0] = maxLen;
+ distances[1] = delta2 - 1;
+ offset = 2;
+ if (maxLen == lenLimit)
+ {
+ SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p));
+ MOVE_POS_RET;
+ }
+ }
+ GET_MATCHES_FOOTER(offset, maxLen)
+}
+
+static UInt32 Bt4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+ UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset;
+ GET_MATCHES_HEADER(4)
+
+ HASH4_CALC;
+
+ delta2 = p->pos - p->hash[ hash2Value];
+ delta3 = p->pos - p->hash[kFix3HashSize + hash3Value];
+ curMatch = p->hash[kFix4HashSize + hashValue];
+
+ p->hash[ hash2Value] =
+ p->hash[kFix3HashSize + hash3Value] =
+ p->hash[kFix4HashSize + hashValue] = p->pos;
+
+ maxLen = 1;
+ offset = 0;
+ if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
+ {
+ distances[0] = maxLen = 2;
+ distances[1] = delta2 - 1;
+ offset = 2;
+ }
+ if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur)
+ {
+ maxLen = 3;
+ distances[offset + 1] = delta3 - 1;
+ offset += 2;
+ delta2 = delta3;
+ }
+ if (offset != 0)
+ {
+ for (; maxLen != lenLimit; maxLen++)
+ if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
+ break;
+ distances[offset - 2] = maxLen;
+ if (maxLen == lenLimit)
+ {
+ SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p));
+ MOVE_POS_RET;
+ }
+ }
+ if (maxLen < 3)
+ maxLen = 3;
+ GET_MATCHES_FOOTER(offset, maxLen)
+}
+
+static UInt32 Hc4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+ UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset;
+ GET_MATCHES_HEADER(4)
+
+ HASH4_CALC;
+
+ delta2 = p->pos - p->hash[ hash2Value];
+ delta3 = p->pos - p->hash[kFix3HashSize + hash3Value];
+ curMatch = p->hash[kFix4HashSize + hashValue];
+
+ p->hash[ hash2Value] =
+ p->hash[kFix3HashSize + hash3Value] =
+ p->hash[kFix4HashSize + hashValue] = p->pos;
+
+ maxLen = 1;
+ offset = 0;
+ if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
+ {
+ distances[0] = maxLen = 2;
+ distances[1] = delta2 - 1;
+ offset = 2;
+ }
+ if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur)
+ {
+ maxLen = 3;
+ distances[offset + 1] = delta3 - 1;
+ offset += 2;
+ delta2 = delta3;
+ }
+ if (offset != 0)
+ {
+ for (; maxLen != lenLimit; maxLen++)
+ if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
+ break;
+ distances[offset - 2] = maxLen;
+ if (maxLen == lenLimit)
+ {
+ p->son[p->cyclicBufferPos] = curMatch;
+ MOVE_POS_RET;
+ }
+ }
+ if (maxLen < 3)
+ maxLen = 3;
+ offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p),
+ distances + offset, maxLen) - (distances));
+ MOVE_POS_RET
+}
+
+UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+ UInt32 offset;
+ GET_MATCHES_HEADER(3)
+ HASH_ZIP_CALC;
+ curMatch = p->hash[hashValue];
+ p->hash[hashValue] = p->pos;
+ offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p),
+ distances, 2) - (distances));
+ MOVE_POS_RET
+}
+
+static void Bt2_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+ do
+ {
+ SKIP_HEADER(2)
+ HASH2_CALC;
+ curMatch = p->hash[hashValue];
+ p->hash[hashValue] = p->pos;
+ SKIP_FOOTER
+ }
+ while (--num != 0);
+}
+
+void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+ do
+ {
+ SKIP_HEADER(3)
+ HASH_ZIP_CALC;
+ curMatch = p->hash[hashValue];
+ p->hash[hashValue] = p->pos;
+ SKIP_FOOTER
+ }
+ while (--num != 0);
+}
+
+static void Bt3_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+ do
+ {
+ UInt32 hash2Value;
+ SKIP_HEADER(3)
+ HASH3_CALC;
+ curMatch = p->hash[kFix3HashSize + hashValue];
+ p->hash[hash2Value] =
+ p->hash[kFix3HashSize + hashValue] = p->pos;
+ SKIP_FOOTER
+ }
+ while (--num != 0);
+}
+
+static void Bt4_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+ do
+ {
+ UInt32 hash2Value, hash3Value;
+ SKIP_HEADER(4)
+ HASH4_CALC;
+ curMatch = p->hash[kFix4HashSize + hashValue];
+ p->hash[ hash2Value] =
+ p->hash[kFix3HashSize + hash3Value] = p->pos;
+ p->hash[kFix4HashSize + hashValue] = p->pos;
+ SKIP_FOOTER
+ }
+ while (--num != 0);
+}
+
+static void Hc4_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+ do
+ {
+ UInt32 hash2Value, hash3Value;
+ SKIP_HEADER(4)
+ HASH4_CALC;
+ curMatch = p->hash[kFix4HashSize + hashValue];
+ p->hash[ hash2Value] =
+ p->hash[kFix3HashSize + hash3Value] =
+ p->hash[kFix4HashSize + hashValue] = p->pos;
+ p->son[p->cyclicBufferPos] = curMatch;
+ MOVE_POS
+ }
+ while (--num != 0);
+}
+
+void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+ do
+ {
+ SKIP_HEADER(3)
+ HASH_ZIP_CALC;
+ curMatch = p->hash[hashValue];
+ p->hash[hashValue] = p->pos;
+ p->son[p->cyclicBufferPos] = curMatch;
+ MOVE_POS
+ }
+ while (--num != 0);
+}
+
+void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable)
+{
+ vTable->Init = (Mf_Init_Func)MatchFinder_Init;
+ vTable->GetIndexByte = (Mf_GetIndexByte_Func)MatchFinder_GetIndexByte;
+ vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinder_GetNumAvailableBytes;
+ vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinder_GetPointerToCurrentPos;
+ if (!p->btMode)
+ {
+ vTable->GetMatches = (Mf_GetMatches_Func)Hc4_MatchFinder_GetMatches;
+ vTable->Skip = (Mf_Skip_Func)Hc4_MatchFinder_Skip;
+ }
+ else if (p->numHashBytes == 2)
+ {
+ vTable->GetMatches = (Mf_GetMatches_Func)Bt2_MatchFinder_GetMatches;
+ vTable->Skip = (Mf_Skip_Func)Bt2_MatchFinder_Skip;
+ }
+ else if (p->numHashBytes == 3)
+ {
+ vTable->GetMatches = (Mf_GetMatches_Func)Bt3_MatchFinder_GetMatches;
+ vTable->Skip = (Mf_Skip_Func)Bt3_MatchFinder_Skip;
+ }
+ else
+ {
+ vTable->GetMatches = (Mf_GetMatches_Func)Bt4_MatchFinder_GetMatches;
+ vTable->Skip = (Mf_Skip_Func)Bt4_MatchFinder_Skip;
+ }
+}
diff --git a/Core/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/LzFind.h b/Core/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/LzFind.h
new file mode 100644
index 0000000000..423d67e0c3
--- /dev/null
+++ b/Core/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/LzFind.h
@@ -0,0 +1,107 @@
+/* LzFind.h -- Match finder for LZ algorithms
+2008-10-04 : Igor Pavlov : Public domain */
+
+#ifndef __LZFIND_H
+#define __LZFIND_H
+
+#include "Types.h"
+
+typedef UInt32 CLzRef;
+
+typedef struct _CMatchFinder
+{
+ Byte *buffer;
+ UInt32 pos;
+ UInt32 posLimit;
+ UInt32 streamPos;
+ UInt32 lenLimit;
+
+ UInt32 cyclicBufferPos;
+ UInt32 cyclicBufferSize; /* it must be = (historySize + 1) */
+
+ UInt32 matchMaxLen;
+ CLzRef *hash;
+ CLzRef *son;
+ UInt32 hashMask;
+ UInt32 cutValue;
+
+ Byte *bufferBase;
+ ISeqInStream *stream;
+ int streamEndWasReached;
+
+ UInt32 blockSize;
+ UInt32 keepSizeBefore;
+ UInt32 keepSizeAfter;
+
+ UInt32 numHashBytes;
+ int directInput;
+ int btMode;
+ /* int skipModeBits; */
+ int bigHash;
+ UInt32 historySize;
+ UInt32 fixedHashSize;
+ UInt32 hashSizeSum;
+ UInt32 numSons;
+ SRes result;
+ UInt32 crc[256];
+} CMatchFinder;
+
+#define Inline_MatchFinder_GetPointerToCurrentPos(p) ((p)->buffer)
+#define Inline_MatchFinder_GetIndexByte(p, index) ((p)->buffer[(Int32)(index)])
+
+#define Inline_MatchFinder_GetNumAvailableBytes(p) ((p)->streamPos - (p)->pos)
+
+int MatchFinder_NeedMove(CMatchFinder *p);
+Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p);
+void MatchFinder_MoveBlock(CMatchFinder *p);
+void MatchFinder_ReadIfRequired(CMatchFinder *p);
+
+void MatchFinder_Construct(CMatchFinder *p);
+
+/* Conditions:
+ historySize <= 3 GB
+ keepAddBufferBefore + matchMaxLen + keepAddBufferAfter < 511MB
+*/
+int MatchFinder_Create(CMatchFinder *p, UInt32 historySize,
+ UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter,
+ ISzAlloc *alloc);
+void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc);
+void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems);
+void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue);
+
+UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *buffer, CLzRef *son,
+ UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue,
+ UInt32 *distances, UInt32 maxLen);
+
+/*
+Conditions:
+ Mf_GetNumAvailableBytes_Func must be called before each Mf_GetMatchLen_Func.
+ Mf_GetPointerToCurrentPos_Func's result must be used only before any other function
+*/
+
+typedef void (*Mf_Init_Func)(void *object);
+typedef Byte (*Mf_GetIndexByte_Func)(void *object, Int32 index);
+typedef UInt32 (*Mf_GetNumAvailableBytes_Func)(void *object);
+typedef const Byte * (*Mf_GetPointerToCurrentPos_Func)(void *object);
+typedef UInt32 (*Mf_GetMatches_Func)(void *object, UInt32 *distances);
+typedef void (*Mf_Skip_Func)(void *object, UInt32);
+
+typedef struct _IMatchFinder
+{
+ Mf_Init_Func Init;
+ Mf_GetIndexByte_Func GetIndexByte;
+ Mf_GetNumAvailableBytes_Func GetNumAvailableBytes;
+ Mf_GetPointerToCurrentPos_Func GetPointerToCurrentPos;
+ Mf_GetMatches_Func GetMatches;
+ Mf_Skip_Func Skip;
+} IMatchFinder;
+
+void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable);
+
+void MatchFinder_Init(CMatchFinder *p);
+UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances);
+UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances);
+void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num);
+void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num);
+
+#endif
diff --git a/Core/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/LzHash.h b/Core/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/LzHash.h
new file mode 100644
index 0000000000..c923417501
--- /dev/null
+++ b/Core/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/LzHash.h
@@ -0,0 +1,54 @@
+/* LzHash.h -- HASH functions for LZ algorithms
+2008-10-04 : Igor Pavlov : Public domain */
+
+#ifndef __LZHASH_H
+#define __LZHASH_H
+
+#define kHash2Size (1 << 10)
+#define kHash3Size (1 << 16)
+#define kHash4Size (1 << 20)
+
+#define kFix3HashSize (kHash2Size)
+#define kFix4HashSize (kHash2Size + kHash3Size)
+#define kFix5HashSize (kHash2Size + kHash3Size + kHash4Size)
+
+#define HASH2_CALC hashValue = cur[0] | ((UInt32)cur[1] << 8);
+
+#define HASH3_CALC { \
+ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
+ hash2Value = temp & (kHash2Size - 1); \
+ hashValue = (temp ^ ((UInt32)cur[2] << 8)) & p->hashMask; }
+
+#define HASH4_CALC { \
+ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
+ hash2Value = temp & (kHash2Size - 1); \
+ hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \
+ hashValue = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)) & p->hashMask; }
+
+#define HASH5_CALC { \
+ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
+ hash2Value = temp & (kHash2Size - 1); \
+ hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \
+ hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)); \
+ hashValue = (hash4Value ^ (p->crc[cur[4]] << 3)) & p->hashMask; \
+ hash4Value &= (kHash4Size - 1); }
+
+/* #define HASH_ZIP_CALC hashValue = ((cur[0] | ((UInt32)cur[1] << 8)) ^ p->crc[cur[2]]) & 0xFFFF; */
+#define HASH_ZIP_CALC hashValue = ((cur[2] | ((UInt32)cur[0] << 8)) ^ p->crc[cur[1]]) & 0xFFFF;
+
+
+#define MT_HASH2_CALC \
+ hash2Value = (p->crc[cur[0]] ^ cur[1]) & (kHash2Size - 1);
+
+#define MT_HASH3_CALC { \
+ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
+ hash2Value = temp & (kHash2Size - 1); \
+ hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); }
+
+#define MT_HASH4_CALC { \
+ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
+ hash2Value = temp & (kHash2Size - 1); \
+ hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \
+ hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)) & (kHash4Size - 1); }
+
+#endif
diff --git a/Core/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/LzmaDec.c b/Core/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/LzmaDec.c
new file mode 100644
index 0000000000..e3db4edbb4
--- /dev/null
+++ b/Core/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/LzmaDec.c
@@ -0,0 +1,1026 @@
+/** @file
+ LzmaDec.c
+
+ Based on LZMA SDK 4.65:
+ LzmaDec.c -- LZMA Decoder
+ 2008-11-06 : Igor Pavlov : Public domain
+
+ Copyright (c) 2009, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "LzmaDec.h"
+
+#ifndef EFIAPI
+
+#include <string.h>
+
+#endif // !EFIAPI
+
+#define kNumTopBits 24
+#define kTopValue ((UInt32)1 << kNumTopBits)
+
+#define kNumBitModelTotalBits 11
+#define kBitModelTotal (1 << kNumBitModelTotalBits)
+#define kNumMoveBits 5
+
+#define RC_INIT_SIZE 5
+
+#define NORMALIZE if (range < kTopValue) { range <<= 8; code = (code << 8) | (*buf++); }
+
+#define IF_BIT_0(p) ttt = *(p); NORMALIZE; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound)
+#define UPDATE_0(p) range = bound; *(p) = (CLzmaProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits));
+#define UPDATE_1(p) range -= bound; code -= bound; *(p) = (CLzmaProb)(ttt - (ttt >> kNumMoveBits));
+#define GET_BIT2(p, i, A0, A1) IF_BIT_0(p) \
+ { UPDATE_0(p); i = (i + i); A0; } else \
+ { UPDATE_1(p); i = (i + i) + 1; A1; }
+#define GET_BIT(p, i) GET_BIT2(p, i, ; , ;)
+
+#define TREE_GET_BIT(probs, i) { GET_BIT((probs + i), i); }
+#define TREE_DECODE(probs, limit, i) \
+ { i = 1; do { TREE_GET_BIT(probs, i); } while (i < limit); i -= limit; }
+
+/* #define _LZMA_SIZE_OPT */
+
+#ifdef _LZMA_SIZE_OPT
+#define TREE_6_DECODE(probs, i) TREE_DECODE(probs, (1 << 6), i)
+#else
+#define TREE_6_DECODE(probs, i) \
+ { i = 1; \
+ TREE_GET_BIT(probs, i); \
+ TREE_GET_BIT(probs, i); \
+ TREE_GET_BIT(probs, i); \
+ TREE_GET_BIT(probs, i); \
+ TREE_GET_BIT(probs, i); \
+ TREE_GET_BIT(probs, i); \
+ i -= 0x40; }
+#endif
+
+#define NORMALIZE_CHECK if (range < kTopValue) { if (buf >= bufLimit) return DUMMY_ERROR; range <<= 8; code = (code << 8) | (*buf++); }
+
+#define IF_BIT_0_CHECK(p) ttt = *(p); NORMALIZE_CHECK; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound)
+#define UPDATE_0_CHECK range = bound;
+#define UPDATE_1_CHECK range -= bound; code -= bound;
+#define GET_BIT2_CHECK(p, i, A0, A1) IF_BIT_0_CHECK(p) \
+ { UPDATE_0_CHECK; i = (i + i); A0; } else \
+ { UPDATE_1_CHECK; i = (i + i) + 1; A1; }
+#define GET_BIT_CHECK(p, i) GET_BIT2_CHECK(p, i, ; , ;)
+#define TREE_DECODE_CHECK(probs, limit, i) \
+ { i = 1; do { GET_BIT_CHECK(probs + i, i) } while (i < limit); i -= limit; }
+
+
+#define kNumPosBitsMax 4
+#define kNumPosStatesMax (1 << kNumPosBitsMax)
+
+#define kLenNumLowBits 3
+#define kLenNumLowSymbols (1 << kLenNumLowBits)
+#define kLenNumMidBits 3
+#define kLenNumMidSymbols (1 << kLenNumMidBits)
+#define kLenNumHighBits 8
+#define kLenNumHighSymbols (1 << kLenNumHighBits)
+
+#define LenChoice 0
+#define LenChoice2 (LenChoice + 1)
+#define LenLow (LenChoice2 + 1)
+#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits))
+#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits))
+#define kNumLenProbs (LenHigh + kLenNumHighSymbols)
+
+
+#define kNumStates 12
+#define kNumLitStates 7
+
+#define kStartPosModelIndex 4
+#define kEndPosModelIndex 14
+#define kNumFullDistances (1 << (kEndPosModelIndex >> 1))
+
+#define kNumPosSlotBits 6
+#define kNumLenToPosStates 4
+
+#define kNumAlignBits 4
+#define kAlignTableSize (1 << kNumAlignBits)
+
+#define kMatchMinLen 2
+#define kMatchSpecLenStart (kMatchMinLen + kLenNumLowSymbols + kLenNumMidSymbols + kLenNumHighSymbols)
+
+#define IsMatch 0
+#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax))
+#define IsRepG0 (IsRep + kNumStates)
+#define IsRepG1 (IsRepG0 + kNumStates)
+#define IsRepG2 (IsRepG1 + kNumStates)
+#define IsRep0Long (IsRepG2 + kNumStates)
+#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax))
+#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits))
+#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex)
+#define LenCoder (Align + kAlignTableSize)
+#define RepLenCoder (LenCoder + kNumLenProbs)
+#define Literal (RepLenCoder + kNumLenProbs)
+
+#define LZMA_BASE_SIZE 1846
+#define LZMA_LIT_SIZE 768
+
+#define LzmaProps_GetNumProbs(p) ((UInt32)LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((p)->lc + (p)->lp)))
+
+#if Literal != LZMA_BASE_SIZE
+StopCompilingDueBUG
+#endif
+
+static const Byte kLiteralNextStates[kNumStates * 2] =
+{
+ 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5,
+ 7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10
+};
+
+#define LZMA_DIC_MIN (1 << 12)
+
+/* First LZMA-symbol is always decoded.
+And it decodes new LZMA-symbols while (buf < bufLimit), but "buf" is without last normalization
+Out:
+ Result:
+ SZ_OK - OK
+ SZ_ERROR_DATA - Error
+ p->remainLen:
+ < kMatchSpecLenStart : normal remain
+ = kMatchSpecLenStart : finished
+ = kMatchSpecLenStart + 1 : Flush marker
+ = kMatchSpecLenStart + 2 : State Init Marker
+*/
+
+static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte *bufLimit)
+{
+ CLzmaProb *probs = p->probs;
+
+ unsigned state = p->state;
+ UInt32 rep0 = p->reps[0], rep1 = p->reps[1], rep2 = p->reps[2], rep3 = p->reps[3];
+ unsigned pbMask = ((unsigned)1 << (p->prop.pb)) - 1;
+ unsigned lpMask = ((unsigned)1 << (p->prop.lp)) - 1;
+ unsigned lc = p->prop.lc;
+
+ Byte *dic = p->dic;
+ SizeT dicBufSize = p->dicBufSize;
+ SizeT dicPos = p->dicPos;
+
+ UInt32 processedPos = p->processedPos;
+ UInt32 checkDicSize = p->checkDicSize;
+ unsigned len = 0;
+
+ const Byte *buf = p->buf;
+ UInt32 range = p->range;
+ UInt32 code = p->code;
+
+ do
+ {
+ CLzmaProb *prob;
+ UInt32 bound;
+ unsigned ttt;
+ unsigned posState = processedPos & pbMask;
+
+ prob = probs + IsMatch + (state << kNumPosBitsMax) + posState;
+ IF_BIT_0(prob)
+ {
+ unsigned symbol;
+ UPDATE_0(prob);
+ prob = probs + Literal;
+ if (checkDicSize != 0 || processedPos != 0)
+ prob += (LZMA_LIT_SIZE * (((processedPos & lpMask) << lc) +
+ (dic[(dicPos == 0 ? dicBufSize : dicPos) - 1] >> (8 - lc))));
+
+ if (state < kNumLitStates)
+ {
+ symbol = 1;
+ do { GET_BIT(prob + symbol, symbol) } while (symbol < 0x100);
+ }
+ else
+ {
+ unsigned matchByte = p->dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)];
+ unsigned offs = 0x100;
+ symbol = 1;
+ do
+ {
+ unsigned bit;
+ CLzmaProb *probLit;
+ matchByte <<= 1;
+ bit = (matchByte & offs);
+ probLit = prob + offs + bit + symbol;
+ GET_BIT2(probLit, symbol, offs &= ~bit, offs &= bit)
+ }
+ while (symbol < 0x100);
+ }
+ dic[dicPos++] = (Byte)symbol;
+ processedPos++;
+
+ state = kLiteralNextStates[state];
+ /* if (state < 4) state = 0; else if (state < 10) state -= 3; else state -= 6; */
+ continue;
+ }
+ else
+ {
+ UPDATE_1(prob);
+ prob = probs + IsRep + state;
+ IF_BIT_0(prob)
+ {
+ UPDATE_0(prob);
+ state += kNumStates;
+ prob = probs + LenCoder;
+ }
+ else
+ {
+ UPDATE_1(prob);
+ if (checkDicSize == 0 && processedPos == 0)
+ return SZ_ERROR_DATA;
+ prob = probs + IsRepG0 + state;
+ IF_BIT_0(prob)
+ {
+ UPDATE_0(prob);
+ prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState;
+ IF_BIT_0(prob)
+ {
+ UPDATE_0(prob);
+ dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)];
+ dicPos++;
+ processedPos++;
+ state = state < kNumLitStates ? 9 : 11;
+ continue;
+ }
+ UPDATE_1(prob);
+ }
+ else
+ {
+ UInt32 distance;
+ UPDATE_1(prob);
+ prob = probs + IsRepG1 + state;
+ IF_BIT_0(prob)
+ {
+ UPDATE_0(prob);
+ distance = rep1;
+ }
+ else
+ {
+ UPDATE_1(prob);
+ prob = probs + IsRepG2 + state;
+ IF_BIT_0(prob)
+ {
+ UPDATE_0(prob);
+ distance = rep2;
+ }
+ else
+ {
+ UPDATE_1(prob);
+ distance = rep3;
+ rep3 = rep2;
+ }
+ rep2 = rep1;
+ }
+ rep1 = rep0;
+ rep0 = distance;
+ }
+ state = state < kNumLitStates ? 8 : 11;
+ prob = probs + RepLenCoder;
+ }
+ {
+ unsigned limit2, offset;
+ CLzmaProb *probLen = prob + LenChoice;
+ IF_BIT_0(probLen)
+ {
+ UPDATE_0(probLen);
+ probLen = prob + LenLow + (posState << kLenNumLowBits);
+ offset = 0;
+ limit2 = (1 << kLenNumLowBits);
+ }
+ else
+ {
+ UPDATE_1(probLen);
+ probLen = prob + LenChoice2;
+ IF_BIT_0(probLen)
+ {
+ UPDATE_0(probLen);
+ probLen = prob + LenMid + (posState << kLenNumMidBits);
+ offset = kLenNumLowSymbols;
+ limit2 = (1 << kLenNumMidBits);
+ }
+ else
+ {
+ UPDATE_1(probLen);
+ probLen = prob + LenHigh;
+ offset = kLenNumLowSymbols + kLenNumMidSymbols;
+ limit2 = (1 << kLenNumHighBits);
+ }
+ }
+ TREE_DECODE(probLen, limit2, len);
+ len += offset;
+ }
+
+ if (state >= kNumStates)
+ {
+ UInt32 distance;
+ prob = probs + PosSlot +
+ ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << kNumPosSlotBits);
+ TREE_6_DECODE(prob, distance);
+ if (distance >= kStartPosModelIndex)
+ {
+ unsigned posSlot = (unsigned)distance;
+ int numDirectBits = (int)(((distance >> 1) - 1));
+ distance = (2 | (distance & 1));
+ if (posSlot < kEndPosModelIndex)
+ {
+ distance <<= numDirectBits;
+ prob = probs + SpecPos + distance - posSlot - 1;
+ {
+ UInt32 mask = 1;
+ unsigned i = 1;
+ do
+ {
+ GET_BIT2(prob + i, i, ; , distance |= mask);
+ mask <<= 1;
+ }
+ while (--numDirectBits != 0);
+ }
+ }
+ else
+ {
+ numDirectBits -= kNumAlignBits;
+ do
+ {
+ NORMALIZE
+ range >>= 1;
+
+ {
+ UInt32 t;
+ code -= range;
+ t = (0 - ((UInt32)code >> 31)); /* (UInt32)((Int32)code >> 31) */
+ distance = (distance << 1) + (t + 1);
+ code += range & t;
+ }
+ /*
+ distance <<= 1;
+ if (code >= range)
+ {
+ code -= range;
+ distance |= 1;
+ }
+ */
+ }
+ while (--numDirectBits != 0);
+ prob = probs + Align;
+ distance <<= kNumAlignBits;
+ {
+ unsigned i = 1;
+ GET_BIT2(prob + i, i, ; , distance |= 1);
+ GET_BIT2(prob + i, i, ; , distance |= 2);
+ GET_BIT2(prob + i, i, ; , distance |= 4);
+ GET_BIT2(prob + i, i, ; , distance |= 8);
+ }
+ if (distance == (UInt32)0xFFFFFFFF)
+ {
+ len += kMatchSpecLenStart;
+ state -= kNumStates;
+ break;
+ }
+ }
+ }
+ rep3 = rep2;
+ rep2 = rep1;
+ rep1 = rep0;
+ rep0 = distance + 1;
+ if (checkDicSize == 0)
+ {
+ if (distance >= processedPos)
+ return SZ_ERROR_DATA;
+ }
+ else if (distance >= checkDicSize)
+ return SZ_ERROR_DATA;
+ state = (state < kNumStates + kNumLitStates) ? kNumLitStates : kNumLitStates + 3;
+ /* state = kLiteralNextStates[state]; */
+ }
+
+ len += kMatchMinLen;
+
+ if (limit == dicPos)
+ return SZ_ERROR_DATA;
+ {
+ SizeT rem = limit - dicPos;
+ unsigned curLen = ((rem < len) ? (unsigned)rem : len);
+ SizeT pos = (dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0);
+
+ processedPos += curLen;
+
+ len -= curLen;
+ if (pos + curLen <= dicBufSize)
+ {
+ Byte *dest = dic + dicPos;
+ ptrdiff_t src = (ptrdiff_t)pos - (ptrdiff_t)dicPos;
+ const Byte *lim = dest + curLen;
+ dicPos += curLen;
+ do
+ *((volatile Byte *)dest) = (Byte)*(dest + src);
+ while (++dest != lim);
+ }
+ else
+ {
+ do
+ {
+ dic[dicPos++] = dic[pos];
+ if (++pos == dicBufSize)
+ pos = 0;
+ }
+ while (--curLen != 0);
+ }
+ }
+ }
+ }
+ while (dicPos < limit && buf < bufLimit);
+ NORMALIZE;
+ p->buf = buf;
+ p->range = range;
+ p->code = code;
+ p->remainLen = len;
+ p->dicPos = dicPos;
+ p->processedPos = processedPos;
+ p->reps[0] = rep0;
+ p->reps[1] = rep1;
+ p->reps[2] = rep2;
+ p->reps[3] = rep3;
+ p->state = state;
+
+ return SZ_OK;
+}
+
+static void MY_FAST_CALL LzmaDec_WriteRem(CLzmaDec *p, SizeT limit)
+{
+ if (p->remainLen != 0 && p->remainLen < kMatchSpecLenStart)
+ {
+ Byte *dic = p->dic;
+ SizeT dicPos = p->dicPos;
+ SizeT dicBufSize = p->dicBufSize;
+ unsigned len = p->remainLen;
+ UInt32 rep0 = p->reps[0];
+ if (limit - dicPos < len)
+ len = (unsigned)(limit - dicPos);
+
+ if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= len)
+ p->checkDicSize = p->prop.dicSize;
+
+ p->processedPos += len;
+ p->remainLen -= len;
+ while (len-- != 0)
+ {
+ dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)];
+ dicPos++;
+ }
+ p->dicPos = dicPos;
+ }
+}
+
+static int MY_FAST_CALL LzmaDec_DecodeReal2(CLzmaDec *p, SizeT limit, const Byte *bufLimit)
+{
+ do
+ {
+ SizeT limit2 = limit;
+ if (p->checkDicSize == 0)
+ {
+ UInt32 rem = p->prop.dicSize - p->processedPos;
+ if (limit - p->dicPos > rem)
+ limit2 = p->dicPos + rem;
+ }
+ RINOK(LzmaDec_DecodeReal(p, limit2, bufLimit));
+ if (p->processedPos >= p->prop.dicSize)
+ p->checkDicSize = p->prop.dicSize;
+ LzmaDec_WriteRem(p, limit);
+ }
+ while (p->dicPos < limit && p->buf < bufLimit && p->remainLen < kMatchSpecLenStart);
+
+ if (p->remainLen > kMatchSpecLenStart)
+ {
+ p->remainLen = kMatchSpecLenStart;
+ }
+ return 0;
+}
+
+typedef enum
+{
+ DUMMY_ERROR, /* unexpected end of input stream */
+ DUMMY_LIT,
+ DUMMY_MATCH,
+ DUMMY_REP
+} ELzmaDummy;
+
+static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, SizeT inSize)
+{
+ UInt32 range = p->range;
+ UInt32 code = p->code;
+ const Byte *bufLimit = buf + inSize;
+ CLzmaProb *probs = p->probs;
+ unsigned state = p->state;
+ ELzmaDummy res;
+
+ {
+ CLzmaProb *prob;
+ UInt32 bound;
+ unsigned ttt;
+ unsigned posState = (p->processedPos) & ((1 << p->prop.pb) - 1);
+
+ prob = probs + IsMatch + (state << kNumPosBitsMax) + posState;
+ IF_BIT_0_CHECK(prob)
+ {
+ UPDATE_0_CHECK
+
+ /* if (bufLimit - buf >= 7) return DUMMY_LIT; */
+
+ prob = probs + Literal;
+ if (p->checkDicSize != 0 || p->processedPos != 0)
+ prob += (LZMA_LIT_SIZE *
+ ((((p->processedPos) & ((1 << (p->prop.lp)) - 1)) << p->prop.lc) +
+ (p->dic[(p->dicPos == 0 ? p->dicBufSize : p->dicPos) - 1] >> (8 - p->prop.lc))));
+
+ if (state < kNumLitStates)
+ {
+ unsigned symbol = 1;
+ do { GET_BIT_CHECK(prob + symbol, symbol) } while (symbol < 0x100);
+ }
+ else
+ {
+ unsigned matchByte = p->dic[p->dicPos - p->reps[0] +
+ ((p->dicPos < p->reps[0]) ? p->dicBufSize : 0)];
+ unsigned offs = 0x100;
+ unsigned symbol = 1;
+ do
+ {
+ unsigned bit;
+ CLzmaProb *probLit;
+ matchByte <<= 1;
+ bit = (matchByte & offs);
+ probLit = prob + offs + bit + symbol;
+ GET_BIT2_CHECK(probLit, symbol, offs &= ~bit, offs &= bit)
+ }
+ while (symbol < 0x100);
+ }
+ res = DUMMY_LIT;
+ }
+ else
+ {
+ unsigned len;
+ UPDATE_1_CHECK;
+
+ prob = probs + IsRep + state;
+ IF_BIT_0_CHECK(prob)
+ {
+ UPDATE_0_CHECK;
+ state = 0;
+ prob = probs + LenCoder;
+ res = DUMMY_MATCH;
+ }
+ else
+ {
+ UPDATE_1_CHECK;
+ res = DUMMY_REP;
+ prob = probs + IsRepG0 + state;
+ IF_BIT_0_CHECK(prob)
+ {
+ UPDATE_0_CHECK;
+ prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState;
+ IF_BIT_0_CHECK(prob)
+ {
+ UPDATE_0_CHECK;
+ NORMALIZE_CHECK;
+ return DUMMY_REP;
+ }
+ else
+ {
+ UPDATE_1_CHECK;
+ }
+ }
+ else
+ {
+ UPDATE_1_CHECK;
+ prob = probs + IsRepG1 + state;
+ IF_BIT_0_CHECK(prob)
+ {
+ UPDATE_0_CHECK;
+ }
+ else
+ {
+ UPDATE_1_CHECK;
+ prob = probs + IsRepG2 + state;
+ IF_BIT_0_CHECK(prob)
+ {
+ UPDATE_0_CHECK;
+ }
+ else
+ {
+ UPDATE_1_CHECK;
+ }
+ }
+ }
+ state = kNumStates;
+ prob = probs + RepLenCoder;
+ }
+ {
+ unsigned limit, offset;
+ CLzmaProb *probLen = prob + LenChoice;
+ IF_BIT_0_CHECK(probLen)
+ {
+ UPDATE_0_CHECK;
+ probLen = prob + LenLow + (posState << kLenNumLowBits);
+ offset = 0;
+ limit = 1 << kLenNumLowBits;
+ }
+ else
+ {
+ UPDATE_1_CHECK;
+ probLen = prob + LenChoice2;
+ IF_BIT_0_CHECK(probLen)
+ {
+ UPDATE_0_CHECK;
+ probLen = prob + LenMid + (posState << kLenNumMidBits);
+ offset = kLenNumLowSymbols;
+ limit = 1 << kLenNumMidBits;
+ }
+ else
+ {
+ UPDATE_1_CHECK;
+ probLen = prob + LenHigh;
+ offset = kLenNumLowSymbols + kLenNumMidSymbols;
+ limit = 1 << kLenNumHighBits;
+ }
+ }
+ TREE_DECODE_CHECK(probLen, limit, len);
+ len += offset;
+ }
+
+ if (state < 4)
+ {
+ unsigned posSlot;
+ prob = probs + PosSlot +
+ ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) <<
+ kNumPosSlotBits);
+ TREE_DECODE_CHECK(prob, 1 << kNumPosSlotBits, posSlot);
+ if (posSlot >= kStartPosModelIndex)
+ {
+ int numDirectBits = ((posSlot >> 1) - 1);
+
+ /* if (bufLimit - buf >= 8) return DUMMY_MATCH; */
+
+ if (posSlot < kEndPosModelIndex)
+ {
+ prob = probs + SpecPos + ((2 | (posSlot & 1)) << numDirectBits) - posSlot - 1;
+ }
+ else
+ {
+ numDirectBits -= kNumAlignBits;
+ do
+ {
+ NORMALIZE_CHECK
+ range >>= 1;
+ code -= range & (((code - range) >> 31) - 1);
+ /* if (code >= range) code -= range; */
+ }
+ while (--numDirectBits != 0);
+ prob = probs + Align;
+ numDirectBits = kNumAlignBits;
+ }
+ {
+ unsigned i = 1;
+ do
+ {
+ GET_BIT_CHECK(prob + i, i);
+ }
+ while (--numDirectBits != 0);
+ }
+ }
+ }
+ }
+ }
+ NORMALIZE_CHECK;
+ return res;
+}
+
+static void LzmaDec_InitRc(CLzmaDec *p, const Byte *data)
+{
+ p->code = ((UInt32)data[1] << 24) | ((UInt32)data[2] << 16) | ((UInt32)data[3] << 8) | ((UInt32)data[4]);
+ p->range = 0xFFFFFFFF;
+ p->needFlush = 0;
+}
+
+void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState)
+{
+ p->needFlush = 1;
+ p->remainLen = 0;
+ p->tempBufSize = 0;
+
+ if (initDic)
+ {
+ p->processedPos = 0;
+ p->checkDicSize = 0;
+ p->needInitState = 1;
+ }
+ if (initState)
+ p->needInitState = 1;
+}
+
+void LzmaDec_Init(CLzmaDec *p)
+{
+ p->dicPos = 0;
+ LzmaDec_InitDicAndState(p, True, True);
+}
+
+static void LzmaDec_InitStateReal(CLzmaDec *p)
+{
+ UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (p->prop.lc + p->prop.lp));
+ UInt32 i;
+ CLzmaProb *probs = p->probs;
+ for (i = 0; i < numProbs; i++)
+ probs[i] = kBitModelTotal >> 1;
+ p->reps[0] = p->reps[1] = p->reps[2] = p->reps[3] = 1;
+ p->state = 0;
+ p->needInitState = 0;
+}
+
+SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen,
+ ELzmaFinishMode finishMode, ELzmaStatus *status)
+{
+ SizeT inSize = *srcLen;
+ (*srcLen) = 0;
+ LzmaDec_WriteRem(p, dicLimit);
+
+ *status = LZMA_STATUS_NOT_SPECIFIED;
+
+ while (p->remainLen != kMatchSpecLenStart)
+ {
+ int checkEndMarkNow;
+
+ if (p->needFlush != 0)
+ {
+ for (; inSize > 0 && p->tempBufSize < RC_INIT_SIZE; (*srcLen)++, inSize--)
+ p->tempBuf[p->tempBufSize++] = *src++;
+ if (p->tempBufSize < RC_INIT_SIZE)
+ {
+ *status = LZMA_STATUS_NEEDS_MORE_INPUT;
+ return SZ_OK;
+ }
+ if (p->tempBuf[0] != 0)
+ return SZ_ERROR_DATA;
+
+ LzmaDec_InitRc(p, p->tempBuf);
+ p->tempBufSize = 0;
+ }
+
+ checkEndMarkNow = 0;
+ if (p->dicPos >= dicLimit)
+ {
+ if (p->remainLen == 0 && p->code == 0)
+ {
+ *status = LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK;
+ return SZ_OK;
+ }
+ if (finishMode == LZMA_FINISH_ANY)
+ {
+ *status = LZMA_STATUS_NOT_FINISHED;
+ return SZ_OK;
+ }
+ if (p->remainLen != 0)
+ {
+ *status = LZMA_STATUS_NOT_FINISHED;
+ return SZ_ERROR_DATA;
+ }
+ checkEndMarkNow = 1;
+ }
+
+ if (p->needInitState)
+ LzmaDec_InitStateReal(p);
+
+ if (p->tempBufSize == 0)
+ {
+ SizeT processed;
+ const Byte *bufLimit;
+ if (inSize < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow)
+ {
+ int dummyRes = LzmaDec_TryDummy(p, src, inSize);
+ if (dummyRes == DUMMY_ERROR)
+ {
+ memcpy(p->tempBuf, src, inSize);
+ p->tempBufSize = (unsigned)inSize;
+ (*srcLen) += inSize;
+ *status = LZMA_STATUS_NEEDS_MORE_INPUT;
+ return SZ_OK;
+ }
+ if (checkEndMarkNow && dummyRes != DUMMY_MATCH)
+ {
+ *status = LZMA_STATUS_NOT_FINISHED;
+ return SZ_ERROR_DATA;
+ }
+ bufLimit = src;
+ }
+ else
+ bufLimit = src + inSize - LZMA_REQUIRED_INPUT_MAX;
+ p->buf = src;
+ if (LzmaDec_DecodeReal2(p, dicLimit, bufLimit) != 0)
+ return SZ_ERROR_DATA;
+ processed = (SizeT)(p->buf - src);
+ (*srcLen) += processed;
+ src += processed;
+ inSize -= processed;
+ }
+ else
+ {
+ unsigned rem = p->tempBufSize, lookAhead = 0;
+ while (rem < LZMA_REQUIRED_INPUT_MAX && lookAhead < inSize)
+ p->tempBuf[rem++] = src[lookAhead++];
+ p->tempBufSize = rem;
+ if (rem < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow)
+ {
+ int dummyRes = LzmaDec_TryDummy(p, p->tempBuf, rem);
+ if (dummyRes == DUMMY_ERROR)
+ {
+ (*srcLen) += lookAhead;
+ *status = LZMA_STATUS_NEEDS_MORE_INPUT;
+ return SZ_OK;
+ }
+ if (checkEndMarkNow && dummyRes != DUMMY_MATCH)
+ {
+ *status = LZMA_STATUS_NOT_FINISHED;
+ return SZ_ERROR_DATA;
+ }
+ }
+ p->buf = p->tempBuf;
+ if (LzmaDec_DecodeReal2(p, dicLimit, p->buf) != 0)
+ return SZ_ERROR_DATA;
+ lookAhead -= (rem - (unsigned)(p->buf - p->tempBuf));
+ (*srcLen) += lookAhead;
+ src += lookAhead;
+ inSize -= lookAhead;
+ p->tempBufSize = 0;
+ }
+ }
+ if (p->code == 0)
+ *status = LZMA_STATUS_FINISHED_WITH_MARK;
+ return (p->code == 0) ? SZ_OK : SZ_ERROR_DATA;
+}
+
+SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status)
+{
+ SizeT outSize = *destLen;
+ SizeT inSize = *srcLen;
+ *srcLen = *destLen = 0;
+ for (;;)
+ {
+ SizeT inSizeCur = inSize, outSizeCur, dicPos;
+ ELzmaFinishMode curFinishMode;
+ SRes res;
+ if (p->dicPos == p->dicBufSize)
+ p->dicPos = 0;
+ dicPos = p->dicPos;
+ if (outSize > p->dicBufSize - dicPos)
+ {
+ outSizeCur = p->dicBufSize;
+ curFinishMode = LZMA_FINISH_ANY;
+ }
+ else
+ {
+ outSizeCur = dicPos + outSize;
+ curFinishMode = finishMode;
+ }
+
+ res = LzmaDec_DecodeToDic(p, outSizeCur, src, &inSizeCur, curFinishMode, status);
+ src += inSizeCur;
+ inSize -= inSizeCur;
+ *srcLen += inSizeCur;
+ outSizeCur = p->dicPos - dicPos;
+ memcpy(dest, p->dic + dicPos, outSizeCur);
+ dest += outSizeCur;
+ outSize -= outSizeCur;
+ *destLen += outSizeCur;
+ if (res != 0)
+ return res;
+ if (outSizeCur == 0 || outSize == 0)
+ return SZ_OK;
+ }
+}
+
+void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc)
+{
+ alloc->Free(alloc, p->probs);
+ p->probs = 0;
+}
+
+static void LzmaDec_FreeDict(CLzmaDec *p, ISzAlloc *alloc)
+{
+ alloc->Free(alloc, p->dic);
+ p->dic = 0;
+}
+
+void LzmaDec_Free(CLzmaDec *p, ISzAlloc *alloc)
+{
+ LzmaDec_FreeProbs(p, alloc);
+ LzmaDec_FreeDict(p, alloc);
+}
+
+SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size)
+{
+ UInt32 dicSize;
+ Byte d;
+
+ if (size < LZMA_PROPS_SIZE)
+ return SZ_ERROR_UNSUPPORTED;
+ else
+ dicSize = data[1] | ((UInt32)data[2] << 8) | ((UInt32)data[3] << 16) | ((UInt32)data[4] << 24);
+
+ if (dicSize < LZMA_DIC_MIN)
+ dicSize = LZMA_DIC_MIN;
+ p->dicSize = dicSize;
+
+ d = data[0];
+ if (d >= (9 * 5 * 5))
+ return SZ_ERROR_UNSUPPORTED;
+
+ p->lc = d % 9;
+ d /= 9;
+ p->pb = d / 5;
+ p->lp = d % 5;
+
+ return SZ_OK;
+}
+
+static SRes LzmaDec_AllocateProbs2(CLzmaDec *p, const CLzmaProps *propNew, ISzAlloc *alloc)
+{
+ UInt32 numProbs = LzmaProps_GetNumProbs(propNew);
+ if (p->probs == 0 || numProbs != p->numProbs)
+ {
+ LzmaDec_FreeProbs(p, alloc);
+ p->probs = (CLzmaProb *)alloc->Alloc(alloc, numProbs * sizeof(CLzmaProb));
+ p->numProbs = numProbs;
+ if (p->probs == 0)
+ return SZ_ERROR_MEM;
+ }
+ return SZ_OK;
+}
+
+SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc)
+{
+ CLzmaProps propNew;
+ RINOK(LzmaProps_Decode(&propNew, props, propsSize));
+ RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc));
+ p->prop = propNew;
+ return SZ_OK;
+}
+
+SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc)
+{
+ CLzmaProps propNew;
+ SizeT dicBufSize;
+ RINOK(LzmaProps_Decode(&propNew, props, propsSize));
+ RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc));
+ dicBufSize = propNew.dicSize;
+ if (p->dic == 0 || dicBufSize != p->dicBufSize)
+ {
+ LzmaDec_FreeDict(p, alloc);
+ p->dic = (Byte *)alloc->Alloc(alloc, dicBufSize);
+ if (p->dic == 0)
+ {
+ LzmaDec_FreeProbs(p, alloc);
+ return SZ_ERROR_MEM;
+ }
+ }
+ p->dicBufSize = dicBufSize;
+ p->prop = propNew;
+ return SZ_OK;
+}
+
+SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
+ const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode,
+ ELzmaStatus *status, ISzAlloc *alloc)
+{
+ CLzmaDec p;
+ SRes res;
+ SizeT inSize = *srcLen;
+ SizeT outSize = *destLen;
+ *srcLen = *destLen = 0;
+ if (inSize < RC_INIT_SIZE)
+ return SZ_ERROR_INPUT_EOF;
+
+ LzmaDec_Construct(&p);
+ res = LzmaDec_AllocateProbs(&p, propData, propSize, alloc);
+ if (res != 0)
+ return res;
+ p.dic = dest;
+ p.dicBufSize = outSize;
+
+ LzmaDec_Init(&p);
+
+ *srcLen = inSize;
+ res = LzmaDec_DecodeToDic(&p, outSize, src, srcLen, finishMode, status);
+
+ if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT)
+ res = SZ_ERROR_INPUT_EOF;
+
+ (*destLen) = p.dicPos;
+ LzmaDec_FreeProbs(&p, alloc);
+ return res;
+}
+
diff --git a/Core/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/LzmaDec.h b/Core/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/LzmaDec.h
new file mode 100644
index 0000000000..ad7d7057a4
--- /dev/null
+++ b/Core/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/LzmaDec.h
@@ -0,0 +1,223 @@
+/* LzmaDec.h -- LZMA Decoder
+2008-10-04 : Igor Pavlov : Public domain */
+
+#ifndef __LZMADEC_H
+#define __LZMADEC_H
+
+#include "Types.h"
+
+/* #define _LZMA_PROB32 */
+/* _LZMA_PROB32 can increase the speed on some CPUs,
+ but memory usage for CLzmaDec::probs will be doubled in that case */
+
+#ifdef _LZMA_PROB32
+#define CLzmaProb UInt32
+#else
+#define CLzmaProb UInt16
+#endif
+
+
+/* ---------- LZMA Properties ---------- */
+
+#define LZMA_PROPS_SIZE 5
+
+typedef struct _CLzmaProps
+{
+ unsigned lc, lp, pb;
+ UInt32 dicSize;
+} CLzmaProps;
+
+/* LzmaProps_Decode - decodes properties
+Returns:
+ SZ_OK
+ SZ_ERROR_UNSUPPORTED - Unsupported properties
+*/
+
+SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size);
+
+
+/* ---------- LZMA Decoder state ---------- */
+
+/* LZMA_REQUIRED_INPUT_MAX = number of required input bytes for worst case.
+ Num bits = log2((2^11 / 31) ^ 22) + 26 < 134 + 26 = 160; */
+
+#define LZMA_REQUIRED_INPUT_MAX 20
+
+typedef struct
+{
+ CLzmaProps prop;
+ CLzmaProb *probs;
+ Byte *dic;
+ const Byte *buf;
+ UInt32 range, code;
+ SizeT dicPos;
+ SizeT dicBufSize;
+ UInt32 processedPos;
+ UInt32 checkDicSize;
+ unsigned state;
+ UInt32 reps[4];
+ unsigned remainLen;
+ int needFlush;
+ int needInitState;
+ UInt32 numProbs;
+ unsigned tempBufSize;
+ Byte tempBuf[LZMA_REQUIRED_INPUT_MAX];
+} CLzmaDec;
+
+#define LzmaDec_Construct(p) { (p)->dic = 0; (p)->probs = 0; }
+
+void LzmaDec_Init(CLzmaDec *p);
+
+/* There are two types of LZMA streams:
+ 0) Stream with end mark. That end mark adds about 6 bytes to compressed size.
+ 1) Stream without end mark. You must know exact uncompressed size to decompress such stream. */
+
+typedef enum
+{
+ LZMA_FINISH_ANY, /* finish at any point */
+ LZMA_FINISH_END /* block must be finished at the end */
+} ELzmaFinishMode;
+
+/* ELzmaFinishMode has meaning only if the decoding reaches output limit !!!
+
+ You must use LZMA_FINISH_END, when you know that current output buffer
+ covers last bytes of block. In other cases you must use LZMA_FINISH_ANY.
+
+ If LZMA decoder sees end marker before reaching output limit, it returns SZ_OK,
+ and output value of destLen will be less than output buffer size limit.
+ You can check status result also.
+
+ You can use multiple checks to test data integrity after full decompression:
+ 1) Check Result and "status" variable.
+ 2) Check that output(destLen) = uncompressedSize, if you know real uncompressedSize.
+ 3) Check that output(srcLen) = compressedSize, if you know real compressedSize.
+ You must use correct finish mode in that case. */
+
+typedef enum
+{
+ LZMA_STATUS_NOT_SPECIFIED, /* use main error code instead */
+ LZMA_STATUS_FINISHED_WITH_MARK, /* stream was finished with end mark. */
+ LZMA_STATUS_NOT_FINISHED, /* stream was not finished */
+ LZMA_STATUS_NEEDS_MORE_INPUT, /* you must provide more input bytes */
+ LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK /* there is probability that stream was finished without end mark */
+} ELzmaStatus;
+
+/* ELzmaStatus is used only as output value for function call */
+
+
+/* ---------- Interfaces ---------- */
+
+/* There are 3 levels of interfaces:
+ 1) Dictionary Interface
+ 2) Buffer Interface
+ 3) One Call Interface
+ You can select any of these interfaces, but don't mix functions from different
+ groups for same object. */
+
+
+/* There are two variants to allocate state for Dictionary Interface:
+ 1) LzmaDec_Allocate / LzmaDec_Free
+ 2) LzmaDec_AllocateProbs / LzmaDec_FreeProbs
+ You can use variant 2, if you set dictionary buffer manually.
+ For Buffer Interface you must always use variant 1.
+
+LzmaDec_Allocate* can return:
+ SZ_OK
+ SZ_ERROR_MEM - Memory allocation error
+ SZ_ERROR_UNSUPPORTED - Unsupported properties
+*/
+
+SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc);
+void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc);
+
+SRes LzmaDec_Allocate(CLzmaDec *state, const Byte *prop, unsigned propsSize, ISzAlloc *alloc);
+void LzmaDec_Free(CLzmaDec *state, ISzAlloc *alloc);
+
+/* ---------- Dictionary Interface ---------- */
+
+/* You can use it, if you want to eliminate the overhead for data copying from
+ dictionary to some other external buffer.
+ You must work with CLzmaDec variables directly in this interface.
+
+ STEPS:
+ LzmaDec_Constr()
+ LzmaDec_Allocate()
+ for (each new stream)
+ {
+ LzmaDec_Init()
+ while (it needs more decompression)
+ {
+ LzmaDec_DecodeToDic()
+ use data from CLzmaDec::dic and update CLzmaDec::dicPos
+ }
+ }
+ LzmaDec_Free()
+*/
+
+/* LzmaDec_DecodeToDic
+
+ The decoding to internal dictionary buffer (CLzmaDec::dic).
+ You must manually update CLzmaDec::dicPos, if it reaches CLzmaDec::dicBufSize !!!
+
+finishMode:
+ It has meaning only if the decoding reaches output limit (dicLimit).
+ LZMA_FINISH_ANY - Decode just dicLimit bytes.
+ LZMA_FINISH_END - Stream must be finished after dicLimit.
+
+Returns:
+ SZ_OK
+ status:
+ LZMA_STATUS_FINISHED_WITH_MARK
+ LZMA_STATUS_NOT_FINISHED
+ LZMA_STATUS_NEEDS_MORE_INPUT
+ LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK
+ SZ_ERROR_DATA - Data error
+*/
+
+SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit,
+ const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
+
+
+/* ---------- Buffer Interface ---------- */
+
+/* It's zlib-like interface.
+ See LzmaDec_DecodeToDic description for information about STEPS and return results,
+ but you must use LzmaDec_DecodeToBuf instead of LzmaDec_DecodeToDic and you don't need
+ to work with CLzmaDec variables manually.
+
+finishMode:
+ It has meaning only if the decoding reaches output limit (*destLen).
+ LZMA_FINISH_ANY - Decode just destLen bytes.
+ LZMA_FINISH_END - Stream must be finished after (*destLen).
+*/
+
+SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen,
+ const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
+
+
+/* ---------- One Call Interface ---------- */
+
+/* LzmaDecode
+
+finishMode:
+ It has meaning only if the decoding reaches output limit (*destLen).
+ LZMA_FINISH_ANY - Decode just destLen bytes.
+ LZMA_FINISH_END - Stream must be finished after (*destLen).
+
+Returns:
+ SZ_OK
+ status:
+ LZMA_STATUS_FINISHED_WITH_MARK
+ LZMA_STATUS_NOT_FINISHED
+ LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK
+ SZ_ERROR_DATA - Data error
+ SZ_ERROR_MEM - Memory allocation error
+ SZ_ERROR_UNSUPPORTED - Unsupported properties
+ SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src).
+*/
+
+SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
+ const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode,
+ ELzmaStatus *status, ISzAlloc *alloc);
+
+#endif
diff --git a/Core/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/Types.h b/Core/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/Types.h
new file mode 100644
index 0000000000..30b16e3bb0
--- /dev/null
+++ b/Core/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/Types.h
@@ -0,0 +1,231 @@
+/** @file
+ Types.h
+
+ Based on LZMA SDK 4.65:
+ Types.h -- Basic types
+ 2008-11-23 : Igor Pavlov : Public domain
+
+ Copyright (c) 2009, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __7Z_TYPES_H
+#define __7Z_TYPES_H
+
+#ifdef EFIAPI
+
+#include "UefiLzma.h"
+
+#else
+
+#include <stddef.h>
+
+#ifdef _WIN32
+#include <windows.h>
+#endif
+
+#endif
+
+#define SZ_OK 0
+
+#define SZ_ERROR_DATA 1
+#define SZ_ERROR_MEM 2
+#define SZ_ERROR_CRC 3
+#define SZ_ERROR_UNSUPPORTED 4
+#define SZ_ERROR_PARAM 5
+#define SZ_ERROR_INPUT_EOF 6
+#define SZ_ERROR_OUTPUT_EOF 7
+#define SZ_ERROR_READ 8
+#define SZ_ERROR_WRITE 9
+#define SZ_ERROR_PROGRESS 10
+#define SZ_ERROR_FAIL 11
+#define SZ_ERROR_THREAD 12
+
+#define SZ_ERROR_ARCHIVE 16
+#define SZ_ERROR_NO_ARCHIVE 17
+
+typedef int SRes;
+
+#ifdef _WIN32
+typedef DWORD WRes;
+#else
+typedef int WRes;
+#endif
+
+#ifndef RINOK
+#define RINOK(x) { int __result__ = (x); if (__result__ != 0) return __result__; }
+#endif
+
+typedef unsigned char Byte;
+typedef short Int16;
+typedef unsigned short UInt16;
+
+#ifdef _LZMA_UINT32_IS_ULONG
+typedef long Int32;
+typedef unsigned long UInt32;
+#else
+typedef int Int32;
+typedef unsigned int UInt32;
+#endif
+
+#ifdef _SZ_NO_INT_64
+
+/* define _SZ_NO_INT_64, if your compiler doesn't support 64-bit integers.
+ NOTES: Some code will work incorrectly in that case! */
+
+typedef long Int64;
+typedef unsigned long UInt64;
+
+#else
+
+#if defined(_MSC_VER) || defined(__BORLANDC__)
+typedef __int64 Int64;
+typedef unsigned __int64 UInt64;
+#else
+typedef long long int Int64;
+typedef unsigned long long int UInt64;
+#endif
+
+#endif
+
+#ifdef _LZMA_NO_SYSTEM_SIZE_T
+typedef UInt32 SizeT;
+#else
+typedef size_t SizeT;
+#endif
+
+typedef int Bool;
+#define True 1
+#define False 0
+
+
+#ifdef _MSC_VER
+
+#if _MSC_VER >= 1300
+#define MY_NO_INLINE __declspec(noinline)
+#else
+#define MY_NO_INLINE
+#endif
+
+#define MY_CDECL __cdecl
+#define MY_STD_CALL __stdcall
+#define MY_FAST_CALL MY_NO_INLINE __fastcall
+
+#else
+
+#define MY_CDECL
+#define MY_STD_CALL
+#define MY_FAST_CALL
+
+#endif
+
+
+/* The following interfaces use first parameter as pointer to structure */
+
+typedef struct
+{
+ SRes (*Read)(void *p, void *buf, size_t *size);
+ /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream.
+ (output(*size) < input(*size)) is allowed */
+} ISeqInStream;
+
+/* it can return SZ_ERROR_INPUT_EOF */
+SRes SeqInStream_Read(ISeqInStream *stream, void *buf, size_t size);
+SRes SeqInStream_Read2(ISeqInStream *stream, void *buf, size_t size, SRes errorType);
+SRes SeqInStream_ReadByte(ISeqInStream *stream, Byte *buf);
+
+typedef struct
+{
+ size_t (*Write)(void *p, const void *buf, size_t size);
+ /* Returns: result - the number of actually written bytes.
+ (result < size) means error */
+} ISeqOutStream;
+
+typedef enum
+{
+ SZ_SEEK_SET = 0,
+ SZ_SEEK_CUR = 1,
+ SZ_SEEK_END = 2
+} ESzSeek;
+
+typedef struct
+{
+ SRes (*Read)(void *p, void *buf, size_t *size); /* same as ISeqInStream::Read */
+ SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin);
+} ISeekInStream;
+
+typedef struct
+{
+ SRes (*Look)(void *p, void **buf, size_t *size);
+ /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream.
+ (output(*size) > input(*size)) is not allowed
+ (output(*size) < input(*size)) is allowed */
+ SRes (*Skip)(void *p, size_t offset);
+ /* offset must be <= output(*size) of Look */
+
+ SRes (*Read)(void *p, void *buf, size_t *size);
+ /* reads directly (without buffer). It's same as ISeqInStream::Read */
+ SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin);
+} ILookInStream;
+
+SRes LookInStream_LookRead(ILookInStream *stream, void *buf, size_t *size);
+SRes LookInStream_SeekTo(ILookInStream *stream, UInt64 offset);
+
+/* reads via ILookInStream::Read */
+SRes LookInStream_Read2(ILookInStream *stream, void *buf, size_t size, SRes errorType);
+SRes LookInStream_Read(ILookInStream *stream, void *buf, size_t size);
+
+#define LookToRead_BUF_SIZE (1 << 14)
+
+typedef struct
+{
+ ILookInStream s;
+ ISeekInStream *realStream;
+ size_t pos;
+ size_t size;
+ Byte buf[LookToRead_BUF_SIZE];
+} CLookToRead;
+
+void LookToRead_CreateVTable(CLookToRead *p, int lookahead);
+void LookToRead_Init(CLookToRead *p);
+
+typedef struct
+{
+ ISeqInStream s;
+ ILookInStream *realStream;
+} CSecToLook;
+
+void SecToLook_CreateVTable(CSecToLook *p);
+
+typedef struct
+{
+ ISeqInStream s;
+ ILookInStream *realStream;
+} CSecToRead;
+
+void SecToRead_CreateVTable(CSecToRead *p);
+
+typedef struct
+{
+ SRes (*Progress)(void *p, UInt64 inSize, UInt64 outSize);
+ /* Returns: result. (result != SZ_OK) means break.
+ Value (UInt64)(Int64)-1 for size means unknown value. */
+} ICompressProgress;
+
+typedef struct
+{
+ void *(*Alloc)(void *p, size_t size);
+ void (*Free)(void *p, void *address); /* address can be 0 */
+} ISzAlloc;
+
+#define IAlloc_Alloc(p, size) (p)->Alloc((p), size)
+#define IAlloc_Free(p, a) (p)->Free((p), a)
+
+#endif
diff --git a/Core/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/history.txt b/Core/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/history.txt
new file mode 100644
index 0000000000..9bed5ebbef
--- /dev/null
+++ b/Core/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/history.txt
@@ -0,0 +1,236 @@
+HISTORY of the LZMA SDK
+-----------------------
+
+4.65 2009-02-03
+-------------------------
+- Some minor fixes
+
+
+4.63 2008-12-31
+-------------------------
+- Some minor fixes
+
+
+4.61 beta 2008-11-23
+-------------------------
+- The bug in ANSI-C LZMA Decoder was fixed:
+ If encoded stream was corrupted, decoder could access memory
+ outside of allocated range.
+- Some changes in ANSI-C 7z Decoder interfaces.
+- LZMA SDK is placed in the public domain.
+
+
+4.60 beta 2008-08-19
+-------------------------
+- Some minor fixes.
+
+
+4.59 beta 2008-08-13
+-------------------------
+- The bug was fixed:
+ LZMA Encoder in fast compression mode could access memory outside of
+ allocated range in some rare cases.
+
+
+4.58 beta 2008-05-05
+-------------------------
+- ANSI-C LZMA Decoder was rewritten for speed optimizations.
+- ANSI-C LZMA Encoder was included to LZMA SDK.
+- C++ LZMA code now is just wrapper over ANSI-C code.
+
+
+4.57 2007-12-12
+-------------------------
+- Speed optimizations in Ñ++ LZMA Decoder.
+- Small changes for more compatibility with some C/C++ compilers.
+
+
+4.49 beta 2007-07-05
+-------------------------
+- .7z ANSI-C Decoder:
+ - now it supports BCJ and BCJ2 filters
+ - now it supports files larger than 4 GB.
+ - now it supports "Last Write Time" field for files.
+- C++ code for .7z archives compressing/decompressing from 7-zip
+ was included to LZMA SDK.
+
+
+4.43 2006-06-04
+-------------------------
+- Small changes for more compatibility with some C/C++ compilers.
+
+
+4.42 2006-05-15
+-------------------------
+- Small changes in .h files in ANSI-C version.
+
+
+4.39 beta 2006-04-14
+-------------------------
+- The bug in versions 4.33b:4.38b was fixed:
+ C++ version of LZMA encoder could not correctly compress
+ files larger than 2 GB with HC4 match finder (-mfhc4).
+
+
+4.37 beta 2005-04-06
+-------------------------
+- Fixes in C++ code: code could no be compiled if _NO_EXCEPTIONS was defined.
+
+
+4.35 beta 2005-03-02
+-------------------------
+- The bug was fixed in C++ version of LZMA Decoder:
+ If encoded stream was corrupted, decoder could access memory
+ outside of allocated range.
+
+
+4.34 beta 2006-02-27
+-------------------------
+- Compressing speed and memory requirements for compressing were increased
+- LZMA now can use only these match finders: HC4, BT2, BT3, BT4
+
+
+4.32 2005-12-09
+-------------------------
+- Java version of LZMA SDK was included
+
+
+4.30 2005-11-20
+-------------------------
+- Compression ratio was improved in -a2 mode
+- Speed optimizations for compressing in -a2 mode
+- -fb switch now supports values up to 273
+- The bug in 7z_C (7zIn.c) was fixed:
+ It used Alloc/Free functions from different memory pools.
+ So if program used two memory pools, it worked incorrectly.
+- 7z_C: .7z format supporting was improved
+- LZMA# SDK (C#.NET version) was included
+
+
+4.27 (Updated) 2005-09-21
+-------------------------
+- Some GUIDs/interfaces in C++ were changed.
+ IStream.h:
+ ISequentialInStream::Read now works as old ReadPart
+ ISequentialOutStream::Write now works as old WritePart
+
+
+4.27 2005-08-07
+-------------------------
+- The bug in LzmaDecodeSize.c was fixed:
+ if _LZMA_IN_CB and _LZMA_OUT_READ were defined,
+ decompressing worked incorrectly.
+
+
+4.26 2005-08-05
+-------------------------
+- Fixes in 7z_C code and LzmaTest.c:
+ previous versions could work incorrectly,
+ if malloc(0) returns 0
+
+
+4.23 2005-06-29
+-------------------------
+- Small fixes in C++ code
+
+
+4.22 2005-06-10
+-------------------------
+- Small fixes
+
+
+4.21 2005-06-08
+-------------------------
+- Interfaces for ANSI-C LZMA Decoder (LzmaDecode.c) were changed
+- New additional version of ANSI-C LZMA Decoder with zlib-like interface:
+ - LzmaStateDecode.h
+ - LzmaStateDecode.c
+ - LzmaStateTest.c
+- ANSI-C LZMA Decoder now can decompress files larger than 4 GB
+
+
+4.17 2005-04-18
+-------------------------
+- New example for RAM->RAM compressing/decompressing:
+ LZMA + BCJ (filter for x86 code):
+ - LzmaRam.h
+ - LzmaRam.cpp
+ - LzmaRamDecode.h
+ - LzmaRamDecode.c
+ - -f86 switch for lzma.exe
+
+
+4.16 2005-03-29
+-------------------------
+- The bug was fixed in LzmaDecode.c (ANSI-C LZMA Decoder):
+ If _LZMA_OUT_READ was defined, and if encoded stream was corrupted,
+ decoder could access memory outside of allocated range.
+- Speed optimization of ANSI-C LZMA Decoder (now it's about 20% faster).
+ Old version of LZMA Decoder now is in file LzmaDecodeSize.c.
+ LzmaDecodeSize.c can provide slightly smaller code than LzmaDecode.c
+- Small speed optimization in LZMA C++ code
+- filter for SPARC's code was added
+- Simplified version of .7z ANSI-C Decoder was included
+
+
+4.06 2004-09-05
+-------------------------
+- The bug in v4.05 was fixed:
+ LZMA-Encoder didn't release output stream in some cases.
+
+
+4.05 2004-08-25
+-------------------------
+- Source code of filters for x86, IA-64, ARM, ARM-Thumb
+ and PowerPC code was included to SDK
+- Some internal minor changes
+
+
+4.04 2004-07-28
+-------------------------
+- More compatibility with some C++ compilers
+
+
+4.03 2004-06-18
+-------------------------
+- "Benchmark" command was added. It measures compressing
+ and decompressing speed and shows rating values.
+ Also it checks hardware errors.
+
+
+4.02 2004-06-10
+-------------------------
+- C++ LZMA Encoder/Decoder code now is more portable
+ and it can be compiled by GCC on Linux.
+
+
+4.01 2004-02-15
+-------------------------
+- Some detection of data corruption was enabled.
+ LzmaDecode.c / RangeDecoderReadByte
+ .....
+ {
+ rd->ExtraBytes = 1;
+ return 0xFF;
+ }
+
+
+4.00 2004-02-13
+-------------------------
+- Original version of LZMA SDK
+
+
+
+HISTORY of the LZMA
+-------------------
+ 2001-2008: Improvements to LZMA compressing/decompressing code,
+ keeping compatibility with original LZMA format
+ 1996-2001: Development of LZMA compression format
+
+ Some milestones:
+
+ 2001-08-30: LZMA compression was added to 7-Zip
+ 1999-01-02: First version of 7-Zip was released
+
+
+End of document
diff --git a/Core/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/lzma.txt b/Core/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/lzma.txt
new file mode 100644
index 0000000000..d4f4af929a
--- /dev/null
+++ b/Core/MdeModulePkg/Library/LzmaCustomDecompressLib/Sdk/lzma.txt
@@ -0,0 +1,594 @@
+LZMA SDK 4.65
+-------------
+
+LZMA SDK provides the documentation, samples, header files, libraries,
+and tools you need to develop applications that use LZMA compression.
+
+LZMA is default and general compression method of 7z format
+in 7-Zip compression program (www.7-zip.org). LZMA provides high
+compression ratio and very fast decompression.
+
+LZMA is an improved version of famous LZ77 compression algorithm.
+It was improved in way of maximum increasing of compression ratio,
+keeping high decompression speed and low memory requirements for
+decompressing.
+
+
+
+LICENSE
+-------
+
+LZMA SDK is written and placed in the public domain by Igor Pavlov.
+
+
+LZMA SDK Contents
+-----------------
+
+LZMA SDK includes:
+
+ - ANSI-C/C++/C#/Java source code for LZMA compressing and decompressing
+ - Compiled file->file LZMA compressing/decompressing program for Windows system
+
+
+UNIX/Linux version
+------------------
+To compile C++ version of file->file LZMA encoding, go to directory
+C++/7zip/Compress/LZMA_Alone
+and call make to recompile it:
+ make -f makefile.gcc clean all
+
+In some UNIX/Linux versions you must compile LZMA with static libraries.
+To compile with static libraries, you can use
+LIB = -lm -static
+
+
+Files
+---------------------
+lzma.txt - LZMA SDK description (this file)
+7zFormat.txt - 7z Format description
+7zC.txt - 7z ANSI-C Decoder description
+methods.txt - Compression method IDs for .7z
+lzma.exe - Compiled file->file LZMA encoder/decoder for Windows
+history.txt - history of the LZMA SDK
+
+
+Source code structure
+---------------------
+
+C/ - C files
+ 7zCrc*.* - CRC code
+ Alloc.* - Memory allocation functions
+ Bra*.* - Filters for x86, IA-64, ARM, ARM-Thumb, PowerPC and SPARC code
+ LzFind.* - Match finder for LZ (LZMA) encoders
+ LzFindMt.* - Match finder for LZ (LZMA) encoders for multithreading encoding
+ LzHash.h - Additional file for LZ match finder
+ LzmaDec.* - LZMA decoding
+ LzmaEnc.* - LZMA encoding
+ LzmaLib.* - LZMA Library for DLL calling
+ Types.h - Basic types for another .c files
+ Threads.* - The code for multithreading.
+
+ LzmaLib - LZMA Library (.DLL for Windows)
+
+ LzmaUtil - LZMA Utility (file->file LZMA encoder/decoder).
+
+ Archive - files related to archiving
+ 7z - 7z ANSI-C Decoder
+
+CPP/ -- CPP files
+
+ Common - common files for C++ projects
+ Windows - common files for Windows related code
+
+ 7zip - files related to 7-Zip Project
+
+ Common - common files for 7-Zip
+
+ Compress - files related to compression/decompression
+
+ Copy - Copy coder
+ RangeCoder - Range Coder (special code of compression/decompression)
+ LZMA - LZMA compression/decompression on C++
+ LZMA_Alone - file->file LZMA compression/decompression
+ Branch - Filters for x86, IA-64, ARM, ARM-Thumb, PowerPC and SPARC code
+
+ Archive - files related to archiving
+
+ Common - common files for archive handling
+ 7z - 7z C++ Encoder/Decoder
+
+ Bundles - Modules that are bundles of other modules
+
+ Alone7z - 7zr.exe: Standalone version of 7z.exe that supports only 7z/LZMA/BCJ/BCJ2
+ Format7zR - 7zr.dll: Reduced version of 7za.dll: extracting/compressing to 7z/LZMA/BCJ/BCJ2
+ Format7zExtractR - 7zxr.dll: Reduced version of 7zxa.dll: extracting from 7z/LZMA/BCJ/BCJ2.
+
+ UI - User Interface files
+
+ Client7z - Test application for 7za.dll, 7zr.dll, 7zxr.dll
+ Common - Common UI files
+ Console - Code for console archiver
+
+
+
+CS/ - C# files
+ 7zip
+ Common - some common files for 7-Zip
+ Compress - files related to compression/decompression
+ LZ - files related to LZ (Lempel-Ziv) compression algorithm
+ LZMA - LZMA compression/decompression
+ LzmaAlone - file->file LZMA compression/decompression
+ RangeCoder - Range Coder (special code of compression/decompression)
+
+Java/ - Java files
+ SevenZip
+ Compression - files related to compression/decompression
+ LZ - files related to LZ (Lempel-Ziv) compression algorithm
+ LZMA - LZMA compression/decompression
+ RangeCoder - Range Coder (special code of compression/decompression)
+
+
+C/C++ source code of LZMA SDK is part of 7-Zip project.
+7-Zip source code can be downloaded from 7-Zip's SourceForge page:
+
+ http://sourceforge.net/projects/sevenzip/
+
+
+
+LZMA features
+-------------
+ - Variable dictionary size (up to 1 GB)
+ - Estimated compressing speed: about 2 MB/s on 2 GHz CPU
+ - Estimated decompressing speed:
+ - 20-30 MB/s on 2 GHz Core 2 or AMD Athlon 64
+ - 1-2 MB/s on 200 MHz ARM, MIPS, PowerPC or other simple RISC
+ - Small memory requirements for decompressing (16 KB + DictionarySize)
+ - Small code size for decompressing: 5-8 KB
+
+LZMA decoder uses only integer operations and can be
+implemented in any modern 32-bit CPU (or on 16-bit CPU with some conditions).
+
+Some critical operations that affect the speed of LZMA decompression:
+ 1) 32*16 bit integer multiply
+ 2) Misspredicted branches (penalty mostly depends from pipeline length)
+ 3) 32-bit shift and arithmetic operations
+
+The speed of LZMA decompressing mostly depends from CPU speed.
+Memory speed has no big meaning. But if your CPU has small data cache,
+overall weight of memory speed will slightly increase.
+
+
+How To Use
+----------
+
+Using LZMA encoder/decoder executable
+--------------------------------------
+
+Usage: LZMA <e|d> inputFile outputFile [<switches>...]
+
+ e: encode file
+
+ d: decode file
+
+ b: Benchmark. There are two tests: compressing and decompressing
+ with LZMA method. Benchmark shows rating in MIPS (million
+ instructions per second). Rating value is calculated from
+ measured speed and it is normalized with Intel's Core 2 results.
+ Also Benchmark checks possible hardware errors (RAM
+ errors in most cases). Benchmark uses these settings:
+ (-a1, -d21, -fb32, -mfbt4). You can change only -d parameter.
+ Also you can change the number of iterations. Example for 30 iterations:
+ LZMA b 30
+ Default number of iterations is 10.
+
+<Switches>
+
+
+ -a{N}: set compression mode 0 = fast, 1 = normal
+ default: 1 (normal)
+
+ d{N}: Sets Dictionary size - [0, 30], default: 23 (8MB)
+ The maximum value for dictionary size is 1 GB = 2^30 bytes.
+ Dictionary size is calculated as DictionarySize = 2^N bytes.
+ For decompressing file compressed by LZMA method with dictionary
+ size D = 2^N you need about D bytes of memory (RAM).
+
+ -fb{N}: set number of fast bytes - [5, 273], default: 128
+ Usually big number gives a little bit better compression ratio
+ and slower compression process.
+
+ -lc{N}: set number of literal context bits - [0, 8], default: 3
+ Sometimes lc=4 gives gain for big files.
+
+ -lp{N}: set number of literal pos bits - [0, 4], default: 0
+ lp switch is intended for periodical data when period is
+ equal 2^N. For example, for 32-bit (4 bytes)
+ periodical data you can use lp=2. Often it's better to set lc0,
+ if you change lp switch.
+
+ -pb{N}: set number of pos bits - [0, 4], default: 2
+ pb switch is intended for periodical data
+ when period is equal 2^N.
+
+ -mf{MF_ID}: set Match Finder. Default: bt4.
+ Algorithms from hc* group doesn't provide good compression
+ ratio, but they often works pretty fast in combination with
+ fast mode (-a0).
+
+ Memory requirements depend from dictionary size
+ (parameter "d" in table below).
+
+ MF_ID Memory Description
+
+ bt2 d * 9.5 + 4MB Binary Tree with 2 bytes hashing.
+ bt3 d * 11.5 + 4MB Binary Tree with 3 bytes hashing.
+ bt4 d * 11.5 + 4MB Binary Tree with 4 bytes hashing.
+ hc4 d * 7.5 + 4MB Hash Chain with 4 bytes hashing.
+
+ -eos: write End Of Stream marker. By default LZMA doesn't write
+ eos marker, since LZMA decoder knows uncompressed size
+ stored in .lzma file header.
+
+ -si: Read data from stdin (it will write End Of Stream marker).
+ -so: Write data to stdout
+
+
+Examples:
+
+1) LZMA e file.bin file.lzma -d16 -lc0
+
+compresses file.bin to file.lzma with 64 KB dictionary (2^16=64K)
+and 0 literal context bits. -lc0 allows to reduce memory requirements
+for decompression.
+
+
+2) LZMA e file.bin file.lzma -lc0 -lp2
+
+compresses file.bin to file.lzma with settings suitable
+for 32-bit periodical data (for example, ARM or MIPS code).
+
+3) LZMA d file.lzma file.bin
+
+decompresses file.lzma to file.bin.
+
+
+Compression ratio hints
+-----------------------
+
+Recommendations
+---------------
+
+To increase the compression ratio for LZMA compressing it's desirable
+to have aligned data (if it's possible) and also it's desirable to locate
+data in such order, where code is grouped in one place and data is
+grouped in other place (it's better than such mixing: code, data, code,
+data, ...).
+
+
+Filters
+-------
+You can increase the compression ratio for some data types, using
+special filters before compressing. For example, it's possible to
+increase the compression ratio on 5-10% for code for those CPU ISAs:
+x86, IA-64, ARM, ARM-Thumb, PowerPC, SPARC.
+
+You can find C source code of such filters in C/Bra*.* files
+
+You can check the compression ratio gain of these filters with such
+7-Zip commands (example for ARM code):
+No filter:
+ 7z a a1.7z a.bin -m0=lzma
+
+With filter for little-endian ARM code:
+ 7z a a2.7z a.bin -m0=arm -m1=lzma
+
+It works in such manner:
+Compressing = Filter_encoding + LZMA_encoding
+Decompressing = LZMA_decoding + Filter_decoding
+
+Compressing and decompressing speed of such filters is very high,
+so it will not increase decompressing time too much.
+Moreover, it reduces decompression time for LZMA_decoding,
+since compression ratio with filtering is higher.
+
+These filters convert CALL (calling procedure) instructions
+from relative offsets to absolute addresses, so such data becomes more
+compressible.
+
+For some ISAs (for example, for MIPS) it's impossible to get gain from such filter.
+
+
+LZMA compressed file format
+---------------------------
+Offset Size Description
+ 0 1 Special LZMA properties (lc,lp, pb in encoded form)
+ 1 4 Dictionary size (little endian)
+ 5 8 Uncompressed size (little endian). -1 means unknown size
+ 13 Compressed data
+
+
+ANSI-C LZMA Decoder
+~~~~~~~~~~~~~~~~~~~
+
+Please note that interfaces for ANSI-C code were changed in LZMA SDK 4.58.
+If you want to use old interfaces you can download previous version of LZMA SDK
+from sourceforge.net site.
+
+To use ANSI-C LZMA Decoder you need the following files:
+1) LzmaDec.h + LzmaDec.c + Types.h
+LzmaUtil/LzmaUtil.c is example application that uses these files.
+
+
+Memory requirements for LZMA decoding
+-------------------------------------
+
+Stack usage of LZMA decoding function for local variables is not
+larger than 200-400 bytes.
+
+LZMA Decoder uses dictionary buffer and internal state structure.
+Internal state structure consumes
+ state_size = (4 + (1.5 << (lc + lp))) KB
+by default (lc=3, lp=0), state_size = 16 KB.
+
+
+How To decompress data
+----------------------
+
+LZMA Decoder (ANSI-C version) now supports 2 interfaces:
+1) Single-call Decompressing
+2) Multi-call State Decompressing (zlib-like interface)
+
+You must use external allocator:
+Example:
+void *SzAlloc(void *p, size_t size) { p = p; return malloc(size); }
+void SzFree(void *p, void *address) { p = p; free(address); }
+ISzAlloc alloc = { SzAlloc, SzFree };
+
+You can use p = p; operator to disable compiler warnings.
+
+
+Single-call Decompressing
+-------------------------
+When to use: RAM->RAM decompressing
+Compile files: LzmaDec.h + LzmaDec.c + Types.h
+Compile defines: no defines
+Memory Requirements:
+ - Input buffer: compressed size
+ - Output buffer: uncompressed size
+ - LZMA Internal Structures: state_size (16 KB for default settings)
+
+Interface:
+ int LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
+ const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode,
+ ELzmaStatus *status, ISzAlloc *alloc);
+ In:
+ dest - output data
+ destLen - output data size
+ src - input data
+ srcLen - input data size
+ propData - LZMA properties (5 bytes)
+ propSize - size of propData buffer (5 bytes)
+ finishMode - It has meaning only if the decoding reaches output limit (*destLen).
+ LZMA_FINISH_ANY - Decode just destLen bytes.
+ LZMA_FINISH_END - Stream must be finished after (*destLen).
+ You can use LZMA_FINISH_END, when you know that
+ current output buffer covers last bytes of stream.
+ alloc - Memory allocator.
+
+ Out:
+ destLen - processed output size
+ srcLen - processed input size
+
+ Output:
+ SZ_OK
+ status:
+ LZMA_STATUS_FINISHED_WITH_MARK
+ LZMA_STATUS_NOT_FINISHED
+ LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK
+ SZ_ERROR_DATA - Data error
+ SZ_ERROR_MEM - Memory allocation error
+ SZ_ERROR_UNSUPPORTED - Unsupported properties
+ SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src).
+
+ If LZMA decoder sees end_marker before reaching output limit, it returns OK result,
+ and output value of destLen will be less than output buffer size limit.
+
+ You can use multiple checks to test data integrity after full decompression:
+ 1) Check Result and "status" variable.
+ 2) Check that output(destLen) = uncompressedSize, if you know real uncompressedSize.
+ 3) Check that output(srcLen) = compressedSize, if you know real compressedSize.
+ You must use correct finish mode in that case. */
+
+
+Multi-call State Decompressing (zlib-like interface)
+----------------------------------------------------
+
+When to use: file->file decompressing
+Compile files: LzmaDec.h + LzmaDec.c + Types.h
+
+Memory Requirements:
+ - Buffer for input stream: any size (for example, 16 KB)
+ - Buffer for output stream: any size (for example, 16 KB)
+ - LZMA Internal Structures: state_size (16 KB for default settings)
+ - LZMA dictionary (dictionary size is encoded in LZMA properties header)
+
+1) read LZMA properties (5 bytes) and uncompressed size (8 bytes, little-endian) to header:
+ unsigned char header[LZMA_PROPS_SIZE + 8];
+ ReadFile(inFile, header, sizeof(header)
+
+2) Allocate CLzmaDec structures (state + dictionary) using LZMA properties
+
+ CLzmaDec state;
+ LzmaDec_Constr(&state);
+ res = LzmaDec_Allocate(&state, header, LZMA_PROPS_SIZE, &g_Alloc);
+ if (res != SZ_OK)
+ return res;
+
+3) Init LzmaDec structure before any new LZMA stream. And call LzmaDec_DecodeToBuf in loop
+
+ LzmaDec_Init(&state);
+ for (;;)
+ {
+ ...
+ int res = LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen,
+ const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode);
+ ...
+ }
+
+
+4) Free all allocated structures
+ LzmaDec_Free(&state, &g_Alloc);
+
+For full code example, look at C/LzmaUtil/LzmaUtil.c code.
+
+
+How To compress data
+--------------------
+
+Compile files: LzmaEnc.h + LzmaEnc.c + Types.h +
+LzFind.c + LzFind.h + LzFindMt.c + LzFindMt.h + LzHash.h
+
+Memory Requirements:
+ - (dictSize * 11.5 + 6 MB) + state_size
+
+Lzma Encoder can use two memory allocators:
+1) alloc - for small arrays.
+2) allocBig - for big arrays.
+
+For example, you can use Large RAM Pages (2 MB) in allocBig allocator for
+better compression speed. Note that Windows has bad implementation for
+Large RAM Pages.
+It's OK to use same allocator for alloc and allocBig.
+
+
+Single-call Compression with callbacks
+--------------------------------------
+
+Check C/LzmaUtil/LzmaUtil.c as example,
+
+When to use: file->file decompressing
+
+1) you must implement callback structures for interfaces:
+ISeqInStream
+ISeqOutStream
+ICompressProgress
+ISzAlloc
+
+static void *SzAlloc(void *p, size_t size) { p = p; return MyAlloc(size); }
+static void SzFree(void *p, void *address) { p = p; MyFree(address); }
+static ISzAlloc g_Alloc = { SzAlloc, SzFree };
+
+ CFileSeqInStream inStream;
+ CFileSeqOutStream outStream;
+
+ inStream.funcTable.Read = MyRead;
+ inStream.file = inFile;
+ outStream.funcTable.Write = MyWrite;
+ outStream.file = outFile;
+
+
+2) Create CLzmaEncHandle object;
+
+ CLzmaEncHandle enc;
+
+ enc = LzmaEnc_Create(&g_Alloc);
+ if (enc == 0)
+ return SZ_ERROR_MEM;
+
+
+3) initialize CLzmaEncProps properties;
+
+ LzmaEncProps_Init(&props);
+
+ Then you can change some properties in that structure.
+
+4) Send LZMA properties to LZMA Encoder
+
+ res = LzmaEnc_SetProps(enc, &props);
+
+5) Write encoded properties to header
+
+ Byte header[LZMA_PROPS_SIZE + 8];
+ size_t headerSize = LZMA_PROPS_SIZE;
+ UInt64 fileSize;
+ int i;
+
+ res = LzmaEnc_WriteProperties(enc, header, &headerSize);
+ fileSize = MyGetFileLength(inFile);
+ for (i = 0; i < 8; i++)
+ header[headerSize++] = (Byte)(fileSize >> (8 * i));
+ MyWriteFileAndCheck(outFile, header, headerSize)
+
+6) Call encoding function:
+ res = LzmaEnc_Encode(enc, &outStream.funcTable, &inStream.funcTable,
+ NULL, &g_Alloc, &g_Alloc);
+
+7) Destroy LZMA Encoder Object
+ LzmaEnc_Destroy(enc, &g_Alloc, &g_Alloc);
+
+
+If callback function return some error code, LzmaEnc_Encode also returns that code.
+
+
+Single-call RAM->RAM Compression
+--------------------------------
+
+Single-call RAM->RAM Compression is similar to Compression with callbacks,
+but you provide pointers to buffers instead of pointers to stream callbacks:
+
+HRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
+ CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark,
+ ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig);
+
+Return code:
+ SZ_OK - OK
+ SZ_ERROR_MEM - Memory allocation error
+ SZ_ERROR_PARAM - Incorrect paramater
+ SZ_ERROR_OUTPUT_EOF - output buffer overflow
+ SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version)
+
+
+
+LZMA Defines
+------------
+
+_LZMA_SIZE_OPT - Enable some optimizations in LZMA Decoder to get smaller executable code.
+
+_LZMA_PROB32 - It can increase the speed on some 32-bit CPUs, but memory usage for
+ some structures will be doubled in that case.
+
+_LZMA_UINT32_IS_ULONG - Define it if int is 16-bit on your compiler and long is 32-bit.
+
+_LZMA_NO_SYSTEM_SIZE_T - Define it if you don't want to use size_t type.
+
+
+C++ LZMA Encoder/Decoder
+~~~~~~~~~~~~~~~~~~~~~~~~
+C++ LZMA code use COM-like interfaces. So if you want to use it,
+you can study basics of COM/OLE.
+C++ LZMA code is just wrapper over ANSI-C code.
+
+
+C++ Notes
+~~~~~~~~~~~~~~~~~~~~~~~~
+If you use some C++ code folders in 7-Zip (for example, C++ code for .7z handling),
+you must check that you correctly work with "new" operator.
+7-Zip can be compiled with MSVC 6.0 that doesn't throw "exception" from "new" operator.
+So 7-Zip uses "CPP\Common\NewHandler.cpp" that redefines "new" operator:
+operator new(size_t size)
+{
+ void *p = ::malloc(size);
+ if (p == 0)
+ throw CNewException();
+ return p;
+}
+If you use MSCV that throws exception for "new" operator, you can compile without
+"NewHandler.cpp". So standard exception will be used. Actually some code of
+7-Zip catches any exception in internal code and converts it to HRESULT code.
+So you don't need to catch CNewException, if you call COM interfaces of 7-Zip.
+
+---
+
+http://www.7-zip.org
+http://www.7-zip.org/sdk.html
+http://www.7-zip.org/support.html
diff --git a/Core/MdeModulePkg/Library/LzmaCustomDecompressLib/UefiLzma.h b/Core/MdeModulePkg/Library/LzmaCustomDecompressLib/UefiLzma.h
new file mode 100644
index 0000000000..863b3ef66b
--- /dev/null
+++ b/Core/MdeModulePkg/Library/LzmaCustomDecompressLib/UefiLzma.h
@@ -0,0 +1,47 @@
+/** @file
+ LZMA UEFI header file
+
+ Allows LZMA code to build under UEFI (edk2) build environment
+
+ Copyright (c) 2009, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __UEFILZMA_H__
+#define __UEFILZMA_H__
+
+#include <Uefi.h>
+#include <Library/BaseMemoryLib.h>
+
+#ifdef _WIN32
+#undef _WIN32
+#endif
+
+#ifndef _SIZE_T_DEFINED
+#if !defined(_WIN64) || defined(__GNUC__)
+typedef unsigned int size_t;
+#endif
+#endif
+
+#ifdef _WIN64
+#undef _WIN64
+#endif
+
+#ifndef _PTRDIFF_T_DEFINED
+typedef int ptrdiff_t;
+#endif
+
+#define memcpy CopyMem
+#define memmove CopyMem
+
+#define _LZMA_SIZE_OPT
+
+#endif // __UEFILZMA_H__
+
diff --git a/Core/MdeModulePkg/Library/OemHookStatusCodeLibNull/OemHookStatusCodeLibNull.c b/Core/MdeModulePkg/Library/OemHookStatusCodeLibNull/OemHookStatusCodeLibNull.c
new file mode 100644
index 0000000000..0df144fe79
--- /dev/null
+++ b/Core/MdeModulePkg/Library/OemHookStatusCodeLibNull/OemHookStatusCodeLibNull.c
@@ -0,0 +1,62 @@
+/** @file
+ Null instance of OEM Hook Status Code Library with empty functions.
+
+ Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+
+/**
+ Initialize OEM status code device .
+
+ @retval EFI_SUCCESS Always return EFI_SUCCESS.
+
+**/
+EFI_STATUS
+EFIAPI
+OemHookStatusCodeInitialize (
+ VOID
+ )
+{
+ return EFI_SUCCESS;
+}
+
+/**
+ Report status code to OEM device.
+
+ @param CodeType Indicates the type of status code being reported.
+ @param Value Describes the current status of a hardware or software entity.
+ This included information about the class and subclass that is used to classify the entity
+ as well as an operation. For progress codes, the operation is the current activity.
+ For error codes, it is the exception. For debug codes, it is not defined at this time.
+ @param Instance The enumeration of a hardware or software entity within the system.
+ A system may contain multiple entities that match a class/subclass pairing.
+ The instance differentiates between them. An instance of 0 indicates that instance information is unavailable,
+ not meaningful, or not relevant. Valid instance numbers start with 1.
+ @param CallerId This optional parameter may be used to identify the caller.
+ This parameter allows the status code driver to apply different rules to different callers.
+ @param Data This optional parameter may be used to pass additional data
+
+ @retval EFI_SUCCESS Always return EFI_SUCCESS.
+
+**/
+EFI_STATUS
+EFIAPI
+OemHookStatusCodeReport (
+ IN EFI_STATUS_CODE_TYPE CodeType,
+ IN EFI_STATUS_CODE_VALUE Value,
+ IN UINT32 Instance,
+ IN EFI_GUID *CallerId, OPTIONAL
+ IN EFI_STATUS_CODE_DATA *Data OPTIONAL
+ )
+{
+ return EFI_SUCCESS;
+}
+
diff --git a/Core/MdeModulePkg/Library/OemHookStatusCodeLibNull/OemHookStatusCodeLibNull.inf b/Core/MdeModulePkg/Library/OemHookStatusCodeLibNull/OemHookStatusCodeLibNull.inf
new file mode 100644
index 0000000000..32ed1a41bf
--- /dev/null
+++ b/Core/MdeModulePkg/Library/OemHookStatusCodeLibNull/OemHookStatusCodeLibNull.inf
@@ -0,0 +1,35 @@
+## @file
+# Null instance of OEM Hook Status Code Library with empty functions.
+#
+# Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = OemHookStatusCodeLibNull
+ MODULE_UNI_FILE = OemHookStatusCodeLibNull.uni
+ FILE_GUID = 54D2878F-25CD-4a2b-8420-EBD18E609C76
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = OemHookStatusCodeLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ OemHookStatusCodeLibNull.c
+
+[Packages]
+ MdePkg/MdePkg.dec \ No newline at end of file
diff --git a/Core/MdeModulePkg/Library/OemHookStatusCodeLibNull/OemHookStatusCodeLibNull.uni b/Core/MdeModulePkg/Library/OemHookStatusCodeLibNull/OemHookStatusCodeLibNull.uni
new file mode 100644
index 0000000000..3e8cdd8d7f
--- /dev/null
+++ b/Core/MdeModulePkg/Library/OemHookStatusCodeLibNull/OemHookStatusCodeLibNull.uni
Binary files differ
diff --git a/Core/MdeModulePkg/Library/PciHostBridgeLibNull/PciHostBridgeLibNull.c b/Core/MdeModulePkg/Library/PciHostBridgeLibNull/PciHostBridgeLibNull.c
new file mode 100644
index 0000000000..761e45b0de
--- /dev/null
+++ b/Core/MdeModulePkg/Library/PciHostBridgeLibNull/PciHostBridgeLibNull.c
@@ -0,0 +1,115 @@
+/** @file
+ Null instance of PCI Host Bridge Library with empty functions.
+
+ Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials are licensed and made available
+ under the terms and conditions of the BSD License which accompanies this
+ distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
+ WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+#include <PiDxe.h>
+#include <Library/PciHostBridgeLib.h>
+#include <Library/DebugLib.h>
+
+GLOBAL_REMOVE_IF_UNREFERENCED
+CHAR16 *mPciHostBridgeLibAcpiAddressSpaceTypeStr[] = {
+ L"Mem", L"I/O", L"Bus"
+};
+
+/**
+ Return all the root bridge instances in an array.
+
+ @param Count Return the count of root bridge instances.
+
+ @return All the root bridge instances in an array.
+ The array should be passed into PciHostBridgeFreeRootBridges()
+ when it's not used.
+**/
+PCI_ROOT_BRIDGE *
+EFIAPI
+PciHostBridgeGetRootBridges (
+ UINTN *Count
+ )
+{
+ *Count = 0;
+ return NULL;
+}
+
+/**
+ Free the root bridge instances array returned from PciHostBridgeGetRootBridges().
+
+ @param Bridges The root bridge instances array.
+ @param Count The count of the array.
+**/
+VOID
+EFIAPI
+PciHostBridgeFreeRootBridges (
+ PCI_ROOT_BRIDGE *Bridges,
+ UINTN Count
+ )
+{
+ return;
+}
+
+/**
+ Inform the platform that the resource conflict happens.
+
+ @param HostBridgeHandle Handle of the Host Bridge.
+ @param Configuration Pointer to PCI I/O and PCI memory resource
+ descriptors. The Configuration contains the resources
+ for all the root bridges. The resource for each root
+ bridge is terminated with END descriptor and an
+ additional END is appended indicating the end of the
+ entire resources. The resource descriptor field
+ values follow the description in
+ EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
+ .SubmitResources().
+**/
+VOID
+EFIAPI
+PciHostBridgeResourceConflict (
+ EFI_HANDLE HostBridgeHandle,
+ VOID *Configuration
+ )
+{
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;
+ UINTN RootBridgeIndex;
+ DEBUG ((EFI_D_ERROR, "PciHostBridge: Resource conflict happens!\n"));
+
+ RootBridgeIndex = 0;
+ Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Configuration;
+ while (Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR) {
+ DEBUG ((EFI_D_ERROR, "RootBridge[%d]:\n", RootBridgeIndex++));
+ for (; Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR; Descriptor++) {
+ ASSERT (Descriptor->ResType <
+ (sizeof (mPciHostBridgeLibAcpiAddressSpaceTypeStr) /
+ sizeof (mPciHostBridgeLibAcpiAddressSpaceTypeStr[0])
+ )
+ );
+ DEBUG ((EFI_D_ERROR, " %s: Length/Alignment = 0x%lx / 0x%lx\n",
+ mPciHostBridgeLibAcpiAddressSpaceTypeStr[Descriptor->ResType],
+ Descriptor->AddrLen, Descriptor->AddrRangeMax
+ ));
+ if (Descriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) {
+ DEBUG ((EFI_D_ERROR, " Granularity/SpecificFlag = %ld / %02x%s\n",
+ Descriptor->AddrSpaceGranularity, Descriptor->SpecificFlag,
+ ((Descriptor->SpecificFlag &
+ EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE
+ ) != 0) ? L" (Prefetchable)" : L""
+ ));
+ }
+ }
+ //
+ // Skip the END descriptor for root bridge
+ //
+ ASSERT (Descriptor->Desc == ACPI_END_TAG_DESCRIPTOR);
+ Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)(
+ (EFI_ACPI_END_TAG_DESCRIPTOR *)Descriptor + 1
+ );
+ }
+}
diff --git a/Core/MdeModulePkg/Library/PciHostBridgeLibNull/PciHostBridgeLibNull.inf b/Core/MdeModulePkg/Library/PciHostBridgeLibNull/PciHostBridgeLibNull.inf
new file mode 100644
index 0000000000..8df14924ad
--- /dev/null
+++ b/Core/MdeModulePkg/Library/PciHostBridgeLibNull/PciHostBridgeLibNull.inf
@@ -0,0 +1,38 @@
+## @file
+# Null instance of PCI Host Bridge Library with empty functions.
+#
+# Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials are licensed and made available
+# under the terms and conditions of the BSD License which accompanies this
+# distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR
+# IMPLIED.
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PciHostBridgeLibNull
+ MODULE_UNI_FILE = PciHostBridgeLibNull.uni
+ FILE_GUID = A19A6C36-7053-4E2C-8BD0-E8286230E473
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = PciHostBridgeLib
+
+#
+# The following information is for reference only and not required by the build
+# tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ PciHostBridgeLibNull.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
diff --git a/Core/MdeModulePkg/Library/PciHostBridgeLibNull/PciHostBridgeLibNull.uni b/Core/MdeModulePkg/Library/PciHostBridgeLibNull/PciHostBridgeLibNull.uni
new file mode 100644
index 0000000000..7b0fdee324
--- /dev/null
+++ b/Core/MdeModulePkg/Library/PciHostBridgeLibNull/PciHostBridgeLibNull.uni
@@ -0,0 +1,20 @@
+// /** @file
+// Null instance of PCI Host Bridge Library with empty functions.
+//
+// Null instance of PCI Host Bridge Library with empty functions.
+//
+// Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Null instance of PCI Host Bridge Library with empty functions."
+
+#string STR_MODULE_DESCRIPTION #language en-US "Null instance of PCI Host Bridge Library with empty functions."
diff --git a/Core/MdeModulePkg/Library/PeiCrc32GuidedSectionExtractLib/PeiCrc32GuidedSectionExtractLib.c b/Core/MdeModulePkg/Library/PeiCrc32GuidedSectionExtractLib/PeiCrc32GuidedSectionExtractLib.c
new file mode 100644
index 0000000000..6e3dcdd690
--- /dev/null
+++ b/Core/MdeModulePkg/Library/PeiCrc32GuidedSectionExtractLib/PeiCrc32GuidedSectionExtractLib.c
@@ -0,0 +1,312 @@
+/** @file
+
+ This library registers CRC32 guided section handler
+ to parse CRC32 encapsulation section and extract raw data.
+
+Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiPei.h>
+#include <Guid/Crc32GuidedSectionExtraction.h>
+#include <Library/ExtractGuidedSectionLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+
+///
+/// CRC32 Guided Section header
+///
+typedef struct {
+ EFI_GUID_DEFINED_SECTION GuidedSectionHeader; ///< EFI guided section header
+ UINT32 CRC32Checksum; ///< 32bit CRC check sum
+} CRC32_SECTION_HEADER;
+
+typedef struct {
+ EFI_GUID_DEFINED_SECTION2 GuidedSectionHeader; ///< EFI guided section header
+ UINT32 CRC32Checksum; ///< 32bit CRC check sum
+} CRC32_SECTION2_HEADER;
+
+/**
+ This internal function reverses bits for 32bit data.
+
+ @param Value The data to be reversed.
+
+ @return Data reversed.
+
+**/
+UINT32
+PeiCrc32GuidedSectionExtractLibReverseBits (
+ UINT32 Value
+ )
+{
+ UINTN Index;
+ UINT32 NewValue;
+
+ NewValue = 0;
+ for (Index = 0; Index < 32; Index++) {
+ if ((Value & (1 << Index)) != 0) {
+ NewValue = NewValue | (1 << (31 - Index));
+ }
+ }
+
+ return NewValue;
+}
+
+/**
+ Calculate CRC32 for target data.
+
+ @param Data The target data.
+ @param DataSize The target data size.
+ @param CrcOut The CRC32 for target data.
+
+ @retval EFI_SUCCESS The CRC32 for target data is calculated successfully.
+ @retval EFI_INVALID_PARAMETER Some parameter is not valid, so the CRC32 is not
+ calculated.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiCrc32GuidedSectionExtractLibCalculateCrc32 (
+ IN VOID *Data,
+ IN UINTN DataSize,
+ OUT UINT32 *CrcOut
+ )
+{
+ UINT32 CrcTable[256];
+ UINTN TableEntry;
+ UINTN Index;
+ UINT32 Value;
+ UINT32 Crc;
+ UINT8 *Ptr;
+
+ if (Data == NULL || DataSize == 0 || CrcOut == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Initialize CRC32 table.
+ //
+ for (TableEntry = 0; TableEntry < 256; TableEntry++) {
+ Value = PeiCrc32GuidedSectionExtractLibReverseBits ((UINT32) TableEntry);
+ for (Index = 0; Index < 8; Index++) {
+ if ((Value & 0x80000000) != 0) {
+ Value = (Value << 1) ^ 0x04c11db7;
+ } else {
+ Value = Value << 1;
+ }
+ }
+ CrcTable[TableEntry] = PeiCrc32GuidedSectionExtractLibReverseBits (Value);
+ }
+
+ //
+ // Compute CRC
+ //
+ Crc = 0xffffffff;
+ for (Index = 0, Ptr = Data; Index < DataSize; Index++, Ptr++) {
+ Crc = (Crc >> 8) ^ CrcTable[(UINT8) Crc ^ *Ptr];
+ }
+
+ *CrcOut = Crc ^ 0xffffffff;
+ return EFI_SUCCESS;
+}
+
+/**
+
+ GetInfo gets raw data size and attribute of the input guided section.
+ It first checks whether the input guid section is supported.
+ If not, EFI_INVALID_PARAMETER will return.
+
+ @param InputSection Buffer containing the input GUIDed section to be processed.
+ @param OutputBufferSize The size of OutputBuffer.
+ @param ScratchBufferSize The size of ScratchBuffer.
+ @param SectionAttribute The attribute of the input guided section.
+
+ @retval EFI_SUCCESS The size of destination buffer, the size of scratch buffer and
+ the attribute of the input section are successull retrieved.
+ @retval EFI_INVALID_PARAMETER The GUID in InputSection does not match this instance guid.
+
+**/
+EFI_STATUS
+EFIAPI
+Crc32GuidedSectionGetInfo (
+ IN CONST VOID *InputSection,
+ OUT UINT32 *OutputBufferSize,
+ OUT UINT32 *ScratchBufferSize,
+ OUT UINT16 *SectionAttribute
+ )
+{
+ if (IS_SECTION2 (InputSection)) {
+ //
+ // Check whether the input guid section is recognized.
+ //
+ if (!CompareGuid (
+ &gEfiCrc32GuidedSectionExtractionGuid,
+ &(((EFI_GUID_DEFINED_SECTION2 *) InputSection)->SectionDefinitionGuid))) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Retrieve the size and attribute of the input section data.
+ //
+ *SectionAttribute = ((EFI_GUID_DEFINED_SECTION2 *) InputSection)->Attributes;
+ *ScratchBufferSize = 0;
+ *OutputBufferSize = SECTION2_SIZE (InputSection) - ((EFI_GUID_DEFINED_SECTION2 *) InputSection)->DataOffset;
+ } else {
+ //
+ // Check whether the input guid section is recognized.
+ //
+ if (!CompareGuid (
+ &gEfiCrc32GuidedSectionExtractionGuid,
+ &(((EFI_GUID_DEFINED_SECTION *) InputSection)->SectionDefinitionGuid))) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Retrieve the size and attribute of the input section data.
+ //
+ *SectionAttribute = ((EFI_GUID_DEFINED_SECTION *) InputSection)->Attributes;
+ *ScratchBufferSize = 0;
+ *OutputBufferSize = SECTION_SIZE (InputSection) - ((EFI_GUID_DEFINED_SECTION *) InputSection)->DataOffset;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Extraction handler tries to extract raw data from the input guided section.
+ It also does authentication check for 32bit CRC value in the input guided section.
+ It first checks whether the input guid section is supported.
+ If not, EFI_INVALID_PARAMETER will return.
+
+ @param InputSection Buffer containing the input GUIDed section to be processed.
+ @param OutputBuffer Buffer to contain the output raw data allocated by the caller.
+ @param ScratchBuffer A pointer to a caller-allocated buffer for function internal use.
+ @param AuthenticationStatus A pointer to a caller-allocated UINT32 that indicates the
+ authentication status of the output buffer.
+
+ @retval EFI_SUCCESS Section Data and Auth Status is extracted successfully.
+ @retval EFI_INVALID_PARAMETER The GUID in InputSection does not match this instance guid.
+
+**/
+EFI_STATUS
+EFIAPI
+Crc32GuidedSectionHandler (
+ IN CONST VOID *InputSection,
+ OUT VOID **OutputBuffer,
+ IN VOID *ScratchBuffer, OPTIONAL
+ OUT UINT32 *AuthenticationStatus
+ )
+{
+ EFI_STATUS Status;
+ UINT32 SectionCrc32Checksum;
+ UINT32 Crc32Checksum;
+ UINT32 OutputBufferSize;
+
+ if (IS_SECTION2 (InputSection)) {
+ //
+ // Check whether the input guid section is recognized.
+ //
+ if (!CompareGuid (
+ &gEfiCrc32GuidedSectionExtractionGuid,
+ &(((EFI_GUID_DEFINED_SECTION2 *) InputSection)->SectionDefinitionGuid))) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Get section Crc32 checksum.
+ //
+ SectionCrc32Checksum = ((CRC32_SECTION2_HEADER *) InputSection)->CRC32Checksum;
+ *OutputBuffer = (UINT8 *) InputSection + ((EFI_GUID_DEFINED_SECTION2 *) InputSection)->DataOffset;
+ OutputBufferSize = SECTION2_SIZE (InputSection) - ((EFI_GUID_DEFINED_SECTION2 *) InputSection)->DataOffset;
+
+ //
+ // Implicitly CRC32 GUIDed section should have STATUS_VALID bit set
+ //
+ ASSERT (((EFI_GUID_DEFINED_SECTION2 *) InputSection)->Attributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID);
+ *AuthenticationStatus = EFI_AUTH_STATUS_IMAGE_SIGNED;
+ } else {
+ //
+ // Check whether the input guid section is recognized.
+ //
+ if (!CompareGuid (
+ &gEfiCrc32GuidedSectionExtractionGuid,
+ &(((EFI_GUID_DEFINED_SECTION *) InputSection)->SectionDefinitionGuid))) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Get section Crc32 checksum.
+ //
+ SectionCrc32Checksum = ((CRC32_SECTION_HEADER *) InputSection)->CRC32Checksum;
+ *OutputBuffer = (UINT8 *) InputSection + ((EFI_GUID_DEFINED_SECTION *) InputSection)->DataOffset;
+ OutputBufferSize = SECTION_SIZE (InputSection) - ((EFI_GUID_DEFINED_SECTION *) InputSection)->DataOffset;
+
+ //
+ // Implicitly CRC32 GUIDed section should have STATUS_VALID bit set
+ //
+ ASSERT (((EFI_GUID_DEFINED_SECTION *) InputSection)->Attributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID);
+ *AuthenticationStatus = EFI_AUTH_STATUS_IMAGE_SIGNED;
+ }
+
+ //
+ // Init Checksum value to Zero.
+ //
+ Crc32Checksum = 0;
+
+ //
+ // Calculate CRC32 Checksum of Image
+ //
+ Status = PeiCrc32GuidedSectionExtractLibCalculateCrc32 (*OutputBuffer, OutputBufferSize, &Crc32Checksum);
+ if (Status == EFI_SUCCESS) {
+ if (Crc32Checksum != SectionCrc32Checksum) {
+ //
+ // If Crc32 checksum is not matched, AUTH tested failed bit is set.
+ //
+ *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED;
+ }
+ } else {
+ //
+ // If Crc32 checksum is not calculated, AUTH not tested bit is set.
+ //
+ *AuthenticationStatus |= EFI_AUTH_STATUS_NOT_TESTED;
+ }
+
+ //
+ // Temp solution until PeiCore checks AUTH Status.
+ //
+ if ((*AuthenticationStatus & (EFI_AUTH_STATUS_TEST_FAILED | EFI_AUTH_STATUS_NOT_TESTED)) != 0) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Register the handler to extract CRC32 guided section.
+
+ @param FileHandle The handle of FFS header the loaded driver.
+ @param PeiServices The pointer to the PEI services.
+
+ @retval EFI_SUCCESS Register successfully.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to register this handler.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiCrc32GuidedSectionExtractLibConstructor (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+{
+ return ExtractGuidedSectionRegisterHandlers (
+ &gEfiCrc32GuidedSectionExtractionGuid,
+ Crc32GuidedSectionGetInfo,
+ Crc32GuidedSectionHandler
+ );
+}
diff --git a/Core/MdeModulePkg/Library/PeiCrc32GuidedSectionExtractLib/PeiCrc32GuidedSectionExtractLib.inf b/Core/MdeModulePkg/Library/PeiCrc32GuidedSectionExtractLib/PeiCrc32GuidedSectionExtractLib.inf
new file mode 100644
index 0000000000..7134810040
--- /dev/null
+++ b/Core/MdeModulePkg/Library/PeiCrc32GuidedSectionExtractLib/PeiCrc32GuidedSectionExtractLib.inf
@@ -0,0 +1,48 @@
+## @file
+# Pei Crc32 Guided Section Extract library.
+#
+# This library doesn't produce any library class. The constructor function uses
+# ExtractGuidedSectionLib service to register CRC32 guided section handler
+# that parses CRC32 encapsulation section and extracts raw data.
+#
+# Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PeiCrc32GuidedSectionExtractLib
+ FILE_GUID = 1EBE57F5-BE42-45f0-A1F9-FA3DC633910B
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = NULL|PEI_CORE PEIM
+ CONSTRUCTOR = PeiCrc32GuidedSectionExtractLibConstructor
+ MODULE_UNI_FILE = PeiCrc32GuidedSectionExtractLib.uni
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC (EBC is for build only)
+#
+
+[Sources]
+ PeiCrc32GuidedSectionExtractLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ ExtractGuidedSectionLib
+ DebugLib
+ BaseMemoryLib
+
+[Guids]
+ gEfiCrc32GuidedSectionExtractionGuid ## PRODUCES ## UNDEFINED
diff --git a/Core/MdeModulePkg/Library/PeiCrc32GuidedSectionExtractLib/PeiCrc32GuidedSectionExtractLib.uni b/Core/MdeModulePkg/Library/PeiCrc32GuidedSectionExtractLib/PeiCrc32GuidedSectionExtractLib.uni
new file mode 100644
index 0000000000..408aadb76d
--- /dev/null
+++ b/Core/MdeModulePkg/Library/PeiCrc32GuidedSectionExtractLib/PeiCrc32GuidedSectionExtractLib.uni
Binary files differ
diff --git a/Core/MdeModulePkg/Library/PeiDebugPrintHobLib/PeiDebugPrintHobLib.c b/Core/MdeModulePkg/Library/PeiDebugPrintHobLib/PeiDebugPrintHobLib.c
new file mode 100644
index 0000000000..4bcf0030a0
--- /dev/null
+++ b/Core/MdeModulePkg/Library/PeiDebugPrintHobLib/PeiDebugPrintHobLib.c
@@ -0,0 +1,78 @@
+/** @file
+ NULL Library class that reads Debug Mask variable and if it exists makes a
+ HOB that contains the debug mask.
+
+ Copyright (c) 2011, Apple, Inc. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiPei.h>
+
+#include <Library/HobLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PeiServicesLib.h>
+
+#include <Ppi/ReadOnlyVariable2.h>
+#include <Guid/DebugMask.h>
+
+
+/**
+ The constructor reads variable and sets HOB
+
+ @param FileHandle The handle of FFS header the loaded driver.
+ @param PeiServices The pointer to the PEI services.
+
+ @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiDebugPrintHobLibConstructor (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+{
+ EFI_STATUS Status;
+ EFI_PEI_READ_ONLY_VARIABLE2_PPI *Variable;
+ UINTN Size;
+ UINT64 GlobalErrorLevel;
+ UINT32 HobErrorLevel;
+
+ Status = PeiServicesLocatePpi (
+ &gEfiPeiReadOnlyVariable2PpiGuid,
+ 0,
+ NULL,
+ (VOID **)&Variable
+ );
+ if (!EFI_ERROR (Status)) {
+ Size = sizeof (GlobalErrorLevel);
+ Status = Variable->GetVariable (
+ Variable,
+ DEBUG_MASK_VARIABLE_NAME,
+ &gEfiGenericVariableGuid,
+ NULL,
+ &Size,
+ &GlobalErrorLevel
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Build the GUID'ed HOB for DXE
+ //
+ HobErrorLevel = (UINT32)GlobalErrorLevel;
+ BuildGuidDataHob (
+ &gEfiGenericVariableGuid,
+ &HobErrorLevel,
+ sizeof (HobErrorLevel)
+ );
+ }
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/Core/MdeModulePkg/Library/PeiDebugPrintHobLib/PeiDebugPrintHobLib.inf b/Core/MdeModulePkg/Library/PeiDebugPrintHobLib/PeiDebugPrintHobLib.inf
new file mode 100644
index 0000000000..0380dee01f
--- /dev/null
+++ b/Core/MdeModulePkg/Library/PeiDebugPrintHobLib/PeiDebugPrintHobLib.inf
@@ -0,0 +1,50 @@
+## @file
+# NULL Library class that reads Debug Mask variable and if it exists makes a
+# HOB that contains the debug mask.
+#
+# Copyright (c) 2011, Apple, Inc. All rights reserved.<BR>
+# Copyright (c) 2012 - 2014, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PeiDebugPrintHobLib
+ MODULE_UNI_FILE = PeiDebugPrintHobLib.uni
+ FILE_GUID = EB0BDD73-DABB-E74B-BF51-62DC1DA521E1
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = NULL|PEIM
+ CONSTRUCTOR = PeiDebugPrintHobLibConstructor
+
+
+[Sources]
+ PeiDebugPrintHobLib.c
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ PeiServicesLib
+ DebugLib
+
+[Ppis]
+ gEfiPeiReadOnlyVariable2PpiGuid ## CONSUMES
+
+[Guids]
+ ## SOMETIMES_CONSUMES ## Variable:L"EFIDebug"
+ ## SOMETIMES_PRODUCES ## HOB
+ gEfiGenericVariableGuid
+
+[Depex]
+ gEfiPeiReadOnlyVariable2PpiGuid \ No newline at end of file
diff --git a/Core/MdeModulePkg/Library/PeiDebugPrintHobLib/PeiDebugPrintHobLib.uni b/Core/MdeModulePkg/Library/PeiDebugPrintHobLib/PeiDebugPrintHobLib.uni
new file mode 100644
index 0000000000..686c606c79
--- /dev/null
+++ b/Core/MdeModulePkg/Library/PeiDebugPrintHobLib/PeiDebugPrintHobLib.uni
Binary files differ
diff --git a/Core/MdeModulePkg/Library/PeiDxeDebugLibReportStatusCode/DebugLib.c b/Core/MdeModulePkg/Library/PeiDxeDebugLibReportStatusCode/DebugLib.c
new file mode 100644
index 0000000000..f1d98277a3
--- /dev/null
+++ b/Core/MdeModulePkg/Library/PeiDxeDebugLibReportStatusCode/DebugLib.c
@@ -0,0 +1,461 @@
+/** @file
+ Debug Library based on report status code library.
+
+ Note that if the debug message length is larger than the maximum allowable
+ record length, then the debug message will be ignored directly.
+
+ Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiPei.h>
+
+#include <Guid/StatusCodeDataTypeId.h>
+#include <Guid/StatusCodeDataTypeDebug.h>
+
+#include <Library/DebugLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/PcdLib.h>
+#include <Library/DebugPrintErrorLevelLib.h>
+
+/**
+ Prints a debug message to the debug output device if the specified error level is enabled.
+
+ If any bit in ErrorLevel is also set in DebugPrintErrorLevelLib function
+ GetDebugPrintErrorLevel (), then print the message specified by Format and the
+ associated variable argument list to the debug output device.
+
+ If Format is NULL, then ASSERT().
+
+ If the length of the message string specificed by Format is larger than the maximum allowable
+ record length, then directly return and not print it.
+
+ @param ErrorLevel The error level of the debug message.
+ @param Format Format string for the debug message to print.
+ @param ... Variable argument list whose contents are accessed
+ based on the format string specified by Format.
+
+**/
+VOID
+EFIAPI
+DebugPrint (
+ IN UINTN ErrorLevel,
+ IN CONST CHAR8 *Format,
+ ...
+ )
+{
+ UINT64 Buffer[(EFI_STATUS_CODE_DATA_MAX_SIZE / sizeof (UINT64)) + 1];
+ EFI_DEBUG_INFO *DebugInfo;
+ UINTN TotalSize;
+ VA_LIST VaListMarker;
+ BASE_LIST BaseListMarker;
+ CHAR8 *FormatString;
+ BOOLEAN Long;
+
+ //
+ // If Format is NULL, then ASSERT().
+ //
+ ASSERT (Format != NULL);
+
+ //
+ // Check driver Debug Level value and global debug level
+ //
+ if ((ErrorLevel & GetDebugPrintErrorLevel ()) == 0) {
+ return;
+ }
+
+ //
+ // Compute the total size of the record.
+ // Note that the passing-in format string and variable parameters will be constructed to
+ // the following layout:
+ //
+ // Buffer->|------------------------|
+ // | Padding | 4 bytes
+ // DebugInfo->|------------------------|
+ // | EFI_DEBUG_INFO | sizeof(EFI_DEBUG_INFO)
+ // BaseListMarker->|------------------------|
+ // | ... |
+ // | variable arguments | 12 * sizeof (UINT64)
+ // | ... |
+ // |------------------------|
+ // | Format String |
+ // |------------------------|<- (UINT8 *)Buffer + sizeof(Buffer)
+ //
+ TotalSize = 4 + sizeof (EFI_DEBUG_INFO) + 12 * sizeof (UINT64) + AsciiStrSize (Format);
+
+ //
+ // If the TotalSize is larger than the maximum record size, then return
+ //
+ if (TotalSize > sizeof (Buffer)) {
+ return;
+ }
+
+ //
+ // Fill in EFI_DEBUG_INFO
+ //
+ // Here we skip the first 4 bytes of Buffer, because we must ensure BaseListMarker is
+ // 64-bit aligned, otherwise retrieving 64-bit parameter from BaseListMarker will cause
+ // exception on IPF. Buffer starts at 64-bit aligned address, so skipping 4 types (sizeof(EFI_DEBUG_INFO))
+ // just makes address of BaseListMarker, which follows DebugInfo, 64-bit aligned.
+ //
+ DebugInfo = (EFI_DEBUG_INFO *)(Buffer) + 1;
+ DebugInfo->ErrorLevel = (UINT32)ErrorLevel;
+ BaseListMarker = (BASE_LIST)(DebugInfo + 1);
+ FormatString = (CHAR8 *)((UINT64 *)(DebugInfo + 1) + 12);
+
+ //
+ // Copy the Format string into the record
+ //
+ AsciiStrCpyS (FormatString, sizeof(Buffer) - (4 + sizeof(EFI_DEBUG_INFO) + 12 * sizeof(UINT64)), Format);
+
+ //
+ // The first 12 * sizeof (UINT64) bytes following EFI_DEBUG_INFO are for variable arguments
+ // of format in DEBUG string, which is followed by the DEBUG format string.
+ // Here we will process the variable arguments and pack them in this area.
+ //
+ VA_START (VaListMarker, Format);
+ for (; *Format != '\0'; Format++) {
+ //
+ // Only format with prefix % is processed.
+ //
+ if (*Format != '%') {
+ continue;
+ }
+ Long = FALSE;
+ //
+ // Parse Flags and Width
+ //
+ for (Format++; TRUE; Format++) {
+ if (*Format == '.' || *Format == '-' || *Format == '+' || *Format == ' ') {
+ //
+ // These characters in format field are omitted.
+ //
+ continue;
+ }
+ if (*Format >= '0' && *Format <= '9') {
+ //
+ // These characters in format field are omitted.
+ //
+ continue;
+ }
+ if (*Format == 'L' || *Format == 'l') {
+ //
+ // 'L" or "l" in format field means the number being printed is a UINT64
+ //
+ Long = TRUE;
+ continue;
+ }
+ if (*Format == '*') {
+ //
+ // '*' in format field means the precision of the field is specified by
+ // a UINTN argument in the argument list.
+ //
+ BASE_ARG (BaseListMarker, UINTN) = VA_ARG (VaListMarker, UINTN);
+ continue;
+ }
+ if (*Format == '\0') {
+ //
+ // Make no output if Format string terminates unexpectedly when
+ // looking up for flag, width, precision and type.
+ //
+ Format--;
+ }
+ //
+ // When valid argument type detected or format string terminates unexpectedly,
+ // the inner loop is done.
+ //
+ break;
+ }
+
+ //
+ // Pack variable arguments into the storage area following EFI_DEBUG_INFO.
+ //
+ if ((*Format == 'p') && (sizeof (VOID *) > 4)) {
+ Long = TRUE;
+ }
+ if (*Format == 'p' || *Format == 'X' || *Format == 'x' || *Format == 'd' || *Format == 'u') {
+ if (Long) {
+ BASE_ARG (BaseListMarker, INT64) = VA_ARG (VaListMarker, INT64);
+ } else {
+ BASE_ARG (BaseListMarker, int) = VA_ARG (VaListMarker, int);
+ }
+ } else if (*Format == 's' || *Format == 'S' || *Format == 'a' || *Format == 'g' || *Format == 't') {
+ BASE_ARG (BaseListMarker, VOID *) = VA_ARG (VaListMarker, VOID *);
+ } else if (*Format == 'c') {
+ BASE_ARG (BaseListMarker, UINTN) = VA_ARG (VaListMarker, UINTN);
+ } else if (*Format == 'r') {
+ BASE_ARG (BaseListMarker, RETURN_STATUS) = VA_ARG (VaListMarker, RETURN_STATUS);
+ }
+
+ //
+ // If the converted BASE_LIST is larger than the 12 * sizeof (UINT64) allocated bytes, then ASSERT()
+ // This indicates that the DEBUG() macro is passing in more argument than can be handled by
+ // the EFI_DEBUG_INFO record
+ //
+ ASSERT ((CHAR8 *)BaseListMarker <= FormatString);
+
+ //
+ // If the converted BASE_LIST is larger than the 12 * sizeof (UINT64) allocated bytes, then return
+ //
+ if ((CHAR8 *)BaseListMarker > FormatString) {
+ VA_END (VaListMarker);
+ return;
+ }
+ }
+ VA_END (VaListMarker);
+
+ //
+ // Send the DebugInfo record
+ //
+ REPORT_STATUS_CODE_EX (
+ EFI_DEBUG_CODE,
+ (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_DC_UNSPECIFIED),
+ 0,
+ NULL,
+ &gEfiStatusCodeDataTypeDebugGuid,
+ DebugInfo,
+ TotalSize
+ );
+}
+
+/**
+ Prints an assert message containing a filename, line number, and description.
+ This may be followed by a breakpoint or a dead loop.
+
+ Print a message of the form "ASSERT <FileName>(<LineNumber>): <Description>\n"
+ to the debug output device. If DEBUG_PROPERTY_ASSERT_BREAKPOINT_ENABLED bit of
+ PcdDebugProperyMask is set then CpuBreakpoint() is called. Otherwise, if
+ DEBUG_PROPERTY_ASSERT_DEADLOOP_ENABLED bit of PcdDebugProperyMask is set then
+ CpuDeadLoop() is called. If neither of these bits are set, then this function
+ returns immediately after the message is printed to the debug output device.
+ DebugAssert() must actively prevent recursion. If DebugAssert() is called while
+ processing another DebugAssert(), then DebugAssert() must return immediately.
+
+ If FileName is NULL, then a <FileName> string of "(NULL) Filename" is printed.
+ If Description is NULL, then a <Description> string of "(NULL) Description" is printed.
+
+ @param FileName Pointer to the name of the source file that generated the assert condition.
+ @param LineNumber The line number in the source file that generated the assert condition
+ @param Description Pointer to the description of the assert condition.
+
+**/
+VOID
+EFIAPI
+DebugAssert (
+ IN CONST CHAR8 *FileName,
+ IN UINTN LineNumber,
+ IN CONST CHAR8 *Description
+ )
+{
+ UINT64 Buffer[EFI_STATUS_CODE_DATA_MAX_SIZE / sizeof(UINT64)];
+ EFI_DEBUG_ASSERT_DATA *AssertData;
+ UINTN HeaderSize;
+ UINTN TotalSize;
+ CHAR8 *Temp;
+ UINTN FileNameSize;
+ UINTN DescriptionSize;
+
+ //
+ // Get string size
+ //
+ HeaderSize = sizeof (EFI_DEBUG_ASSERT_DATA);
+ FileNameSize = AsciiStrSize (FileName);
+ DescriptionSize = AsciiStrSize (Description);
+
+ //
+ // Make sure it will all fit in the passed in buffer.
+ //
+ if (HeaderSize + FileNameSize + DescriptionSize > sizeof (Buffer)) {
+ //
+ // FileName + Description is too long to be filled into buffer.
+ //
+ if (HeaderSize + FileNameSize < sizeof (Buffer)) {
+ //
+ // Description has enough buffer to be truncated.
+ //
+ DescriptionSize = sizeof (Buffer) - HeaderSize - FileNameSize;
+ } else {
+ //
+ // FileName is too long to be filled into buffer.
+ // FileName will be truncated. Reserved one byte for Description NULL terminator.
+ //
+ DescriptionSize = 1;
+ FileNameSize = sizeof (Buffer) - HeaderSize - DescriptionSize;
+ }
+ }
+
+ //
+ // Fill in EFI_DEBUG_ASSERT_DATA
+ //
+ AssertData = (EFI_DEBUG_ASSERT_DATA *)Buffer;
+ AssertData->LineNumber = (UINT32)LineNumber;
+ TotalSize = sizeof (EFI_DEBUG_ASSERT_DATA);
+
+ //
+ // Copy Ascii FileName including NULL terminator.
+ //
+ Temp = CopyMem (AssertData + 1, FileName, FileNameSize);
+ Temp[FileNameSize - 1] = 0;
+ TotalSize += FileNameSize;
+
+ //
+ // Copy Ascii Description include NULL terminator.
+ //
+ Temp = CopyMem (Temp + FileNameSize, Description, DescriptionSize);
+ Temp[DescriptionSize - 1] = 0;
+ TotalSize += DescriptionSize;
+
+ REPORT_STATUS_CODE_EX (
+ (EFI_ERROR_CODE | EFI_ERROR_UNRECOVERED),
+ (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_EC_ILLEGAL_SOFTWARE_STATE),
+ 0,
+ NULL,
+ NULL,
+ AssertData,
+ TotalSize
+ );
+
+ //
+ // Generate a Breakpoint, DeadLoop, or NOP based on PCD settings
+ //
+ if ((PcdGet8 (PcdDebugPropertyMask) & DEBUG_PROPERTY_ASSERT_BREAKPOINT_ENABLED) != 0) {
+ CpuBreakpoint ();
+ } else if ((PcdGet8 (PcdDebugPropertyMask) & DEBUG_PROPERTY_ASSERT_DEADLOOP_ENABLED) != 0) {
+ CpuDeadLoop ();
+ }
+}
+
+
+/**
+ Fills a target buffer with PcdDebugClearMemoryValue, and returns the target buffer.
+
+ This function fills Length bytes of Buffer with the value specified by
+ PcdDebugClearMemoryValue, and returns Buffer.
+
+ If Buffer is NULL, then ASSERT().
+ If Length is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
+
+ @param Buffer Pointer to the target buffer to be filled with PcdDebugClearMemoryValue.
+ @param Length Number of bytes in Buffer to fill with zeros PcdDebugClearMemoryValue.
+
+ @return Buffer Pointer to the target buffer filled with PcdDebugClearMemoryValue.
+
+**/
+VOID *
+EFIAPI
+DebugClearMemory (
+ OUT VOID *Buffer,
+ IN UINTN Length
+ )
+{
+ ASSERT (Buffer != NULL);
+
+ return SetMem (Buffer, Length, PcdGet8 (PcdDebugClearMemoryValue));
+}
+
+
+/**
+ Returns TRUE if ASSERT() macros are enabled.
+
+ This function returns TRUE if the DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED bit of
+ PcdDebugProperyMask is set. Otherwise FALSE is returned.
+
+ @retval TRUE The DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED bit of PcdDebugProperyMask is set.
+ @retval FALSE The DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED bit of PcdDebugProperyMask is clear.
+
+**/
+BOOLEAN
+EFIAPI
+DebugAssertEnabled (
+ VOID
+ )
+{
+ return (BOOLEAN) ((PcdGet8 (PcdDebugPropertyMask) & DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED) != 0);
+}
+
+
+/**
+ Returns TRUE if DEBUG() macros are enabled.
+
+ This function returns TRUE if the DEBUG_PROPERTY_DEBUG_PRINT_ENABLED bit of
+ PcdDebugProperyMask is set. Otherwise FALSE is returned.
+
+ @retval TRUE The DEBUG_PROPERTY_DEBUG_PRINT_ENABLED bit of PcdDebugProperyMask is set.
+ @retval FALSE The DEBUG_PROPERTY_DEBUG_PRINT_ENABLED bit of PcdDebugProperyMask is clear.
+
+**/
+BOOLEAN
+EFIAPI
+DebugPrintEnabled (
+ VOID
+ )
+{
+ return (BOOLEAN) ((PcdGet8 (PcdDebugPropertyMask) & DEBUG_PROPERTY_DEBUG_PRINT_ENABLED) != 0);
+}
+
+
+/**
+ Returns TRUE if DEBUG_CODE() macros are enabled.
+
+ This function returns TRUE if the DEBUG_PROPERTY_DEBUG_CODE_ENABLED bit of
+ PcdDebugProperyMask is set. Otherwise FALSE is returned.
+
+ @retval TRUE The DEBUG_PROPERTY_DEBUG_CODE_ENABLED bit of PcdDebugProperyMask is set.
+ @retval FALSE The DEBUG_PROPERTY_DEBUG_CODE_ENABLED bit of PcdDebugProperyMask is clear.
+
+**/
+BOOLEAN
+EFIAPI
+DebugCodeEnabled (
+ VOID
+ )
+{
+ return (BOOLEAN) ((PcdGet8 (PcdDebugPropertyMask) & DEBUG_PROPERTY_DEBUG_CODE_ENABLED) != 0);
+}
+
+
+/**
+ Returns TRUE if DEBUG_CLEAR_MEMORY() macro is enabled.
+
+ This function returns TRUE if the DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED bit of
+ PcdDebugProperyMask is set. Otherwise FALSE is returned.
+
+ @retval TRUE The DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED bit of PcdDebugProperyMask is set.
+ @retval FALSE The DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED bit of PcdDebugProperyMask is clear.
+
+**/
+BOOLEAN
+EFIAPI
+DebugClearMemoryEnabled (
+ VOID
+ )
+{
+ return (BOOLEAN) ((PcdGet8 (PcdDebugPropertyMask) & DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED) != 0);
+}
+
+/**
+ Returns TRUE if any one of the bit is set both in ErrorLevel and PcdFixedDebugPrintErrorLevel.
+
+ This function compares the bit mask of ErrorLevel and PcdFixedDebugPrintErrorLevel.
+
+ @retval TRUE Current ErrorLevel is supported.
+ @retval FALSE Current ErrorLevel is not supported.
+
+**/
+BOOLEAN
+EFIAPI
+DebugPrintLevelEnabled (
+ IN CONST UINTN ErrorLevel
+ )
+{
+ return (BOOLEAN) ((ErrorLevel & PcdGet32(PcdFixedDebugPrintErrorLevel)) != 0);
+}
diff --git a/Core/MdeModulePkg/Library/PeiDxeDebugLibReportStatusCode/PeiDxeDebugLibReportStatusCode.inf b/Core/MdeModulePkg/Library/PeiDxeDebugLibReportStatusCode/PeiDxeDebugLibReportStatusCode.inf
new file mode 100644
index 0000000000..55446672d7
--- /dev/null
+++ b/Core/MdeModulePkg/Library/PeiDxeDebugLibReportStatusCode/PeiDxeDebugLibReportStatusCode.inf
@@ -0,0 +1,54 @@
+## @file
+# Debug Library based on report status code library
+#
+# Debug Library for PEIMs and DXE drivers that sends debug messages to ReportStatusCode
+# Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PeiDxeDebugLibReportStatusCode
+ MODULE_UNI_FILE = PeiDxeDebugLibReportStatusCode.uni
+ FILE_GUID = bda39d3a-451b-4350-8266-81ab10fa0523
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = DebugLib|DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SAL_DRIVER DXE_SMM_DRIVER SMM_CORE PEIM SEC PEI_CORE UEFI_APPLICATION UEFI_DRIVER
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ DebugLib.c
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ PcdLib
+ ReportStatusCodeLib
+ BaseMemoryLib
+ BaseLib
+ DebugPrintErrorLevelLib
+
+[Pcd]
+ gEfiMdePkgTokenSpaceGuid.PcdDebugClearMemoryValue ## SOMETIMES_CONSUMES
+ gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask ## CONSUMES
+ gEfiMdePkgTokenSpaceGuid.PcdFixedDebugPrintErrorLevel ## CONSUMES
+
+[Guids]
+ gEfiStatusCodeDataTypeDebugGuid ## SOMETIMES_CONSUMES ## GUID
+
diff --git a/Core/MdeModulePkg/Library/PeiDxeDebugLibReportStatusCode/PeiDxeDebugLibReportStatusCode.uni b/Core/MdeModulePkg/Library/PeiDxeDebugLibReportStatusCode/PeiDxeDebugLibReportStatusCode.uni
new file mode 100644
index 0000000000..fe2abee431
--- /dev/null
+++ b/Core/MdeModulePkg/Library/PeiDxeDebugLibReportStatusCode/PeiDxeDebugLibReportStatusCode.uni
Binary files differ
diff --git a/Core/MdeModulePkg/Library/PeiIpmiLibIpmiPpi/PeiIpmiLibIpmiPpi.c b/Core/MdeModulePkg/Library/PeiIpmiLibIpmiPpi/PeiIpmiLibIpmiPpi.c
new file mode 100644
index 0000000000..cb6a007360
--- /dev/null
+++ b/Core/MdeModulePkg/Library/PeiIpmiLibIpmiPpi/PeiIpmiLibIpmiPpi.c
@@ -0,0 +1,81 @@
+/** @file
+ Implementation of Ipmi Library in PEI Phase for SMS.
+
+ Copyright (c) 2014 - 2015, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiPei.h>
+#include <Ppi/IpmiPpi.h>
+#include <Library/IpmiLib.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/DebugLib.h>
+
+
+/**
+ This service enables submitting commands via Ipmi.
+
+ @param[in] NetFunction Net function of the command.
+ @param[in] Command IPMI Command.
+ @param[in] RequestData Command Request Data.
+ @param[in] RequestDataSize Size of Command Request Data.
+ @param[out] ResponseData Command Response Data. The completion code is the first byte of response data.
+ @param[in, out] ResponseDataSize Size of Command Response Data.
+
+ @retval EFI_SUCCESS The command byte stream was successfully submit to the device and a response was successfully received.
+ @retval EFI_NOT_FOUND The command was not successfully sent to the device or a response was not successfully received from the device.
+ @retval EFI_NOT_READY Ipmi Device is not ready for Ipmi command access.
+ @retval EFI_DEVICE_ERROR Ipmi Device hardware error.
+ @retval EFI_TIMEOUT The command time out.
+ @retval EFI_UNSUPPORTED The command was not successfully sent to the device.
+ @retval EFI_OUT_OF_RESOURCES The resource allcation is out of resource or data size error.
+**/
+EFI_STATUS
+EFIAPI
+IpmiSubmitCommand (
+ IN UINT8 NetFunction,
+ IN UINT8 Command,
+ IN UINT8 *RequestData,
+ IN UINT32 RequestDataSize,
+ OUT UINT8 *ResponseData,
+ IN OUT UINT32 *ResponseDataSize
+ )
+{
+ EFI_STATUS Status;
+ PEI_IPMI_PPI *IpmiPpi;
+
+ Status = PeiServicesLocatePpi(
+ &gPeiIpmiPpiGuid,
+ 0,
+ NULL,
+ (VOID **) &IpmiPpi
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Ipmi Ppi is not installed. So, IPMI device is not present.
+ //
+ DEBUG ((EFI_D_ERROR, "IpmiSubmitCommand in Pei Phase under SMS Status - %r\n", Status));
+ return EFI_NOT_FOUND;
+ }
+
+ Status = IpmiPpi->IpmiSubmitCommand (
+ IpmiPpi,
+ NetFunction,
+ Command,
+ RequestData,
+ RequestDataSize,
+ ResponseData,
+ ResponseDataSize
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ return EFI_SUCCESS;
+}
diff --git a/Core/MdeModulePkg/Library/PeiIpmiLibIpmiPpi/PeiIpmiLibIpmiPpi.inf b/Core/MdeModulePkg/Library/PeiIpmiLibIpmiPpi/PeiIpmiLibIpmiPpi.inf
new file mode 100644
index 0000000000..e2e2646f91
--- /dev/null
+++ b/Core/MdeModulePkg/Library/PeiIpmiLibIpmiPpi/PeiIpmiLibIpmiPpi.inf
@@ -0,0 +1,41 @@
+## @file
+# Instance of IPMI Library in PEI phase for SMS.
+#
+# Copyright (c) 2014 - 2015, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php.
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PeiIpmiLibIpmiPpi
+ FILE_GUID = 43679142-87C4-44AD-AF02-B47F782D6CF3
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = IpmiLib|PEIM PEI_CORE
+
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ PeiIpmiLibIpmiPpi.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ DebugLib
+ BaseMemoryLib
+ PeiServicesLib
+
+[Ppis]
+ gPeiIpmiPpiGuid ## SOMETIMES_CONSUMES
diff --git a/Core/MdeModulePkg/Library/PeiPerformanceLib/PeiPerformanceLib.c b/Core/MdeModulePkg/Library/PeiPerformanceLib/PeiPerformanceLib.c
new file mode 100644
index 0000000000..0b5a717caa
--- /dev/null
+++ b/Core/MdeModulePkg/Library/PeiPerformanceLib/PeiPerformanceLib.c
@@ -0,0 +1,494 @@
+/** @file
+ Performance library instance used in PEI phase.
+
+ This file implements all APIs in Performance Library class in MdePkg. It creates
+ performance logging GUIDed HOB on the first performance logging and then logs the
+ performance data to the GUIDed HOB. Due to the limitation of temporary RAM, the maximum
+ number of performance logging entry is specified by PcdMaxPeiPerformanceLogEntries.
+
+Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+
+#include <PiPei.h>
+
+#include <Guid/Performance.h>
+
+#include <Library/PerformanceLib.h>
+#include <Library/DebugLib.h>
+#include <Library/HobLib.h>
+#include <Library/BaseLib.h>
+#include <Library/TimerLib.h>
+#include <Library/PcdLib.h>
+#include <Library/BaseMemoryLib.h>
+
+
+/**
+ Gets the GUID HOB for PEI performance.
+
+ This internal function searches for the GUID HOB for PEI performance.
+ If that GUID HOB is not found, it will build a new one.
+ It outputs the data area of that GUID HOB to record performance log.
+
+ @param PeiPerformanceLog Pointer to Pointer to PEI performance log header.
+ @param PeiPerformanceIdArray Pointer to Pointer to PEI performance identifier array.
+
+**/
+VOID
+InternalGetPerformanceHobLog (
+ OUT PEI_PERFORMANCE_LOG_HEADER **PeiPerformanceLog,
+ OUT UINT32 **PeiPerformanceIdArray
+ )
+{
+ EFI_HOB_GUID_TYPE *GuidHob;
+ UINTN PeiPerformanceSize;
+
+ ASSERT (PeiPerformanceLog != NULL);
+ ASSERT (PeiPerformanceIdArray != NULL);
+
+ GuidHob = GetFirstGuidHob (&gPerformanceProtocolGuid);
+
+ if (GuidHob != NULL) {
+ //
+ // PEI Performance HOB was found, then return the existing one.
+ //
+ *PeiPerformanceLog = GET_GUID_HOB_DATA (GuidHob);
+
+ GuidHob = GetFirstGuidHob (&gPerformanceExProtocolGuid);
+ ASSERT (GuidHob != NULL);
+ *PeiPerformanceIdArray = GET_GUID_HOB_DATA (GuidHob);
+ } else {
+ //
+ // PEI Performance HOB was not found, then build one.
+ //
+ PeiPerformanceSize = sizeof (PEI_PERFORMANCE_LOG_HEADER) +
+ sizeof (PEI_PERFORMANCE_LOG_ENTRY) * PcdGet8 (PcdMaxPeiPerformanceLogEntries);
+ *PeiPerformanceLog = BuildGuidHob (&gPerformanceProtocolGuid, PeiPerformanceSize);
+ *PeiPerformanceLog = ZeroMem (*PeiPerformanceLog, PeiPerformanceSize);
+
+ PeiPerformanceSize = sizeof (UINT32) * PcdGet8 (PcdMaxPeiPerformanceLogEntries);
+ *PeiPerformanceIdArray = BuildGuidHob (&gPerformanceExProtocolGuid, PeiPerformanceSize);
+ *PeiPerformanceIdArray = ZeroMem (*PeiPerformanceIdArray, PeiPerformanceSize);
+ }
+}
+
+/**
+ Searches in the log array with keyword Handle, Token, Module and Identifier.
+
+ This internal function searches for the log entry in the log array.
+ If there is an entry that exactly matches the given keywords
+ and its end time stamp is zero, then the index of that log entry is returned;
+ otherwise, the the number of log entries in the array is returned.
+
+ @param PeiPerformanceLog Pointer to the data structure containing PEI
+ performance data.
+ @param PeiPerformanceIdArray Pointer to PEI performance identifier array.
+ @param Handle Pointer to environment specific context used
+ to identify the component being measured.
+ @param Token Pointer to a Null-terminated ASCII string
+ that identifies the component being measured.
+ @param Module Pointer to a Null-terminated ASCII string
+ that identifies the module being measured.
+ @param Identifier 32-bit identifier.
+
+ @retval The index of log entry in the array.
+
+**/
+UINT32
+InternalSearchForLogEntry (
+ IN PEI_PERFORMANCE_LOG_HEADER *PeiPerformanceLog,
+ IN UINT32 *PeiPerformanceIdArray,
+ IN CONST VOID *Handle, OPTIONAL
+ IN CONST CHAR8 *Token, OPTIONAL
+ IN CONST CHAR8 *Module, OPTIONAL
+ IN UINT32 Identifier
+ )
+{
+ UINT32 Index;
+ UINT32 Index2;
+ UINT32 NumberOfEntries;
+ PEI_PERFORMANCE_LOG_ENTRY *LogEntryArray;
+
+
+ if (Token == NULL) {
+ Token = "";
+ }
+ if (Module == NULL) {
+ Module = "";
+ }
+ NumberOfEntries = PeiPerformanceLog->NumberOfEntries;
+ LogEntryArray = (PEI_PERFORMANCE_LOG_ENTRY *) (PeiPerformanceLog + 1);
+
+ Index2 = 0;
+
+ for (Index = 0; Index < NumberOfEntries; Index++) {
+ Index2 = NumberOfEntries - 1 - Index;
+ if (LogEntryArray[Index2].EndTimeStamp == 0 &&
+ (LogEntryArray[Index2].Handle == (EFI_PHYSICAL_ADDRESS) (UINTN) Handle) &&
+ AsciiStrnCmp (LogEntryArray[Index2].Token, Token, PEI_PERFORMANCE_STRING_LENGTH) == 0 &&
+ AsciiStrnCmp (LogEntryArray[Index2].Module, Module, PEI_PERFORMANCE_STRING_LENGTH) == 0 &&
+ (PeiPerformanceIdArray[Index2] == Identifier)) {
+ Index = Index2;
+ break;
+ }
+ }
+ return Index;
+}
+
+/**
+ Creates a record for the beginning of a performance measurement.
+
+ Creates a record that contains the Handle, Token, Module and Identifier.
+ If TimeStamp is not zero, then TimeStamp is added to the record as the start time.
+ If TimeStamp is zero, then this function reads the current time stamp
+ and adds that time stamp value to the record as the start time.
+
+ @param Handle Pointer to environment specific context used
+ to identify the component being measured.
+ @param Token Pointer to a Null-terminated ASCII string
+ that identifies the component being measured.
+ @param Module Pointer to a Null-terminated ASCII string
+ that identifies the module being measured.
+ @param TimeStamp 64-bit time stamp.
+ @param Identifier 32-bit identifier. If the value is 0, the created record
+ is same as the one created by StartPerformanceMeasurement.
+
+ @retval RETURN_SUCCESS The start of the measurement was recorded.
+ @retval RETURN_OUT_OF_RESOURCES There are not enough resources to record the measurement.
+
+**/
+RETURN_STATUS
+EFIAPI
+StartPerformanceMeasurementEx (
+ IN CONST VOID *Handle, OPTIONAL
+ IN CONST CHAR8 *Token, OPTIONAL
+ IN CONST CHAR8 *Module, OPTIONAL
+ IN UINT64 TimeStamp,
+ IN UINT32 Identifier
+ )
+{
+ PEI_PERFORMANCE_LOG_HEADER *PeiPerformanceLog;
+ UINT32 *PeiPerformanceIdArray;
+ PEI_PERFORMANCE_LOG_ENTRY *LogEntryArray;
+ UINT32 Index;
+
+ InternalGetPerformanceHobLog (&PeiPerformanceLog, &PeiPerformanceIdArray);
+
+ if (PeiPerformanceLog->NumberOfEntries >= PcdGet8 (PcdMaxPeiPerformanceLogEntries)) {
+ return RETURN_OUT_OF_RESOURCES;
+ }
+ Index = PeiPerformanceLog->NumberOfEntries++;
+ LogEntryArray = (PEI_PERFORMANCE_LOG_ENTRY *) (PeiPerformanceLog + 1);
+ LogEntryArray[Index].Handle = (EFI_PHYSICAL_ADDRESS) (UINTN) Handle;
+
+ if (Token != NULL) {
+ AsciiStrnCpyS (LogEntryArray[Index].Token, PEI_PERFORMANCE_STRING_SIZE, Token, PEI_PERFORMANCE_STRING_LENGTH);
+ }
+ if (Module != NULL) {
+ AsciiStrnCpyS (LogEntryArray[Index].Module, PEI_PERFORMANCE_STRING_SIZE, Module, PEI_PERFORMANCE_STRING_LENGTH);
+ }
+
+ LogEntryArray[Index].EndTimeStamp = 0;
+ PeiPerformanceIdArray[Index] = Identifier;
+
+ if (TimeStamp == 0) {
+ TimeStamp = GetPerformanceCounter ();
+ }
+ LogEntryArray[Index].StartTimeStamp = TimeStamp;
+
+ return RETURN_SUCCESS;
+}
+
+/**
+ Fills in the end time of a performance measurement.
+
+ Looks up the record that matches Handle, Token, Module and Identifier.
+ If the record can not be found then return RETURN_NOT_FOUND.
+ If the record is found and TimeStamp is not zero,
+ then TimeStamp is added to the record as the end time.
+ If the record is found and TimeStamp is zero, then this function reads
+ the current time stamp and adds that time stamp value to the record as the end time.
+
+ @param Handle Pointer to environment specific context used
+ to identify the component being measured.
+ @param Token Pointer to a Null-terminated ASCII string
+ that identifies the component being measured.
+ @param Module Pointer to a Null-terminated ASCII string
+ that identifies the module being measured.
+ @param TimeStamp 64-bit time stamp.
+ @param Identifier 32-bit identifier. If the value is 0, the found record
+ is same as the one found by EndPerformanceMeasurement.
+
+ @retval RETURN_SUCCESS The end of the measurement was recorded.
+ @retval RETURN_NOT_FOUND The specified measurement record could not be found.
+
+**/
+RETURN_STATUS
+EFIAPI
+EndPerformanceMeasurementEx (
+ IN CONST VOID *Handle, OPTIONAL
+ IN CONST CHAR8 *Token, OPTIONAL
+ IN CONST CHAR8 *Module, OPTIONAL
+ IN UINT64 TimeStamp,
+ IN UINT32 Identifier
+ )
+{
+ PEI_PERFORMANCE_LOG_HEADER *PeiPerformanceLog;
+ UINT32 *PeiPerformanceIdArray;
+ PEI_PERFORMANCE_LOG_ENTRY *LogEntryArray;
+ UINT32 Index;
+
+ if (TimeStamp == 0) {
+ TimeStamp = GetPerformanceCounter ();
+ }
+
+ InternalGetPerformanceHobLog (&PeiPerformanceLog, &PeiPerformanceIdArray);
+ Index = InternalSearchForLogEntry (PeiPerformanceLog, PeiPerformanceIdArray, Handle, Token, Module, Identifier);
+ if (Index >= PeiPerformanceLog->NumberOfEntries) {
+ return RETURN_NOT_FOUND;
+ }
+ LogEntryArray = (PEI_PERFORMANCE_LOG_ENTRY *) (PeiPerformanceLog + 1);
+ LogEntryArray[Index].EndTimeStamp = TimeStamp;
+
+ return RETURN_SUCCESS;
+}
+
+/**
+ Attempts to retrieve a performance measurement log entry from the performance measurement log.
+ It can also retrieve the log created by StartPerformanceMeasurement and EndPerformanceMeasurement,
+ and then assign the Identifier with 0.
+
+ Attempts to retrieve the performance log entry specified by LogEntryKey. If LogEntryKey is
+ zero on entry, then an attempt is made to retrieve the first entry from the performance log,
+ and the key for the second entry in the log is returned. If the performance log is empty,
+ then no entry is retrieved and zero is returned. If LogEntryKey is not zero, then the performance
+ log entry associated with LogEntryKey is retrieved, and the key for the next entry in the log is
+ returned. If LogEntryKey is the key for the last entry in the log, then the last log entry is
+ retrieved and an implementation specific non-zero key value that specifies the end of the performance
+ log is returned. If LogEntryKey is equal this implementation specific non-zero key value, then no entry
+ is retrieved and zero is returned. In the cases where a performance log entry can be returned,
+ the log entry is returned in Handle, Token, Module, StartTimeStamp, EndTimeStamp and Identifier.
+ If LogEntryKey is not a valid log entry key for the performance measurement log, then ASSERT().
+ If Handle is NULL, then ASSERT().
+ If Token is NULL, then ASSERT().
+ If Module is NULL, then ASSERT().
+ If StartTimeStamp is NULL, then ASSERT().
+ If EndTimeStamp is NULL, then ASSERT().
+ If Identifier is NULL, then ASSERT().
+
+ @param LogEntryKey On entry, the key of the performance measurement log entry to retrieve.
+ 0, then the first performance measurement log entry is retrieved.
+ On exit, the key of the next performance of entry entry.
+ @param Handle Pointer to environment specific context used to identify the component
+ being measured.
+ @param Token Pointer to a Null-terminated ASCII string that identifies the component
+ being measured.
+ @param Module Pointer to a Null-terminated ASCII string that identifies the module
+ being measured.
+ @param StartTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
+ was started.
+ @param EndTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
+ was ended.
+ @param Identifier Pointer to the 32-bit identifier that was recorded.
+
+ @return The key for the next performance log entry (in general case).
+
+**/
+UINTN
+EFIAPI
+GetPerformanceMeasurementEx (
+ IN UINTN LogEntryKey,
+ OUT CONST VOID **Handle,
+ OUT CONST CHAR8 **Token,
+ OUT CONST CHAR8 **Module,
+ OUT UINT64 *StartTimeStamp,
+ OUT UINT64 *EndTimeStamp,
+ OUT UINT32 *Identifier
+ )
+{
+ PEI_PERFORMANCE_LOG_HEADER *PeiPerformanceLog;
+ UINT32 *PeiPerformanceIdArray;
+ PEI_PERFORMANCE_LOG_ENTRY *CurrentLogEntry;
+ PEI_PERFORMANCE_LOG_ENTRY *LogEntryArray;
+ UINTN NumberOfEntries;
+
+ ASSERT (Handle != NULL);
+ ASSERT (Token != NULL);
+ ASSERT (Module != NULL);
+ ASSERT (StartTimeStamp != NULL);
+ ASSERT (EndTimeStamp != NULL);
+ ASSERT (Identifier != NULL);
+
+ InternalGetPerformanceHobLog (&PeiPerformanceLog, &PeiPerformanceIdArray);
+
+ NumberOfEntries = (UINTN) (PeiPerformanceLog->NumberOfEntries);
+ LogEntryArray = (PEI_PERFORMANCE_LOG_ENTRY *) (PeiPerformanceLog + 1);
+ //
+ // Make sure that LogEntryKey is a valid log entry key.
+ //
+ ASSERT (LogEntryKey <= NumberOfEntries);
+
+ if (LogEntryKey == NumberOfEntries) {
+ return 0;
+ }
+
+ CurrentLogEntry = &(LogEntryArray[LogEntryKey]);
+
+ *Handle = (VOID *) (UINTN) (CurrentLogEntry->Handle);
+ *Token = CurrentLogEntry->Token;
+ *Module = CurrentLogEntry->Module;
+ *StartTimeStamp = CurrentLogEntry->StartTimeStamp;
+ *EndTimeStamp = CurrentLogEntry->EndTimeStamp;
+ *Identifier = PeiPerformanceIdArray[LogEntryKey++];
+
+ return LogEntryKey;
+}
+
+/**
+ Creates a record for the beginning of a performance measurement.
+
+ Creates a record that contains the Handle, Token, and Module.
+ If TimeStamp is not zero, then TimeStamp is added to the record as the start time.
+ If TimeStamp is zero, then this function reads the current time stamp
+ and adds that time stamp value to the record as the start time.
+
+ @param Handle Pointer to environment specific context used
+ to identify the component being measured.
+ @param Token Pointer to a Null-terminated ASCII string
+ that identifies the component being measured.
+ @param Module Pointer to a Null-terminated ASCII string
+ that identifies the module being measured.
+ @param TimeStamp 64-bit time stamp.
+
+ @retval RETURN_SUCCESS The start of the measurement was recorded.
+ @retval RETURN_OUT_OF_RESOURCES There are not enough resources to record the measurement.
+
+**/
+RETURN_STATUS
+EFIAPI
+StartPerformanceMeasurement (
+ IN CONST VOID *Handle, OPTIONAL
+ IN CONST CHAR8 *Token, OPTIONAL
+ IN CONST CHAR8 *Module, OPTIONAL
+ IN UINT64 TimeStamp
+ )
+{
+ return StartPerformanceMeasurementEx (Handle, Token, Module, TimeStamp, 0);
+}
+
+/**
+ Fills in the end time of a performance measurement.
+
+ Looks up the record that matches Handle, Token, and Module.
+ If the record can not be found then return RETURN_NOT_FOUND.
+ If the record is found and TimeStamp is not zero,
+ then TimeStamp is added to the record as the end time.
+ If the record is found and TimeStamp is zero, then this function reads
+ the current time stamp and adds that time stamp value to the record as the end time.
+
+ @param Handle Pointer to environment specific context used
+ to identify the component being measured.
+ @param Token Pointer to a Null-terminated ASCII string
+ that identifies the component being measured.
+ @param Module Pointer to a Null-terminated ASCII string
+ that identifies the module being measured.
+ @param TimeStamp 64-bit time stamp.
+
+ @retval RETURN_SUCCESS The end of the measurement was recorded.
+ @retval RETURN_NOT_FOUND The specified measurement record could not be found.
+
+**/
+RETURN_STATUS
+EFIAPI
+EndPerformanceMeasurement (
+ IN CONST VOID *Handle, OPTIONAL
+ IN CONST CHAR8 *Token, OPTIONAL
+ IN CONST CHAR8 *Module, OPTIONAL
+ IN UINT64 TimeStamp
+ )
+{
+ return EndPerformanceMeasurementEx (Handle, Token, Module, TimeStamp, 0);
+}
+
+/**
+ Attempts to retrieve a performance measurement log entry from the performance measurement log.
+ It can also retrieve the log created by StartPerformanceMeasurementEx and EndPerformanceMeasurementEx,
+ and then eliminate the Identifier.
+
+ Attempts to retrieve the performance log entry specified by LogEntryKey. If LogEntryKey is
+ zero on entry, then an attempt is made to retrieve the first entry from the performance log,
+ and the key for the second entry in the log is returned. If the performance log is empty,
+ then no entry is retrieved and zero is returned. If LogEntryKey is not zero, then the performance
+ log entry associated with LogEntryKey is retrieved, and the key for the next entry in the log is
+ returned. If LogEntryKey is the key for the last entry in the log, then the last log entry is
+ retrieved and an implementation specific non-zero key value that specifies the end of the performance
+ log is returned. If LogEntryKey is equal this implementation specific non-zero key value, then no entry
+ is retrieved and zero is returned. In the cases where a performance log entry can be returned,
+ the log entry is returned in Handle, Token, Module, StartTimeStamp, and EndTimeStamp.
+ If LogEntryKey is not a valid log entry key for the performance measurement log, then ASSERT().
+ If Handle is NULL, then ASSERT().
+ If Token is NULL, then ASSERT().
+ If Module is NULL, then ASSERT().
+ If StartTimeStamp is NULL, then ASSERT().
+ If EndTimeStamp is NULL, then ASSERT().
+
+ @param LogEntryKey On entry, the key of the performance measurement log entry to retrieve.
+ 0, then the first performance measurement log entry is retrieved.
+ On exit, the key of the next performance of entry entry.
+ @param Handle Pointer to environment specific context used to identify the component
+ being measured.
+ @param Token Pointer to a Null-terminated ASCII string that identifies the component
+ being measured.
+ @param Module Pointer to a Null-terminated ASCII string that identifies the module
+ being measured.
+ @param StartTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
+ was started.
+ @param EndTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
+ was ended.
+
+ @return The key for the next performance log entry (in general case).
+
+**/
+UINTN
+EFIAPI
+GetPerformanceMeasurement (
+ IN UINTN LogEntryKey,
+ OUT CONST VOID **Handle,
+ OUT CONST CHAR8 **Token,
+ OUT CONST CHAR8 **Module,
+ OUT UINT64 *StartTimeStamp,
+ OUT UINT64 *EndTimeStamp
+ )
+{
+ UINT32 Identifier;
+ return GetPerformanceMeasurementEx (LogEntryKey, Handle, Token, Module, StartTimeStamp, EndTimeStamp, &Identifier);
+}
+
+/**
+ Returns TRUE if the performance measurement macros are enabled.
+
+ This function returns TRUE if the PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
+ PcdPerformanceLibraryPropertyMask is set. Otherwise FALSE is returned.
+
+ @retval TRUE The PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
+ PcdPerformanceLibraryPropertyMask is set.
+ @retval FALSE The PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
+ PcdPerformanceLibraryPropertyMask is clear.
+
+**/
+BOOLEAN
+EFIAPI
+PerformanceMeasurementEnabled (
+ VOID
+ )
+{
+ return (BOOLEAN) ((PcdGet8(PcdPerformanceLibraryPropertyMask) & PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED) != 0);
+}
diff --git a/Core/MdeModulePkg/Library/PeiPerformanceLib/PeiPerformanceLib.inf b/Core/MdeModulePkg/Library/PeiPerformanceLib/PeiPerformanceLib.inf
new file mode 100644
index 0000000000..7a5d2407ac
--- /dev/null
+++ b/Core/MdeModulePkg/Library/PeiPerformanceLib/PeiPerformanceLib.inf
@@ -0,0 +1,62 @@
+## @file
+# Performance library instance used in PEI phase.
+#
+# This library provides the performance measurement interfaces in PEI phase, it creates
+# and consumes GUIDed HOB for performance logging. The GUIDed HOB is passed to DXE phase
+# so that it can be taken over by DxeCorePerformanceLib.
+#
+# Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PeiPerformanceLib
+ MODULE_UNI_FILE = PeiPerformanceLib.uni
+ FILE_GUID = F72DE735-B24F-4ef6-897F-70A85D01A047
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = PerformanceLib|PEIM PEI_CORE SEC
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC (EBC is for build only)
+#
+
+[Sources]
+ PeiPerformanceLib.c
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+
+[LibraryClasses]
+ BaseMemoryLib
+ PcdLib
+ TimerLib
+ BaseLib
+ HobLib
+ DebugLib
+
+
+[Guids]
+ ## PRODUCES ## HOB
+ ## CONSUMES ## HOB
+ gPerformanceProtocolGuid
+ ## PRODUCES ## HOB
+ ## CONSUMES ## HOB
+ gPerformanceExProtocolGuid
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxPeiPerformanceLogEntries ## CONSUMES
+ gEfiMdePkgTokenSpaceGuid.PcdPerformanceLibraryPropertyMask ## CONSUMES
diff --git a/Core/MdeModulePkg/Library/PeiPerformanceLib/PeiPerformanceLib.uni b/Core/MdeModulePkg/Library/PeiPerformanceLib/PeiPerformanceLib.uni
new file mode 100644
index 0000000000..3be291a988
--- /dev/null
+++ b/Core/MdeModulePkg/Library/PeiPerformanceLib/PeiPerformanceLib.uni
Binary files differ
diff --git a/Core/MdeModulePkg/Library/PeiRecoveryLibNull/PeiRecoveryLibNull.c b/Core/MdeModulePkg/Library/PeiRecoveryLibNull/PeiRecoveryLibNull.c
new file mode 100644
index 0000000000..d77c6e544b
--- /dev/null
+++ b/Core/MdeModulePkg/Library/PeiRecoveryLibNull/PeiRecoveryLibNull.c
@@ -0,0 +1,34 @@
+/** @file
+ Null Recovery Library instance does nothing and returns unsupported status.
+
+ This library instance is no longer used and module using this library
+ class should update to directly locate EFI_PEI_RECOVERY_MODULE_PPI defined
+ in PI 1.2 specification.
+
+Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+#include <PiPei.h>
+#include <Library/RecoveryLib.h>
+
+/**
+ Calling this function causes the system do recovery boot path.
+
+ @retval EFI_UNSUPPORTED Recovery is not supported.
+**/
+EFI_STATUS
+EFIAPI
+PeiRecoverFirmware (
+ VOID
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
diff --git a/Core/MdeModulePkg/Library/PeiRecoveryLibNull/PeiRecoveryLibNull.inf b/Core/MdeModulePkg/Library/PeiRecoveryLibNull/PeiRecoveryLibNull.inf
new file mode 100644
index 0000000000..6c565acc40
--- /dev/null
+++ b/Core/MdeModulePkg/Library/PeiRecoveryLibNull/PeiRecoveryLibNull.inf
@@ -0,0 +1,39 @@
+## @file
+# Null Recovery library instance for PEIM module
+# This library instance is no longer used and module using this library
+# class should update to directly locate EFI_PEI_RECOVERY_MODULE_PPI defined
+# in PI 1.2 specification.
+#
+# Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PeiRecoveryLibNull
+ MODULE_UNI_FILE = PeiRecoveryLibNull.uni
+ FILE_GUID = 41789FB9-02AC-4484-BD40-A3147D7EDA25
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = RecoveryLib|PEIM
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC (EBC is for build only)
+#
+
+[Sources]
+ PeiRecoveryLibNull.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
diff --git a/Core/MdeModulePkg/Library/PeiRecoveryLibNull/PeiRecoveryLibNull.uni b/Core/MdeModulePkg/Library/PeiRecoveryLibNull/PeiRecoveryLibNull.uni
new file mode 100644
index 0000000000..6c7a2cdb7a
--- /dev/null
+++ b/Core/MdeModulePkg/Library/PeiRecoveryLibNull/PeiRecoveryLibNull.uni
Binary files differ
diff --git a/Core/MdeModulePkg/Library/PeiReportStatusCodeLib/PeiReportStatusCodeLib.inf b/Core/MdeModulePkg/Library/PeiReportStatusCodeLib/PeiReportStatusCodeLib.inf
new file mode 100644
index 0000000000..f66ce80cd5
--- /dev/null
+++ b/Core/MdeModulePkg/Library/PeiReportStatusCodeLib/PeiReportStatusCodeLib.inf
@@ -0,0 +1,59 @@
+## @file
+# Instance of Report Status Code Library for PEI Phase.
+#
+# Instance of Report Status Code Library for PEI Phase. It first tries to report status
+# code via PEI Status Code Service. If the service is not available, it then tries calling
+# OEM Hook Status Code Library.
+#
+# Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PeiReportStatusCodeLib
+ MODULE_UNI_FILE = PeiReportStatusCodeLib.uni
+ FILE_GUID = 8c690838-7a22-45c4-aa58-a33e3e515cd4
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = ReportStatusCodeLib|SEC PEIM PEI_CORE
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC (EBC is for build only)
+#
+
+[Sources]
+ ReportStatusCodeLib.c
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ PcdLib
+ PeiServicesTablePointerLib
+ BaseMemoryLib
+ BaseLib
+ DebugLib
+ OemHookStatusCodeLib
+
+
+[Guids]
+ gEfiStatusCodeSpecificDataGuid ## SOMETIMES_CONSUMES ## UNDEFINED
+ gEfiStatusCodeDataTypeDebugGuid ## SOMETIMES_CONSUMES ## UNDEFINED
+
+
+[Pcd]
+ gEfiMdePkgTokenSpaceGuid.PcdReportStatusCodePropertyMask ## CONSUMES
+
diff --git a/Core/MdeModulePkg/Library/PeiReportStatusCodeLib/PeiReportStatusCodeLib.uni b/Core/MdeModulePkg/Library/PeiReportStatusCodeLib/PeiReportStatusCodeLib.uni
new file mode 100644
index 0000000000..53c74d809f
--- /dev/null
+++ b/Core/MdeModulePkg/Library/PeiReportStatusCodeLib/PeiReportStatusCodeLib.uni
Binary files differ
diff --git a/Core/MdeModulePkg/Library/PeiReportStatusCodeLib/ReportStatusCodeLib.c b/Core/MdeModulePkg/Library/PeiReportStatusCodeLib/ReportStatusCodeLib.c
new file mode 100644
index 0000000000..d41d4e981d
--- /dev/null
+++ b/Core/MdeModulePkg/Library/PeiReportStatusCodeLib/ReportStatusCodeLib.c
@@ -0,0 +1,560 @@
+/** @file
+ Instance of Report Status Code Library for PEI Phase.
+
+ Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Guid/StatusCodeDataTypeId.h>
+#include <Guid/StatusCodeDataTypeDebug.h>
+
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PeiServicesTablePointerLib.h>
+#include <Library/OemHookStatusCodeLib.h>
+#include <Library/PcdLib.h>
+
+//
+// Define the maximum extended data size that is supported in the PEI phase
+//
+#define MAX_EXTENDED_DATA_SIZE 0x200
+
+/**
+ Internal worker function that reports a status code through the PEI Status Code Service or
+ OEM Hook Status Code Library.
+
+ This function first tries to report status code via PEI Status Code Service. If the service
+ is not available, it then tries calling OEM Hook Status Code Library.
+
+ @param Type Status code type.
+ @param Value Status code value.
+ @param Instance Status code instance number.
+ @param CallerId Pointer to a GUID that identifies the caller of this
+ function. This is an optional parameter that may be
+ NULL.
+ @param Data Pointer to the extended data buffer. This is an
+ optional parameter that may be NULL.
+
+ @retval EFI_SUCCESS The status code was reported.
+ @retval EFI_UNSUPPORTED Status code type is not supported.
+ @retval Others Failed to report status code.
+
+**/
+EFI_STATUS
+InternalReportStatusCode (
+ IN EFI_STATUS_CODE_TYPE Type,
+ IN EFI_STATUS_CODE_VALUE Value,
+ IN UINT32 Instance,
+ IN CONST EFI_GUID *CallerId OPTIONAL,
+ IN EFI_STATUS_CODE_DATA *Data OPTIONAL
+ )
+{
+ CONST EFI_PEI_SERVICES **PeiServices;
+ EFI_STATUS Status;
+
+ if ((ReportProgressCodeEnabled() && ((Type) & EFI_STATUS_CODE_TYPE_MASK) == EFI_PROGRESS_CODE) ||
+ (ReportErrorCodeEnabled() && ((Type) & EFI_STATUS_CODE_TYPE_MASK) == EFI_ERROR_CODE) ||
+ (ReportDebugCodeEnabled() && ((Type) & EFI_STATUS_CODE_TYPE_MASK) == EFI_DEBUG_CODE)) {
+ PeiServices = GetPeiServicesTablePointer ();
+ Status = (*PeiServices)->ReportStatusCode (
+ PeiServices,
+ Type,
+ Value,
+ Instance,
+ (EFI_GUID *)CallerId,
+ Data
+ );
+ if (Status == EFI_NOT_AVAILABLE_YET) {
+ Status = OemHookStatusCodeInitialize ();
+ if (!EFI_ERROR (Status)) {
+ return OemHookStatusCodeReport (Type, Value, Instance, (EFI_GUID *) CallerId, Data);
+ }
+ }
+ return Status;
+ }
+
+ return EFI_UNSUPPORTED;
+}
+
+
+/**
+ Converts a status code to an 8-bit POST code value.
+
+ Converts the status code specified by CodeType and Value to an 8-bit POST code
+ and returns the 8-bit POST code in PostCode. If CodeType is an
+ EFI_PROGRESS_CODE or CodeType is an EFI_ERROR_CODE, then bits 0..4 of PostCode
+ are set to bits 16..20 of Value, and bits 5..7 of PostCode are set to bits
+ 24..26 of Value., and TRUE is returned. Otherwise, FALSE is returned.
+
+ If PostCode is NULL, then ASSERT().
+
+ @param CodeType The type of status code being converted.
+ @param Value The status code value being converted.
+ @param PostCode A pointer to the 8-bit POST code value to return.
+
+ @retval TRUE The status code specified by CodeType and Value was converted
+ to an 8-bit POST code and returned in PostCode.
+ @retval FALSE The status code specified by CodeType and Value could not be
+ converted to an 8-bit POST code value.
+
+**/
+BOOLEAN
+EFIAPI
+CodeTypeToPostCode (
+ IN EFI_STATUS_CODE_TYPE CodeType,
+ IN EFI_STATUS_CODE_VALUE Value,
+ OUT UINT8 *PostCode
+ )
+{
+ //
+ // If PostCode is NULL, then ASSERT()
+ //
+ ASSERT (PostCode != NULL);
+
+ //
+ // Convert Value to an 8 bit post code
+ //
+ if (((CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_PROGRESS_CODE) ||
+ ((CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_ERROR_CODE)) {
+ *PostCode = (UINT8) ((((Value & EFI_STATUS_CODE_CLASS_MASK) >> 24) << 5) |
+ (((Value & EFI_STATUS_CODE_SUBCLASS_MASK) >> 16) & 0x1f));
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+/**
+ Extracts ASSERT() information from a status code structure.
+
+ Converts the status code specified by CodeType, Value, and Data to the ASSERT()
+ arguments specified by Filename, Description, and LineNumber. If CodeType is
+ an EFI_ERROR_CODE, and CodeType has a severity of EFI_ERROR_UNRECOVERED, and
+ Value has an operation mask of EFI_SW_EC_ILLEGAL_SOFTWARE_STATE, extract
+ Filename, Description, and LineNumber from the optional data area of the
+ status code buffer specified by Data. The optional data area of Data contains
+ a Null-terminated ASCII string for the FileName, followed by a Null-terminated
+ ASCII string for the Description, followed by a 32-bit LineNumber. If the
+ ASSERT() information could be extracted from Data, then return TRUE.
+ Otherwise, FALSE is returned.
+
+ If Data is NULL, then ASSERT().
+ If Filename is NULL, then ASSERT().
+ If Description is NULL, then ASSERT().
+ If LineNumber is NULL, then ASSERT().
+
+ @param CodeType The type of status code being converted.
+ @param Value The status code value being converted.
+ @param Data Pointer to status code data buffer.
+ @param Filename Pointer to the source file name that generated the ASSERT().
+ @param Description Pointer to the description of the ASSERT().
+ @param LineNumber Pointer to source line number that generated the ASSERT().
+
+ @retval TRUE The status code specified by CodeType, Value, and Data was
+ converted ASSERT() arguments specified by Filename, Description,
+ and LineNumber.
+ @retval FALSE The status code specified by CodeType, Value, and Data could
+ not be converted to ASSERT() arguments.
+
+**/
+BOOLEAN
+EFIAPI
+ReportStatusCodeExtractAssertInfo (
+ IN EFI_STATUS_CODE_TYPE CodeType,
+ IN EFI_STATUS_CODE_VALUE Value,
+ IN CONST EFI_STATUS_CODE_DATA *Data,
+ OUT CHAR8 **Filename,
+ OUT CHAR8 **Description,
+ OUT UINT32 *LineNumber
+ )
+{
+ EFI_DEBUG_ASSERT_DATA *AssertData;
+
+ ASSERT (Data != NULL);
+ ASSERT (Filename != NULL);
+ ASSERT (Description != NULL);
+ ASSERT (LineNumber != NULL);
+
+ if (((CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_ERROR_CODE) &&
+ ((CodeType & EFI_STATUS_CODE_SEVERITY_MASK) == EFI_ERROR_UNRECOVERED) &&
+ ((Value & EFI_STATUS_CODE_OPERATION_MASK) == EFI_SW_EC_ILLEGAL_SOFTWARE_STATE)) {
+ AssertData = (EFI_DEBUG_ASSERT_DATA *)(Data + 1);
+ *Filename = (CHAR8 *)(AssertData + 1);
+ *Description = *Filename + AsciiStrLen (*Filename) + 1;
+ *LineNumber = AssertData->LineNumber;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+/**
+ Extracts DEBUG() information from a status code structure.
+
+ Converts the status code specified by Data to the DEBUG() arguments specified
+ by ErrorLevel, Marker, and Format. If type GUID in Data is
+ EFI_STATUS_CODE_DATA_TYPE_DEBUG_GUID, then extract ErrorLevel, Marker, and
+ Format from the optional data area of the status code buffer specified by Data.
+ The optional data area of Data contains a 32-bit ErrorLevel followed by Marker
+ which is 12 UINTN parameters, followed by a Null-terminated ASCII string for
+ the Format. If the DEBUG() information could be extracted from Data, then
+ return TRUE. Otherwise, FALSE is returned.
+
+ If Data is NULL, then ASSERT().
+ If ErrorLevel is NULL, then ASSERT().
+ If Marker is NULL, then ASSERT().
+ If Format is NULL, then ASSERT().
+
+ @param Data Pointer to status code data buffer.
+ @param ErrorLevel Pointer to error level mask for a debug message.
+ @param Marker Pointer to the variable argument list associated with Format.
+ @param Format Pointer to a Null-terminated ASCII format string of a
+ debug message.
+
+ @retval TRUE The status code specified by Data was converted DEBUG() arguments
+ specified by ErrorLevel, Marker, and Format.
+ @retval FALSE The status code specified by Data could not be converted to
+ DEBUG() arguments.
+
+**/
+BOOLEAN
+EFIAPI
+ReportStatusCodeExtractDebugInfo (
+ IN CONST EFI_STATUS_CODE_DATA *Data,
+ OUT UINT32 *ErrorLevel,
+ OUT BASE_LIST *Marker,
+ OUT CHAR8 **Format
+ )
+{
+ EFI_DEBUG_INFO *DebugInfo;
+
+ ASSERT (Data != NULL);
+ ASSERT (ErrorLevel != NULL);
+ ASSERT (Marker != NULL);
+ ASSERT (Format != NULL);
+
+ //
+ // If the GUID type is not EFI_STATUS_CODE_DATA_TYPE_DEBUG_GUID then return FALSE
+ //
+ if (!CompareGuid (&Data->Type, &gEfiStatusCodeDataTypeDebugGuid)) {
+ return FALSE;
+ }
+
+ //
+ // Retrieve the debug information from the status code record
+ //
+ DebugInfo = (EFI_DEBUG_INFO *)(Data + 1);
+
+ *ErrorLevel = DebugInfo->ErrorLevel;
+
+ //
+ // The first 12 * sizeof (UINT64) bytes following EFI_DEBUG_INFO are for variable arguments
+ // of format in DEBUG string. Its address is returned in Marker and has to be 64-bit aligned.
+ // It must be noticed that EFI_DEBUG_INFO follows EFI_STATUS_CODE_DATA, whose size is
+ // 20 bytes. The size of EFI_DEBUG_INFO is 4 bytes, so we can ensure that Marker
+ // returned is 64-bit aligned.
+ // 64-bit aligned is a must, otherwise retrieving 64-bit parameter from BASE_LIST will
+ // cause unalignment exception.
+ //
+ *Marker = (BASE_LIST) (DebugInfo + 1);
+ *Format = (CHAR8 *)(((UINT64 *)*Marker) + 12);
+
+ return TRUE;
+}
+
+
+/**
+ Reports a status code.
+
+ Reports the status code specified by the parameters Type and Value. Status
+ code also require an instance, caller ID, and extended data. This function
+ passed in a zero instance, NULL extended data, and a caller ID of
+ gEfiCallerIdGuid, which is the GUID for the module.
+
+ ReportStatusCode()must actively prevent recusrsion. If ReportStatusCode()
+ is called while processing another any other Report Status Code Library function,
+ then ReportStatusCode() must return immediately.
+
+ @param Type Status code type.
+ @param Value Status code value.
+
+ @retval EFI_SUCCESS The status code was reported.
+ @retval EFI_DEVICE_ERROR There status code could not be reported due to a
+ device error.
+ @retval EFI_UNSUPPORTED Report status code is not supported
+
+**/
+EFI_STATUS
+EFIAPI
+ReportStatusCode (
+ IN EFI_STATUS_CODE_TYPE Type,
+ IN EFI_STATUS_CODE_VALUE Value
+ )
+{
+ return InternalReportStatusCode (Type, Value, 0, &gEfiCallerIdGuid, NULL);
+}
+
+
+/**
+ Reports a status code with a Device Path Protocol as the extended data.
+
+ Allocates and fills in the extended data section of a status code with the
+ Device Path Protocol specified by DevicePath. This function is responsible
+ for allocating a buffer large enough for the standard header and the device
+ path. The standard header is filled in with a GUID of
+ gEfiStatusCodeSpecificDataGuid. The status code is reported with a zero
+ instance and a caller ID of gEfiCallerIdGuid.
+
+ ReportStatusCodeWithDevicePath()must actively prevent recursion. If
+ ReportStatusCodeWithDevicePath() is called while processing another any other
+ Report Status Code Library function, then ReportStatusCodeWithDevicePath()
+ must return EFI_DEVICE_ERROR immediately.
+
+ If DevicePath is NULL, then ASSERT().
+
+ @param Type Status code type.
+ @param Value Status code value.
+ @param DevicePath Pointer to the Device Path Protocol to be reported.
+
+ @retval EFI_SUCCESS The status code was reported with the extended
+ data specified by DevicePath.
+ @retval EFI_OUT_OF_RESOURCES There were not enough resources to allocate the
+ extended data section.
+ @retval EFI_UNSUPPORTED Report status code is not supported
+
+**/
+EFI_STATUS
+EFIAPI
+ReportStatusCodeWithDevicePath (
+ IN EFI_STATUS_CODE_TYPE Type,
+ IN EFI_STATUS_CODE_VALUE Value,
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ ASSERT (DevicePath != NULL);
+ //
+ // EFI_UNSUPPORTED is returned for device path is not supported in PEI phase.
+ //
+ return EFI_UNSUPPORTED;
+}
+
+
+/**
+ Reports a status code with an extended data buffer.
+
+ Allocates and fills in the extended data section of a status code with the
+ extended data specified by ExtendedData and ExtendedDataSize. ExtendedData
+ is assumed to be one of the data structures specified in Related Definitions.
+ These data structure do not have the standard header, so this function is
+ responsible for allocating a buffer large enough for the standard header and
+ the extended data passed into this function. The standard header is filled
+ in with a GUID of gEfiStatusCodeSpecificDataGuid. The status code is reported
+ with a zero instance and a caller ID of gEfiCallerIdGuid.
+
+ ReportStatusCodeWithExtendedData()must actively prevent recursion. If
+ ReportStatusCodeWithExtendedData() is called while processing another any other
+ Report Status Code Library function, then ReportStatusCodeWithExtendedData()
+ must return EFI_DEVICE_ERROR immediately.
+
+ If ExtendedData is NULL, then ASSERT().
+ If ExtendedDataSize is 0, then ASSERT().
+
+ @param Type Status code type.
+ @param Value Status code value.
+ @param ExtendedData Pointer to the extended data buffer to be reported.
+ @param ExtendedDataSize The size, in bytes, of the extended data buffer to
+ be reported.
+
+ @retval EFI_SUCCESS The status code was reported with the extended
+ data specified by ExtendedData and ExtendedDataSize.
+ @retval EFI_OUT_OF_RESOURCES There were not enough resources to allocate the
+ extended data section.
+ @retval EFI_UNSUPPORTED Report status code is not supported
+
+**/
+EFI_STATUS
+EFIAPI
+ReportStatusCodeWithExtendedData (
+ IN EFI_STATUS_CODE_TYPE Type,
+ IN EFI_STATUS_CODE_VALUE Value,
+ IN CONST VOID *ExtendedData,
+ IN UINTN ExtendedDataSize
+ )
+{
+ ASSERT (ExtendedData != NULL);
+ ASSERT (ExtendedDataSize != 0);
+ return ReportStatusCodeEx (
+ Type,
+ Value,
+ 0,
+ NULL,
+ NULL,
+ ExtendedData,
+ ExtendedDataSize
+ );
+}
+
+
+/**
+ Reports a status code with full parameters.
+
+ The function reports a status code. If ExtendedData is NULL and ExtendedDataSize
+ is 0, then an extended data buffer is not reported. If ExtendedData is not
+ NULL and ExtendedDataSize is not 0, then an extended data buffer is allocated.
+ ExtendedData is assumed not have the standard status code header, so this function
+ is responsible for allocating a buffer large enough for the standard header and
+ the extended data passed into this function. The standard header is filled in
+ with a GUID specified by ExtendedDataGuid. If ExtendedDataGuid is NULL, then a
+ GUID of gEfiStatusCodeSpecificDatauid is used. The status code is reported with
+ an instance specified by Instance and a caller ID specified by CallerId. If
+ CallerId is NULL, then a caller ID of gEfiCallerIdGuid is used.
+
+ ReportStatusCodeEx()must actively prevent recursion. If ReportStatusCodeEx()
+ is called while processing another any other Report Status Code Library function,
+ then ReportStatusCodeEx() must return EFI_DEVICE_ERROR immediately.
+
+ If ExtendedData is NULL and ExtendedDataSize is not zero, then ASSERT().
+ If ExtendedData is not NULL and ExtendedDataSize is zero, then ASSERT().
+
+ @param Type Status code type.
+ @param Value Status code value.
+ @param Instance Status code instance number.
+ @param CallerId Pointer to a GUID that identifies the caller of this
+ function. If this parameter is NULL, then a caller
+ ID of gEfiCallerIdGuid is used.
+ @param ExtendedDataGuid Pointer to the GUID for the extended data buffer.
+ If this parameter is NULL, then a the status code
+ standard header is filled in with
+ gEfiStatusCodeSpecificDataGuid.
+ @param ExtendedData Pointer to the extended data buffer. This is an
+ optional parameter that may be NULL.
+ @param ExtendedDataSize The size, in bytes, of the extended data buffer.
+
+ @retval EFI_SUCCESS The status code was reported.
+ @retval EFI_OUT_OF_RESOURCES There were not enough resources to allocate
+ the extended data section if it was specified.
+ @retval EFI_UNSUPPORTED Report status code is not supported
+
+**/
+EFI_STATUS
+EFIAPI
+ReportStatusCodeEx (
+ IN EFI_STATUS_CODE_TYPE Type,
+ IN EFI_STATUS_CODE_VALUE Value,
+ IN UINT32 Instance,
+ IN CONST EFI_GUID *CallerId OPTIONAL,
+ IN CONST EFI_GUID *ExtendedDataGuid OPTIONAL,
+ IN CONST VOID *ExtendedData OPTIONAL,
+ IN UINTN ExtendedDataSize
+ )
+{
+ EFI_STATUS_CODE_DATA *StatusCodeData;
+ UINT64 Buffer[(MAX_EXTENDED_DATA_SIZE / sizeof (UINT64)) + 1];
+
+ //
+ // If ExtendedData is NULL and ExtendedDataSize is not zero, then ASSERT().
+ //
+ ASSERT (!((ExtendedData == NULL) && (ExtendedDataSize != 0)));
+ //
+ // If ExtendedData is not NULL and ExtendedDataSize is zero, then ASSERT().
+ //
+ ASSERT (!((ExtendedData != NULL) && (ExtendedDataSize == 0)));
+
+ if (ExtendedDataSize > (MAX_EXTENDED_DATA_SIZE - sizeof (EFI_STATUS_CODE_DATA))) {
+ //
+ // The local variable Buffer not large enough to hold the extended data associated
+ // with the status code being reported.
+ //
+ DEBUG ((EFI_D_ERROR, "Status code extended data is too large to be reported!\n"));
+ return EFI_OUT_OF_RESOURCES;
+ }
+ StatusCodeData = (EFI_STATUS_CODE_DATA *) Buffer;
+ StatusCodeData->HeaderSize = (UINT16) sizeof (EFI_STATUS_CODE_DATA);
+ StatusCodeData->Size = (UINT16) ExtendedDataSize;
+ if (ExtendedDataGuid == NULL) {
+ ExtendedDataGuid = &gEfiStatusCodeSpecificDataGuid;
+ }
+ CopyGuid (&StatusCodeData->Type, ExtendedDataGuid);
+ if (ExtendedData != NULL) {
+ CopyMem (StatusCodeData + 1, ExtendedData, ExtendedDataSize);
+ }
+ if (CallerId == NULL) {
+ CallerId = &gEfiCallerIdGuid;
+ }
+ return InternalReportStatusCode (Type, Value, Instance, CallerId, StatusCodeData);
+}
+
+
+/**
+ Returns TRUE if status codes of type EFI_PROGRESS_CODE are enabled
+
+ This function returns TRUE if the REPORT_STATUS_CODE_PROPERTY_PROGRESS_CODE_ENABLED
+ bit of PcdReportStatusCodeProperyMask is set. Otherwise FALSE is returned.
+
+ @retval TRUE The REPORT_STATUS_CODE_PROPERTY_PROGRESS_CODE_ENABLED bit of
+ PcdReportStatusCodeProperyMask is set.
+ @retval FALSE The REPORT_STATUS_CODE_PROPERTY_PROGRESS_CODE_ENABLED bit of
+ PcdReportStatusCodeProperyMask is clear.
+
+**/
+BOOLEAN
+EFIAPI
+ReportProgressCodeEnabled (
+ VOID
+ )
+{
+ return (BOOLEAN) ((PcdGet8 (PcdReportStatusCodePropertyMask) & REPORT_STATUS_CODE_PROPERTY_PROGRESS_CODE_ENABLED) != 0);
+}
+
+
+/**
+ Returns TRUE if status codes of type EFI_ERROR_CODE are enabled
+
+ This function returns TRUE if the REPORT_STATUS_CODE_PROPERTY_ERROR_CODE_ENABLED
+ bit of PcdReportStatusCodeProperyMask is set. Otherwise FALSE is returned.
+
+ @retval TRUE The REPORT_STATUS_CODE_PROPERTY_ERROR_CODE_ENABLED bit of
+ PcdReportStatusCodeProperyMask is set.
+ @retval FALSE The REPORT_STATUS_CODE_PROPERTY_ERROR_CODE_ENABLED bit of
+ PcdReportStatusCodeProperyMask is clear.
+
+**/
+BOOLEAN
+EFIAPI
+ReportErrorCodeEnabled (
+ VOID
+ )
+{
+ return (BOOLEAN) ((PcdGet8 (PcdReportStatusCodePropertyMask) & REPORT_STATUS_CODE_PROPERTY_ERROR_CODE_ENABLED) != 0);
+}
+
+
+/**
+ Returns TRUE if status codes of type EFI_DEBUG_CODE are enabled
+
+ This function returns TRUE if the REPORT_STATUS_CODE_PROPERTY_DEBUG_CODE_ENABLED
+ bit of PcdReportStatusCodeProperyMask is set. Otherwise FALSE is returned.
+
+ @retval TRUE The REPORT_STATUS_CODE_PROPERTY_DEBUG_CODE_ENABLED bit of
+ PcdReportStatusCodeProperyMask is set.
+ @retval FALSE The REPORT_STATUS_CODE_PROPERTY_DEBUG_CODE_ENABLED bit of
+ PcdReportStatusCodeProperyMask is clear.
+
+**/
+BOOLEAN
+EFIAPI
+ReportDebugCodeEnabled (
+ VOID
+ )
+{
+ return (BOOLEAN) ((PcdGet8 (PcdReportStatusCodePropertyMask) & REPORT_STATUS_CODE_PROPERTY_DEBUG_CODE_ENABLED) != 0);
+}
diff --git a/Core/MdeModulePkg/Library/PeiS3LibNull/PeiS3LibNull.c b/Core/MdeModulePkg/Library/PeiS3LibNull/PeiS3LibNull.c
new file mode 100644
index 0000000000..82882b8706
--- /dev/null
+++ b/Core/MdeModulePkg/Library/PeiS3LibNull/PeiS3LibNull.c
@@ -0,0 +1,35 @@
+/** @file
+ Null S3 Library instance does nothing and returns unsupported status.
+
+ This library instance is no longer used and module using this library
+ class should update to directly locate EFI_PEI_S3_RESUME_PPI defined
+ in PI 1.2 specification.
+
+Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+#include <PiPei.h>
+#include <Library/S3Lib.h>
+
+/**
+ This function is responsible for calling the S3 resume vector in the ACPI Tables.
+
+ @retval EFI_SUCESS Success to restore config from S3.
+ @retval Others Fail to restore config from S3.
+**/
+EFI_STATUS
+EFIAPI
+AcpiS3ResumeOs (
+ VOID
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
diff --git a/Core/MdeModulePkg/Library/PeiS3LibNull/PeiS3LibNull.inf b/Core/MdeModulePkg/Library/PeiS3LibNull/PeiS3LibNull.inf
new file mode 100644
index 0000000000..f582054870
--- /dev/null
+++ b/Core/MdeModulePkg/Library/PeiS3LibNull/PeiS3LibNull.inf
@@ -0,0 +1,40 @@
+## @file
+# Null S3 library instance for PEIM module.
+# This library instance is no longer used and module using this library
+# class should update to directly locate EFI_PEI_S3_RESUME_PPI defined
+# in PI 1.2 specification.
+#
+# Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PeiS3LibNull
+ MODULE_UNI_FILE = PeiS3LibNull.uni
+ FILE_GUID = 018E1925-D6A2-4a2a-8958-817610A15ADF
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = S3Lib|PEIM
+
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC (EBC is for build only)
+#
+
+[Sources]
+ PeiS3LibNull.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
diff --git a/Core/MdeModulePkg/Library/PeiS3LibNull/PeiS3LibNull.uni b/Core/MdeModulePkg/Library/PeiS3LibNull/PeiS3LibNull.uni
new file mode 100644
index 0000000000..ac0ce9f08d
--- /dev/null
+++ b/Core/MdeModulePkg/Library/PeiS3LibNull/PeiS3LibNull.uni
Binary files differ
diff --git a/Core/MdeModulePkg/Library/PiDxeS3BootScriptLib/BootScriptExecute.c b/Core/MdeModulePkg/Library/PiDxeS3BootScriptLib/BootScriptExecute.c
new file mode 100644
index 0000000000..45dd581b08
--- /dev/null
+++ b/Core/MdeModulePkg/Library/PiDxeS3BootScriptLib/BootScriptExecute.c
@@ -0,0 +1,1792 @@
+/** @file
+ Interpret and execute the S3 data in S3 boot script.
+
+ Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions
+ of the BSD License which accompanies this distribution. The
+ full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+#include "InternalBootScriptLib.h"
+
+/**
+ Executes an SMBus operation to an SMBus controller. Returns when either the command has been
+ executed or an error is encountered in doing the operation.
+
+ The SmbusExecute() function provides a standard way to execute an operation as defined in the System
+ Management Bus (SMBus) Specification. The resulting transaction will be either that the SMBus
+ slave devices accept this transaction or that this function returns with error.
+
+ @param SmbusAddress Address that encodes the SMBUS Slave Address, SMBUS Command, SMBUS Data Length,
+ and PEC.
+ @param Operation Signifies which particular SMBus hardware protocol instance that
+ it will use to execute the SMBus transactions. This SMBus
+ hardware protocol is defined by the SMBus Specification and is
+ not related to EFI.
+ @param Length Signifies the number of bytes that this operation will do. The
+ maximum number of bytes can be revision specific and operation
+ specific. This field will contain the actual number of bytes that
+ are executed for this operation. Not all operations require this
+ argument.
+ @param Buffer Contains the value of data to execute to the SMBus slave device.
+ Not all operations require this argument. The length of this
+ buffer is identified by Length.
+
+ @retval EFI_SUCCESS The last data that was returned from the access matched the poll
+ exit criteria.
+ @retval EFI_CRC_ERROR Checksum is not correct (PEC is incorrect).
+ @retval EFI_TIMEOUT Timeout expired before the operation was completed. Timeout is
+ determined by the SMBus host controller device.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_DEVICE_ERROR The request was not completed because a failure that was
+ reflected in the Host Status Register bit. Device errors are a
+ result of a transaction collision, illegal command field,
+ unclaimed cycle (host initiated), or bus errors (collisions).
+ @retval EFI_INVALID_PARAMETER Operation is not defined in EFI_SMBUS_OPERATION.
+ @retval EFI_INVALID_PARAMETER Length/Buffer is NULL for operations except for EfiSmbusQuickRead
+ and EfiSmbusQuickWrite. Length is outside the range of valid
+ values.
+ @retval EFI_UNSUPPORTED The SMBus operation or PEC is not supported.
+ @retval EFI_BUFFER_TOO_SMALL Buffer is not sufficient for this operation.
+
+**/
+EFI_STATUS
+SmbusExecute (
+ IN UINTN SmbusAddress,
+ IN EFI_SMBUS_OPERATION Operation,
+ IN OUT UINTN *Length,
+ IN OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ UINT8 WorkBuffer[MAX_SMBUS_BLOCK_LEN];
+
+ switch (Operation) {
+ case EfiSmbusQuickRead:
+ DEBUG ((EFI_D_INFO, "EfiSmbusQuickRead - 0x%08x\n", SmbusAddress));
+ SmBusQuickRead (SmbusAddress, &Status);
+ break;
+ case EfiSmbusQuickWrite:
+ DEBUG ((EFI_D_INFO, "EfiSmbusQuickWrite - 0x%08x\n", SmbusAddress));
+ SmBusQuickWrite (SmbusAddress, &Status);
+ break;
+ case EfiSmbusReceiveByte:
+ DEBUG ((EFI_D_INFO, "EfiSmbusReceiveByte - 0x%08x\n", SmbusAddress));
+ SmBusReceiveByte (SmbusAddress, &Status);
+ break;
+ case EfiSmbusSendByte:
+ DEBUG ((EFI_D_INFO, "EfiSmbusSendByte - 0x%08x (0x%02x)\n", SmbusAddress, (UINTN)*(UINT8 *) Buffer));
+ SmBusSendByte (SmbusAddress, *(UINT8 *) Buffer, &Status);
+ break;
+ case EfiSmbusReadByte:
+ DEBUG ((EFI_D_INFO, "EfiSmbusReadByte - 0x%08x\n", SmbusAddress));
+ SmBusReadDataByte (SmbusAddress, &Status);
+ break;
+ case EfiSmbusWriteByte:
+ DEBUG ((EFI_D_INFO, "EfiSmbusWriteByte - 0x%08x (0x%02x)\n", SmbusAddress, (UINTN)*(UINT8 *) Buffer));
+ SmBusWriteDataByte (SmbusAddress, *(UINT8 *) Buffer, &Status);
+ break;
+ case EfiSmbusReadWord:
+ DEBUG ((EFI_D_INFO, "EfiSmbusReadWord - 0x%08x\n", SmbusAddress));
+ SmBusReadDataWord (SmbusAddress, &Status);
+ break;
+ case EfiSmbusWriteWord:
+ DEBUG ((EFI_D_INFO, "EfiSmbusWriteWord - 0x%08x (0x%04x)\n", SmbusAddress, (UINTN)*(UINT16 *) Buffer));
+ SmBusWriteDataWord (SmbusAddress, *(UINT16 *) Buffer, &Status);
+ break;
+ case EfiSmbusProcessCall:
+ DEBUG ((EFI_D_INFO, "EfiSmbusProcessCall - 0x%08x (0x%04x)\n", SmbusAddress, (UINTN)*(UINT16 *) Buffer));
+ SmBusProcessCall (SmbusAddress, *(UINT16 *) Buffer, &Status);
+ break;
+ case EfiSmbusReadBlock:
+ DEBUG ((EFI_D_INFO, "EfiSmbusReadBlock - 0x%08x\n", SmbusAddress));
+ SmBusReadBlock (SmbusAddress, WorkBuffer, &Status);
+ break;
+ case EfiSmbusWriteBlock:
+ DEBUG ((EFI_D_INFO, "EfiSmbusWriteBlock - 0x%08x\n", SmbusAddress));
+ SmBusWriteBlock ((SmbusAddress + SMBUS_LIB_ADDRESS (0, 0, (*Length), FALSE)), Buffer, &Status);
+ break;
+ case EfiSmbusBWBRProcessCall:
+ DEBUG ((EFI_D_INFO, "EfiSmbusBWBRProcessCall - 0x%08x\n", SmbusAddress));
+ SmBusBlockProcessCall ((SmbusAddress + SMBUS_LIB_ADDRESS (0, 0, (*Length), FALSE)), Buffer, WorkBuffer, &Status);
+ break;
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return Status;
+}
+
+/**
+ Translates boot script width and address stride to MDE library interface.
+
+
+ @param Width Width of the operation.
+ @param Address Address of the operation.
+ @param AddressStride Instride for stepping input buffer.
+ @param BufferStride Outstride for stepping output buffer.
+
+ @retval EFI_SUCCESS Successful translation.
+ @retval EFI_INVALID_PARAMETER Width or Address is invalid.
+**/
+EFI_STATUS
+BuildLoopData (
+ IN S3_BOOT_SCRIPT_LIB_WIDTH Width,
+ IN UINT64 Address,
+ OUT UINTN *AddressStride,
+ OUT UINTN *BufferStride
+ )
+{
+ UINTN AlignMask;
+
+ if (Width >= S3BootScriptWidthMaximum) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *AddressStride = (UINT32)(1 << (Width & 0x03));
+ *BufferStride = *AddressStride;
+
+ AlignMask = *AddressStride - 1;
+ if ((Address & AlignMask) != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Width >= S3BootScriptWidthFifoUint8 && Width <= S3BootScriptWidthFifoUint64) {
+ *AddressStride = 0;
+ }
+
+ if (Width >= S3BootScriptWidthFillUint8 && Width <= S3BootScriptWidthFillUint64) {
+ *BufferStride = 0;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Perform IO read operation
+
+ @param[in] Width Width of the operation.
+ @param[in] Address Address of the operation.
+ @param[in] Count Count of the number of accesses to perform.
+ @param[out] Buffer Pointer to the buffer to read from I/O space.
+
+ @retval EFI_SUCCESS The data was written to the EFI System.
+ @retval EFI_INVALID_PARAMETER Width is invalid for this EFI System.
+ Buffer is NULL.
+ The Buffer is not aligned for the given Width.
+ Address is outside the legal range of I/O ports.
+
+**/
+EFI_STATUS
+ScriptIoRead (
+ IN S3_BOOT_SCRIPT_LIB_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ UINTN AddressStride;
+ UINTN BufferStride;
+ PTR Out;
+
+ Out.Buf = (UINT8 *) Buffer;
+
+ if (Address > MAX_IO_ADDRESS) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = BuildLoopData (Width, Address, &AddressStride, &BufferStride);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Loop for each iteration and move the data
+ //
+ for (; Count > 0; Count--, Address += AddressStride, Out.Buf += BufferStride) {
+ switch (Width) {
+
+ case S3BootScriptWidthUint8:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthUint8 - 0x%08x\n", (UINTN) Address));
+ *Out.Uint8 = IoRead8 ((UINTN) Address);
+ break;
+ case S3BootScriptWidthFifoUint8:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFifoUint8 - 0x%08x\n", (UINTN) Address));
+ *Out.Uint8 = IoRead8 ((UINTN) Address);
+ break;
+ case S3BootScriptWidthFillUint8:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFillUint8 - 0x%08x\n", (UINTN) Address));
+ *Out.Uint8 = IoRead8 ((UINTN) Address);
+ break;
+
+ case S3BootScriptWidthUint16:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthUint16 - 0x%08x\n", (UINTN) Address));
+ *Out.Uint16 = IoRead16 ((UINTN) Address);
+ break;
+ case S3BootScriptWidthFifoUint16:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFifoUint16 - 0x%08x\n", (UINTN) Address));
+ *Out.Uint16 = IoRead16 ((UINTN) Address);
+ break;
+ case S3BootScriptWidthFillUint16:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFillUint16 - 0x%08x\n", (UINTN) Address));
+ *Out.Uint16 = IoRead16 ((UINTN) Address);
+ break;
+
+ case S3BootScriptWidthUint32:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthUint32 - 0x%08x\n", (UINTN) Address));
+ *Out.Uint32 = IoRead32 ((UINTN) Address);
+ break;
+ case S3BootScriptWidthFifoUint32:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFifoUint32 - 0x%08x\n", (UINTN) Address));
+ *Out.Uint32 = IoRead32 ((UINTN) Address);
+ break;
+ case S3BootScriptWidthFillUint32:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFillUint32 - 0x%08x\n", (UINTN) Address));
+ *Out.Uint32 = IoRead32 ((UINTN) Address);
+ break;
+
+ case S3BootScriptWidthUint64:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthUint64 - 0x%08x\n", (UINTN) Address));
+ *Out.Uint64 = IoRead64 ((UINTN) Address);
+ break;
+ case S3BootScriptWidthFifoUint64:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFifoUint64 - 0x%08x\n", (UINTN) Address));
+ *Out.Uint64 = IoRead64 ((UINTN) Address);
+ break;
+ case S3BootScriptWidthFillUint64:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFillUint64 - 0x%08x\n", (UINTN) Address));
+ *Out.Uint64 = IoRead64 ((UINTN) Address);
+ break;
+
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Perform IO write operation
+
+ @param[in] Width Width of the operation.
+ @param[in] Address Address of the operation.
+ @param[in] Count Count of the number of accesses to perform.
+ @param[in] Buffer Pointer to the buffer to write to I/O space.
+
+ @retval EFI_SUCCESS The data was written to the EFI System.
+ @retval EFI_INVALID_PARAMETER Width is invalid for this EFI System.
+ Buffer is NULL.
+ The Buffer is not aligned for the given Width.
+ Address is outside the legal range of I/O ports.
+
+**/
+EFI_STATUS
+ScriptIoWrite (
+ IN S3_BOOT_SCRIPT_LIB_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ UINTN AddressStride;
+ UINTN BufferStride;
+ UINT64 OriginalAddress;
+ PTR In;
+ PTR OriginalIn;
+
+ In.Buf = (UINT8 *) Buffer;
+
+ if (Address > MAX_IO_ADDRESS) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = BuildLoopData (Width, Address, &AddressStride, &BufferStride);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Loop for each iteration and move the data
+ //
+ OriginalAddress = Address;
+ OriginalIn.Buf = In.Buf;
+ for (; Count > 0; Count--, Address += AddressStride, In.Buf += BufferStride) {
+ switch (Width) {
+ case S3BootScriptWidthUint8:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthUint8 - 0x%08x (0x%02x)\n", (UINTN)Address, (UINTN)*In.Uint8));
+ IoWrite8 ((UINTN) Address, *In.Uint8);
+ break;
+ case S3BootScriptWidthFifoUint8:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFifoUint8 - 0x%08x (0x%02x)\n", (UINTN)OriginalAddress, (UINTN)*In.Uint8));
+ IoWrite8 ((UINTN) OriginalAddress, *In.Uint8);
+ break;
+ case S3BootScriptWidthFillUint8:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFillUint8 - 0x%08x (0x%02x)\n", (UINTN)Address, (UINTN)*OriginalIn.Uint8));
+ IoWrite8 ((UINTN) Address, *OriginalIn.Uint8);
+ break;
+ case S3BootScriptWidthUint16:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthUint16 - 0x%08x (0x%04x)\n", (UINTN)Address, (UINTN)*In.Uint16));
+ IoWrite16 ((UINTN) Address, *In.Uint16);
+ break;
+ case S3BootScriptWidthFifoUint16:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFifoUint16 - 0x%08x (0x%04x)\n", (UINTN)OriginalAddress, (UINTN)*In.Uint16));
+ IoWrite16 ((UINTN) OriginalAddress, *In.Uint16);
+ break;
+ case S3BootScriptWidthFillUint16:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFillUint16 - 0x%08x (0x%04x)\n", (UINTN)Address, (UINTN)*OriginalIn.Uint16));
+ IoWrite16 ((UINTN) Address, *OriginalIn.Uint16);
+ break;
+ case S3BootScriptWidthUint32:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthUint32 - 0x%08x (0x%08x)\n", (UINTN)Address, (UINTN)*In.Uint32));
+ IoWrite32 ((UINTN) Address, *In.Uint32);
+ break;
+ case S3BootScriptWidthFifoUint32:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFifoUint32 - 0x%08x (0x%08x)\n", (UINTN)OriginalAddress, (UINTN)*In.Uint32));
+ IoWrite32 ((UINTN) OriginalAddress, *In.Uint32);
+ break;
+ case S3BootScriptWidthFillUint32:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFillUint32 - 0x%08x (0x%08x)\n", (UINTN)Address, (UINTN)*OriginalIn.Uint32));
+ IoWrite32 ((UINTN) Address, *OriginalIn.Uint32);
+ break;
+ case S3BootScriptWidthUint64:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthUint64 - 0x%08x (0x%016lx)\n", (UINTN)Address, *In.Uint64));
+ IoWrite64 ((UINTN) Address, *In.Uint64);
+ break;
+ case S3BootScriptWidthFifoUint64:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFifoUint64 - 0x%08x (0x%016lx)\n", (UINTN)OriginalAddress, *In.Uint64));
+ IoWrite64 ((UINTN) OriginalAddress, *In.Uint64);
+ break;
+ case S3BootScriptWidthFillUint64:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFillUint64 - 0x%08x (0x%016lx)\n", (UINTN)Address, *OriginalIn.Uint64));
+ IoWrite64 ((UINTN) Address, *OriginalIn.Uint64);
+ break;
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+
+ return EFI_SUCCESS;
+}
+/**
+ Interprete the boot script node with EFI_BOOT_SCRIPT_IO_WRITE OP code.
+
+ @param Script Pointer to the node which is to be interpreted.
+
+ @retval EFI_SUCCESS The data was written to the EFI System.
+ @retval EFI_INVALID_PARAMETER Width is invalid for this EFI System.
+ Buffer is NULL.
+ The Buffer is not aligned for the given Width.
+ Address is outside the legal range of I/O ports.
+
+**/
+EFI_STATUS
+BootScriptExecuteIoWrite (
+ IN UINT8 *Script
+ )
+{
+ S3_BOOT_SCRIPT_LIB_WIDTH Width;
+ UINT64 Address;
+ UINTN Count;
+ VOID *Buffer;
+ EFI_BOOT_SCRIPT_IO_WRITE IoWrite;
+
+ CopyMem ((VOID*)&IoWrite, (VOID*)Script, sizeof(EFI_BOOT_SCRIPT_IO_WRITE));
+ Width = (S3_BOOT_SCRIPT_LIB_WIDTH) IoWrite.Width;
+ Address = IoWrite.Address;
+ Count = IoWrite.Count;
+ Buffer = Script + sizeof (EFI_BOOT_SCRIPT_IO_WRITE);
+
+ DEBUG ((EFI_D_INFO, "BootScriptExecuteIoWrite - 0x%08x, 0x%08x, 0x%08x\n", (UINTN)Address, Count, (UINTN)Width));
+ return ScriptIoWrite(Width, Address, Count, Buffer);
+}
+/**
+ Perform memory read operation
+
+ @param Width Width of the operation.
+ @param Address Address of the operation.
+ @param Count Count of the number of accesses to perform.
+ @param Buffer Pointer to the buffer read from memory.
+
+ @retval EFI_SUCCESS The data was written to the EFI System.
+ @retval EFI_INVALID_PARAMETER Width is invalid for this EFI System.
+ Buffer is NULL.
+ The Buffer is not aligned for the given Width.
+ @retval EFI_UNSUPPORTED The address range specified by Address, Width, and Count
+ is not valid for this EFI System.
+
+**/
+EFI_STATUS
+ScriptMemoryRead (
+ IN S3_BOOT_SCRIPT_LIB_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ UINTN AddressStride;
+ UINTN BufferStride;
+ PTR Out;
+
+ Out.Buf = Buffer;
+
+ Status = BuildLoopData (Width, Address, &AddressStride, &BufferStride);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Loop for each iteration and move the data
+ //
+ for (; Count > 0; Count--, Address += AddressStride, Out.Buf += BufferStride) {
+ switch (Width) {
+ case S3BootScriptWidthUint8:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthUint8 - 0x%08x\n", (UINTN)Address));
+ *Out.Uint8 = MmioRead8 ((UINTN) Address);
+ break;
+ case S3BootScriptWidthFifoUint8:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFifoUint8 - 0x%08x\n", (UINTN)Address));
+ *Out.Uint8 = MmioRead8 ((UINTN) Address);
+ break;
+ case S3BootScriptWidthFillUint8:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFillUint8 - 0x%08x\n", (UINTN)Address));
+ *Out.Uint8 = MmioRead8 ((UINTN) Address);
+ break;
+
+ case S3BootScriptWidthUint16:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthUint16 - 0x%08x\n", (UINTN)Address));
+ *Out.Uint16 = MmioRead16 ((UINTN) Address);
+ break;
+ case S3BootScriptWidthFifoUint16:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFifoUint16 - 0x%08x\n", (UINTN)Address));
+ *Out.Uint16 = MmioRead16 ((UINTN) Address);
+ break;
+ case S3BootScriptWidthFillUint16:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFillUint16 - 0x%08x\n", (UINTN)Address));
+ *Out.Uint16 = MmioRead16 ((UINTN) Address);
+ break;
+
+ case S3BootScriptWidthUint32:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthUint32 - 0x%08x\n", (UINTN)Address));
+ *Out.Uint32 = MmioRead32 ((UINTN) Address);
+ break;
+ case S3BootScriptWidthFifoUint32:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFifoUint32 - 0x%08x\n", (UINTN)Address));
+ *Out.Uint32 = MmioRead32 ((UINTN) Address);
+ break;
+ case S3BootScriptWidthFillUint32:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFillUint32 - 0x%08x\n", (UINTN)Address));
+ *Out.Uint32 = MmioRead32 ((UINTN) Address);
+ break;
+
+ case S3BootScriptWidthUint64:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthUint64 - 0x%08x\n", (UINTN)Address));
+ *Out.Uint64 = MmioRead64 ((UINTN) Address);
+ break;
+ case S3BootScriptWidthFifoUint64:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFifoUint64 - 0x%08x\n", (UINTN)Address));
+ *Out.Uint64 = MmioRead64 ((UINTN) Address);
+ break;
+ case S3BootScriptWidthFillUint64:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFillUint64 - 0x%08x\n", (UINTN)Address));
+ *Out.Uint64 = MmioRead64 ((UINTN) Address);
+ break;
+
+ default:
+ return EFI_UNSUPPORTED;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+/**
+ Perform memory write operation
+
+ @param Width Width of the operation.
+ @param Address Address of the operation.
+ @param Count Count of the number of accesses to perform.
+ @param Buffer Pointer to the buffer write to memory.
+
+ @retval EFI_SUCCESS The data was written to the EFI System.
+ @retval EFI_INVALID_PARAMETER Width is invalid for this EFI System.
+ Buffer is NULL.
+ The Buffer is not aligned for the given Width.
+ @retval EFI_UNSUPPORTED The address range specified by Address, Width, and Count
+ is not valid for this EFI System.
+
+**/
+EFI_STATUS
+ScriptMemoryWrite (
+ IN S3_BOOT_SCRIPT_LIB_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ UINTN AddressStride;
+ UINT64 OriginalAddress;
+ UINTN BufferStride;
+ PTR In;
+ PTR OriginalIn;
+
+ In.Buf = Buffer;
+
+ Status = BuildLoopData (Width, Address, &AddressStride, &BufferStride);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Loop for each iteration and move the data
+ //
+ OriginalAddress = Address;
+ OriginalIn.Buf = In.Buf;
+ for (; Count > 0; Count--, Address += AddressStride, In.Buf += BufferStride) {
+ switch (Width) {
+ case S3BootScriptWidthUint8:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthUint8 - 0x%08x (0x%02x)\n", (UINTN)Address, (UINTN)*In.Uint8));
+ MmioWrite8 ((UINTN) Address, *In.Uint8);
+ break;
+ case S3BootScriptWidthFifoUint8:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFifoUint8 - 0x%08x (0x%02x)\n", (UINTN)OriginalAddress, (UINTN)*In.Uint8));
+ MmioWrite8 ((UINTN) OriginalAddress, *In.Uint8);
+ break;
+ case S3BootScriptWidthFillUint8:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFillUint8 - 0x%08x (0x%02x)\n", (UINTN)Address, (UINTN)*OriginalIn.Uint8));
+ MmioWrite8 ((UINTN) Address, *OriginalIn.Uint8);
+ break;
+ case S3BootScriptWidthUint16:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthUint16 - 0x%08x (0x%04x)\n", (UINTN)Address, (UINTN)*In.Uint16));
+ MmioWrite16 ((UINTN) Address, *In.Uint16);
+ break;
+ case S3BootScriptWidthFifoUint16:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFifoUint16 - 0x%08x (0x%04x)\n", (UINTN)OriginalAddress, (UINTN)*In.Uint16));
+ MmioWrite16 ((UINTN) OriginalAddress, *In.Uint16);
+ break;
+ case S3BootScriptWidthFillUint16:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFillUint16 - 0x%08x (0x%04x)\n", (UINTN)Address, (UINTN)*OriginalIn.Uint16));
+ MmioWrite16 ((UINTN) Address, *OriginalIn.Uint16);
+ break;
+ case S3BootScriptWidthUint32:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthUint32 - 0x%08x (0x%08x)\n", (UINTN)Address, (UINTN)*In.Uint32));
+ MmioWrite32 ((UINTN) Address, *In.Uint32);
+ break;
+ case S3BootScriptWidthFifoUint32:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFifoUint32 - 0x%08x (0x%08x)\n", (UINTN)OriginalAddress, (UINTN)*In.Uint32));
+ MmioWrite32 ((UINTN) OriginalAddress, *In.Uint32);
+ break;
+ case S3BootScriptWidthFillUint32:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFillUint32 - 0x%08x (0x%08x)\n", (UINTN)Address, (UINTN)*OriginalIn.Uint32));
+ MmioWrite32 ((UINTN) Address, *OriginalIn.Uint32);
+ break;
+ case S3BootScriptWidthUint64:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthUint64 - 0x%08x (0x%016lx)\n", (UINTN)Address, *In.Uint64));
+ MmioWrite64 ((UINTN) Address, *In.Uint64);
+ break;
+ case S3BootScriptWidthFifoUint64:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFifoUint64 - 0x%08x (0x%016lx)\n", (UINTN)OriginalAddress, *In.Uint64));
+ MmioWrite64 ((UINTN) OriginalAddress, *In.Uint64);
+ break;
+ case S3BootScriptWidthFillUint64:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFillUint64 - 0x%08x (0x%016lx)\n", (UINTN)Address, *OriginalIn.Uint64));
+ MmioWrite64 ((UINTN) Address, *OriginalIn.Uint64);
+ break;
+ default:
+ return EFI_UNSUPPORTED;
+ }
+ }
+ return EFI_SUCCESS;
+}
+/**
+ Interprete the boot script node with EFI_BOOT_SCRIPT_MEM_WRITE OP code.
+
+ @param[in] Script Pointer to the node which is to be interpreted.
+
+ @retval EFI_SUCCESS The data was written to the EFI System.
+ @retval EFI_INVALID_PARAMETER Width is invalid for this EFI System.
+ Buffer is NULL.
+ The Buffer is not aligned for the given Width.
+ @retval EFI_UNSUPPORTED The address range specified by Address, Width, and Count
+ is not valid for this EFI System.
+
+**/
+EFI_STATUS
+BootScriptExecuteMemoryWrite (
+ IN UINT8 *Script
+ )
+{
+ VOID *Buffer;
+ S3_BOOT_SCRIPT_LIB_WIDTH Width;
+ UINT64 Address;
+ UINTN Count;
+ EFI_BOOT_SCRIPT_MEM_WRITE MemWrite;
+
+ CopyMem((VOID*)&MemWrite, (VOID*)Script, sizeof(EFI_BOOT_SCRIPT_MEM_WRITE));
+ Width = (S3_BOOT_SCRIPT_LIB_WIDTH)MemWrite.Width;
+ Address = MemWrite.Address;
+ Count = MemWrite.Count;
+ Buffer = Script + sizeof(EFI_BOOT_SCRIPT_MEM_WRITE);
+
+ DEBUG ((EFI_D_INFO, "BootScriptExecuteMemoryWrite - 0x%08x, 0x%08x, 0x%08x\n", (UINTN)Address, Count, (UINTN)Width));
+ return ScriptMemoryWrite (Width,Address, Count, Buffer);
+
+}
+/**
+ Performance PCI configuration read operation
+
+ @param Width Width of the operation.
+ @param Address Address of the operation.
+ @param Count Count of the number of accesses to perform.
+ @param Buffer Pointer to the buffer read from PCI config space
+
+ @retval EFI_SUCCESS The read succeed.
+ @retval EFI_INVALID_PARAMETER if Width is not defined
+ @note A known Limitations in the implementation which is 64bits operations are not supported.
+
+**/
+EFI_STATUS
+ScriptPciCfgRead (
+ IN S3_BOOT_SCRIPT_LIB_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ UINTN AddressStride;
+ UINTN BufferStride;
+ PTR Out;
+ UINTN PciAddress;
+
+ Out.Buf = (UINT8 *) Buffer;
+
+ PciAddress = PCI_ADDRESS_ENCODE (Address);
+
+ Status = BuildLoopData (Width, PciAddress, &AddressStride, &BufferStride);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Loop for each iteration and move the data
+ //
+ for (; Count > 0; Count--, PciAddress += AddressStride, Out.Buf += BufferStride) {
+ switch (Width) {
+ case S3BootScriptWidthUint8:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthUint8 - 0x%08x\n", PciAddress));
+ *Out.Uint8 = PciRead8 (PciAddress);
+ break;
+ case S3BootScriptWidthFifoUint8:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFifoUint8 - 0x%08x\n", PciAddress));
+ *Out.Uint8 = PciRead8 (PciAddress);
+ break;
+ case S3BootScriptWidthFillUint8:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFillUint8 - 0x%08x\n", PciAddress));
+ *Out.Uint8 = PciRead8 (PciAddress);
+ break;
+
+ case S3BootScriptWidthUint16:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthUint16 - 0x%08x\n", PciAddress));
+ *Out.Uint16 = PciRead16 (PciAddress);
+ break;
+ case S3BootScriptWidthFifoUint16:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFifoUint16 - 0x%08x\n", PciAddress));
+ *Out.Uint16 = PciRead16 (PciAddress);
+ break;
+ case S3BootScriptWidthFillUint16:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFillUint16 - 0x%08x\n", PciAddress));
+ *Out.Uint16 = PciRead16 (PciAddress);
+ break;
+
+ case S3BootScriptWidthUint32:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthUint32 - 0x%08x\n", PciAddress));
+ *Out.Uint32 = PciRead32 (PciAddress);
+ break;
+ case S3BootScriptWidthFifoUint32:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFifoUint32 - 0x%08x\n", PciAddress));
+ *Out.Uint32 = PciRead32 (PciAddress);
+ break;
+ case S3BootScriptWidthFillUint32:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFillUint32 - 0x%08x\n", PciAddress));
+ *Out.Uint32 = PciRead32 (PciAddress);
+ break;
+
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Performance PCI configuration write operation
+
+ @param Width Width of the operation.
+ @param Address Address of the operation.
+ @param Count Count of the number of accesses to perform.
+ @param Buffer Pointer to the buffer write to PCI config space
+
+ @retval EFI_SUCCESS The write succeed.
+ @retval EFI_INVALID_PARAMETER if Width is not defined
+ @note A known Limitations in the implementation which is 64bits operations are not supported.
+
+**/
+EFI_STATUS
+ScriptPciCfgWrite (
+ IN S3_BOOT_SCRIPT_LIB_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ UINTN AddressStride;
+ UINTN BufferStride;
+ UINTN OriginalPciAddress;
+ PTR In;
+ PTR OriginalIn;
+ UINTN PciAddress;
+
+ In.Buf = (UINT8 *) Buffer;
+
+ PciAddress = PCI_ADDRESS_ENCODE (Address);
+
+ Status = BuildLoopData (Width, PciAddress, &AddressStride, &BufferStride);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Loop for each iteration and move the data
+ //
+ OriginalPciAddress = PciAddress;
+ OriginalIn.Buf = In.Buf;
+ for (; Count > 0; Count--, PciAddress += AddressStride, In.Buf += BufferStride) {
+ switch (Width) {
+ case S3BootScriptWidthUint8:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthUint8 - 0x%08x (0x%02x)\n", PciAddress, (UINTN)*In.Uint8));
+ PciWrite8 (PciAddress, *In.Uint8);
+ break;
+ case S3BootScriptWidthFifoUint8:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFifoUint8 - 0x%08x (0x%02x)\n", OriginalPciAddress, (UINTN)*In.Uint8));
+ PciWrite8 (OriginalPciAddress, *In.Uint8);
+ break;
+ case S3BootScriptWidthFillUint8:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFillUint8 - 0x%08x (0x%02x)\n", PciAddress, (UINTN)*OriginalIn.Uint8));
+ PciWrite8 (PciAddress, *OriginalIn.Uint8);
+ break;
+ case S3BootScriptWidthUint16:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthUint16 - 0x%08x (0x%04x)\n", PciAddress, (UINTN)*In.Uint16));
+ PciWrite16 (PciAddress, *In.Uint16);
+ break;
+ case S3BootScriptWidthFifoUint16:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFifoUint16 - 0x%08x (0x%04x)\n", OriginalPciAddress, (UINTN)*In.Uint16));
+ PciWrite16 (OriginalPciAddress, *In.Uint16);
+ break;
+ case S3BootScriptWidthFillUint16:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFillUint16 - 0x%08x (0x%04x)\n", PciAddress, (UINTN)*OriginalIn.Uint16));
+ PciWrite16 (PciAddress, *OriginalIn.Uint16);
+ break;
+ case S3BootScriptWidthUint32:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthUint32 - 0x%08x (0x%08x)\n", PciAddress, (UINTN)*In.Uint32));
+ PciWrite32 (PciAddress, *In.Uint32);
+ break;
+ case S3BootScriptWidthFifoUint32:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFifoUint32 - 0x%08x (0x%08x)\n", OriginalPciAddress, (UINTN)*In.Uint32));
+ PciWrite32 (OriginalPciAddress, *In.Uint32);
+ break;
+ case S3BootScriptWidthFillUint32:
+ DEBUG ((EFI_D_INFO, "S3BootScriptWidthFillUint32 - 0x%08x (0x%08x)\n", (UINTN)PciAddress, (UINTN)*OriginalIn.Uint32));
+ PciWrite32 (PciAddress, *OriginalIn.Uint32);
+ break;
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ return EFI_SUCCESS;
+}
+/**
+ Performance PCI configuration 2 read operation
+
+ @param Width Width of the operation.
+ @param Segment Pci segment number
+ @param Address Address of the operation.
+ @param Count Count of the number of accesses to perform.
+ @param Buffer Pointer to the buffer to read from PCI config space.
+
+ @retval EFI_SUCCESS The data was written to the EFI System.
+ @retval EFI_INVALID_PARAMETER Width is invalid for this EFI System.
+ Buffer is NULL.
+ The Buffer is not aligned for the given Width.
+ Address is outside the legal range of I/O ports.
+ @note A known Limitations in the implementation which is the 'Segment' parameter is assumed as
+ Zero, or else, assert.
+**/
+EFI_STATUS
+ScriptPciCfg2Read (
+ IN S3_BOOT_SCRIPT_LIB_WIDTH Width,
+ IN UINT16 Segment,
+ IN UINT64 Address,
+ IN UINTN Count,
+ OUT VOID *Buffer
+ )
+{
+ ASSERT (Segment==0);
+
+ return ScriptPciCfgRead (Width, Address, Count, Buffer);
+}
+/**
+ Performance PCI configuration 2 write operation
+
+ @param Width Width of the operation.
+ @param Segment Pci segment number
+ @param Address Address of the operation.
+ @param Count Count of the number of accesses to perform.
+ @param Buffer Pointer to the buffer to write to PCI config space.
+
+ @retval EFI_SUCCESS The data was written to the EFI System.
+ @retval EFI_INVALID_PARAMETER Width is invalid for this EFI System.
+ Buffer is NULL.
+ The Buffer is not aligned for the given Width.
+ Address is outside the legal range of I/O ports.
+ @note A known Limitations in the implementation which is the 'Segment' parameter is assumed as
+ Zero, or else, assert.
+
+**/
+EFI_STATUS
+EFIAPI
+ScriptPciCfg2Write (
+ IN S3_BOOT_SCRIPT_LIB_WIDTH Width,
+ IN UINT16 Segment,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN VOID *Buffer
+ )
+{
+ ASSERT (Segment==0);
+ return ScriptPciCfgWrite (Width, Address, Count, Buffer);
+}
+/**
+ Interprete the boot script node with EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE OP code.
+
+ @param Script The pointer of typed node in boot script table
+
+ @retval EFI_SUCCESS The operation was executed successfully
+**/
+EFI_STATUS
+BootScriptExecutePciCfgWrite (
+ IN UINT8 *Script
+ )
+{
+ VOID *Buffer;
+ S3_BOOT_SCRIPT_LIB_WIDTH Width;
+ UINT64 Address;
+ UINTN Count;
+ EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE PciCfgWrite;
+
+ CopyMem ((VOID*)&PciCfgWrite, (VOID*)Script, sizeof(EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE));
+
+ Width = (S3_BOOT_SCRIPT_LIB_WIDTH)PciCfgWrite.Width;
+ Address = PciCfgWrite.Address;
+ Count = PciCfgWrite.Count;
+ Buffer = Script + sizeof(EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE);
+
+ DEBUG ((EFI_D_INFO, "BootScriptExecutePciCfgWrite - 0x%08x, 0x%08x, 0x%08x\n", PCI_ADDRESS_ENCODE (Address), Count, (UINTN)Width));
+ return ScriptPciCfgWrite (Width, Address, Count, Buffer);
+}
+/**
+ Interprete the boot script node with EFI_BOOT_SCRIPT_IO_READ_WRITE OP code.
+
+ @param Script The pointer of typed node in boot script table
+ @param AndMask Mask value for 'and' operation
+ @param OrMask Mask value for 'or' operation
+
+ @retval EFI_SUCCESS The operation was executed successfully
+**/
+EFI_STATUS
+BootScriptExecuteIoReadWrite (
+ IN UINT8 *Script,
+ IN UINT64 AndMask,
+ IN UINT64 OrMask
+ )
+
+{
+ EFI_STATUS Status;
+ UINT64 Data;
+ EFI_BOOT_SCRIPT_IO_READ_WRITE IoReadWrite;
+
+ Data = 0;
+
+ CopyMem((VOID*)&IoReadWrite, (VOID*)Script, sizeof(EFI_BOOT_SCRIPT_IO_READ_WRITE));
+
+ DEBUG ((EFI_D_INFO, "BootScriptExecuteIoReadWrite - 0x%08x, 0x%016lx, 0x%016lx\n", (UINTN)IoReadWrite.Address, AndMask, OrMask));
+
+ Status = ScriptIoRead (
+ (S3_BOOT_SCRIPT_LIB_WIDTH) IoReadWrite.Width,
+ IoReadWrite.Address,
+ 1,
+ &Data
+ );
+ if (!EFI_ERROR (Status)) {
+ Data = (Data & AndMask) | OrMask;
+ Status = ScriptIoWrite (
+ (S3_BOOT_SCRIPT_LIB_WIDTH) IoReadWrite.Width,
+ IoReadWrite.Address,
+ 1,
+ &Data
+ );
+ }
+ return Status;
+}
+/**
+ Interprete the boot script node with EFI_BOOT_SCRIPT_MEM_READ_WRITE OP code.
+
+ @param Script The pointer of typed node in boot script table
+ @param AndMask Mask value for 'and' operation
+ @param OrMask Mask value for 'or' operation
+
+ @retval EFI_SUCCESS The operation was executed successfully
+**/
+EFI_STATUS
+BootScriptExecuteMemoryReadWrite (
+ IN UINT8 *Script,
+ IN UINT64 AndMask,
+ IN UINT64 OrMask
+ )
+
+{
+ EFI_STATUS Status;
+ UINT64 Data;
+ EFI_BOOT_SCRIPT_MEM_READ_WRITE MemReadWrite;
+
+ Data = 0;
+
+ CopyMem((VOID*)&MemReadWrite, (VOID*)Script, sizeof(EFI_BOOT_SCRIPT_MEM_READ_WRITE));
+
+ DEBUG ((EFI_D_INFO, "BootScriptExecuteMemoryReadWrite - 0x%08x, 0x%016lx, 0x%016lx\n", (UINTN)MemReadWrite.Address, AndMask, OrMask));
+
+ Status = ScriptMemoryRead (
+ (S3_BOOT_SCRIPT_LIB_WIDTH) MemReadWrite.Width,
+ MemReadWrite.Address,
+ 1,
+ &Data
+ );
+ if (!EFI_ERROR (Status)) {
+ Data = (Data & AndMask) | OrMask;
+ Status = ScriptMemoryWrite (
+ (S3_BOOT_SCRIPT_LIB_WIDTH) MemReadWrite.Width,
+ MemReadWrite.Address,
+ 1,
+ &Data
+ );
+ }
+ return Status;
+}
+/**
+ Interprete the boot script node with EFI_BOOT_SCRIPT_PCI_CFG_READ_WRITE OP code.
+
+ @param Script The pointer of typed node in boot script table
+ @param AndMask Mask value for 'and' operation
+ @param OrMask Mask value for 'or' operation
+
+ @retval EFI_SUCCESS The operation was executed successfully
+**/
+EFI_STATUS
+BootScriptExecutePciCfgReadWrite (
+ IN UINT8 *Script,
+ IN UINT64 AndMask,
+ IN UINT64 OrMask
+ )
+
+{
+ EFI_STATUS Status;
+ UINT64 Data;
+ EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE PciCfgReadWrite;
+
+ Data = 0;
+
+ CopyMem((VOID*)&PciCfgReadWrite, (VOID*)Script, sizeof(EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE));
+
+ DEBUG ((EFI_D_INFO, "BootScriptExecutePciCfgReadWrite - 0x%08x, 0x%016lx, 0x%016lx\n", PCI_ADDRESS_ENCODE (PciCfgReadWrite.Address), AndMask, OrMask));
+
+ Status = ScriptPciCfgRead (
+ (S3_BOOT_SCRIPT_LIB_WIDTH) PciCfgReadWrite.Width,
+ PciCfgReadWrite.Address,
+ 1,
+ &Data
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Data = (Data & AndMask) | OrMask;
+
+ Status = ScriptPciCfgWrite (
+ (S3_BOOT_SCRIPT_LIB_WIDTH) PciCfgReadWrite.Width,
+ PciCfgReadWrite.Address,
+ 1,
+ &Data
+ );
+
+ return Status;
+}
+/**
+ Interprete the boot script node with EFI_BOOT_SCRIPT_SMBUS_EXECUTE OP code.
+
+ @param Script The pointer of typed node in boot script table
+
+ @retval EFI_SUCCESS The operation was executed successfully
+ @retval EFI_UNSUPPORTED Cannot locate smbus ppi or occur error of script execution
+ @retval Others Result of script execution
+**/
+EFI_STATUS
+BootScriptExecuteSmbusExecute (
+ IN UINT8 *Script
+ )
+{
+ UINTN SmBusAddress;
+ UINTN DataSize;
+ EFI_BOOT_SCRIPT_SMBUS_EXECUTE SmbusExecuteEntry;
+
+ CopyMem ((VOID*)&SmbusExecuteEntry, (VOID*)Script, sizeof(EFI_BOOT_SCRIPT_SMBUS_EXECUTE ));
+
+ DEBUG ((EFI_D_INFO, "BootScriptExecuteSmbusExecute - 0x%08x, 0x%08x\n", (UINTN)SmbusExecuteEntry.SmBusAddress, (UINTN)SmbusExecuteEntry.Operation));
+
+ SmBusAddress = (UINTN)SmbusExecuteEntry.SmBusAddress;
+ DataSize = (UINTN) SmbusExecuteEntry.DataSize;
+ return SmbusExecute (
+ SmBusAddress,
+ (EFI_SMBUS_OPERATION) SmbusExecuteEntry.Operation,
+ &DataSize,
+ Script + sizeof (EFI_BOOT_SCRIPT_SMBUS_EXECUTE)
+ );
+}
+/**
+ Interprete the boot script node with EFI_BOOT_SCRIPT_STALL OP code.
+
+ @param Script The pointer of typed node in boot script table
+
+ @retval EFI_SUCCESS The operation was executed successfully
+**/
+EFI_STATUS
+BootScriptExecuteStall (
+ IN UINT8 *Script
+ )
+{
+ EFI_BOOT_SCRIPT_STALL Stall;
+
+ CopyMem ((VOID*)&Stall, (VOID*)Script, sizeof(EFI_BOOT_SCRIPT_STALL));
+
+ DEBUG ((EFI_D_INFO, "BootScriptExecuteStall - 0x%08x\n", (UINTN)Stall.Duration));
+
+ MicroSecondDelay ((UINTN) Stall.Duration);
+ return EFI_SUCCESS;
+}
+/**
+ Interprete the boot script node with EFI_BOOT_SCRIPT_DISPATCH OP code.
+
+ @param Script The pointer of typed node in boot script table
+ @retval EFI_SUCCESS The operation was executed successfully
+**/
+EFI_STATUS
+BootScriptExecuteDispatch (
+ IN UINT8 *Script
+ )
+{
+ EFI_STATUS Status;
+ DISPATCH_ENTRYPOINT_FUNC EntryFunc;
+ EFI_BOOT_SCRIPT_DISPATCH ScriptDispatch;
+
+ CopyMem ((VOID*)&ScriptDispatch, (VOID*)Script, sizeof(EFI_BOOT_SCRIPT_DISPATCH));
+ EntryFunc = (DISPATCH_ENTRYPOINT_FUNC) (UINTN) (ScriptDispatch.EntryPoint);
+
+ DEBUG ((EFI_D_INFO, "BootScriptExecuteDispatch - 0x%08x\n", (UINTN)ScriptDispatch.EntryPoint));
+
+ Status = EntryFunc (NULL, NULL);
+
+ return Status;
+}
+/**
+ Interprete the boot script node with EFI_BOOT_SCRIPT_DISPATCH_2 OP code.
+
+ @param Script The pointer of typed node in boot script table
+ @retval EFI_SUCCESS The operation was executed successfully
+**/
+EFI_STATUS
+BootScriptExecuteDispatch2 (
+ IN UINT8 *Script
+ )
+{
+ EFI_STATUS Status;
+ DISPATCH_ENTRYPOINT_FUNC EntryFunc;
+ EFI_BOOT_SCRIPT_DISPATCH_2 ScriptDispatch2;
+
+ CopyMem ((VOID*)&ScriptDispatch2, (VOID*)Script, sizeof(EFI_BOOT_SCRIPT_DISPATCH_2));
+
+ DEBUG ((EFI_D_INFO, "BootScriptExecuteDispatch2 - 0x%08x(0x%08x)\n", (UINTN)ScriptDispatch2.EntryPoint, (UINTN)ScriptDispatch2.Context));
+
+ EntryFunc = (DISPATCH_ENTRYPOINT_FUNC) (UINTN) (ScriptDispatch2.EntryPoint);
+
+ Status = EntryFunc (NULL, (VOID *) (UINTN) ScriptDispatch2.Context);
+
+ return Status;
+}
+/**
+ Interprete the boot script node with EFI_BOOT_SCRIPT_MEM_POLL OP code.
+
+ @param Script The pointer of typed node in boot script table
+ @param AndMask Mask value for 'and' operation
+ @param OrMask Mask value for 'or' operation
+
+ @retval EFI_DEVICE_ERROR Data polled from memory does not equal to
+ the epecting data within the Loop Times.
+ @retval EFI_SUCCESS The operation was executed successfully
+**/
+EFI_STATUS
+BootScriptExecuteMemPoll (
+ IN UINT8 *Script,
+ IN UINT64 AndMask,
+ IN UINT64 OrMask
+ )
+{
+
+ UINT64 Data;
+ UINT64 LoopTimes;
+ EFI_STATUS Status;
+ EFI_BOOT_SCRIPT_MEM_POLL MemPoll;
+
+ CopyMem ((VOID*)&MemPoll, (VOID*)Script, sizeof(EFI_BOOT_SCRIPT_MEM_POLL));
+
+ DEBUG ((EFI_D_INFO, "BootScriptExecuteMemPoll - 0x%08x, 0x%016lx, 0x%016lx\n", (UINTN)MemPoll.Address, AndMask, OrMask));
+
+ Data = 0;
+ Status = ScriptMemoryRead (
+ (S3_BOOT_SCRIPT_LIB_WIDTH) MemPoll.Width,
+ MemPoll.Address,
+ 1,
+ &Data
+ );
+ if ((!EFI_ERROR (Status)) && (Data & AndMask) == OrMask) {
+ return EFI_SUCCESS;
+ }
+
+ for (LoopTimes = 0; LoopTimes < MemPoll.LoopTimes; LoopTimes++) {
+ MicroSecondDelay ((UINTN)MemPoll.Duration);
+
+ Data = 0;
+ Status = ScriptMemoryRead (
+ (S3_BOOT_SCRIPT_LIB_WIDTH) MemPoll.Width,
+ MemPoll.Address,
+ 1,
+ &Data
+ );
+ if ((!EFI_ERROR (Status)) && (Data & AndMask) == OrMask) {
+ return EFI_SUCCESS;
+ }
+ }
+
+ if (LoopTimes < MemPoll.LoopTimes) {
+ return EFI_SUCCESS;
+ } else {
+ return EFI_DEVICE_ERROR;
+ }
+}
+/**
+ Execute the boot script to interpret the Store arbitrary information.
+ This opcode is a no-op on dispatch and is only used for debugging script issues.
+
+ @param Script The pointer of node in boot script table
+
+**/
+VOID
+BootScriptExecuteInformation (
+ IN UINT8 *Script
+ )
+
+{
+ UINT32 Index;
+ EFI_BOOT_SCRIPT_INFORMATION Information;
+ UINT8 *InformationData;
+
+ CopyMem ((VOID*)&Information, (VOID*)Script, sizeof(EFI_BOOT_SCRIPT_INFORMATION));
+
+ InformationData = Script + sizeof (EFI_BOOT_SCRIPT_INFORMATION);
+ DEBUG ((EFI_D_INFO, "BootScriptExecuteInformation - 0x%08x\n", (UINTN) InformationData));
+
+ DEBUG ((EFI_D_INFO, "BootScriptInformation: "));
+ for (Index = 0; Index < Information.InformationLength; Index++) {
+ DEBUG ((EFI_D_INFO, "%02x ", InformationData[Index]));
+ }
+ DEBUG ((EFI_D_INFO, "\n"));
+}
+
+/**
+ Execute the boot script to interpret the Label information.
+
+ @param Script The pointer of node in boot script table
+
+**/
+VOID
+BootScriptExecuteLabel (
+ IN UINT8 *Script
+ )
+
+{
+ UINT32 Index;
+ EFI_BOOT_SCRIPT_INFORMATION Information;
+ UINT8 *InformationData;
+
+ CopyMem ((VOID*)&Information, (VOID*)Script, sizeof(EFI_BOOT_SCRIPT_INFORMATION));
+
+ InformationData = Script + sizeof (EFI_BOOT_SCRIPT_INFORMATION);
+ DEBUG ((EFI_D_INFO, "BootScriptExecuteLabel - 0x%08x\n", (UINTN) InformationData));
+
+ DEBUG ((EFI_D_INFO, "BootScriptLabel: "));
+ for (Index = 0; Index < Information.InformationLength; Index++) {
+ DEBUG ((EFI_D_INFO, "%02x ", InformationData[Index]));
+ }
+ DEBUG ((EFI_D_INFO, "\n"));
+}
+
+/**
+ calculate the mask value for 'and' and 'or' operation
+ @param ScriptHeader The pointer of header of node in boot script table
+ @param AndMask The Mask value for 'and' operation
+ @param OrMask The Mask value for 'or' operation
+ @param Script Pointer to the entry.
+
+**/
+VOID
+CheckAndOrMask (
+ IN EFI_BOOT_SCRIPT_COMMON_HEADER *ScriptHeader,
+ OUT UINT64 *AndMask,
+ OUT UINT64 *OrMask,
+ IN UINT8 *Script
+ )
+{
+ UINT8 *DataPtr;
+ UINTN Size;
+
+ switch (ScriptHeader->OpCode) {
+ case EFI_BOOT_SCRIPT_IO_READ_WRITE_OPCODE:
+ Size = sizeof (EFI_BOOT_SCRIPT_IO_READ_WRITE);
+ break;
+
+ case EFI_BOOT_SCRIPT_MEM_READ_WRITE_OPCODE:
+ Size = sizeof (EFI_BOOT_SCRIPT_MEM_READ_WRITE);
+ break;
+
+ case EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE_OPCODE:
+ Size = sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE);
+ break;
+ case EFI_BOOT_SCRIPT_MEM_POLL_OPCODE:
+ Size = sizeof (EFI_BOOT_SCRIPT_MEM_POLL);
+ break;
+
+ case EFI_BOOT_SCRIPT_IO_POLL_OPCODE:
+ Size = sizeof (EFI_BOOT_SCRIPT_IO_POLL);
+ break;
+
+ case EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE_OPCODE:
+ Size = sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE);
+ break;
+
+ case EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL_OPCODE:
+ Size = sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL);
+ break;
+
+ case EFI_BOOT_SCRIPT_PCI_CONFIG_POLL_OPCODE:
+ Size = sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_POLL);
+ break;
+
+ default:
+ return;
+ }
+
+ DataPtr = Script + Size;
+
+ switch (ScriptHeader->Width) {
+ case S3BootScriptWidthUint8:
+ *AndMask = (UINT64) (*(UINT8*) (DataPtr + 1));
+ *OrMask = (UINT64) (*DataPtr);
+ break;
+
+ case S3BootScriptWidthUint16:
+ *AndMask = (UINT64) (*(UINT16 *) (DataPtr + 2));
+ *OrMask = (UINT64) (*(UINT16 *) DataPtr);
+ break;
+
+ case S3BootScriptWidthUint32:
+ *AndMask = (UINT64) (*(UINT32 *) (DataPtr + 4));
+ *OrMask = (UINT64) (*(UINT32 *) DataPtr);
+ break;
+
+ case S3BootScriptWidthUint64:
+ *AndMask = (UINT64) (*(UINT64 *) (DataPtr + 8));
+ *OrMask = (UINT64) (*(UINT64 *) DataPtr);
+ break;
+
+ default:
+ break;
+ }
+
+ return;
+}
+/**
+ Interprete the boot script node with EFI_BOOT_SCRIPT_IO_POLL OP code.
+
+ @param Script The pointer of typed node in boot script table
+ @param AndMask Mask value for 'and' operation
+ @param OrMask Mask value for 'or' operation
+
+ @retval EFI_DEVICE_ERROR Data polled from memory does not equal to
+ the epecting data within the Loop Times.
+ @retval EFI_SUCCESS The operation was executed successfully
+**/
+EFI_STATUS
+BootScriptExecuteIoPoll (
+ IN UINT8 *Script,
+ IN UINT64 AndMask,
+ IN UINT64 OrMask
+ )
+{
+ EFI_STATUS Status;
+ UINT64 Data;
+ UINT64 LoopTimes;
+ EFI_BOOT_SCRIPT_IO_POLL IoPoll;
+
+ CopyMem ((VOID*)&IoPoll, (VOID*)Script, sizeof(EFI_BOOT_SCRIPT_IO_POLL));
+
+ DEBUG ((EFI_D_INFO, "BootScriptExecuteIoPoll - 0x%08x, 0x%016lx, 0x%016lx\n", (UINTN)IoPoll.Address, AndMask, OrMask));
+
+ Data = 0;
+ Status = ScriptIoRead (
+ (S3_BOOT_SCRIPT_LIB_WIDTH) IoPoll.Width,
+ IoPoll.Address,
+ 1,
+ &Data
+ );
+ if ((!EFI_ERROR (Status)) && (Data & AndMask) == OrMask) {
+ return EFI_SUCCESS;
+ }
+ for (LoopTimes = 0; LoopTimes < IoPoll.Delay; LoopTimes++) {
+ NanoSecondDelay (100);
+ Data = 0;
+ Status = ScriptIoRead (
+ (S3_BOOT_SCRIPT_LIB_WIDTH) IoPoll.Width,
+ IoPoll.Address,
+ 1,
+ &Data
+ );
+ if ((!EFI_ERROR (Status)) &&(Data & AndMask) == OrMask) {
+ return EFI_SUCCESS;
+ }
+ }
+
+ if (LoopTimes < IoPoll.Delay) {
+ return EFI_SUCCESS;
+ } else {
+ return EFI_DEVICE_ERROR;
+ }
+}
+/**
+ Interprete the boot script node with EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE OP code.
+
+ @param Script The pointer of S3 boot script
+
+ @retval EFI_SUCCESS The operation was executed successfully
+
+**/
+EFI_STATUS
+BootScriptExecutePciCfg2Write (
+ IN UINT8 *Script
+ )
+{
+ VOID *Buffer;
+ S3_BOOT_SCRIPT_LIB_WIDTH Width;
+ UINT16 Segment;
+ UINT64 Address;
+ UINTN Count;
+ EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE PciCfg2Write;
+
+ CopyMem ((VOID*)&PciCfg2Write, (VOID*)Script, sizeof(EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE));
+
+ Width = (S3_BOOT_SCRIPT_LIB_WIDTH)PciCfg2Write.Width;
+ Segment = PciCfg2Write.Segment;
+ Address = PciCfg2Write.Address;
+ Count = PciCfg2Write.Count;
+ Buffer = Script + sizeof(EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE);
+
+ DEBUG ((EFI_D_INFO, "BootScriptExecutePciCfg2Write - 0x%04x, 0x%08x, 0x%08x, 0x%08x\n", Segment, PCI_ADDRESS_ENCODE (Address), Count, (UINTN)Width));
+ return ScriptPciCfg2Write (Width, Segment, Address, Count, Buffer);
+}
+
+
+/**
+ Interprete the boot script node with EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE OP code.
+
+ @param Script The pointer of S3 boot script
+ @param AndMask Mask value for 'and' operation
+ @param OrMask Mask value for 'or' operation
+
+ @retval EFI_SUCCESS The operation was executed successfully
+
+**/
+EFI_STATUS
+BootScriptExecutePciCfg2ReadWrite (
+ IN UINT8 *Script,
+ IN UINT64 AndMask,
+ IN UINT64 OrMask
+ )
+{
+ UINT64 Data;
+ EFI_STATUS Status;
+ EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE PciCfg2ReadWrite;
+
+ Data = 0;
+
+ CopyMem ((VOID*)&PciCfg2ReadWrite, (VOID*)Script, sizeof(EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE));
+
+ DEBUG ((EFI_D_INFO, "BootScriptExecutePciCfg2ReadWrite - 0x%04x, 0x%08x, 0x%016lx, 0x%016lx\n", PciCfg2ReadWrite.Segment, PCI_ADDRESS_ENCODE (PciCfg2ReadWrite.Address), AndMask, OrMask));
+
+ Status = ScriptPciCfg2Read (
+ (S3_BOOT_SCRIPT_LIB_WIDTH) PciCfg2ReadWrite.Width,
+ PciCfg2ReadWrite.Segment,
+ PciCfg2ReadWrite.Address,
+ 1,
+ &Data
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Data = (Data & AndMask) | OrMask;
+ Status = ScriptPciCfg2Write (
+ (S3_BOOT_SCRIPT_LIB_WIDTH) PciCfg2ReadWrite.Width,
+ PciCfg2ReadWrite.Segment,
+ PciCfg2ReadWrite.Address,
+ 1,
+ &Data
+ );
+ return Status;
+}
+/**
+ Interprete the boot script node with EFI_BOOT_SCRIPT_PCI_CONFIG_POLL OP code.
+
+ @param Script The pointer of S3 boot script
+ @param AndMask Mask value for 'and' operation
+ @param OrMask Mask value for 'or' operation
+
+ @retval EFI_SUCCESS The operation was executed successfully
+ @retval EFI_DEVICE_ERROR Data polled from Pci configuration space does not equal to
+ epecting data within the Loop Times.
+**/
+EFI_STATUS
+BootScriptPciCfgPoll (
+ IN UINT8 *Script,
+ IN UINT64 AndMask,
+ IN UINT64 OrMask
+ )
+{
+ UINT64 Data;
+ UINT64 LoopTimes;
+ EFI_STATUS Status;
+ EFI_BOOT_SCRIPT_PCI_CONFIG_POLL PciCfgPoll;
+ CopyMem ((VOID*)&PciCfgPoll, (VOID*)Script, sizeof(EFI_BOOT_SCRIPT_PCI_CONFIG_POLL));
+
+ DEBUG ((EFI_D_INFO, "BootScriptPciCfgPoll - 0x%08x, 0x%016lx, 0x%016lx\n", PCI_ADDRESS_ENCODE (PciCfgPoll.Address), AndMask, OrMask));
+
+ Data = 0;
+ Status = ScriptPciCfgRead (
+ (S3_BOOT_SCRIPT_LIB_WIDTH) PciCfgPoll.Width,
+ PciCfgPoll.Address,
+ 1,
+ &Data
+ );
+ if ((!EFI_ERROR (Status)) &&(Data & AndMask) == OrMask) {
+ return EFI_SUCCESS;
+ }
+
+ for (LoopTimes = 0; LoopTimes < PciCfgPoll.Delay; LoopTimes++) {
+ NanoSecondDelay (100);
+ Data = 0;
+ Status = ScriptPciCfgRead (
+ (S3_BOOT_SCRIPT_LIB_WIDTH) PciCfgPoll.Width,
+ PciCfgPoll.Address,
+ 1,
+ &Data
+ );
+ if ((!EFI_ERROR (Status)) &&
+ (Data & AndMask) == OrMask) {
+ return EFI_SUCCESS;
+ }
+ }
+
+ if (LoopTimes < PciCfgPoll.Delay) {
+ return EFI_SUCCESS;
+ } else {
+ return EFI_DEVICE_ERROR;
+ }
+}
+
+/**
+ Interprete the boot script node with EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL OP code.
+
+ @param Script The pointer of S3 Boot Script
+ @param AndMask Mask value for 'and' operation
+ @param OrMask Mask value for 'or' operation
+
+ @retval EFI_SUCCESS The operation was executed successfully
+ @retval EFI_DEVICE_ERROR Data polled from Pci configuration space does not equal to
+ epecting data within the Loop Times.
+
+**/
+EFI_STATUS
+BootScriptPciCfg2Poll (
+ IN UINT8 *Script,
+ IN UINT64 AndMask,
+ IN UINT64 OrMask
+ )
+{
+ EFI_STATUS Status;
+ UINT64 Data;
+ UINT64 LoopTimes;
+ EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL PciCfg2Poll;
+
+ Data = 0;
+ CopyMem ((VOID*)&PciCfg2Poll, (VOID*)Script, sizeof(EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL));
+
+ DEBUG ((EFI_D_INFO, "BootScriptPciCfg2Poll - 0x%04x, 0x%08x, 0x%016lx, 0x%016lx\n", PciCfg2Poll.Segment, PCI_ADDRESS_ENCODE (PciCfg2Poll.Address), AndMask, OrMask));
+
+ Status = ScriptPciCfg2Read (
+ (S3_BOOT_SCRIPT_LIB_WIDTH) PciCfg2Poll.Width,
+ PciCfg2Poll.Segment,
+ PciCfg2Poll.Address,
+ 1,
+ &Data
+ );
+ if ((!EFI_ERROR (Status)) && (Data & AndMask) == OrMask) {
+ return EFI_SUCCESS;
+ }
+
+ for (LoopTimes = 0; LoopTimes < PciCfg2Poll.Delay; LoopTimes++) {
+ NanoSecondDelay (100);
+
+ Data = 0;
+ Status = ScriptPciCfg2Read (
+ (S3_BOOT_SCRIPT_LIB_WIDTH) PciCfg2Poll.Width,
+ PciCfg2Poll.Segment,
+ PciCfg2Poll.Address,
+ 1,
+ &Data
+ );
+ if ((!EFI_ERROR (Status)) && (Data & AndMask) == OrMask) {
+ return EFI_SUCCESS;
+ }
+ }
+
+ if (LoopTimes < PciCfg2Poll.Delay) {
+ return EFI_SUCCESS;
+ } else {
+ return EFI_DEVICE_ERROR;
+ }
+
+}
+
+/**
+ Executes the S3 boot script table.
+
+ @retval RETURN_SUCCESS The boot script table was executed successfully.
+ @retval RETURN_UNSUPPORTED Invalid script table or opcode.
+
+ @note A known Limitations in the implementation: When interpreting the opcode EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE_OPCODE
+ EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE_OPCODE and EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL_OPCODE, the 'Segment' parameter is assumed as
+ Zero, or else, assert.
+**/
+RETURN_STATUS
+EFIAPI
+S3BootScriptExecute (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINT8* Script;
+ UINTN StartAddress;
+ UINT32 TableLength;
+ UINT64 AndMask;
+ UINT64 OrMask;
+ EFI_BOOT_SCRIPT_COMMON_HEADER ScriptHeader;
+ EFI_BOOT_SCRIPT_TABLE_HEADER TableHeader;
+ Script = mS3BootScriptTablePtr->TableBase;
+ if (Script != 0) {
+ CopyMem ((VOID*)&TableHeader, Script, sizeof(EFI_BOOT_SCRIPT_TABLE_HEADER));
+ } else {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ DEBUG ((EFI_D_INFO, "S3BootScriptExecute:\n"));
+ if (TableHeader.OpCode != S3_BOOT_SCRIPT_LIB_TABLE_OPCODE) {
+ return EFI_UNSUPPORTED;
+ }
+
+ DEBUG ((EFI_D_INFO, "TableHeader - 0x%08x\n", Script));
+
+ StartAddress = (UINTN) Script;
+ TableLength = TableHeader.TableLength;
+ Script = Script + TableHeader.Length;
+ Status = EFI_SUCCESS;
+ AndMask = 0;
+ OrMask = 0;
+
+ DEBUG ((EFI_D_INFO, "TableHeader.Version - 0x%04x\n", (UINTN)TableHeader.Version));
+ DEBUG ((EFI_D_INFO, "TableHeader.TableLength - 0x%08x\n", (UINTN)TableLength));
+
+ while ((UINTN) Script < (UINTN) (StartAddress + TableLength)) {
+ DEBUG ((EFI_D_INFO, "ExecuteBootScript - %08x\n", (UINTN)Script));
+
+ CopyMem ((VOID*)&ScriptHeader, Script, sizeof(EFI_BOOT_SCRIPT_COMMON_HEADER));
+ switch (ScriptHeader.OpCode) {
+
+ case EFI_BOOT_SCRIPT_MEM_WRITE_OPCODE:
+ DEBUG ((EFI_D_INFO, "EFI_BOOT_SCRIPT_MEM_WRITE_OPCODE\n"));
+ Status = BootScriptExecuteMemoryWrite (Script);
+ break;
+
+ case EFI_BOOT_SCRIPT_MEM_READ_WRITE_OPCODE:
+ DEBUG ((EFI_D_INFO, "EFI_BOOT_SCRIPT_MEM_READ_WRITE_OPCODE\n"));
+ CheckAndOrMask (&ScriptHeader, &AndMask, &OrMask, Script);
+ Status = BootScriptExecuteMemoryReadWrite (
+ Script,
+ AndMask,
+ OrMask
+ );
+ break;
+
+ case EFI_BOOT_SCRIPT_IO_WRITE_OPCODE:
+ DEBUG ((EFI_D_INFO, "EFI_BOOT_SCRIPT_IO_WRITE_OPCODE\n"));
+ Status = BootScriptExecuteIoWrite (Script);
+ break;
+
+ case EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE_OPCODE:
+ DEBUG ((EFI_D_INFO, "EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE_OPCODE\n"));
+ Status = BootScriptExecutePciCfgWrite (Script);
+ break;
+
+ case EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE_OPCODE:
+ DEBUG ((EFI_D_INFO, "EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE_OPCODE\n"));
+ CheckAndOrMask (&ScriptHeader, &AndMask, &OrMask, Script);
+ Status = BootScriptExecutePciCfgReadWrite (
+ Script,
+ AndMask,
+ OrMask
+ );
+ break;
+ case EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE_OPCODE:
+ DEBUG ((EFI_D_INFO, "EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE_OPCODE\n"));
+ Status = BootScriptExecutePciCfg2Write (Script);
+ break;
+
+ case EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE_OPCODE:
+ DEBUG ((EFI_D_INFO, "EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE_OPCODE\n"));
+ CheckAndOrMask (&ScriptHeader, &AndMask, &OrMask, Script);
+ Status = BootScriptExecutePciCfg2ReadWrite (
+ Script,
+ AndMask,
+ OrMask
+ );
+ break;
+ case EFI_BOOT_SCRIPT_DISPATCH_OPCODE:
+ DEBUG ((EFI_D_INFO, "EFI_BOOT_SCRIPT_DISPATCH_OPCODE\n"));
+ Status = BootScriptExecuteDispatch (Script);
+ break;
+
+ case EFI_BOOT_SCRIPT_DISPATCH_2_OPCODE:
+ DEBUG ((EFI_D_INFO, "EFI_BOOT_SCRIPT_DISPATCH_2_OPCODE\n"));
+ Status = BootScriptExecuteDispatch2 (Script);
+ break;
+
+ case EFI_BOOT_SCRIPT_INFORMATION_OPCODE:
+ DEBUG ((EFI_D_INFO, "EFI_BOOT_SCRIPT_INFORMATION_OPCODE\n"));
+ BootScriptExecuteInformation (Script);
+ break;
+
+ case S3_BOOT_SCRIPT_LIB_TERMINATE_OPCODE:
+ DEBUG ((EFI_D_INFO, "S3_BOOT_SCRIPT_LIB_TERMINATE_OPCODE\n"));
+ DEBUG ((EFI_D_INFO, "S3BootScriptDone - %r\n", EFI_SUCCESS));
+ return EFI_SUCCESS;
+
+ case EFI_BOOT_SCRIPT_IO_READ_WRITE_OPCODE:
+ DEBUG ((EFI_D_INFO, "EFI_BOOT_SCRIPT_IO_READ_WRITE_OPCODE\n"));
+ CheckAndOrMask (&ScriptHeader, &AndMask, &OrMask, Script);
+ Status = BootScriptExecuteIoReadWrite (
+ Script,
+ AndMask,
+ OrMask
+ );
+ break;
+
+ case EFI_BOOT_SCRIPT_SMBUS_EXECUTE_OPCODE:
+ DEBUG ((EFI_D_INFO, "EFI_BOOT_SCRIPT_SMBUS_EXECUTE_OPCODE\n"));
+ Status = BootScriptExecuteSmbusExecute (Script);
+ break;
+
+ case EFI_BOOT_SCRIPT_STALL_OPCODE:
+ DEBUG ((EFI_D_INFO, "EFI_BOOT_SCRIPT_STALL_OPCODE\n"));
+ Status = BootScriptExecuteStall (Script);
+ break;
+
+ case EFI_BOOT_SCRIPT_MEM_POLL_OPCODE:
+ DEBUG ((EFI_D_INFO, "EFI_BOOT_SCRIPT_MEM_POLL_OPCODE\n"));
+ CheckAndOrMask (&ScriptHeader, &AndMask, &OrMask, Script);
+ Status = BootScriptExecuteMemPoll (Script, AndMask, OrMask);
+
+ break;
+
+ case EFI_BOOT_SCRIPT_IO_POLL_OPCODE:
+ DEBUG ((EFI_D_INFO, "EFI_BOOT_SCRIPT_IO_POLL_OPCODE\n"));
+ CheckAndOrMask (&ScriptHeader, &AndMask, &OrMask, Script);
+ Status = BootScriptExecuteIoPoll (Script, AndMask, OrMask);
+ break;
+
+ case EFI_BOOT_SCRIPT_PCI_CONFIG_POLL_OPCODE:
+ DEBUG ((EFI_D_INFO, "EFI_BOOT_SCRIPT_PCI_CONFIG_POLL_OPCODE\n"));
+ CheckAndOrMask (&ScriptHeader, &AndMask, &OrMask, Script);
+ Status = BootScriptPciCfgPoll (Script, AndMask, OrMask);
+ break;
+
+ case EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL_OPCODE:
+ DEBUG ((EFI_D_INFO, "EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL_OPCODE\n"));
+ CheckAndOrMask (&ScriptHeader, &AndMask, &OrMask, Script);
+ Status = BootScriptPciCfg2Poll (Script, AndMask, OrMask);
+ break;
+
+ case S3_BOOT_SCRIPT_LIB_LABEL_OPCODE:
+ //
+ // For label
+ //
+ DEBUG ((EFI_D_INFO, "S3_BOOT_SCRIPT_LIB_LABEL_OPCODE\n"));
+ BootScriptExecuteLabel (Script);
+ break;
+ default:
+ DEBUG ((EFI_D_INFO, "S3BootScriptDone - %r\n", EFI_UNSUPPORTED));
+ return EFI_UNSUPPORTED;
+ }
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_INFO, "S3BootScriptDone - %r\n", Status));
+ return Status;
+ }
+
+ Script = Script + ScriptHeader.Length;
+ }
+
+ DEBUG ((EFI_D_INFO, "S3BootScriptDone - %r\n", Status));
+
+ return Status;
+}
+
diff --git a/Core/MdeModulePkg/Library/PiDxeS3BootScriptLib/BootScriptInternalFormat.h b/Core/MdeModulePkg/Library/PiDxeS3BootScriptLib/BootScriptInternalFormat.h
new file mode 100644
index 0000000000..99cb407dbd
--- /dev/null
+++ b/Core/MdeModulePkg/Library/PiDxeS3BootScriptLib/BootScriptInternalFormat.h
@@ -0,0 +1,188 @@
+/** @file
+ This file declares the internal Framework Boot Script format used by
+ the PI implementation of Script Saver and Executor.
+
+ Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions
+ of the BSD License which accompanies this distribution. The
+ full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _BOOT_SCRIPT_INTERNAL_FORMAT_H_
+#define _BOOT_SCRIPT_INTERNAL_FORMAT_H_
+
+#pragma pack(1)
+
+//
+// Boot Script Opcode Header Structure Definitions
+//
+
+typedef struct {
+ UINT16 OpCode;
+ UINT8 Length;
+} EFI_BOOT_SCRIPT_GENERIC_HEADER;
+
+typedef struct {
+ UINT16 OpCode;
+ UINT8 Length;
+ UINT16 Version;
+ UINT32 TableLength;
+ UINT16 Reserved[2];
+} EFI_BOOT_SCRIPT_TABLE_HEADER;
+
+typedef struct {
+ UINT16 OpCode;
+ UINT8 Length;
+ UINT32 Width;
+} EFI_BOOT_SCRIPT_COMMON_HEADER;
+
+typedef struct {
+ UINT16 OpCode;
+ UINT8 Length;
+ UINT32 Width;
+ UINT32 Count;
+ UINT64 Address;
+} EFI_BOOT_SCRIPT_IO_WRITE;
+
+typedef struct {
+ UINT16 OpCode;
+ UINT8 Length;
+ UINT32 Width;
+ UINT64 Address;
+} EFI_BOOT_SCRIPT_IO_READ_WRITE;
+
+typedef struct {
+ UINT16 OpCode;
+ UINT8 Length;
+ UINT32 Width;
+ UINT32 Count;
+ UINT64 Address;
+} EFI_BOOT_SCRIPT_MEM_WRITE;
+
+typedef struct {
+ UINT16 OpCode;
+ UINT8 Length;
+ UINT32 Width;
+ UINT64 Address;
+} EFI_BOOT_SCRIPT_MEM_READ_WRITE;
+
+typedef struct {
+ UINT16 OpCode;
+ UINT8 Length;
+ UINT32 Width;
+ UINT32 Count;
+ UINT64 Address;
+} EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE;
+
+typedef struct {
+ UINT16 OpCode;
+ UINT8 Length;
+ UINT32 Width;
+ UINT32 Count;
+ UINT64 Address;
+ UINT16 Segment;
+} EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE;
+
+typedef struct {
+ UINT16 OpCode;
+ UINT8 Length;
+ UINT32 Width;
+ UINT64 Address;
+} EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE;
+
+typedef struct {
+ UINT16 OpCode;
+ UINT8 Length;
+ UINT32 Width;
+ UINT64 Address;
+ UINT16 Segment;
+} EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE;
+
+typedef struct {
+ UINT16 OpCode;
+ UINT8 Length;
+ UINT64 SmBusAddress;
+ UINT32 Operation;
+ UINT32 DataSize;
+} EFI_BOOT_SCRIPT_SMBUS_EXECUTE;
+
+typedef struct {
+ UINT16 OpCode;
+ UINT8 Length;
+ UINT64 Duration;
+} EFI_BOOT_SCRIPT_STALL;
+
+typedef struct {
+ UINT16 OpCode;
+ UINT8 Length;
+ EFI_PHYSICAL_ADDRESS EntryPoint;
+} EFI_BOOT_SCRIPT_DISPATCH;
+
+typedef struct {
+ UINT16 OpCode;
+ UINT8 Length;
+ EFI_PHYSICAL_ADDRESS EntryPoint;
+ EFI_PHYSICAL_ADDRESS Context;
+} EFI_BOOT_SCRIPT_DISPATCH_2;
+
+typedef struct {
+ UINT16 OpCode;
+ UINT8 Length;
+ UINT32 Width;
+ UINT64 Address;
+ UINT64 Duration;
+ UINT64 LoopTimes;
+} EFI_BOOT_SCRIPT_MEM_POLL;
+
+typedef struct {
+ UINT16 OpCode;
+ UINT8 Length;
+ UINT32 InformationLength;
+// UINT8 InformationData[InformationLength];
+} EFI_BOOT_SCRIPT_INFORMATION;
+
+typedef struct {
+ UINT16 OpCode;
+ UINT8 Length;
+ UINT32 Width;
+ UINT64 Address;
+ UINT64 Delay;
+} EFI_BOOT_SCRIPT_IO_POLL;
+
+typedef struct {
+ UINT16 OpCode;
+ UINT8 Length;
+ UINT32 Width;
+ UINT64 Address;
+ UINT64 Delay;
+} EFI_BOOT_SCRIPT_PCI_CONFIG_POLL;
+
+typedef struct {
+ UINT16 OpCode;
+ UINT8 Length;
+ UINT32 Width;
+ UINT64 Address;
+ UINT16 Segment;
+ UINT64 Delay;
+} EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL;
+
+typedef struct {
+ UINT16 OpCode;
+ UINT8 Length;
+} EFI_BOOT_SCRIPT_TERMINATE;
+
+
+#pragma pack()
+
+#define BOOT_SCRIPT_NODE_MAX_LENGTH 1024
+
+#define BOOT_SCRIPT_TABLE_VERSION 0x0001
+
+#endif
diff --git a/Core/MdeModulePkg/Library/PiDxeS3BootScriptLib/BootScriptSave.c b/Core/MdeModulePkg/Library/PiDxeS3BootScriptLib/BootScriptSave.c
new file mode 100644
index 0000000000..0459bae4c6
--- /dev/null
+++ b/Core/MdeModulePkg/Library/PiDxeS3BootScriptLib/BootScriptSave.c
@@ -0,0 +1,2358 @@
+/** @file
+ Save the S3 data to S3 boot script.
+
+ Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions
+ of the BSD License which accompanies this distribution. The
+ full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+#include "InternalBootScriptLib.h"
+
+/**
+
+ Data structure usage:
+
+ +------------------------------+<------- PcdS3BootScriptTablePrivateDataPtr
+ | SCRIPT_TABLE_PRIVATE_DATA | (mS3BootScriptTablePtr, Before SmmReadyToLock)
+ | TableBase |--- PcdS3BootScriptTablePrivateSmmDataPtr
+ | TableLength |--|-- (mS3BootScriptTablePtr = mS3BootScriptTableSmmPtr, After SmmReadyToLock InSmm)
+ | TableMemoryPageNumber |--|-|----
+ | AtRuntime | | | |
+ | InSmm | | | |
+ | BootTimeScriptLength |--|-|---|---
+ | SmmLocked | | | | |
+ | BackFromS3 | | | | |
+ +------------------------------+ | | | |
+ | | | |
+ +------------------------------+<-- | | |
+ | EFI_BOOT_SCRIPT_TABLE_HEADER | | | |
+ | TableLength |----|-- | |
+ +------------------------------+ | | | |
+ | ...... | | | | |
+ +------------------------------+<---- | | |
+ | EFI_BOOT_SCRIPT_TERMINATE | | | |
+ +------------------------------+<------ | |
+ | |
+ | |
+ mBootScriptDataBootTimeGuid LockBox: | |
+ Used to restore data after back from S3| |
+ to handle potential INSERT boot script | |
+ at runtime. | |
+ +------------------------------+ | |
+ | Boot Time Boot Script | | |
+ | Before SmmReadyToLock | | |
+ | | | |
+ | | | |
+ +------------------------------+ | |
+ | Boot Time Boot Script | | |
+ | After SmmReadyToLock InSmm | | |
+ | | | |
+ +------------------------------+<-------|--|
+ | |
+ | |
+ mBootScriptDataGuid LockBox: (IN_PLACE) | |
+ Used to restore data at S3 resume. | |
+ +------------------------------+ | |
+ | Boot Time Boot Script | | |
+ | Before SmmReadyToLock | | |
+ | | | |
+ | | | |
+ +------------------------------+ | |
+ | Boot Time Boot Script | | |
+ | After SmmReadyToLock InSmm | | |
+ | | | |
+ +------------------------------+<-------|---
+ | Runtime Boot Script | |
+ | After SmmReadyToLock InSmm | |
+ +------------------------------+ |
+ | ...... | |
+ +------------------------------+<--------
+
+
+ mBootScriptTableBaseGuid LockBox: (IN_PLACE)
+ +------------------------------+
+ | mS3BootScriptTablePtr-> |
+ | TableBase |
+ +------------------------------+
+
+
+ mBootScriptSmmPrivateDataGuid LockBox: (IN_PLACE)
+ SMM private data with BackFromS3 = TRUE
+ at runtime. S3 will help restore it to
+ tell the Library the system is back from S3.
+ +------------------------------+
+ | SCRIPT_TABLE_PRIVATE_DATA |
+ | TableBase |
+ | TableLength |
+ | TableMemoryPageNumber |
+ | AtRuntime |
+ | InSmm |
+ | BootTimeScriptLength |
+ | SmmLocked |
+ | BackFromS3 = TRUE |
+ +------------------------------+
+
+**/
+
+SCRIPT_TABLE_PRIVATE_DATA *mS3BootScriptTablePtr;
+
+//
+// Allocate SMM copy because we can not use mS3BootScriptTablePtr after SmmReadyToLock in InSmm.
+//
+SCRIPT_TABLE_PRIVATE_DATA *mS3BootScriptTableSmmPtr;
+
+EFI_GUID mBootScriptDataGuid = {
+ 0xaea6b965, 0xdcf5, 0x4311, { 0xb4, 0xb8, 0xf, 0x12, 0x46, 0x44, 0x94, 0xd2 }
+};
+
+EFI_GUID mBootScriptDataBootTimeGuid = {
+ 0xb5af1d7a, 0xb8cf, 0x4eb3, { 0x89, 0x25, 0xa8, 0x20, 0xe1, 0x6b, 0x68, 0x7d }
+};
+
+EFI_GUID mBootScriptTableBaseGuid = {
+ 0x1810ab4a, 0x2314, 0x4df6, { 0x81, 0xeb, 0x67, 0xc6, 0xec, 0x5, 0x85, 0x91 }
+};
+
+EFI_GUID mBootScriptSmmPrivateDataGuid = {
+ 0x627ee2da, 0x3bf9, 0x439b, { 0x92, 0x9f, 0x2e, 0xe, 0x6e, 0x9d, 0xba, 0x62 }
+};
+
+EFI_EVENT mEventDxeSmmReadyToLock = NULL;
+VOID *mRegistrationSmmExitBootServices = NULL;
+VOID *mRegistrationSmmLegacyBoot = NULL;
+VOID *mRegistrationSmmReadyToLock = NULL;
+BOOLEAN mS3BootScriptTableAllocated = FALSE;
+BOOLEAN mS3BootScriptTableSmmAllocated = FALSE;
+EFI_SMM_SYSTEM_TABLE2 *mBootScriptSmst = NULL;
+
+/**
+ This is an internal function to add a terminate node the entry, recalculate the table
+ length and fill into the table.
+
+ @return the base address of the boot script table.
+ **/
+UINT8*
+S3BootScriptInternalCloseTable (
+ VOID
+ )
+{
+ UINT8 *S3TableBase;
+ EFI_BOOT_SCRIPT_TERMINATE ScriptTerminate;
+ EFI_BOOT_SCRIPT_TABLE_HEADER *ScriptTableInfo;
+ S3TableBase = mS3BootScriptTablePtr->TableBase;
+
+ if (S3TableBase == NULL) {
+ //
+ // the table is not exist
+ //
+ return S3TableBase;
+ }
+ //
+ // Append the termination entry.
+ //
+ ScriptTerminate.OpCode = S3_BOOT_SCRIPT_LIB_TERMINATE_OPCODE;
+ ScriptTerminate.Length = (UINT8) sizeof (EFI_BOOT_SCRIPT_TERMINATE);
+ CopyMem (mS3BootScriptTablePtr->TableBase + mS3BootScriptTablePtr->TableLength, &ScriptTerminate, sizeof (EFI_BOOT_SCRIPT_TERMINATE));
+ //
+ // fill the table length
+ //
+ ScriptTableInfo = (EFI_BOOT_SCRIPT_TABLE_HEADER*)(mS3BootScriptTablePtr->TableBase);
+ ScriptTableInfo->TableLength = mS3BootScriptTablePtr->TableLength + sizeof (EFI_BOOT_SCRIPT_TERMINATE);
+
+
+
+ return S3TableBase;
+ //
+ // NOTE: Here we did NOT adjust the mS3BootScriptTablePtr->TableLength to
+ // mS3BootScriptTablePtr->TableLength + sizeof (EFI_BOOT_SCRIPT_TERMINATE).
+ // Because maybe after SmmReadyToLock, we still need add entries into the table,
+ // and the entry should be added start before this TERMINATE node.
+ //
+}
+
+/**
+ This function save boot script data to LockBox.
+
+**/
+VOID
+SaveBootScriptDataToLockBox (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Save whole memory copy into LockBox.
+ // It will be used to restore data at S3 resume.
+ //
+ Status = SaveLockBox (
+ &mBootScriptDataGuid,
+ (VOID *)mS3BootScriptTablePtr->TableBase,
+ EFI_PAGES_TO_SIZE (mS3BootScriptTablePtr->TableMemoryPageNumber)
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = SetLockBoxAttributes (&mBootScriptDataGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Just need save TableBase.
+ // Do not update other field because they will NOT be used in S3.
+ //
+ Status = SaveLockBox (
+ &mBootScriptTableBaseGuid,
+ (VOID *)&mS3BootScriptTablePtr->TableBase,
+ sizeof(mS3BootScriptTablePtr->TableBase)
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = SetLockBoxAttributes (&mBootScriptTableBaseGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE);
+ ASSERT_EFI_ERROR (Status);
+}
+
+/**
+ This is the Event call back function to notify the Library the system is entering
+ SmmLocked phase.
+
+ @param Event Pointer to this event
+ @param Context Event handler private data
+ **/
+VOID
+EFIAPI
+S3BootScriptEventCallBack (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ VOID *Interface;
+
+ //
+ // Try to locate it because EfiCreateProtocolNotifyEvent will trigger it once when registration.
+ // Just return if it is not found.
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiDxeSmmReadyToLockProtocolGuid,
+ NULL,
+ &Interface
+ );
+ if (EFI_ERROR (Status)) {
+ return ;
+ }
+
+ //
+ // Here we should tell the library that we are entering SmmLocked phase.
+ // and the memory page number occupied by the table should not grow anymore.
+ //
+ if (!mS3BootScriptTablePtr->SmmLocked) {
+ //
+ // Before SmmReadyToLock, we need not write the terminate node when adding a node to boot scipt table
+ // or else, that will impact the performance. However, after SmmReadyToLock, we should append terminate
+ // node on every add to boot script table.
+ //
+ S3BootScriptInternalCloseTable ();
+ mS3BootScriptTablePtr->SmmLocked = TRUE;
+
+ //
+ // Save BootScript data to lockbox
+ //
+ SaveBootScriptDataToLockBox ();
+ }
+}
+
+/**
+ This is the Event call back function is triggered in SMM to notify the Library
+ the system is entering SmmLocked phase and set InSmm flag.
+
+ @param Protocol Points to the protocol's unique identifier
+ @param Interface Points to the interface instance
+ @param Handle The handle on which the interface was installed
+
+ @retval EFI_SUCCESS SmmEventCallback runs successfully
+ **/
+EFI_STATUS
+EFIAPI
+S3BootScriptSmmEventCallBack (
+ IN CONST EFI_GUID *Protocol,
+ IN VOID *Interface,
+ IN EFI_HANDLE Handle
+ )
+{
+ //
+ // Check if it is already done
+ //
+ if (mS3BootScriptTablePtr == mS3BootScriptTableSmmPtr) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Last chance to call-out, just make sure SmmLocked is set.
+ //
+ S3BootScriptEventCallBack (NULL, NULL);
+
+ //
+ // Save a SMM copy. If TableBase is NOT null, it means SMM copy has been ready, skip copy mem.
+ //
+ if (mS3BootScriptTableSmmPtr->TableBase == NULL) {
+ CopyMem (mS3BootScriptTableSmmPtr, mS3BootScriptTablePtr, sizeof(*mS3BootScriptTablePtr));
+
+ //
+ // Set InSmm, we allow boot script update when InSmm, but not allow boot script outside SMM.
+ // InSmm will only be checked if SmmLocked is TRUE.
+ //
+ mS3BootScriptTableSmmPtr->InSmm = TRUE;
+ }
+ //
+ // We should not use ACPI Reserved copy, because it is not safe.
+ //
+ mS3BootScriptTablePtr = mS3BootScriptTableSmmPtr;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function is to save boot time boot script data to LockBox.
+
+ Because there may be INSERT boot script at runtime in SMM.
+ The boot time copy will be used to restore data after back from S3.
+ Otherwise the data inserted may cause some boot time boot script data lost
+ if only BootScriptData used.
+
+**/
+VOID
+SaveBootTimeDataToLockBox (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // ACPI Reserved copy is not safe, restore from BootScriptData LockBox first,
+ // and then save the data to BootScriptDataBootTime LockBox.
+ //
+ Status = RestoreLockBox (
+ &mBootScriptDataGuid,
+ NULL,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Save BootScriptDataBootTime
+ // It will be used to restore data after back from S3.
+ //
+ Status = SaveLockBox (
+ &mBootScriptDataBootTimeGuid,
+ (VOID *) mS3BootScriptTablePtr->TableBase,
+ mS3BootScriptTablePtr->BootTimeScriptLength
+ );
+ ASSERT_EFI_ERROR (Status);
+}
+
+/**
+ This function save boot script SMM private data to LockBox with BackFromS3 = TRUE at runtime.
+ S3 resume will help restore it to tell the Library the system is back from S3.
+
+**/
+VOID
+SaveSmmPriviateDataToLockBoxAtRuntime (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Save boot script SMM private data with BackFromS3 = TRUE.
+ //
+ mS3BootScriptTablePtr->BackFromS3 = TRUE;
+ Status = SaveLockBox (
+ &mBootScriptSmmPrivateDataGuid,
+ (VOID *) mS3BootScriptTablePtr,
+ sizeof (SCRIPT_TABLE_PRIVATE_DATA)
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = SetLockBoxAttributes (&mBootScriptSmmPrivateDataGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Set BackFromS3 flag back to FALSE to indicate that now is not back from S3.
+ //
+ mS3BootScriptTablePtr->BackFromS3 = FALSE;
+}
+
+/**
+ This is the Event call back function is triggered in SMM to notify the Library
+ the system is entering runtime phase.
+
+ @param[in] Protocol Points to the protocol's unique identifier
+ @param[in] Interface Points to the interface instance
+ @param[in] Handle The handle on which the interface was installed
+
+ @retval EFI_SUCCESS SmmAtRuntimeCallBack runs successfully
+ **/
+EFI_STATUS
+EFIAPI
+S3BootScriptSmmAtRuntimeCallBack (
+ IN CONST EFI_GUID *Protocol,
+ IN VOID *Interface,
+ IN EFI_HANDLE Handle
+ )
+{
+ if (!mS3BootScriptTablePtr->AtRuntime) {
+ mS3BootScriptTablePtr->BootTimeScriptLength = (UINT32) (mS3BootScriptTablePtr->TableLength + sizeof (EFI_BOOT_SCRIPT_TERMINATE));
+ SaveBootTimeDataToLockBox ();
+
+ mS3BootScriptTablePtr->AtRuntime = TRUE;
+ SaveSmmPriviateDataToLockBoxAtRuntime ();
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Library Constructor.
+ this function just identify it is a smm driver or non-smm driver linked against
+ with the library
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval RETURN_SUCCESS The constructor always returns RETURN_SUCCESS.
+
+**/
+RETURN_STATUS
+EFIAPI
+S3BootScriptLibInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ SCRIPT_TABLE_PRIVATE_DATA *S3TablePtr;
+ SCRIPT_TABLE_PRIVATE_DATA *S3TableSmmPtr;
+ VOID *Registration;
+ EFI_SMM_BASE2_PROTOCOL *SmmBase2;
+ BOOLEAN InSmm;
+ EFI_PHYSICAL_ADDRESS Buffer;
+
+ S3TablePtr = (SCRIPT_TABLE_PRIVATE_DATA*)(UINTN)PcdGet64(PcdS3BootScriptTablePrivateDataPtr);
+ //
+ // The Boot script private data is not be initialized. create it
+ //
+ if (S3TablePtr == 0) {
+ Buffer = SIZE_4GB - 1;
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiReservedMemoryType,
+ EFI_SIZE_TO_PAGES(sizeof(SCRIPT_TABLE_PRIVATE_DATA)),
+ &Buffer
+ );
+ ASSERT_EFI_ERROR (Status);
+ mS3BootScriptTableAllocated = TRUE;
+ S3TablePtr = (VOID *) (UINTN) Buffer;
+
+ Status = PcdSet64S (PcdS3BootScriptTablePrivateDataPtr, (UINT64) (UINTN)S3TablePtr);
+ ASSERT_EFI_ERROR (Status);
+ ZeroMem (S3TablePtr, sizeof(SCRIPT_TABLE_PRIVATE_DATA));
+ //
+ // Create event to notify the library system enter the SmmLocked phase.
+ //
+ mEventDxeSmmReadyToLock = EfiCreateProtocolNotifyEvent (
+ &gEfiDxeSmmReadyToLockProtocolGuid,
+ TPL_CALLBACK,
+ S3BootScriptEventCallBack,
+ NULL,
+ &Registration
+ );
+ ASSERT (mEventDxeSmmReadyToLock != NULL);
+ }
+ mS3BootScriptTablePtr = S3TablePtr;
+
+ //
+ // Get InSmm, we need to register SmmReadyToLock if this library is linked to SMM driver.
+ //
+ Status = gBS->LocateProtocol (&gEfiSmmBase2ProtocolGuid, NULL, (VOID**) &SmmBase2);
+ if (EFI_ERROR (Status)) {
+ return RETURN_SUCCESS;
+ }
+ Status = SmmBase2->InSmm (SmmBase2, &InSmm);
+ if (EFI_ERROR (Status)) {
+ return RETURN_SUCCESS;
+ }
+ if (!InSmm) {
+ return RETURN_SUCCESS;
+ }
+ //
+ // Good, we are in SMM
+ //
+ Status = SmmBase2->GetSmstLocation (SmmBase2, &mBootScriptSmst);
+ if (EFI_ERROR (Status)) {
+ return RETURN_SUCCESS;
+ }
+
+ S3TableSmmPtr = (SCRIPT_TABLE_PRIVATE_DATA*)(UINTN)PcdGet64(PcdS3BootScriptTablePrivateSmmDataPtr);
+ //
+ // The Boot script private data in SMM is not be initialized. create it
+ //
+ if (S3TableSmmPtr == 0) {
+ Status = mBootScriptSmst->SmmAllocatePool (
+ EfiRuntimeServicesData,
+ sizeof(SCRIPT_TABLE_PRIVATE_DATA),
+ (VOID **) &S3TableSmmPtr
+ );
+ ASSERT_EFI_ERROR (Status);
+ mS3BootScriptTableSmmAllocated = TRUE;
+
+ Status = PcdSet64S (PcdS3BootScriptTablePrivateSmmDataPtr, (UINT64) (UINTN)S3TableSmmPtr);
+ ASSERT_EFI_ERROR (Status);
+ ZeroMem (S3TableSmmPtr, sizeof(SCRIPT_TABLE_PRIVATE_DATA));
+
+ //
+ // Register SmmExitBootServices and SmmLegacyBoot notification.
+ //
+ Status = mBootScriptSmst->SmmRegisterProtocolNotify (
+ &gEdkiiSmmExitBootServicesProtocolGuid,
+ S3BootScriptSmmAtRuntimeCallBack,
+ &mRegistrationSmmExitBootServices
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = mBootScriptSmst->SmmRegisterProtocolNotify (
+ &gEdkiiSmmLegacyBootProtocolGuid,
+ S3BootScriptSmmAtRuntimeCallBack,
+ &mRegistrationSmmLegacyBoot
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+ mS3BootScriptTableSmmPtr = S3TableSmmPtr;
+
+ //
+ // Register SmmReadyToLock notification.
+ //
+ Status = mBootScriptSmst->SmmRegisterProtocolNotify (
+ &gEfiSmmReadyToLockProtocolGuid,
+ S3BootScriptSmmEventCallBack,
+ &mRegistrationSmmReadyToLock
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return RETURN_SUCCESS;
+}
+
+/**
+ Library Destructor to free the resources allocated by
+ S3BootScriptLibInitialize() and unregister callbacks.
+
+ NOTICE: The destructor doesn't support unloading as a separate action, and it
+ only supports unloading if the containing driver's entry point function fails.
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval RETURN_SUCCESS The destructor always returns RETURN_SUCCESS.
+
+**/
+RETURN_STATUS
+EFIAPI
+S3BootScriptLibDeinitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ DEBUG ((EFI_D_INFO, "%a() in %a module\n", __FUNCTION__, gEfiCallerBaseName));
+
+ if (mEventDxeSmmReadyToLock != NULL) {
+ //
+ // Close the DxeSmmReadyToLock event.
+ //
+ Status = gBS->CloseEvent (mEventDxeSmmReadyToLock);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ if (mBootScriptSmst != NULL) {
+ if (mRegistrationSmmExitBootServices != NULL) {
+ //
+ // Unregister SmmExitBootServices notification.
+ //
+ Status = mBootScriptSmst->SmmRegisterProtocolNotify (
+ &gEdkiiSmmExitBootServicesProtocolGuid,
+ NULL,
+ &mRegistrationSmmExitBootServices
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+ if (mRegistrationSmmLegacyBoot != NULL) {
+ //
+ // Unregister SmmLegacyBoot notification.
+ //
+ Status = mBootScriptSmst->SmmRegisterProtocolNotify (
+ &gEdkiiSmmLegacyBootProtocolGuid,
+ NULL,
+ &mRegistrationSmmLegacyBoot
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+ if (mRegistrationSmmReadyToLock != NULL) {
+ //
+ // Unregister SmmReadyToLock notification.
+ //
+ Status = mBootScriptSmst->SmmRegisterProtocolNotify (
+ &gEfiSmmReadyToLockProtocolGuid,
+ NULL,
+ &mRegistrationSmmReadyToLock
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+ }
+
+ //
+ // Free the resources allocated and set PCDs to 0.
+ //
+ if (mS3BootScriptTableAllocated) {
+ Status = gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) mS3BootScriptTablePtr, EFI_SIZE_TO_PAGES(sizeof(SCRIPT_TABLE_PRIVATE_DATA)));
+ ASSERT_EFI_ERROR (Status);
+ Status = PcdSet64S (PcdS3BootScriptTablePrivateDataPtr, 0);
+ ASSERT_EFI_ERROR (Status);
+ }
+ if ((mBootScriptSmst != NULL) && mS3BootScriptTableSmmAllocated) {
+ Status = mBootScriptSmst->SmmFreePool (mS3BootScriptTableSmmPtr);
+ ASSERT_EFI_ERROR (Status);
+ Status = PcdSet64S (PcdS3BootScriptTablePrivateSmmDataPtr, 0);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ return RETURN_SUCCESS;
+}
+
+/**
+ To get the start address from which a new boot time s3 boot script entry will write into.
+ If the table is not exist, the functio will first allocate a buffer for the table
+ If the table buffer is not enough for the new entry, in non-smm mode, the funtion will
+ invoke reallocate to enlarge buffer.
+
+ @param EntryLength the new entry length.
+
+ @retval the address from which the a new s3 boot script entry will write into
+ **/
+UINT8*
+S3BootScriptGetBootTimeEntryAddAddress (
+ UINT8 EntryLength
+ )
+{
+ EFI_PHYSICAL_ADDRESS S3TableBase;
+ EFI_PHYSICAL_ADDRESS NewS3TableBase;
+ UINT8 *NewEntryPtr;
+ UINT32 TableLength;
+ UINT16 PageNumber;
+ EFI_STATUS Status;
+ EFI_BOOT_SCRIPT_TABLE_HEADER *ScriptTableInfo;
+
+ S3TableBase = (EFI_PHYSICAL_ADDRESS)(UINTN)(mS3BootScriptTablePtr->TableBase);
+ if (S3TableBase == 0) {
+ //
+ // The table is not exist. This is the first to add entry.
+ // Allocate ACPI script table space under 4G memory.
+ //
+ S3TableBase = 0xffffffff;
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiReservedMemoryType,
+ 2 + PcdGet16(PcdS3BootScriptRuntimeTableReservePageNumber),
+ (EFI_PHYSICAL_ADDRESS*)&S3TableBase
+ );
+
+ if (EFI_ERROR(Status)) {
+ ASSERT_EFI_ERROR (Status);
+ return 0;
+ }
+ //
+ // Fill Table Header
+ //
+ ScriptTableInfo = (EFI_BOOT_SCRIPT_TABLE_HEADER*)(UINTN)S3TableBase;
+ ScriptTableInfo->OpCode = S3_BOOT_SCRIPT_LIB_TABLE_OPCODE;
+ ScriptTableInfo->Length = (UINT8) sizeof (EFI_BOOT_SCRIPT_TABLE_HEADER);
+ ScriptTableInfo->Version = BOOT_SCRIPT_TABLE_VERSION;
+ ScriptTableInfo->TableLength = 0; // will be calculate at CloseTable
+ mS3BootScriptTablePtr->TableLength = sizeof (EFI_BOOT_SCRIPT_TABLE_HEADER);
+ mS3BootScriptTablePtr->TableBase = (UINT8*)(UINTN)S3TableBase;
+ mS3BootScriptTablePtr->TableMemoryPageNumber = (UINT16)(2 + PcdGet16(PcdS3BootScriptRuntimeTableReservePageNumber));
+ }
+
+ // Here we do not count the reserved memory for runtime script table.
+ PageNumber = (UINT16) (mS3BootScriptTablePtr->TableMemoryPageNumber - PcdGet16(PcdS3BootScriptRuntimeTableReservePageNumber));
+ TableLength = mS3BootScriptTablePtr->TableLength;
+ if ((UINTN) EFI_PAGES_TO_SIZE ((UINTN) PageNumber) < (UINTN) (TableLength + EntryLength + sizeof (EFI_BOOT_SCRIPT_TERMINATE))) {
+ //
+ // The buffer is too small to hold the table, Reallocate the buffer
+ //
+ NewS3TableBase = 0xffffffff;
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiReservedMemoryType,
+ 2 + PageNumber + PcdGet16(PcdS3BootScriptRuntimeTableReservePageNumber),
+ (EFI_PHYSICAL_ADDRESS*)&NewS3TableBase
+ );
+
+ if (EFI_ERROR(Status)) {
+ ASSERT_EFI_ERROR (Status);
+ return 0;
+ }
+
+ CopyMem ((VOID*)(UINTN)NewS3TableBase, (VOID*)(UINTN)S3TableBase, TableLength);
+ gBS->FreePages (S3TableBase, mS3BootScriptTablePtr->TableMemoryPageNumber);
+
+ mS3BootScriptTablePtr->TableBase = (UINT8*)(UINTN)NewS3TableBase;
+ mS3BootScriptTablePtr->TableMemoryPageNumber = (UINT16) (2 + PageNumber + PcdGet16(PcdS3BootScriptRuntimeTableReservePageNumber));
+ }
+ //
+ // calculate the the start address for the new entry.
+ //
+ NewEntryPtr = mS3BootScriptTablePtr->TableBase + TableLength;
+
+ //
+ // update the table lenghth
+ //
+ mS3BootScriptTablePtr->TableLength = TableLength + EntryLength;
+
+ //
+ // In the boot time, we will not append the termination entry to the boot script
+ // table until the callers think there is no boot time data that should be added and
+ // it is caller's responsibility to explicit call the CloseTable.
+ //
+ //
+
+ return NewEntryPtr;
+}
+/**
+ To get the start address from which a new runtime(after SmmReadyToLock) s3 boot script entry will write into.
+ In this case, it should be ensured that there is enough buffer to hold the entry.
+
+ @param EntryLength the new entry length.
+
+ @retval the address from which the a new s3 runtime(after SmmReadyToLock) script entry will write into
+ **/
+UINT8*
+S3BootScriptGetRuntimeEntryAddAddress (
+ UINT8 EntryLength
+ )
+{
+ UINT8 *NewEntryPtr;
+
+ NewEntryPtr = NULL;
+ //
+ // Check if the memory range reserved for S3 Boot Script table is large enough to hold the node.
+ //
+ if ((UINTN) (mS3BootScriptTablePtr->TableLength + EntryLength + sizeof (EFI_BOOT_SCRIPT_TERMINATE)) <= (UINTN) EFI_PAGES_TO_SIZE ((UINTN) (mS3BootScriptTablePtr->TableMemoryPageNumber))) {
+ NewEntryPtr = mS3BootScriptTablePtr->TableBase + mS3BootScriptTablePtr->TableLength;
+ mS3BootScriptTablePtr->TableLength = mS3BootScriptTablePtr->TableLength + EntryLength;
+ //
+ // Append a terminate node on every insert
+ //
+ S3BootScriptInternalCloseTable ();
+ }
+ return (UINT8*)NewEntryPtr;
+}
+
+/**
+ This function is to restore boot time boot script data from LockBox.
+
+**/
+VOID
+RestoreBootTimeDataFromLockBox (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN LockBoxLength;
+
+ //
+ // Restore boot time boot script data from LockBox.
+ //
+ LockBoxLength = mS3BootScriptTablePtr->BootTimeScriptLength;
+ Status = RestoreLockBox (
+ &mBootScriptDataBootTimeGuid,
+ (VOID *) mS3BootScriptTablePtr->TableBase,
+ &LockBoxLength
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Update the data to BootScriptData LockBox.
+ //
+ Status = UpdateLockBox (
+ &mBootScriptDataGuid,
+ 0,
+ (VOID *) mS3BootScriptTablePtr->TableBase,
+ LockBoxLength
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Update TableLength.
+ //
+ mS3BootScriptTablePtr->TableLength = (UINT32) (mS3BootScriptTablePtr->BootTimeScriptLength - sizeof (EFI_BOOT_SCRIPT_TERMINATE));
+}
+
+/**
+ To get the start address from which a new s3 boot script entry will write into.
+
+ @param EntryLength the new entry length.
+
+ @retval the address from which the a new s3 boot script entry will write into
+ **/
+UINT8*
+S3BootScriptGetEntryAddAddress (
+ UINT8 EntryLength
+ )
+{
+ UINT8* NewEntryPtr;
+
+ if (mS3BootScriptTablePtr->SmmLocked) {
+ //
+ // We need check InSmm, because after SmmReadyToLock, only SMM driver is allowed to write boot script.
+ //
+ if (!mS3BootScriptTablePtr->InSmm) {
+ //
+ // Add DEBUG ERROR, so that we can find it after SmmReadyToLock.
+ // Do not use ASSERT, because we may have test to invoke this interface.
+ //
+ DEBUG ((EFI_D_ERROR, "FATAL ERROR: Set boot script outside SMM after SmmReadyToLock!!!\n"));
+ return NULL;
+ }
+
+ if (mS3BootScriptTablePtr->BackFromS3) {
+ //
+ // Back from S3, restore boot time boot script data from LockBox
+ // and set BackFromS3 flag back to FALSE.
+ //
+ RestoreBootTimeDataFromLockBox ();
+ mS3BootScriptTablePtr->BackFromS3 = FALSE;
+ }
+
+ NewEntryPtr = S3BootScriptGetRuntimeEntryAddAddress (EntryLength);
+ } else {
+ NewEntryPtr = S3BootScriptGetBootTimeEntryAddAddress (EntryLength);
+ }
+ return NewEntryPtr;
+
+}
+
+/**
+ Sync BootScript LockBox data.
+
+ @param Script The address from where the boot script has been added or updated.
+
+**/
+VOID
+SyncBootScript (
+ IN UINT8 *Script
+ )
+{
+ EFI_STATUS Status;
+ UINT32 ScriptOffset;
+ UINT32 TotalScriptLength;
+
+ if (!mS3BootScriptTablePtr->SmmLocked || !mS3BootScriptTablePtr->InSmm) {
+ //
+ // If it is not after SmmReadyToLock in SMM,
+ // just return.
+ //
+ return ;
+ }
+
+ ScriptOffset = (UINT32) (Script - mS3BootScriptTablePtr->TableBase);
+
+ TotalScriptLength = (UINT32) (mS3BootScriptTablePtr->TableLength + sizeof (EFI_BOOT_SCRIPT_TERMINATE));
+
+ //
+ // Update BootScriptData
+ // So in S3 resume, the data can be restored correctly.
+ //
+ Status = UpdateLockBox (
+ &mBootScriptDataGuid,
+ ScriptOffset,
+ (VOID *)((UINTN)mS3BootScriptTablePtr->TableBase + ScriptOffset),
+ TotalScriptLength - ScriptOffset
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Now the length field is updated, need sync to lockbox.
+ // So at S3 resume, the data can be restored correctly.
+ //
+ Status = UpdateLockBox (
+ &mBootScriptDataGuid,
+ OFFSET_OF (EFI_BOOT_SCRIPT_TABLE_HEADER, TableLength),
+ &TotalScriptLength,
+ sizeof (TotalScriptLength)
+ );
+ ASSERT_EFI_ERROR (Status);
+}
+
+/**
+ This is an function to close the S3 boot script table. The function could only be called in
+ BOOT time phase. To comply with the Framework spec definition on
+ EFI_BOOT_SCRIPT_SAVE_PROTOCOL.CloseTable(), this function will fulfill following things:
+ 1. Closes the specified boot script table
+ 2. It allocates a new memory pool to duplicate all the boot scripts in the specified table.
+ Once this function is called, the table maintained by the library will be destroyed
+ after it is copied into the allocated pool.
+ 3. Any attempts to add a script record after calling this function will cause a new table
+ to be created by the library.
+ 4. The base address of the allocated pool will be returned in Address. Note that after
+ using the boot script table, the CALLER is responsible for freeing the pool that is allocated
+ by this function.
+
+ In Spec PI1.1, this EFI_BOOT_SCRIPT_SAVE_PROTOCOL.CloseTable() is retired. To provides this API for now is
+ for Framework Spec compatibility.
+
+ If anyone does call CloseTable() on a real platform, then the caller is responsible for figuring out
+ how to get the script to run at S3 resume because the boot script maintained by the lib will be
+ destroyed.
+
+ @return the base address of the new copy of the boot script table.
+ @note this function could only called in boot time phase
+
+**/
+UINT8*
+EFIAPI
+S3BootScriptCloseTable (
+ VOID
+ )
+{
+ UINT8 *S3TableBase;
+ UINT32 TableLength;
+ UINT8 *Buffer;
+ EFI_STATUS Status;
+ EFI_BOOT_SCRIPT_TABLE_HEADER *ScriptTableInfo;
+
+ S3TableBase = mS3BootScriptTablePtr->TableBase;
+ if (S3TableBase == 0) {
+ return 0;
+ }
+ //
+ // Append the termination record the S3 boot script table
+ //
+ S3BootScriptInternalCloseTable();
+ TableLength = mS3BootScriptTablePtr->TableLength + sizeof (EFI_BOOT_SCRIPT_TERMINATE);
+ //
+ // Allocate the buffer and copy the boot script to the buffer.
+ //
+ Status = gBS->AllocatePool (
+ EfiBootServicesData,
+ (UINTN)TableLength,
+ (VOID **) &Buffer
+ );
+ if (EFI_ERROR (Status)) {
+ return 0;
+ }
+ CopyMem (Buffer, S3TableBase, TableLength);
+
+ //
+ // Destroy the table maintained by the library so that the next write operation
+ // will write the record to the first entry of the table.
+ //
+ // Fill the table header.
+ ScriptTableInfo = (EFI_BOOT_SCRIPT_TABLE_HEADER*)S3TableBase;
+ ScriptTableInfo->OpCode = S3_BOOT_SCRIPT_LIB_TABLE_OPCODE;
+ ScriptTableInfo->Length = (UINT8) sizeof (EFI_BOOT_SCRIPT_TABLE_HEADER);
+ ScriptTableInfo->TableLength = 0; // will be calculate at close the table
+
+ mS3BootScriptTablePtr->TableLength = sizeof (EFI_BOOT_SCRIPT_TABLE_HEADER);
+ return Buffer;
+}
+/**
+ Save I/O write to boot script
+
+ @param Width The width of the I/O operations.Enumerated in S3_BOOT_SCRIPT_LIB_WIDTH.
+ @param Address The base address of the I/O operations.
+ @param Count The number of I/O operations to perform.
+ @param Buffer The source buffer from which to write data.
+
+ @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.
+ @retval RETURN_SUCCESS Opcode is added.
+**/
+RETURN_STATUS
+EFIAPI
+S3BootScriptSaveIoWrite (
+ IN S3_BOOT_SCRIPT_LIB_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN VOID *Buffer
+ )
+
+{
+ UINT8 Length;
+ UINT8 *Script;
+ UINT8 WidthInByte;
+ EFI_BOOT_SCRIPT_IO_WRITE ScriptIoWrite;
+
+ WidthInByte = (UINT8) (0x01 << (Width & 0x03));
+ Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_IO_WRITE) + (WidthInByte * Count));
+
+ Script = S3BootScriptGetEntryAddAddress (Length);
+ if (Script == NULL) {
+ return RETURN_OUT_OF_RESOURCES;
+ }
+ //
+ // save script data
+ //
+ ScriptIoWrite.OpCode = EFI_BOOT_SCRIPT_IO_WRITE_OPCODE;
+ ScriptIoWrite.Length = Length;
+ ScriptIoWrite.Width = Width;
+ ScriptIoWrite.Address = Address;
+ ScriptIoWrite.Count = (UINT32) Count;
+ CopyMem ((VOID*)Script, (VOID*)&ScriptIoWrite, sizeof(EFI_BOOT_SCRIPT_IO_WRITE));
+ CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_IO_WRITE)), Buffer, WidthInByte * Count);
+
+ SyncBootScript (Script);
+
+ return RETURN_SUCCESS;
+}
+
+/**
+ Adds a record for an I/O modify operation into a S3 boot script table
+
+ @param Width The width of the I/O operations.Enumerated in S3_BOOT_SCRIPT_LIB_WIDTH.
+ @param Address The base address of the I/O operations.
+ @param Data A pointer to the data to be OR-ed.
+ @param DataMask A pointer to the data mask to be AND-ed with the data read from the register
+
+ @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.
+ @retval RETURN_SUCCESS Opcode is added.
+**/
+RETURN_STATUS
+EFIAPI
+S3BootScriptSaveIoReadWrite (
+ IN S3_BOOT_SCRIPT_LIB_WIDTH Width,
+ IN UINT64 Address,
+ IN VOID *Data,
+ IN VOID *DataMask
+ )
+{
+ UINT8 Length;
+ UINT8 *Script;
+ UINT8 WidthInByte;
+ EFI_BOOT_SCRIPT_IO_READ_WRITE ScriptIoReadWrite;
+
+ WidthInByte = (UINT8) (0x01 << (Width & 0x03));
+ Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_IO_READ_WRITE) + (WidthInByte * 2));
+
+ Script = S3BootScriptGetEntryAddAddress (Length);
+ if (Script == NULL) {
+ return RETURN_OUT_OF_RESOURCES;
+ }
+ //
+ // Build script data
+ //
+ ScriptIoReadWrite.OpCode = EFI_BOOT_SCRIPT_IO_READ_WRITE_OPCODE;
+ ScriptIoReadWrite.Length = Length;
+ ScriptIoReadWrite.Width = Width;
+ ScriptIoReadWrite.Address = Address;
+
+ CopyMem ((VOID*)Script, (VOID*)&ScriptIoReadWrite, sizeof(EFI_BOOT_SCRIPT_IO_READ_WRITE));
+ CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_IO_READ_WRITE)), Data, WidthInByte);
+ CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_IO_READ_WRITE) + WidthInByte), DataMask, WidthInByte);
+
+ SyncBootScript (Script);
+
+ return RETURN_SUCCESS;
+}
+/**
+ Adds a record for a memory write operation into a specified boot script table.
+
+ @param Width The width of the I/O operations.Enumerated in S3_BOOT_SCRIPT_LIB_WIDTH.
+ @param Address The base address of the memory operations
+ @param Count The number of memory operations to perform.
+ @param Buffer The source buffer from which to write the data.
+
+ @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.
+ @retval RETURN_SUCCESS Opcode is added.
+**/
+RETURN_STATUS
+EFIAPI
+S3BootScriptSaveMemWrite (
+ IN S3_BOOT_SCRIPT_LIB_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN VOID *Buffer
+ )
+{
+ UINT8 Length;
+ UINT8 *Script;
+ UINT8 WidthInByte;
+ EFI_BOOT_SCRIPT_MEM_WRITE ScriptMemWrite;
+
+ WidthInByte = (UINT8) (0x01 << (Width & 0x03));
+ Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_MEM_WRITE) + (WidthInByte * Count));
+
+ Script = S3BootScriptGetEntryAddAddress (Length);
+ if (Script == NULL) {
+ return RETURN_OUT_OF_RESOURCES;
+ }
+ //
+ // Build script data
+ //
+ ScriptMemWrite.OpCode = EFI_BOOT_SCRIPT_MEM_WRITE_OPCODE;
+ ScriptMemWrite.Length = Length;
+ ScriptMemWrite.Width = Width;
+ ScriptMemWrite.Address = Address;
+ ScriptMemWrite.Count = (UINT32) Count;
+
+ CopyMem ((VOID*)Script, (VOID*)&ScriptMemWrite, sizeof(EFI_BOOT_SCRIPT_MEM_WRITE));
+ CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_MEM_WRITE)), Buffer, WidthInByte * Count);
+
+ SyncBootScript (Script);
+
+ return RETURN_SUCCESS;
+}
+/**
+ Adds a record for a memory modify operation into a specified boot script table.
+
+ @param Width The width of the I/O operations.Enumerated in S3_BOOT_SCRIPT_LIB_WIDTH.
+ @param Address The base address of the memory operations. Address needs alignment if required
+ @param Data A pointer to the data to be OR-ed.
+ @param DataMask A pointer to the data mask to be AND-ed with the data read from the register.
+
+ @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.
+ @retval RETURN_SUCCESS Opcode is added.
+**/
+RETURN_STATUS
+EFIAPI
+S3BootScriptSaveMemReadWrite (
+ IN S3_BOOT_SCRIPT_LIB_WIDTH Width,
+ IN UINT64 Address,
+ IN VOID *Data,
+ IN VOID *DataMask
+ )
+{
+ UINT8 Length;
+ UINT8 *Script;
+ UINT8 WidthInByte;
+ EFI_BOOT_SCRIPT_MEM_READ_WRITE ScriptMemReadWrite;
+
+ WidthInByte = (UINT8) (0x01 << (Width & 0x03));
+ Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_MEM_READ_WRITE) + (WidthInByte * 2));
+
+ Script = S3BootScriptGetEntryAddAddress (Length);
+ if (Script == NULL) {
+ return RETURN_OUT_OF_RESOURCES;
+ }
+ //
+ // Build script data
+ //
+ ScriptMemReadWrite.OpCode = EFI_BOOT_SCRIPT_MEM_READ_WRITE_OPCODE;
+ ScriptMemReadWrite.Length = Length;
+ ScriptMemReadWrite.Width = Width;
+ ScriptMemReadWrite.Address = Address;
+
+ CopyMem ((VOID*)Script, (VOID*)&ScriptMemReadWrite , sizeof (EFI_BOOT_SCRIPT_MEM_READ_WRITE));
+ CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_MEM_READ_WRITE)), Data, WidthInByte);
+ CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_MEM_READ_WRITE) + WidthInByte), DataMask, WidthInByte);
+
+ SyncBootScript (Script);
+
+ return RETURN_SUCCESS;
+}
+/**
+ Adds a record for a PCI configuration space write operation into a specified boot script table.
+
+ @param Width The width of the I/O operations.Enumerated in S3_BOOT_SCRIPT_LIB_WIDTH.
+ @param Address The address within the PCI configuration space.
+ @param Count The number of PCI operations to perform.
+ @param Buffer The source buffer from which to write the data.
+
+ @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.
+ @retval RETURN_SUCCESS Opcode is added.
+ @note A known Limitations in the implementation which is 64bits operations are not supported.
+
+**/
+RETURN_STATUS
+EFIAPI
+S3BootScriptSavePciCfgWrite (
+ IN S3_BOOT_SCRIPT_LIB_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN VOID *Buffer
+ )
+{
+ UINT8 Length;
+ UINT8 *Script;
+ UINT8 WidthInByte;
+ EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE ScriptPciWrite;
+
+ if (Width == S3BootScriptWidthUint64 ||
+ Width == S3BootScriptWidthFifoUint64 ||
+ Width == S3BootScriptWidthFillUint64) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ WidthInByte = (UINT8) (0x01 << (Width & 0x03));
+ Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE) + (WidthInByte * Count));
+
+ Script = S3BootScriptGetEntryAddAddress (Length);
+ if (Script == NULL) {
+ return RETURN_OUT_OF_RESOURCES;
+ }
+ //
+ // Build script data
+ //
+ ScriptPciWrite.OpCode = EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE_OPCODE;
+ ScriptPciWrite.Length = Length;
+ ScriptPciWrite.Width = Width;
+ ScriptPciWrite.Address = Address;
+ ScriptPciWrite.Count = (UINT32) Count;
+
+ CopyMem ((VOID*)Script, (VOID*)&ScriptPciWrite, sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE));
+ CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE)), Buffer, WidthInByte * Count);
+
+ SyncBootScript (Script);
+
+ return RETURN_SUCCESS;
+}
+/**
+ Adds a record for a PCI configuration space modify operation into a specified boot script table.
+
+ @param Width The width of the I/O operations.Enumerated in S3_BOOT_SCRIPT_LIB_WIDTH.
+ @param Address The address within the PCI configuration space.
+ @param Data A pointer to the data to be OR-ed.The size depends on Width.
+ @param DataMask A pointer to the data mask to be AND-ed.
+
+ @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.
+ @retval RETURN__SUCCESS Opcode is added.
+ @note A known Limitations in the implementation which is 64bits operations are not supported.
+
+**/
+RETURN_STATUS
+EFIAPI
+S3BootScriptSavePciCfgReadWrite (
+ IN S3_BOOT_SCRIPT_LIB_WIDTH Width,
+ IN UINT64 Address,
+ IN VOID *Data,
+ IN VOID *DataMask
+ )
+{
+ UINT8 Length;
+ UINT8 *Script;
+ UINT8 WidthInByte;
+ EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE ScriptPciReadWrite;
+
+ if (Width == S3BootScriptWidthUint64 ||
+ Width == S3BootScriptWidthFifoUint64 ||
+ Width == S3BootScriptWidthFillUint64) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ WidthInByte = (UINT8) (0x01 << (Width & 0x03));
+ Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE) + (WidthInByte * 2));
+
+ Script = S3BootScriptGetEntryAddAddress (Length);
+ if (Script == NULL) {
+ return RETURN_OUT_OF_RESOURCES;
+ }
+ //
+ // Build script data
+ //
+ ScriptPciReadWrite.OpCode = EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE_OPCODE;
+ ScriptPciReadWrite.Length = Length;
+ ScriptPciReadWrite.Width = Width;
+ ScriptPciReadWrite.Address = Address;
+
+ CopyMem ((VOID*)Script, (VOID*)&ScriptPciReadWrite, sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE));
+ CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE)), Data, WidthInByte);
+ CopyMem (
+ (VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE) + WidthInByte),
+ DataMask,
+ WidthInByte
+ );
+
+ SyncBootScript (Script);
+
+ return RETURN_SUCCESS;
+}
+/**
+ Adds a record for a PCI configuration 2 space write operation into a specified boot script table.
+
+ @param Width The width of the I/O operations.Enumerated in S3_BOOT_SCRIPT_LIB_WIDTH.
+ @param Segment The PCI segment number for Address.
+ @param Address The address within the PCI configuration space.
+ @param Count The number of PCI operations to perform.
+ @param Buffer The source buffer from which to write the data.
+
+ @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.
+ @retval RETURN_SUCCESS Opcode is added.
+ @note A known Limitations in the implementation which is non-zero Segment and 64bits operations are not supported.
+
+**/
+RETURN_STATUS
+EFIAPI
+S3BootScriptSavePciCfg2Write (
+ IN S3_BOOT_SCRIPT_LIB_WIDTH Width,
+ IN UINT16 Segment,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN VOID *Buffer
+ )
+{
+ UINT8 Length;
+ UINT8 *Script;
+ UINT8 WidthInByte;
+ EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE ScriptPciWrite2;
+
+ if (Segment != 0 ||
+ Width == S3BootScriptWidthUint64 ||
+ Width == S3BootScriptWidthFifoUint64 ||
+ Width == S3BootScriptWidthFillUint64) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ WidthInByte = (UINT8) (0x01 << (Width & 0x03));
+ Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE) + (WidthInByte * Count));
+
+ Script = S3BootScriptGetEntryAddAddress (Length);
+ if (Script == NULL) {
+ return RETURN_OUT_OF_RESOURCES;
+ }
+ //
+ // Build script data
+ //
+ ScriptPciWrite2.OpCode = EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE_OPCODE;
+ ScriptPciWrite2.Length = Length;
+ ScriptPciWrite2.Width = Width;
+ ScriptPciWrite2.Address = Address;
+ ScriptPciWrite2.Segment = Segment;
+ ScriptPciWrite2.Count = (UINT32)Count;
+
+ CopyMem ((VOID*)Script, (VOID*)&ScriptPciWrite2, sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE));
+ CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_WRITE)), Buffer, WidthInByte * Count);
+
+ SyncBootScript (Script);
+
+ return RETURN_SUCCESS;
+}
+/**
+ Adds a record for a PCI configuration 2 space modify operation into a specified boot script table.
+
+ @param Width The width of the I/O operations.Enumerated in S3_BOOT_SCRIPT_LIB_WIDTH.
+ @param Segment The PCI segment number for Address.
+ @param Address The address within the PCI configuration space.
+ @param Data A pointer to the data to be OR-ed. The size depends on Width.
+ @param DataMask A pointer to the data mask to be AND-ed.
+
+ @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.
+ @retval RETURN_SUCCESS Opcode is added.
+ @note A known Limitations in the implementation which is non-zero Segment and 64bits operations are not supported.
+
+**/
+RETURN_STATUS
+EFIAPI
+S3BootScriptSavePciCfg2ReadWrite (
+ IN S3_BOOT_SCRIPT_LIB_WIDTH Width,
+ IN UINT16 Segment,
+ IN UINT64 Address,
+ IN VOID *Data,
+ IN VOID *DataMask
+ )
+{
+ UINT8 Length;
+ UINT8 *Script;
+ UINT8 WidthInByte;
+ EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE ScriptPciReadWrite2;
+
+ if (Segment != 0 ||
+ Width == S3BootScriptWidthUint64 ||
+ Width == S3BootScriptWidthFifoUint64 ||
+ Width == S3BootScriptWidthFillUint64) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ WidthInByte = (UINT8) (0x01 << (Width & 0x03));
+ Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE) + (WidthInByte * 2));
+
+ Script = S3BootScriptGetEntryAddAddress (Length);
+ if (Script == NULL) {
+ return RETURN_OUT_OF_RESOURCES;
+ }
+ //
+ // Build script data
+ //
+ ScriptPciReadWrite2.OpCode = EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE_OPCODE;
+ ScriptPciReadWrite2.Length = Length;
+ ScriptPciReadWrite2.Width = Width;
+ ScriptPciReadWrite2.Segment = Segment;
+ ScriptPciReadWrite2.Address = Address;
+
+ CopyMem ((VOID*)Script, (VOID*)&ScriptPciReadWrite2, sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE));
+ CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE)), Data, WidthInByte);
+ CopyMem (
+ (VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_READ_WRITE) + WidthInByte),
+ DataMask,
+ WidthInByte
+ );
+
+ SyncBootScript (Script);
+
+ return RETURN_SUCCESS;
+}
+
+/**
+ Checks the parameter of S3BootScriptSaveSmbusExecute().
+
+ This function checks the input parameters of SmbusExecute(). If the input parameters are valid
+ for certain SMBus bus protocol, it will return EFI_SUCCESS; otherwise, it will return certain
+ error code based on the input SMBus bus protocol.
+
+ @param SmBusAddress Address that encodes the SMBUS Slave Address, SMBUS Command, SMBUS Data Length,
+ and PEC.
+ @param Operation Signifies which particular SMBus hardware protocol instance that
+ it will use to execute the SMBus transactions. This SMBus
+ hardware protocol is defined by the SMBus Specification and is
+ not related to EFI.
+ @param Length Signifies the number of bytes that this operation will do. The
+ maximum number of bytes can be revision specific and operation
+ specific. This field will contain the actual number of bytes that
+ are executed for this operation. Not all operations require this
+ argument.
+ @param Buffer Contains the value of data to execute to the SMBus slave device.
+ Not all operations require this argument. The length of this
+ buffer is identified by Length.
+
+ @retval EFI_SUCCESS All the parameters are valid for the corresponding SMBus bus
+ protocol.
+ @retval EFI_INVALID_PARAMETER Operation is not defined in EFI_SMBUS_OPERATION.
+ @retval EFI_INVALID_PARAMETER Length/Buffer is NULL for operations except for EfiSmbusQuickRead
+ and EfiSmbusQuickWrite. Length is outside the range of valid
+ values.
+ @retval EFI_UNSUPPORTED The SMBus operation or PEC is not supported.
+ @retval EFI_BUFFER_TOO_SMALL Buffer is not sufficient for this operation.
+
+**/
+EFI_STATUS
+CheckParameters (
+ IN UINTN SmBusAddress,
+ IN EFI_SMBUS_OPERATION Operation,
+ IN OUT UINTN *Length,
+ IN VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ UINTN RequiredLen;
+ EFI_SMBUS_DEVICE_COMMAND Command;
+ BOOLEAN PecCheck;
+
+ Command = SMBUS_LIB_COMMAND (SmBusAddress);
+ PecCheck = SMBUS_LIB_PEC (SmBusAddress);
+ //
+ // Set default value to be 2:
+ // for SmbusReadWord, SmbusWriteWord and SmbusProcessCall.
+ //
+ RequiredLen = 2;
+ Status = EFI_SUCCESS;
+ switch (Operation) {
+ case EfiSmbusQuickRead:
+ case EfiSmbusQuickWrite:
+ if (PecCheck || Command != 0) {
+ return EFI_UNSUPPORTED;
+ }
+ break;
+ case EfiSmbusReceiveByte:
+ case EfiSmbusSendByte:
+ if (Command != 0) {
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Cascade to check length parameter.
+ //
+ case EfiSmbusReadByte:
+ case EfiSmbusWriteByte:
+ RequiredLen = 1;
+ //
+ // Cascade to check length parameter.
+ //
+ case EfiSmbusReadWord:
+ case EfiSmbusWriteWord:
+ case EfiSmbusProcessCall:
+ if (Buffer == NULL || Length == NULL) {
+ return EFI_INVALID_PARAMETER;
+ } else if (*Length < RequiredLen) {
+ Status = EFI_BUFFER_TOO_SMALL;
+ }
+ *Length = RequiredLen;
+ break;
+ case EfiSmbusReadBlock:
+ case EfiSmbusWriteBlock:
+ case EfiSmbusBWBRProcessCall:
+ if ((Buffer == NULL) ||
+ (Length == NULL) ||
+ (*Length < MIN_SMBUS_BLOCK_LEN) ||
+ (*Length > MAX_SMBUS_BLOCK_LEN)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ break;
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+ return Status;
+}
+
+/**
+ Adds a record for an SMBus command execution into a specified boot script table.
+
+ @param SmBusAddress Address that encodes the SMBUS Slave Address, SMBUS Command, SMBUS Data Length, and PEC.
+ @param Operation Indicates which particular SMBus protocol it will use to execute the SMBus
+ transactions.
+ @param Length A pointer to signify the number of bytes that this operation will do.
+ @param Buffer Contains the value of data to execute to the SMBUS slave device.
+
+ @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.
+ @retval RETURN_SUCCESS Opcode is added.
+**/
+RETURN_STATUS
+EFIAPI
+S3BootScriptSaveSmbusExecute (
+ IN UINTN SmBusAddress,
+ IN EFI_SMBUS_OPERATION Operation,
+ IN UINTN *Length,
+ IN VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ UINTN BufferLength;
+ UINT8 DataSize;
+ UINT8 *Script;
+ EFI_BOOT_SCRIPT_SMBUS_EXECUTE ScriptSmbusExecute;
+
+ if (Length == NULL) {
+ BufferLength = 0;
+ } else {
+ BufferLength = *Length;
+ }
+
+ Status = CheckParameters (SmBusAddress, Operation, &BufferLength, Buffer);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ DataSize = (UINT8)(sizeof (EFI_BOOT_SCRIPT_SMBUS_EXECUTE) + BufferLength);
+
+ Script = S3BootScriptGetEntryAddAddress (DataSize);
+ if (Script == NULL) {
+ return RETURN_OUT_OF_RESOURCES;
+ }
+ //
+ // Build script data
+ //
+ ScriptSmbusExecute.OpCode = EFI_BOOT_SCRIPT_SMBUS_EXECUTE_OPCODE;
+ ScriptSmbusExecute.Length = DataSize;
+ ScriptSmbusExecute.SmBusAddress = (UINT64) SmBusAddress;
+ ScriptSmbusExecute.Operation = Operation;
+ ScriptSmbusExecute.DataSize = (UINT32) BufferLength;
+
+ CopyMem ((VOID*)Script, (VOID*)&ScriptSmbusExecute, sizeof (EFI_BOOT_SCRIPT_SMBUS_EXECUTE));
+ CopyMem (
+ (VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_SMBUS_EXECUTE)),
+ Buffer,
+ BufferLength
+ );
+
+ SyncBootScript (Script);
+
+ return RETURN_SUCCESS;
+}
+/**
+ Adds a record for an execution stall on the processor into a specified boot script table.
+
+ @param Duration Duration in microseconds of the stall
+
+ @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.
+ @retval RETURN_SUCCESS Opcode is added.
+**/
+RETURN_STATUS
+EFIAPI
+S3BootScriptSaveStall (
+ IN UINTN Duration
+ )
+{
+ UINT8 Length;
+ UINT8 *Script;
+ EFI_BOOT_SCRIPT_STALL ScriptStall;
+
+ Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_STALL));
+
+ Script = S3BootScriptGetEntryAddAddress (Length);
+ if (Script == NULL) {
+ return RETURN_OUT_OF_RESOURCES;
+ }
+ //
+ // Build script data
+ //
+ ScriptStall.OpCode = EFI_BOOT_SCRIPT_STALL_OPCODE;
+ ScriptStall.Length = Length;
+ ScriptStall.Duration = Duration;
+
+ CopyMem ((VOID*)Script, (VOID*)&ScriptStall, sizeof (EFI_BOOT_SCRIPT_STALL));
+
+ SyncBootScript (Script);
+
+ return RETURN_SUCCESS;
+}
+/**
+ Adds a record for dispatching specified arbitrary code into a specified boot script table.
+
+ @param EntryPoint Entry point of the code to be dispatched.
+ @param Context Argument to be passed into the EntryPoint of the code to be dispatched.
+
+ @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.
+ @retval RETURN_SUCCESS Opcode is added.
+**/
+RETURN_STATUS
+EFIAPI
+S3BootScriptSaveDispatch2 (
+ IN VOID *EntryPoint,
+ IN VOID *Context
+ )
+{
+ UINT8 Length;
+ UINT8 *Script;
+ EFI_BOOT_SCRIPT_DISPATCH_2 ScriptDispatch2;
+ Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_DISPATCH_2));
+
+ Script = S3BootScriptGetEntryAddAddress (Length);
+ if (Script == NULL) {
+ return RETURN_OUT_OF_RESOURCES;
+ }
+ //
+ // Build script data
+ //
+ ScriptDispatch2.OpCode = EFI_BOOT_SCRIPT_DISPATCH_2_OPCODE;
+ ScriptDispatch2.Length = Length;
+ ScriptDispatch2.EntryPoint = (EFI_PHYSICAL_ADDRESS)(UINTN)EntryPoint;
+ ScriptDispatch2.Context = (EFI_PHYSICAL_ADDRESS)(UINTN)Context;
+
+ CopyMem ((VOID*)Script, (VOID*)&ScriptDispatch2, sizeof (EFI_BOOT_SCRIPT_DISPATCH_2));
+
+ SyncBootScript (Script);
+
+ return RETURN_SUCCESS;
+
+}
+/**
+ Adds a record for memory reads of the memory location and continues when the exit criteria is
+ satisfied or after a defined duration.
+
+ Please aware, below interface is different with PI specification, Vol 5:
+ EFI_S3_SAVE_STATE_PROTOCOL.Write() for EFI_BOOT_SCRIPT_MEM_POLL_OPCODE.
+ "Duration" below is microseconds, while "Delay" in PI specification means
+ the number of 100ns units to poll.
+
+ @param Width The width of the memory operations.
+ @param Address The base address of the memory operations.
+ @param BitMask A pointer to the bit mask to be AND-ed with the data read from the register.
+ @param BitValue A pointer to the data value after to be Masked.
+ @param Duration Duration in microseconds of the stall.
+ @param LoopTimes The times of the register polling.
+
+ @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.
+ @retval RETURN_SUCCESS Opcode is added.
+
+**/
+RETURN_STATUS
+EFIAPI
+S3BootScriptSaveMemPoll (
+ IN S3_BOOT_SCRIPT_LIB_WIDTH Width,
+ IN UINT64 Address,
+ IN VOID *BitMask,
+ IN VOID *BitValue,
+ IN UINTN Duration,
+ IN UINTN LoopTimes
+ )
+{
+ UINT8 Length;
+ UINT8 *Script;
+ UINT8 WidthInByte;
+ EFI_BOOT_SCRIPT_MEM_POLL ScriptMemPoll;
+
+ WidthInByte = (UINT8) (0x01 << (Width & 0x03));
+
+ Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_MEM_POLL) + (WidthInByte * 2));
+
+ Script = S3BootScriptGetEntryAddAddress (Length);
+ if (Script == NULL) {
+ return RETURN_OUT_OF_RESOURCES;
+ }
+ //
+ // Build script data
+ //
+ ScriptMemPoll.OpCode = EFI_BOOT_SCRIPT_MEM_POLL_OPCODE;
+ ScriptMemPoll.Length = Length;
+ ScriptMemPoll.Width = Width;
+ ScriptMemPoll.Address = Address;
+ ScriptMemPoll.Duration = Duration;
+ ScriptMemPoll.LoopTimes = LoopTimes;
+
+ CopyMem ((UINT8 *) (Script + sizeof (EFI_BOOT_SCRIPT_MEM_POLL)), BitValue, WidthInByte);
+ CopyMem ((UINT8 *) (Script + sizeof (EFI_BOOT_SCRIPT_MEM_POLL) + WidthInByte), BitMask, WidthInByte);
+ CopyMem ((VOID*)Script, (VOID*)&ScriptMemPoll, sizeof (EFI_BOOT_SCRIPT_MEM_POLL));
+
+ SyncBootScript (Script);
+
+ return RETURN_SUCCESS;
+}
+/**
+ Store arbitrary information in the boot script table. This opcode is a no-op on dispatch and is only
+ used for debugging script issues.
+
+ @param InformationLength Length of the data in bytes
+ @param Information Information to be logged in the boot scrpit
+
+ @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.
+ @retval RETURN_SUCCESS Opcode is added.
+
+**/
+RETURN_STATUS
+EFIAPI
+S3BootScriptSaveInformation (
+ IN UINT32 InformationLength,
+ IN VOID *Information
+ )
+{
+ UINT8 Length;
+ UINT8 *Script;
+ EFI_BOOT_SCRIPT_INFORMATION ScriptInformation;
+
+ Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_INFORMATION) + InformationLength);
+
+ Script = S3BootScriptGetEntryAddAddress (Length);
+ if (Script == NULL) {
+ return RETURN_OUT_OF_RESOURCES;
+ }
+ //
+ // Build script data
+ //
+ ScriptInformation.OpCode = EFI_BOOT_SCRIPT_INFORMATION_OPCODE;
+ ScriptInformation.Length = Length;
+
+
+ ScriptInformation.InformationLength = InformationLength;
+
+ CopyMem ((VOID*)Script, (VOID*)&ScriptInformation, sizeof (EFI_BOOT_SCRIPT_INFORMATION));
+ CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_INFORMATION)), (VOID *) Information, (UINTN) InformationLength);
+
+ SyncBootScript (Script);
+
+ return RETURN_SUCCESS;
+
+}
+/**
+ Store a string in the boot script table. This opcode is a no-op on dispatch and is only
+ used for debugging script issues.
+
+ @param String The string to save to boot script table
+
+ @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.
+ @retval RETURN_SUCCESS Opcode is added.
+
+**/
+RETURN_STATUS
+EFIAPI
+S3BootScriptSaveInformationAsciiString (
+ IN CONST CHAR8 *String
+ )
+{
+ return S3BootScriptSaveInformation (
+ (UINT32) AsciiStrLen (String) + 1,
+ (VOID*) String
+ );
+}
+/**
+ Adds a record for dispatching specified arbitrary code into a specified boot script table.
+
+ @param EntryPoint Entry point of the code to be dispatched.
+
+ @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.
+ @retval RETURN_SUCCESS Opcode is added.
+**/
+RETURN_STATUS
+EFIAPI
+S3BootScriptSaveDispatch (
+ IN VOID *EntryPoint
+ )
+{
+ UINT8 Length;
+ UINT8 *Script;
+ EFI_BOOT_SCRIPT_DISPATCH ScriptDispatch;
+
+ Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_DISPATCH));
+
+ Script = S3BootScriptGetEntryAddAddress (Length);
+ if (Script == NULL) {
+ return RETURN_OUT_OF_RESOURCES;
+ }
+ //
+ // Build script data
+ //
+ ScriptDispatch.OpCode = EFI_BOOT_SCRIPT_DISPATCH_OPCODE;
+ ScriptDispatch.Length = Length;
+ ScriptDispatch.EntryPoint = (EFI_PHYSICAL_ADDRESS)(UINTN)EntryPoint;
+
+ CopyMem ((VOID*)Script, (VOID*)&ScriptDispatch, sizeof (EFI_BOOT_SCRIPT_DISPATCH));
+
+ SyncBootScript (Script);
+
+ return RETURN_SUCCESS;
+
+}
+/**
+ Adds a record for I/O reads the I/O location and continues when the exit criteria is satisfied or after a
+ defined duration.
+
+ @param Width The width of the I/O operations.
+ @param Address The base address of the I/O operations.
+ @param Data The comparison value used for the polling exit criteria.
+ @param DataMask Mask used for the polling criteria. The bits in the bytes below Width which are zero
+ in Data are ignored when polling the memory address.
+ @param Delay The number of 100ns units to poll. Note that timer available may be of poorer
+ granularity so the delay may be longer.
+
+ @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.
+ @retval RETURN_SUCCESS Opcode is added.
+
+**/
+RETURN_STATUS
+EFIAPI
+S3BootScriptSaveIoPoll (
+ IN S3_BOOT_SCRIPT_LIB_WIDTH Width,
+ IN UINT64 Address,
+ IN VOID *Data,
+ IN VOID *DataMask,
+ IN UINT64 Delay
+ )
+{
+ UINT8 WidthInByte;
+ UINT8 *Script;
+ UINT8 Length;
+ EFI_BOOT_SCRIPT_IO_POLL ScriptIoPoll;
+
+
+ WidthInByte = (UINT8) (0x01 << (Width & 0x03));
+ Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_IO_POLL) + (WidthInByte * 2));
+
+ Script = S3BootScriptGetEntryAddAddress (Length);
+ if (Script == NULL) {
+ return RETURN_OUT_OF_RESOURCES;
+ }
+ //
+ // Build script data
+ //
+ ScriptIoPoll.OpCode = EFI_BOOT_SCRIPT_IO_POLL_OPCODE;
+ ScriptIoPoll.Length = (UINT8) (sizeof (EFI_BOOT_SCRIPT_IO_POLL) + (WidthInByte * 2));
+ ScriptIoPoll.Width = Width;
+ ScriptIoPoll.Address = Address;
+ ScriptIoPoll.Delay = Delay;
+
+ CopyMem ((VOID*)Script, (VOID*)&ScriptIoPoll, sizeof (EFI_BOOT_SCRIPT_IO_POLL));
+ CopyMem ((UINT8 *) (Script + sizeof (EFI_BOOT_SCRIPT_IO_POLL)), Data, WidthInByte);
+ CopyMem ((UINT8 *) (Script + sizeof (EFI_BOOT_SCRIPT_IO_POLL) + WidthInByte), DataMask, WidthInByte);
+
+ SyncBootScript (Script);
+
+ return RETURN_SUCCESS;
+}
+
+/**
+ Adds a record for PCI configuration space reads and continues when the exit criteria is satisfied or
+ after a defined duration.
+
+ @param Width The width of the I/O operations.
+ @param Address The address within the PCI configuration space.
+ @param Data The comparison value used for the polling exit criteria.
+ @param DataMask Mask used for the polling criteria. The bits in the bytes below Width which are zero
+ in Data are ignored when polling the memory address
+ @param Delay The number of 100ns units to poll. Note that timer available may be of poorer
+ granularity so the delay may be longer.
+
+ @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.
+ @retval RETURN_SUCCESS Opcode is added.
+ @note A known Limitations in the implementation which is 64bits operations are not supported.
+
+**/
+RETURN_STATUS
+EFIAPI
+S3BootScriptSavePciPoll (
+ IN S3_BOOT_SCRIPT_LIB_WIDTH Width,
+ IN UINT64 Address,
+ IN VOID *Data,
+ IN VOID *DataMask,
+ IN UINT64 Delay
+)
+{
+ UINT8 *Script;
+ UINT8 WidthInByte;
+ UINT8 Length;
+ EFI_BOOT_SCRIPT_PCI_CONFIG_POLL ScriptPciPoll;
+
+ if (Width == S3BootScriptWidthUint64 ||
+ Width == S3BootScriptWidthFifoUint64 ||
+ Width == S3BootScriptWidthFillUint64) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ WidthInByte = (UINT8) (0x01 << (Width & 0x03));
+ Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_POLL) + (WidthInByte * 2));
+
+ Script = S3BootScriptGetEntryAddAddress (Length);
+ if (Script == NULL) {
+ return RETURN_OUT_OF_RESOURCES;
+ }
+ //
+ // Build script data
+ //
+ ScriptPciPoll.OpCode = EFI_BOOT_SCRIPT_PCI_CONFIG_POLL_OPCODE;
+ ScriptPciPoll.Length = (UINT8) (sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_POLL) + (WidthInByte * 2));
+ ScriptPciPoll.Width = Width;
+ ScriptPciPoll.Address = Address;
+ ScriptPciPoll.Delay = Delay;
+
+ CopyMem ((VOID*)Script, (VOID*)&ScriptPciPoll, sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_POLL));
+ CopyMem ((UINT8 *) (Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_POLL)), Data, WidthInByte);
+ CopyMem ((UINT8 *) (Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG_POLL) + WidthInByte), DataMask, WidthInByte);
+
+ SyncBootScript (Script);
+
+ return RETURN_SUCCESS;
+}
+/**
+ Adds a record for PCI configuration space reads and continues when the exit criteria is satisfied or
+ after a defined duration.
+
+ @param Width The width of the I/O operations.
+ @param Segment The PCI segment number for Address.
+ @param Address The address within the PCI configuration space.
+ @param Data The comparison value used for the polling exit criteria.
+ @param DataMask Mask used for the polling criteria. The bits in the bytes below Width which are zero
+ in Data are ignored when polling the memory address
+ @param Delay The number of 100ns units to poll. Note that timer available may be of poorer
+ granularity so the delay may be longer.
+
+ @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.
+ @retval RETURN_SUCCESS Opcode is added.
+ @note A known Limitations in the implementation which is non-zero Segment and 64bits operations are not supported.
+
+**/
+RETURN_STATUS
+EFIAPI
+S3BootScriptSavePci2Poll (
+ IN S3_BOOT_SCRIPT_LIB_WIDTH Width,
+ IN UINT16 Segment,
+ IN UINT64 Address,
+ IN VOID *Data,
+ IN VOID *DataMask,
+ IN UINT64 Delay
+)
+{
+ UINT8 WidthInByte;
+ UINT8 *Script;
+ UINT8 Length;
+ EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL ScriptPci2Poll;
+
+ if (Segment != 0 ||
+ Width == S3BootScriptWidthUint64 ||
+ Width == S3BootScriptWidthFifoUint64 ||
+ Width == S3BootScriptWidthFillUint64) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ WidthInByte = (UINT8) (0x01 << (Width & 0x03));
+ Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL) + (WidthInByte * 2));
+
+ Script = S3BootScriptGetEntryAddAddress (Length);
+ if (Script == NULL) {
+ return RETURN_OUT_OF_RESOURCES;
+ }
+ //
+ // Build script data
+ //
+ ScriptPci2Poll.OpCode = EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL_OPCODE;
+ ScriptPci2Poll.Length = (UINT8) (sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL) + (WidthInByte * 2));
+ ScriptPci2Poll.Width = Width;
+ ScriptPci2Poll.Segment = Segment;
+ ScriptPci2Poll.Address = Address;
+ ScriptPci2Poll.Delay = Delay;
+
+ CopyMem ((VOID*)Script, (VOID*)&ScriptPci2Poll, sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL));
+ CopyMem ((UINT8 *) (Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL)), Data, WidthInByte);
+ CopyMem ((UINT8 *) (Script + sizeof (EFI_BOOT_SCRIPT_PCI_CONFIG2_POLL) + WidthInByte), DataMask, WidthInByte);
+
+ SyncBootScript (Script);
+
+ return RETURN_SUCCESS;
+}
+/**
+ Do the calculation of start address from which a new s3 boot script entry will write into.
+
+ @param EntryLength The new entry length.
+ @param Position specifies the position in the boot script table where the opcode will be
+ inserted, either before or after, depending on BeforeOrAfter.
+ @param BeforeOrAfter The flag to indicate to insert the nod before or after the position.
+ This parameter is effective when InsertFlag is TRUE
+ @param Script return out the position from which the a new s3 boot script entry will write into
+**/
+VOID
+S3BootScriptCalculateInsertAddress (
+ IN UINT8 EntryLength,
+ IN VOID *Position OPTIONAL,
+ IN BOOLEAN BeforeOrAfter OPTIONAL,
+ OUT UINT8 **Script
+ )
+{
+ UINTN TableLength;
+ UINT8 *S3TableBase;
+ UINTN PositionOffset;
+ EFI_BOOT_SCRIPT_COMMON_HEADER ScriptHeader;
+ //
+ // The entry inserting to table is already added to the end of the table
+ //
+ TableLength = mS3BootScriptTablePtr->TableLength - EntryLength;
+ S3TableBase = mS3BootScriptTablePtr->TableBase ;
+ //
+ // calculate the Position offset
+ //
+ if (Position != NULL) {
+ PositionOffset = (UINTN) ((UINT8 *)Position - S3TableBase);
+
+ //
+ // If the BeforeOrAfter is FALSE, that means to insert the node right after the node.
+ //
+ if (!BeforeOrAfter) {
+ CopyMem ((VOID*)&ScriptHeader, Position, sizeof(EFI_BOOT_SCRIPT_COMMON_HEADER));
+ PositionOffset += (ScriptHeader.Length);
+ }
+ //
+ // Insert the node before the adjusted Position
+ //
+ CopyMem (S3TableBase+PositionOffset+EntryLength, S3TableBase+PositionOffset, TableLength - PositionOffset);
+ //
+ // calculate the the start address for the new entry.
+ //
+ *Script = S3TableBase + PositionOffset;
+
+ } else {
+ if (!BeforeOrAfter) {
+ //
+ // Insert the node to the end of the table
+ //
+ *Script = S3TableBase + TableLength;
+ } else {
+ //
+ // Insert the node to the beginning of the table
+ //
+ PositionOffset = (UINTN) sizeof(EFI_BOOT_SCRIPT_TABLE_HEADER);
+ CopyMem (S3TableBase+PositionOffset+EntryLength, S3TableBase+PositionOffset, TableLength - PositionOffset);
+ *Script = S3TableBase + PositionOffset;
+ }
+ }
+}
+/**
+ Move the last boot script entry to the position
+
+ @param BeforeOrAfter Specifies whether the opcode is stored before (TRUE) or after (FALSE) the position
+ in the boot script table specified by Position. If Position is NULL or points to
+ NULL then the new opcode is inserted at the beginning of the table (if TRUE) or end
+ of the table (if FALSE).
+ @param Position On entry, specifies the position in the boot script table where the opcode will be
+ inserted, either before or after, depending on BeforeOrAfter. On exit, specifies
+ the position of the inserted opcode in the boot script table.
+
+ @retval RETURN_OUT_OF_RESOURCES The table is not available.
+ @retval RETURN_INVALID_PARAMETER The Position is not a valid position in the boot script table.
+ @retval RETURN_SUCCESS Opcode is inserted.
+**/
+RETURN_STATUS
+EFIAPI
+S3BootScriptMoveLastOpcode (
+ IN BOOLEAN BeforeOrAfter,
+ IN OUT VOID **Position OPTIONAL
+)
+{
+ UINT8* Script;
+ VOID *TempPosition;
+ UINTN StartAddress;
+ UINT32 TableLength;
+ EFI_BOOT_SCRIPT_COMMON_HEADER ScriptHeader;
+ BOOLEAN ValidatePosition;
+ UINT8* LastOpcode;
+ UINT8 TempBootScriptEntry[BOOT_SCRIPT_NODE_MAX_LENGTH];
+
+ ValidatePosition = FALSE;
+ TempPosition = (Position == NULL) ? NULL:(*Position);
+
+ //
+ // Check that the script is initialized and synced without adding an entry to the script.
+ //
+ Script = S3BootScriptGetEntryAddAddress (0);
+ if (Script == NULL) {
+ return RETURN_OUT_OF_RESOURCES;
+ }
+ Script = mS3BootScriptTablePtr->TableBase;
+
+ StartAddress = (UINTN) Script;
+ TableLength = mS3BootScriptTablePtr->TableLength;
+ Script = Script + sizeof(EFI_BOOT_SCRIPT_TABLE_HEADER);
+ LastOpcode = Script;
+ //
+ // Find the last boot Script Entry which is not the terminate node
+ //
+ while ((UINTN) Script < (UINTN) (StartAddress + TableLength)) {
+ CopyMem ((VOID*)&ScriptHeader, Script, sizeof(EFI_BOOT_SCRIPT_COMMON_HEADER));
+ if (TempPosition != NULL && TempPosition == Script) {
+ //
+ // If the position is specified, the position must be pointed to a boot script entry start address.
+ //
+ ValidatePosition = TRUE;
+ }
+ if (ScriptHeader.OpCode != S3_BOOT_SCRIPT_LIB_TERMINATE_OPCODE) {
+ LastOpcode = Script;
+ }
+ Script = Script + ScriptHeader.Length;
+ }
+ //
+ // If the position is specified, but not the start of a boot script entry, it is a invalid input
+ //
+ if (TempPosition != NULL && !ValidatePosition) {
+ return RETURN_INVALID_PARAMETER;
+ }
+
+ CopyMem ((VOID*)&ScriptHeader, LastOpcode, sizeof(EFI_BOOT_SCRIPT_COMMON_HEADER));
+
+ CopyMem((VOID*)TempBootScriptEntry, LastOpcode, ScriptHeader.Length);
+ //
+ // Find the right position to write the node in
+ //
+ S3BootScriptCalculateInsertAddress (
+ ScriptHeader.Length,
+ TempPosition,
+ BeforeOrAfter,
+ &Script
+ );
+ //
+ // Copy the node to Boot script table
+ //
+ CopyMem((VOID*)Script, (VOID*)TempBootScriptEntry, ScriptHeader.Length);
+
+ SyncBootScript (Script);
+
+ //
+ // return out the Position
+ //
+ if (Position != NULL) {
+ *Position = Script;
+ }
+ return RETURN_SUCCESS;
+}
+/**
+ Create a Label node in the boot script table.
+
+ @param BeforeOrAfter Specifies whether the opcode is stored before (TRUE) or after (FALSE) the position
+ in the boot script table specified by Position. If Position is NULL or points to
+ NULL then the new opcode is inserted at the beginning of the table (if TRUE) or end
+ of the table (if FALSE).
+ @param Position On entry, specifies the position in the boot script table where the opcode will be
+ inserted, either before or after, depending on BeforeOrAfter. On exit, specifies
+ the position of the inserted opcode in the boot script table.
+ @param InformationLength Length of the label in bytes
+ @param Information Label to be logged in the boot scrpit
+
+ @retval RETURN_INVALID_PARAMETER The Position is not a valid position in the boot script table.
+ @retval RETURN_OUT_OF_RESOURCES Not enough memory for the table do operation.
+ @retval RETURN_SUCCESS Opcode is added.
+
+**/
+RETURN_STATUS
+EFIAPI
+S3BootScriptLabelInternal (
+ IN BOOLEAN BeforeOrAfter,
+ IN OUT VOID **Position OPTIONAL,
+ IN UINT32 InformationLength,
+ IN CONST CHAR8 *Information
+ )
+{
+ UINT8 Length;
+ UINT8 *Script;
+ EFI_BOOT_SCRIPT_INFORMATION ScriptInformation;
+
+ Length = (UINT8)(sizeof (EFI_BOOT_SCRIPT_INFORMATION) + InformationLength);
+
+ Script = S3BootScriptGetEntryAddAddress (Length);
+ if (Script == NULL) {
+ return RETURN_OUT_OF_RESOURCES;
+ }
+ //
+ // Build script data
+ //
+ ScriptInformation.OpCode = S3_BOOT_SCRIPT_LIB_LABEL_OPCODE;
+ ScriptInformation.Length = Length;
+
+
+ ScriptInformation.InformationLength = InformationLength;
+
+ CopyMem ((VOID*)Script, (VOID*)&ScriptInformation, sizeof (EFI_BOOT_SCRIPT_INFORMATION));
+ CopyMem ((VOID*)(Script + sizeof (EFI_BOOT_SCRIPT_INFORMATION)), (VOID *) Information, (UINTN) InformationLength);
+
+ SyncBootScript (Script);
+
+ return S3BootScriptMoveLastOpcode (BeforeOrAfter, Position);
+
+}
+/**
+ Find a label within the boot script table and, if not present, optionally create it.
+
+ @param BeforeOrAfter Specifies whether the opcode is stored before (TRUE)
+ or after (FALSE) the position in the boot script table
+ specified by Position.
+ @param CreateIfNotFound Specifies whether the label will be created if the label
+ does not exists (TRUE) or not (FALSE).
+ @param Position On entry, specifies the position in the boot script table
+ where the opcode will be inserted, either before or after,
+ depending on BeforeOrAfter. On exit, specifies the position
+ of the inserted opcode in the boot script table.
+ @param Label Points to the label which will be inserted in the boot script table.
+
+ @retval EFI_SUCCESS The operation succeeded. A record was added into the
+ specified script table.
+ @retval EFI_INVALID_PARAMETER The parameter is illegal or the given boot script is not supported.
+ If the opcode is unknow or not supported because of the PCD
+ Feature Flags.
+ @retval EFI_OUT_OF_RESOURCES There is insufficient memory to store the boot script.
+
+**/
+RETURN_STATUS
+EFIAPI
+S3BootScriptLabel (
+ IN BOOLEAN BeforeOrAfter,
+ IN BOOLEAN CreateIfNotFound,
+ IN OUT VOID **Position OPTIONAL,
+ IN CONST CHAR8 *Label
+ )
+{
+ UINT8* Script;
+ UINTN StartAddress;
+ UINT32 TableLength;
+ EFI_BOOT_SCRIPT_COMMON_HEADER ScriptHeader;
+ EFI_BOOT_SCRIPT_TABLE_HEADER TableHeader;
+ UINT32 LabelLength;
+ //
+ // Check NULL Label
+ //
+ if (Label == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Check empty Label
+ //
+ if (Label[0] == '\0') {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check that the script is initialized and synced without adding an entry to the script.
+ // The code must search for the label first before it knows if a new entry needs
+ // to be added.
+ //
+ Script = S3BootScriptGetEntryAddAddress (0);
+ if (Script == NULL) {
+ return RETURN_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Check the header and search for existing label.
+ //
+ Script = mS3BootScriptTablePtr->TableBase;
+ CopyMem ((VOID*)&TableHeader, Script, sizeof(EFI_BOOT_SCRIPT_TABLE_HEADER));
+ if (TableHeader.OpCode != S3_BOOT_SCRIPT_LIB_TABLE_OPCODE) {
+ return EFI_INVALID_PARAMETER;
+ }
+ StartAddress = (UINTN) Script;
+ TableLength = mS3BootScriptTablePtr->TableLength;
+ Script = Script + TableHeader.Length;
+ while ((UINTN) Script < (UINTN) (StartAddress + TableLength)) {
+
+ CopyMem ((VOID*)&ScriptHeader, Script, sizeof(EFI_BOOT_SCRIPT_COMMON_HEADER));
+ if (ScriptHeader.OpCode == S3_BOOT_SCRIPT_LIB_LABEL_OPCODE) {
+ if (AsciiStrCmp ((CHAR8 *)(UINTN)(Script+sizeof(EFI_BOOT_SCRIPT_INFORMATION)), Label) == 0) {
+ (*Position) = Script;
+ return EFI_SUCCESS;
+ }
+ }
+ Script = Script + ScriptHeader.Length;
+ }
+ if (CreateIfNotFound) {
+ LabelLength = (UINT32)AsciiStrSize(Label);
+ return S3BootScriptLabelInternal (BeforeOrAfter,Position, LabelLength, Label);
+ } else {
+ return EFI_NOT_FOUND;
+ }
+}
+
+/**
+ Compare two positions in the boot script table and return their relative position.
+ @param Position1 The positions in the boot script table to compare
+ @param Position2 The positions in the boot script table to compare
+ @param RelativePosition On return, points to the result of the comparison
+
+ @retval EFI_SUCCESS The operation succeeded. A record was added into the
+ specified script table.
+ @retval EFI_INVALID_PARAMETER The parameter is illegal or the given boot script is not supported.
+ If the opcode is unknow or not supported because of the PCD
+ Feature Flags.
+ @retval EFI_OUT_OF_RESOURCES There is insufficient memory to store the boot script.
+
+**/
+RETURN_STATUS
+EFIAPI
+S3BootScriptCompare (
+ IN UINT8 *Position1,
+ IN UINT8 *Position2,
+ OUT UINTN *RelativePosition
+ )
+{
+ UINT8* Script;
+ UINT32 TableLength;
+
+ if (RelativePosition == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check that the script is initialized and synced without adding an entry to the script.
+ //
+ Script = S3BootScriptGetEntryAddAddress (0);
+ if (Script == NULL) {
+ return RETURN_OUT_OF_RESOURCES;
+ }
+ Script = mS3BootScriptTablePtr->TableBase;
+
+ //
+ // mS3BootScriptTablePtr->TableLength does not include the termination node, so add it up
+ //
+ TableLength = mS3BootScriptTablePtr->TableLength + sizeof (EFI_BOOT_SCRIPT_TERMINATE);
+ if (Position1 < Script || Position1 > Script+TableLength) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (Position2 < Script || Position2 > Script+TableLength) {
+ return EFI_INVALID_PARAMETER;
+ }
+ *RelativePosition = (Position1 < Position2)?-1:((Position1 == Position2)?0:1);
+
+ return EFI_SUCCESS;
+}
+
diff --git a/Core/MdeModulePkg/Library/PiDxeS3BootScriptLib/DxeS3BootScriptLib.inf b/Core/MdeModulePkg/Library/PiDxeS3BootScriptLib/DxeS3BootScriptLib.inf
new file mode 100644
index 0000000000..de314db479
--- /dev/null
+++ b/Core/MdeModulePkg/Library/PiDxeS3BootScriptLib/DxeS3BootScriptLib.inf
@@ -0,0 +1,74 @@
+## @file
+# DXE S3 boot script Library.
+#
+# Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials are
+# licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxeS3BootScriptLib
+ MODULE_UNI_FILE = DxeS3BootScriptLib.uni
+ FILE_GUID = 57F9967B-26CD-4262-837A-55B8AA158254
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = S3BootScriptLib|DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER DXE_SAL_DRIVER UEFI_DRIVER UEFI_APPLICATION
+
+
+ CONSTRUCTOR = S3BootScriptLibInitialize
+ DESTRUCTOR = S3BootScriptLibDeinitialize
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ BootScriptSave.c
+ BootScriptExecute.c
+ InternalBootScriptLib.h
+ BootScriptInternalFormat.h
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiBootServicesTableLib
+ BaseLib
+ BaseMemoryLib
+ TimerLib
+ DebugLib
+ PcdLib
+ UefiLib
+ SmbusLib
+ PciLib
+ IoLib
+ LockBoxLib
+
+[Protocols]
+ gEfiSmmBase2ProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiDxeSmmReadyToLockProtocolGuid ## NOTIFY
+ gEfiSmmReadyToLockProtocolGuid ## NOTIFY
+ gEdkiiSmmExitBootServicesProtocolGuid ## NOTIFY
+ gEdkiiSmmLegacyBootProtocolGuid ## NOTIFY
+
+[Pcd]
+ ## CONSUMES
+ ## SOMETIMES_PRODUCES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdS3BootScriptTablePrivateDataPtr
+ ## CONSUMES
+ ## SOMETIMES_PRODUCES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdS3BootScriptTablePrivateSmmDataPtr
+ gEfiMdeModulePkgTokenSpaceGuid.PcdS3BootScriptRuntimeTableReservePageNumber ## CONSUMES
+
diff --git a/Core/MdeModulePkg/Library/PiDxeS3BootScriptLib/DxeS3BootScriptLib.uni b/Core/MdeModulePkg/Library/PiDxeS3BootScriptLib/DxeS3BootScriptLib.uni
new file mode 100644
index 0000000000..775b2f8715
--- /dev/null
+++ b/Core/MdeModulePkg/Library/PiDxeS3BootScriptLib/DxeS3BootScriptLib.uni
Binary files differ
diff --git a/Core/MdeModulePkg/Library/PiDxeS3BootScriptLib/InternalBootScriptLib.h b/Core/MdeModulePkg/Library/PiDxeS3BootScriptLib/InternalBootScriptLib.h
new file mode 100644
index 0000000000..e540278483
--- /dev/null
+++ b/Core/MdeModulePkg/Library/PiDxeS3BootScriptLib/InternalBootScriptLib.h
@@ -0,0 +1,110 @@
+/** @file
+ Support for S3 boot script lib. This file defined some internal macro and internal
+ data structure
+
+ Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions
+ of the BSD License which accompanies this distribution. The
+ full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+#ifndef __INTERNAL_BOOT_SCRIPT_LIB__
+#define __INTERNAL_BOOT_SCRIPT_LIB__
+
+#include <PiDxe.h>
+
+#include <Guid/EventGroup.h>
+#include <Protocol/SmmBase2.h>
+#include <Protocol/DxeSmmReadyToLock.h>
+#include <Protocol/SmmReadyToLock.h>
+#include <Protocol/SmmExitBootServices.h>
+#include <Protocol/SmmLegacyBoot.h>
+
+#include <Library/S3BootScriptLib.h>
+
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/BaseLib.h>
+#include <Library/PcdLib.h>
+#include <Library/SmbusLib.h>
+#include <Library/IoLib.h>
+#include <Library/PciLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/TimerLib.h>
+#include <Library/UefiLib.h>
+#include <Library/LockBoxLib.h>
+
+#include "BootScriptInternalFormat.h"
+
+#define MAX_IO_ADDRESS 0xFFFF
+
+//
+// Macro to convert a UEFI PCI address to a PCI Library PCI address
+//
+#define PCI_ADDRESS_ENCODE(A) (UINTN)PCI_LIB_ADDRESS( \
+ ((((UINTN)(A))& 0xff000000) >> 24), ((((UINTN)(A)) &0x00ff0000) >> 16), ((((UINTN)(A)) & 0xff00) >> 8), ((RShiftU64 ((A), 32) & 0xfff) | ((A)& 0xff)) \
+ )
+
+
+
+typedef union {
+ UINT8 volatile *Buf;
+ UINT8 volatile *Uint8;
+ UINT16 volatile *Uint16;
+ UINT32 volatile *Uint32;
+ UINT64 volatile *Uint64;
+ UINTN volatile Uint;
+} PTR;
+
+
+// Minimum and maximum length for SMBus bus block protocols defined in SMBus spec 2.0.
+//
+#define MIN_SMBUS_BLOCK_LEN 1
+#define MAX_SMBUS_BLOCK_LEN 32
+
+//
+// The boot script private data.
+//
+typedef struct {
+ UINT8 *TableBase;
+ UINT32 TableLength; // Record the actual memory length
+ UINT16 TableMemoryPageNumber; // Record the page number Allocated for the table
+ BOOLEAN InSmm; // Record if this library is in SMM.
+ BOOLEAN AtRuntime; // Record if current state is after SmmExitBootServices or SmmLegacyBoot.
+ UINT32 BootTimeScriptLength; // Maintain boot time script length in LockBox after SmmReadyToLock in SMM.
+ BOOLEAN SmmLocked; // Record if current state is after SmmReadyToLock
+ BOOLEAN BackFromS3; // Indicate that the system is back from S3.
+} SCRIPT_TABLE_PRIVATE_DATA;
+
+typedef
+EFI_STATUS
+(EFIAPI *DISPATCH_ENTRYPOINT_FUNC) (
+ IN EFI_HANDLE ImageHandle,
+ IN VOID *Context
+ );
+
+extern SCRIPT_TABLE_PRIVATE_DATA *mS3BootScriptTablePtr;
+
+//
+// Define Opcode for Label which is implementation specific and no standard spec define.
+//
+#define S3_BOOT_SCRIPT_LIB_LABEL_OPCODE 0xFE
+
+///
+/// The opcode indicate the start of the boot script table.
+///
+#define S3_BOOT_SCRIPT_LIB_TABLE_OPCODE 0xAA
+///
+/// The opcode indicate the end of the boot script table.
+///
+#define S3_BOOT_SCRIPT_LIB_TERMINATE_OPCODE 0xFF
+
+
+#endif //__INTERNAL_BOOT_SCRIPT_LIB__
+
diff --git a/Core/MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/MemoryAllocationLib.c b/Core/MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/MemoryAllocationLib.c
new file mode 100644
index 0000000000..5e13a3eda2
--- /dev/null
+++ b/Core/MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/MemoryAllocationLib.c
@@ -0,0 +1,929 @@
+/** @file
+ Support routines for memory allocation routines based on SMM Core internal functions.
+
+ The PI System Management Mode Core Interface Specification only allows the use
+ of EfiRuntimeServicesCode and EfiRuntimeServicesData memory types for memory
+ allocations as the SMRAM space should be reserved after BDS phase. The functions
+ in the Memory Allocation Library use EfiBootServicesData as the default memory
+ allocation type. For this SMM specific instance of the Memory Allocation Library,
+ EfiRuntimeServicesData is used as the default memory type for all allocations.
+ In addition, allocation for the Reserved memory types are not supported and will
+ always return NULL.
+
+ Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiSmm.h>
+
+#include <Protocol/SmmAccess2.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include "PiSmmCoreMemoryAllocationServices.h"
+
+EFI_SMRAM_DESCRIPTOR *mSmmCoreMemoryAllocLibSmramRanges = NULL;
+UINTN mSmmCoreMemoryAllocLibSmramRangeCount = 0;
+
+/**
+ Check whether the start address of buffer is within any of the SMRAM ranges.
+
+ @param[in] Buffer The pointer to the buffer to be checked.
+
+ @retval TURE The buffer is in SMRAM ranges.
+ @retval FALSE The buffer is out of SMRAM ranges.
+**/
+BOOLEAN
+EFIAPI
+BufferInSmram (
+ IN VOID *Buffer
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index < mSmmCoreMemoryAllocLibSmramRangeCount; Index ++) {
+ if (((EFI_PHYSICAL_ADDRESS) (UINTN) Buffer >= mSmmCoreMemoryAllocLibSmramRanges[Index].CpuStart) &&
+ ((EFI_PHYSICAL_ADDRESS) (UINTN) Buffer < (mSmmCoreMemoryAllocLibSmramRanges[Index].CpuStart + mSmmCoreMemoryAllocLibSmramRanges[Index].PhysicalSize))) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ Allocates one or more 4KB pages of a certain memory type.
+
+ Allocates the number of 4KB pages of a certain memory type and returns a pointer to the allocated
+ buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL is returned.
+ If there is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ @param MemoryType The type of memory to allocate.
+ @param Pages The number of 4 KB pages to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+InternalAllocatePages (
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN Pages
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS Memory;
+
+ if (Pages == 0) {
+ return NULL;
+ }
+
+ Status = SmmAllocatePages (AllocateAnyPages, MemoryType, Pages, &Memory);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+ return (VOID *) (UINTN) Memory;
+}
+
+/**
+ Allocates one or more 4KB pages of type EfiRuntimeServicesData.
+
+ Allocates the number of 4KB pages of type EfiRuntimeServicesData and returns a pointer to the
+ allocated buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL
+ is returned. If there is not enough memory remaining to satisfy the request, then NULL is
+ returned.
+
+ @param Pages The number of 4 KB pages to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocatePages (
+ IN UINTN Pages
+ )
+{
+ return InternalAllocatePages (EfiRuntimeServicesData, Pages);
+}
+
+/**
+ Allocates one or more 4KB pages of type EfiRuntimeServicesData.
+
+ Allocates the number of 4KB pages of type EfiRuntimeServicesData and returns a pointer to the
+ allocated buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL
+ is returned. If there is not enough memory remaining to satisfy the request, then NULL is
+ returned.
+
+ @param Pages The number of 4 KB pages to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateRuntimePages (
+ IN UINTN Pages
+ )
+{
+ return InternalAllocatePages (EfiRuntimeServicesData, Pages);
+}
+
+/**
+ Allocates one or more 4KB pages of type EfiReservedMemoryType.
+
+ Allocates the number of 4KB pages of type EfiReservedMemoryType and returns a pointer to the
+ allocated buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL
+ is returned. If there is not enough memory remaining to satisfy the request, then NULL is
+ returned.
+
+ @param Pages The number of 4 KB pages to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateReservedPages (
+ IN UINTN Pages
+ )
+{
+ return NULL;
+}
+
+/**
+ Frees one or more 4KB pages that were previously allocated with one of the page allocation
+ functions in the Memory Allocation Library.
+
+ Frees the number of 4KB pages specified by Pages from the buffer specified by Buffer. Buffer
+ must have been allocated on a previous call to the page allocation services of the Memory
+ Allocation Library. If it is not possible to free allocated pages, then this function will
+ perform no actions.
+
+ If Buffer was not allocated with a page allocation function in the Memory Allocation Library,
+ then ASSERT().
+ If Pages is zero, then ASSERT().
+
+ @param Buffer Pointer to the buffer of pages to free.
+ @param Pages The number of 4 KB pages to free.
+
+**/
+VOID
+EFIAPI
+FreePages (
+ IN VOID *Buffer,
+ IN UINTN Pages
+ )
+{
+ EFI_STATUS Status;
+
+ ASSERT (Pages != 0);
+ if (BufferInSmram (Buffer)) {
+ //
+ // When Buffer is in SMRAM range, it should be allocated by SmmAllocatePages() service.
+ // So, SmmFreePages() service is used to free it.
+ //
+ Status = SmmFreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) Buffer, Pages);
+ } else {
+ //
+ // When Buffer is out of SMRAM range, it should be allocated by gBS->AllocatePages() service.
+ // So, gBS->FreePages() service is used to free it.
+ //
+ Status = gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) Buffer, Pages);
+ }
+ ASSERT_EFI_ERROR (Status);
+}
+
+/**
+ Allocates one or more 4KB pages of a certain memory type at a specified alignment.
+
+ Allocates the number of 4KB pages specified by Pages of a certain memory type with an alignment
+ specified by Alignment. The allocated buffer is returned. If Pages is 0, then NULL is returned.
+ If there is not enough memory at the specified alignment remaining to satisfy the request, then
+ NULL is returned.
+ If Alignment is not a power of two and Alignment is not zero, then ASSERT().
+ If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT().
+
+ @param MemoryType The type of memory to allocate.
+ @param Pages The number of 4 KB pages to allocate.
+ @param Alignment The requested alignment of the allocation. Must be a power of two.
+ If Alignment is zero, then byte alignment is used.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+InternalAllocateAlignedPages (
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN Pages,
+ IN UINTN Alignment
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS Memory;
+ UINTN AlignedMemory;
+ UINTN AlignmentMask;
+ UINTN UnalignedPages;
+ UINTN RealPages;
+
+ //
+ // Alignment must be a power of two or zero.
+ //
+ ASSERT ((Alignment & (Alignment - 1)) == 0);
+
+ if (Pages == 0) {
+ return NULL;
+ }
+ if (Alignment > EFI_PAGE_SIZE) {
+ //
+ // Calculate the total number of pages since alignment is larger than page size.
+ //
+ AlignmentMask = Alignment - 1;
+ RealPages = Pages + EFI_SIZE_TO_PAGES (Alignment);
+ //
+ // Make sure that Pages plus EFI_SIZE_TO_PAGES (Alignment) does not overflow.
+ //
+ ASSERT (RealPages > Pages);
+
+ Status = SmmAllocatePages (AllocateAnyPages, MemoryType, RealPages, &Memory);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+ AlignedMemory = ((UINTN) Memory + AlignmentMask) & ~AlignmentMask;
+ UnalignedPages = EFI_SIZE_TO_PAGES (AlignedMemory - (UINTN) Memory);
+ if (UnalignedPages > 0) {
+ //
+ // Free first unaligned page(s).
+ //
+ Status = SmmFreePages (Memory, UnalignedPages);
+ ASSERT_EFI_ERROR (Status);
+ }
+ Memory = (EFI_PHYSICAL_ADDRESS) (AlignedMemory + EFI_PAGES_TO_SIZE (Pages));
+ UnalignedPages = RealPages - Pages - UnalignedPages;
+ if (UnalignedPages > 0) {
+ //
+ // Free last unaligned page(s).
+ //
+ Status = SmmFreePages (Memory, UnalignedPages);
+ ASSERT_EFI_ERROR (Status);
+ }
+ } else {
+ //
+ // Do not over-allocate pages in this case.
+ //
+ Status = SmmAllocatePages (AllocateAnyPages, MemoryType, Pages, &Memory);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+ AlignedMemory = (UINTN) Memory;
+ }
+ return (VOID *) AlignedMemory;
+}
+
+/**
+ Allocates one or more 4KB pages of type EfiRuntimeServicesData at a specified alignment.
+
+ Allocates the number of 4KB pages specified by Pages of type EfiRuntimeServicesData with an
+ alignment specified by Alignment. The allocated buffer is returned. If Pages is 0, then NULL is
+ returned. If there is not enough memory at the specified alignment remaining to satisfy the
+ request, then NULL is returned.
+
+ If Alignment is not a power of two and Alignment is not zero, then ASSERT().
+ If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT().
+
+ @param Pages The number of 4 KB pages to allocate.
+ @param Alignment The requested alignment of the allocation. Must be a power of two.
+ If Alignment is zero, then byte alignment is used.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateAlignedPages (
+ IN UINTN Pages,
+ IN UINTN Alignment
+ )
+{
+ return InternalAllocateAlignedPages (EfiRuntimeServicesData, Pages, Alignment);
+}
+
+/**
+ Allocates one or more 4KB pages of type EfiRuntimeServicesData at a specified alignment.
+
+ Allocates the number of 4KB pages specified by Pages of type EfiRuntimeServicesData with an
+ alignment specified by Alignment. The allocated buffer is returned. If Pages is 0, then NULL is
+ returned. If there is not enough memory at the specified alignment remaining to satisfy the
+ request, then NULL is returned.
+
+ If Alignment is not a power of two and Alignment is not zero, then ASSERT().
+ If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT().
+
+ @param Pages The number of 4 KB pages to allocate.
+ @param Alignment The requested alignment of the allocation. Must be a power of two.
+ If Alignment is zero, then byte alignment is used.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateAlignedRuntimePages (
+ IN UINTN Pages,
+ IN UINTN Alignment
+ )
+{
+ return InternalAllocateAlignedPages (EfiRuntimeServicesData, Pages, Alignment);
+}
+
+/**
+ Allocates one or more 4KB pages of type EfiReservedMemoryType at a specified alignment.
+
+ Allocates the number of 4KB pages specified by Pages of type EfiReservedMemoryType with an
+ alignment specified by Alignment. The allocated buffer is returned. If Pages is 0, then NULL is
+ returned. If there is not enough memory at the specified alignment remaining to satisfy the
+ request, then NULL is returned.
+
+ If Alignment is not a power of two and Alignment is not zero, then ASSERT().
+ If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT().
+
+ @param Pages The number of 4 KB pages to allocate.
+ @param Alignment The requested alignment of the allocation. Must be a power of two.
+ If Alignment is zero, then byte alignment is used.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateAlignedReservedPages (
+ IN UINTN Pages,
+ IN UINTN Alignment
+ )
+{
+ return NULL;
+}
+
+/**
+ Frees one or more 4KB pages that were previously allocated with one of the aligned page
+ allocation functions in the Memory Allocation Library.
+
+ Frees the number of 4KB pages specified by Pages from the buffer specified by Buffer. Buffer
+ must have been allocated on a previous call to the aligned page allocation services of the Memory
+ Allocation Library. If it is not possible to free allocated pages, then this function will
+ perform no actions.
+
+ If Buffer was not allocated with an aligned page allocation function in the Memory Allocation
+ Library, then ASSERT().
+ If Pages is zero, then ASSERT().
+
+ @param Buffer Pointer to the buffer of pages to free.
+ @param Pages The number of 4 KB pages to free.
+
+**/
+VOID
+EFIAPI
+FreeAlignedPages (
+ IN VOID *Buffer,
+ IN UINTN Pages
+ )
+{
+ EFI_STATUS Status;
+
+ ASSERT (Pages != 0);
+ if (BufferInSmram (Buffer)) {
+ //
+ // When Buffer is in SMRAM range, it should be allocated by SmmAllocatePages() service.
+ // So, SmmFreePages() service is used to free it.
+ //
+ Status = SmmFreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) Buffer, Pages);
+ } else {
+ //
+ // When Buffer is out of SMRAM range, it should be allocated by gBS->AllocatePages() service.
+ // So, gBS->FreePages() service is used to free it.
+ //
+ Status = gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) Buffer, Pages);
+ }
+ ASSERT_EFI_ERROR (Status);
+}
+
+/**
+ Allocates a buffer of a certain pool type.
+
+ Allocates the number bytes specified by AllocationSize of a certain pool type and returns a
+ pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is
+ returned. If there is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ @param MemoryType The type of memory to allocate.
+ @param AllocationSize The number of bytes to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+InternalAllocatePool (
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN AllocationSize
+ )
+{
+ EFI_STATUS Status;
+ VOID *Memory;
+
+ Memory = NULL;
+
+ Status = SmmAllocatePool (MemoryType, AllocationSize, &Memory);
+ if (EFI_ERROR (Status)) {
+ Memory = NULL;
+ }
+ return Memory;
+}
+
+/**
+ Allocates a buffer of type EfiRuntimeServicesData.
+
+ Allocates the number bytes specified by AllocationSize of type EfiRuntimeServicesData and returns a
+ pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is
+ returned. If there is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ @param AllocationSize The number of bytes to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocatePool (
+ IN UINTN AllocationSize
+ )
+{
+ return InternalAllocatePool (EfiRuntimeServicesData, AllocationSize);
+}
+
+/**
+ Allocates a buffer of type EfiRuntimeServicesData.
+
+ Allocates the number bytes specified by AllocationSize of type EfiRuntimeServicesData and returns
+ a pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is
+ returned. If there is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ @param AllocationSize The number of bytes to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateRuntimePool (
+ IN UINTN AllocationSize
+ )
+{
+ return InternalAllocatePool (EfiRuntimeServicesData, AllocationSize);
+}
+
+/**
+ Allocates a buffer of type EfiReservedMemoryType.
+
+ Allocates the number bytes specified by AllocationSize of type EfiReservedMemoryType and returns
+ a pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is
+ returned. If there is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ @param AllocationSize The number of bytes to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateReservedPool (
+ IN UINTN AllocationSize
+ )
+{
+ return NULL;
+}
+
+/**
+ Allocates and zeros a buffer of a certain pool type.
+
+ Allocates the number bytes specified by AllocationSize of a certain pool type, clears the buffer
+ with zeros, and returns a pointer to the allocated buffer. If AllocationSize is 0, then a valid
+ buffer of 0 size is returned. If there is not enough memory remaining to satisfy the request,
+ then NULL is returned.
+
+ @param PoolType The type of memory to allocate.
+ @param AllocationSize The number of bytes to allocate and zero.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+InternalAllocateZeroPool (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN AllocationSize
+ )
+{
+ VOID *Memory;
+
+ Memory = InternalAllocatePool (PoolType, AllocationSize);
+ if (Memory != NULL) {
+ Memory = ZeroMem (Memory, AllocationSize);
+ }
+ return Memory;
+}
+
+/**
+ Allocates and zeros a buffer of type EfiRuntimeServicesData.
+
+ Allocates the number bytes specified by AllocationSize of type EfiRuntimeServicesData, clears the
+ buffer with zeros, and returns a pointer to the allocated buffer. If AllocationSize is 0, then a
+ valid buffer of 0 size is returned. If there is not enough memory remaining to satisfy the
+ request, then NULL is returned.
+
+ @param AllocationSize The number of bytes to allocate and zero.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateZeroPool (
+ IN UINTN AllocationSize
+ )
+{
+ return InternalAllocateZeroPool (EfiRuntimeServicesData, AllocationSize);
+}
+
+/**
+ Allocates and zeros a buffer of type EfiRuntimeServicesData.
+
+ Allocates the number bytes specified by AllocationSize of type EfiRuntimeServicesData, clears the
+ buffer with zeros, and returns a pointer to the allocated buffer. If AllocationSize is 0, then a
+ valid buffer of 0 size is returned. If there is not enough memory remaining to satisfy the
+ request, then NULL is returned.
+
+ @param AllocationSize The number of bytes to allocate and zero.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateRuntimeZeroPool (
+ IN UINTN AllocationSize
+ )
+{
+ return InternalAllocateZeroPool (EfiRuntimeServicesData, AllocationSize);
+}
+
+/**
+ Allocates and zeros a buffer of type EfiReservedMemoryType.
+
+ Allocates the number bytes specified by AllocationSize of type EfiReservedMemoryType, clears the
+ buffer with zeros, and returns a pointer to the allocated buffer. If AllocationSize is 0, then a
+ valid buffer of 0 size is returned. If there is not enough memory remaining to satisfy the
+ request, then NULL is returned.
+
+ @param AllocationSize The number of bytes to allocate and zero.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateReservedZeroPool (
+ IN UINTN AllocationSize
+ )
+{
+ return NULL;
+}
+
+/**
+ Copies a buffer to an allocated buffer of a certain pool type.
+
+ Allocates the number bytes specified by AllocationSize of a certain pool type, copies
+ AllocationSize bytes from Buffer to the newly allocated buffer, and returns a pointer to the
+ allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned. If there
+ is not enough memory remaining to satisfy the request, then NULL is returned.
+ If Buffer is NULL, then ASSERT().
+ If AllocationSize is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
+
+ @param PoolType The type of pool to allocate.
+ @param AllocationSize The number of bytes to allocate and zero.
+ @param Buffer The buffer to copy to the allocated buffer.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+InternalAllocateCopyPool (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN AllocationSize,
+ IN CONST VOID *Buffer
+ )
+{
+ VOID *Memory;
+
+ ASSERT (Buffer != NULL);
+ ASSERT (AllocationSize <= (MAX_ADDRESS - (UINTN) Buffer + 1));
+
+ Memory = InternalAllocatePool (PoolType, AllocationSize);
+ if (Memory != NULL) {
+ Memory = CopyMem (Memory, Buffer, AllocationSize);
+ }
+ return Memory;
+}
+
+/**
+ Copies a buffer to an allocated buffer of type EfiRuntimeServicesData.
+
+ Allocates the number bytes specified by AllocationSize of type EfiRuntimeServicesData, copies
+ AllocationSize bytes from Buffer to the newly allocated buffer, and returns a pointer to the
+ allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned. If there
+ is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ If Buffer is NULL, then ASSERT().
+ If AllocationSize is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
+
+ @param AllocationSize The number of bytes to allocate and zero.
+ @param Buffer The buffer to copy to the allocated buffer.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateCopyPool (
+ IN UINTN AllocationSize,
+ IN CONST VOID *Buffer
+ )
+{
+ return InternalAllocateCopyPool (EfiRuntimeServicesData, AllocationSize, Buffer);
+}
+
+/**
+ Copies a buffer to an allocated buffer of type EfiRuntimeServicesData.
+
+ Allocates the number bytes specified by AllocationSize of type EfiRuntimeServicesData, copies
+ AllocationSize bytes from Buffer to the newly allocated buffer, and returns a pointer to the
+ allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned. If there
+ is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ If Buffer is NULL, then ASSERT().
+ If AllocationSize is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
+
+ @param AllocationSize The number of bytes to allocate and zero.
+ @param Buffer The buffer to copy to the allocated buffer.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateRuntimeCopyPool (
+ IN UINTN AllocationSize,
+ IN CONST VOID *Buffer
+ )
+{
+ return InternalAllocateCopyPool (EfiRuntimeServicesData, AllocationSize, Buffer);
+}
+
+/**
+ Copies a buffer to an allocated buffer of type EfiReservedMemoryType.
+
+ Allocates the number bytes specified by AllocationSize of type EfiReservedMemoryType, copies
+ AllocationSize bytes from Buffer to the newly allocated buffer, and returns a pointer to the
+ allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned. If there
+ is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ If Buffer is NULL, then ASSERT().
+ If AllocationSize is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
+
+ @param AllocationSize The number of bytes to allocate and zero.
+ @param Buffer The buffer to copy to the allocated buffer.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocateReservedCopyPool (
+ IN UINTN AllocationSize,
+ IN CONST VOID *Buffer
+ )
+{
+ return NULL;
+}
+
+/**
+ Reallocates a buffer of a specified memory type.
+
+ Allocates and zeros the number bytes specified by NewSize from memory of the type
+ specified by PoolType. If OldBuffer is not NULL, then the smaller of OldSize and
+ NewSize bytes are copied from OldBuffer to the newly allocated buffer, and
+ OldBuffer is freed. A pointer to the newly allocated buffer is returned.
+ If NewSize is 0, then a valid buffer of 0 size is returned. If there is not
+ enough memory remaining to satisfy the request, then NULL is returned.
+
+ If the allocation of the new buffer is successful and the smaller of NewSize and OldSize
+ is greater than (MAX_ADDRESS - OldBuffer + 1), then ASSERT().
+
+ @param PoolType The type of pool to allocate.
+ @param OldSize The size, in bytes, of OldBuffer.
+ @param NewSize The size, in bytes, of the buffer to reallocate.
+ @param OldBuffer The buffer to copy to the allocated buffer. This is an optional
+ parameter that may be NULL.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+InternalReallocatePool (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN OldSize,
+ IN UINTN NewSize,
+ IN VOID *OldBuffer OPTIONAL
+ )
+{
+ VOID *NewBuffer;
+
+ NewBuffer = InternalAllocateZeroPool (PoolType, NewSize);
+ if (NewBuffer != NULL && OldBuffer != NULL) {
+ CopyMem (NewBuffer, OldBuffer, MIN (OldSize, NewSize));
+ FreePool (OldBuffer);
+ }
+ return NewBuffer;
+}
+
+/**
+ Reallocates a buffer of type EfiRuntimeServicesData.
+
+ Allocates and zeros the number bytes specified by NewSize from memory of type
+ EfiRuntimeServicesData. If OldBuffer is not NULL, then the smaller of OldSize and
+ NewSize bytes are copied from OldBuffer to the newly allocated buffer, and
+ OldBuffer is freed. A pointer to the newly allocated buffer is returned.
+ If NewSize is 0, then a valid buffer of 0 size is returned. If there is not
+ enough memory remaining to satisfy the request, then NULL is returned.
+
+ If the allocation of the new buffer is successful and the smaller of NewSize and OldSize
+ is greater than (MAX_ADDRESS - OldBuffer + 1), then ASSERT().
+
+ @param OldSize The size, in bytes, of OldBuffer.
+ @param NewSize The size, in bytes, of the buffer to reallocate.
+ @param OldBuffer The buffer to copy to the allocated buffer. This is an optional
+ parameter that may be NULL.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+ReallocatePool (
+ IN UINTN OldSize,
+ IN UINTN NewSize,
+ IN VOID *OldBuffer OPTIONAL
+ )
+{
+ return InternalReallocatePool (EfiRuntimeServicesData, OldSize, NewSize, OldBuffer);
+}
+
+/**
+ Reallocates a buffer of type EfiRuntimeServicesData.
+
+ Allocates and zeros the number bytes specified by NewSize from memory of type
+ EfiRuntimeServicesData. If OldBuffer is not NULL, then the smaller of OldSize and
+ NewSize bytes are copied from OldBuffer to the newly allocated buffer, and
+ OldBuffer is freed. A pointer to the newly allocated buffer is returned.
+ If NewSize is 0, then a valid buffer of 0 size is returned. If there is not
+ enough memory remaining to satisfy the request, then NULL is returned.
+
+ If the allocation of the new buffer is successful and the smaller of NewSize and OldSize
+ is greater than (MAX_ADDRESS - OldBuffer + 1), then ASSERT().
+
+ @param OldSize The size, in bytes, of OldBuffer.
+ @param NewSize The size, in bytes, of the buffer to reallocate.
+ @param OldBuffer The buffer to copy to the allocated buffer. This is an optional
+ parameter that may be NULL.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+ReallocateRuntimePool (
+ IN UINTN OldSize,
+ IN UINTN NewSize,
+ IN VOID *OldBuffer OPTIONAL
+ )
+{
+ return InternalReallocatePool (EfiRuntimeServicesData, OldSize, NewSize, OldBuffer);
+}
+
+/**
+ Reallocates a buffer of type EfiReservedMemoryType.
+
+ Allocates and zeros the number bytes specified by NewSize from memory of type
+ EfiReservedMemoryType. If OldBuffer is not NULL, then the smaller of OldSize and
+ NewSize bytes are copied from OldBuffer to the newly allocated buffer, and
+ OldBuffer is freed. A pointer to the newly allocated buffer is returned.
+ If NewSize is 0, then a valid buffer of 0 size is returned. If there is not
+ enough memory remaining to satisfy the request, then NULL is returned.
+
+ If the allocation of the new buffer is successful and the smaller of NewSize and OldSize
+ is greater than (MAX_ADDRESS - OldBuffer + 1), then ASSERT().
+
+ @param OldSize The size, in bytes, of OldBuffer.
+ @param NewSize The size, in bytes, of the buffer to reallocate.
+ @param OldBuffer The buffer to copy to the allocated buffer. This is an optional
+ parameter that may be NULL.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+ReallocateReservedPool (
+ IN UINTN OldSize,
+ IN UINTN NewSize,
+ IN VOID *OldBuffer OPTIONAL
+ )
+{
+ return NULL;
+}
+
+/**
+ Frees a buffer that was previously allocated with one of the pool allocation functions in the
+ Memory Allocation Library.
+
+ Frees the buffer specified by Buffer. Buffer must have been allocated on a previous call to the
+ pool allocation services of the Memory Allocation Library. If it is not possible to free pool
+ resources, then this function will perform no actions.
+
+ If Buffer was not allocated with a pool allocation function in the Memory Allocation Library,
+ then ASSERT().
+
+ @param Buffer Pointer to the buffer to free.
+
+**/
+VOID
+EFIAPI
+FreePool (
+ IN VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+
+ if (BufferInSmram (Buffer)) {
+ //
+ // When Buffer is in SMRAM range, it should be allocated by SmmAllocatePool() service.
+ // So, SmmFreePool() service is used to free it.
+ //
+ Status = SmmFreePool (Buffer);
+ } else {
+ //
+ // When Buffer is out of SMRAM range, it should be allocated by gBS->AllocatePool() service.
+ // So, gBS->FreePool() service is used to free it.
+ //
+ Status = gBS->FreePool (Buffer);
+ }
+ ASSERT_EFI_ERROR (Status);
+}
+
+/**
+ The constructor function calls SmmInitializeMemoryServices to initialize memory in SMRAM.
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
+
+**/
+EFI_STATUS
+EFIAPI
+PiSmmCoreMemoryAllocationLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ SMM_CORE_PRIVATE_DATA *SmmCorePrivate;
+ UINTN Size;
+
+ SmmCorePrivate = (SMM_CORE_PRIVATE_DATA *)ImageHandle;
+ //
+ // Initialize memory service using free SMRAM
+ //
+ SmmInitializeMemoryServices (SmmCorePrivate->SmramRangeCount, SmmCorePrivate->SmramRanges);
+
+ mSmmCoreMemoryAllocLibSmramRangeCount = SmmCorePrivate->SmramRangeCount;
+ Size = mSmmCoreMemoryAllocLibSmramRangeCount * sizeof (EFI_SMRAM_DESCRIPTOR);
+ mSmmCoreMemoryAllocLibSmramRanges = (EFI_SMRAM_DESCRIPTOR *) AllocatePool (Size);
+ ASSERT (mSmmCoreMemoryAllocLibSmramRanges != NULL);
+ CopyMem (mSmmCoreMemoryAllocLibSmramRanges, SmmCorePrivate->SmramRanges, Size);
+
+ return EFI_SUCCESS;
+}
diff --git a/Core/MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/PiSmmCoreMemoryAllocationLib.inf b/Core/MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/PiSmmCoreMemoryAllocationLib.inf
new file mode 100644
index 0000000000..e8f7081149
--- /dev/null
+++ b/Core/MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/PiSmmCoreMemoryAllocationLib.inf
@@ -0,0 +1,48 @@
+## @file
+# Memory Allocation Library instance dedicated to SMM Core.
+# The implementation borrows the SMM Core Memory Allocation services as the primitive
+# for memory allocation instead of using SMM System Table servces in an indirect way.
+# It is assumed that this library instance must be linked with SMM Cre in this package.
+#
+# Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PiSmmCoreMemoryAllocationLib
+ MODULE_UNI_FILE = PiSmmCoreMemoryAllocationLib.uni
+ FILE_GUID = B618E089-9ABA-4d97-AE80-57B5BCCDA51D
+ MODULE_TYPE = SMM_CORE
+ VERSION_STRING = 1.0
+ PI_SPECIFICATION_VERSION = 0x0001000A
+ LIBRARY_CLASS = MemoryAllocationLib|SMM_CORE
+ CONSTRUCTOR = PiSmmCoreMemoryAllocationLibConstructor
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ MemoryAllocationLib.c
+ PiSmmCoreMemoryAllocationServices.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ DebugLib
+ BaseMemoryLib
+ UefiBootServicesTableLib
+
+[Protocols]
+ gEfiSmmAccess2ProtocolGuid ## CONSUMES
diff --git a/Core/MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/PiSmmCoreMemoryAllocationLib.uni b/Core/MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/PiSmmCoreMemoryAllocationLib.uni
new file mode 100644
index 0000000000..adfc0381c1
--- /dev/null
+++ b/Core/MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/PiSmmCoreMemoryAllocationLib.uni
Binary files differ
diff --git a/Core/MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/PiSmmCoreMemoryAllocationServices.h b/Core/MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/PiSmmCoreMemoryAllocationServices.h
new file mode 100644
index 0000000000..a2b89acf5d
--- /dev/null
+++ b/Core/MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/PiSmmCoreMemoryAllocationServices.h
@@ -0,0 +1,191 @@
+/** @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 - 2015, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#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/Core/MdeModulePkg/Library/PiSmmCoreSmmServicesTableLib/PiSmmCoreSmmServicesTableLib.c b/Core/MdeModulePkg/Library/PiSmmCoreSmmServicesTableLib/PiSmmCoreSmmServicesTableLib.c
new file mode 100644
index 0000000000..788fafae35
--- /dev/null
+++ b/Core/MdeModulePkg/Library/PiSmmCoreSmmServicesTableLib/PiSmmCoreSmmServicesTableLib.c
@@ -0,0 +1,60 @@
+/** @file
+ SMM Core SMM Services Table Library.
+
+ Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiSmm.h>
+#include <Library/SmmServicesTableLib.h>
+#include <Library/DebugLib.h>
+
+EFI_SMM_SYSTEM_TABLE2 *gSmst = NULL;
+extern EFI_SMM_SYSTEM_TABLE2 gSmmCoreSmst;
+
+/**
+ The constructor function caches the pointer of SMM Services Table.
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmCoreSmmServicesTableLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ gSmst = &gSmmCoreSmst;
+ return EFI_SUCCESS;
+}
+
+/**
+ This function allows the caller to determine if the driver is executing in
+ System Management Mode(SMM).
+
+ This function returns TRUE if the driver is executing in SMM and FALSE if the
+ driver is not executing in SMM.
+
+ @retval TRUE The driver is executing in System Management Mode (SMM).
+ @retval FALSE The driver is not executing in System Management Mode (SMM).
+
+**/
+BOOLEAN
+EFIAPI
+InSmm (
+ VOID
+ )
+{
+ return TRUE;
+}
diff --git a/Core/MdeModulePkg/Library/PiSmmCoreSmmServicesTableLib/PiSmmCoreSmmServicesTableLib.inf b/Core/MdeModulePkg/Library/PiSmmCoreSmmServicesTableLib/PiSmmCoreSmmServicesTableLib.inf
new file mode 100644
index 0000000000..80d523c71b
--- /dev/null
+++ b/Core/MdeModulePkg/Library/PiSmmCoreSmmServicesTableLib/PiSmmCoreSmmServicesTableLib.inf
@@ -0,0 +1,36 @@
+## @file
+# SMM Core SMM Services Table Library.
+#
+# Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PiSmmCoreSmmServicesTableLib
+ MODULE_UNI_FILE = PiSmmCoreSmmServicesTableLib.uni
+ FILE_GUID = C427146A-2EF2-4af9-A85A-E09EA65EE47D
+ MODULE_TYPE = SMM_CORE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = SmmServicesTableLib|SMM_CORE
+ PI_SPECIFICATION_VERSION = 0x0001000A
+ CONSTRUCTOR = SmmCoreSmmServicesTableLibConstructor
+
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ PiSmmCoreSmmServicesTableLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+
diff --git a/Core/MdeModulePkg/Library/PiSmmCoreSmmServicesTableLib/PiSmmCoreSmmServicesTableLib.uni b/Core/MdeModulePkg/Library/PiSmmCoreSmmServicesTableLib/PiSmmCoreSmmServicesTableLib.uni
new file mode 100644
index 0000000000..3e0854c169
--- /dev/null
+++ b/Core/MdeModulePkg/Library/PiSmmCoreSmmServicesTableLib/PiSmmCoreSmmServicesTableLib.uni
Binary files differ
diff --git a/Core/MdeModulePkg/Library/PlatformBootManagerLibNull/PlatformBootManager.c b/Core/MdeModulePkg/Library/PlatformBootManagerLibNull/PlatformBootManager.c
new file mode 100644
index 0000000000..1390e19097
--- /dev/null
+++ b/Core/MdeModulePkg/Library/PlatformBootManagerLibNull/PlatformBootManager.c
@@ -0,0 +1,67 @@
+/** @file
+ This file include all platform action which can be customized
+ by IBV/OEM.
+
+Copyright (c) 2012 - 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Library/PlatformBootManagerLib.h>
+
+
+/**
+ Do the platform specific action before the console is connected.
+
+ Such as:
+ Update console variable;
+ Register new Driver#### or Boot####;
+ Signal ReadyToLock event.
+**/
+VOID
+EFIAPI
+PlatformBootManagerBeforeConsole (
+ VOID
+ )
+{
+ return;
+}
+
+/**
+ Do the platform specific action after the console is connected.
+
+ Such as:
+ Dynamically switch output mode;
+ Signal console ready platform customized event;
+ Run diagnostics like memory testing;
+ Connect certain devices;
+ Dispatch aditional option roms.
+**/
+VOID
+EFIAPI
+PlatformBootManagerAfterConsole (
+ VOID
+ )
+{
+ return;
+}
+
+/**
+ This function is called each second during the boot manager waits the timeout.
+
+ @param TimeoutRemain The remaining timeout.
+**/
+VOID
+EFIAPI
+PlatformBootManagerWaitCallback (
+ UINT16 TimeoutRemain
+ )
+{
+ return;
+}
diff --git a/Core/MdeModulePkg/Library/PlatformBootManagerLibNull/PlatformBootManagerLibNull.inf b/Core/MdeModulePkg/Library/PlatformBootManagerLibNull/PlatformBootManagerLibNull.inf
new file mode 100644
index 0000000000..fb756ca2ff
--- /dev/null
+++ b/Core/MdeModulePkg/Library/PlatformBootManagerLibNull/PlatformBootManagerLibNull.inf
@@ -0,0 +1,37 @@
+## @file
+# Include all platform action which can be customized by IBV/OEM.
+#
+# Copyright (c) 2012 - 2015, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PlatformBootManagerLib
+ MODULE_UNI_FILE = PlatformBootManagerLibNull.uni
+ FILE_GUID = 95C097CC-8943-4038-BB8A-1C70CF2E9F3C
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = PlatformBootManagerLib|DXE_DRIVER
+
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ PlatformBootManager.c
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
diff --git a/Core/MdeModulePkg/Library/PlatformBootManagerLibNull/PlatformBootManagerLibNull.uni b/Core/MdeModulePkg/Library/PlatformBootManagerLibNull/PlatformBootManagerLibNull.uni
new file mode 100644
index 0000000000..329790afb0
--- /dev/null
+++ b/Core/MdeModulePkg/Library/PlatformBootManagerLibNull/PlatformBootManagerLibNull.uni
Binary files differ
diff --git a/Core/MdeModulePkg/Library/PlatformHookLibSerialPortPpi/PlatformHookLibSerialPortPpi.c b/Core/MdeModulePkg/Library/PlatformHookLibSerialPortPpi/PlatformHookLibSerialPortPpi.c
new file mode 100644
index 0000000000..00b70c79e6
--- /dev/null
+++ b/Core/MdeModulePkg/Library/PlatformHookLibSerialPortPpi/PlatformHookLibSerialPortPpi.c
@@ -0,0 +1,36 @@
+/** @file
+ Null Platform Hook Library instance with dependency on gPeiSerialPortPpiGuid
+
+ Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Base.h>
+#include <Library/PlatformHookLib.h>
+
+/**
+ Performs platform specific initialization required for the CPU to access
+ the hardware associated with a SerialPortLib instance. This function does
+ not initialize the serial port hardware itself. Instead, it initializes
+ hardware devices that are required for the CPU to access the serial port
+ hardware. This function may be called more than once.
+
+ @retval RETURN_SUCCESS The platform specific initialization succeeded.
+ @retval RETURN_DEVICE_ERROR The platform specific initialization could not be completed.
+
+**/
+RETURN_STATUS
+EFIAPI
+PlatformHookSerialPortInitialize (
+ VOID
+ )
+{
+ return RETURN_SUCCESS;
+}
diff --git a/Core/MdeModulePkg/Library/PlatformHookLibSerialPortPpi/PlatformHookLibSerialPortPpi.inf b/Core/MdeModulePkg/Library/PlatformHookLibSerialPortPpi/PlatformHookLibSerialPortPpi.inf
new file mode 100644
index 0000000000..09074a8a4e
--- /dev/null
+++ b/Core/MdeModulePkg/Library/PlatformHookLibSerialPortPpi/PlatformHookLibSerialPortPpi.inf
@@ -0,0 +1,38 @@
+## @file
+# Null Platform Hook Library instance with dependency on gPeiSerialPortPpiGuid
+#
+# Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PlatformHookLibSerialPortPpi
+ FILE_GUID = 621734D8-8B5E-4c01-B330-9F89A1081710
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = PlatformHookLib
+ MODULE_UNI_FILE = PlatformHookLibSerialPortPpi.uni
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ PlatformHookLibSerialPortPpi.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[Depex.common.PEIM]
+ gPeiSerialPortPpiGuid
diff --git a/Core/MdeModulePkg/Library/PlatformHookLibSerialPortPpi/PlatformHookLibSerialPortPpi.uni b/Core/MdeModulePkg/Library/PlatformHookLibSerialPortPpi/PlatformHookLibSerialPortPpi.uni
new file mode 100644
index 0000000000..d88a279f8e
--- /dev/null
+++ b/Core/MdeModulePkg/Library/PlatformHookLibSerialPortPpi/PlatformHookLibSerialPortPpi.uni
Binary files differ
diff --git a/Core/MdeModulePkg/Library/PlatformVarCleanupLib/PlatVarCleanup.h b/Core/MdeModulePkg/Library/PlatformVarCleanupLib/PlatVarCleanup.h
new file mode 100644
index 0000000000..5290aae158
--- /dev/null
+++ b/Core/MdeModulePkg/Library/PlatformVarCleanupLib/PlatVarCleanup.h
@@ -0,0 +1,108 @@
+/** @file
+ Include file for platform variable cleanup.
+
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _PLAT_VAR_CLEANUP_
+#define _PLAT_VAR_CLEANUP_
+
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PrintLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/HiiLib.h>
+#include <Library/PlatformVarCleanupLib.h>
+
+#include <Protocol/Variable.h>
+#include <Protocol/VarCheck.h>
+#include <Protocol/FormBrowser2.h>
+#include <Protocol/HiiConfigAccess.h>
+#include <Protocol/HiiConfigRouting.h>
+#include <Protocol/DevicePath.h>
+
+#include <Guid/EventGroup.h>
+#include <Guid/MdeModuleHii.h>
+#include <Guid/ImageAuthentication.h>
+#include <Guid/VarErrorFlag.h>
+
+#include "PlatVarCleanupHii.h"
+
+//
+// This is the generated IFR binary data for each formset defined in VFR.
+// This data array is ready to be used as input of HiiAddPackages() to
+// create a packagelist (which contains Form packages, String packages, etc).
+//
+extern UINT8 PlatVarCleanupBin[];
+
+//
+// This is the generated String package data for all .UNI files.
+// This data array is ready to be used as input of HiiAddPackages() to
+// create a packagelist (which contains Form packages, String packages, etc).
+//
+extern UINT8 PlatformVarCleanupLibStrings[];
+
+#define USER_VARIABLE_NODE_SIGNATURE SIGNATURE_32 ('U', 'V', 'N', 'S')
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link;
+ EFI_GUID Guid;
+ CHAR16 *PromptString;
+ LIST_ENTRY NameLink;
+} USER_VARIABLE_NODE;
+
+#define USER_VARIABLE_FROM_LINK(a) CR (a, USER_VARIABLE_NODE, Link, USER_VARIABLE_NODE_SIGNATURE)
+
+#define USER_VARIABLE_NAME_NODE_SIGNATURE SIGNATURE_32 ('U', 'V', 'N', 'N')
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link;
+ CHAR16 *Name;
+ UINTN DataSize;
+ UINT32 Attributes;
+ UINT16 Index;
+ EFI_QUESTION_ID QuestionId;
+ CHAR16 *PromptString;
+ CHAR16 *HelpString;
+ BOOLEAN Deleted;
+} USER_VARIABLE_NAME_NODE;
+
+#define USER_VARIABLE_NAME_FROM_LINK(a) CR (a, USER_VARIABLE_NAME_NODE, Link, USER_VARIABLE_NAME_NODE_SIGNATURE)
+
+#pragma pack(1)
+//
+// HII specific Vendor Device Path definition.
+//
+typedef struct {
+ VENDOR_DEVICE_PATH VendorDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL End;
+} HII_VENDOR_DEVICE_PATH;
+#pragma pack()
+
+#define VARIABLE_CLEANUP_HII_PRIVATE_SIGNATURE SIGNATURE_32 ('V', 'C', 'H', 'P')
+
+typedef struct {
+ UINTN Signature;
+ EFI_HANDLE DriverHandle;
+ EFI_HII_HANDLE HiiHandle;
+ EFI_HII_CONFIG_ACCESS_PROTOCOL ConfigAccess;
+ EFI_HII_CONFIG_ROUTING_PROTOCOL *ConfigRouting;
+ VARIABLE_CLEANUP_DATA VariableCleanupData;
+} VARIABLE_CLEANUP_HII_PRIVATE_DATA;
+
+#define VARIABLE_CLEANUP_HII_PRIVATE_FROM_THIS(a) CR (a, VARIABLE_CLEANUP_HII_PRIVATE_DATA, ConfigAccess, VARIABLE_CLEANUP_HII_PRIVATE_SIGNATURE)
+
+#endif
diff --git a/Core/MdeModulePkg/Library/PlatformVarCleanupLib/PlatVarCleanup.vfr b/Core/MdeModulePkg/Library/PlatformVarCleanupLib/PlatVarCleanup.vfr
new file mode 100644
index 0000000000..7dfeafa2c4
--- /dev/null
+++ b/Core/MdeModulePkg/Library/PlatformVarCleanupLib/PlatVarCleanup.vfr
@@ -0,0 +1,41 @@
+/** @file
+ Platform variable cleanup Formset.
+
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "PlatVarCleanupHii.h"
+
+formset
+ guid = VARIABLE_CLEANUP_HII_GUID,
+ title = STRING_TOKEN(STR_ENTRY_TITLE),
+ help = STRING_TOKEN(STR_TITLE_HELP),
+
+ varstore VARIABLE_CLEANUP_DATA,
+ varid = VARIABLE_CLEANUP_VARSTORE_ID,
+ name = VariableCleanup,
+ guid = VARIABLE_CLEANUP_HII_GUID;
+
+ form formid = FORM_ID_VARIABLE_CLEANUP,
+ title = STRING_TOKEN(STR_TITLE);
+
+ checkbox varid = VARIABLE_CLEANUP_DATA.SelectAll,
+ prompt = STRING_TOKEN(STR_SELECT_ALL_PROMPT),
+ help = STRING_TOKEN(STR_SELECT_ALL_HELP),
+ flags = INTERACTIVE,
+ key = SELECT_ALL_QUESTION_ID,
+ endcheckbox;
+
+ label LABEL_START;
+ label LABEL_END;
+
+ endform;
+endformset;
diff --git a/Core/MdeModulePkg/Library/PlatformVarCleanupLib/PlatVarCleanupHii.h b/Core/MdeModulePkg/Library/PlatformVarCleanupLib/PlatVarCleanupHii.h
new file mode 100644
index 0000000000..02af877b44
--- /dev/null
+++ b/Core/MdeModulePkg/Library/PlatformVarCleanupLib/PlatVarCleanupHii.h
@@ -0,0 +1,59 @@
+/** @file
+ Include file for platform variable cleanup HII.
+
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _PLAT_VAR_CLEANUP_HII_
+#define _PLAT_VAR_CLEANUP_HII_
+
+//
+// {24F14D8A-D7A8-4991-91E0-96C3B7DB8456}
+//
+#define VARIABLE_CLEANUP_HII_GUID \
+ { \
+ 0x24f14d8a, 0xd7a8, 0x4991, { 0x91, 0xe0, 0x96, 0xc3, 0xb7, 0xdb, 0x84, 0x56 } \
+ }
+
+#define MAX_USER_VARIABLE_COUNT 0x1000
+
+typedef struct {
+ UINT8 SelectAll;
+ //
+ // FALSE is to not delete, TRUE is to delete.
+ //
+ UINT8 UserVariable[MAX_USER_VARIABLE_COUNT];
+} VARIABLE_CLEANUP_DATA;
+
+#define VARIABLE_CLEANUP_VARSTORE_ID 0x8000
+
+//
+// Field offset of structure VARIABLE_CLEANUP_DATA
+//
+#define VAR_OFFSET(Field) ((UINTN) &(((VARIABLE_CLEANUP_DATA *) 0)->Field))
+#define USER_VARIABLE_VAR_OFFSET (VAR_OFFSET (UserVariable))
+
+#define FORM_ID_VARIABLE_CLEANUP 0x8000
+
+#define LABEL_START 0x0000
+#define LABEL_END 0xFFFF
+
+#define SELECT_ALL_QUESTION_ID 0x7FFD
+#define SAVE_AND_EXIT_QUESTION_ID 0x7FFE
+#define NO_SAVE_AND_EXIT_QUESTION_ID 0x7FFF
+
+//
+// Tool automatic generated Question Id start from 1.
+// In order to avoid to conflict them, the user variable QuestionID offset is defined from 0x8000.
+//
+#define USER_VARIABLE_QUESTION_ID 0x8000
+
+#endif
diff --git a/Core/MdeModulePkg/Library/PlatformVarCleanupLib/PlatVarCleanupLib.c b/Core/MdeModulePkg/Library/PlatformVarCleanupLib/PlatVarCleanupLib.c
new file mode 100644
index 0000000000..d99174c4b9
--- /dev/null
+++ b/Core/MdeModulePkg/Library/PlatformVarCleanupLib/PlatVarCleanupLib.c
@@ -0,0 +1,1250 @@
+/** @file
+ Sample platform variable cleanup library implementation.
+
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "PlatVarCleanup.h"
+
+VAR_ERROR_FLAG mLastVarErrorFlag = VAR_ERROR_FLAG_NO_ERROR;
+EDKII_VAR_CHECK_PROTOCOL *mVarCheck = NULL;
+
+///
+/// The flag to indicate whether the platform has left the DXE phase of execution.
+///
+BOOLEAN mEndOfDxe = FALSE;
+
+LIST_ENTRY mUserVariableList = INITIALIZE_LIST_HEAD_VARIABLE (mUserVariableList);
+UINT16 mUserVariableCount = 0;
+UINT16 mMarkedUserVariableCount = 0;
+
+EFI_GUID mVariableCleanupHiiGuid = VARIABLE_CLEANUP_HII_GUID;
+CHAR16 mVarStoreName[] = L"VariableCleanup";
+
+HII_VENDOR_DEVICE_PATH mVarCleanupHiiVendorDevicePath = {
+ {
+ {
+ HARDWARE_DEVICE_PATH,
+ HW_VENDOR_DP,
+ {
+ (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
+ (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
+ }
+ },
+ VARIABLE_CLEANUP_HII_GUID
+ },
+ {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ {
+ (UINT8) (sizeof (EFI_DEVICE_PATH_PROTOCOL)),
+ (UINT8) ((sizeof (EFI_DEVICE_PATH_PROTOCOL)) >> 8)
+ }
+ }
+};
+
+/**
+ Internal get variable error flag.
+
+ @return Variable error flag.
+
+**/
+VAR_ERROR_FLAG
+InternalGetVarErrorFlag (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN Size;
+ VAR_ERROR_FLAG ErrorFlag;
+
+ Size = sizeof (ErrorFlag);
+ Status = gRT->GetVariable (
+ VAR_ERROR_FLAG_NAME,
+ &gEdkiiVarErrorFlagGuid,
+ NULL,
+ &Size,
+ &ErrorFlag
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_INFO, "%s - not found\n", VAR_ERROR_FLAG_NAME));
+ return VAR_ERROR_FLAG_NO_ERROR;
+ }
+ return ErrorFlag;
+}
+
+/**
+ Is user variable?
+
+ @param[in] Name Pointer to variable name.
+ @param[in] Guid Pointer to vendor guid.
+
+ @retval TRUE User variable.
+ @retval FALSE System variable.
+
+**/
+BOOLEAN
+IsUserVariable (
+ IN CHAR16 *Name,
+ IN EFI_GUID *Guid
+ )
+{
+ EFI_STATUS Status;
+ VAR_CHECK_VARIABLE_PROPERTY Property;
+
+ ZeroMem (&Property, sizeof (Property));
+ Status = mVarCheck->VariablePropertyGet (
+ Name,
+ Guid,
+ &Property
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // No property, it is user variable.
+ //
+ DEBUG ((EFI_D_INFO, "PlatformVarCleanup - User variable: %g:%s\n", Guid, Name));
+ return TRUE;
+ }
+
+// DEBUG ((EFI_D_INFO, "PlatformVarCleanup - Variable Property: %g:%s\n", Guid, Name));
+// DEBUG ((EFI_D_INFO, " Revision - 0x%04x\n", Property.Revision));
+// DEBUG ((EFI_D_INFO, " Property - 0x%04x\n", Property.Property));
+// DEBUG ((EFI_D_INFO, " Attribute - 0x%08x\n", Property.Attributes));
+// DEBUG ((EFI_D_INFO, " MinSize - 0x%x\n", Property.MinSize));
+// DEBUG ((EFI_D_INFO, " MaxSize - 0x%x\n", Property.MaxSize));
+
+ return FALSE;
+}
+
+/**
+ Find user variable node by variable GUID.
+
+ @param[in] Guid Pointer to vendor guid.
+
+ @return Pointer to user variable node.
+
+**/
+USER_VARIABLE_NODE *
+FindUserVariableNodeByGuid (
+ IN EFI_GUID *Guid
+ )
+{
+ USER_VARIABLE_NODE *UserVariableNode;
+ LIST_ENTRY *Link;
+
+ for (Link = mUserVariableList.ForwardLink
+ ;Link != &mUserVariableList
+ ;Link = Link->ForwardLink) {
+ UserVariableNode = USER_VARIABLE_FROM_LINK (Link);
+
+ if (CompareGuid (Guid, &UserVariableNode->Guid)) {
+ //
+ // Found it.
+ //
+ return UserVariableNode;
+ }
+ }
+
+ //
+ // Create new one if not found.
+ //
+ UserVariableNode = AllocateZeroPool (sizeof (*UserVariableNode));
+ ASSERT (UserVariableNode != NULL);
+ UserVariableNode->Signature = USER_VARIABLE_NODE_SIGNATURE;
+ CopyGuid (&UserVariableNode->Guid, Guid);
+ //
+ // (36 chars of "########-####-####-####-############" + 1 space + 1 terminator) * sizeof (CHAR16).
+ //
+ UserVariableNode->PromptString = AllocatePool ((36 + 2) * sizeof (CHAR16));
+ ASSERT (UserVariableNode->PromptString != NULL);
+ UnicodeSPrint (UserVariableNode->PromptString, (36 + 2) * sizeof (CHAR16), L" %g", &UserVariableNode->Guid);
+ InitializeListHead (&UserVariableNode->NameLink);
+ InsertTailList (&mUserVariableList, &UserVariableNode->Link);
+ return UserVariableNode;
+}
+
+/**
+ Create user variable node.
+
+**/
+VOID
+CreateUserVariableNode (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_STATUS GetVariableStatus;
+ CHAR16 *VarName;
+ UINTN MaxVarNameSize;
+ UINTN VarNameSize;
+ UINTN MaxDataSize;
+ UINTN DataSize;
+ VOID *Data;
+ UINT32 Attributes;
+ EFI_GUID Guid;
+ USER_VARIABLE_NODE *UserVariableNode;
+ USER_VARIABLE_NAME_NODE *UserVariableNameNode;
+ UINT16 Index;
+ UINTN StringSize;
+
+ //
+ // Initialize 128 * sizeof (CHAR16) variable name size.
+ //
+ MaxVarNameSize = 128 * sizeof (CHAR16);
+ VarName = AllocateZeroPool (MaxVarNameSize);
+ ASSERT (VarName != NULL);
+
+ //
+ // Initialize 0x1000 variable data size.
+ //
+ MaxDataSize = 0x1000;
+ Data = AllocateZeroPool (MaxDataSize);
+ ASSERT (Data != NULL);
+
+ Index = 0;
+ do {
+ VarNameSize = MaxVarNameSize;
+ Status = gRT->GetNextVariableName (&VarNameSize, VarName, &Guid);
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ VarName = ReallocatePool (MaxVarNameSize, VarNameSize, VarName);
+ ASSERT (VarName != NULL);
+ MaxVarNameSize = VarNameSize;
+ Status = gRT->GetNextVariableName (&VarNameSize, VarName, &Guid);
+ }
+
+ if (!EFI_ERROR (Status)) {
+ if (IsUserVariable (VarName, &Guid)) {
+ DataSize = MaxDataSize;
+ GetVariableStatus = gRT->GetVariable (VarName, &Guid, &Attributes, &DataSize, Data);
+ if (GetVariableStatus == EFI_BUFFER_TOO_SMALL) {
+ Data = ReallocatePool (MaxDataSize, DataSize, Data);
+ ASSERT (Data != NULL);
+ MaxDataSize = DataSize;
+ GetVariableStatus = gRT->GetVariable (VarName, &Guid, &Attributes, &DataSize, Data);
+ }
+ ASSERT_EFI_ERROR (GetVariableStatus);
+
+ if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
+ UserVariableNode = FindUserVariableNodeByGuid (&Guid);
+ ASSERT (UserVariableNode != NULL);
+
+ //
+ // Different variables that have same variable GUID share same user variable node.
+ //
+ UserVariableNameNode = AllocateZeroPool (sizeof (*UserVariableNameNode));
+ ASSERT (UserVariableNameNode != NULL);
+ UserVariableNameNode->Signature = USER_VARIABLE_NAME_NODE_SIGNATURE;
+ UserVariableNameNode->Name = AllocateCopyPool (VarNameSize, VarName);
+ UserVariableNameNode->Attributes = Attributes;
+ UserVariableNameNode->DataSize = DataSize;
+ UserVariableNameNode->Index = Index;
+ UserVariableNameNode->QuestionId = (EFI_QUESTION_ID) (USER_VARIABLE_QUESTION_ID + Index);
+ //
+ // 2 space * sizeof (CHAR16) + StrSize.
+ //
+ StringSize = 2 * sizeof (CHAR16) + StrSize (UserVariableNameNode->Name);
+ UserVariableNameNode->PromptString = AllocatePool (StringSize);
+ ASSERT (UserVariableNameNode->PromptString != NULL);
+ UnicodeSPrint (UserVariableNameNode->PromptString, StringSize, L" %s", UserVariableNameNode->Name);
+ //
+ // (33 chars of "Attribtues = 0x and DataSize = 0x" + 1 terminator + (sizeof (UINT32) + sizeof (UINTN)) * 2) * sizeof (CHAR16).
+ //
+ StringSize = (33 + 1 + (sizeof (UINT32) + sizeof (UINTN)) * 2) * sizeof (CHAR16);
+ UserVariableNameNode->HelpString = AllocatePool (StringSize);
+ ASSERT (UserVariableNameNode->HelpString != NULL);
+ UnicodeSPrint (UserVariableNameNode->HelpString, StringSize, L"Attribtues = 0x%08x and DataSize = 0x%x", UserVariableNameNode->Attributes, UserVariableNameNode->DataSize);
+ UserVariableNameNode->Deleted = FALSE;
+ InsertTailList (&UserVariableNode->NameLink, &UserVariableNameNode->Link);
+ Index++;
+ }
+ }
+ }
+ } while (Status != EFI_NOT_FOUND);
+
+ mUserVariableCount = Index;
+ ASSERT (mUserVariableCount <= MAX_USER_VARIABLE_COUNT);
+ DEBUG ((EFI_D_INFO, "PlatformVarCleanup - User variable count: 0x%04x\n", mUserVariableCount));
+
+ FreePool (VarName);
+ FreePool (Data);
+}
+
+/**
+ Destroy user variable nodes.
+
+**/
+VOID
+DestroyUserVariableNode (
+ VOID
+ )
+{
+ USER_VARIABLE_NODE *UserVariableNode;
+ LIST_ENTRY *Link;
+ USER_VARIABLE_NAME_NODE *UserVariableNameNode;
+ LIST_ENTRY *NameLink;
+
+ while (mUserVariableList.ForwardLink != &mUserVariableList) {
+ Link = mUserVariableList.ForwardLink;
+ UserVariableNode = USER_VARIABLE_FROM_LINK (Link);
+
+ RemoveEntryList (&UserVariableNode->Link);
+
+ while (UserVariableNode->NameLink.ForwardLink != &UserVariableNode->NameLink) {
+ NameLink = UserVariableNode->NameLink.ForwardLink;
+ UserVariableNameNode = USER_VARIABLE_NAME_FROM_LINK (NameLink);
+
+ RemoveEntryList (&UserVariableNameNode->Link);
+
+ FreePool (UserVariableNameNode->Name);
+ FreePool (UserVariableNameNode->PromptString);
+ FreePool (UserVariableNameNode->HelpString);
+ FreePool (UserVariableNameNode);
+ }
+
+ FreePool (UserVariableNode->PromptString);
+ FreePool (UserVariableNode);
+ }
+}
+
+/**
+ Create a time based data payload by concatenating the EFI_VARIABLE_AUTHENTICATION_2
+ descriptor with the input data. NO authentication is required in this function.
+
+ @param[in, out] DataSize On input, the size of Data buffer in bytes.
+ On output, the size of data returned in Data
+ buffer in bytes.
+ @param[in, out] Data On input, Pointer to data buffer to be wrapped or
+ pointer to NULL to wrap an empty payload.
+ On output, Pointer to the new payload date buffer allocated from pool,
+ it's caller's responsibility to free the memory after using it.
+
+ @retval EFI_SUCCESS Create time based payload successfully.
+ @retval EFI_OUT_OF_RESOURCES There are not enough memory resourses to create time based payload.
+ @retval EFI_INVALID_PARAMETER The parameter is invalid.
+ @retval Others Unexpected error happens.
+
+**/
+EFI_STATUS
+CreateTimeBasedPayload (
+ IN OUT UINTN *DataSize,
+ IN OUT UINT8 **Data
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *NewData;
+ UINT8 *Payload;
+ UINTN PayloadSize;
+ EFI_VARIABLE_AUTHENTICATION_2 *DescriptorData;
+ UINTN DescriptorSize;
+ EFI_TIME Time;
+
+ if (Data == NULL || DataSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // At user physical presence, the variable does not need to be signed but the
+ // parameters to the SetVariable() call still need to be prepared as authenticated
+ // variable. So we create EFI_VARIABLE_AUTHENTICATED_2 descriptor without certificate
+ // data in it.
+ //
+ Payload = *Data;
+ PayloadSize = *DataSize;
+
+ DescriptorSize = OFFSET_OF (EFI_VARIABLE_AUTHENTICATION_2, AuthInfo) + OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData);
+ NewData = (UINT8 *) AllocateZeroPool (DescriptorSize + PayloadSize);
+ if (NewData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if ((Payload != NULL) && (PayloadSize != 0)) {
+ CopyMem (NewData + DescriptorSize, Payload, PayloadSize);
+ }
+
+ DescriptorData = (EFI_VARIABLE_AUTHENTICATION_2 *) (NewData);
+
+ ZeroMem (&Time, sizeof (EFI_TIME));
+ Status = gRT->GetTime (&Time, NULL);
+ if (EFI_ERROR (Status)) {
+ FreePool (NewData);
+ return Status;
+ }
+ Time.Pad1 = 0;
+ Time.Nanosecond = 0;
+ Time.TimeZone = 0;
+ Time.Daylight = 0;
+ Time.Pad2 = 0;
+ CopyMem (&DescriptorData->TimeStamp, &Time, sizeof (EFI_TIME));
+
+ DescriptorData->AuthInfo.Hdr.dwLength = OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData);
+ DescriptorData->AuthInfo.Hdr.wRevision = 0x0200;
+ DescriptorData->AuthInfo.Hdr.wCertificateType = WIN_CERT_TYPE_EFI_GUID;
+ CopyGuid (&DescriptorData->AuthInfo.CertType, &gEfiCertPkcs7Guid);
+
+ if (Payload != NULL) {
+ FreePool (Payload);
+ }
+
+ *DataSize = DescriptorSize + PayloadSize;
+ *Data = NewData;
+ return EFI_SUCCESS;
+}
+
+/**
+ Create a counter based data payload by concatenating the EFI_VARIABLE_AUTHENTICATION
+ descriptor with the input data. NO authentication is required in this function.
+
+ @param[in, out] DataSize On input, the size of Data buffer in bytes.
+ On output, the size of data returned in Data
+ buffer in bytes.
+ @param[in, out] Data On input, Pointer to data buffer to be wrapped or
+ pointer to NULL to wrap an empty payload.
+ On output, Pointer to the new payload date buffer allocated from pool,
+ it's caller's responsibility to free the memory after using it.
+
+ @retval EFI_SUCCESS Create counter based payload successfully.
+ @retval EFI_OUT_OF_RESOURCES There are not enough memory resourses to create time based payload.
+ @retval EFI_INVALID_PARAMETER The parameter is invalid.
+ @retval Others Unexpected error happens.
+
+**/
+EFI_STATUS
+CreateCounterBasedPayload (
+ IN OUT UINTN *DataSize,
+ IN OUT UINT8 **Data
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *NewData;
+ UINT8 *Payload;
+ UINTN PayloadSize;
+ EFI_VARIABLE_AUTHENTICATION *DescriptorData;
+ UINTN DescriptorSize;
+ UINT64 MonotonicCount;
+
+ if (Data == NULL || DataSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // At user physical presence, the variable does not need to be signed but the
+ // parameters to the SetVariable() call still need to be prepared as authenticated
+ // variable. So we create EFI_VARIABLE_AUTHENTICATED descriptor without certificate
+ // data in it.
+ //
+ Payload = *Data;
+ PayloadSize = *DataSize;
+
+ DescriptorSize = (OFFSET_OF (EFI_VARIABLE_AUTHENTICATION, AuthInfo)) + \
+ (OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData)) + \
+ sizeof (EFI_CERT_BLOCK_RSA_2048_SHA256);
+ NewData = (UINT8 *) AllocateZeroPool (DescriptorSize + PayloadSize);
+ if (NewData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if ((Payload != NULL) && (PayloadSize != 0)) {
+ CopyMem (NewData + DescriptorSize, Payload, PayloadSize);
+ }
+
+ DescriptorData = (EFI_VARIABLE_AUTHENTICATION *) (NewData);
+
+ Status = gBS->GetNextMonotonicCount (&MonotonicCount);
+ if (EFI_ERROR (Status)) {
+ FreePool (NewData);
+ return Status;
+ }
+ DescriptorData->MonotonicCount = MonotonicCount;
+
+ DescriptorData->AuthInfo.Hdr.dwLength = OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData) + sizeof (EFI_CERT_BLOCK_RSA_2048_SHA256);
+ DescriptorData->AuthInfo.Hdr.wRevision = 0x0200;
+ DescriptorData->AuthInfo.Hdr.wCertificateType = WIN_CERT_TYPE_EFI_GUID;
+ CopyGuid (&DescriptorData->AuthInfo.CertType, &gEfiCertTypeRsa2048Sha256Guid);
+
+ if (Payload != NULL) {
+ FreePool (Payload);
+ }
+
+ *DataSize = DescriptorSize + PayloadSize;
+ *Data = NewData;
+ return EFI_SUCCESS;
+}
+
+/**
+ Delete user variable.
+
+ @param[in] DeleteAll Delete all user variables.
+ @param[in] VariableCleanupData Pointer to variable cleanup data.
+
+**/
+VOID
+DeleteUserVariable (
+ IN BOOLEAN DeleteAll,
+ IN VARIABLE_CLEANUP_DATA *VariableCleanupData OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ USER_VARIABLE_NODE *UserVariableNode;
+ LIST_ENTRY *Link;
+ USER_VARIABLE_NAME_NODE *UserVariableNameNode;
+ LIST_ENTRY *NameLink;
+ UINTN DataSize;
+ UINT8 *Data;
+
+ for (Link = mUserVariableList.ForwardLink
+ ;Link != &mUserVariableList
+ ;Link = Link->ForwardLink) {
+ UserVariableNode = USER_VARIABLE_FROM_LINK (Link);
+
+ for (NameLink = UserVariableNode->NameLink.ForwardLink
+ ;NameLink != &UserVariableNode->NameLink
+ ;NameLink = NameLink->ForwardLink) {
+ UserVariableNameNode = USER_VARIABLE_NAME_FROM_LINK (NameLink);
+
+ if (!UserVariableNameNode->Deleted && (DeleteAll || ((VariableCleanupData != NULL) && (VariableCleanupData->UserVariable[UserVariableNameNode->Index] == TRUE)))) {
+ DEBUG ((EFI_D_INFO, "PlatformVarCleanup - Delete variable: %g:%s\n", &UserVariableNode->Guid, UserVariableNameNode->Name));
+ if ((UserVariableNameNode->Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {
+ DataSize = 0;
+ Data = NULL;
+ Status = CreateTimeBasedPayload (&DataSize, &Data);
+ if (!EFI_ERROR (Status)) {
+ Status = gRT->SetVariable (UserVariableNameNode->Name, &UserVariableNode->Guid, UserVariableNameNode->Attributes, DataSize, Data);
+ FreePool (Data);
+ }
+ } else if ((UserVariableNameNode->Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {
+ DataSize = 0;
+ Data = NULL;
+ Status = CreateCounterBasedPayload (&DataSize, &Data);
+ if (!EFI_ERROR (Status)) {
+ Status = gRT->SetVariable (UserVariableNameNode->Name, &UserVariableNode->Guid, UserVariableNameNode->Attributes, DataSize, Data);
+ FreePool (Data);
+ }
+ } else {
+ Status = gRT->SetVariable (UserVariableNameNode->Name, &UserVariableNode->Guid, 0, 0, NULL);
+ }
+ if (!EFI_ERROR (Status)) {
+ UserVariableNameNode->Deleted = TRUE;
+ } else {
+ DEBUG ((EFI_D_INFO, "PlatformVarCleanup - Delete variable fail: %g:%s\n", &UserVariableNode->Guid, UserVariableNameNode->Name));
+ }
+ }
+ }
+ }
+}
+
+/**
+ This function allows a caller to extract the current configuration for one
+ or more named elements from the target driver.
+
+ @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param[in] Request A null-terminated Unicode string in <ConfigRequest> format.
+ @param[out] Progress On return, points to a character in the Request string.
+ Points to the string's null terminator if request was successful.
+ Points to the most recent '&' before the first failing name/value
+ pair (or the beginning of the string if the failure is in the
+ first name/value pair) if the request was not successful.
+ @param[out] Results A null-terminated Unicode string in <ConfigAltResp> format which
+ has all values filled in for the names in the Request string.
+ String to be allocated by the called function.
+
+ @retval EFI_SUCCESS The Results is filled with the requested values.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results.
+ @retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name.
+ @retval EFI_NOT_FOUND Routing data doesn't match any storage in this driver.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableCleanupHiiExtractConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Request,
+ OUT EFI_STRING *Progress,
+ OUT EFI_STRING *Results
+ )
+{
+ EFI_STATUS Status;
+ VARIABLE_CLEANUP_HII_PRIVATE_DATA *Private;
+ UINTN BufferSize;
+ EFI_STRING ConfigRequestHdr;
+ EFI_STRING ConfigRequest;
+ BOOLEAN AllocatedRequest;
+ UINTN Size;
+
+ if (Progress == NULL || Results == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *Progress = Request;
+ if ((Request != NULL) && !HiiIsConfigHdrMatch (Request, &mVariableCleanupHiiGuid, mVarStoreName)) {
+ return EFI_NOT_FOUND;
+ }
+
+ ConfigRequestHdr = NULL;
+ ConfigRequest = NULL;
+ AllocatedRequest = FALSE;
+ Size = 0;
+
+ Private = VARIABLE_CLEANUP_HII_PRIVATE_FROM_THIS (This);
+ //
+ // Convert buffer data to <ConfigResp> by helper function BlockToConfig().
+ //
+ BufferSize = sizeof (VARIABLE_CLEANUP_DATA);
+ ConfigRequest = Request;
+ if ((Request == NULL) || (StrStr (Request, L"OFFSET") == NULL)) {
+ //
+ // Request has no request element, construct full request string.
+ // Allocate and fill a buffer large enough to hold the <ConfigHdr> template
+ // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator.
+ //
+ ConfigRequestHdr = HiiConstructConfigHdr (&mVariableCleanupHiiGuid, mVarStoreName, Private->HiiHandle);
+ Size = (StrLen (ConfigRequestHdr) + 32 + 1) * sizeof (CHAR16);
+ ConfigRequest = AllocateZeroPool (Size);
+ ASSERT (ConfigRequest != NULL);
+ AllocatedRequest = TRUE;
+ UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=0&WIDTH=%016LX", ConfigRequestHdr, (UINT64)BufferSize);
+ FreePool (ConfigRequestHdr);
+ }
+
+ Status = Private->ConfigRouting->BlockToConfig (
+ Private->ConfigRouting,
+ ConfigRequest,
+ (UINT8 *) &Private->VariableCleanupData,
+ BufferSize,
+ Results,
+ Progress
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Free the allocated config request string.
+ //
+ if (AllocatedRequest) {
+ FreePool (ConfigRequest);
+ ConfigRequest = NULL;
+ }
+ //
+ // Set Progress string to the original request string or the string's null terminator.
+ //
+ if (Request == NULL) {
+ *Progress = NULL;
+ } else if (StrStr (Request, L"OFFSET") == NULL) {
+ *Progress = Request + StrLen (Request);
+ }
+
+ return Status;
+}
+
+/**
+ Update user variable form.
+
+ @param[in] Private Points to the VARIABLE_CLEANUP_HII_PRIVATE_DATA.
+
+**/
+VOID
+UpdateUserVariableForm (
+ IN VARIABLE_CLEANUP_HII_PRIVATE_DATA *Private
+ )
+{
+ EFI_STRING_ID PromptStringToken;
+ EFI_STRING_ID HelpStringToken;
+ VOID *StartOpCodeHandle;
+ VOID *EndOpCodeHandle;
+ EFI_IFR_GUID_LABEL *StartLabel;
+ EFI_IFR_GUID_LABEL *EndLabel;
+ USER_VARIABLE_NODE *UserVariableNode;
+ LIST_ENTRY *Link;
+ USER_VARIABLE_NAME_NODE *UserVariableNameNode;
+ LIST_ENTRY *NameLink;
+ BOOLEAN Created;
+
+ //
+ // Init OpCode Handle.
+ //
+ StartOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (StartOpCodeHandle != NULL);
+
+ EndOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (EndOpCodeHandle != NULL);
+
+ //
+ // Create Hii Extend Label OpCode as the start opcode.
+ //
+ StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (StartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
+ StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
+ StartLabel->Number = LABEL_START;
+
+ //
+ // Create Hii Extend Label OpCode as the end opcode.
+ //
+ EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (EndOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
+ EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
+ EndLabel->Number = LABEL_END;
+
+ HiiUpdateForm (
+ Private->HiiHandle,
+ &mVariableCleanupHiiGuid,
+ FORM_ID_VARIABLE_CLEANUP,
+ StartOpCodeHandle, // LABEL_START
+ EndOpCodeHandle // LABEL_END
+ );
+
+ for (Link = mUserVariableList.ForwardLink
+ ;Link != &mUserVariableList
+ ;Link = Link->ForwardLink) {
+ UserVariableNode = USER_VARIABLE_FROM_LINK (Link);
+
+ //
+ // Create checkbox opcode for variables in the same variable GUID space.
+ //
+ Created = FALSE;
+ for (NameLink = UserVariableNode->NameLink.ForwardLink
+ ;NameLink != &UserVariableNode->NameLink
+ ;NameLink = NameLink->ForwardLink) {
+ UserVariableNameNode = USER_VARIABLE_NAME_FROM_LINK (NameLink);
+
+ if (!UserVariableNameNode->Deleted) {
+ if (!Created) {
+ //
+ // Create subtitle opcode for variable GUID.
+ //
+ PromptStringToken = HiiSetString (Private->HiiHandle, 0, UserVariableNode->PromptString, NULL);
+ HiiCreateSubTitleOpCode (StartOpCodeHandle, PromptStringToken, 0, 0, 0);
+ Created = TRUE;
+ }
+
+ //
+ // Only create opcode for the non-deleted variables.
+ //
+ PromptStringToken = HiiSetString (Private->HiiHandle, 0, UserVariableNameNode->PromptString, NULL);
+ HelpStringToken = HiiSetString (Private->HiiHandle, 0, UserVariableNameNode->HelpString, NULL);
+ HiiCreateCheckBoxOpCode (
+ StartOpCodeHandle,
+ UserVariableNameNode->QuestionId,
+ VARIABLE_CLEANUP_VARSTORE_ID,
+ (UINT16) (USER_VARIABLE_VAR_OFFSET + UserVariableNameNode->Index),
+ PromptStringToken,
+ HelpStringToken,
+ EFI_IFR_FLAG_CALLBACK,
+ Private->VariableCleanupData.UserVariable[UserVariableNameNode->Index],
+ NULL
+ );
+ }
+ }
+ }
+
+ HiiCreateSubTitleOpCode (
+ StartOpCodeHandle,
+ STRING_TOKEN (STR_NULL_STRING),
+ 0,
+ 0,
+ 0
+ );
+
+ //
+ // Create the "Apply changes" and "Discard changes" tags.
+ //
+ HiiCreateActionOpCode (
+ StartOpCodeHandle,
+ SAVE_AND_EXIT_QUESTION_ID,
+ STRING_TOKEN (STR_SAVE_AND_EXIT),
+ STRING_TOKEN (STR_NULL_STRING),
+ EFI_IFR_FLAG_CALLBACK,
+ 0
+ );
+ HiiCreateActionOpCode (
+ StartOpCodeHandle,
+ NO_SAVE_AND_EXIT_QUESTION_ID,
+ STRING_TOKEN (STR_NO_SAVE_AND_EXIT),
+ STRING_TOKEN (STR_NULL_STRING),
+ EFI_IFR_FLAG_CALLBACK,
+ 0
+ );
+
+ HiiUpdateForm (
+ Private->HiiHandle,
+ &mVariableCleanupHiiGuid,
+ FORM_ID_VARIABLE_CLEANUP,
+ StartOpCodeHandle, // LABEL_START
+ EndOpCodeHandle // LABEL_END
+ );
+
+ HiiFreeOpCodeHandle (StartOpCodeHandle);
+ HiiFreeOpCodeHandle (EndOpCodeHandle);
+}
+
+/**
+ This function applies changes in a driver's configuration.
+ Input is a Configuration, which has the routing data for this
+ driver followed by name / value configuration pairs. The driver
+ must apply those pairs to its configurable storage. If the
+ driver's configuration is stored in a linear block of data
+ and the driver's name / value pairs are in <BlockConfig>
+ format, it may use the ConfigToBlock helper function (above) to
+ simplify the job. Currently not implemented.
+
+ @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param[in] Configuration A null-terminated Unicode string in
+ <ConfigString> format.
+ @param[out] Progress A pointer to a string filled in with the
+ offset of the most recent '&' before the
+ first failing name / value pair (or the
+ beginn ing of the string if the failure
+ is in the first name / value pair) or
+ the terminating NULL if all was
+ successful.
+
+ @retval EFI_SUCCESS The results have been distributed or are
+ awaiting distribution.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to store the
+ parts of the results that must be
+ stored awaiting possible future
+ protocols.
+ @retval EFI_INVALID_PARAMETERS Passing in a NULL for the
+ Results parameter would result
+ in this type of error.
+ @retval EFI_NOT_FOUND Target for the specified routing data
+ was not found.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableCleanupHiiRouteConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Configuration,
+ OUT EFI_STRING *Progress
+ )
+{
+ EFI_STATUS Status;
+ VARIABLE_CLEANUP_HII_PRIVATE_DATA *Private;
+ UINTN BufferSize;
+
+ if (Progress == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ *Progress = Configuration;
+
+ if (Configuration == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check routing data in <ConfigHdr>.
+ // Note: there is no name for Name/Value storage, only GUID will be checked.
+ //
+ if (!HiiIsConfigHdrMatch (Configuration, &mVariableCleanupHiiGuid, mVarStoreName)) {
+ return EFI_NOT_FOUND;
+ }
+
+ Private = VARIABLE_CLEANUP_HII_PRIVATE_FROM_THIS (This);
+ //
+ // Get Buffer Storage data.
+ //
+ BufferSize = sizeof (VARIABLE_CLEANUP_DATA);
+ //
+ // Convert <ConfigResp> to buffer data by helper function ConfigToBlock().
+ //
+ Status = Private->ConfigRouting->ConfigToBlock (
+ Private->ConfigRouting,
+ Configuration,
+ (UINT8 *) &Private->VariableCleanupData,
+ &BufferSize,
+ Progress
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ DeleteUserVariable (FALSE, &Private->VariableCleanupData);
+ //
+ // For "F10" hotkey to refresh the form.
+ //
+// UpdateUserVariableForm (Private);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function is called to provide results data to the driver.
+ This data consists of a unique key that is used to identify
+ which data is either being passed back or being asked for.
+
+ @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param[in] Action Specifies the type of action taken by the browser.
+ @param[in] QuestionId A unique value which is sent to the original
+ exporting driver so that it can identify the type
+ of data to expect. The format of the data tends to
+ vary based on the opcode that generated the callback.
+ @param[in] Type The type of value for the question.
+ @param[in] Value A pointer to the data being sent to the original
+ exporting driver.
+ @param[out] ActionRequest On return, points to the action requested by the
+ callback function.
+
+ @retval EFI_SUCCESS The callback successfully handled the action.
+ @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the
+ variable and its data.
+ @retval EFI_DEVICE_ERROR The variable could not be saved.
+ @retval EFI_UNSUPPORTED The specified Action is not supported by the
+ callback.
+**/
+EFI_STATUS
+EFIAPI
+VariableCleanupHiiCallback (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN EFI_BROWSER_ACTION Action,
+ IN EFI_QUESTION_ID QuestionId,
+ IN UINT8 Type,
+ IN EFI_IFR_TYPE_VALUE *Value,
+ OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
+ )
+{
+ VARIABLE_CLEANUP_HII_PRIVATE_DATA *Private;
+ VARIABLE_CLEANUP_DATA *VariableCleanupData;
+
+ Private = VARIABLE_CLEANUP_HII_PRIVATE_FROM_THIS (This);
+
+ if ((Action != EFI_BROWSER_ACTION_CHANGING) && (Action != EFI_BROWSER_ACTION_CHANGED)) {
+ //
+ // All other action return unsupported.
+ //
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Retrive uncommitted data from Form Browser.
+ //
+ VariableCleanupData = &Private->VariableCleanupData;
+ HiiGetBrowserData (&mVariableCleanupHiiGuid, mVarStoreName, sizeof (VARIABLE_CLEANUP_DATA), (UINT8 *) VariableCleanupData);
+ if (Action == EFI_BROWSER_ACTION_CHANGING) {
+ if (Value == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ } else if (Action == EFI_BROWSER_ACTION_CHANGED) {
+ if ((Value == NULL) || (ActionRequest == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if ((QuestionId >= USER_VARIABLE_QUESTION_ID) && (QuestionId < USER_VARIABLE_QUESTION_ID + MAX_USER_VARIABLE_COUNT)) {
+ if (Value->b){
+ //
+ // Means one user variable checkbox is marked to delete but not press F10 or "Commit Changes and Exit" menu.
+ //
+ mMarkedUserVariableCount++;
+ ASSERT (mMarkedUserVariableCount <= mUserVariableCount);
+ if (mMarkedUserVariableCount == mUserVariableCount) {
+ //
+ // All user variables have been marked, then also mark the SelectAll checkbox.
+ //
+ VariableCleanupData->SelectAll = TRUE;
+ }
+ } else {
+ //
+ // Means one user variable checkbox is unmarked.
+ //
+ mMarkedUserVariableCount--;
+ //
+ // Also unmark the SelectAll checkbox.
+ //
+ VariableCleanupData->SelectAll = FALSE;
+ }
+ } else {
+ switch (QuestionId) {
+ case SELECT_ALL_QUESTION_ID:
+ if (Value->b){
+ //
+ // Means the SelectAll checkbox is marked to delete all user variables but not press F10 or "Commit Changes and Exit" menu.
+ //
+ SetMem (VariableCleanupData->UserVariable, sizeof (VariableCleanupData->UserVariable), TRUE);
+ mMarkedUserVariableCount = mUserVariableCount;
+ } else {
+ //
+ // Means the SelectAll checkbox is unmarked.
+ //
+ SetMem (VariableCleanupData->UserVariable, sizeof (VariableCleanupData->UserVariable), FALSE);
+ mMarkedUserVariableCount = 0;
+ }
+ break;
+ case SAVE_AND_EXIT_QUESTION_ID:
+ DeleteUserVariable (FALSE, VariableCleanupData);
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT;
+ break;
+
+ case NO_SAVE_AND_EXIT_QUESTION_ID:
+ //
+ // Restore local maintain data.
+ //
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT;
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ //
+ // Pass changed uncommitted data back to Form Browser.
+ //
+ HiiSetBrowserData (&mVariableCleanupHiiGuid, mVarStoreName, sizeof (VARIABLE_CLEANUP_DATA), (UINT8 *) VariableCleanupData, NULL);
+ return EFI_SUCCESS;
+}
+
+/**
+ Platform variable cleanup.
+
+ @param[in] Flag Variable error flag.
+ @param[in] Type Variable cleanup type.
+ If it is VarCleanupManually, the interface must be called after console connected.
+
+ @retval EFI_SUCCESS No error or error processed.
+ @retval EFI_UNSUPPORTED The specified Flag or Type is not supported.
+ For example, system error may be not supported to process and Platform should have mechanism to reset system to manufacture mode.
+ Another, if system and user variables are wanted to be distinguished to process, the interface must be called after EndOfDxe.
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to process the error.
+ @retval EFI_INVALID_PARAMETER The specified Flag or Type is an invalid value.
+ @retval Others Other failure occurs.
+
+**/
+EFI_STATUS
+EFIAPI
+PlatformVarCleanup (
+ IN VAR_ERROR_FLAG Flag,
+ IN VAR_CLEANUP_TYPE Type
+ )
+{
+ EFI_STATUS Status;
+ EFI_FORM_BROWSER2_PROTOCOL *FormBrowser2;
+ VARIABLE_CLEANUP_HII_PRIVATE_DATA *Private;
+
+ if (!mEndOfDxe) {
+ //
+ // This implementation must be called after EndOfDxe.
+ //
+ return EFI_UNSUPPORTED;
+ }
+
+ if ((Type >= VarCleanupMax) || ((Flag & ((VAR_ERROR_FLAG) (VAR_ERROR_FLAG_SYSTEM_ERROR & VAR_ERROR_FLAG_USER_ERROR))) == 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Flag == VAR_ERROR_FLAG_NO_ERROR) {
+ //
+ // Just return success if no error.
+ //
+ return EFI_SUCCESS;
+ }
+
+ if ((Flag & (~((VAR_ERROR_FLAG) VAR_ERROR_FLAG_SYSTEM_ERROR))) == 0) {
+ //
+ // This sample does not support system variables cleanup.
+ //
+ DEBUG ((EFI_D_ERROR, "NOTICE - VAR_ERROR_FLAG_SYSTEM_ERROR\n"));
+ DEBUG ((EFI_D_ERROR, "Platform should have mechanism to reset system to manufacture mode\n"));
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Continue to process VAR_ERROR_FLAG_USER_ERROR.
+ //
+
+ //
+ // Create user variable nodes for the following processing.
+ //
+ CreateUserVariableNode ();
+
+ switch (Type) {
+ case VarCleanupAll:
+ DeleteUserVariable (TRUE, NULL);
+ //
+ // Destroyed the created user variable nodes
+ //
+ DestroyUserVariableNode ();
+ return EFI_SUCCESS;
+ break;
+
+ case VarCleanupManually:
+ //
+ // Locate FormBrowser2 protocol.
+ //
+ Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **) &FormBrowser2);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Private = AllocateZeroPool (sizeof (VARIABLE_CLEANUP_HII_PRIVATE_DATA));
+ if (Private == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Private->Signature = VARIABLE_CLEANUP_HII_PRIVATE_SIGNATURE;
+ Private->ConfigAccess.ExtractConfig = VariableCleanupHiiExtractConfig;
+ Private->ConfigAccess.RouteConfig = VariableCleanupHiiRouteConfig;
+ Private->ConfigAccess.Callback = VariableCleanupHiiCallback;
+
+ Status = gBS->LocateProtocol (
+ &gEfiHiiConfigRoutingProtocolGuid,
+ NULL,
+ (VOID **) &Private->ConfigRouting
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Install Device Path Protocol and Config Access protocol to driver handle.
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Private->DriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mVarCleanupHiiVendorDevicePath,
+ &gEfiHiiConfigAccessProtocolGuid,
+ &Private->ConfigAccess,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Publish our HII data.
+ //
+ Private->HiiHandle = HiiAddPackages (
+ &mVariableCleanupHiiGuid,
+ Private->DriverHandle,
+ PlatformVarCleanupLibStrings,
+ PlatVarCleanupBin,
+ NULL
+ );
+ if (Private->HiiHandle == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ UpdateUserVariableForm (Private);
+
+ Status = FormBrowser2->SendForm (
+ FormBrowser2,
+ &Private->HiiHandle,
+ 1,
+ NULL,
+ 0,
+ NULL,
+ NULL
+ );
+ break;
+
+ default:
+ return EFI_UNSUPPORTED;
+ break;
+ }
+
+Done:
+ if (Private->DriverHandle != NULL) {
+ gBS->UninstallMultipleProtocolInterfaces (
+ Private->DriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mVarCleanupHiiVendorDevicePath,
+ &gEfiHiiConfigAccessProtocolGuid,
+ &Private->ConfigAccess,
+ NULL
+ );
+ }
+ if (Private->HiiHandle != NULL) {
+ HiiRemovePackages (Private->HiiHandle);
+ }
+
+ FreePool (Private);
+
+ //
+ // Destroyed the created user variable nodes
+ //
+ DestroyUserVariableNode ();
+ return Status;
+}
+
+/**
+ Get last boot variable error flag.
+
+ @return Last boot variable error flag.
+
+**/
+VAR_ERROR_FLAG
+EFIAPI
+GetLastBootVarErrorFlag (
+ )
+{
+ return mLastVarErrorFlag;
+}
+
+/**
+ Notification function of END_OF_DXE.
+
+ This is a notification function registered on END_OF_DXE event.
+
+ @param[in] Event Event whose notification function is being invoked.
+ @param[in] Context Pointer to the notification function's context.
+
+**/
+VOID
+EFIAPI
+PlatformVarCleanupEndOfDxeEvent (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ mEndOfDxe = TRUE;
+}
+
+/**
+ The constructor function caches the pointer to VarCheck protocol and last boot variable error flag.
+
+ The constructor function locates VarCheck protocol from protocol database.
+ It will ASSERT() if that operation fails and it will always return EFI_SUCCESS.
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
+
+**/
+EFI_STATUS
+EFIAPI
+PlatformVarCleanupLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_EVENT Event;
+
+ mLastVarErrorFlag = InternalGetVarErrorFlag ();
+ DEBUG ((EFI_D_INFO, "mLastVarErrorFlag - 0x%02x\n", mLastVarErrorFlag));
+
+ Status = gBS->LocateProtocol (
+ &gEdkiiVarCheckProtocolGuid,
+ NULL,
+ (VOID **) &mVarCheck
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Register EFI_END_OF_DXE_EVENT_GROUP_GUID event.
+ //
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ PlatformVarCleanupEndOfDxeEvent,
+ NULL,
+ &gEfiEndOfDxeEventGroupGuid,
+ &Event
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
+
diff --git a/Core/MdeModulePkg/Library/PlatformVarCleanupLib/PlatformVarCleanupLib.inf b/Core/MdeModulePkg/Library/PlatformVarCleanupLib/PlatformVarCleanupLib.inf
new file mode 100644
index 0000000000..c56a17584a
--- /dev/null
+++ b/Core/MdeModulePkg/Library/PlatformVarCleanupLib/PlatformVarCleanupLib.inf
@@ -0,0 +1,73 @@
+## @file
+# Sample platform variable cleanup library instance.
+#
+# Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions
+# of the BSD License which accompanies this distribution. The
+# full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PlatformVarCleanupLib
+ MODULE_UNI_FILE = PlatformVarCleanupLib.uni
+ FILE_GUID = 9C9623EB-4EF3-44e0-A931-F3A340D1A0F9
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = PlatformVarCleanupLib|DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SAL_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER
+ CONSTRUCTOR = PlatformVarCleanupLibConstructor
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources.common]
+ PlatVarCleanupLib.c
+ PlatVarCleanup.h
+ PlatVarCleanupHii.h
+ PlatVarCleanup.vfr
+ VfrStrings.uni
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiBootServicesTableLib
+ UefiRuntimeServicesTableLib
+ UefiLib
+ BaseLib
+ DebugLib
+ BaseMemoryLib
+ PrintLib
+ MemoryAllocationLib
+ HiiLib
+
+[Guids]
+ gEfiIfrTianoGuid ## SOMETIMES_PRODUCES ## GUID
+ gEdkiiVarErrorFlagGuid ## CONSUMES ## Variable:L"VarErrorFlag"
+ gEfiEndOfDxeEventGroupGuid ## CONSUMES ## Event
+ gEfiCertPkcs7Guid ## SOMETIMES_CONSUMES ## GUID
+ gEfiCertTypeRsa2048Sha256Guid ## SOMETIMES_CONSUMES ## GUID
+
+[Protocols]
+ gEfiVariableArchProtocolGuid ## CONSUMES
+ gEdkiiVarCheckProtocolGuid ## CONSUMES
+ gEfiDevicePathProtocolGuid ## SOMETIMES_PRODUCES
+ gEfiFormBrowser2ProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiHiiConfigAccessProtocolGuid ## SOMETIMES_PRODUCES
+ gEfiHiiConfigRoutingProtocolGuid ## SOMETIMES_CONSUMES
+
+[Depex]
+ gEdkiiVarCheckProtocolGuid AND
+ gEfiVariableArchProtocolGuid
+
diff --git a/Core/MdeModulePkg/Library/PlatformVarCleanupLib/PlatformVarCleanupLib.uni b/Core/MdeModulePkg/Library/PlatformVarCleanupLib/PlatformVarCleanupLib.uni
new file mode 100644
index 0000000000..e4a0debafa
--- /dev/null
+++ b/Core/MdeModulePkg/Library/PlatformVarCleanupLib/PlatformVarCleanupLib.uni
Binary files differ
diff --git a/Core/MdeModulePkg/Library/PlatformVarCleanupLib/VfrStrings.uni b/Core/MdeModulePkg/Library/PlatformVarCleanupLib/VfrStrings.uni
new file mode 100644
index 0000000000..56f8e3625f
--- /dev/null
+++ b/Core/MdeModulePkg/Library/PlatformVarCleanupLib/VfrStrings.uni
Binary files differ
diff --git a/Core/MdeModulePkg/Library/RuntimeDxeReportStatusCodeLib/ReportStatusCodeLib.c b/Core/MdeModulePkg/Library/RuntimeDxeReportStatusCodeLib/ReportStatusCodeLib.c
new file mode 100644
index 0000000000..e533af3d33
--- /dev/null
+++ b/Core/MdeModulePkg/Library/RuntimeDxeReportStatusCodeLib/ReportStatusCodeLib.c
@@ -0,0 +1,754 @@
+/** @file
+ API implementation for instance of Report Status Code Library.
+
+ Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PcdLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/UefiRuntimeLib.h>
+
+#include <Protocol/StatusCode.h>
+
+#include <Guid/StatusCodeDataTypeId.h>
+#include <Guid/StatusCodeDataTypeDebug.h>
+#include <Guid/EventGroup.h>
+
+
+//
+// Define the maximum extended data size that is supported when a status code is reported.
+//
+#define MAX_EXTENDED_DATA_SIZE 0x200
+
+EFI_STATUS_CODE_PROTOCOL *mReportStatusCodeLibStatusCodeProtocol = NULL;
+EFI_EVENT mReportStatusCodeLibVirtualAddressChangeEvent;
+EFI_EVENT mReportStatusCodeLibExitBootServicesEvent;
+BOOLEAN mHaveExitedBootServices = FALSE;
+
+/**
+ Locate the report status code service.
+
+ Retrieve ReportStatusCode() API of Report Status Code Protocol.
+
+**/
+VOID
+InternalGetReportStatusCode (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+
+ if (mReportStatusCodeLibStatusCodeProtocol != NULL) {
+ return;
+ }
+
+ if (mHaveExitedBootServices) {
+ return;
+ }
+
+ //
+ // Check gBS just in case ReportStatusCode is called before gBS is initialized.
+ //
+ if (gBS != NULL && gBS->LocateProtocol != NULL) {
+ Status = gBS->LocateProtocol (&gEfiStatusCodeRuntimeProtocolGuid, NULL, (VOID**) &mReportStatusCodeLibStatusCodeProtocol);
+ if (EFI_ERROR (Status)) {
+ mReportStatusCodeLibStatusCodeProtocol = NULL;
+ }
+ }
+}
+
+/**
+ Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.
+
+ @param Event Event whose notification function is being invoked.
+ @param Context Pointer to the notification function's context
+
+**/
+VOID
+EFIAPI
+ReportStatusCodeLibVirtualAddressChange (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ if (mReportStatusCodeLibStatusCodeProtocol == NULL) {
+ return;
+ }
+ EfiConvertPointer (0, (VOID **) &mReportStatusCodeLibStatusCodeProtocol);
+}
+
+/**
+ Notification function of EVT_SIGNAL_EXIT_BOOT_SERVICES.
+
+ @param Event Event whose notification function is being invoked.
+ @param Context Pointer to the notification function's context
+
+**/
+VOID
+EFIAPI
+ReportStatusCodeLibExitBootServices (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ //
+ // Locate the report status code service before enter runtime.
+ //
+ InternalGetReportStatusCode ();
+
+ mHaveExitedBootServices = TRUE;
+}
+
+/**
+ The constructor function of Runtime DXE Report Status Code Lib.
+
+ This function allocates memory for extended status code data, caches
+ the report status code service, and registers events.
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
+
+**/
+EFI_STATUS
+EFIAPI
+ReportStatusCodeLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Cache the report status code service
+ //
+ InternalGetReportStatusCode ();
+
+ //
+ // Register notify function for EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
+ //
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ ReportStatusCodeLibVirtualAddressChange,
+ NULL,
+ &gEfiEventVirtualAddressChangeGuid,
+ &mReportStatusCodeLibVirtualAddressChangeEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Register notify function for EVT_SIGNAL_EXIT_BOOT_SERVICES
+ //
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ ReportStatusCodeLibExitBootServices,
+ NULL,
+ &gEfiEventExitBootServicesGuid,
+ &mReportStatusCodeLibExitBootServicesEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ The destructor function of Runtime DXE Report Status Code Lib.
+
+ The destructor function frees memory allocated by constructor, and closes related events.
+ It will ASSERT() if that related operation fails and it will always return EFI_SUCCESS.
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
+
+**/
+EFI_STATUS
+EFIAPI
+ReportStatusCodeLibDestructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ ASSERT (gBS != NULL);
+ Status = gBS->CloseEvent (mReportStatusCodeLibVirtualAddressChangeEvent);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->CloseEvent (mReportStatusCodeLibExitBootServicesEvent);
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Internal worker function that reports a status code through the Report Status Code Protocol.
+
+ If status code service is not cached, then this function checks if Report Status Code
+ Protocol is available in system. If Report Status Code Protocol is not available, then
+ EFI_UNSUPPORTED is returned. If Report Status Code Protocol is present, then it is
+ cached in mReportStatusCodeLibStatusCodeProtocol. Finally this function reports status
+ code through the Report Status Code Protocol.
+
+ @param Type Status code type.
+ @param Value Status code value.
+ @param Instance Status code instance number.
+ @param CallerId Pointer to a GUID that identifies the caller of this
+ function. This is an optional parameter that may be
+ NULL.
+ @param Data Pointer to the extended data buffer. This is an
+ optional parameter that may be NULL.
+
+ @retval EFI_SUCCESS The status code was reported.
+ @retval EFI_UNSUPPORTED Report Status Code Protocol is not available.
+ @retval EFI_UNSUPPORTED Status code type is not supported.
+
+**/
+EFI_STATUS
+InternalReportStatusCode (
+ IN EFI_STATUS_CODE_TYPE Type,
+ IN EFI_STATUS_CODE_VALUE Value,
+ IN UINT32 Instance,
+ IN CONST EFI_GUID *CallerId OPTIONAL,
+ IN EFI_STATUS_CODE_DATA *Data OPTIONAL
+ )
+{
+ if ((ReportProgressCodeEnabled() && ((Type) & EFI_STATUS_CODE_TYPE_MASK) == EFI_PROGRESS_CODE) ||
+ (ReportErrorCodeEnabled() && ((Type) & EFI_STATUS_CODE_TYPE_MASK) == EFI_ERROR_CODE) ||
+ (ReportDebugCodeEnabled() && ((Type) & EFI_STATUS_CODE_TYPE_MASK) == EFI_DEBUG_CODE)) {
+ //
+ // If mReportStatusCodeLibStatusCodeProtocol is NULL, then check if Report Status Code Protocol is available in system.
+ //
+ InternalGetReportStatusCode ();
+ if (mReportStatusCodeLibStatusCodeProtocol == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // A Report Status Code Protocol is present in system, so pass in all the parameters to the service.
+ //
+ return mReportStatusCodeLibStatusCodeProtocol->ReportStatusCode (Type, Value, Instance, (EFI_GUID *)CallerId, Data);
+ }
+
+ return EFI_UNSUPPORTED;
+}
+
+
+/**
+ Converts a status code to an 8-bit POST code value.
+
+ Converts the status code specified by CodeType and Value to an 8-bit POST code
+ and returns the 8-bit POST code in PostCode. If CodeType is an
+ EFI_PROGRESS_CODE or CodeType is an EFI_ERROR_CODE, then bits 0..4 of PostCode
+ are set to bits 16..20 of Value, and bits 5..7 of PostCode are set to bits
+ 24..26 of Value., and TRUE is returned. Otherwise, FALSE is returned.
+
+ If PostCode is NULL, then ASSERT().
+
+ @param CodeType The type of status code being converted.
+ @param Value The status code value being converted.
+ @param PostCode A pointer to the 8-bit POST code value to return.
+
+ @retval TRUE The status code specified by CodeType and Value was converted
+ to an 8-bit POST code and returned in PostCode.
+ @retval FALSE The status code specified by CodeType and Value could not be
+ converted to an 8-bit POST code value.
+
+**/
+BOOLEAN
+EFIAPI
+CodeTypeToPostCode (
+ IN EFI_STATUS_CODE_TYPE CodeType,
+ IN EFI_STATUS_CODE_VALUE Value,
+ OUT UINT8 *PostCode
+ )
+{
+ //
+ // If PostCode is NULL, then ASSERT()
+ //
+ ASSERT (PostCode != NULL);
+
+ //
+ // Convert Value to an 8 bit post code
+ //
+ if (((CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_PROGRESS_CODE) ||
+ ((CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_ERROR_CODE) ) {
+ *PostCode = (UINT8) ((((Value & EFI_STATUS_CODE_CLASS_MASK) >> 24) << 5) |
+ (((Value & EFI_STATUS_CODE_SUBCLASS_MASK) >> 16) & 0x1f));
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+/**
+ Extracts ASSERT() information from a status code structure.
+
+ Converts the status code specified by CodeType, Value, and Data to the ASSERT()
+ arguments specified by Filename, Description, and LineNumber. If CodeType is
+ an EFI_ERROR_CODE, and CodeType has a severity of EFI_ERROR_UNRECOVERED, and
+ Value has an operation mask of EFI_SW_EC_ILLEGAL_SOFTWARE_STATE, extract
+ Filename, Description, and LineNumber from the optional data area of the
+ status code buffer specified by Data. The optional data area of Data contains
+ a Null-terminated ASCII string for the FileName, followed by a Null-terminated
+ ASCII string for the Description, followed by a 32-bit LineNumber. If the
+ ASSERT() information could be extracted from Data, then return TRUE.
+ Otherwise, FALSE is returned.
+
+ If Data is NULL, then ASSERT().
+ If Filename is NULL, then ASSERT().
+ If Description is NULL, then ASSERT().
+ If LineNumber is NULL, then ASSERT().
+
+ @param CodeType The type of status code being converted.
+ @param Value The status code value being converted.
+ @param Data Pointer to status code data buffer.
+ @param Filename Pointer to the source file name that generated the ASSERT().
+ @param Description Pointer to the description of the ASSERT().
+ @param LineNumber Pointer to source line number that generated the ASSERT().
+
+ @retval TRUE The status code specified by CodeType, Value, and Data was
+ converted ASSERT() arguments specified by Filename, Description,
+ and LineNumber.
+ @retval FALSE The status code specified by CodeType, Value, and Data could
+ not be converted to ASSERT() arguments.
+
+**/
+BOOLEAN
+EFIAPI
+ReportStatusCodeExtractAssertInfo (
+ IN EFI_STATUS_CODE_TYPE CodeType,
+ IN EFI_STATUS_CODE_VALUE Value,
+ IN CONST EFI_STATUS_CODE_DATA *Data,
+ OUT CHAR8 **Filename,
+ OUT CHAR8 **Description,
+ OUT UINT32 *LineNumber
+ )
+{
+ EFI_DEBUG_ASSERT_DATA *AssertData;
+
+ ASSERT (Data != NULL);
+ ASSERT (Filename != NULL);
+ ASSERT (Description != NULL);
+ ASSERT (LineNumber != NULL);
+
+ if (((CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_ERROR_CODE) &&
+ ((CodeType & EFI_STATUS_CODE_SEVERITY_MASK) == EFI_ERROR_UNRECOVERED) &&
+ ((Value & EFI_STATUS_CODE_OPERATION_MASK) == EFI_SW_EC_ILLEGAL_SOFTWARE_STATE)) {
+ AssertData = (EFI_DEBUG_ASSERT_DATA *)(Data + 1);
+ *Filename = (CHAR8 *)(AssertData + 1);
+ *Description = *Filename + AsciiStrLen (*Filename) + 1;
+ *LineNumber = AssertData->LineNumber;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+/**
+ Extracts DEBUG() information from a status code structure.
+
+ Converts the status code specified by Data to the DEBUG() arguments specified
+ by ErrorLevel, Marker, and Format. If type GUID in Data is
+ EFI_STATUS_CODE_DATA_TYPE_DEBUG_GUID, then extract ErrorLevel, Marker, and
+ Format from the optional data area of the status code buffer specified by Data.
+ The optional data area of Data contains a 32-bit ErrorLevel followed by Marker
+ which is 12 UINTN parameters, followed by a Null-terminated ASCII string for
+ the Format. If the DEBUG() information could be extracted from Data, then
+ return TRUE. Otherwise, FALSE is returned.
+
+ If Data is NULL, then ASSERT().
+ If ErrorLevel is NULL, then ASSERT().
+ If Marker is NULL, then ASSERT().
+ If Format is NULL, then ASSERT().
+
+ @param Data Pointer to status code data buffer.
+ @param ErrorLevel Pointer to error level mask for a debug message.
+ @param Marker Pointer to the variable argument list associated with Format.
+ @param Format Pointer to a Null-terminated ASCII format string of a
+ debug message.
+
+ @retval TRUE The status code specified by Data was converted DEBUG() arguments
+ specified by ErrorLevel, Marker, and Format.
+ @retval FALSE The status code specified by Data could not be converted to
+ DEBUG() arguments.
+
+**/
+BOOLEAN
+EFIAPI
+ReportStatusCodeExtractDebugInfo (
+ IN CONST EFI_STATUS_CODE_DATA *Data,
+ OUT UINT32 *ErrorLevel,
+ OUT BASE_LIST *Marker,
+ OUT CHAR8 **Format
+ )
+{
+ EFI_DEBUG_INFO *DebugInfo;
+
+ ASSERT (Data != NULL);
+ ASSERT (ErrorLevel != NULL);
+ ASSERT (Marker != NULL);
+ ASSERT (Format != NULL);
+
+ //
+ // If the GUID type is not EFI_STATUS_CODE_DATA_TYPE_DEBUG_GUID then return FALSE
+ //
+ if (!CompareGuid (&Data->Type, &gEfiStatusCodeDataTypeDebugGuid)) {
+ return FALSE;
+ }
+
+ //
+ // Retrieve the debug information from the status code record
+ //
+ DebugInfo = (EFI_DEBUG_INFO *)(Data + 1);
+
+ *ErrorLevel = DebugInfo->ErrorLevel;
+
+ //
+ // The first 12 * sizeof (UINT64) bytes following EFI_DEBUG_INFO are for variable arguments
+ // of format in DEBUG string. Its address is returned in Marker and has to be 64-bit aligned.
+ // It must be noticed that EFI_DEBUG_INFO follows EFI_STATUS_CODE_DATA, whose size is
+ // 20 bytes. The size of EFI_DEBUG_INFO is 4 bytes, so we can ensure that Marker
+ // returned is 64-bit aligned.
+ // 64-bit aligned is a must, otherwise retrieving 64-bit parameter from BASE_LIST will
+ // cause unalignment exception.
+ //
+ *Marker = (BASE_LIST) (DebugInfo + 1);
+ *Format = (CHAR8 *)(((UINT64 *)*Marker) + 12);
+
+ return TRUE;
+}
+
+
+/**
+ Reports a status code.
+
+ Reports the status code specified by the parameters Type and Value. Status
+ code also require an instance, caller ID, and extended data. This function
+ passed in a zero instance, NULL extended data, and a caller ID of
+ gEfiCallerIdGuid, which is the GUID for the module.
+
+ ReportStatusCode()must actively prevent recusrsion. If ReportStatusCode()
+ is called while processing another any other Report Status Code Library function,
+ then ReportStatusCode() must return immediately.
+
+ @param Type Status code type.
+ @param Value Status code value.
+
+ @retval EFI_SUCCESS The status code was reported.
+ @retval EFI_DEVICE_ERROR There status code could not be reported due to a
+ device error.
+ @retval EFI_UNSUPPORTED Report status code is not supported
+
+**/
+EFI_STATUS
+EFIAPI
+ReportStatusCode (
+ IN EFI_STATUS_CODE_TYPE Type,
+ IN EFI_STATUS_CODE_VALUE Value
+ )
+{
+ return InternalReportStatusCode (Type, Value, 0, &gEfiCallerIdGuid, NULL);
+}
+
+
+/**
+ Reports a status code with a Device Path Protocol as the extended data.
+
+ Allocates and fills in the extended data section of a status code with the
+ Device Path Protocol specified by DevicePath. This function is responsible
+ for allocating a buffer large enough for the standard header and the device
+ path. The standard header is filled in with a GUID of
+ gEfiStatusCodeSpecificDataGuid. The status code is reported with a zero
+ instance and a caller ID of gEfiCallerIdGuid.
+
+ ReportStatusCodeWithDevicePath()must actively prevent recursion. If
+ ReportStatusCodeWithDevicePath() is called while processing another any other
+ Report Status Code Library function, then ReportStatusCodeWithDevicePath()
+ must return EFI_DEVICE_ERROR immediately.
+
+ If DevicePath is NULL, then ASSERT().
+
+ @param Type Status code type.
+ @param Value Status code value.
+ @param DevicePath Pointer to the Device Path Protocol to be reported.
+
+ @retval EFI_SUCCESS The status code was reported with the extended
+ data specified by DevicePath.
+ @retval EFI_OUT_OF_RESOURCES There were not enough resources to allocate the
+ extended data section.
+ @retval EFI_UNSUPPORTED Report status code is not supported
+
+**/
+EFI_STATUS
+EFIAPI
+ReportStatusCodeWithDevicePath (
+ IN EFI_STATUS_CODE_TYPE Type,
+ IN EFI_STATUS_CODE_VALUE Value,
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ ASSERT (DevicePath != NULL);
+ return ReportStatusCodeWithExtendedData (
+ Type,
+ Value,
+ (VOID *)DevicePath,
+ GetDevicePathSize (DevicePath)
+ );
+}
+
+
+/**
+ Reports a status code with an extended data buffer.
+
+ Allocates and fills in the extended data section of a status code with the
+ extended data specified by ExtendedData and ExtendedDataSize. ExtendedData
+ is assumed to be one of the data structures specified in Related Definitions.
+ These data structure do not have the standard header, so this function is
+ responsible for allocating a buffer large enough for the standard header and
+ the extended data passed into this function. The standard header is filled
+ in with a GUID of gEfiStatusCodeSpecificDataGuid. The status code is reported
+ with a zero instance and a caller ID of gEfiCallerIdGuid.
+
+ ReportStatusCodeWithExtendedData()must actively prevent recursion. If
+ ReportStatusCodeWithExtendedData() is called while processing another any other
+ Report Status Code Library function, then ReportStatusCodeWithExtendedData()
+ must return EFI_DEVICE_ERROR immediately.
+
+ If ExtendedData is NULL, then ASSERT().
+ If ExtendedDataSize is 0, then ASSERT().
+
+ @param Type Status code type.
+ @param Value Status code value.
+ @param ExtendedData Pointer to the extended data buffer to be reported.
+ @param ExtendedDataSize The size, in bytes, of the extended data buffer to
+ be reported.
+
+ @retval EFI_SUCCESS The status code was reported with the extended
+ data specified by ExtendedData and ExtendedDataSize.
+ @retval EFI_OUT_OF_RESOURCES There were not enough resources to allocate the
+ extended data section.
+ @retval EFI_UNSUPPORTED Report status code is not supported
+
+**/
+EFI_STATUS
+EFIAPI
+ReportStatusCodeWithExtendedData (
+ IN EFI_STATUS_CODE_TYPE Type,
+ IN EFI_STATUS_CODE_VALUE Value,
+ IN CONST VOID *ExtendedData,
+ IN UINTN ExtendedDataSize
+ )
+{
+ ASSERT (ExtendedData != NULL);
+ ASSERT (ExtendedDataSize != 0);
+ return ReportStatusCodeEx (
+ Type,
+ Value,
+ 0,
+ NULL,
+ NULL,
+ ExtendedData,
+ ExtendedDataSize
+ );
+}
+
+
+/**
+ Reports a status code with full parameters.
+
+ The function reports a status code. If ExtendedData is NULL and ExtendedDataSize
+ is 0, then an extended data buffer is not reported. If ExtendedData is not
+ NULL and ExtendedDataSize is not 0, then an extended data buffer is allocated.
+ ExtendedData is assumed not have the standard status code header, so this function
+ is responsible for allocating a buffer large enough for the standard header and
+ the extended data passed into this function. The standard header is filled in
+ with a GUID specified by ExtendedDataGuid. If ExtendedDataGuid is NULL, then a
+ GUID of gEfiStatusCodeSpecificDataGuid is used. The status code is reported with
+ an instance specified by Instance and a caller ID specified by CallerId. If
+ CallerId is NULL, then a caller ID of gEfiCallerIdGuid is used.
+
+ ReportStatusCodeEx()must actively prevent recursion. If
+ ReportStatusCodeEx() is called while processing another any
+ other Report Status Code Library function, then
+ ReportStatusCodeEx() must return EFI_DEVICE_ERROR immediately.
+
+ If ExtendedData is NULL and ExtendedDataSize is not zero, then ASSERT().
+ If ExtendedData is not NULL and ExtendedDataSize is zero, then ASSERT().
+
+ @param Type Status code type.
+ @param Value Status code value.
+ @param Instance Status code instance number.
+ @param CallerId Pointer to a GUID that identifies the caller of this
+ function. If this parameter is NULL, then a caller
+ ID of gEfiCallerIdGuid is used.
+ @param ExtendedDataGuid Pointer to the GUID for the extended data buffer.
+ If this parameter is NULL, then a the status code
+ standard header is filled in with
+ gEfiStatusCodeSpecificDataGuid.
+ @param ExtendedData Pointer to the extended data buffer. This is an
+ optional parameter that may be NULL.
+ @param ExtendedDataSize The size, in bytes, of the extended data buffer.
+
+ @retval EFI_SUCCESS The status code was reported.
+ @retval EFI_OUT_OF_RESOURCES There were not enough resources to allocate
+ the extended data section if it was specified.
+ @retval EFI_UNSUPPORTED Report status code is not supported
+
+**/
+EFI_STATUS
+EFIAPI
+ReportStatusCodeEx (
+ IN EFI_STATUS_CODE_TYPE Type,
+ IN EFI_STATUS_CODE_VALUE Value,
+ IN UINT32 Instance,
+ IN CONST EFI_GUID *CallerId OPTIONAL,
+ IN CONST EFI_GUID *ExtendedDataGuid OPTIONAL,
+ IN CONST VOID *ExtendedData OPTIONAL,
+ IN UINTN ExtendedDataSize
+ )
+{
+ EFI_STATUS Status;
+ EFI_STATUS_CODE_DATA *StatusCodeData;
+ UINT64 StatusCodeBuffer[(MAX_EXTENDED_DATA_SIZE / sizeof (UINT64)) + 1];
+
+ ASSERT (!((ExtendedData == NULL) && (ExtendedDataSize != 0)));
+ ASSERT (!((ExtendedData != NULL) && (ExtendedDataSize == 0)));
+
+ if (mHaveExitedBootServices) {
+ if (sizeof (EFI_STATUS_CODE_DATA) + ExtendedDataSize > MAX_EXTENDED_DATA_SIZE) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ StatusCodeData = (EFI_STATUS_CODE_DATA *) StatusCodeBuffer;
+ } else {
+ if (gBS == NULL || gBS->AllocatePool == NULL || gBS->FreePool == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Allocate space for the Status Code Header and its buffer
+ //
+ StatusCodeData = NULL;
+ gBS->AllocatePool (EfiBootServicesData, sizeof (EFI_STATUS_CODE_DATA) + ExtendedDataSize, (VOID **)&StatusCodeData);
+ if (StatusCodeData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+
+ //
+ // Fill in the extended data header
+ //
+ StatusCodeData->HeaderSize = (UINT16) sizeof (EFI_STATUS_CODE_DATA);
+ StatusCodeData->Size = (UINT16) ExtendedDataSize;
+ if (ExtendedDataGuid == NULL) {
+ ExtendedDataGuid = &gEfiStatusCodeSpecificDataGuid;
+ }
+ CopyGuid (&StatusCodeData->Type, ExtendedDataGuid);
+
+ //
+ // Fill in the extended data buffer
+ //
+ if (ExtendedData != NULL) {
+ CopyMem (StatusCodeData + 1, ExtendedData, ExtendedDataSize);
+ }
+
+ //
+ // Report the status code
+ //
+ if (CallerId == NULL) {
+ CallerId = &gEfiCallerIdGuid;
+ }
+ Status = InternalReportStatusCode (Type, Value, Instance, CallerId, StatusCodeData);
+
+ //
+ // Free the allocated buffer
+ //
+ if (!mHaveExitedBootServices) {
+ gBS->FreePool (StatusCodeData);
+ }
+
+ return Status;
+}
+
+
+/**
+ Returns TRUE if status codes of type EFI_PROGRESS_CODE are enabled
+
+ This function returns TRUE if the REPORT_STATUS_CODE_PROPERTY_PROGRESS_CODE_ENABLED
+ bit of PcdReportStatusCodeProperyMask is set. Otherwise FALSE is returned.
+
+ @retval TRUE The REPORT_STATUS_CODE_PROPERTY_PROGRESS_CODE_ENABLED bit of
+ PcdReportStatusCodeProperyMask is set.
+ @retval FALSE The REPORT_STATUS_CODE_PROPERTY_PROGRESS_CODE_ENABLED bit of
+ PcdReportStatusCodeProperyMask is clear.
+
+**/
+BOOLEAN
+EFIAPI
+ReportProgressCodeEnabled (
+ VOID
+ )
+{
+ return (BOOLEAN) ((PcdGet8 (PcdReportStatusCodePropertyMask) & REPORT_STATUS_CODE_PROPERTY_PROGRESS_CODE_ENABLED) != 0);
+}
+
+
+/**
+ Returns TRUE if status codes of type EFI_ERROR_CODE are enabled
+
+ This function returns TRUE if the REPORT_STATUS_CODE_PROPERTY_ERROR_CODE_ENABLED
+ bit of PcdReportStatusCodeProperyMask is set. Otherwise FALSE is returned.
+
+ @retval TRUE The REPORT_STATUS_CODE_PROPERTY_ERROR_CODE_ENABLED bit of
+ PcdReportStatusCodeProperyMask is set.
+ @retval FALSE The REPORT_STATUS_CODE_PROPERTY_ERROR_CODE_ENABLED bit of
+ PcdReportStatusCodeProperyMask is clear.
+
+**/
+BOOLEAN
+EFIAPI
+ReportErrorCodeEnabled (
+ VOID
+ )
+{
+ return (BOOLEAN) ((PcdGet8 (PcdReportStatusCodePropertyMask) & REPORT_STATUS_CODE_PROPERTY_ERROR_CODE_ENABLED) != 0);
+}
+
+
+/**
+ Returns TRUE if status codes of type EFI_DEBUG_CODE are enabled
+
+ This function returns TRUE if the REPORT_STATUS_CODE_PROPERTY_DEBUG_CODE_ENABLED
+ bit of PcdReportStatusCodeProperyMask is set. Otherwise FALSE is returned.
+
+ @retval TRUE The REPORT_STATUS_CODE_PROPERTY_DEBUG_CODE_ENABLED bit of
+ PcdReportStatusCodeProperyMask is set.
+ @retval FALSE The REPORT_STATUS_CODE_PROPERTY_DEBUG_CODE_ENABLED bit of
+ PcdReportStatusCodeProperyMask is clear.
+
+**/
+BOOLEAN
+EFIAPI
+ReportDebugCodeEnabled (
+ VOID
+ )
+{
+ return (BOOLEAN) ((PcdGet8 (PcdReportStatusCodePropertyMask) & REPORT_STATUS_CODE_PROPERTY_DEBUG_CODE_ENABLED) != 0);
+}
diff --git a/Core/MdeModulePkg/Library/RuntimeDxeReportStatusCodeLib/RuntimeDxeReportStatusCodeLib.inf b/Core/MdeModulePkg/Library/RuntimeDxeReportStatusCodeLib/RuntimeDxeReportStatusCodeLib.inf
new file mode 100644
index 0000000000..49d9933b58
--- /dev/null
+++ b/Core/MdeModulePkg/Library/RuntimeDxeReportStatusCodeLib/RuntimeDxeReportStatusCodeLib.inf
@@ -0,0 +1,59 @@
+## @file
+# Report status code library instance which supports logging message in DXE & runtime phase.
+#
+# Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = RuntimeDxeReportStatusCodeLib
+ MODULE_UNI_FILE = RuntimeDxeReportStatusCodeLib.uni
+ FILE_GUID = 07D25BBB-F832-41bb-BBA0-612E9F033067
+ MODULE_TYPE = DXE_RUNTIME_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = ReportStatusCodeLib|DXE_RUNTIME_DRIVER DXE_SAL_DRIVER
+ CONSTRUCTOR = ReportStatusCodeLibConstructor
+ DESTRUCTOR = ReportStatusCodeLibDestructor
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ ReportStatusCodeLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ DebugLib
+ UefiBootServicesTableLib
+ BaseMemoryLib
+ PcdLib
+ DevicePathLib
+ UefiRuntimeLib
+
+[Guids]
+ gEfiStatusCodeSpecificDataGuid ## SOMETIMES_CONSUMES ## UNDEFINED
+ gEfiStatusCodeDataTypeDebugGuid ## SOMETIMES_CONSUMES ## UNDEFINED
+ gEfiEventVirtualAddressChangeGuid ## CONSUMES ## Event
+ gEfiEventExitBootServicesGuid ## CONSUMES ## Event
+
+[Protocols]
+ gEfiStatusCodeRuntimeProtocolGuid ## CONSUMES
+
+[Pcd]
+ gEfiMdePkgTokenSpaceGuid.PcdReportStatusCodePropertyMask ## CONSUMES
+
diff --git a/Core/MdeModulePkg/Library/RuntimeDxeReportStatusCodeLib/RuntimeDxeReportStatusCodeLib.uni b/Core/MdeModulePkg/Library/RuntimeDxeReportStatusCodeLib/RuntimeDxeReportStatusCodeLib.uni
new file mode 100644
index 0000000000..5392a9bf1b
--- /dev/null
+++ b/Core/MdeModulePkg/Library/RuntimeDxeReportStatusCodeLib/RuntimeDxeReportStatusCodeLib.uni
Binary files differ
diff --git a/Core/MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLib.c b/Core/MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLib.c
new file mode 100644
index 0000000000..e59cc28d53
--- /dev/null
+++ b/Core/MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLib.c
@@ -0,0 +1,1099 @@
+/** @file
+ Performance library instance used by SMM Core.
+
+ This library provides the performance measurement interfaces and initializes performance
+ logging for the SMM phase.
+ It initializes SMM phase performance logging by publishing the SMM Performance and PerformanceEx Protocol,
+ which is consumed by SmmPerformanceLib to logging performance data in SMM phase.
+
+ This library is mainly used by SMM Core to start performance logging to ensure that
+ SMM Performance and PerformanceEx Protocol are installed at the very beginning of SMM phase.
+
+ Caution: This module requires additional review when modified.
+ This driver will have external input - performance data and communicate buffer in SMM mode.
+ This external input must be validated carefully to avoid security issue like
+ buffer overflow, integer overflow.
+
+ SmmPerformanceHandlerEx(), SmmPerformanceHandler() will receive untrusted input and do basic validation.
+
+Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+
+#include "SmmCorePerformanceLibInternal.h"
+
+//
+// The data structure to hold global performance data.
+//
+GAUGE_DATA_HEADER *mGaugeData;
+
+//
+// The current maximum number of logging entries. If current number of
+// entries exceeds this value, it will re-allocate a larger array and
+// migration the old data to the larger array.
+//
+UINT32 mMaxGaugeRecords;
+
+//
+// The handle to install Performance Protocol instance.
+//
+EFI_HANDLE mHandle = NULL;
+
+BOOLEAN mPerformanceMeasurementEnabled;
+
+SPIN_LOCK mSmmPerfLock;
+
+//
+// Interfaces for SMM Performance Protocol.
+//
+PERFORMANCE_PROTOCOL mPerformanceInterface = {
+ StartGauge,
+ EndGauge,
+ GetGauge
+};
+
+//
+// Interfaces for SMM PerformanceEx Protocol.
+//
+PERFORMANCE_EX_PROTOCOL mPerformanceExInterface = {
+ StartGaugeEx,
+ EndGaugeEx,
+ GetGaugeEx
+};
+
+/**
+ Searches in the gauge array with keyword Handle, Token, Module and Identfier.
+
+ This internal function searches for the gauge entry in the gauge array.
+ If there is an entry that exactly matches the given keywords
+ and its end time stamp is zero, then the index of that gauge entry is returned;
+ otherwise, the the number of gauge entries in the array is returned.
+
+ @param Handle Pointer to environment specific context used
+ to identify the component being measured.
+ @param Token Pointer to a Null-terminated ASCII string
+ that identifies the component being measured.
+ @param Module Pointer to a Null-terminated ASCII string
+ that identifies the module being measured.
+ @param Identifier 32-bit identifier.
+
+ @retval The index of gauge entry in the array.
+
+**/
+UINT32
+SmmSearchForGaugeEntry (
+ IN CONST VOID *Handle, OPTIONAL
+ IN CONST CHAR8 *Token, OPTIONAL
+ IN CONST CHAR8 *Module, OPTIONAL
+ IN CONST UINT32 Identifier
+ )
+{
+ UINT32 Index;
+ UINT32 Index2;
+ UINT32 NumberOfEntries;
+ GAUGE_DATA_ENTRY_EX *GaugeEntryExArray;
+
+ if (Token == NULL) {
+ Token = "";
+ }
+ if (Module == NULL) {
+ Module = "";
+ }
+
+ NumberOfEntries = mGaugeData->NumberOfEntries;
+ GaugeEntryExArray = (GAUGE_DATA_ENTRY_EX *) (mGaugeData + 1);
+
+ Index2 = 0;
+
+ for (Index = 0; Index < NumberOfEntries; Index++) {
+ Index2 = NumberOfEntries - 1 - Index;
+ if (GaugeEntryExArray[Index2].EndTimeStamp == 0 &&
+ (GaugeEntryExArray[Index2].Handle == (EFI_PHYSICAL_ADDRESS) (UINTN) Handle) &&
+ AsciiStrnCmp (GaugeEntryExArray[Index2].Token, Token, SMM_PERFORMANCE_STRING_LENGTH) == 0 &&
+ AsciiStrnCmp (GaugeEntryExArray[Index2].Module, Module, SMM_PERFORMANCE_STRING_LENGTH) == 0 &&
+ (GaugeEntryExArray[Index2].Identifier == Identifier)) {
+ Index = Index2;
+ break;
+ }
+ }
+
+ return Index;
+}
+
+/**
+ Adds a record at the end of the performance measurement log
+ that records the start time of a performance measurement.
+
+ Adds a record to the end of the performance measurement log
+ that contains the Handle, Token, Module and Identifier.
+ The end time of the new record must be set to zero.
+ If TimeStamp is not zero, then TimeStamp is used to fill in the start time in the record.
+ If TimeStamp is zero, the start time in the record is filled in with the value
+ read from the current time stamp.
+
+ @param Handle Pointer to environment specific context used
+ to identify the component being measured.
+ @param Token Pointer to a Null-terminated ASCII string
+ that identifies the component being measured.
+ @param Module Pointer to a Null-terminated ASCII string
+ that identifies the module being measured.
+ @param TimeStamp 64-bit time stamp.
+ @param Identifier 32-bit identifier. If the value is 0, the created record
+ is same as the one created by StartGauge of PERFORMANCE_PROTOCOL.
+
+ @retval EFI_SUCCESS The data was read correctly from the device.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources to record the measurement.
+
+**/
+EFI_STATUS
+EFIAPI
+StartGaugeEx (
+ IN CONST VOID *Handle, OPTIONAL
+ IN CONST CHAR8 *Token, OPTIONAL
+ IN CONST CHAR8 *Module, OPTIONAL
+ IN UINT64 TimeStamp,
+ IN UINT32 Identifier
+ )
+{
+ GAUGE_DATA_ENTRY_EX *GaugeEntryExArray;
+ UINTN GaugeDataSize;
+ GAUGE_DATA_HEADER *NewGaugeData;
+ UINTN OldGaugeDataSize;
+ GAUGE_DATA_HEADER *OldGaugeData;
+ UINT32 Index;
+
+ AcquireSpinLock (&mSmmPerfLock);
+
+ Index = mGaugeData->NumberOfEntries;
+ if (Index >= mMaxGaugeRecords) {
+ //
+ // Try to enlarge the scale of gauge array.
+ //
+ OldGaugeData = mGaugeData;
+ OldGaugeDataSize = sizeof (GAUGE_DATA_HEADER) + sizeof (GAUGE_DATA_ENTRY_EX) * mMaxGaugeRecords;
+
+ GaugeDataSize = sizeof (GAUGE_DATA_HEADER) + sizeof (GAUGE_DATA_ENTRY_EX) * mMaxGaugeRecords * 2;
+
+ NewGaugeData = AllocateZeroPool (GaugeDataSize);
+ if (NewGaugeData == NULL) {
+ ReleaseSpinLock (&mSmmPerfLock);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ mGaugeData = NewGaugeData;
+ mMaxGaugeRecords *= 2;
+
+ //
+ // Initialize new data array and migrate old data one.
+ //
+ mGaugeData = CopyMem (mGaugeData, OldGaugeData, OldGaugeDataSize);
+
+ FreePool (OldGaugeData);
+ }
+
+ GaugeEntryExArray = (GAUGE_DATA_ENTRY_EX *) (mGaugeData + 1);
+ GaugeEntryExArray[Index].Handle = (EFI_PHYSICAL_ADDRESS) (UINTN) Handle;
+
+ if (Token != NULL) {
+ AsciiStrnCpyS (GaugeEntryExArray[Index].Token, SMM_PERFORMANCE_STRING_SIZE, Token, SMM_PERFORMANCE_STRING_LENGTH);
+ }
+ if (Module != NULL) {
+ AsciiStrnCpyS (GaugeEntryExArray[Index].Module, SMM_PERFORMANCE_STRING_SIZE, Module, SMM_PERFORMANCE_STRING_LENGTH);
+ }
+
+ GaugeEntryExArray[Index].EndTimeStamp = 0;
+ GaugeEntryExArray[Index].Identifier = Identifier;
+
+ if (TimeStamp == 0) {
+ TimeStamp = GetPerformanceCounter ();
+ }
+ GaugeEntryExArray[Index].StartTimeStamp = TimeStamp;
+
+ mGaugeData->NumberOfEntries++;
+
+ ReleaseSpinLock (&mSmmPerfLock);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Searches the performance measurement log from the beginning of the log
+ for the first matching record that contains a zero end time and fills in a valid end time.
+
+ Searches the performance measurement log from the beginning of the log
+ for the first record that matches Handle, Token, Module and Identifier and has an end time value of zero.
+ If the record can not be found then return EFI_NOT_FOUND.
+ If the record is found and TimeStamp is not zero,
+ then the end time in the record is filled in with the value specified by TimeStamp.
+ If the record is found and TimeStamp is zero, then the end time in the matching record
+ is filled in with the current time stamp value.
+
+ @param Handle Pointer to environment specific context used
+ to identify the component being measured.
+ @param Token Pointer to a Null-terminated ASCII string
+ that identifies the component being measured.
+ @param Module Pointer to a Null-terminated ASCII string
+ that identifies the module being measured.
+ @param TimeStamp 64-bit time stamp.
+ @param Identifier 32-bit identifier. If the value is 0, the found record
+ is same as the one found by EndGauge of PERFORMANCE_PROTOCOL.
+
+ @retval EFI_SUCCESS The end of the measurement was recorded.
+ @retval EFI_NOT_FOUND The specified measurement record could not be found.
+
+**/
+EFI_STATUS
+EFIAPI
+EndGaugeEx (
+ IN CONST VOID *Handle, OPTIONAL
+ IN CONST CHAR8 *Token, OPTIONAL
+ IN CONST CHAR8 *Module, OPTIONAL
+ IN UINT64 TimeStamp,
+ IN UINT32 Identifier
+ )
+{
+ GAUGE_DATA_ENTRY_EX *GaugeEntryExArray;
+ UINT32 Index;
+
+ AcquireSpinLock (&mSmmPerfLock);
+
+ if (TimeStamp == 0) {
+ TimeStamp = GetPerformanceCounter ();
+ }
+
+ Index = SmmSearchForGaugeEntry (Handle, Token, Module, Identifier);
+ if (Index >= mGaugeData->NumberOfEntries) {
+ ReleaseSpinLock (&mSmmPerfLock);
+ return EFI_NOT_FOUND;
+ }
+ GaugeEntryExArray = (GAUGE_DATA_ENTRY_EX *) (mGaugeData + 1);
+ GaugeEntryExArray[Index].EndTimeStamp = TimeStamp;
+
+ ReleaseSpinLock (&mSmmPerfLock);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Retrieves a previously logged performance measurement.
+ It can also retrieve the log created by StartGauge and EndGauge of PERFORMANCE_PROTOCOL,
+ and then assign the Identifier with 0.
+
+ Retrieves the performance log entry from the performance log specified by LogEntryKey.
+ If it stands for a valid entry, then EFI_SUCCESS is returned and
+ GaugeDataEntryEx stores the pointer to that entry.
+
+ @param LogEntryKey The key for the previous performance measurement log entry.
+ If 0, then the first performance measurement log entry is retrieved.
+ @param GaugeDataEntryEx The indirect pointer to the extended gauge data entry specified by LogEntryKey
+ if the retrieval is successful.
+
+ @retval EFI_SUCCESS The GuageDataEntryEx is successfully found based on LogEntryKey.
+ @retval EFI_NOT_FOUND The LogEntryKey is the last entry (equals to the total entry number).
+ @retval EFI_INVALIDE_PARAMETER The LogEntryKey is not a valid entry (greater than the total entry number).
+ @retval EFI_INVALIDE_PARAMETER GaugeDataEntryEx is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+GetGaugeEx (
+ IN UINTN LogEntryKey,
+ OUT GAUGE_DATA_ENTRY_EX **GaugeDataEntryEx
+ )
+{
+ UINTN NumberOfEntries;
+ GAUGE_DATA_ENTRY_EX *GaugeEntryExArray;
+
+ NumberOfEntries = (UINTN) (mGaugeData->NumberOfEntries);
+ if (LogEntryKey > NumberOfEntries) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (LogEntryKey == NumberOfEntries) {
+ return EFI_NOT_FOUND;
+ }
+
+ GaugeEntryExArray = (GAUGE_DATA_ENTRY_EX *) (mGaugeData + 1);
+
+ if (GaugeDataEntryEx == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ *GaugeDataEntryEx = &GaugeEntryExArray[LogEntryKey];
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Adds a record at the end of the performance measurement log
+ that records the start time of a performance measurement.
+
+ Adds a record to the end of the performance measurement log
+ that contains the Handle, Token, and Module.
+ The end time of the new record must be set to zero.
+ If TimeStamp is not zero, then TimeStamp is used to fill in the start time in the record.
+ If TimeStamp is zero, the start time in the record is filled in with the value
+ read from the current time stamp.
+
+ @param Handle Pointer to environment specific context used
+ to identify the component being measured.
+ @param Token Pointer to a Null-terminated ASCII string
+ that identifies the component being measured.
+ @param Module Pointer to a Null-terminated ASCII string
+ that identifies the module being measured.
+ @param TimeStamp 64-bit time stamp.
+
+ @retval EFI_SUCCESS The data was read correctly from the device.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources to record the measurement.
+
+**/
+EFI_STATUS
+EFIAPI
+StartGauge (
+ IN CONST VOID *Handle, OPTIONAL
+ IN CONST CHAR8 *Token, OPTIONAL
+ IN CONST CHAR8 *Module, OPTIONAL
+ IN UINT64 TimeStamp
+ )
+{
+ return StartGaugeEx (Handle, Token, Module, TimeStamp, 0);
+}
+
+/**
+ Searches the performance measurement log from the beginning of the log
+ for the first matching record that contains a zero end time and fills in a valid end time.
+
+ Searches the performance measurement log from the beginning of the log
+ for the first record that matches Handle, Token, and Module and has an end time value of zero.
+ If the record can not be found then return EFI_NOT_FOUND.
+ If the record is found and TimeStamp is not zero,
+ then the end time in the record is filled in with the value specified by TimeStamp.
+ If the record is found and TimeStamp is zero, then the end time in the matching record
+ is filled in with the current time stamp value.
+
+ @param Handle Pointer to environment specific context used
+ to identify the component being measured.
+ @param Token Pointer to a Null-terminated ASCII string
+ that identifies the component being measured.
+ @param Module Pointer to a Null-terminated ASCII string
+ that identifies the module being measured.
+ @param TimeStamp 64-bit time stamp.
+
+ @retval EFI_SUCCESS The end of the measurement was recorded.
+ @retval EFI_NOT_FOUND The specified measurement record could not be found.
+
+**/
+EFI_STATUS
+EFIAPI
+EndGauge (
+ IN CONST VOID *Handle, OPTIONAL
+ IN CONST CHAR8 *Token, OPTIONAL
+ IN CONST CHAR8 *Module, OPTIONAL
+ IN UINT64 TimeStamp
+ )
+{
+ return EndGaugeEx (Handle, Token, Module, TimeStamp, 0);
+}
+
+/**
+ Retrieves a previously logged performance measurement.
+ It can also retrieve the log created by StartGaugeEx and EndGaugeEx of PERFORMANCE_EX_PROTOCOL,
+ and then eliminate the Identifier.
+
+ Retrieves the performance log entry from the performance log specified by LogEntryKey.
+ If it stands for a valid entry, then EFI_SUCCESS is returned and
+ GaugeDataEntry stores the pointer to that entry.
+
+ @param LogEntryKey The key for the previous performance measurement log entry.
+ If 0, then the first performance measurement log entry is retrieved.
+ @param GaugeDataEntry The indirect pointer to the gauge data entry specified by LogEntryKey
+ if the retrieval is successful.
+
+ @retval EFI_SUCCESS The GuageDataEntry is successfully found based on LogEntryKey.
+ @retval EFI_NOT_FOUND The LogEntryKey is the last entry (equals to the total entry number).
+ @retval EFI_INVALIDE_PARAMETER The LogEntryKey is not a valid entry (greater than the total entry number).
+ @retval EFI_INVALIDE_PARAMETER GaugeDataEntry is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+GetGauge (
+ IN UINTN LogEntryKey,
+ OUT GAUGE_DATA_ENTRY **GaugeDataEntry
+ )
+{
+ EFI_STATUS Status;
+ GAUGE_DATA_ENTRY_EX *GaugeEntryEx;
+
+ GaugeEntryEx = NULL;
+
+ Status = GetGaugeEx (LogEntryKey, &GaugeEntryEx);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (GaugeDataEntry == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *GaugeDataEntry = (GAUGE_DATA_ENTRY *) GaugeEntryEx;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Communication service SMI Handler entry.
+
+ This SMI handler provides services for the performance wrapper driver.
+
+ Caution: This function may receive untrusted input.
+ Communicate buffer and buffer size are external input, so this function will do basic validation.
+
+ @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
+ @param[in] RegisterContext Points to an optional handler context which was specified when the
+ handler was registered.
+ @param[in, out] CommBuffer A pointer to a collection of data in memory that will
+ be conveyed from a non-SMM environment into an SMM environment.
+ @param[in, out] CommBufferSize The size of the CommBuffer.
+
+ @retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers
+ should still be called.
+ @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED The interrupt has been quiesced but other handlers should
+ still be called.
+ @retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still pending and other handlers should still
+ be called.
+ @retval EFI_INTERRUPT_PENDING The interrupt could not be quiesced.
+**/
+EFI_STATUS
+EFIAPI
+SmmPerformanceHandlerEx (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *RegisterContext,
+ IN OUT VOID *CommBuffer,
+ IN OUT UINTN *CommBufferSize
+ )
+{
+ EFI_STATUS Status;
+ SMM_PERF_COMMUNICATE_EX *SmmPerfCommData;
+ GAUGE_DATA_ENTRY_EX *GaugeEntryExArray;
+ UINT64 DataSize;
+ UINTN Index;
+ GAUGE_DATA_ENTRY_EX *GaugeDataEx;
+ UINTN NumberOfEntries;
+ UINTN LogEntryKey;
+ UINTN TempCommBufferSize;
+
+ GaugeEntryExArray = NULL;
+
+ //
+ // If input is invalid, stop processing this SMI
+ //
+ if (CommBuffer == NULL || CommBufferSize == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ TempCommBufferSize = *CommBufferSize;
+
+ if(TempCommBufferSize < sizeof (SMM_PERF_COMMUNICATE_EX)) {
+ return EFI_SUCCESS;
+ }
+
+ if (!SmmIsBufferOutsideSmmValid ((UINTN)CommBuffer, TempCommBufferSize)) {
+ DEBUG ((EFI_D_ERROR, "SmmPerformanceHandlerEx: SMM communcation data buffer in SMRAM or overflow!\n"));
+ return EFI_SUCCESS;
+ }
+
+ SmmPerfCommData = (SMM_PERF_COMMUNICATE_EX *)CommBuffer;
+
+ switch (SmmPerfCommData->Function) {
+ case SMM_PERF_FUNCTION_GET_GAUGE_ENTRY_NUMBER :
+ SmmPerfCommData->NumberOfEntries = mGaugeData->NumberOfEntries;
+ Status = EFI_SUCCESS;
+ break;
+
+ case SMM_PERF_FUNCTION_GET_GAUGE_DATA :
+ GaugeDataEx = SmmPerfCommData->GaugeDataEx;
+ NumberOfEntries = SmmPerfCommData->NumberOfEntries;
+ LogEntryKey = SmmPerfCommData->LogEntryKey;
+ if (GaugeDataEx == NULL || NumberOfEntries == 0 || LogEntryKey > mGaugeData->NumberOfEntries ||
+ NumberOfEntries > mGaugeData->NumberOfEntries || LogEntryKey > (mGaugeData->NumberOfEntries - NumberOfEntries)) {
+ Status = EFI_INVALID_PARAMETER;
+ break;
+ }
+
+ //
+ // Sanity check
+ //
+ DataSize = MultU64x32 (NumberOfEntries, sizeof(GAUGE_DATA_ENTRY_EX));
+ if (!SmmIsBufferOutsideSmmValid ((UINTN) GaugeDataEx, DataSize)) {
+ DEBUG ((EFI_D_ERROR, "SmmPerformanceHandlerEx: SMM Performance Data buffer in SMRAM or overflow!\n"));
+ Status = EFI_ACCESS_DENIED;
+ break;
+ }
+
+ GaugeEntryExArray = (GAUGE_DATA_ENTRY_EX *) (mGaugeData + 1);
+
+ for (Index = 0; Index < NumberOfEntries; Index++) {
+ CopyMem (
+ (UINT8 *) &GaugeDataEx[Index],
+ (UINT8 *) &GaugeEntryExArray[LogEntryKey++],
+ sizeof (GAUGE_DATA_ENTRY_EX)
+ );
+ }
+ Status = EFI_SUCCESS;
+ break;
+
+ default:
+ Status = EFI_UNSUPPORTED;
+ }
+
+
+ SmmPerfCommData->ReturnStatus = Status;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Communication service SMI Handler entry.
+
+ This SMI handler provides services for the performance wrapper driver.
+
+ Caution: This function may receive untrusted input.
+ Communicate buffer and buffer size are external input, so this function will do basic validation.
+
+ @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
+ @param[in] RegisterContext Points to an optional handler context which was specified when the
+ handler was registered.
+ @param[in, out] CommBuffer A pointer to a collection of data in memory that will
+ be conveyed from a non-SMM environment into an SMM environment.
+ @param[in, out] CommBufferSize The size of the CommBuffer.
+
+ @retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers
+ should still be called.
+ @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED The interrupt has been quiesced but other handlers should
+ still be called.
+ @retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still pending and other handlers should still
+ be called.
+ @retval EFI_INTERRUPT_PENDING The interrupt could not be quiesced.
+**/
+EFI_STATUS
+EFIAPI
+SmmPerformanceHandler (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *RegisterContext,
+ IN OUT VOID *CommBuffer,
+ IN OUT UINTN *CommBufferSize
+ )
+{
+ EFI_STATUS Status;
+ SMM_PERF_COMMUNICATE *SmmPerfCommData;
+ GAUGE_DATA_ENTRY_EX *GaugeEntryExArray;
+ UINT64 DataSize;
+ UINTN Index;
+ GAUGE_DATA_ENTRY *GaugeData;
+ UINTN NumberOfEntries;
+ UINTN LogEntryKey;
+ UINTN TempCommBufferSize;
+
+ GaugeEntryExArray = NULL;
+
+ //
+ // If input is invalid, stop processing this SMI
+ //
+ if (CommBuffer == NULL || CommBufferSize == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ TempCommBufferSize = *CommBufferSize;
+
+ if(TempCommBufferSize < sizeof (SMM_PERF_COMMUNICATE)) {
+ return EFI_SUCCESS;
+ }
+
+ if (!SmmIsBufferOutsideSmmValid ((UINTN)CommBuffer, TempCommBufferSize)) {
+ DEBUG ((EFI_D_ERROR, "SmmPerformanceHandler: SMM communcation data buffer in SMRAM or overflow!\n"));
+ return EFI_SUCCESS;
+ }
+
+ SmmPerfCommData = (SMM_PERF_COMMUNICATE *)CommBuffer;
+
+ switch (SmmPerfCommData->Function) {
+ case SMM_PERF_FUNCTION_GET_GAUGE_ENTRY_NUMBER :
+ SmmPerfCommData->NumberOfEntries = mGaugeData->NumberOfEntries;
+ Status = EFI_SUCCESS;
+ break;
+
+ case SMM_PERF_FUNCTION_GET_GAUGE_DATA :
+ GaugeData = SmmPerfCommData->GaugeData;
+ NumberOfEntries = SmmPerfCommData->NumberOfEntries;
+ LogEntryKey = SmmPerfCommData->LogEntryKey;
+ if (GaugeData == NULL || NumberOfEntries == 0 || LogEntryKey > mGaugeData->NumberOfEntries ||
+ NumberOfEntries > mGaugeData->NumberOfEntries || LogEntryKey > (mGaugeData->NumberOfEntries - NumberOfEntries)) {
+ Status = EFI_INVALID_PARAMETER;
+ break;
+ }
+
+ //
+ // Sanity check
+ //
+ DataSize = MultU64x32 (NumberOfEntries, sizeof(GAUGE_DATA_ENTRY));
+ if (!SmmIsBufferOutsideSmmValid ((UINTN) GaugeData, DataSize)) {
+ DEBUG ((EFI_D_ERROR, "SmmPerformanceHandler: SMM Performance Data buffer in SMRAM or overflow!\n"));
+ Status = EFI_ACCESS_DENIED;
+ break;
+ }
+
+ GaugeEntryExArray = (GAUGE_DATA_ENTRY_EX *) (mGaugeData + 1);
+
+ for (Index = 0; Index < NumberOfEntries; Index++) {
+ CopyMem (
+ (UINT8 *) &GaugeData[Index],
+ (UINT8 *) &GaugeEntryExArray[LogEntryKey++],
+ sizeof (GAUGE_DATA_ENTRY)
+ );
+ }
+ Status = EFI_SUCCESS;
+ break;
+
+ default:
+ Status = EFI_UNSUPPORTED;
+ }
+
+
+ SmmPerfCommData->ReturnStatus = Status;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ SmmBase2 protocol notify callback function, when SMST and SMM memory service get initialized
+ this function is callbacked to initialize the Smm Performance Lib
+
+ @param Event The event of notify protocol.
+ @param Context Notify event context.
+
+**/
+VOID
+EFIAPI
+InitializeSmmCorePerformanceLib (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE Handle;
+
+ //
+ // Initialize spin lock
+ //
+ InitializeSpinLock (&mSmmPerfLock);
+
+ mMaxGaugeRecords = INIT_SMM_GAUGE_DATA_ENTRIES;
+
+ mGaugeData = AllocateZeroPool (sizeof (GAUGE_DATA_HEADER) + (sizeof (GAUGE_DATA_ENTRY_EX) * mMaxGaugeRecords));
+ ASSERT (mGaugeData != NULL);
+
+ //
+ // Install the protocol interfaces.
+ //
+ Status = gSmst->SmmInstallProtocolInterface (
+ &mHandle,
+ &gSmmPerformanceProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &mPerformanceInterface
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gSmst->SmmInstallProtocolInterface (
+ &mHandle,
+ &gSmmPerformanceExProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &mPerformanceExInterface
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ ///
+ /// Register SMM Performance SMI handler
+ ///
+ Handle = NULL;
+ Status = gSmst->SmiHandlerRegister (SmmPerformanceHandler, &gSmmPerformanceProtocolGuid, &Handle);
+ ASSERT_EFI_ERROR (Status);
+ Status = gSmst->SmiHandlerRegister (SmmPerformanceHandlerEx, &gSmmPerformanceExProtocolGuid, &Handle);
+ ASSERT_EFI_ERROR (Status);
+}
+
+/**
+ The constructor function initializes the Performance Measurement Enable flag and
+ registers SmmBase2 protocol notify callback.
+ It will ASSERT() if one of these operations fails and it will always return EFI_SUCCESS.
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmCorePerformanceLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_EVENT Event;
+ VOID *Registration;
+
+ mPerformanceMeasurementEnabled = (BOOLEAN) ((PcdGet8(PcdPerformanceLibraryPropertyMask) & PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED) != 0);
+ if (!mPerformanceMeasurementEnabled) {
+ //
+ // Do not initialize performance infrastructure if not required.
+ //
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Create the events to do the library init.
+ //
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ InitializeSmmCorePerformanceLib,
+ NULL,
+ &Event
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Register for protocol notifications on this event
+ //
+ Status = gBS->RegisterProtocolNotify (
+ &gEfiSmmBase2ProtocolGuid,
+ Event,
+ &Registration
+ );
+
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Adds a record at the end of the performance measurement log
+ that records the start time of a performance measurement.
+
+ Adds a record to the end of the performance measurement log
+ that contains the Handle, Token, Module and Identifier.
+ The end time of the new record must be set to zero.
+ If TimeStamp is not zero, then TimeStamp is used to fill in the start time in the record.
+ If TimeStamp is zero, the start time in the record is filled in with the value
+ read from the current time stamp.
+
+ @param Handle Pointer to environment specific context used
+ to identify the component being measured.
+ @param Token Pointer to a Null-terminated ASCII string
+ that identifies the component being measured.
+ @param Module Pointer to a Null-terminated ASCII string
+ that identifies the module being measured.
+ @param TimeStamp 64-bit time stamp.
+ @param Identifier 32-bit identifier. If the value is 0, the created record
+ is same as the one created by StartPerformanceMeasurement.
+
+ @retval RETURN_SUCCESS The start of the measurement was recorded.
+ @retval RETURN_OUT_OF_RESOURCES There are not enough resources to record the measurement.
+
+**/
+RETURN_STATUS
+EFIAPI
+StartPerformanceMeasurementEx (
+ IN CONST VOID *Handle, OPTIONAL
+ IN CONST CHAR8 *Token, OPTIONAL
+ IN CONST CHAR8 *Module, OPTIONAL
+ IN UINT64 TimeStamp,
+ IN UINT32 Identifier
+ )
+{
+ return (RETURN_STATUS) StartGaugeEx (Handle, Token, Module, TimeStamp, Identifier);
+}
+
+/**
+ Searches the performance measurement log from the beginning of the log
+ for the first matching record that contains a zero end time and fills in a valid end time.
+
+ Searches the performance measurement log from the beginning of the log
+ for the first record that matches Handle, Token, Module and Identifier and has an end time value of zero.
+ If the record can not be found then return RETURN_NOT_FOUND.
+ If the record is found and TimeStamp is not zero,
+ then the end time in the record is filled in with the value specified by TimeStamp.
+ If the record is found and TimeStamp is zero, then the end time in the matching record
+ is filled in with the current time stamp value.
+
+ @param Handle Pointer to environment specific context used
+ to identify the component being measured.
+ @param Token Pointer to a Null-terminated ASCII string
+ that identifies the component being measured.
+ @param Module Pointer to a Null-terminated ASCII string
+ that identifies the module being measured.
+ @param TimeStamp 64-bit time stamp.
+ @param Identifier 32-bit identifier. If the value is 0, the found record
+ is same as the one found by EndPerformanceMeasurement.
+
+ @retval RETURN_SUCCESS The end of the measurement was recorded.
+ @retval RETURN_NOT_FOUND The specified measurement record could not be found.
+
+**/
+RETURN_STATUS
+EFIAPI
+EndPerformanceMeasurementEx (
+ IN CONST VOID *Handle, OPTIONAL
+ IN CONST CHAR8 *Token, OPTIONAL
+ IN CONST CHAR8 *Module, OPTIONAL
+ IN UINT64 TimeStamp,
+ IN UINT32 Identifier
+ )
+{
+ return (RETURN_STATUS) EndGaugeEx (Handle, Token, Module, TimeStamp, Identifier);
+}
+
+/**
+ Attempts to retrieve a performance measurement log entry from the performance measurement log.
+ It can also retrieve the log created by StartPerformanceMeasurement and EndPerformanceMeasurement,
+ and then assign the Identifier with 0.
+
+ Attempts to retrieve the performance log entry specified by LogEntryKey. If LogEntryKey is
+ zero on entry, then an attempt is made to retrieve the first entry from the performance log,
+ and the key for the second entry in the log is returned. If the performance log is empty,
+ then no entry is retrieved and zero is returned. If LogEntryKey is not zero, then the performance
+ log entry associated with LogEntryKey is retrieved, and the key for the next entry in the log is
+ returned. If LogEntryKey is the key for the last entry in the log, then the last log entry is
+ retrieved and an implementation specific non-zero key value that specifies the end of the performance
+ log is returned. If LogEntryKey is equal this implementation specific non-zero key value, then no entry
+ is retrieved and zero is returned. In the cases where a performance log entry can be returned,
+ the log entry is returned in Handle, Token, Module, StartTimeStamp, EndTimeStamp and Identifier.
+ If LogEntryKey is not a valid log entry key for the performance measurement log, then ASSERT().
+ If Handle is NULL, then ASSERT().
+ If Token is NULL, then ASSERT().
+ If Module is NULL, then ASSERT().
+ If StartTimeStamp is NULL, then ASSERT().
+ If EndTimeStamp is NULL, then ASSERT().
+ If Identifier is NULL, then ASSERT().
+
+ @param LogEntryKey On entry, the key of the performance measurement log entry to retrieve.
+ 0, then the first performance measurement log entry is retrieved.
+ On exit, the key of the next performance log entry.
+ @param Handle Pointer to environment specific context used to identify the component
+ being measured.
+ @param Token Pointer to a Null-terminated ASCII string that identifies the component
+ being measured.
+ @param Module Pointer to a Null-terminated ASCII string that identifies the module
+ being measured.
+ @param StartTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
+ was started.
+ @param EndTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
+ was ended.
+ @param Identifier Pointer to the 32-bit identifier that was recorded.
+
+ @return The key for the next performance log entry (in general case).
+
+**/
+UINTN
+EFIAPI
+GetPerformanceMeasurementEx (
+ IN UINTN LogEntryKey,
+ OUT CONST VOID **Handle,
+ OUT CONST CHAR8 **Token,
+ OUT CONST CHAR8 **Module,
+ OUT UINT64 *StartTimeStamp,
+ OUT UINT64 *EndTimeStamp,
+ OUT UINT32 *Identifier
+ )
+{
+ EFI_STATUS Status;
+ GAUGE_DATA_ENTRY_EX *GaugeData;
+
+ GaugeData = NULL;
+
+ ASSERT (Handle != NULL);
+ ASSERT (Token != NULL);
+ ASSERT (Module != NULL);
+ ASSERT (StartTimeStamp != NULL);
+ ASSERT (EndTimeStamp != NULL);
+ ASSERT (Identifier != NULL);
+
+ Status = GetGaugeEx (LogEntryKey++, &GaugeData);
+
+ //
+ // Make sure that LogEntryKey is a valid log entry key,
+ //
+ ASSERT (Status != EFI_INVALID_PARAMETER);
+
+ if (EFI_ERROR (Status)) {
+ //
+ // The LogEntryKey is the last entry (equals to the total entry number).
+ //
+ return 0;
+ }
+
+ ASSERT (GaugeData != NULL);
+
+ *Handle = (VOID *) (UINTN) GaugeData->Handle;
+ *Token = GaugeData->Token;
+ *Module = GaugeData->Module;
+ *StartTimeStamp = GaugeData->StartTimeStamp;
+ *EndTimeStamp = GaugeData->EndTimeStamp;
+ *Identifier = GaugeData->Identifier;
+
+ return LogEntryKey;
+}
+
+/**
+ Adds a record at the end of the performance measurement log
+ that records the start time of a performance measurement.
+
+ Adds a record to the end of the performance measurement log
+ that contains the Handle, Token, and Module.
+ The end time of the new record must be set to zero.
+ If TimeStamp is not zero, then TimeStamp is used to fill in the start time in the record.
+ If TimeStamp is zero, the start time in the record is filled in with the value
+ read from the current time stamp.
+
+ @param Handle Pointer to environment specific context used
+ to identify the component being measured.
+ @param Token Pointer to a Null-terminated ASCII string
+ that identifies the component being measured.
+ @param Module Pointer to a Null-terminated ASCII string
+ that identifies the module being measured.
+ @param TimeStamp 64-bit time stamp.
+
+ @retval RETURN_SUCCESS The start of the measurement was recorded.
+ @retval RETURN_OUT_OF_RESOURCES There are not enough resources to record the measurement.
+
+**/
+RETURN_STATUS
+EFIAPI
+StartPerformanceMeasurement (
+ IN CONST VOID *Handle, OPTIONAL
+ IN CONST CHAR8 *Token, OPTIONAL
+ IN CONST CHAR8 *Module, OPTIONAL
+ IN UINT64 TimeStamp
+ )
+{
+ return StartPerformanceMeasurementEx (Handle, Token, Module, TimeStamp, 0);
+}
+
+/**
+ Searches the performance measurement log from the beginning of the log
+ for the first matching record that contains a zero end time and fills in a valid end time.
+
+ Searches the performance measurement log from the beginning of the log
+ for the first record that matches Handle, Token, and Module and has an end time value of zero.
+ If the record can not be found then return RETURN_NOT_FOUND.
+ If the record is found and TimeStamp is not zero,
+ then the end time in the record is filled in with the value specified by TimeStamp.
+ If the record is found and TimeStamp is zero, then the end time in the matching record
+ is filled in with the current time stamp value.
+
+ @param Handle Pointer to environment specific context used
+ to identify the component being measured.
+ @param Token Pointer to a Null-terminated ASCII string
+ that identifies the component being measured.
+ @param Module Pointer to a Null-terminated ASCII string
+ that identifies the module being measured.
+ @param TimeStamp 64-bit time stamp.
+
+ @retval RETURN_SUCCESS The end of the measurement was recorded.
+ @retval RETURN_NOT_FOUND The specified measurement record could not be found.
+
+**/
+RETURN_STATUS
+EFIAPI
+EndPerformanceMeasurement (
+ IN CONST VOID *Handle, OPTIONAL
+ IN CONST CHAR8 *Token, OPTIONAL
+ IN CONST CHAR8 *Module, OPTIONAL
+ IN UINT64 TimeStamp
+ )
+{
+ return EndPerformanceMeasurementEx (Handle, Token, Module, TimeStamp, 0);
+}
+
+/**
+ Attempts to retrieve a performance measurement log entry from the performance measurement log.
+ It can also retrieve the log created by StartPerformanceMeasurementEx and EndPerformanceMeasurementEx,
+ and then eliminate the Identifier.
+
+ Attempts to retrieve the performance log entry specified by LogEntryKey. If LogEntryKey is
+ zero on entry, then an attempt is made to retrieve the first entry from the performance log,
+ and the key for the second entry in the log is returned. If the performance log is empty,
+ then no entry is retrieved and zero is returned. If LogEntryKey is not zero, then the performance
+ log entry associated with LogEntryKey is retrieved, and the key for the next entry in the log is
+ returned. If LogEntryKey is the key for the last entry in the log, then the last log entry is
+ retrieved and an implementation specific non-zero key value that specifies the end of the performance
+ log is returned. If LogEntryKey is equal this implementation specific non-zero key value, then no entry
+ is retrieved and zero is returned. In the cases where a performance log entry can be returned,
+ the log entry is returned in Handle, Token, Module, StartTimeStamp, and EndTimeStamp.
+ If LogEntryKey is not a valid log entry key for the performance measurement log, then ASSERT().
+ If Handle is NULL, then ASSERT().
+ If Token is NULL, then ASSERT().
+ If Module is NULL, then ASSERT().
+ If StartTimeStamp is NULL, then ASSERT().
+ If EndTimeStamp is NULL, then ASSERT().
+
+ @param LogEntryKey On entry, the key of the performance measurement log entry to retrieve.
+ 0, then the first performance measurement log entry is retrieved.
+ On exit, the key of the next performance log entry.
+ @param Handle Pointer to environment specific context used to identify the component
+ being measured.
+ @param Token Pointer to a Null-terminated ASCII string that identifies the component
+ being measured.
+ @param Module Pointer to a Null-terminated ASCII string that identifies the module
+ being measured.
+ @param StartTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
+ was started.
+ @param EndTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
+ was ended.
+
+ @return The key for the next performance log entry (in general case).
+
+**/
+UINTN
+EFIAPI
+GetPerformanceMeasurement (
+ IN UINTN LogEntryKey,
+ OUT CONST VOID **Handle,
+ OUT CONST CHAR8 **Token,
+ OUT CONST CHAR8 **Module,
+ OUT UINT64 *StartTimeStamp,
+ OUT UINT64 *EndTimeStamp
+ )
+{
+ UINT32 Identifier;
+ return GetPerformanceMeasurementEx (LogEntryKey, Handle, Token, Module, StartTimeStamp, EndTimeStamp, &Identifier);
+}
+
+/**
+ Returns TRUE if the performance measurement macros are enabled.
+
+ This function returns TRUE if the PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
+ PcdPerformanceLibraryPropertyMask is set. Otherwise FALSE is returned.
+
+ @retval TRUE The PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
+ PcdPerformanceLibraryPropertyMask is set.
+ @retval FALSE The PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
+ PcdPerformanceLibraryPropertyMask is clear.
+
+**/
+BOOLEAN
+EFIAPI
+PerformanceMeasurementEnabled (
+ VOID
+ )
+{
+ return mPerformanceMeasurementEnabled;
+}
diff --git a/Core/MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLib.inf b/Core/MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLib.inf
new file mode 100644
index 0000000000..160a749390
--- /dev/null
+++ b/Core/MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLib.inf
@@ -0,0 +1,73 @@
+## @file
+# Performance library instance used by SMM Core.
+#
+# This library provides the performance measurement interfaces and initializes performance
+# logging for the SMM phase.
+# It initializes SMM phase performance logging by publishing the SMM Performance and PerformanceEx Protocol,
+# which is consumed by SmmPerformanceLib to logging performance data in SMM phase.
+# This library is mainly used by SMM Core to start performance logging to ensure that
+# SMM Performance and PerformanceEx Protocol are installed at the very beginning of SMM phase.
+#
+# Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SmmCorePerformanceLib
+ MODULE_UNI_FILE = SmmCorePerformanceLib.uni
+ FILE_GUID = 36290D10-0F47-42c1-BBCE-E191C7928DCF
+ MODULE_TYPE = SMM_CORE
+ VERSION_STRING = 1.0
+ PI_SPECIFICATION_VERSION = 0x0001000A
+ LIBRARY_CLASS = PerformanceLib|SMM_CORE
+
+ CONSTRUCTOR = SmmCorePerformanceLibConstructor
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ SmmCorePerformanceLib.c
+ SmmCorePerformanceLibInternal.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+
+[LibraryClasses]
+ MemoryAllocationLib
+ UefiBootServicesTableLib
+ PcdLib
+ TimerLib
+ BaseMemoryLib
+ BaseLib
+ DebugLib
+ SynchronizationLib
+ SmmServicesTableLib
+ SmmMemLib
+
+[Protocols]
+ gEfiSmmBase2ProtocolGuid ## CONSUMES
+
+[Guids]
+ ## PRODUCES ## UNDEFINED # Install protocol
+ ## CONSUMES ## UNDEFINED # SmiHandlerRegister
+ gSmmPerformanceProtocolGuid
+ ## PRODUCES ## UNDEFINED # Install protocol
+ ## CONSUMES ## UNDEFINED # SmiHandlerRegister
+ gSmmPerformanceExProtocolGuid
+
+[Pcd]
+ gEfiMdePkgTokenSpaceGuid.PcdPerformanceLibraryPropertyMask ## CONSUMES
diff --git a/Core/MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLib.uni b/Core/MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLib.uni
new file mode 100644
index 0000000000..40c74dc5d8
--- /dev/null
+++ b/Core/MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLib.uni
Binary files differ
diff --git a/Core/MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLibInternal.h b/Core/MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLibInternal.h
new file mode 100644
index 0000000000..8eb30320ee
--- /dev/null
+++ b/Core/MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLibInternal.h
@@ -0,0 +1,236 @@
+/** @file
+ Master header files for SmmCorePerformanceLib instance.
+
+ This header file holds the prototypes of the SMM Performance and PerformanceEx Protocol published by this
+ library instance at its constructor.
+
+Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _SMM_CORE_PERFORMANCE_LIB_INTERNAL_H_
+#define _SMM_CORE_PERFORMANCE_LIB_INTERNAL_H_
+
+
+#include <Guid/Performance.h>
+
+#include <Library/SmmServicesTableLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PerformanceLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/TimerLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/SynchronizationLib.h>
+#include <Library/SmmMemLib.h>
+
+#include <Protocol/SmmBase2.h>
+
+//
+// Interface declarations for SMM PerformanceEx Protocol.
+//
+/**
+ Adds a record at the end of the performance measurement log
+ that records the start time of a performance measurement.
+
+ Adds a record to the end of the performance measurement log
+ that contains the Handle, Token, Module and Identifier.
+ The end time of the new record must be set to zero.
+ If TimeStamp is not zero, then TimeStamp is used to fill in the start time in the record.
+ If TimeStamp is zero, the start time in the record is filled in with the value
+ read from the current time stamp.
+
+ @param Handle Pointer to environment specific context used
+ to identify the component being measured.
+ @param Token Pointer to a Null-terminated ASCII string
+ that identifies the component being measured.
+ @param Module Pointer to a Null-terminated ASCII string
+ that identifies the module being measured.
+ @param TimeStamp 64-bit time stamp.
+ @param Identifier 32-bit identifier. If the value is 0, the created record
+ is same as the one created by StartGauge of PERFORMANCE_PROTOCOL.
+
+ @retval EFI_SUCCESS The data was read correctly from the device.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources to record the measurement.
+
+**/
+EFI_STATUS
+EFIAPI
+StartGaugeEx (
+ IN CONST VOID *Handle, OPTIONAL
+ IN CONST CHAR8 *Token, OPTIONAL
+ IN CONST CHAR8 *Module, OPTIONAL
+ IN UINT64 TimeStamp,
+ IN UINT32 Identifier
+ );
+
+/**
+ Searches the performance measurement log from the beginning of the log
+ for the first matching record that contains a zero end time and fills in a valid end time.
+
+ Searches the performance measurement log from the beginning of the log
+ for the first record that matches Handle, Token, Module and Identifier and has an end time value of zero.
+ If the record can not be found then return EFI_NOT_FOUND.
+ If the record is found and TimeStamp is not zero,
+ then the end time in the record is filled in with the value specified by TimeStamp.
+ If the record is found and TimeStamp is zero, then the end time in the matching record
+ is filled in with the current time stamp value.
+
+ @param Handle Pointer to environment specific context used
+ to identify the component being measured.
+ @param Token Pointer to a Null-terminated ASCII string
+ that identifies the component being measured.
+ @param Module Pointer to a Null-terminated ASCII string
+ that identifies the module being measured.
+ @param TimeStamp 64-bit time stamp.
+ @param Identifier 32-bit identifier. If the value is 0, the found record
+ is same as the one found by EndGauge of PERFORMANCE_PROTOCOL.
+
+ @retval EFI_SUCCESS The end of the measurement was recorded.
+ @retval EFI_NOT_FOUND The specified measurement record could not be found.
+
+**/
+EFI_STATUS
+EFIAPI
+EndGaugeEx (
+ IN CONST VOID *Handle, OPTIONAL
+ IN CONST CHAR8 *Token, OPTIONAL
+ IN CONST CHAR8 *Module, OPTIONAL
+ IN UINT64 TimeStamp,
+ IN UINT32 Identifier
+ );
+
+/**
+ Retrieves a previously logged performance measurement.
+ It can also retrieve the log created by StartGauge and EndGauge of PERFORMANCE_PROTOCOL,
+ and then assign the Identifier with 0.
+
+ Retrieves the performance log entry from the performance log specified by LogEntryKey.
+ If it stands for a valid entry, then EFI_SUCCESS is returned and
+ GaugeDataEntryEx stores the pointer to that entry.
+
+ @param LogEntryKey The key for the previous performance measurement log entry.
+ If 0, then the first performance measurement log entry is retrieved.
+ @param GaugeDataEntryEx The indirect pointer to the extended gauge data entry specified by LogEntryKey
+ if the retrieval is successful.
+
+ @retval EFI_SUCCESS The GuageDataEntryEx is successfully found based on LogEntryKey.
+ @retval EFI_NOT_FOUND The LogEntryKey is the last entry (equals to the total entry number).
+ @retval EFI_INVALIDE_PARAMETER The LogEntryKey is not a valid entry (greater than the total entry number).
+ @retval EFI_INVALIDE_PARAMETER GaugeDataEntryEx is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+GetGaugeEx (
+ IN UINTN LogEntryKey,
+ OUT GAUGE_DATA_ENTRY_EX **GaugeDataEntryEx
+ );
+
+//
+// Interface declarations for SMM Performance Protocol.
+//
+/**
+ Adds a record at the end of the performance measurement log
+ that records the start time of a performance measurement.
+
+ Adds a record to the end of the performance measurement log
+ that contains the Handle, Token, and Module.
+ The end time of the new record must be set to zero.
+ If TimeStamp is not zero, then TimeStamp is used to fill in the start time in the record.
+ If TimeStamp is zero, the start time in the record is filled in with the value
+ read from the current time stamp.
+
+ @param Handle Pointer to environment specific context used
+ to identify the component being measured.
+ @param Token Pointer to a Null-terminated ASCII string
+ that identifies the component being measured.
+ @param Module Pointer to a Null-terminated ASCII string
+ that identifies the module being measured.
+ @param TimeStamp 64-bit time stamp.
+
+ @retval EFI_SUCCESS The data was read correctly from the device.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources to record the measurement.
+
+**/
+EFI_STATUS
+EFIAPI
+StartGauge (
+ IN CONST VOID *Handle, OPTIONAL
+ IN CONST CHAR8 *Token, OPTIONAL
+ IN CONST CHAR8 *Module, OPTIONAL
+ IN UINT64 TimeStamp
+ );
+
+/**
+ Searches the performance measurement log from the beginning of the log
+ for the first matching record that contains a zero end time and fills in a valid end time.
+
+ Searches the performance measurement log from the beginning of the log
+ for the first record that matches Handle, Token, and Module and has an end time value of zero.
+ If the record can not be found then return EFI_NOT_FOUND.
+ If the record is found and TimeStamp is not zero,
+ then the end time in the record is filled in with the value specified by TimeStamp.
+ If the record is found and TimeStamp is zero, then the end time in the matching record
+ is filled in with the current time stamp value.
+
+ @param Handle Pointer to environment specific context used
+ to identify the component being measured.
+ @param Token Pointer to a Null-terminated ASCII string
+ that identifies the component being measured.
+ @param Module Pointer to a Null-terminated ASCII string
+ that identifies the module being measured.
+ @param TimeStamp 64-bit time stamp.
+
+ @retval EFI_SUCCESS The end of the measurement was recorded.
+ @retval EFI_NOT_FOUND The specified measurement record could not be found.
+
+**/
+EFI_STATUS
+EFIAPI
+EndGauge (
+ IN CONST VOID *Handle, OPTIONAL
+ IN CONST CHAR8 *Token, OPTIONAL
+ IN CONST CHAR8 *Module, OPTIONAL
+ IN UINT64 TimeStamp
+ );
+
+/**
+ Retrieves a previously logged performance measurement.
+ It can also retrieve the log created by StartGaugeEx and EndGaugeEx of PERFORMANCE_EX_PROTOCOL,
+ and then eliminate the Identifier.
+
+ Retrieves the performance log entry from the performance log specified by LogEntryKey.
+ If it stands for a valid entry, then EFI_SUCCESS is returned and
+ GaugeDataEntry stores the pointer to that entry.
+
+ @param LogEntryKey The key for the previous performance measurement log entry.
+ If 0, then the first performance measurement log entry is retrieved.
+ @param GaugeDataEntry The indirect pointer to the gauge data entry specified by LogEntryKey
+ if the retrieval is successful.
+
+ @retval EFI_SUCCESS The GuageDataEntry is successfully found based on LogEntryKey.
+ @retval EFI_NOT_FOUND The LogEntryKey is the last entry (equals to the total entry number).
+ @retval EFI_INVALIDE_PARAMETER The LogEntryKey is not a valid entry (greater than the total entry number).
+ @retval EFI_INVALIDE_PARAMETER GaugeDataEntry is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+GetGauge (
+ IN UINTN LogEntryKey,
+ OUT GAUGE_DATA_ENTRY **GaugeDataEntry
+ );
+
+
+#endif
diff --git a/Core/MdeModulePkg/Library/SmmCorePlatformHookLibNull/SmmCorePlatformHookLibNull.c b/Core/MdeModulePkg/Library/SmmCorePlatformHookLibNull/SmmCorePlatformHookLibNull.c
new file mode 100644
index 0000000000..ef38c8fdf5
--- /dev/null
+++ b/Core/MdeModulePkg/Library/SmmCorePlatformHookLibNull/SmmCorePlatformHookLibNull.c
@@ -0,0 +1,52 @@
+/** @file
+ Null instance of SmmCorePlatformHookLibNull.
+
+ Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Library/SmmCorePlatformHookLib.h>
+
+/**
+ Performs platform specific tasks before invoking registered SMI handlers.
+
+ This function performs platform specific tasks before invoking registered SMI handlers.
+
+ @retval EFI_SUCCESS The platform hook completes successfully.
+ @retval Other values The paltform hook cannot complete due to some error.
+
+**/
+EFI_STATUS
+EFIAPI
+PlatformHookBeforeSmmDispatch (
+ VOID
+ )
+{
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Performs platform specific tasks after invoking registered SMI handlers.
+
+ This function performs platform specific tasks after invoking registered SMI handlers.
+
+ @retval EFI_SUCCESS The platform hook completes successfully.
+ @retval Other values The paltform hook cannot complete due to some error.
+
+**/
+EFI_STATUS
+EFIAPI
+PlatformHookAfterSmmDispatch (
+ VOID
+ )
+{
+ return EFI_SUCCESS;
+}
diff --git a/Core/MdeModulePkg/Library/SmmCorePlatformHookLibNull/SmmCorePlatformHookLibNull.inf b/Core/MdeModulePkg/Library/SmmCorePlatformHookLibNull/SmmCorePlatformHookLibNull.inf
new file mode 100644
index 0000000000..ff7c1d26b3
--- /dev/null
+++ b/Core/MdeModulePkg/Library/SmmCorePlatformHookLibNull/SmmCorePlatformHookLibNull.inf
@@ -0,0 +1,36 @@
+## @file
+# SMM Core Platform Hook Null Library instance
+#
+# Copyright (c) 2011 - 2014, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SmmCorePlatformHookLibNull
+ MODULE_UNI_FILE = SmmCorePlatformHookLibNull.uni
+ FILE_GUID = FED6583D-2418-4760-AC96-B5E18F0A6326
+ MODULE_TYPE = SMM_CORE
+ VERSION_STRING = 1.0
+ PI_SPECIFICATION_VERSION = 0x0001000A
+ LIBRARY_CLASS = SmmCorePlatformHookLib|SMM_CORE
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ SmmCorePlatformHookLibNull.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
diff --git a/Core/MdeModulePkg/Library/SmmCorePlatformHookLibNull/SmmCorePlatformHookLibNull.uni b/Core/MdeModulePkg/Library/SmmCorePlatformHookLibNull/SmmCorePlatformHookLibNull.uni
new file mode 100644
index 0000000000..40d79a3804
--- /dev/null
+++ b/Core/MdeModulePkg/Library/SmmCorePlatformHookLibNull/SmmCorePlatformHookLibNull.uni
Binary files differ
diff --git a/Core/MdeModulePkg/Library/SmmIpmiLibSmmIpmiProtocol/SmmIpmiLibSmmIpmiProtocol.c b/Core/MdeModulePkg/Library/SmmIpmiLibSmmIpmiProtocol/SmmIpmiLibSmmIpmiProtocol.c
new file mode 100644
index 0000000000..70d12a2138
--- /dev/null
+++ b/Core/MdeModulePkg/Library/SmmIpmiLibSmmIpmiProtocol/SmmIpmiLibSmmIpmiProtocol.c
@@ -0,0 +1,82 @@
+/** @file
+ Implementation of Ipmi Library for SMM.
+
+ Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiSmm.h>
+#include <Protocol/IpmiProtocol.h>
+#include <Library/IpmiLib.h>
+#include <Library/SmmServicesTableLib.h>
+#include <Library/DebugLib.h>
+
+IPMI_PROTOCOL *mIpmiProtocol = NULL;
+
+/**
+ This service enables submitting commands via Ipmi.
+
+ @param[in] NetFunction Net function of the command.
+ @param[in] Command IPMI Command.
+ @param[in] RequestData Command Request Data.
+ @param[in] RequestDataSize Size of Command Request Data.
+ @param[out] ResponseData Command Response Data. The completion code is the first byte of response data.
+ @param[in, out] ResponseDataSize Size of Command Response Data.
+
+ @retval EFI_SUCCESS The command byte stream was successfully submit to the device and a response was successfully received.
+ @retval EFI_NOT_FOUND The command was not successfully sent to the device or a response was not successfully received from the device.
+ @retval EFI_NOT_READY Ipmi Device is not ready for Ipmi command access.
+ @retval EFI_DEVICE_ERROR Ipmi Device hardware error.
+ @retval EFI_TIMEOUT The command time out.
+ @retval EFI_UNSUPPORTED The command was not successfully sent to the device.
+ @retval EFI_OUT_OF_RESOURCES The resource allcation is out of resource or data size error.
+**/
+EFI_STATUS
+EFIAPI
+IpmiSubmitCommand (
+ IN UINT8 NetFunction,
+ IN UINT8 Command,
+ IN UINT8 *RequestData,
+ IN UINT32 RequestDataSize,
+ OUT UINT8 *ResponseData,
+ IN OUT UINT32 *ResponseDataSize
+ )
+{
+ EFI_STATUS Status;
+
+ if (mIpmiProtocol == NULL) {
+ Status = gSmst->SmmLocateProtocol (
+ &gSmmIpmiProtocolGuid,
+ NULL,
+ (VOID **) &mIpmiProtocol
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Smm Ipmi Protocol is not installed. So, IPMI device is not present.
+ //
+ DEBUG ((EFI_D_ERROR, "IpmiSubmitCommand for SMM Status - %r\n", Status));
+ return EFI_NOT_FOUND;
+ }
+ }
+
+ Status = mIpmiProtocol->IpmiSubmitCommand (
+ mIpmiProtocol,
+ NetFunction,
+ Command,
+ RequestData,
+ RequestDataSize,
+ ResponseData,
+ ResponseDataSize
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ return EFI_SUCCESS;
+}
diff --git a/Core/MdeModulePkg/Library/SmmIpmiLibSmmIpmiProtocol/SmmIpmiLibSmmIpmiProtocol.inf b/Core/MdeModulePkg/Library/SmmIpmiLibSmmIpmiProtocol/SmmIpmiLibSmmIpmiProtocol.inf
new file mode 100644
index 0000000000..f13e5a433b
--- /dev/null
+++ b/Core/MdeModulePkg/Library/SmmIpmiLibSmmIpmiProtocol/SmmIpmiLibSmmIpmiProtocol.inf
@@ -0,0 +1,40 @@
+## @file
+# Instance of SMM IPMI Library.
+#
+# Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php.
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SmmIpmiLibSmmIpmiProtocol
+ FILE_GUID = B422FB70-E835-448D-A921-EBA460E105B6
+ MODULE_TYPE = DXE_SMM_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = IpmiLib|DXE_SMM_DRIVER SMM_CORE
+
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ SmmIpmiLibSmmIpmiProtocol.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ DebugLib
+ SmmServicesTableLib
+
+[Protocols]
+ gSmmIpmiProtocolGuid ## SOMETIMES_CONSUMES
diff --git a/Core/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.c b/Core/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.c
new file mode 100644
index 0000000000..9659f014e9
--- /dev/null
+++ b/Core/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.c
@@ -0,0 +1,455 @@
+/** @file
+
+Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiDxe.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/LockBoxLib.h>
+#include <Library/DebugLib.h>
+#include <Protocol/SmmCommunication.h>
+#include <Guid/SmmLockBox.h>
+
+#include "SmmLockBoxLibPrivate.h"
+
+/**
+ This function will save confidential information to lockbox.
+
+ @param Guid the guid to identify the confidential information
+ @param Buffer the address of the confidential information
+ @param Length the length of the confidential information
+
+ @retval RETURN_SUCCESS the information is saved successfully.
+ @retval RETURN_INVALID_PARAMETER the Guid is NULL, or Buffer is NULL, or Length is 0
+ @retval RETURN_ALREADY_STARTED the requested GUID already exist.
+ @retval RETURN_OUT_OF_RESOURCES no enough resource to save the information.
+ @retval RETURN_ACCESS_DENIED it is too late to invoke this interface
+ @retval RETURN_NOT_STARTED it is too early to invoke this interface
+ @retval RETURN_UNSUPPORTED the service is not supported by implementaion.
+**/
+RETURN_STATUS
+EFIAPI
+SaveLockBox (
+ IN GUID *Guid,
+ IN VOID *Buffer,
+ IN UINTN Length
+ )
+{
+ EFI_STATUS Status;
+ EFI_SMM_COMMUNICATION_PROTOCOL *SmmCommunication;
+ EFI_SMM_LOCK_BOX_PARAMETER_SAVE *LockBoxParameterSave;
+ EFI_SMM_COMMUNICATE_HEADER *CommHeader;
+ UINT8 CommBuffer[sizeof(EFI_GUID) + sizeof(UINTN) + sizeof(EFI_SMM_LOCK_BOX_PARAMETER_SAVE)];
+ UINTN CommSize;
+
+ DEBUG ((EFI_D_INFO, "SmmLockBoxDxeLib SaveLockBox - Enter\n"));
+
+ //
+ // Basic check
+ //
+ if ((Guid == NULL) || (Buffer == NULL) || (Length == 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Get needed resource
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiSmmCommunicationProtocolGuid,
+ NULL,
+ (VOID **)&SmmCommunication
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_STARTED;
+ }
+
+ //
+ // Prepare parameter
+ //
+ CommHeader = (EFI_SMM_COMMUNICATE_HEADER *)&CommBuffer[0];
+ CopyMem (&CommHeader->HeaderGuid, &gEfiSmmLockBoxCommunicationGuid, sizeof(gEfiSmmLockBoxCommunicationGuid));
+ CommHeader->MessageLength = sizeof(*LockBoxParameterSave);
+
+ LockBoxParameterSave = (EFI_SMM_LOCK_BOX_PARAMETER_SAVE *)&CommBuffer[OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data)];
+ LockBoxParameterSave->Header.Command = EFI_SMM_LOCK_BOX_COMMAND_SAVE;
+ LockBoxParameterSave->Header.DataLength = sizeof(*LockBoxParameterSave);
+ LockBoxParameterSave->Header.ReturnStatus = (UINT64)-1;
+ CopyMem (&LockBoxParameterSave->Guid, Guid, sizeof(*Guid));
+ LockBoxParameterSave->Buffer = (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer;
+ LockBoxParameterSave->Length = (UINT64)Length;
+
+ //
+ // Send command
+ //
+ CommSize = sizeof(CommBuffer);
+ Status = SmmCommunication->Communicate (
+ SmmCommunication,
+ &CommBuffer[0],
+ &CommSize
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = (EFI_STATUS)LockBoxParameterSave->Header.ReturnStatus;
+
+ DEBUG ((EFI_D_INFO, "SmmLockBoxDxeLib SaveLockBox - Exit (%r)\n", Status));
+
+ //
+ // Done
+ //
+ return Status;
+}
+
+/**
+ This function will set lockbox attributes.
+
+ @param Guid the guid to identify the confidential information
+ @param Attributes the attributes of the lockbox
+
+ @retval RETURN_SUCCESS the information is saved successfully.
+ @retval RETURN_INVALID_PARAMETER attributes is invalid.
+ @retval RETURN_NOT_FOUND the requested GUID not found.
+ @retval RETURN_ACCESS_DENIED it is too late to invoke this interface
+ @retval RETURN_NOT_STARTED it is too early to invoke this interface
+ @retval RETURN_UNSUPPORTED the service is not supported by implementaion.
+**/
+RETURN_STATUS
+EFIAPI
+SetLockBoxAttributes (
+ IN GUID *Guid,
+ IN UINT64 Attributes
+ )
+{
+ EFI_STATUS Status;
+ EFI_SMM_COMMUNICATION_PROTOCOL *SmmCommunication;
+ EFI_SMM_LOCK_BOX_PARAMETER_SET_ATTRIBUTES *LockBoxParameterSetAttributes;
+ EFI_SMM_COMMUNICATE_HEADER *CommHeader;
+ UINT8 CommBuffer[sizeof(EFI_GUID) + sizeof(UINTN) + sizeof(EFI_SMM_LOCK_BOX_PARAMETER_SET_ATTRIBUTES)];
+ UINTN CommSize;
+
+ DEBUG ((EFI_D_INFO, "SmmLockBoxDxeLib SetLockBoxAttributes - Enter\n"));
+
+ //
+ // Basic check
+ //
+ if ((Guid == NULL) ||
+ ((Attributes & ~LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE) != 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Get needed resource
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiSmmCommunicationProtocolGuid,
+ NULL,
+ (VOID **)&SmmCommunication
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_STARTED;
+ }
+
+ //
+ // Prepare parameter
+ //
+ CommHeader = (EFI_SMM_COMMUNICATE_HEADER *)&CommBuffer[0];
+ CopyMem (&CommHeader->HeaderGuid, &gEfiSmmLockBoxCommunicationGuid, sizeof(gEfiSmmLockBoxCommunicationGuid));
+ CommHeader->MessageLength = sizeof(*LockBoxParameterSetAttributes);
+
+ LockBoxParameterSetAttributes = (EFI_SMM_LOCK_BOX_PARAMETER_SET_ATTRIBUTES *)&CommBuffer[OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data)];
+ LockBoxParameterSetAttributes->Header.Command = EFI_SMM_LOCK_BOX_COMMAND_SET_ATTRIBUTES;
+ LockBoxParameterSetAttributes->Header.DataLength = sizeof(*LockBoxParameterSetAttributes);
+ LockBoxParameterSetAttributes->Header.ReturnStatus = (UINT64)-1;
+ CopyMem (&LockBoxParameterSetAttributes->Guid, Guid, sizeof(*Guid));
+ LockBoxParameterSetAttributes->Attributes = (UINT64)Attributes;
+
+ //
+ // Send command
+ //
+ CommSize = sizeof(CommBuffer);
+ Status = SmmCommunication->Communicate (
+ SmmCommunication,
+ &CommBuffer[0],
+ &CommSize
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = (EFI_STATUS)LockBoxParameterSetAttributes->Header.ReturnStatus;
+
+ DEBUG ((EFI_D_INFO, "SmmLockBoxDxeLib SetLockBoxAttributes - Exit (%r)\n", Status));
+
+ //
+ // Done
+ //
+ return Status;
+}
+
+/**
+ This function will update confidential information to lockbox.
+
+ @param Guid the guid to identify the original confidential information
+ @param Offset the offset of the original confidential information
+ @param Buffer the address of the updated confidential information
+ @param Length the length of the updated confidential information
+
+ @retval RETURN_SUCCESS the information is saved successfully.
+ @retval RETURN_INVALID_PARAMETER the Guid is NULL, or Buffer is NULL, or Length is 0.
+ @retval RETURN_NOT_FOUND the requested GUID not found.
+ @retval RETURN_BUFFER_TOO_SMALL the original buffer to too small to hold new information.
+ @retval RETURN_ACCESS_DENIED it is too late to invoke this interface
+ @retval RETURN_NOT_STARTED it is too early to invoke this interface
+ @retval RETURN_UNSUPPORTED the service is not supported by implementaion.
+**/
+RETURN_STATUS
+EFIAPI
+UpdateLockBox (
+ IN GUID *Guid,
+ IN UINTN Offset,
+ IN VOID *Buffer,
+ IN UINTN Length
+ )
+{
+ EFI_STATUS Status;
+ EFI_SMM_COMMUNICATION_PROTOCOL *SmmCommunication;
+ EFI_SMM_LOCK_BOX_PARAMETER_UPDATE *LockBoxParameterUpdate;
+ EFI_SMM_COMMUNICATE_HEADER *CommHeader;
+ UINT8 CommBuffer[sizeof(EFI_GUID) + sizeof(UINTN) + sizeof(EFI_SMM_LOCK_BOX_PARAMETER_UPDATE)];
+ UINTN CommSize;
+
+ DEBUG ((EFI_D_INFO, "SmmLockBoxDxeLib UpdateLockBox - Enter\n"));
+
+ //
+ // Basic check
+ //
+ if ((Guid == NULL) || (Buffer == NULL) || (Length == 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Get needed resource
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiSmmCommunicationProtocolGuid,
+ NULL,
+ (VOID **)&SmmCommunication
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_STARTED;
+ }
+
+ //
+ // Prepare parameter
+ //
+ CommHeader = (EFI_SMM_COMMUNICATE_HEADER *)&CommBuffer[0];
+ CopyMem (&CommHeader->HeaderGuid, &gEfiSmmLockBoxCommunicationGuid, sizeof(gEfiSmmLockBoxCommunicationGuid));
+ CommHeader->MessageLength = sizeof(*LockBoxParameterUpdate);
+
+ LockBoxParameterUpdate = (EFI_SMM_LOCK_BOX_PARAMETER_UPDATE *)(UINTN)&CommBuffer[OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data)];
+ LockBoxParameterUpdate->Header.Command = EFI_SMM_LOCK_BOX_COMMAND_UPDATE;
+ LockBoxParameterUpdate->Header.DataLength = sizeof(*LockBoxParameterUpdate);
+ LockBoxParameterUpdate->Header.ReturnStatus = (UINT64)-1;
+ CopyMem (&LockBoxParameterUpdate->Guid, Guid, sizeof(*Guid));
+ LockBoxParameterUpdate->Offset = (UINT64)Offset;
+ LockBoxParameterUpdate->Buffer = (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer;
+ LockBoxParameterUpdate->Length = (UINT64)Length;
+
+ //
+ // Send command
+ //
+ CommSize = sizeof(CommBuffer);
+ Status = SmmCommunication->Communicate (
+ SmmCommunication,
+ &CommBuffer[0],
+ &CommSize
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = (EFI_STATUS)LockBoxParameterUpdate->Header.ReturnStatus;
+
+ DEBUG ((EFI_D_INFO, "SmmLockBoxDxeLib UpdateLockBox - Exit (%r)\n", Status));
+
+ //
+ // Done
+ //
+ return Status;
+}
+
+/**
+ This function will restore confidential information from lockbox.
+
+ @param Guid the guid to identify the confidential information
+ @param Buffer the address of the restored confidential information
+ NULL means restored to original address, Length MUST be NULL at same time.
+ @param Length the length of the restored confidential information
+
+ @retval RETURN_SUCCESS the information is restored successfully.
+ @retval RETURN_INVALID_PARAMETER the Guid is NULL, or one of Buffer and Length is NULL.
+ @retval RETURN_WRITE_PROTECTED Buffer and Length are NULL, but the LockBox has no
+ LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE attribute.
+ @retval RETURN_BUFFER_TOO_SMALL the Length is too small to hold the confidential information.
+ @retval RETURN_NOT_FOUND the requested GUID not found.
+ @retval RETURN_NOT_STARTED it is too early to invoke this interface
+ @retval RETURN_ACCESS_DENIED not allow to restore to the address
+ @retval RETURN_UNSUPPORTED the service is not supported by implementaion.
+**/
+RETURN_STATUS
+EFIAPI
+RestoreLockBox (
+ IN GUID *Guid,
+ IN VOID *Buffer, OPTIONAL
+ IN OUT UINTN *Length OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_SMM_COMMUNICATION_PROTOCOL *SmmCommunication;
+ EFI_SMM_LOCK_BOX_PARAMETER_RESTORE *LockBoxParameterRestore;
+ EFI_SMM_COMMUNICATE_HEADER *CommHeader;
+ UINT8 CommBuffer[sizeof(EFI_GUID) + sizeof(UINTN) + sizeof(EFI_SMM_LOCK_BOX_PARAMETER_RESTORE)];
+ UINTN CommSize;
+
+ DEBUG ((EFI_D_INFO, "SmmLockBoxDxeLib RestoreLockBox - Enter\n"));
+
+ //
+ // Basic check
+ //
+ if ((Guid == NULL) ||
+ ((Buffer == NULL) && (Length != NULL)) ||
+ ((Buffer != NULL) && (Length == NULL))) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Get needed resource
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiSmmCommunicationProtocolGuid,
+ NULL,
+ (VOID **)&SmmCommunication
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_STARTED;
+ }
+
+ //
+ // Prepare parameter
+ //
+ CommHeader = (EFI_SMM_COMMUNICATE_HEADER *)&CommBuffer[0];
+ CopyMem (&CommHeader->HeaderGuid, &gEfiSmmLockBoxCommunicationGuid, sizeof(gEfiSmmLockBoxCommunicationGuid));
+ CommHeader->MessageLength = sizeof(*LockBoxParameterRestore);
+
+ LockBoxParameterRestore = (EFI_SMM_LOCK_BOX_PARAMETER_RESTORE *)&CommBuffer[OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data)];
+ LockBoxParameterRestore->Header.Command = EFI_SMM_LOCK_BOX_COMMAND_RESTORE;
+ LockBoxParameterRestore->Header.DataLength = sizeof(*LockBoxParameterRestore);
+ LockBoxParameterRestore->Header.ReturnStatus = (UINT64)-1;
+ CopyMem (&LockBoxParameterRestore->Guid, Guid, sizeof(*Guid));
+ LockBoxParameterRestore->Buffer = (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer;
+ if (Length != NULL) {
+ LockBoxParameterRestore->Length = (EFI_PHYSICAL_ADDRESS)*Length;
+ } else {
+ LockBoxParameterRestore->Length = 0;
+ }
+
+ //
+ // Send command
+ //
+ CommSize = sizeof(CommBuffer);
+ Status = SmmCommunication->Communicate (
+ SmmCommunication,
+ &CommBuffer[0],
+ &CommSize
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ if (Length != NULL) {
+ *Length = (UINTN)LockBoxParameterRestore->Length;
+ }
+
+ Status = (EFI_STATUS)LockBoxParameterRestore->Header.ReturnStatus;
+
+ DEBUG ((EFI_D_INFO, "SmmLockBoxDxeLib RestoreLockBox - Exit (%r)\n", Status));
+
+ //
+ // Done
+ //
+ return Status;
+}
+
+/**
+ This function will restore confidential information from all lockbox which have RestoreInPlace attribute.
+
+ @retval RETURN_SUCCESS the information is restored successfully.
+ @retval RETURN_NOT_STARTED it is too early to invoke this interface
+ @retval RETURN_UNSUPPORTED the service is not supported by implementaion.
+**/
+RETURN_STATUS
+EFIAPI
+RestoreAllLockBoxInPlace (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_SMM_COMMUNICATION_PROTOCOL *SmmCommunication;
+ EFI_SMM_LOCK_BOX_PARAMETER_RESTORE_ALL_IN_PLACE *LockBoxParameterRestoreAllInPlace;
+ EFI_SMM_COMMUNICATE_HEADER *CommHeader;
+ UINT8 CommBuffer[sizeof(EFI_GUID) + sizeof(UINTN) + sizeof(EFI_SMM_LOCK_BOX_PARAMETER_RESTORE_ALL_IN_PLACE)];
+ UINTN CommSize;
+
+ DEBUG ((EFI_D_INFO, "SmmLockBoxDxeLib RestoreAllLockBoxInPlace - Enter\n"));
+
+ //
+ // Get needed resource
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiSmmCommunicationProtocolGuid,
+ NULL,
+ (VOID **)&SmmCommunication
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_STARTED;
+ }
+
+ //
+ // Prepare parameter
+ //
+ CommHeader = (EFI_SMM_COMMUNICATE_HEADER *)&CommBuffer[0];
+ CopyMem (&CommHeader->HeaderGuid, &gEfiSmmLockBoxCommunicationGuid, sizeof(gEfiSmmLockBoxCommunicationGuid));
+ CommHeader->MessageLength = sizeof(*LockBoxParameterRestoreAllInPlace);
+
+ LockBoxParameterRestoreAllInPlace = (EFI_SMM_LOCK_BOX_PARAMETER_RESTORE_ALL_IN_PLACE *)&CommBuffer[OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data)];
+ LockBoxParameterRestoreAllInPlace->Header.Command = EFI_SMM_LOCK_BOX_COMMAND_RESTORE_ALL_IN_PLACE;
+ LockBoxParameterRestoreAllInPlace->Header.DataLength = sizeof(*LockBoxParameterRestoreAllInPlace);
+ LockBoxParameterRestoreAllInPlace->Header.ReturnStatus = (UINT64)-1;
+
+ //
+ // Send command
+ //
+ CommSize = sizeof(CommBuffer);
+ Status = SmmCommunication->Communicate (
+ SmmCommunication,
+ &CommBuffer[0],
+ &CommSize
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = (EFI_STATUS)LockBoxParameterRestoreAllInPlace->Header.ReturnStatus;
+
+ DEBUG ((EFI_D_INFO, "SmmLockBoxDxeLib RestoreAllLockBoxInPlace - Exit (%r)\n", Status));
+
+ //
+ // Done
+ //
+ return Status;
+}
+
diff --git a/Core/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.inf b/Core/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.inf
new file mode 100644
index 0000000000..48cdb9c66a
--- /dev/null
+++ b/Core/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.inf
@@ -0,0 +1,50 @@
+## @file
+# DXE LockBox library instance.
+#
+# Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions
+# of the BSD License which accompanies this distribution. The
+# full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SmmLockBoxDxeLib
+ MODULE_UNI_FILE = SmmLockBoxDxeLib.uni
+ FILE_GUID = 4A0054B4-3CA8-4e1b-9339-9B58D5FBB7D2
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = LockBoxLib|DXE_DRIVER DXE_RUNTIME_DRIVER UEFI_DRIVER UEFI_APPLICATION
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ SmmLockBoxDxeLib.c
+ SmmLockBoxLibPrivate.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiBootServicesTableLib
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+
+[Guids]
+ gEfiSmmLockBoxCommunicationGuid ## SOMETIMES_CONSUMES ## GUID # Used to do smm communication
+
+[Protocols]
+ gEfiSmmCommunicationProtocolGuid ## SOMETIMES_CONSUMES
diff --git a/Core/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.uni b/Core/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.uni
new file mode 100644
index 0000000000..78aa7db639
--- /dev/null
+++ b/Core/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.uni
Binary files differ
diff --git a/Core/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxLibPrivate.h b/Core/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxLibPrivate.h
new file mode 100644
index 0000000000..31da89af0f
--- /dev/null
+++ b/Core/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxLibPrivate.h
@@ -0,0 +1,54 @@
+/** @file
+
+Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _SMM_LOCK_BOX_LIB_PRIVATE_H_
+#define _SMM_LOCK_BOX_LIB_PRIVATE_H_
+
+#include <Uefi.h>
+
+#pragma pack(1)
+
+//
+// Below data structure is used for lockbox registration in SMST
+//
+
+#define SMM_LOCK_BOX_SIGNATURE_32 SIGNATURE_64 ('L','O','C','K','B','_','3','2')
+#define SMM_LOCK_BOX_SIGNATURE_64 SIGNATURE_64 ('L','O','C','K','B','_','6','4')
+
+typedef struct {
+ UINT64 Signature;
+ EFI_PHYSICAL_ADDRESS LockBoxDataAddress;
+} SMM_LOCK_BOX_CONTEXT;
+
+//
+// Below data structure is used for lockbox management
+//
+
+#define SMM_LOCK_BOX_DATA_SIGNATURE SIGNATURE_64 ('L','O','C','K','B','O','X','D')
+
+typedef struct {
+ UINT64 Signature;
+ EFI_GUID Guid;
+ EFI_PHYSICAL_ADDRESS Buffer;
+ UINT64 Length;
+ UINT64 Attributes;
+ EFI_PHYSICAL_ADDRESS SmramBuffer;
+ LIST_ENTRY Link;
+} SMM_LOCK_BOX_DATA;
+
+#pragma pack()
+
+#endif
+
diff --git a/Core/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.c b/Core/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.c
new file mode 100644
index 0000000000..bd3204b195
--- /dev/null
+++ b/Core/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.c
@@ -0,0 +1,741 @@
+/** @file
+
+Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiPei.h>
+#include <PiDxe.h>
+#include <PiSmm.h>
+#include <Library/PeiServicesTablePointerLib.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/LockBoxLib.h>
+#include <Library/HobLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PcdLib.h>
+#include <Protocol/SmmCommunication.h>
+#include <Ppi/SmmCommunication.h>
+#include <Ppi/SmmAccess.h>
+#include <Guid/AcpiS3Context.h>
+#include <Guid/SmmLockBox.h>
+
+#include "SmmLockBoxLibPrivate.h"
+
+#if defined (MDE_CPU_IA32)
+typedef struct _LIST_ENTRY64 LIST_ENTRY64;
+struct _LIST_ENTRY64 {
+ LIST_ENTRY64 *ForwardLink;
+ UINT32 Reserved1;
+ LIST_ENTRY64 *BackLink;
+ UINT32 Reserved2;
+};
+
+typedef struct {
+ EFI_TABLE_HEADER Hdr;
+ UINT64 SmmFirmwareVendor;
+ UINT64 SmmFirmwareRevision;
+ UINT64 SmmInstallConfigurationTable;
+ UINT64 SmmIoMemRead;
+ UINT64 SmmIoMemWrite;
+ UINT64 SmmIoIoRead;
+ UINT64 SmmIoIoWrite;
+ UINT64 SmmAllocatePool;
+ UINT64 SmmFreePool;
+ UINT64 SmmAllocatePages;
+ UINT64 SmmFreePages;
+ UINT64 SmmStartupThisAp;
+ UINT64 CurrentlyExecutingCpu;
+ UINT64 NumberOfCpus;
+ UINT64 CpuSaveStateSize;
+ UINT64 CpuSaveState;
+ UINT64 NumberOfTableEntries;
+ UINT64 SmmConfigurationTable;
+} EFI_SMM_SYSTEM_TABLE2_64;
+
+typedef struct {
+ EFI_GUID VendorGuid;
+ UINT64 VendorTable;
+} EFI_CONFIGURATION_TABLE64;
+#endif
+
+#if defined (MDE_CPU_X64)
+typedef LIST_ENTRY LIST_ENTRY64;
+typedef EFI_SMM_SYSTEM_TABLE2 EFI_SMM_SYSTEM_TABLE2_64;
+typedef EFI_CONFIGURATION_TABLE EFI_CONFIGURATION_TABLE64;
+#endif
+
+/**
+ This function return first node of LinkList queue.
+
+ @param LockBoxQueue LinkList queue
+
+ @return first node of LinkList queue
+**/
+LIST_ENTRY *
+InternalInitLinkDxe (
+ IN LIST_ENTRY *LinkList
+ )
+{
+ if ((sizeof(UINTN) == sizeof(UINT32)) && (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) ) {
+ //
+ // 32 PEI + 64 DXE
+ //
+ return (LIST_ENTRY *)(((LIST_ENTRY64 *)LinkList)->ForwardLink);
+ } else {
+ return LinkList->ForwardLink;
+ }
+}
+
+/**
+ This function return next node of LinkList.
+
+ @param Link LinkList node
+
+ @return next node of LinkList
+**/
+LIST_ENTRY *
+InternalNextLinkDxe (
+ IN LIST_ENTRY *Link
+ )
+{
+ if ((sizeof(UINTN) == sizeof(UINT32)) && (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) ) {
+ //
+ // 32 PEI + 64 DXE
+ //
+ return (LIST_ENTRY *)(((LIST_ENTRY64 *)Link)->ForwardLink);
+ } else {
+ return Link->ForwardLink;
+ }
+}
+
+/**
+ This function find LockBox by GUID from SMRAM.
+
+ @param LockBoxQueue The LockBox queue in SMRAM
+ @param Guid The guid to indentify the LockBox
+
+ @return LockBoxData
+**/
+SMM_LOCK_BOX_DATA *
+InternalFindLockBoxByGuidFromSmram (
+ IN LIST_ENTRY *LockBoxQueue,
+ IN EFI_GUID *Guid
+ )
+{
+ LIST_ENTRY *Link;
+ SMM_LOCK_BOX_DATA *LockBox;
+
+ for (Link = InternalInitLinkDxe (LockBoxQueue);
+ Link != LockBoxQueue;
+ Link = InternalNextLinkDxe (Link)) {
+ LockBox = BASE_CR (
+ Link,
+ SMM_LOCK_BOX_DATA,
+ Link
+ );
+ if (CompareGuid (&LockBox->Guid, Guid)) {
+ return LockBox;
+ }
+ }
+ return NULL;
+}
+
+/**
+ Get VendorTable by VendorGuid in Smst.
+
+ @param Signature Signature of SMM_S3_RESUME_STATE
+ @param Smst SMM system table
+ @param VendorGuid vendor guid
+
+ @return vendor table.
+**/
+VOID *
+InternalSmstGetVendorTableByGuid (
+ IN UINT64 Signature,
+ IN EFI_SMM_SYSTEM_TABLE2 *Smst,
+ IN EFI_GUID *VendorGuid
+ )
+{
+ EFI_CONFIGURATION_TABLE *SmmConfigurationTable;
+ UINTN NumberOfTableEntries;
+ UINTN Index;
+ EFI_SMM_SYSTEM_TABLE2_64 *Smst64;
+ EFI_CONFIGURATION_TABLE64 *SmmConfigurationTable64;
+
+ if ((sizeof(UINTN) == sizeof(UINT32)) && (FeaturePcdGet (PcdDxeIplSwitchToLongMode))) {
+ //
+ // 32 PEI + 64 DXE
+ //
+ Smst64 = (EFI_SMM_SYSTEM_TABLE2_64 *)Smst;
+ SmmConfigurationTable64 = (EFI_CONFIGURATION_TABLE64 *)(UINTN)Smst64->SmmConfigurationTable;
+ NumberOfTableEntries = (UINTN)Smst64->NumberOfTableEntries;
+ for (Index = 0; Index < NumberOfTableEntries; Index++) {
+ if (CompareGuid (&SmmConfigurationTable64[Index].VendorGuid, VendorGuid)) {
+ return (VOID *)(UINTN)SmmConfigurationTable64[Index].VendorTable;
+ }
+ }
+ return NULL;
+ } else {
+ SmmConfigurationTable = Smst->SmmConfigurationTable;
+ NumberOfTableEntries = Smst->NumberOfTableEntries;
+ for (Index = 0; Index < NumberOfTableEntries; Index++) {
+ if (CompareGuid (&SmmConfigurationTable[Index].VendorGuid, VendorGuid)) {
+ return (VOID *)SmmConfigurationTable[Index].VendorTable;
+ }
+ }
+ return NULL;
+ }
+}
+
+/**
+ Get SMM LockBox context.
+
+ @return SMM LockBox context.
+**/
+SMM_LOCK_BOX_CONTEXT *
+InternalGetSmmLockBoxContext (
+ VOID
+ )
+{
+ EFI_SMRAM_DESCRIPTOR *SmramDescriptor;
+ SMM_S3_RESUME_STATE *SmmS3ResumeState;
+ VOID *GuidHob;
+ SMM_LOCK_BOX_CONTEXT *SmmLockBoxContext;
+
+ GuidHob = GetFirstGuidHob (&gEfiAcpiVariableGuid);
+ ASSERT (GuidHob != NULL);
+ SmramDescriptor = (EFI_SMRAM_DESCRIPTOR *) GET_GUID_HOB_DATA (GuidHob);
+ SmmS3ResumeState = (SMM_S3_RESUME_STATE *)(UINTN)SmramDescriptor->CpuStart;
+
+ SmmLockBoxContext = (SMM_LOCK_BOX_CONTEXT *)InternalSmstGetVendorTableByGuid (
+ SmmS3ResumeState->Signature,
+ (EFI_SMM_SYSTEM_TABLE2 *)(UINTN)SmmS3ResumeState->Smst,
+ &gEfiSmmLockBoxCommunicationGuid
+ );
+ ASSERT (SmmLockBoxContext != NULL);
+
+ return SmmLockBoxContext;
+}
+
+/**
+ This function will restore confidential information from lockbox in SMRAM directly.
+
+ @param Guid the guid to identify the confidential information
+ @param Buffer the address of the restored confidential information
+ NULL means restored to original address, Length MUST be NULL at same time.
+ @param Length the length of the restored confidential information
+
+ @retval RETURN_SUCCESS the information is restored successfully.
+ @retval RETURN_WRITE_PROTECTED Buffer and Length are NULL, but the LockBox has no
+ LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE attribute.
+ @retval RETURN_BUFFER_TOO_SMALL the Length is too small to hold the confidential information.
+ @retval RETURN_NOT_FOUND the requested GUID not found.
+**/
+EFI_STATUS
+InternalRestoreLockBoxFromSmram (
+ IN GUID *Guid,
+ IN VOID *Buffer, OPTIONAL
+ IN OUT UINTN *Length OPTIONAL
+ )
+{
+ PEI_SMM_ACCESS_PPI *SmmAccess;
+ UINTN Index;
+ EFI_STATUS Status;
+ SMM_LOCK_BOX_CONTEXT *SmmLockBoxContext;
+ LIST_ENTRY *LockBoxQueue;
+ SMM_LOCK_BOX_DATA *LockBox;
+ VOID *RestoreBuffer;
+
+ //
+ // Get needed resource
+ //
+ Status = PeiServicesLocatePpi (
+ &gPeiSmmAccessPpiGuid,
+ 0,
+ NULL,
+ (VOID **)&SmmAccess
+ );
+ if (!EFI_ERROR (Status)) {
+ for (Index = 0; !EFI_ERROR (Status); Index++) {
+ Status = SmmAccess->Open ((EFI_PEI_SERVICES **)GetPeiServicesTablePointer (), SmmAccess, Index);
+ }
+ }
+
+ //
+ // Get LockBox context
+ //
+ SmmLockBoxContext = InternalGetSmmLockBoxContext ();
+ LockBoxQueue = (LIST_ENTRY *)(UINTN)SmmLockBoxContext->LockBoxDataAddress;
+
+ //
+ // We do NOT check Buffer address in SMRAM, because if SMRAM not locked, we trust the caller.
+ //
+
+ //
+ // Restore this, Buffer and Length MUST be both NULL or both non-NULL
+ //
+
+ //
+ // Find LockBox
+ //
+ LockBox = InternalFindLockBoxByGuidFromSmram (LockBoxQueue, Guid);
+ if (LockBox == NULL) {
+ //
+ // Not found
+ //
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Set RestoreBuffer
+ //
+ if (Buffer != NULL) {
+ //
+ // restore to new buffer
+ //
+ RestoreBuffer = Buffer;
+ } else {
+ //
+ // restore to original buffer
+ //
+ if ((LockBox->Attributes & LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE) == 0) {
+ return EFI_WRITE_PROTECTED;
+ }
+ RestoreBuffer = (VOID *)(UINTN)LockBox->Buffer;
+ }
+
+ //
+ // Set RestoreLength
+ //
+ if (Length != NULL) {
+ if (*Length < (UINTN)LockBox->Length) {
+ //
+ // Input buffer is too small to hold all data.
+ //
+ *Length = (UINTN)LockBox->Length;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+ *Length = (UINTN)LockBox->Length;
+ }
+
+ //
+ // Restore data
+ //
+ CopyMem (RestoreBuffer, (VOID *)(UINTN)LockBox->SmramBuffer, (UINTN)LockBox->Length);
+
+ //
+ // Done
+ //
+ return EFI_SUCCESS;
+}
+
+/**
+ This function will restore confidential information from all lockbox which have RestoreInPlace attribute.
+
+ @retval RETURN_SUCCESS the information is restored successfully.
+**/
+EFI_STATUS
+InternalRestoreAllLockBoxInPlaceFromSmram (
+ VOID
+ )
+{
+ PEI_SMM_ACCESS_PPI *SmmAccess;
+ UINTN Index;
+ EFI_STATUS Status;
+ SMM_LOCK_BOX_CONTEXT *SmmLockBoxContext;
+ LIST_ENTRY *LockBoxQueue;
+ SMM_LOCK_BOX_DATA *LockBox;
+ LIST_ENTRY *Link;
+
+ //
+ // Get needed resource
+ //
+ Status = PeiServicesLocatePpi (
+ &gPeiSmmAccessPpiGuid,
+ 0,
+ NULL,
+ (VOID **)&SmmAccess
+ );
+ if (!EFI_ERROR (Status)) {
+ for (Index = 0; !EFI_ERROR (Status); Index++) {
+ Status = SmmAccess->Open ((EFI_PEI_SERVICES **)GetPeiServicesTablePointer (), SmmAccess, Index);
+ }
+ }
+
+ //
+ // Get LockBox context
+ //
+ SmmLockBoxContext = InternalGetSmmLockBoxContext ();
+ LockBoxQueue = (LIST_ENTRY *)(UINTN)SmmLockBoxContext->LockBoxDataAddress;
+
+ //
+ // We do NOT check Buffer address in SMRAM, because if SMRAM not locked, we trust the caller.
+ //
+
+ //
+ // Restore all, Buffer and Length MUST be NULL
+ //
+ for (Link = InternalInitLinkDxe (LockBoxQueue);
+ Link != LockBoxQueue;
+ Link = InternalNextLinkDxe (Link)) {
+ LockBox = BASE_CR (
+ Link,
+ SMM_LOCK_BOX_DATA,
+ Link
+ );
+ if ((LockBox->Attributes & LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE) != 0) {
+ //
+ // Restore data
+ //
+ CopyMem ((VOID *)(UINTN)LockBox->Buffer, (VOID *)(UINTN)LockBox->SmramBuffer, (UINTN)LockBox->Length);
+ }
+ }
+ //
+ // Done
+ //
+ return EFI_SUCCESS;
+}
+
+/**
+ This function will save confidential information to lockbox.
+
+ @param Guid the guid to identify the confidential information
+ @param Buffer the address of the confidential information
+ @param Length the length of the confidential information
+
+ @retval RETURN_SUCCESS the information is saved successfully.
+ @retval RETURN_INVALID_PARAMETER the Guid is NULL, or Buffer is NULL, or Length is 0
+ @retval RETURN_ALREADY_STARTED the requested GUID already exist.
+ @retval RETURN_OUT_OF_RESOURCES no enough resource to save the information.
+ @retval RETURN_ACCESS_DENIED it is too late to invoke this interface
+ @retval RETURN_NOT_STARTED it is too early to invoke this interface
+ @retval RETURN_UNSUPPORTED the service is not supported by implementaion.
+**/
+RETURN_STATUS
+EFIAPI
+SaveLockBox (
+ IN GUID *Guid,
+ IN VOID *Buffer,
+ IN UINTN Length
+ )
+{
+ ASSERT (FALSE);
+
+ //
+ // No support to save at PEI phase
+ //
+ return RETURN_UNSUPPORTED;
+}
+
+/**
+ This function will set lockbox attributes.
+
+ @param Guid the guid to identify the confidential information
+ @param Attributes the attributes of the lockbox
+
+ @retval RETURN_SUCCESS the information is saved successfully.
+ @retval RETURN_INVALID_PARAMETER attributes is invalid.
+ @retval RETURN_NOT_FOUND the requested GUID not found.
+ @retval RETURN_ACCESS_DENIED it is too late to invoke this interface
+ @retval RETURN_NOT_STARTED it is too early to invoke this interface
+ @retval RETURN_UNSUPPORTED the service is not supported by implementaion.
+**/
+RETURN_STATUS
+EFIAPI
+SetLockBoxAttributes (
+ IN GUID *Guid,
+ IN UINT64 Attributes
+ )
+{
+ ASSERT (FALSE);
+
+ //
+ // No support to save at PEI phase
+ //
+ return RETURN_UNSUPPORTED;
+}
+
+/**
+ This function will update confidential information to lockbox.
+
+ @param Guid the guid to identify the original confidential information
+ @param Offset the offset of the original confidential information
+ @param Buffer the address of the updated confidential information
+ @param Length the length of the updated confidential information
+
+ @retval RETURN_SUCCESS the information is saved successfully.
+ @retval RETURN_INVALID_PARAMETER the Guid is NULL, or Buffer is NULL, or Length is 0.
+ @retval RETURN_NOT_FOUND the requested GUID not found.
+ @retval RETURN_BUFFER_TOO_SMALL the original buffer to too small to hold new information.
+ @retval RETURN_ACCESS_DENIED it is too late to invoke this interface
+ @retval RETURN_NOT_STARTED it is too early to invoke this interface
+ @retval RETURN_UNSUPPORTED the service is not supported by implementaion.
+**/
+RETURN_STATUS
+EFIAPI
+UpdateLockBox (
+ IN GUID *Guid,
+ IN UINTN Offset,
+ IN VOID *Buffer,
+ IN UINTN Length
+ )
+{
+ ASSERT (FALSE);
+
+ //
+ // No support to update at PEI phase
+ //
+ return RETURN_UNSUPPORTED;
+}
+
+/**
+ This function will restore confidential information from lockbox.
+
+ @param Guid the guid to identify the confidential information
+ @param Buffer the address of the restored confidential information
+ NULL means restored to original address, Length MUST be NULL at same time.
+ @param Length the length of the restored confidential information
+
+ @retval RETURN_SUCCESS the information is restored successfully.
+ @retval RETURN_INVALID_PARAMETER the Guid is NULL, or one of Buffer and Length is NULL.
+ @retval RETURN_WRITE_PROTECTED Buffer and Length are NULL, but the LockBox has no
+ LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE attribute.
+ @retval RETURN_BUFFER_TOO_SMALL the Length is too small to hold the confidential information.
+ @retval RETURN_NOT_FOUND the requested GUID not found.
+ @retval RETURN_NOT_STARTED it is too early to invoke this interface
+ @retval RETURN_ACCESS_DENIED not allow to restore to the address
+ @retval RETURN_UNSUPPORTED the service is not supported by implementaion.
+**/
+RETURN_STATUS
+EFIAPI
+RestoreLockBox (
+ IN GUID *Guid,
+ IN VOID *Buffer, OPTIONAL
+ IN OUT UINTN *Length OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_PEI_SMM_COMMUNICATION_PPI *SmmCommunicationPpi;
+ EFI_SMM_LOCK_BOX_PARAMETER_RESTORE *LockBoxParameterRestore;
+ EFI_SMM_COMMUNICATE_HEADER *CommHeader;
+ UINT8 CommBuffer[sizeof(EFI_GUID) + sizeof(UINT64) + sizeof(EFI_SMM_LOCK_BOX_PARAMETER_RESTORE)];
+ UINTN CommSize;
+ UINT64 MessageLength;
+
+ //
+ // Please aware that there is UINTN in EFI_SMM_COMMUNICATE_HEADER. It might be UINT64 in DXE, while it is UINT32 in PEI.
+ // typedef struct {
+ // EFI_GUID HeaderGuid;
+ // UINTN MessageLength;
+ // UINT8 Data[1];
+ // } EFI_SMM_COMMUNICATE_HEADER;
+ //
+
+ DEBUG ((EFI_D_INFO, "SmmLockBoxPeiLib RestoreLockBox - Enter\n"));
+
+ //
+ // Basic check
+ //
+ if ((Guid == NULL) ||
+ ((Buffer == NULL) && (Length != NULL)) ||
+ ((Buffer != NULL) && (Length == NULL))) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Get needed resource
+ //
+ Status = PeiServicesLocatePpi (
+ &gEfiPeiSmmCommunicationPpiGuid,
+ 0,
+ NULL,
+ (VOID **)&SmmCommunicationPpi
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_STARTED;
+ }
+
+ //
+ // Prepare parameter
+ //
+ CommHeader = (EFI_SMM_COMMUNICATE_HEADER *)&CommBuffer[0];
+ CopyMem (&CommHeader->HeaderGuid, &gEfiSmmLockBoxCommunicationGuid, sizeof(gEfiSmmLockBoxCommunicationGuid));
+ if ((sizeof(UINTN) == sizeof(UINT32)) && (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) ) {
+ MessageLength = sizeof(*LockBoxParameterRestore);
+ CopyMem (&CommBuffer[OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, MessageLength)], &MessageLength, sizeof(MessageLength));
+ } else {
+ CommHeader->MessageLength = sizeof(*LockBoxParameterRestore);
+ }
+
+ DEBUG ((EFI_D_INFO, "SmmLockBoxPeiLib CommBuffer - %x\n", &CommBuffer[0]));
+ if ((sizeof(UINTN) == sizeof(UINT32)) && (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) ) {
+ LockBoxParameterRestore = (EFI_SMM_LOCK_BOX_PARAMETER_RESTORE *)&CommBuffer[OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, MessageLength) + sizeof(UINT64)];
+ } else {
+ LockBoxParameterRestore = (EFI_SMM_LOCK_BOX_PARAMETER_RESTORE *)&CommBuffer[OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, MessageLength) + sizeof(UINTN)];
+ }
+ DEBUG ((EFI_D_INFO, "SmmLockBoxPeiLib LockBoxParameterRestore - %x\n", LockBoxParameterRestore));
+ LockBoxParameterRestore->Header.Command = EFI_SMM_LOCK_BOX_COMMAND_RESTORE;
+ LockBoxParameterRestore->Header.DataLength = sizeof(*LockBoxParameterRestore);
+ LockBoxParameterRestore->Header.ReturnStatus = (UINT64)-1;
+ if (Guid != 0) {
+ CopyMem (&LockBoxParameterRestore->Guid, Guid, sizeof(*Guid));
+ } else {
+ ZeroMem (&LockBoxParameterRestore->Guid, sizeof(*Guid));
+ }
+ LockBoxParameterRestore->Buffer = (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer;
+ if (Length != NULL) {
+ LockBoxParameterRestore->Length = (EFI_PHYSICAL_ADDRESS)*Length;
+ } else {
+ LockBoxParameterRestore->Length = 0;
+ }
+
+ //
+ // Send command
+ //
+ CommSize = sizeof(CommBuffer);
+ Status = SmmCommunicationPpi->Communicate (
+ SmmCommunicationPpi,
+ &CommBuffer[0],
+ &CommSize
+ );
+ if (Status == EFI_NOT_STARTED) {
+ //
+ // Pei SMM communication not ready yet, so we access SMRAM directly
+ //
+ DEBUG ((EFI_D_INFO, "SmmLockBoxPeiLib Communicate - (%r)\n", Status));
+ Status = InternalRestoreLockBoxFromSmram (Guid, Buffer, Length);
+ LockBoxParameterRestore->Header.ReturnStatus = (UINT64)Status;
+ if (Length != NULL) {
+ LockBoxParameterRestore->Length = (UINT64)*Length;
+ }
+ }
+ ASSERT_EFI_ERROR (Status);
+
+ if (Length != NULL) {
+ *Length = (UINTN)LockBoxParameterRestore->Length;
+ }
+
+ Status = (EFI_STATUS)LockBoxParameterRestore->Header.ReturnStatus;
+ if (Status != EFI_SUCCESS) {
+ // Need or MAX_BIT, because there might be case that SMM is X64 while PEI is IA32.
+ Status |= MAX_BIT;
+ }
+
+ DEBUG ((EFI_D_INFO, "SmmLockBoxPeiLib RestoreLockBox - Exit (%r)\n", Status));
+
+ //
+ // Done
+ //
+ return Status;
+}
+
+/**
+ This function will restore confidential information from all lockbox which have RestoreInPlace attribute.
+
+ @retval RETURN_SUCCESS the information is restored successfully.
+ @retval RETURN_NOT_STARTED it is too early to invoke this interface
+ @retval RETURN_UNSUPPORTED the service is not supported by implementaion.
+**/
+RETURN_STATUS
+EFIAPI
+RestoreAllLockBoxInPlace (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_PEI_SMM_COMMUNICATION_PPI *SmmCommunicationPpi;
+ EFI_SMM_LOCK_BOX_PARAMETER_RESTORE_ALL_IN_PLACE *LockBoxParameterRestoreAllInPlace;
+ EFI_SMM_COMMUNICATE_HEADER *CommHeader;
+ UINT8 CommBuffer[sizeof(EFI_GUID) + sizeof(UINT64) + sizeof(EFI_SMM_LOCK_BOX_PARAMETER_RESTORE_ALL_IN_PLACE)];
+ UINTN CommSize;
+ UINT64 MessageLength;
+
+ //
+ // Please aware that there is UINTN in EFI_SMM_COMMUNICATE_HEADER. It might be UINT64 in DXE, while it is UINT32 in PEI.
+ // typedef struct {
+ // EFI_GUID HeaderGuid;
+ // UINTN MessageLength;
+ // UINT8 Data[1];
+ // } EFI_SMM_COMMUNICATE_HEADER;
+ //
+
+ DEBUG ((EFI_D_INFO, "SmmLockBoxPeiLib RestoreAllLockBoxInPlace - Enter\n"));
+
+ //
+ // Get needed resource
+ //
+ Status = PeiServicesLocatePpi (
+ &gEfiPeiSmmCommunicationPpiGuid,
+ 0,
+ NULL,
+ (VOID **)&SmmCommunicationPpi
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_STARTED;
+ }
+
+ //
+ // Prepare parameter
+ //
+ CommHeader = (EFI_SMM_COMMUNICATE_HEADER *)&CommBuffer[0];
+ CopyMem (&CommHeader->HeaderGuid, &gEfiSmmLockBoxCommunicationGuid, sizeof(gEfiSmmLockBoxCommunicationGuid));
+ if ((sizeof(UINTN) == sizeof(UINT32)) && (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) ) {
+ MessageLength = sizeof(*LockBoxParameterRestoreAllInPlace);
+ CopyMem (&CommBuffer[OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, MessageLength)], &MessageLength, sizeof(MessageLength));
+ } else {
+ CommHeader->MessageLength = sizeof(*LockBoxParameterRestoreAllInPlace);
+ }
+
+ if ((sizeof(UINTN) == sizeof(UINT32)) && (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) ) {
+ LockBoxParameterRestoreAllInPlace = (EFI_SMM_LOCK_BOX_PARAMETER_RESTORE_ALL_IN_PLACE *)&CommBuffer[OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, MessageLength) + sizeof(UINT64)];
+ } else {
+ LockBoxParameterRestoreAllInPlace = (EFI_SMM_LOCK_BOX_PARAMETER_RESTORE_ALL_IN_PLACE *)&CommBuffer[OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, MessageLength) + sizeof(UINTN)];
+ }
+ LockBoxParameterRestoreAllInPlace->Header.Command = EFI_SMM_LOCK_BOX_COMMAND_RESTORE_ALL_IN_PLACE;
+ LockBoxParameterRestoreAllInPlace->Header.DataLength = sizeof(*LockBoxParameterRestoreAllInPlace);
+ LockBoxParameterRestoreAllInPlace->Header.ReturnStatus = (UINT64)-1;
+
+ //
+ // Send command
+ //
+ CommSize = sizeof(CommBuffer);
+ Status = SmmCommunicationPpi->Communicate (
+ SmmCommunicationPpi,
+ &CommBuffer[0],
+ &CommSize
+ );
+ if (Status == EFI_NOT_STARTED) {
+ //
+ // Pei SMM communication not ready yet, so we access SMRAM directly
+ //
+ DEBUG ((EFI_D_INFO, "SmmLockBoxPeiLib Communicate - (%r)\n", Status));
+ Status = InternalRestoreAllLockBoxInPlaceFromSmram ();
+ LockBoxParameterRestoreAllInPlace->Header.ReturnStatus = (UINT64)Status;
+ }
+ ASSERT_EFI_ERROR (Status);
+
+ Status = (EFI_STATUS)LockBoxParameterRestoreAllInPlace->Header.ReturnStatus;
+ if (Status != EFI_SUCCESS) {
+ // Need or MAX_BIT, because there might be case that SMM is X64 while PEI is IA32.
+ Status |= MAX_BIT;
+ }
+
+ DEBUG ((EFI_D_INFO, "SmmLockBoxPeiLib RestoreAllLockBoxInPlace - Exit (%r)\n", Status));
+
+ //
+ // Done
+ //
+ return Status;
+}
+
diff --git a/Core/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.inf b/Core/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.inf
new file mode 100644
index 0000000000..dceff8f0f6
--- /dev/null
+++ b/Core/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.inf
@@ -0,0 +1,59 @@
+## @file
+# PEI LockBox library instance.
+#
+# Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions
+# of the BSD License which accompanies this distribution. The
+# full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SmmLockBoxPeiLib
+ MODULE_UNI_FILE = SmmLockBoxPeiLib.uni
+ FILE_GUID = 5F5E6140-E7BA-4bd6-B85F-236B5BCD8E1E
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = LockBoxLib|PEIM
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ SmmLockBoxPeiLib.c
+ SmmLockBoxLibPrivate.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ PeiServicesTablePointerLib
+ PeiServicesLib
+ BaseLib
+ BaseMemoryLib
+ HobLib
+ DebugLib
+
+[FeaturePcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSwitchToLongMode ## CONSUMES
+
+[Guids]
+ ## SOMETIMES_CONSUMES ## UNDEFINED # Used to do smm communication
+ ## SOMETIMES_CONSUMES ## UNDEFINED # SmmSystemTable
+ gEfiSmmLockBoxCommunicationGuid
+ gEfiAcpiVariableGuid ## SOMETIMES_CONSUMES ## HOB
+
+[Ppis]
+ gEfiPeiSmmCommunicationPpiGuid ## CONSUMES
+ gPeiSmmAccessPpiGuid ## SOMETIMES_CONSUMES
diff --git a/Core/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.uni b/Core/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.uni
new file mode 100644
index 0000000000..d4302d2543
--- /dev/null
+++ b/Core/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.uni
Binary files differ
diff --git a/Core/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.c b/Core/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.c
new file mode 100644
index 0000000000..4960df7555
--- /dev/null
+++ b/Core/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.c
@@ -0,0 +1,591 @@
+/** @file
+
+Copyright (c) 2010 - 2016, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiSmm.h>
+#include <Library/SmmServicesTableLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/LockBoxLib.h>
+#include <Library/DebugLib.h>
+#include <Guid/SmmLockBox.h>
+
+#include "SmmLockBoxLibPrivate.h"
+
+/**
+ We need handle this library carefully. Only one library instance will construct the environment.
+ Below 2 global variable can only be used in constructor. They should NOT be used in any other library functions.
+**/
+SMM_LOCK_BOX_CONTEXT mSmmLockBoxContext;
+LIST_ENTRY mLockBoxQueue = INITIALIZE_LIST_HEAD_VARIABLE (mLockBoxQueue);
+
+BOOLEAN mSmmConfigurationTableInstalled = FALSE;
+
+/**
+ This function return SmmLockBox context from SMST.
+
+ @return SmmLockBox context from SMST.
+**/
+SMM_LOCK_BOX_CONTEXT *
+InternalGetSmmLockBoxContext (
+ VOID
+ )
+{
+ UINTN Index;
+
+ //
+ // Check if gEfiSmmLockBoxCommunicationGuid is installed by someone
+ //
+ for (Index = 0; Index < gSmst->NumberOfTableEntries; Index++) {
+ if (CompareGuid (&gSmst->SmmConfigurationTable[Index].VendorGuid, &gEfiSmmLockBoxCommunicationGuid)) {
+ //
+ // Found. That means some other library instance is already run.
+ // No need to install again, just return.
+ //
+ return (SMM_LOCK_BOX_CONTEXT *)gSmst->SmmConfigurationTable[Index].VendorTable;
+ }
+ }
+
+ //
+ // Not found.
+ //
+ return NULL;
+}
+
+/**
+ Constructor for SmmLockBox library.
+ This is used to set SmmLockBox context, which will be used in PEI phase in S3 boot path later.
+
+ @param[in] ImageHandle Image handle of this driver.
+ @param[in] SystemTable A Pointer to the EFI System Table.
+
+ @retval EFI_SUCEESS
+ @return Others Some error occurs.
+**/
+EFI_STATUS
+EFIAPI
+SmmLockBoxSmmConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ SMM_LOCK_BOX_CONTEXT *SmmLockBoxContext;
+
+ DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib SmmLockBoxSmmConstructor - Enter\n"));
+
+ //
+ // Check if gEfiSmmLockBoxCommunicationGuid is installed by someone
+ //
+ SmmLockBoxContext = InternalGetSmmLockBoxContext ();
+ if (SmmLockBoxContext != NULL) {
+ //
+ // Find it. That means some other library instance is already run.
+ // No need to install again, just return.
+ //
+ DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib SmmLockBoxContext - already installed\n"));
+ DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib SmmLockBoxSmmConstructor - Exit\n"));
+ return EFI_SUCCESS;
+ }
+
+ //
+ // If no one install this, it means this is first instance. Install it.
+ //
+ if (sizeof(UINTN) == sizeof(UINT64)) {
+ mSmmLockBoxContext.Signature = SMM_LOCK_BOX_SIGNATURE_64;
+ } else {
+ mSmmLockBoxContext.Signature = SMM_LOCK_BOX_SIGNATURE_32;
+ }
+ mSmmLockBoxContext.LockBoxDataAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)&mLockBoxQueue;
+
+ Status = gSmst->SmmInstallConfigurationTable (
+ gSmst,
+ &gEfiSmmLockBoxCommunicationGuid,
+ &mSmmLockBoxContext,
+ sizeof(mSmmLockBoxContext)
+ );
+ ASSERT_EFI_ERROR (Status);
+ mSmmConfigurationTableInstalled = TRUE;
+
+ DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib SmmLockBoxContext - %x\n", (UINTN)&mSmmLockBoxContext));
+ DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib LockBoxDataAddress - %x\n", (UINTN)&mLockBoxQueue));
+ DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib SmmLockBoxSmmConstructor - Exit\n"));
+
+ return Status;
+}
+
+/**
+ Destructor for SmmLockBox library.
+ This is used to uninstall SmmLockBoxCommunication configuration table
+ if it has been installed in Constructor.
+
+ @param[in] ImageHandle Image handle of this driver.
+ @param[in] SystemTable A Pointer to the EFI System Table.
+
+ @retval EFI_SUCEESS The destructor always returns EFI_SUCCESS.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmLockBoxSmmDestructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib SmmLockBoxSmmDestructor in %a module\n", gEfiCallerBaseName));
+
+ if (mSmmConfigurationTableInstalled) {
+ Status = gSmst->SmmInstallConfigurationTable (
+ gSmst,
+ &gEfiSmmLockBoxCommunicationGuid,
+ NULL,
+ 0
+ );
+ ASSERT_EFI_ERROR (Status);
+ DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib uninstall SmmLockBoxCommunication configuration table\n"));
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function return SmmLockBox queue address.
+
+ @return SmmLockBox queue address.
+**/
+LIST_ENTRY *
+InternalGetLockBoxQueue (
+ VOID
+ )
+{
+ SMM_LOCK_BOX_CONTEXT *SmmLockBoxContext;
+
+ SmmLockBoxContext = InternalGetSmmLockBoxContext ();
+ ASSERT (SmmLockBoxContext != NULL);
+ if (SmmLockBoxContext == NULL) {
+ return NULL;
+ }
+ return (LIST_ENTRY *)(UINTN)SmmLockBoxContext->LockBoxDataAddress;
+}
+
+/**
+ This function find LockBox by GUID.
+
+ @param Guid The guid to indentify the LockBox
+
+ @return LockBoxData
+**/
+SMM_LOCK_BOX_DATA *
+InternalFindLockBoxByGuid (
+ IN EFI_GUID *Guid
+ )
+{
+ LIST_ENTRY *Link;
+ SMM_LOCK_BOX_DATA *LockBox;
+ LIST_ENTRY *LockBoxQueue;
+
+ LockBoxQueue = InternalGetLockBoxQueue ();
+ ASSERT (LockBoxQueue != NULL);
+
+ for (Link = LockBoxQueue->ForwardLink;
+ Link != LockBoxQueue;
+ Link = Link->ForwardLink) {
+ LockBox = BASE_CR (
+ Link,
+ SMM_LOCK_BOX_DATA,
+ Link
+ );
+ if (CompareGuid (&LockBox->Guid, Guid)) {
+ return LockBox;
+ }
+ }
+ return NULL;
+}
+
+/**
+ This function will save confidential information to lockbox.
+
+ @param Guid the guid to identify the confidential information
+ @param Buffer the address of the confidential information
+ @param Length the length of the confidential information
+
+ @retval RETURN_SUCCESS the information is saved successfully.
+ @retval RETURN_INVALID_PARAMETER the Guid is NULL, or Buffer is NULL, or Length is 0
+ @retval RETURN_ALREADY_STARTED the requested GUID already exist.
+ @retval RETURN_OUT_OF_RESOURCES no enough resource to save the information.
+ @retval RETURN_ACCESS_DENIED it is too late to invoke this interface
+ @retval RETURN_NOT_STARTED it is too early to invoke this interface
+ @retval RETURN_UNSUPPORTED the service is not supported by implementaion.
+**/
+RETURN_STATUS
+EFIAPI
+SaveLockBox (
+ IN GUID *Guid,
+ IN VOID *Buffer,
+ IN UINTN Length
+ )
+{
+ SMM_LOCK_BOX_DATA *LockBox;
+ EFI_PHYSICAL_ADDRESS SmramBuffer;
+ EFI_STATUS Status;
+ LIST_ENTRY *LockBoxQueue;
+
+ DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib SaveLockBox - Enter\n"));
+
+ //
+ // Basic check
+ //
+ if ((Guid == NULL) || (Buffer == NULL) || (Length == 0)) {
+ DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib SaveLockBox - Exit (%r)\n", EFI_INVALID_PARAMETER));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Find LockBox
+ //
+ LockBox = InternalFindLockBoxByGuid (Guid);
+ if (LockBox != NULL) {
+ DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib SaveLockBox - Exit (%r)\n", EFI_ALREADY_STARTED));
+ return EFI_ALREADY_STARTED;
+ }
+
+ //
+ // Allocate SMRAM buffer
+ //
+ Status = gSmst->SmmAllocatePages (
+ AllocateAnyPages,
+ EfiRuntimeServicesData,
+ EFI_SIZE_TO_PAGES (Length),
+ &SmramBuffer
+ );
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib SaveLockBox - Exit (%r)\n", EFI_OUT_OF_RESOURCES));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Allocate LockBox
+ //
+ Status = gSmst->SmmAllocatePool (
+ EfiRuntimeServicesData,
+ sizeof(*LockBox),
+ (VOID **)&LockBox
+ );
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ gSmst->SmmFreePages (SmramBuffer, EFI_SIZE_TO_PAGES (Length));
+ DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib SaveLockBox - Exit (%r)\n", EFI_OUT_OF_RESOURCES));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Save data
+ //
+ CopyMem ((VOID *)(UINTN)SmramBuffer, (VOID *)(UINTN)Buffer, Length);
+
+ //
+ // Insert LockBox to queue
+ //
+ LockBox->Signature = SMM_LOCK_BOX_DATA_SIGNATURE;
+ CopyMem (&LockBox->Guid, Guid, sizeof(EFI_GUID));
+ LockBox->Buffer = (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer;
+ LockBox->Length = (UINT64)Length;
+ LockBox->Attributes = 0;
+ LockBox->SmramBuffer = SmramBuffer;
+
+ DEBUG ((
+ EFI_D_INFO,
+ "LockBoxGuid - %g, SmramBuffer - 0x%lx, Length - 0x%lx\n",
+ &LockBox->Guid,
+ LockBox->SmramBuffer,
+ LockBox->Length
+ ));
+
+ LockBoxQueue = InternalGetLockBoxQueue ();
+ ASSERT (LockBoxQueue != NULL);
+ InsertTailList (LockBoxQueue, &LockBox->Link);
+
+ //
+ // Done
+ //
+ DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib SaveLockBox - Exit (%r)\n", EFI_SUCCESS));
+ return EFI_SUCCESS;
+}
+
+/**
+ This function will set lockbox attributes.
+
+ @param Guid the guid to identify the confidential information
+ @param Attributes the attributes of the lockbox
+
+ @retval RETURN_SUCCESS the information is saved successfully.
+ @retval RETURN_INVALID_PARAMETER attributes is invalid.
+ @retval RETURN_NOT_FOUND the requested GUID not found.
+ @retval RETURN_ACCESS_DENIED it is too late to invoke this interface
+ @retval RETURN_NOT_STARTED it is too early to invoke this interface
+ @retval RETURN_UNSUPPORTED the service is not supported by implementaion.
+**/
+RETURN_STATUS
+EFIAPI
+SetLockBoxAttributes (
+ IN GUID *Guid,
+ IN UINT64 Attributes
+ )
+{
+ SMM_LOCK_BOX_DATA *LockBox;
+
+ DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib SetLockBoxAttributes - Enter\n"));
+
+ //
+ // Basic check
+ //
+ if ((Guid == NULL) ||
+ ((Attributes & ~LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE) != 0)) {
+ DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib SetLockBoxAttributes - Exit (%r)\n", EFI_INVALID_PARAMETER));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Find LockBox
+ //
+ LockBox = InternalFindLockBoxByGuid (Guid);
+ if (LockBox == NULL) {
+ DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib SetLockBoxAttributes - Exit (%r)\n", EFI_NOT_FOUND));
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Update data
+ //
+ LockBox->Attributes = Attributes;
+
+ //
+ // Done
+ //
+ DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib SetLockBoxAttributes - Exit (%r)\n", EFI_SUCCESS));
+ return EFI_SUCCESS;
+}
+
+/**
+ This function will update confidential information to lockbox.
+
+ @param Guid the guid to identify the original confidential information
+ @param Offset the offset of the original confidential information
+ @param Buffer the address of the updated confidential information
+ @param Length the length of the updated confidential information
+
+ @retval RETURN_SUCCESS the information is saved successfully.
+ @retval RETURN_INVALID_PARAMETER the Guid is NULL, or Buffer is NULL, or Length is 0.
+ @retval RETURN_NOT_FOUND the requested GUID not found.
+ @retval RETURN_BUFFER_TOO_SMALL the original buffer to too small to hold new information.
+ @retval RETURN_ACCESS_DENIED it is too late to invoke this interface
+ @retval RETURN_NOT_STARTED it is too early to invoke this interface
+ @retval RETURN_UNSUPPORTED the service is not supported by implementaion.
+**/
+RETURN_STATUS
+EFIAPI
+UpdateLockBox (
+ IN GUID *Guid,
+ IN UINTN Offset,
+ IN VOID *Buffer,
+ IN UINTN Length
+ )
+{
+ SMM_LOCK_BOX_DATA *LockBox;
+
+ DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib UpdateLockBox - Enter\n"));
+
+ //
+ // Basic check
+ //
+ if ((Guid == NULL) || (Buffer == NULL) || (Length == 0)) {
+ DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib UpdateLockBox - Exit (%r)\n", EFI_INVALID_PARAMETER));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Find LockBox
+ //
+ LockBox = InternalFindLockBoxByGuid (Guid);
+ if (LockBox == NULL) {
+ DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib UpdateLockBox - Exit (%r)\n", EFI_NOT_FOUND));
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Update data
+ //
+ if (LockBox->Length < Offset + Length) {
+ DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib UpdateLockBox - Exit (%r)\n", EFI_BUFFER_TOO_SMALL));
+ return EFI_BUFFER_TOO_SMALL;
+ }
+ ASSERT ((UINTN)LockBox->SmramBuffer <= (MAX_ADDRESS - Offset));
+ CopyMem ((VOID *)((UINTN)LockBox->SmramBuffer + Offset), Buffer, Length);
+
+ //
+ // Done
+ //
+ DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib UpdateLockBox - Exit (%r)\n", EFI_SUCCESS));
+ return EFI_SUCCESS;
+}
+
+/**
+ This function will restore confidential information from lockbox.
+
+ @param Guid the guid to identify the confidential information
+ @param Buffer the address of the restored confidential information
+ NULL means restored to original address, Length MUST be NULL at same time.
+ @param Length the length of the restored confidential information
+
+ @retval RETURN_SUCCESS the information is restored successfully.
+ @retval RETURN_INVALID_PARAMETER the Guid is NULL, or one of Buffer and Length is NULL.
+ @retval RETURN_WRITE_PROTECTED Buffer and Length are NULL, but the LockBox has no
+ LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE attribute.
+ @retval RETURN_BUFFER_TOO_SMALL the Length is too small to hold the confidential information.
+ @retval RETURN_NOT_FOUND the requested GUID not found.
+ @retval RETURN_NOT_STARTED it is too early to invoke this interface
+ @retval RETURN_ACCESS_DENIED not allow to restore to the address
+ @retval RETURN_UNSUPPORTED the service is not supported by implementaion.
+**/
+RETURN_STATUS
+EFIAPI
+RestoreLockBox (
+ IN GUID *Guid,
+ IN VOID *Buffer, OPTIONAL
+ IN OUT UINTN *Length OPTIONAL
+ )
+{
+ SMM_LOCK_BOX_DATA *LockBox;
+ VOID *RestoreBuffer;
+
+ DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib RestoreLockBox - Enter\n"));
+
+ //
+ // Restore this, Buffer and Length MUST be both NULL or both non-NULL
+ //
+ if ((Guid == NULL) ||
+ ((Buffer == NULL) && (Length != NULL)) ||
+ ((Buffer != NULL) && (Length == NULL))) {
+ DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib RestoreLockBox - Exit (%r)\n", EFI_INVALID_PARAMETER));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Find LockBox
+ //
+ LockBox = InternalFindLockBoxByGuid (Guid);
+ if (LockBox == NULL) {
+ //
+ // Not found
+ //
+ DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib RestoreLockBox - Exit (%r)\n", EFI_NOT_FOUND));
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Set RestoreBuffer
+ //
+ if (Buffer != NULL) {
+ //
+ // restore to new buffer
+ //
+ RestoreBuffer = Buffer;
+ } else {
+ //
+ // restore to original buffer
+ //
+ if ((LockBox->Attributes & LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE) == 0) {
+ DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib RestoreLockBox - Exit (%r)\n", EFI_WRITE_PROTECTED));
+ return EFI_WRITE_PROTECTED;
+ }
+ RestoreBuffer = (VOID *)(UINTN)LockBox->Buffer;
+ }
+
+ //
+ // Set RestoreLength
+ //
+ if (Length != NULL) {
+ if (*Length < (UINTN)LockBox->Length) {
+ //
+ // Input buffer is too small to hold all data.
+ //
+ *Length = (UINTN)LockBox->Length;
+ DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib RestoreLockBox - Exit (%r)\n", EFI_BUFFER_TOO_SMALL));
+ return EFI_BUFFER_TOO_SMALL;
+ }
+ *Length = (UINTN)LockBox->Length;
+ }
+
+ //
+ // Restore data
+ //
+ CopyMem (RestoreBuffer, (VOID *)(UINTN)LockBox->SmramBuffer, (UINTN)LockBox->Length);
+
+ //
+ // Done
+ //
+ DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib RestoreLockBox - Exit (%r)\n", EFI_SUCCESS));
+ return EFI_SUCCESS;
+}
+
+/**
+ This function will restore confidential information from all lockbox which have RestoreInPlace attribute.
+
+ @retval RETURN_SUCCESS the information is restored successfully.
+ @retval RETURN_NOT_STARTED it is too early to invoke this interface
+ @retval RETURN_UNSUPPORTED the service is not supported by implementaion.
+**/
+RETURN_STATUS
+EFIAPI
+RestoreAllLockBoxInPlace (
+ VOID
+ )
+{
+ SMM_LOCK_BOX_DATA *LockBox;
+ LIST_ENTRY *Link;
+ LIST_ENTRY *LockBoxQueue;
+
+ DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib RestoreAllLockBoxInPlace - Enter\n"));
+
+ LockBoxQueue = InternalGetLockBoxQueue ();
+ ASSERT (LockBoxQueue != NULL);
+
+ //
+ // Restore all, Buffer and Length MUST be NULL
+ //
+ for (Link = LockBoxQueue->ForwardLink;
+ Link != LockBoxQueue;
+ Link = Link->ForwardLink) {
+ LockBox = BASE_CR (
+ Link,
+ SMM_LOCK_BOX_DATA,
+ Link
+ );
+ if ((LockBox->Attributes & LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE) != 0) {
+ //
+ // Restore data
+ //
+ CopyMem ((VOID *)(UINTN)LockBox->Buffer, (VOID *)(UINTN)LockBox->SmramBuffer, (UINTN)LockBox->Length);
+ }
+ }
+ //
+ // Done
+ //
+ DEBUG ((EFI_D_INFO, "SmmLockBoxSmmLib RestoreAllLockBoxInPlace - Exit (%r)\n", EFI_SUCCESS));
+ return EFI_SUCCESS;
+}
+
diff --git a/Core/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.inf b/Core/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.inf
new file mode 100644
index 0000000000..eb7ba0bb2e
--- /dev/null
+++ b/Core/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.inf
@@ -0,0 +1,50 @@
+## @file
+# SMM LockBox library instance.
+#
+# Copyright (c) 2010 - 2016, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions
+# of the BSD License which accompanies this distribution. The
+# full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SmmLockBoxSmmLib
+ MODULE_UNI_FILE = SmmLockBoxSmmLib.uni
+ FILE_GUID = E04894D6-290D-4171-A362-0ACFD939F3C8
+ MODULE_TYPE = DXE_SMM_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = LockBoxLib|DXE_SMM_DRIVER
+ CONSTRUCTOR = SmmLockBoxSmmConstructor
+ DESTRUCTOR = SmmLockBoxSmmDestructor
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ SmmLockBoxSmmLib.c
+ SmmLockBoxLibPrivate.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ SmmServicesTableLib
+ BaseLib
+ DebugLib
+
+[Guids]
+ ## SOMETIMES_CONSUMES ## UNDEFINED # SmmSystemTable
+ ## SOMETIMES_PRODUCES ## UNDEFINED # SmmSystemTable
+ gEfiSmmLockBoxCommunicationGuid
diff --git a/Core/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.uni b/Core/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.uni
new file mode 100644
index 0000000000..a3fef6620b
--- /dev/null
+++ b/Core/MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.uni
Binary files differ
diff --git a/Core/MdeModulePkg/Library/SmmPerformanceLib/SmmPerformanceLib.c b/Core/MdeModulePkg/Library/SmmPerformanceLib/SmmPerformanceLib.c
new file mode 100644
index 0000000000..c01d16d1eb
--- /dev/null
+++ b/Core/MdeModulePkg/Library/SmmPerformanceLib/SmmPerformanceLib.c
@@ -0,0 +1,451 @@
+/** @file
+ Performance Library used in SMM phase.
+
+ This library instance provides infrastructure for SMM drivers to log performance
+ data. It consumes SMM PerformanceEx or Performance Protocol published by SmmCorePerformanceLib
+ to log performance data. If both SMM PerformanceEx and Performance Protocol are not available, it does not log any
+ performance information.
+
+ Copyright (c) 2011 - 2012, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+
+#include <Guid/Performance.h>
+
+#include <Library/PerformanceLib.h>
+#include <Library/DebugLib.h>
+#include <Library/SmmServicesTableLib.h>
+#include <Library/PcdLib.h>
+#include <Library/BaseMemoryLib.h>
+
+//
+// The cached SMM Performance Protocol and SMM PerformanceEx Protocol interface.
+//
+PERFORMANCE_PROTOCOL *mPerformance = NULL;
+PERFORMANCE_EX_PROTOCOL *mPerformanceEx = NULL;
+BOOLEAN mPerformanceMeasurementEnabled;
+
+/**
+ The constructor function initializes the Performance Measurement Enable flag
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmPerformanceLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+
+ mPerformanceMeasurementEnabled = (BOOLEAN) ((PcdGet8(PcdPerformanceLibraryPropertyMask) & PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED) != 0);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ The function caches the pointers to SMM PerformanceEx protocol and Performance Protocol.
+
+ The function locates SMM PerformanceEx protocol and Performance Protocol from protocol database.
+
+ @retval EFI_SUCCESS SMM PerformanceEx protocol or Performance Protocol is successfully located.
+ @retval EFI_NOT_FOUND Both SMM PerformanceEx protocol and Performance Protocol are not located to log performance.
+
+**/
+EFI_STATUS
+GetPerformanceProtocol (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ PERFORMANCE_PROTOCOL *Performance;
+ PERFORMANCE_EX_PROTOCOL *PerformanceEx;
+
+ if (mPerformanceEx != NULL || mPerformance != NULL) {
+ return EFI_SUCCESS;
+ }
+
+ Status = gSmst->SmmLocateProtocol (&gSmmPerformanceExProtocolGuid, NULL, (VOID **) &PerformanceEx);
+ if (!EFI_ERROR (Status)) {
+ ASSERT (PerformanceEx != NULL);
+ //
+ // Cache PerformanceEx Protocol.
+ //
+ mPerformanceEx = PerformanceEx;
+ return EFI_SUCCESS;
+ }
+
+ Status = gSmst->SmmLocateProtocol (&gSmmPerformanceProtocolGuid, NULL, (VOID **) &Performance);
+ if (!EFI_ERROR (Status)) {
+ ASSERT (Performance != NULL);
+ //
+ // Cache performance protocol.
+ //
+ mPerformance = Performance;
+ return EFI_SUCCESS;
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Creates a record for the beginning of a performance measurement.
+
+ Creates a record that contains the Handle, Token, Module and Identifier.
+ If TimeStamp is not zero, then TimeStamp is added to the record as the start time.
+ If TimeStamp is zero, then this function reads the current time stamp
+ and adds that time stamp value to the record as the start time.
+
+ @param Handle Pointer to environment specific context used
+ to identify the component being measured.
+ @param Token Pointer to a Null-terminated ASCII string
+ that identifies the component being measured.
+ @param Module Pointer to a Null-terminated ASCII string
+ that identifies the module being measured.
+ @param TimeStamp 64-bit time stamp.
+ @param Identifier 32-bit identifier. If the value is 0, the created record
+ is same as the one created by StartPerformanceMeasurement.
+
+ @retval RETURN_SUCCESS The start of the measurement was recorded.
+ @retval RETURN_OUT_OF_RESOURCES There are not enough resources to record the measurement.
+
+**/
+RETURN_STATUS
+EFIAPI
+StartPerformanceMeasurementEx (
+ IN CONST VOID *Handle, OPTIONAL
+ IN CONST CHAR8 *Token, OPTIONAL
+ IN CONST CHAR8 *Module, OPTIONAL
+ IN UINT64 TimeStamp,
+ IN UINT32 Identifier
+ )
+{
+ EFI_STATUS Status;
+
+ Status = GetPerformanceProtocol ();
+ if (EFI_ERROR (Status)) {
+ return RETURN_OUT_OF_RESOURCES;
+ }
+
+ if (mPerformanceEx != NULL) {
+ Status = mPerformanceEx->StartGaugeEx (Handle, Token, Module, TimeStamp, Identifier);
+ } else if (mPerformance != NULL) {
+ Status = mPerformance->StartGauge (Handle, Token, Module, TimeStamp);
+ } else {
+ ASSERT (FALSE);
+ }
+
+ return (RETURN_STATUS) Status;
+}
+
+/**
+ Fills in the end time of a performance measurement.
+
+ Looks up the record that matches Handle, Token, Module and Identifier.
+ If the record can not be found then return RETURN_NOT_FOUND.
+ If the record is found and TimeStamp is not zero,
+ then TimeStamp is added to the record as the end time.
+ If the record is found and TimeStamp is zero, then this function reads
+ the current time stamp and adds that time stamp value to the record as the end time.
+
+ @param Handle Pointer to environment specific context used
+ to identify the component being measured.
+ @param Token Pointer to a Null-terminated ASCII string
+ that identifies the component being measured.
+ @param Module Pointer to a Null-terminated ASCII string
+ that identifies the module being measured.
+ @param TimeStamp 64-bit time stamp.
+ @param Identifier 32-bit identifier. If the value is 0, the found record
+ is same as the one found by EndPerformanceMeasurement.
+
+ @retval RETURN_SUCCESS The end of the measurement was recorded.
+ @retval RETURN_NOT_FOUND The specified measurement record could not be found.
+
+**/
+RETURN_STATUS
+EFIAPI
+EndPerformanceMeasurementEx (
+ IN CONST VOID *Handle, OPTIONAL
+ IN CONST CHAR8 *Token, OPTIONAL
+ IN CONST CHAR8 *Module, OPTIONAL
+ IN UINT64 TimeStamp,
+ IN UINT32 Identifier
+ )
+{
+ EFI_STATUS Status;
+
+ Status = GetPerformanceProtocol ();
+ if (EFI_ERROR (Status)) {
+ return RETURN_NOT_FOUND;
+ }
+
+ if (mPerformanceEx != NULL) {
+ Status = mPerformanceEx->EndGaugeEx (Handle, Token, Module, TimeStamp, Identifier);
+ } else if (mPerformance != NULL) {
+ Status = mPerformance->EndGauge (Handle, Token, Module, TimeStamp);
+ } else {
+ ASSERT (FALSE);
+ }
+
+ return (RETURN_STATUS) Status;
+}
+
+/**
+ Attempts to retrieve a performance measurement log entry from the performance measurement log.
+ It can also retrieve the log created by StartPerformanceMeasurement and EndPerformanceMeasurement,
+ and then assign the Identifier with 0.
+
+ Attempts to retrieve the performance log entry specified by LogEntryKey. If LogEntryKey is
+ zero on entry, then an attempt is made to retrieve the first entry from the performance log,
+ and the key for the second entry in the log is returned. If the performance log is empty,
+ then no entry is retrieved and zero is returned. If LogEntryKey is not zero, then the performance
+ log entry associated with LogEntryKey is retrieved, and the key for the next entry in the log is
+ returned. If LogEntryKey is the key for the last entry in the log, then the last log entry is
+ retrieved and an implementation specific non-zero key value that specifies the end of the performance
+ log is returned. If LogEntryKey is equal this implementation specific non-zero key value, then no entry
+ is retrieved and zero is returned. In the cases where a performance log entry can be returned,
+ the log entry is returned in Handle, Token, Module, StartTimeStamp, EndTimeStamp and Identifier.
+ If LogEntryKey is not a valid log entry key for the performance measurement log, then ASSERT().
+ If Handle is NULL, then ASSERT().
+ If Token is NULL, then ASSERT().
+ If Module is NULL, then ASSERT().
+ If StartTimeStamp is NULL, then ASSERT().
+ If EndTimeStamp is NULL, then ASSERT().
+ If Identifier is NULL, then ASSERT().
+
+ @param LogEntryKey On entry, the key of the performance measurement log entry to retrieve.
+ 0, then the first performance measurement log entry is retrieved.
+ On exit, the key of the next performance log entry.
+ @param Handle Pointer to environment specific context used to identify the component
+ being measured.
+ @param Token Pointer to a Null-terminated ASCII string that identifies the component
+ being measured.
+ @param Module Pointer to a Null-terminated ASCII string that identifies the module
+ being measured.
+ @param StartTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
+ was started.
+ @param EndTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
+ was ended.
+ @param Identifier Pointer to the 32-bit identifier that was recorded.
+
+ @return The key for the next performance log entry (in general case).
+
+**/
+UINTN
+EFIAPI
+GetPerformanceMeasurementEx (
+ IN UINTN LogEntryKey,
+ OUT CONST VOID **Handle,
+ OUT CONST CHAR8 **Token,
+ OUT CONST CHAR8 **Module,
+ OUT UINT64 *StartTimeStamp,
+ OUT UINT64 *EndTimeStamp,
+ OUT UINT32 *Identifier
+ )
+{
+ EFI_STATUS Status;
+ GAUGE_DATA_ENTRY_EX *GaugeData;
+
+ GaugeData = NULL;
+
+ ASSERT (Handle != NULL);
+ ASSERT (Token != NULL);
+ ASSERT (Module != NULL);
+ ASSERT (StartTimeStamp != NULL);
+ ASSERT (EndTimeStamp != NULL);
+ ASSERT (Identifier != NULL);
+
+ Status = GetPerformanceProtocol ();
+ if (EFI_ERROR (Status)) {
+ return 0;
+ }
+
+ if (mPerformanceEx != NULL) {
+ Status = mPerformanceEx->GetGaugeEx (LogEntryKey++, &GaugeData);
+ } else if (mPerformance != NULL) {
+ Status = mPerformance->GetGauge (LogEntryKey++, (GAUGE_DATA_ENTRY **) &GaugeData);
+ } else {
+ ASSERT (FALSE);
+ return 0;
+ }
+
+ //
+ // Make sure that LogEntryKey is a valid log entry key,
+ //
+ ASSERT (Status != EFI_INVALID_PARAMETER);
+
+ if (EFI_ERROR (Status)) {
+ //
+ // The LogEntryKey is the last entry (equals to the total entry number).
+ //
+ return 0;
+ }
+
+ ASSERT (GaugeData != NULL);
+
+ *Handle = (VOID *) (UINTN) GaugeData->Handle;
+ *Token = GaugeData->Token;
+ *Module = GaugeData->Module;
+ *StartTimeStamp = GaugeData->StartTimeStamp;
+ *EndTimeStamp = GaugeData->EndTimeStamp;
+ if (mPerformanceEx != NULL) {
+ *Identifier = GaugeData->Identifier;
+ } else {
+ *Identifier = 0;
+ }
+
+ return LogEntryKey;
+}
+
+/**
+ Creates a record for the beginning of a performance measurement.
+
+ Creates a record that contains the Handle, Token, and Module.
+ If TimeStamp is not zero, then TimeStamp is added to the record as the start time.
+ If TimeStamp is zero, then this function reads the current time stamp
+ and adds that time stamp value to the record as the start time.
+
+ @param Handle Pointer to environment specific context used
+ to identify the component being measured.
+ @param Token Pointer to a Null-terminated ASCII string
+ that identifies the component being measured.
+ @param Module Pointer to a Null-terminated ASCII string
+ that identifies the module being measured.
+ @param TimeStamp 64-bit time stamp.
+
+ @retval RETURN_SUCCESS The start of the measurement was recorded.
+ @retval RETURN_OUT_OF_RESOURCES There are not enough resources to record the measurement.
+
+**/
+RETURN_STATUS
+EFIAPI
+StartPerformanceMeasurement (
+ IN CONST VOID *Handle, OPTIONAL
+ IN CONST CHAR8 *Token, OPTIONAL
+ IN CONST CHAR8 *Module, OPTIONAL
+ IN UINT64 TimeStamp
+ )
+{
+ return StartPerformanceMeasurementEx (Handle, Token, Module, TimeStamp, 0);
+}
+
+/**
+ Fills in the end time of a performance measurement.
+
+ Looks up the record that matches Handle, Token, and Module.
+ If the record can not be found then return RETURN_NOT_FOUND.
+ If the record is found and TimeStamp is not zero,
+ then TimeStamp is added to the record as the end time.
+ If the record is found and TimeStamp is zero, then this function reads
+ the current time stamp and adds that time stamp value to the record as the end time.
+
+ @param Handle Pointer to environment specific context used
+ to identify the component being measured.
+ @param Token Pointer to a Null-terminated ASCII string
+ that identifies the component being measured.
+ @param Module Pointer to a Null-terminated ASCII string
+ that identifies the module being measured.
+ @param TimeStamp 64-bit time stamp.
+
+ @retval RETURN_SUCCESS The end of the measurement was recorded.
+ @retval RETURN_NOT_FOUND The specified measurement record could not be found.
+
+**/
+RETURN_STATUS
+EFIAPI
+EndPerformanceMeasurement (
+ IN CONST VOID *Handle, OPTIONAL
+ IN CONST CHAR8 *Token, OPTIONAL
+ IN CONST CHAR8 *Module, OPTIONAL
+ IN UINT64 TimeStamp
+ )
+{
+ return EndPerformanceMeasurementEx (Handle, Token, Module, TimeStamp, 0);
+}
+
+/**
+ Attempts to retrieve a performance measurement log entry from the performance measurement log.
+ It can also retrieve the log created by StartPerformanceMeasurementEx and EndPerformanceMeasurementEx,
+ and then eliminate the Identifier.
+
+ Attempts to retrieve the performance log entry specified by LogEntryKey. If LogEntryKey is
+ zero on entry, then an attempt is made to retrieve the first entry from the performance log,
+ and the key for the second entry in the log is returned. If the performance log is empty,
+ then no entry is retrieved and zero is returned. If LogEntryKey is not zero, then the performance
+ log entry associated with LogEntryKey is retrieved, and the key for the next entry in the log is
+ returned. If LogEntryKey is the key for the last entry in the log, then the last log entry is
+ retrieved and an implementation specific non-zero key value that specifies the end of the performance
+ log is returned. If LogEntryKey is equal this implementation specific non-zero key value, then no entry
+ is retrieved and zero is returned. In the cases where a performance log entry can be returned,
+ the log entry is returned in Handle, Token, Module, StartTimeStamp, and EndTimeStamp.
+ If LogEntryKey is not a valid log entry key for the performance measurement log, then ASSERT().
+ If Handle is NULL, then ASSERT().
+ If Token is NULL, then ASSERT().
+ If Module is NULL, then ASSERT().
+ If StartTimeStamp is NULL, then ASSERT().
+ If EndTimeStamp is NULL, then ASSERT().
+
+ @param LogEntryKey On entry, the key of the performance measurement log entry to retrieve.
+ 0, then the first performance measurement log entry is retrieved.
+ On exit, the key of the next performance log entry.
+ @param Handle Pointer to environment specific context used to identify the component
+ being measured.
+ @param Token Pointer to a Null-terminated ASCII string that identifies the component
+ being measured.
+ @param Module Pointer to a Null-terminated ASCII string that identifies the module
+ being measured.
+ @param StartTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
+ was started.
+ @param EndTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
+ was ended.
+
+ @return The key for the next performance log entry (in general case).
+
+**/
+UINTN
+EFIAPI
+GetPerformanceMeasurement (
+ IN UINTN LogEntryKey,
+ OUT CONST VOID **Handle,
+ OUT CONST CHAR8 **Token,
+ OUT CONST CHAR8 **Module,
+ OUT UINT64 *StartTimeStamp,
+ OUT UINT64 *EndTimeStamp
+ )
+{
+ UINT32 Identifier;
+ return GetPerformanceMeasurementEx (LogEntryKey, Handle, Token, Module, StartTimeStamp, EndTimeStamp, &Identifier);
+}
+
+/**
+ Returns TRUE if the performance measurement macros are enabled.
+
+ This function returns TRUE if the PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
+ PcdPerformanceLibraryPropertyMask is set. Otherwise FALSE is returned.
+
+ @retval TRUE The PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
+ PcdPerformanceLibraryPropertyMask is set.
+ @retval FALSE The PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
+ PcdPerformanceLibraryPropertyMask is clear.
+
+**/
+BOOLEAN
+EFIAPI
+PerformanceMeasurementEnabled (
+ VOID
+ )
+{
+ return mPerformanceMeasurementEnabled;
+}
diff --git a/Core/MdeModulePkg/Library/SmmPerformanceLib/SmmPerformanceLib.inf b/Core/MdeModulePkg/Library/SmmPerformanceLib/SmmPerformanceLib.inf
new file mode 100644
index 0000000000..c3d01a1e51
--- /dev/null
+++ b/Core/MdeModulePkg/Library/SmmPerformanceLib/SmmPerformanceLib.inf
@@ -0,0 +1,57 @@
+## @file
+# Performance library instance used in SMM phase.
+#
+# This library instance provides infrastructure for SMM drivers to log performance
+# data. It consumes SMM PerformanceEx or Performance Protocol published by SmmCorePerformanceLib
+# to log performance data. If both SMM PerformanceEx and Performance Protocol are not available,
+# it does not log any performance information.
+#
+# Copyright (c) 2011 - 2014, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SmmPerformanceLib
+ MODULE_UNI_FILE = SmmPerformanceLib.uni
+ FILE_GUID = 1EDD13E6-D0CD-4432-A692-FF65C9B4F039
+ MODULE_TYPE = DXE_SMM_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = PerformanceLib|DXE_SMM_DRIVER
+
+ CONSTRUCTOR = SmmPerformanceLibConstructor
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ SmmPerformanceLib.c
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+
+[LibraryClasses]
+ PcdLib
+ SmmServicesTableLib
+ DebugLib
+ BaseMemoryLib
+
+[Guids]
+ gSmmPerformanceProtocolGuid ## SOMETIMES_CONSUMES ## UNDEFINED # Locate protocol
+ gSmmPerformanceExProtocolGuid ## SOMETIMES_CONSUMES ## UNDEFINED # Locate protocol
+
+[Pcd]
+ gEfiMdePkgTokenSpaceGuid.PcdPerformanceLibraryPropertyMask ## CONSUMES
diff --git a/Core/MdeModulePkg/Library/SmmPerformanceLib/SmmPerformanceLib.uni b/Core/MdeModulePkg/Library/SmmPerformanceLib/SmmPerformanceLib.uni
new file mode 100644
index 0000000000..aa804d269e
--- /dev/null
+++ b/Core/MdeModulePkg/Library/SmmPerformanceLib/SmmPerformanceLib.uni
Binary files differ
diff --git a/Core/MdeModulePkg/Library/SmmReportStatusCodeLib/ReportStatusCodeLib.c b/Core/MdeModulePkg/Library/SmmReportStatusCodeLib/ReportStatusCodeLib.c
new file mode 100644
index 0000000000..5394fb9e97
--- /dev/null
+++ b/Core/MdeModulePkg/Library/SmmReportStatusCodeLib/ReportStatusCodeLib.c
@@ -0,0 +1,545 @@
+/** @file
+ Report Status Code Library for SMM Phase.
+
+ Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/DebugLib.h>
+#include <Library/SmmServicesTableLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PcdLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+#include <Guid/StatusCodeDataTypeId.h>
+#include <Guid/StatusCodeDataTypeDebug.h>
+#include <Protocol/SmmStatusCode.h>
+
+EFI_SMM_REPORT_STATUS_CODE mReportStatusCode = NULL;
+EFI_SMM_STATUS_CODE_PROTOCOL *mStatusCodeProtocol = NULL;
+
+
+/**
+ Locate the report status code service.
+
+ @return Function pointer to the report status code service.
+ NULL is returned if no status code service is available.
+
+**/
+EFI_SMM_REPORT_STATUS_CODE
+InternalGetReportStatusCode (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+
+ Status = gSmst->SmmLocateProtocol (&gEfiSmmStatusCodeProtocolGuid, NULL, (VOID**)&mStatusCodeProtocol);
+ if (!EFI_ERROR (Status) && mStatusCodeProtocol != NULL) {
+ return mStatusCodeProtocol->ReportStatusCode;
+ }
+ return NULL;
+}
+
+/**
+ Internal worker function that reports a status code through the status code service.
+
+ If status code service is not cached, then this function checks if status code service is
+ available in system. If status code service is not available, then EFI_UNSUPPORTED is
+ returned. If status code service is present, then it is cached in mReportStatusCode.
+ Finally this function reports status code through the status code service.
+
+ @param Type Status code type.
+ @param Value Status code value.
+ @param Instance Status code instance number.
+ @param CallerId Pointer to a GUID that identifies the caller of this
+ function. This is an optional parameter that may be
+ NULL.
+ @param Data Pointer to the extended data buffer. This is an
+ optional parameter that may be NULL.
+
+ @retval EFI_SUCCESS The status code was reported.
+ @retval EFI_UNSUPPORTED Status code service is not available.
+ @retval EFI_UNSUPPORTED Status code type is not supported.
+
+**/
+EFI_STATUS
+InternalReportStatusCode (
+ IN EFI_STATUS_CODE_TYPE Type,
+ IN EFI_STATUS_CODE_VALUE Value,
+ IN UINT32 Instance,
+ IN CONST EFI_GUID *CallerId OPTIONAL,
+ IN EFI_STATUS_CODE_DATA *Data OPTIONAL
+ )
+{
+ if ((ReportProgressCodeEnabled() && ((Type) & EFI_STATUS_CODE_TYPE_MASK) == EFI_PROGRESS_CODE) ||
+ (ReportErrorCodeEnabled() && ((Type) & EFI_STATUS_CODE_TYPE_MASK) == EFI_ERROR_CODE) ||
+ (ReportDebugCodeEnabled() && ((Type) & EFI_STATUS_CODE_TYPE_MASK) == EFI_DEBUG_CODE)) {
+ //
+ // If mReportStatusCode is NULL, then check if status code service is available in system.
+ //
+ if (mReportStatusCode == NULL) {
+ mReportStatusCode = InternalGetReportStatusCode ();
+ if (mReportStatusCode == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+ }
+
+ //
+ // A status code service is present in system, so pass in all the parameters to the service.
+ //
+ return (*mReportStatusCode) (mStatusCodeProtocol, Type, Value, Instance, (EFI_GUID *)CallerId, Data);
+ }
+
+ return EFI_UNSUPPORTED;
+}
+
+
+/**
+ Converts a status code to an 8-bit POST code value.
+
+ Converts the status code specified by CodeType and Value to an 8-bit POST code
+ and returns the 8-bit POST code in PostCode. If CodeType is an
+ EFI_PROGRESS_CODE or CodeType is an EFI_ERROR_CODE, then bits 0..4 of PostCode
+ are set to bits 16..20 of Value, and bits 5..7 of PostCode are set to bits
+ 24..26 of Value., and TRUE is returned. Otherwise, FALSE is returned.
+
+ If PostCode is NULL, then ASSERT().
+
+ @param CodeType The type of status code being converted.
+ @param Value The status code value being converted.
+ @param PostCode A pointer to the 8-bit POST code value to return.
+
+ @retval TRUE The status code specified by CodeType and Value was converted
+ to an 8-bit POST code and returned in PostCode.
+ @retval FALSE The status code specified by CodeType and Value could not be
+ converted to an 8-bit POST code value.
+
+**/
+BOOLEAN
+EFIAPI
+CodeTypeToPostCode (
+ IN EFI_STATUS_CODE_TYPE CodeType,
+ IN EFI_STATUS_CODE_VALUE Value,
+ OUT UINT8 *PostCode
+ )
+{
+ //
+ // If PostCode is NULL, then ASSERT()
+ //
+ ASSERT (PostCode != NULL);
+
+ //
+ // Convert Value to an 8 bit post code
+ //
+ if (((CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_PROGRESS_CODE) ||
+ ((CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_ERROR_CODE) ) {
+ *PostCode = (UINT8) ((((Value & EFI_STATUS_CODE_CLASS_MASK) >> 24) << 5) |
+ (((Value & EFI_STATUS_CODE_SUBCLASS_MASK) >> 16) & 0x1f));
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+/**
+ Extracts ASSERT() information from a status code structure.
+
+ Converts the status code specified by CodeType, Value, and Data to the ASSERT()
+ arguments specified by Filename, Description, and LineNumber. If CodeType is
+ an EFI_ERROR_CODE, and CodeType has a severity of EFI_ERROR_UNRECOVERED, and
+ Value has an operation mask of EFI_SW_EC_ILLEGAL_SOFTWARE_STATE, extract
+ Filename, Description, and LineNumber from the optional data area of the
+ status code buffer specified by Data. The optional data area of Data contains
+ a Null-terminated ASCII string for the FileName, followed by a Null-terminated
+ ASCII string for the Description, followed by a 32-bit LineNumber. If the
+ ASSERT() information could be extracted from Data, then return TRUE.
+ Otherwise, FALSE is returned.
+
+ If Data is NULL, then ASSERT().
+ If Filename is NULL, then ASSERT().
+ If Description is NULL, then ASSERT().
+ If LineNumber is NULL, then ASSERT().
+
+ @param CodeType The type of status code being converted.
+ @param Value The status code value being converted.
+ @param Data Pointer to status code data buffer.
+ @param Filename Pointer to the source file name that generated the ASSERT().
+ @param Description Pointer to the description of the ASSERT().
+ @param LineNumber Pointer to source line number that generated the ASSERT().
+
+ @retval TRUE The status code specified by CodeType, Value, and Data was
+ converted ASSERT() arguments specified by Filename, Description,
+ and LineNumber.
+ @retval FALSE The status code specified by CodeType, Value, and Data could
+ not be converted to ASSERT() arguments.
+
+**/
+BOOLEAN
+EFIAPI
+ReportStatusCodeExtractAssertInfo (
+ IN EFI_STATUS_CODE_TYPE CodeType,
+ IN EFI_STATUS_CODE_VALUE Value,
+ IN CONST EFI_STATUS_CODE_DATA *Data,
+ OUT CHAR8 **Filename,
+ OUT CHAR8 **Description,
+ OUT UINT32 *LineNumber
+ )
+{
+ EFI_DEBUG_ASSERT_DATA *AssertData;
+
+ ASSERT (Data != NULL);
+ ASSERT (Filename != NULL);
+ ASSERT (Description != NULL);
+ ASSERT (LineNumber != NULL);
+
+ if (((CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_ERROR_CODE) &&
+ ((CodeType & EFI_STATUS_CODE_SEVERITY_MASK) == EFI_ERROR_UNRECOVERED) &&
+ ((Value & EFI_STATUS_CODE_OPERATION_MASK) == EFI_SW_EC_ILLEGAL_SOFTWARE_STATE)) {
+ AssertData = (EFI_DEBUG_ASSERT_DATA *)(Data + 1);
+ *Filename = (CHAR8 *)(AssertData + 1);
+ *Description = *Filename + AsciiStrLen (*Filename) + 1;
+ *LineNumber = AssertData->LineNumber;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+/**
+ Extracts DEBUG() information from a status code structure.
+
+ Converts the status code specified by Data to the DEBUG() arguments specified
+ by ErrorLevel, Marker, and Format. If type GUID in Data is
+ EFI_STATUS_CODE_DATA_TYPE_DEBUG_GUID, then extract ErrorLevel, Marker, and
+ Format from the optional data area of the status code buffer specified by Data.
+ The optional data area of Data contains a 32-bit ErrorLevel followed by Marker
+ which is 12 UINTN parameters, followed by a Null-terminated ASCII string for
+ the Format. If the DEBUG() information could be extracted from Data, then
+ return TRUE. Otherwise, FALSE is returned.
+
+ If Data is NULL, then ASSERT().
+ If ErrorLevel is NULL, then ASSERT().
+ If Marker is NULL, then ASSERT().
+ If Format is NULL, then ASSERT().
+
+ @param Data Pointer to status code data buffer.
+ @param ErrorLevel Pointer to error level mask for a debug message.
+ @param Marker Pointer to the variable argument list associated with Format.
+ @param Format Pointer to a Null-terminated ASCII format string of a
+ debug message.
+
+ @retval TRUE The status code specified by Data was converted DEBUG() arguments
+ specified by ErrorLevel, Marker, and Format.
+ @retval FALSE The status code specified by Data could not be converted to
+ DEBUG() arguments.
+
+**/
+BOOLEAN
+EFIAPI
+ReportStatusCodeExtractDebugInfo (
+ IN CONST EFI_STATUS_CODE_DATA *Data,
+ OUT UINT32 *ErrorLevel,
+ OUT BASE_LIST *Marker,
+ OUT CHAR8 **Format
+ )
+{
+ EFI_DEBUG_INFO *DebugInfo;
+
+ ASSERT (Data != NULL);
+ ASSERT (ErrorLevel != NULL);
+ ASSERT (Marker != NULL);
+ ASSERT (Format != NULL);
+
+ //
+ // If the GUID type is not EFI_STATUS_CODE_DATA_TYPE_DEBUG_GUID then return FALSE
+ //
+ if (!CompareGuid (&Data->Type, &gEfiStatusCodeDataTypeDebugGuid)) {
+ return FALSE;
+ }
+
+ //
+ // Retrieve the debug information from the status code record
+ //
+ DebugInfo = (EFI_DEBUG_INFO *)(Data + 1);
+
+ *ErrorLevel = DebugInfo->ErrorLevel;
+
+ //
+ // The first 12 * sizeof (UINT64) bytes following EFI_DEBUG_INFO are for variable arguments
+ // of format in DEBUG string. Its address is returned in Marker and has to be 64-bit aligned.
+ // It must be noticed that EFI_DEBUG_INFO follows EFI_STATUS_CODE_DATA, whose size is
+ // 20 bytes. The size of EFI_DEBUG_INFO is 4 bytes, so we can ensure that Marker
+ // returned is 64-bit aligned.
+ // 64-bit aligned is a must, otherwise retrieving 64-bit parameter from BASE_LIST will
+ // cause unalignment exception.
+ //
+ *Marker = (BASE_LIST) (DebugInfo + 1);
+ *Format = (CHAR8 *)(((UINT64 *)*Marker) + 12);
+
+ return TRUE;
+}
+
+
+/**
+ Reports a status code.
+
+ Reports the status code specified by the parameters Type and Value. Status
+ code also require an instance, caller ID, and extended data. This function
+ passed in a zero instance, NULL extended data, and a caller ID of
+ gEfiCallerIdGuid, which is the GUID for the module.
+
+ ReportStatusCode()must actively prevent recusrsion. If ReportStatusCode()
+ is called while processing another any other Report Status Code Library function,
+ then ReportStatusCode() must return immediately.
+
+ @param Type Status code type.
+ @param Value Status code value.
+
+ @retval EFI_SUCCESS The status code was reported.
+ @retval EFI_DEVICE_ERROR There status code could not be reported due to a
+ device error.
+ @retval EFI_UNSUPPORTED Report status code is not supported
+
+**/
+EFI_STATUS
+EFIAPI
+ReportStatusCode (
+ IN EFI_STATUS_CODE_TYPE Type,
+ IN EFI_STATUS_CODE_VALUE Value
+ )
+{
+ return InternalReportStatusCode (Type, Value, 0, &gEfiCallerIdGuid, NULL);
+}
+
+
+/**
+ Reports a status code with an extended data buffer.
+
+ Allocates and fills in the extended data section of a status code with the
+ extended data specified by ExtendedData and ExtendedDataSize. ExtendedData
+ is assumed to be one of the data structures specified in Related Definitions.
+ These data structure do not have the standard header, so this function is
+ responsible for allocating a buffer large enough for the standard header and
+ the extended data passed into this function. The standard header is filled
+ in with a GUID of gEfiStatusCodeSpecificDataGuid. The status code is reported
+ with a zero instance and a caller ID of gEfiCallerIdGuid.
+
+ ReportStatusCodeWithExtendedData()must actively prevent recursion. If
+ ReportStatusCodeWithExtendedData() is called while processing another any other
+ Report Status Code Library function, then ReportStatusCodeWithExtendedData()
+ must return EFI_DEVICE_ERROR immediately.
+
+ If ExtendedData is NULL, then ASSERT().
+ If ExtendedDataSize is 0, then ASSERT().
+
+ @param Type Status code type.
+ @param Value Status code value.
+ @param ExtendedData Pointer to the extended data buffer to be reported.
+ @param ExtendedDataSize The size, in bytes, of the extended data buffer to
+ be reported.
+
+ @retval EFI_SUCCESS The status code was reported with the extended
+ data specified by ExtendedData and ExtendedDataSize.
+ @retval EFI_OUT_OF_RESOURCES There were not enough resources to allocate the
+ extended data section.
+ @retval EFI_UNSUPPORTED Report status code is not supported
+
+**/
+EFI_STATUS
+EFIAPI
+ReportStatusCodeWithExtendedData (
+ IN EFI_STATUS_CODE_TYPE Type,
+ IN EFI_STATUS_CODE_VALUE Value,
+ IN CONST VOID *ExtendedData,
+ IN UINTN ExtendedDataSize
+ )
+{
+ ASSERT (ExtendedData != NULL);
+ ASSERT (ExtendedDataSize != 0);
+ return ReportStatusCodeEx (
+ Type,
+ Value,
+ 0,
+ NULL,
+ NULL,
+ ExtendedData,
+ ExtendedDataSize
+ );
+}
+
+
+/**
+ Reports a status code with full parameters.
+
+ The function reports a status code. If ExtendedData is NULL and ExtendedDataSize
+ is 0, then an extended data buffer is not reported. If ExtendedData is not
+ NULL and ExtendedDataSize is not 0, then an extended data buffer is allocated.
+ ExtendedData is assumed not have the standard status code header, so this function
+ is responsible for allocating a buffer large enough for the standard header and
+ the extended data passed into this function. The standard header is filled in
+ with a GUID specified by ExtendedDataGuid. If ExtendedDataGuid is NULL, then a
+ GUID of gEfiStatusCodeSpecificDataGuid is used. The status code is reported with
+ an instance specified by Instance and a caller ID specified by CallerId. If
+ CallerId is NULL, then a caller ID of gEfiCallerIdGuid is used.
+
+ ReportStatusCodeEx()must actively prevent recursion. If
+ ReportStatusCodeEx() is called while processing another any
+ other Report Status Code Library function, then
+ ReportStatusCodeEx() must return EFI_DEVICE_ERROR immediately.
+
+ If ExtendedData is NULL and ExtendedDataSize is not zero, then ASSERT().
+ If ExtendedData is not NULL and ExtendedDataSize is zero, then ASSERT().
+
+ @param Type Status code type.
+ @param Value Status code value.
+ @param Instance Status code instance number.
+ @param CallerId Pointer to a GUID that identifies the caller of this
+ function. If this parameter is NULL, then a caller
+ ID of gEfiCallerIdGuid is used.
+ @param ExtendedDataGuid Pointer to the GUID for the extended data buffer.
+ If this parameter is NULL, then a the status code
+ standard header is filled in with
+ gEfiStatusCodeSpecificDataGuid.
+ @param ExtendedData Pointer to the extended data buffer. This is an
+ optional parameter that may be NULL.
+ @param ExtendedDataSize The size, in bytes, of the extended data buffer.
+
+ @retval EFI_SUCCESS The status code was reported.
+ @retval EFI_OUT_OF_RESOURCES There were not enough resources to allocate
+ the extended data section if it was specified.
+ @retval EFI_UNSUPPORTED Report status code is not supported
+
+**/
+EFI_STATUS
+EFIAPI
+ReportStatusCodeEx (
+ IN EFI_STATUS_CODE_TYPE Type,
+ IN EFI_STATUS_CODE_VALUE Value,
+ IN UINT32 Instance,
+ IN CONST EFI_GUID *CallerId OPTIONAL,
+ IN CONST EFI_GUID *ExtendedDataGuid OPTIONAL,
+ IN CONST VOID *ExtendedData OPTIONAL,
+ IN UINTN ExtendedDataSize
+ )
+{
+ EFI_STATUS Status;
+ EFI_STATUS_CODE_DATA *StatusCodeData;
+
+ ASSERT (!((ExtendedData == NULL) && (ExtendedDataSize != 0)));
+ ASSERT (!((ExtendedData != NULL) && (ExtendedDataSize == 0)));
+
+ //
+ // Allocate space for the Status Code Header and its buffer
+ //
+ StatusCodeData = AllocatePool (sizeof (EFI_STATUS_CODE_DATA) + ExtendedDataSize);
+ if (StatusCodeData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Fill in the extended data header
+ //
+ StatusCodeData->HeaderSize = (UINT16) sizeof (EFI_STATUS_CODE_DATA);
+ StatusCodeData->Size = (UINT16) ExtendedDataSize;
+ if (ExtendedDataGuid == NULL) {
+ ExtendedDataGuid = &gEfiStatusCodeSpecificDataGuid;
+ }
+ CopyGuid (&StatusCodeData->Type, ExtendedDataGuid);
+
+ //
+ // Fill in the extended data buffer
+ //
+ if (ExtendedData != NULL) {
+ CopyMem (StatusCodeData + 1, ExtendedData, ExtendedDataSize);
+ }
+
+ //
+ // Report the status code
+ //
+ if (CallerId == NULL) {
+ CallerId = &gEfiCallerIdGuid;
+ }
+ Status = InternalReportStatusCode (Type, Value, Instance, CallerId, StatusCodeData);
+
+ //
+ // Free the allocated buffer
+ //
+ FreePool (StatusCodeData);
+
+ return Status;
+}
+
+
+/**
+ Returns TRUE if status codes of type EFI_PROGRESS_CODE are enabled
+
+ This function returns TRUE if the REPORT_STATUS_CODE_PROPERTY_PROGRESS_CODE_ENABLED
+ bit of PcdReportStatusCodeProperyMask is set. Otherwise FALSE is returned.
+
+ @retval TRUE The REPORT_STATUS_CODE_PROPERTY_PROGRESS_CODE_ENABLED bit of
+ PcdReportStatusCodeProperyMask is set.
+ @retval FALSE The REPORT_STATUS_CODE_PROPERTY_PROGRESS_CODE_ENABLED bit of
+ PcdReportStatusCodeProperyMask is clear.
+
+**/
+BOOLEAN
+EFIAPI
+ReportProgressCodeEnabled (
+ VOID
+ )
+{
+ return (BOOLEAN) ((PcdGet8 (PcdReportStatusCodePropertyMask) & REPORT_STATUS_CODE_PROPERTY_PROGRESS_CODE_ENABLED) != 0);
+}
+
+
+/**
+ Returns TRUE if status codes of type EFI_ERROR_CODE are enabled
+
+ This function returns TRUE if the REPORT_STATUS_CODE_PROPERTY_ERROR_CODE_ENABLED
+ bit of PcdReportStatusCodeProperyMask is set. Otherwise FALSE is returned.
+
+ @retval TRUE The REPORT_STATUS_CODE_PROPERTY_ERROR_CODE_ENABLED bit of
+ PcdReportStatusCodeProperyMask is set.
+ @retval FALSE The REPORT_STATUS_CODE_PROPERTY_ERROR_CODE_ENABLED bit of
+ PcdReportStatusCodeProperyMask is clear.
+
+**/
+BOOLEAN
+EFIAPI
+ReportErrorCodeEnabled (
+ VOID
+ )
+{
+ return (BOOLEAN) ((PcdGet8 (PcdReportStatusCodePropertyMask) & REPORT_STATUS_CODE_PROPERTY_ERROR_CODE_ENABLED) != 0);
+}
+
+
+/**
+ Returns TRUE if status codes of type EFI_DEBUG_CODE are enabled
+
+ This function returns TRUE if the REPORT_STATUS_CODE_PROPERTY_DEBUG_CODE_ENABLED
+ bit of PcdReportStatusCodeProperyMask is set. Otherwise FALSE is returned.
+
+ @retval TRUE The REPORT_STATUS_CODE_PROPERTY_DEBUG_CODE_ENABLED bit of
+ PcdReportStatusCodeProperyMask is set.
+ @retval FALSE The REPORT_STATUS_CODE_PROPERTY_DEBUG_CODE_ENABLED bit of
+ PcdReportStatusCodeProperyMask is clear.
+
+**/
+BOOLEAN
+EFIAPI
+ReportDebugCodeEnabled (
+ VOID
+ )
+{
+ return (BOOLEAN) ((PcdGet8 (PcdReportStatusCodePropertyMask) & REPORT_STATUS_CODE_PROPERTY_DEBUG_CODE_ENABLED) != 0);
+}
diff --git a/Core/MdeModulePkg/Library/SmmReportStatusCodeLib/SmmReportStatusCodeLib.inf b/Core/MdeModulePkg/Library/SmmReportStatusCodeLib/SmmReportStatusCodeLib.inf
new file mode 100644
index 0000000000..15799299fc
--- /dev/null
+++ b/Core/MdeModulePkg/Library/SmmReportStatusCodeLib/SmmReportStatusCodeLib.inf
@@ -0,0 +1,56 @@
+## @file
+# SMM report status code library.
+#
+# Retrieve status code and report status code in SMM phase.
+#
+# Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SmmReportStatusCodeLib
+ MODULE_UNI_FILE = SmmReportStatusCodeLib.uni
+ FILE_GUID = 67089D19-B3D6-4d9e-A0EB-FEDC1F83A1EE
+ MODULE_TYPE = DXE_SMM_DRIVER
+ VERSION_STRING = 1.0
+ PI_SPECIFICATION_VERSION = 0x0001000A
+ LIBRARY_CLASS = ReportStatusCodeLib|DXE_SMM_DRIVER SMM_CORE
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ ReportStatusCodeLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ PcdLib
+ BaseMemoryLib
+ SmmServicesTableLib
+ DebugLib
+ MemoryAllocationLib
+
+[Guids]
+ gEfiStatusCodeSpecificDataGuid ## SOMETIMES_CONSUMES ## UNDEFINED
+ gEfiStatusCodeDataTypeDebugGuid ## SOMETIMES_CONSUMES ## UNDEFINED
+
+[Protocols]
+ gEfiSmmStatusCodeProtocolGuid ## CONSUMES
+
+[Pcd]
+ gEfiMdePkgTokenSpaceGuid.PcdReportStatusCodePropertyMask ## CONSUMES
diff --git a/Core/MdeModulePkg/Library/SmmReportStatusCodeLib/SmmReportStatusCodeLib.uni b/Core/MdeModulePkg/Library/SmmReportStatusCodeLib/SmmReportStatusCodeLib.uni
new file mode 100644
index 0000000000..99cfab569d
--- /dev/null
+++ b/Core/MdeModulePkg/Library/SmmReportStatusCodeLib/SmmReportStatusCodeLib.uni
Binary files differ
diff --git a/Core/MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.c b/Core/MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.c
new file mode 100644
index 0000000000..8a0377b7a4
--- /dev/null
+++ b/Core/MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.c
@@ -0,0 +1,45 @@
+/** @file
+ This library is used by other modules to measure data to TPM.
+
+Copyright (c) 2015, Intel Corporation. All rights reserved. <BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+/**
+ Tpm measure and log data, and extend the measurement result into a specific PCR.
+
+ @param[in] PcrIndex PCR Index.
+ @param[in] EventType Event type.
+ @param[in] EventLog Measurement event log.
+ @param[in] LogLen Event log length in bytes.
+ @param[in] HashData The start of the data buffer to be hashed, extended.
+ @param[in] HashDataLen The length, in bytes, of the buffer referenced by HashData
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_UNSUPPORTED TPM device not available.
+ @retval EFI_OUT_OF_RESOURCES Out of memory.
+ @retval EFI_DEVICE_ERROR The operation was unsuccessful.
+**/
+EFI_STATUS
+EFIAPI
+TpmMeasureAndLogData (
+ IN UINT32 PcrIndex,
+ IN UINT32 EventType,
+ IN VOID *EventLog,
+ IN UINT32 LogLen,
+ IN VOID *HashData,
+ IN UINT64 HashDataLen
+ )
+{
+ //
+ // Do nothing, just return EFI_SUCCESS.
+ //
+ return EFI_SUCCESS;
+}
diff --git a/Core/MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.inf b/Core/MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.inf
new file mode 100644
index 0000000000..fef783a4f9
--- /dev/null
+++ b/Core/MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.inf
@@ -0,0 +1,34 @@
+## @file
+# Provides NULL TPM measurement function.
+#
+# Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = TpmMeasurementLibNull
+ FILE_GUID = 6DFD6E9F-9278-48D8-8F45-B6CFF2C2B69C
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = TpmMeasurementLib|DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SAL_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER
+ MODULE_UNI_FILE = TpmMeasurementLibNull.uni
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF
+#
+
+[Sources]
+ TpmMeasurementLibNull.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
diff --git a/Core/MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.uni b/Core/MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.uni
new file mode 100644
index 0000000000..71a2b1f392
--- /dev/null
+++ b/Core/MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.uni
Binary files differ
diff --git a/Core/MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c b/Core/MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c
new file mode 100644
index 0000000000..52f2d038f3
--- /dev/null
+++ b/Core/MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c
@@ -0,0 +1,2351 @@
+/** @file
+ Library functions which relates with booting.
+
+(C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>
+Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "InternalBm.h"
+
+#define VENDOR_IDENTIFICATION_OFFSET 3
+#define VENDOR_IDENTIFICATION_LENGTH 8
+#define PRODUCT_IDENTIFICATION_OFFSET 11
+#define PRODUCT_IDENTIFICATION_LENGTH 16
+
+CONST UINT16 mBmUsbLangId = 0x0409; // English
+CHAR16 mBmUefiPrefix[] = L"UEFI ";
+
+EFI_BOOT_MANAGER_REFRESH_LEGACY_BOOT_OPTION mBmRefreshLegacyBootOption = NULL;
+EFI_BOOT_MANAGER_LEGACY_BOOT mBmLegacyBoot = NULL;
+
+LIST_ENTRY mPlatformBootDescriptionHandlers = INITIALIZE_LIST_HEAD_VARIABLE (mPlatformBootDescriptionHandlers);
+
+///
+/// This GUID is used for an EFI Variable that stores the front device pathes
+/// for a partial device path that starts with the HD node.
+///
+EFI_GUID mBmHardDriveBootVariableGuid = { 0xfab7e9e1, 0x39dd, 0x4f2b, { 0x84, 0x08, 0xe2, 0x0e, 0x90, 0x6c, 0xb6, 0xde } };
+EFI_GUID mBmAutoCreateBootOptionGuid = { 0x8108ac4e, 0x9f11, 0x4d59, { 0x85, 0x0e, 0xe2, 0x1a, 0x52, 0x2c, 0x59, 0xb2 } };
+
+/**
+ The function registers the legacy boot support capabilities.
+
+ @param RefreshLegacyBootOption The function pointer to create all the legacy boot options.
+ @param LegacyBoot The function pointer to boot the legacy boot option.
+**/
+VOID
+EFIAPI
+EfiBootManagerRegisterLegacyBootSupport (
+ EFI_BOOT_MANAGER_REFRESH_LEGACY_BOOT_OPTION RefreshLegacyBootOption,
+ EFI_BOOT_MANAGER_LEGACY_BOOT LegacyBoot
+ )
+{
+ mBmRefreshLegacyBootOption = RefreshLegacyBootOption;
+ mBmLegacyBoot = LegacyBoot;
+}
+
+/**
+ Return TRUE when the boot option is auto-created instead of manually added.
+
+ @param BootOption Pointer to the boot option to check.
+
+ @retval TRUE The boot option is auto-created.
+ @retval FALSE The boot option is manually added.
+**/
+BOOLEAN
+BmIsAutoCreateBootOption (
+ EFI_BOOT_MANAGER_LOAD_OPTION *BootOption
+ )
+{
+ if ((BootOption->OptionalDataSize == sizeof (EFI_GUID)) &&
+ CompareGuid ((EFI_GUID *) BootOption->OptionalData, &mBmAutoCreateBootOptionGuid)
+ ) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/**
+ For a bootable Device path, return its boot type.
+
+ @param DevicePath The bootable device Path to check
+
+ @retval AcpiFloppyBoot If given device path contains ACPI_DEVICE_PATH type device path node
+ which HID is floppy device.
+ @retval MessageAtapiBoot If given device path contains MESSAGING_DEVICE_PATH type device path node
+ and its last device path node's subtype is MSG_ATAPI_DP.
+ @retval MessageSataBoot If given device path contains MESSAGING_DEVICE_PATH type device path node
+ and its last device path node's subtype is MSG_SATA_DP.
+ @retval MessageScsiBoot If given device path contains MESSAGING_DEVICE_PATH type device path node
+ and its last device path node's subtype is MSG_SCSI_DP.
+ @retval MessageUsbBoot If given device path contains MESSAGING_DEVICE_PATH type device path node
+ and its last device path node's subtype is MSG_USB_DP.
+ @retval MessageNetworkBoot If given device path contains MESSAGING_DEVICE_PATH type device path node
+ and its last device path node's subtype is MSG_MAC_ADDR_DP, MSG_VLAN_DP,
+ MSG_IPv4_DP or MSG_IPv6_DP.
+ @retval MessageHttpBoot If given device path contains MESSAGING_DEVICE_PATH type device path node
+ and its last device path node's subtype is MSG_URI_DP.
+ @retval UnsupportedBoot If tiven device path doesn't match the above condition, it's not supported.
+
+**/
+BM_BOOT_TYPE
+BmDevicePathType (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *Node;
+ EFI_DEVICE_PATH_PROTOCOL *NextNode;
+
+ ASSERT (DevicePath != NULL);
+
+ for (Node = DevicePath; !IsDevicePathEndType (Node); Node = NextDevicePathNode (Node)) {
+ switch (DevicePathType (Node)) {
+
+ case ACPI_DEVICE_PATH:
+ if (EISA_ID_TO_NUM (((ACPI_HID_DEVICE_PATH *) Node)->HID) == 0x0604) {
+ return BmAcpiFloppyBoot;
+ }
+ break;
+
+ case HARDWARE_DEVICE_PATH:
+ if (DevicePathSubType (Node) == HW_CONTROLLER_DP) {
+ return BmHardwareDeviceBoot;
+ }
+ break;
+
+ case MESSAGING_DEVICE_PATH:
+ //
+ // Skip LUN device node
+ //
+ NextNode = Node;
+ do {
+ NextNode = NextDevicePathNode (NextNode);
+ } while (
+ (DevicePathType (NextNode) == MESSAGING_DEVICE_PATH) &&
+ (DevicePathSubType(NextNode) == MSG_DEVICE_LOGICAL_UNIT_DP)
+ );
+
+ //
+ // If the device path not only point to driver device, it is not a messaging device path,
+ //
+ if (!IsDevicePathEndType (NextNode)) {
+ continue;
+ }
+
+ switch (DevicePathSubType (Node)) {
+ case MSG_ATAPI_DP:
+ return BmMessageAtapiBoot;
+ break;
+
+ case MSG_SATA_DP:
+ return BmMessageSataBoot;
+ break;
+
+ case MSG_USB_DP:
+ return BmMessageUsbBoot;
+ break;
+
+ case MSG_SCSI_DP:
+ return BmMessageScsiBoot;
+ break;
+
+ case MSG_MAC_ADDR_DP:
+ case MSG_VLAN_DP:
+ case MSG_IPv4_DP:
+ case MSG_IPv6_DP:
+ return BmMessageNetworkBoot;
+ break;
+
+ case MSG_URI_DP:
+ return BmMessageHttpBoot;
+ break;
+ }
+ }
+ }
+
+ return BmMiscBoot;
+}
+
+/**
+ Find the boot option in the NV storage and return the option number.
+
+ @param OptionToFind Boot option to be checked.
+
+ @return The option number of the found boot option.
+
+**/
+UINTN
+BmFindBootOptionInVariable (
+ IN EFI_BOOT_MANAGER_LOAD_OPTION *OptionToFind
+ )
+{
+ EFI_STATUS Status;
+ EFI_BOOT_MANAGER_LOAD_OPTION BootOption;
+ UINTN OptionNumber;
+ CHAR16 OptionName[BM_OPTION_NAME_LEN];
+ EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
+ UINTN BootOptionCount;
+ UINTN Index;
+
+ OptionNumber = LoadOptionNumberUnassigned;
+
+ //
+ // Try to match the variable exactly if the option number is assigned
+ //
+ if (OptionToFind->OptionNumber != LoadOptionNumberUnassigned) {
+ UnicodeSPrint (
+ OptionName, sizeof (OptionName), L"%s%04x",
+ mBmLoadOptionName[OptionToFind->OptionType], OptionToFind->OptionNumber
+ );
+ Status = EfiBootManagerVariableToLoadOption (OptionName, &BootOption);
+
+ if (!EFI_ERROR (Status)) {
+ ASSERT (OptionToFind->OptionNumber == BootOption.OptionNumber);
+ if ((OptionToFind->Attributes == BootOption.Attributes) &&
+ (StrCmp (OptionToFind->Description, BootOption.Description) == 0) &&
+ (CompareMem (OptionToFind->FilePath, BootOption.FilePath, GetDevicePathSize (OptionToFind->FilePath)) == 0) &&
+ (OptionToFind->OptionalDataSize == BootOption.OptionalDataSize) &&
+ (CompareMem (OptionToFind->OptionalData, BootOption.OptionalData, OptionToFind->OptionalDataSize) == 0)
+ ) {
+ OptionNumber = OptionToFind->OptionNumber;
+ }
+ EfiBootManagerFreeLoadOption (&BootOption);
+ }
+ }
+
+ //
+ // The option number assigned is either incorrect or unassigned.
+ //
+ if (OptionNumber == LoadOptionNumberUnassigned) {
+ BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
+
+ Index = BmFindLoadOption (OptionToFind, BootOptions, BootOptionCount);
+ if (Index != -1) {
+ OptionNumber = BootOptions[Index].OptionNumber;
+ }
+
+ EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
+ }
+
+ return OptionNumber;
+}
+
+/**
+ Get the file buffer using a Memory Mapped Device Path.
+
+ FV address may change across reboot. This routine promises the FV file device path is right.
+
+ @param DevicePath The Memory Mapped Device Path to get the file buffer.
+ @param FullPath Receive the updated FV Device Path pointint to the file.
+ @param FileSize Receive the file buffer size.
+
+ @return The file buffer.
+**/
+VOID *
+BmGetFileBufferByMemmapFv (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
+ OUT UINTN *FileSize
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ EFI_DEVICE_PATH_PROTOCOL *FvFileNode;
+ EFI_HANDLE FvHandle;
+ EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
+ UINT32 AuthenticationStatus;
+ UINTN FvHandleCount;
+ EFI_HANDLE *FvHandles;
+ EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
+ VOID *FileBuffer;
+
+ FvFileNode = DevicePath;
+ Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &FvFileNode, &FvHandle);
+ if (!EFI_ERROR (Status)) {
+ FileBuffer = GetFileBufferByFilePath (TRUE, DevicePath, FileSize, &AuthenticationStatus);
+ if (FileBuffer != NULL) {
+ *FullPath = DuplicateDevicePath (DevicePath);
+ }
+ return FileBuffer;
+ }
+
+ FvFileNode = NextDevicePathNode (DevicePath);
+
+ //
+ // Firstly find the FV file in current FV
+ //
+ gBS->HandleProtocol (
+ gImageHandle,
+ &gEfiLoadedImageProtocolGuid,
+ (VOID **) &LoadedImage
+ );
+ NewDevicePath = AppendDevicePathNode (DevicePathFromHandle (LoadedImage->DeviceHandle), FvFileNode);
+ FileBuffer = BmGetFileBufferByMemmapFv (NewDevicePath, FullPath, FileSize);
+ FreePool (NewDevicePath);
+
+ if (FileBuffer != NULL) {
+ return FileBuffer;
+ }
+
+ //
+ // Secondly find the FV file in all other FVs
+ //
+ gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiFirmwareVolume2ProtocolGuid,
+ NULL,
+ &FvHandleCount,
+ &FvHandles
+ );
+ for (Index = 0; (Index < FvHandleCount) && (FileBuffer == NULL); Index++) {
+ if (FvHandles[Index] == LoadedImage->DeviceHandle) {
+ //
+ // Skip current FV
+ //
+ continue;
+ }
+ NewDevicePath = AppendDevicePathNode (DevicePathFromHandle (FvHandles[Index]), FvFileNode);
+ FileBuffer = BmGetFileBufferByMemmapFv (NewDevicePath, FullPath, FileSize);
+ FreePool (NewDevicePath);
+ }
+
+ if (FvHandles != NULL) {
+ FreePool (FvHandles);
+ }
+ return FileBuffer;
+}
+
+/**
+ Check if it's a Memory Mapped FV Device Path.
+
+ The function doesn't garentee the device path points to existing FV file.
+
+ @param DevicePath Input device path.
+
+ @retval TRUE The device path is a Memory Mapped FV Device Path.
+ @retval FALSE The device path is NOT a Memory Mapped FV Device Path.
+**/
+BOOLEAN
+BmIsMemmapFvFilePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *FileNode;
+
+ if ((DevicePathType (DevicePath) == HARDWARE_DEVICE_PATH) && (DevicePathSubType (DevicePath) == HW_MEMMAP_DP)) {
+ FileNode = NextDevicePathNode (DevicePath);
+ if ((DevicePathType (FileNode) == MEDIA_DEVICE_PATH) && (DevicePathSubType (FileNode) == MEDIA_PIWG_FW_FILE_DP)) {
+ return IsDevicePathEnd (NextDevicePathNode (FileNode));
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ Check whether a USB device match the specified USB Class device path. This
+ function follows "Load Option Processing" behavior in UEFI specification.
+
+ @param UsbIo USB I/O protocol associated with the USB device.
+ @param UsbClass The USB Class device path to match.
+
+ @retval TRUE The USB device match the USB Class device path.
+ @retval FALSE The USB device does not match the USB Class device path.
+
+**/
+BOOLEAN
+BmMatchUsbClass (
+ IN EFI_USB_IO_PROTOCOL *UsbIo,
+ IN USB_CLASS_DEVICE_PATH *UsbClass
+ )
+{
+ EFI_STATUS Status;
+ EFI_USB_DEVICE_DESCRIPTOR DevDesc;
+ EFI_USB_INTERFACE_DESCRIPTOR IfDesc;
+ UINT8 DeviceClass;
+ UINT8 DeviceSubClass;
+ UINT8 DeviceProtocol;
+
+ if ((DevicePathType (UsbClass) != MESSAGING_DEVICE_PATH) ||
+ (DevicePathSubType (UsbClass) != MSG_USB_CLASS_DP)){
+ return FALSE;
+ }
+
+ //
+ // Check Vendor Id and Product Id.
+ //
+ Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc);
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ if ((UsbClass->VendorId != 0xffff) &&
+ (UsbClass->VendorId != DevDesc.IdVendor)) {
+ return FALSE;
+ }
+
+ if ((UsbClass->ProductId != 0xffff) &&
+ (UsbClass->ProductId != DevDesc.IdProduct)) {
+ return FALSE;
+ }
+
+ DeviceClass = DevDesc.DeviceClass;
+ DeviceSubClass = DevDesc.DeviceSubClass;
+ DeviceProtocol = DevDesc.DeviceProtocol;
+ if (DeviceClass == 0) {
+ //
+ // If Class in Device Descriptor is set to 0, use the Class, SubClass and
+ // Protocol in Interface Descriptor instead.
+ //
+ Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &IfDesc);
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ DeviceClass = IfDesc.InterfaceClass;
+ DeviceSubClass = IfDesc.InterfaceSubClass;
+ DeviceProtocol = IfDesc.InterfaceProtocol;
+ }
+
+ //
+ // Check Class, SubClass and Protocol.
+ //
+ if ((UsbClass->DeviceClass != 0xff) &&
+ (UsbClass->DeviceClass != DeviceClass)) {
+ return FALSE;
+ }
+
+ if ((UsbClass->DeviceSubClass != 0xff) &&
+ (UsbClass->DeviceSubClass != DeviceSubClass)) {
+ return FALSE;
+ }
+
+ if ((UsbClass->DeviceProtocol != 0xff) &&
+ (UsbClass->DeviceProtocol != DeviceProtocol)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ Eliminate the extra spaces in the Str to one space.
+
+ @param Str Input string info.
+**/
+VOID
+BmEliminateExtraSpaces (
+ IN CHAR16 *Str
+ )
+{
+ UINTN Index;
+ UINTN ActualIndex;
+
+ for (Index = 0, ActualIndex = 0; Str[Index] != L'\0'; Index++) {
+ if ((Str[Index] != L' ') || ((ActualIndex > 0) && (Str[ActualIndex - 1] != L' '))) {
+ Str[ActualIndex++] = Str[Index];
+ }
+ }
+ Str[ActualIndex] = L'\0';
+}
+
+/**
+ Try to get the controller's ATA/ATAPI description.
+
+ @param Handle Controller handle.
+
+ @return The description string.
+**/
+CHAR16 *
+BmGetDescriptionFromDiskInfo (
+ IN EFI_HANDLE Handle
+ )
+{
+ UINTN Index;
+ EFI_STATUS Status;
+ EFI_DISK_INFO_PROTOCOL *DiskInfo;
+ UINT32 BufferSize;
+ EFI_ATAPI_IDENTIFY_DATA IdentifyData;
+ EFI_SCSI_INQUIRY_DATA InquiryData;
+ CHAR16 *Description;
+ UINTN Length;
+ CONST UINTN ModelNameLength = 40;
+ CONST UINTN SerialNumberLength = 20;
+ CHAR8 *StrPtr;
+ UINT8 Temp;
+
+ Description = NULL;
+
+ Status = gBS->HandleProtocol (
+ Handle,
+ &gEfiDiskInfoProtocolGuid,
+ (VOID **) &DiskInfo
+ );
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ if (CompareGuid (&DiskInfo->Interface, &gEfiDiskInfoAhciInterfaceGuid) ||
+ CompareGuid (&DiskInfo->Interface, &gEfiDiskInfoIdeInterfaceGuid)) {
+ BufferSize = sizeof (EFI_ATAPI_IDENTIFY_DATA);
+ Status = DiskInfo->Identify (
+ DiskInfo,
+ &IdentifyData,
+ &BufferSize
+ );
+ if (!EFI_ERROR (Status)) {
+ Description = AllocateZeroPool ((ModelNameLength + SerialNumberLength + 2) * sizeof (CHAR16));
+ ASSERT (Description != NULL);
+ for (Index = 0; Index + 1 < ModelNameLength; Index += 2) {
+ Description[Index] = (CHAR16) IdentifyData.ModelName[Index + 1];
+ Description[Index + 1] = (CHAR16) IdentifyData.ModelName[Index];
+ }
+
+ Length = Index;
+ Description[Length++] = L' ';
+
+ for (Index = 0; Index + 1 < SerialNumberLength; Index += 2) {
+ Description[Length + Index] = (CHAR16) IdentifyData.SerialNo[Index + 1];
+ Description[Length + Index + 1] = (CHAR16) IdentifyData.SerialNo[Index];
+ }
+ Length += Index;
+ Description[Length++] = L'\0';
+ ASSERT (Length == ModelNameLength + SerialNumberLength + 2);
+
+ BmEliminateExtraSpaces (Description);
+ }
+ } else if (CompareGuid (&DiskInfo->Interface, &gEfiDiskInfoScsiInterfaceGuid)) {
+ BufferSize = sizeof (EFI_SCSI_INQUIRY_DATA);
+ Status = DiskInfo->Inquiry (
+ DiskInfo,
+ &InquiryData,
+ &BufferSize
+ );
+ if (!EFI_ERROR (Status)) {
+ Description = AllocateZeroPool ((VENDOR_IDENTIFICATION_LENGTH + PRODUCT_IDENTIFICATION_LENGTH + 2) * sizeof (CHAR16));
+ ASSERT (Description != NULL);
+
+ //
+ // Per SCSI spec, EFI_SCSI_INQUIRY_DATA.Reserved_5_95[3 - 10] save the Verdor identification
+ // EFI_SCSI_INQUIRY_DATA.Reserved_5_95[11 - 26] save the product identification,
+ // Here combine the vendor identification and product identification to the description.
+ //
+ StrPtr = (CHAR8 *) (&InquiryData.Reserved_5_95[VENDOR_IDENTIFICATION_OFFSET]);
+ Temp = StrPtr[VENDOR_IDENTIFICATION_LENGTH];
+ StrPtr[VENDOR_IDENTIFICATION_LENGTH] = '\0';
+ AsciiStrToUnicodeStrS (StrPtr, Description, VENDOR_IDENTIFICATION_LENGTH + 1);
+ StrPtr[VENDOR_IDENTIFICATION_LENGTH] = Temp;
+
+ //
+ // Add one space at the middle of vendor information and product information.
+ //
+ Description[VENDOR_IDENTIFICATION_LENGTH] = L' ';
+
+ StrPtr = (CHAR8 *) (&InquiryData.Reserved_5_95[PRODUCT_IDENTIFICATION_OFFSET]);
+ StrPtr[PRODUCT_IDENTIFICATION_LENGTH] = '\0';
+ AsciiStrToUnicodeStrS (StrPtr, Description + VENDOR_IDENTIFICATION_LENGTH + 1, PRODUCT_IDENTIFICATION_LENGTH + 1);
+
+ BmEliminateExtraSpaces (Description);
+ }
+ }
+
+ return Description;
+}
+
+/**
+ Try to get the controller's USB description.
+
+ @param Handle Controller handle.
+
+ @return The description string.
+**/
+CHAR16 *
+BmGetUsbDescription (
+ IN EFI_HANDLE Handle
+ )
+{
+ EFI_STATUS Status;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+ CHAR16 NullChar;
+ CHAR16 *Manufacturer;
+ CHAR16 *Product;
+ CHAR16 *SerialNumber;
+ CHAR16 *Description;
+ EFI_USB_DEVICE_DESCRIPTOR DevDesc;
+ UINTN DescMaxSize;
+
+ Status = gBS->HandleProtocol (
+ Handle,
+ &gEfiUsbIoProtocolGuid,
+ (VOID **) &UsbIo
+ );
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ NullChar = L'\0';
+
+ Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ Status = UsbIo->UsbGetStringDescriptor (
+ UsbIo,
+ mBmUsbLangId,
+ DevDesc.StrManufacturer,
+ &Manufacturer
+ );
+ if (EFI_ERROR (Status)) {
+ Manufacturer = &NullChar;
+ }
+
+ Status = UsbIo->UsbGetStringDescriptor (
+ UsbIo,
+ mBmUsbLangId,
+ DevDesc.StrProduct,
+ &Product
+ );
+ if (EFI_ERROR (Status)) {
+ Product = &NullChar;
+ }
+
+ Status = UsbIo->UsbGetStringDescriptor (
+ UsbIo,
+ mBmUsbLangId,
+ DevDesc.StrSerialNumber,
+ &SerialNumber
+ );
+ if (EFI_ERROR (Status)) {
+ SerialNumber = &NullChar;
+ }
+
+ if ((Manufacturer == &NullChar) &&
+ (Product == &NullChar) &&
+ (SerialNumber == &NullChar)
+ ) {
+ return NULL;
+ }
+
+ DescMaxSize = StrSize (Manufacturer) + StrSize (Product) + StrSize (SerialNumber);
+ Description = AllocateZeroPool (DescMaxSize);
+ ASSERT (Description != NULL);
+ StrCatS (Description, DescMaxSize/sizeof(CHAR16), Manufacturer);
+ StrCatS (Description, DescMaxSize/sizeof(CHAR16), L" ");
+
+ StrCatS (Description, DescMaxSize/sizeof(CHAR16), Product);
+ StrCatS (Description, DescMaxSize/sizeof(CHAR16), L" ");
+
+ StrCatS (Description, DescMaxSize/sizeof(CHAR16), SerialNumber);
+
+ if (Manufacturer != &NullChar) {
+ FreePool (Manufacturer);
+ }
+ if (Product != &NullChar) {
+ FreePool (Product);
+ }
+ if (SerialNumber != &NullChar) {
+ FreePool (SerialNumber);
+ }
+
+ BmEliminateExtraSpaces (Description);
+
+ return Description;
+}
+
+/**
+ Return the boot description for the controller based on the type.
+
+ @param Handle Controller handle.
+
+ @return The description string.
+**/
+CHAR16 *
+BmGetMiscDescription (
+ IN EFI_HANDLE Handle
+ )
+{
+ EFI_STATUS Status;
+ CHAR16 *Description;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs;
+
+ switch (BmDevicePathType (DevicePathFromHandle (Handle))) {
+ case BmAcpiFloppyBoot:
+ Description = L"Floppy";
+ break;
+
+ case BmMessageAtapiBoot:
+ case BmMessageSataBoot:
+ Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);
+ ASSERT_EFI_ERROR (Status);
+ //
+ // Assume a removable SATA device should be the DVD/CD device
+ //
+ Description = BlockIo->Media->RemovableMedia ? L"DVD/CDROM" : L"Hard Drive";
+ break;
+
+ case BmMessageUsbBoot:
+ Description = L"USB Device";
+ break;
+
+ case BmMessageScsiBoot:
+ Description = L"SCSI Device";
+ break;
+
+ case BmHardwareDeviceBoot:
+ Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);
+ if (!EFI_ERROR (Status)) {
+ Description = BlockIo->Media->RemovableMedia ? L"Removable Disk" : L"Hard Drive";
+ } else {
+ Description = L"Misc Device";
+ }
+ break;
+
+ case BmMessageNetworkBoot:
+ Description = L"Network";
+ break;
+
+ case BmMessageHttpBoot:
+ Description = L"Http";
+ break;
+
+ default:
+ Status = gBS->HandleProtocol (Handle, &gEfiSimpleFileSystemProtocolGuid, (VOID **) &Fs);
+ if (!EFI_ERROR (Status)) {
+ Description = L"Non-Block Boot Device";
+ } else {
+ Description = L"Misc Device";
+ }
+ break;
+ }
+
+ return AllocateCopyPool (StrSize (Description), Description);
+}
+
+/**
+ Register the platform provided boot description handler.
+
+ @param Handler The platform provided boot description handler
+
+ @retval EFI_SUCCESS The handler was registered successfully.
+ @retval EFI_ALREADY_STARTED The handler was already registered.
+ @retval EFI_OUT_OF_RESOURCES There is not enough resource to perform the registration.
+**/
+EFI_STATUS
+EFIAPI
+EfiBootManagerRegisterBootDescriptionHandler (
+ IN EFI_BOOT_MANAGER_BOOT_DESCRIPTION_HANDLER Handler
+ )
+{
+ LIST_ENTRY *Link;
+ BM_BOOT_DESCRIPTION_ENTRY *Entry;
+
+ for ( Link = GetFirstNode (&mPlatformBootDescriptionHandlers)
+ ; !IsNull (&mPlatformBootDescriptionHandlers, Link)
+ ; Link = GetNextNode (&mPlatformBootDescriptionHandlers, Link)
+ ) {
+ Entry = CR (Link, BM_BOOT_DESCRIPTION_ENTRY, Link, BM_BOOT_DESCRIPTION_ENTRY_SIGNATURE);
+ if (Entry->Handler == Handler) {
+ return EFI_ALREADY_STARTED;
+ }
+ }
+
+ Entry = AllocatePool (sizeof (BM_BOOT_DESCRIPTION_ENTRY));
+ if (Entry == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Entry->Signature = BM_BOOT_DESCRIPTION_ENTRY_SIGNATURE;
+ Entry->Handler = Handler;
+ InsertTailList (&mPlatformBootDescriptionHandlers, &Entry->Link);
+ return EFI_SUCCESS;
+}
+
+BM_GET_BOOT_DESCRIPTION mBmBootDescriptionHandlers[] = {
+ BmGetUsbDescription,
+ BmGetDescriptionFromDiskInfo,
+ BmGetMiscDescription
+};
+
+/**
+ Return the boot description for the controller.
+
+ @param Handle Controller handle.
+
+ @return The description string.
+**/
+CHAR16 *
+BmGetBootDescription (
+ IN EFI_HANDLE Handle
+ )
+{
+ LIST_ENTRY *Link;
+ BM_BOOT_DESCRIPTION_ENTRY *Entry;
+ CHAR16 *Description;
+ CHAR16 *DefaultDescription;
+ CHAR16 *Temp;
+ UINTN Index;
+
+ //
+ // Firstly get the default boot description
+ //
+ DefaultDescription = NULL;
+ for (Index = 0; Index < sizeof (mBmBootDescriptionHandlers) / sizeof (mBmBootDescriptionHandlers[0]); Index++) {
+ DefaultDescription = mBmBootDescriptionHandlers[Index] (Handle);
+ if (DefaultDescription != NULL) {
+ //
+ // Avoid description confusion between UEFI & Legacy boot option by adding "UEFI " prefix
+ // ONLY for core provided boot description handler.
+ //
+ Temp = AllocatePool (StrSize (DefaultDescription) + sizeof (mBmUefiPrefix));
+ ASSERT (Temp != NULL);
+ StrCpyS ( Temp,
+ (StrSize (DefaultDescription) + sizeof (mBmUefiPrefix))/sizeof(CHAR16),
+ mBmUefiPrefix
+ );
+ StrCatS ( Temp,
+ (StrSize (DefaultDescription) + sizeof (mBmUefiPrefix))/sizeof(CHAR16),
+ DefaultDescription
+ );
+ FreePool (DefaultDescription);
+ DefaultDescription = Temp;
+ break;
+ }
+ }
+ ASSERT (DefaultDescription != NULL);
+
+ //
+ // Secondly query platform for the better boot description
+ //
+ for ( Link = GetFirstNode (&mPlatformBootDescriptionHandlers)
+ ; !IsNull (&mPlatformBootDescriptionHandlers, Link)
+ ; Link = GetNextNode (&mPlatformBootDescriptionHandlers, Link)
+ ) {
+ Entry = CR (Link, BM_BOOT_DESCRIPTION_ENTRY, Link, BM_BOOT_DESCRIPTION_ENTRY_SIGNATURE);
+ Description = Entry->Handler (Handle, DefaultDescription);
+ if (Description != NULL) {
+ FreePool (DefaultDescription);
+ return Description;
+ }
+ }
+
+ return DefaultDescription;
+}
+
+/**
+ Check whether a USB device match the specified USB WWID device path. This
+ function follows "Load Option Processing" behavior in UEFI specification.
+
+ @param UsbIo USB I/O protocol associated with the USB device.
+ @param UsbWwid The USB WWID device path to match.
+
+ @retval TRUE The USB device match the USB WWID device path.
+ @retval FALSE The USB device does not match the USB WWID device path.
+
+**/
+BOOLEAN
+BmMatchUsbWwid (
+ IN EFI_USB_IO_PROTOCOL *UsbIo,
+ IN USB_WWID_DEVICE_PATH *UsbWwid
+ )
+{
+ EFI_STATUS Status;
+ EFI_USB_DEVICE_DESCRIPTOR DevDesc;
+ EFI_USB_INTERFACE_DESCRIPTOR IfDesc;
+ UINT16 *LangIdTable;
+ UINT16 TableSize;
+ UINT16 Index;
+ CHAR16 *CompareStr;
+ UINTN CompareLen;
+ CHAR16 *SerialNumberStr;
+ UINTN Length;
+
+ if ((DevicePathType (UsbWwid) != MESSAGING_DEVICE_PATH) ||
+ (DevicePathSubType (UsbWwid) != MSG_USB_WWID_DP)) {
+ return FALSE;
+ }
+
+ //
+ // Check Vendor Id and Product Id.
+ //
+ Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc);
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+ if ((DevDesc.IdVendor != UsbWwid->VendorId) ||
+ (DevDesc.IdProduct != UsbWwid->ProductId)) {
+ return FALSE;
+ }
+
+ //
+ // Check Interface Number.
+ //
+ Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &IfDesc);
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+ if (IfDesc.InterfaceNumber != UsbWwid->InterfaceNumber) {
+ return FALSE;
+ }
+
+ //
+ // Check Serial Number.
+ //
+ if (DevDesc.StrSerialNumber == 0) {
+ return FALSE;
+ }
+
+ //
+ // Get all supported languages.
+ //
+ TableSize = 0;
+ LangIdTable = NULL;
+ Status = UsbIo->UsbGetSupportedLanguages (UsbIo, &LangIdTable, &TableSize);
+ if (EFI_ERROR (Status) || (TableSize == 0) || (LangIdTable == NULL)) {
+ return FALSE;
+ }
+
+ //
+ // Serial number in USB WWID device path is the last 64-or-less UTF-16 characters.
+ //
+ CompareStr = (CHAR16 *) (UINTN) (UsbWwid + 1);
+ CompareLen = (DevicePathNodeLength (UsbWwid) - sizeof (USB_WWID_DEVICE_PATH)) / sizeof (CHAR16);
+ if (CompareStr[CompareLen - 1] == L'\0') {
+ CompareLen--;
+ }
+
+ //
+ // Compare serial number in each supported language.
+ //
+ for (Index = 0; Index < TableSize / sizeof (UINT16); Index++) {
+ SerialNumberStr = NULL;
+ Status = UsbIo->UsbGetStringDescriptor (
+ UsbIo,
+ LangIdTable[Index],
+ DevDesc.StrSerialNumber,
+ &SerialNumberStr
+ );
+ if (EFI_ERROR (Status) || (SerialNumberStr == NULL)) {
+ continue;
+ }
+
+ Length = StrLen (SerialNumberStr);
+ if ((Length >= CompareLen) &&
+ (CompareMem (SerialNumberStr + Length - CompareLen, CompareStr, CompareLen * sizeof (CHAR16)) == 0)) {
+ FreePool (SerialNumberStr);
+ return TRUE;
+ }
+
+ FreePool (SerialNumberStr);
+ }
+
+ return FALSE;
+}
+
+/**
+ Find a USB device which match the specified short-form device path start with
+ USB Class or USB WWID device path. If ParentDevicePath is NULL, this function
+ will search in all USB devices of the platform. If ParentDevicePath is not NULL,
+ this function will only search in its child devices.
+
+ @param DevicePath The device path that contains USB Class or USB WWID device path.
+ @param ParentDevicePathSize The length of the device path before the USB Class or
+ USB WWID device path.
+ @param UsbIoHandleCount A pointer to the count of the returned USB IO handles.
+
+ @retval NULL The matched USB IO handles cannot be found.
+ @retval other The matched USB IO handles.
+
+**/
+EFI_HANDLE *
+BmFindUsbDevice (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ IN UINTN ParentDevicePathSize,
+ OUT UINTN *UsbIoHandleCount
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE *UsbIoHandles;
+ EFI_DEVICE_PATH_PROTOCOL *UsbIoDevicePath;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+ UINTN Index;
+ BOOLEAN Matched;
+
+ ASSERT (UsbIoHandleCount != NULL);
+
+ //
+ // Get all UsbIo Handles.
+ //
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiUsbIoProtocolGuid,
+ NULL,
+ UsbIoHandleCount,
+ &UsbIoHandles
+ );
+ if (EFI_ERROR (Status)) {
+ *UsbIoHandleCount = 0;
+ UsbIoHandles = NULL;
+ }
+
+ for (Index = 0; Index < *UsbIoHandleCount; ) {
+ //
+ // Get the Usb IO interface.
+ //
+ Status = gBS->HandleProtocol(
+ UsbIoHandles[Index],
+ &gEfiUsbIoProtocolGuid,
+ (VOID **) &UsbIo
+ );
+ UsbIoDevicePath = DevicePathFromHandle (UsbIoHandles[Index]);
+ Matched = FALSE;
+ if (!EFI_ERROR (Status) && (UsbIoDevicePath != NULL)) {
+
+ //
+ // Compare starting part of UsbIoHandle's device path with ParentDevicePath.
+ //
+ if (CompareMem (UsbIoDevicePath, DevicePath, ParentDevicePathSize) == 0) {
+ if (BmMatchUsbClass (UsbIo, (USB_CLASS_DEVICE_PATH *) ((UINTN) DevicePath + ParentDevicePathSize)) ||
+ BmMatchUsbWwid (UsbIo, (USB_WWID_DEVICE_PATH *) ((UINTN) DevicePath + ParentDevicePathSize))) {
+ Matched = TRUE;
+ }
+ }
+ }
+
+ if (!Matched) {
+ (*UsbIoHandleCount) --;
+ CopyMem (&UsbIoHandles[Index], &UsbIoHandles[Index + 1], (*UsbIoHandleCount - Index) * sizeof (EFI_HANDLE));
+ } else {
+ Index++;
+ }
+ }
+
+ return UsbIoHandles;
+}
+
+/**
+ Expand USB Class or USB WWID device path node to be full device path of a USB
+ device in platform.
+
+ This function support following 4 cases:
+ 1) Boot Option device path starts with a USB Class or USB WWID device path,
+ and there is no Media FilePath device path in the end.
+ In this case, it will follow Removable Media Boot Behavior.
+ 2) Boot Option device path starts with a USB Class or USB WWID device path,
+ and ended with Media FilePath device path.
+ 3) Boot Option device path starts with a full device path to a USB Host Controller,
+ contains a USB Class or USB WWID device path node, while not ended with Media
+ FilePath device path. In this case, it will follow Removable Media Boot Behavior.
+ 4) Boot Option device path starts with a full device path to a USB Host Controller,
+ contains a USB Class or USB WWID device path node, and ended with Media
+ FilePath device path.
+
+ @param FilePath The device path pointing to a load option.
+ It could be a short-form device path.
+ @param FullPath Return the full device path of the load option after
+ short-form device path expanding.
+ Caller is responsible to free it.
+ @param FileSize Return the load option size.
+ @param ShortformNode Pointer to the USB short-form device path node in the FilePath buffer.
+
+ @return The load option buffer. Caller is responsible to free the memory.
+**/
+VOID *
+BmExpandUsbDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
+ OUT UINTN *FileSize,
+ IN EFI_DEVICE_PATH_PROTOCOL *ShortformNode
+ )
+{
+ UINTN ParentDevicePathSize;
+ EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *FullDevicePath;
+ EFI_HANDLE *Handles;
+ UINTN HandleCount;
+ UINTN Index;
+ VOID *FileBuffer;
+
+ ParentDevicePathSize = (UINTN) ShortformNode - (UINTN) FilePath;
+ RemainingDevicePath = NextDevicePathNode (ShortformNode);
+ FileBuffer = NULL;
+ Handles = BmFindUsbDevice (FilePath, ParentDevicePathSize, &HandleCount);
+
+ for (Index = 0; (Index < HandleCount) && (FileBuffer == NULL); Index++) {
+ FullDevicePath = AppendDevicePath (DevicePathFromHandle (Handles[Index]), RemainingDevicePath);
+ FileBuffer = BmGetLoadOptionBuffer (FullDevicePath, FullPath, FileSize);
+ FreePool (FullDevicePath);
+ }
+
+ if (Handles != NULL) {
+ FreePool (Handles);
+ }
+
+ return FileBuffer;
+}
+
+/**
+ Save the partition DevicePath to the CachedDevicePath as the first instance.
+
+ @param CachedDevicePath The device path cache.
+ @param DevicePath The partition device path to be cached.
+**/
+VOID
+BmCachePartitionDevicePath (
+ IN OUT EFI_DEVICE_PATH_PROTOCOL **CachedDevicePath,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
+ UINTN Count;
+
+ if (BmMatchDevicePaths (*CachedDevicePath, DevicePath)) {
+ TempDevicePath = *CachedDevicePath;
+ *CachedDevicePath = BmDelPartMatchInstance (*CachedDevicePath, DevicePath);
+ FreePool (TempDevicePath);
+ }
+
+ if (*CachedDevicePath == NULL) {
+ *CachedDevicePath = DuplicateDevicePath (DevicePath);
+ return;
+ }
+
+ TempDevicePath = *CachedDevicePath;
+ *CachedDevicePath = AppendDevicePathInstance (DevicePath, *CachedDevicePath);
+ if (TempDevicePath != NULL) {
+ FreePool (TempDevicePath);
+ }
+
+ //
+ // Here limit the device path instance number to 12, which is max number for a system support 3 IDE controller
+ // If the user try to boot many OS in different HDs or partitions, in theory, the 'HDDP' variable maybe become larger and larger.
+ //
+ Count = 0;
+ TempDevicePath = *CachedDevicePath;
+ while (!IsDevicePathEnd (TempDevicePath)) {
+ TempDevicePath = NextDevicePathNode (TempDevicePath);
+ //
+ // Parse one instance
+ //
+ while (!IsDevicePathEndType (TempDevicePath)) {
+ TempDevicePath = NextDevicePathNode (TempDevicePath);
+ }
+ Count++;
+ //
+ // If the CachedDevicePath variable contain too much instance, only remain 12 instances.
+ //
+ if (Count == 12) {
+ SetDevicePathEndNode (TempDevicePath);
+ break;
+ }
+ }
+}
+
+/**
+ Expand a device path that starts with a hard drive media device path node to be a
+ full device path that includes the full hardware path to the device. We need
+ to do this so it can be booted. As an optimization the front match (the part point
+ to the partition node. E.g. ACPI() /PCI()/ATA()/Partition() ) is saved in a variable
+ so a connect all is not required on every boot. All successful history device path
+ which point to partition node (the front part) will be saved.
+
+ @param FilePath The device path pointing to a load option.
+ It could be a short-form device path.
+ @param FullPath Return the full device path of the load option after
+ short-form device path expanding.
+ Caller is responsible to free it.
+ @param FileSize Return the load option size.
+
+ @return The load option buffer. Caller is responsible to free the memory.
+**/
+VOID *
+BmExpandPartitionDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
+ OUT UINTN *FileSize
+ )
+{
+ EFI_STATUS Status;
+ UINTN BlockIoHandleCount;
+ EFI_HANDLE *BlockIoBuffer;
+ VOID *FileBuffer;
+ EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath;
+ UINTN Index;
+ EFI_DEVICE_PATH_PROTOCOL *CachedDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *TempNewDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
+ UINTN CachedDevicePathSize;
+ BOOLEAN NeedAdjust;
+ EFI_DEVICE_PATH_PROTOCOL *Instance;
+ UINTN Size;
+
+ FileBuffer = NULL;
+ //
+ // Check if there is prestore 'HDDP' variable.
+ // If exist, search the front path which point to partition node in the variable instants.
+ // If fail to find or 'HDDP' not exist, reconnect all and search in all system
+ //
+ GetVariable2 (L"HDDP", &mBmHardDriveBootVariableGuid, (VOID **) &CachedDevicePath, &CachedDevicePathSize);
+
+ //
+ // Delete the invalid 'HDDP' variable.
+ //
+ if ((CachedDevicePath != NULL) && !IsDevicePathValid (CachedDevicePath, CachedDevicePathSize)) {
+ FreePool (CachedDevicePath);
+ CachedDevicePath = NULL;
+ Status = gRT->SetVariable (
+ L"HDDP",
+ &mBmHardDriveBootVariableGuid,
+ 0,
+ 0,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ if (CachedDevicePath != NULL) {
+ TempNewDevicePath = CachedDevicePath;
+ NeedAdjust = FALSE;
+ do {
+ //
+ // Check every instance of the variable
+ // First, check whether the instance contain the partition node, which is needed for distinguishing multi
+ // partial partition boot option. Second, check whether the instance could be connected.
+ //
+ Instance = GetNextDevicePathInstance (&TempNewDevicePath, &Size);
+ if (BmMatchPartitionDevicePathNode (Instance, (HARDDRIVE_DEVICE_PATH *) FilePath)) {
+ //
+ // Connect the device path instance, the device path point to hard drive media device path node
+ // e.g. ACPI() /PCI()/ATA()/Partition()
+ //
+ Status = EfiBootManagerConnectDevicePath (Instance, NULL);
+ if (!EFI_ERROR (Status)) {
+ TempDevicePath = AppendDevicePath (Instance, NextDevicePathNode (FilePath));
+ FileBuffer = BmGetLoadOptionBuffer (TempDevicePath, FullPath, FileSize);
+ FreePool (TempDevicePath);
+
+ if (FileBuffer != NULL) {
+ //
+ // Adjust the 'HDDP' instances sequence if the matched one is not first one.
+ //
+ if (NeedAdjust) {
+ BmCachePartitionDevicePath (&CachedDevicePath, Instance);
+ //
+ // Save the matching Device Path so we don't need to do a connect all next time
+ // Failing to save only impacts performance next time expanding the short-form device path
+ //
+ Status = gRT->SetVariable (
+ L"HDDP",
+ &mBmHardDriveBootVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ GetDevicePathSize (CachedDevicePath),
+ CachedDevicePath
+ );
+ }
+
+ FreePool (Instance);
+ FreePool (CachedDevicePath);
+ return FileBuffer;
+ }
+ }
+ }
+ //
+ // Come here means the first instance is not matched
+ //
+ NeedAdjust = TRUE;
+ FreePool(Instance);
+ } while (TempNewDevicePath != NULL);
+ }
+
+ //
+ // If we get here we fail to find or 'HDDP' not exist, and now we need
+ // to search all devices in the system for a matched partition
+ //
+ EfiBootManagerConnectAll ();
+ Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiBlockIoProtocolGuid, NULL, &BlockIoHandleCount, &BlockIoBuffer);
+ if (EFI_ERROR (Status)) {
+ BlockIoHandleCount = 0;
+ BlockIoBuffer = NULL;
+ }
+ //
+ // Loop through all the device handles that support the BLOCK_IO Protocol
+ //
+ for (Index = 0; Index < BlockIoHandleCount; Index++) {
+ BlockIoDevicePath = DevicePathFromHandle (BlockIoBuffer[Index]);
+ if (BlockIoDevicePath == NULL) {
+ continue;
+ }
+
+ if (BmMatchPartitionDevicePathNode (BlockIoDevicePath, (HARDDRIVE_DEVICE_PATH *) FilePath)) {
+ //
+ // Find the matched partition device path
+ //
+ TempDevicePath = AppendDevicePath (BlockIoDevicePath, NextDevicePathNode (FilePath));
+ FileBuffer = BmGetLoadOptionBuffer (TempDevicePath, FullPath, FileSize);
+ FreePool (TempDevicePath);
+
+ if (FileBuffer != NULL) {
+ BmCachePartitionDevicePath (&CachedDevicePath, BlockIoDevicePath);
+
+ //
+ // Save the matching Device Path so we don't need to do a connect all next time
+ // Failing to save only impacts performance next time expanding the short-form device path
+ //
+ Status = gRT->SetVariable (
+ L"HDDP",
+ &mBmHardDriveBootVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ GetDevicePathSize (CachedDevicePath),
+ CachedDevicePath
+ );
+
+ break;
+ }
+ }
+ }
+
+ if (CachedDevicePath != NULL) {
+ FreePool (CachedDevicePath);
+ }
+ if (BlockIoBuffer != NULL) {
+ FreePool (BlockIoBuffer);
+ }
+ return FileBuffer;
+}
+
+/**
+ Expand the media device path which points to a BlockIo or SimpleFileSystem instance
+ by appending EFI_REMOVABLE_MEDIA_FILE_NAME.
+
+ @param DevicePath The media device path pointing to a BlockIo or SimpleFileSystem instance.
+ @param FullPath Return the full device path pointing to the load option.
+ @param FileSize Return the size of the load option.
+
+ @return The load option buffer.
+**/
+VOID *
+BmExpandMediaDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
+ OUT UINTN *FileSize
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE Handle;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+ VOID *Buffer;
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
+ UINTN Size;
+ UINTN TempSize;
+ EFI_HANDLE *SimpleFileSystemHandles;
+ UINTN NumberSimpleFileSystemHandles;
+ UINTN Index;
+ VOID *FileBuffer;
+ UINT32 AuthenticationStatus;
+
+ //
+ // Check whether the device is connected
+ //
+ TempDevicePath = DevicePath;
+ Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &TempDevicePath, &Handle);
+ if (!EFI_ERROR (Status)) {
+ ASSERT (IsDevicePathEnd (TempDevicePath));
+
+ TempDevicePath = FileDevicePath (Handle, EFI_REMOVABLE_MEDIA_FILE_NAME);
+ FileBuffer = GetFileBufferByFilePath (TRUE, TempDevicePath, FileSize, &AuthenticationStatus);
+ if (FileBuffer == NULL) {
+ FreePool (TempDevicePath);
+ TempDevicePath = NULL;
+ }
+ *FullPath = TempDevicePath;
+ return FileBuffer;
+ }
+
+ //
+ // For device boot option only pointing to the removable device handle,
+ // should make sure all its children handles (its child partion or media handles) are created and connected.
+ //
+ gBS->ConnectController (Handle, NULL, NULL, TRUE);
+
+ //
+ // Issue a dummy read to the device to check for media change.
+ // When the removable media is changed, any Block IO read/write will
+ // cause the BlockIo protocol be reinstalled and EFI_MEDIA_CHANGED is
+ // returned. After the Block IO protocol is reinstalled, subsequent
+ // Block IO read/write will success.
+ //
+ Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &TempDevicePath, &Handle);
+ ASSERT_EFI_ERROR (Status);
+ Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);
+ ASSERT_EFI_ERROR (Status);
+ Buffer = AllocatePool (BlockIo->Media->BlockSize);
+ if (Buffer != NULL) {
+ BlockIo->ReadBlocks (
+ BlockIo,
+ BlockIo->Media->MediaId,
+ 0,
+ BlockIo->Media->BlockSize,
+ Buffer
+ );
+ FreePool (Buffer);
+ }
+
+ //
+ // Detect the the default boot file from removable Media
+ //
+ FileBuffer = NULL;
+ *FullPath = NULL;
+ Size = GetDevicePathSize (DevicePath) - END_DEVICE_PATH_LENGTH;
+ gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiSimpleFileSystemProtocolGuid,
+ NULL,
+ &NumberSimpleFileSystemHandles,
+ &SimpleFileSystemHandles
+ );
+ for (Index = 0; Index < NumberSimpleFileSystemHandles; Index++) {
+ //
+ // Get the device path size of SimpleFileSystem handle
+ //
+ TempDevicePath = DevicePathFromHandle (SimpleFileSystemHandles[Index]);
+ TempSize = GetDevicePathSize (TempDevicePath) - END_DEVICE_PATH_LENGTH;
+ //
+ // Check whether the device path of boot option is part of the SimpleFileSystem handle's device path
+ //
+ if ((Size <= TempSize) && (CompareMem (TempDevicePath, DevicePath, Size) == 0)) {
+ TempDevicePath = FileDevicePath (SimpleFileSystemHandles[Index], EFI_REMOVABLE_MEDIA_FILE_NAME);
+ FileBuffer = GetFileBufferByFilePath (TRUE, TempDevicePath, FileSize, &AuthenticationStatus);
+ if (FileBuffer != NULL) {
+ *FullPath = TempDevicePath;
+ break;
+ }
+ FreePool (TempDevicePath);
+ }
+ }
+
+ if (SimpleFileSystemHandles != NULL) {
+ FreePool (SimpleFileSystemHandles);
+ }
+
+ return FileBuffer;
+}
+
+/**
+ Get the load option by its device path.
+
+ @param FilePath The device path pointing to a load option.
+ It could be a short-form device path.
+ @param FullPath Return the full device path of the load option after
+ short-form device path expanding.
+ Caller is responsible to free it.
+ @param FileSize Return the load option size.
+
+ @return The load option buffer. Caller is responsible to free the memory.
+**/
+VOID *
+BmGetLoadOptionBuffer (
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
+ OUT UINTN *FileSize
+ )
+{
+ EFI_HANDLE Handle;
+ VOID *FileBuffer;
+ UINT32 AuthenticationStatus;
+ EFI_DEVICE_PATH_PROTOCOL *Node;
+ EFI_STATUS Status;
+
+ ASSERT ((FilePath != NULL) && (FullPath != NULL) && (FileSize != NULL));
+
+ EfiBootManagerConnectDevicePath (FilePath, NULL);
+
+ *FullPath = NULL;
+ *FileSize = 0;
+ FileBuffer = NULL;
+
+ //
+ // Boot from media device by adding a default file name \EFI\BOOT\BOOT{machine type short-name}.EFI
+ //
+ Node = FilePath;
+ Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &Node, &Handle);
+ if (EFI_ERROR (Status)) {
+ Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &Node, &Handle);
+ }
+
+ if (!EFI_ERROR (Status) && IsDevicePathEnd (Node)) {
+ return BmExpandMediaDevicePath (FilePath, FullPath, FileSize);
+ }
+
+ //
+ // Expand the short-form device path to full device path
+ //
+ if ((DevicePathType (FilePath) == MEDIA_DEVICE_PATH) &&
+ (DevicePathSubType (FilePath) == MEDIA_HARDDRIVE_DP)) {
+ //
+ // Expand the Harddrive device path
+ //
+ return BmExpandPartitionDevicePath (FilePath, FullPath, FileSize);
+ } else {
+ for (Node = FilePath; !IsDevicePathEnd (Node); Node = NextDevicePathNode (Node)) {
+ if ((DevicePathType (Node) == MESSAGING_DEVICE_PATH) &&
+ ((DevicePathSubType (Node) == MSG_USB_CLASS_DP) || (DevicePathSubType (Node) == MSG_USB_WWID_DP))) {
+ break;
+ }
+ }
+
+ if (!IsDevicePathEnd (Node)) {
+ //
+ // Expand the USB WWID/Class device path
+ //
+ FileBuffer = BmExpandUsbDevicePath (FilePath, FullPath, FileSize, Node);
+ if ((FileBuffer == NULL) && (FilePath == Node)) {
+ //
+ // Boot Option device path starts with USB Class or USB WWID device path.
+ // For Boot Option device path which doesn't begin with the USB Class or
+ // USB WWID device path, it's not needed to connect again here.
+ //
+ BmConnectUsbShortFormDevicePath (FilePath);
+ FileBuffer = BmExpandUsbDevicePath (FilePath, FullPath, FileSize, Node);
+ }
+ return FileBuffer;
+ }
+ }
+
+ //
+ // Fix up the boot option path if it points to a FV in memory map style of device path
+ //
+ if (BmIsMemmapFvFilePath (FilePath)) {
+ return BmGetFileBufferByMemmapFv (FilePath, FullPath, FileSize);
+ }
+
+ //
+ // Directly reads the load option when it doesn't reside in simple file system instance (LoadFile/LoadFile2),
+ // or it directly points to a file in simple file system instance.
+ //
+ Node = FilePath;
+ Status = gBS->LocateDevicePath (&gEfiLoadFileProtocolGuid, &Node, &Handle);
+ FileBuffer = GetFileBufferByFilePath (TRUE, FilePath, FileSize, &AuthenticationStatus);
+ if (FileBuffer != NULL) {
+ if (EFI_ERROR (Status)) {
+ *FullPath = DuplicateDevicePath (FilePath);
+ } else {
+ //
+ // LoadFile () may cause the device path of the Handle be updated.
+ //
+ *FullPath = AppendDevicePath (DevicePathFromHandle (Handle), Node);
+ }
+ }
+
+ return FileBuffer;
+}
+
+/**
+ Attempt to boot the EFI boot option. This routine sets L"BootCurent" and
+ also signals the EFI ready to boot event. If the device path for the option
+ starts with a BBS device path a legacy boot is attempted via the registered
+ gLegacyBoot function. Short form device paths are also supported via this
+ rountine. A device path starting with MEDIA_HARDDRIVE_DP, MSG_USB_WWID_DP,
+ MSG_USB_CLASS_DP gets expaned out to find the first device that matches.
+ If the BootOption Device Path fails the removable media boot algorithm
+ is attempted (\EFI\BOOTIA32.EFI, \EFI\BOOTX64.EFI,... only one file type
+ is tried per processor type)
+
+ @param BootOption Boot Option to try and boot.
+ On return, BootOption->Status contains the boot status.
+ EFI_SUCCESS BootOption was booted
+ EFI_UNSUPPORTED A BBS device path was found with no valid callback
+ registered via EfiBootManagerInitialize().
+ EFI_NOT_FOUND The BootOption was not found on the system
+ !EFI_SUCCESS BootOption failed with this error status
+
+**/
+VOID
+EFIAPI
+EfiBootManagerBoot (
+ IN EFI_BOOT_MANAGER_LOAD_OPTION *BootOption
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE ImageHandle;
+ EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;
+ UINT16 Uint16;
+ UINTN OptionNumber;
+ UINTN OriginalOptionNumber;
+ EFI_DEVICE_PATH_PROTOCOL *FilePath;
+ EFI_DEVICE_PATH_PROTOCOL *Node;
+ EFI_HANDLE FvHandle;
+ VOID *FileBuffer;
+ UINTN FileSize;
+ EFI_BOOT_LOGO_PROTOCOL *BootLogo;
+ EFI_EVENT LegacyBootEvent;
+
+ if (BootOption == NULL) {
+ return;
+ }
+
+ if (BootOption->FilePath == NULL || BootOption->OptionType != LoadOptionTypeBoot) {
+ BootOption->Status = EFI_INVALID_PARAMETER;
+ return;
+ }
+
+ //
+ // 1. Create Boot#### for a temporary boot if there is no match Boot#### (i.e. a boot by selected a EFI Shell using "Boot From File")
+ //
+ OptionNumber = BmFindBootOptionInVariable (BootOption);
+ if (OptionNumber == LoadOptionNumberUnassigned) {
+ Status = BmGetFreeOptionNumber (LoadOptionTypeBoot, &Uint16);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Save the BootOption->OptionNumber to restore later
+ //
+ OptionNumber = Uint16;
+ OriginalOptionNumber = BootOption->OptionNumber;
+ BootOption->OptionNumber = OptionNumber;
+ Status = EfiBootManagerLoadOptionToVariable (BootOption);
+ BootOption->OptionNumber = OriginalOptionNumber;
+ }
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "[Bds] Failed to create Boot#### for a temporary boot - %r!\n", Status));
+ BootOption->Status = Status;
+ return ;
+ }
+ }
+
+ //
+ // 2. Set BootCurrent
+ //
+ Uint16 = (UINT16) OptionNumber;
+ BmSetVariableAndReportStatusCodeOnError (
+ L"BootCurrent",
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ sizeof (UINT16),
+ &Uint16
+ );
+
+ //
+ // 3. Signal the EVT_SIGNAL_READY_TO_BOOT event when we are about to load and execute
+ // the boot option.
+ //
+ Node = BootOption->FilePath;
+ Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &Node, &FvHandle);
+ if (!EFI_ERROR (Status) && CompareGuid (
+ EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) Node),
+ PcdGetPtr (PcdBootManagerMenuFile)
+ )) {
+ DEBUG ((EFI_D_INFO, "[Bds] Booting Boot Manager Menu.\n"));
+ BmStopHotkeyService (NULL, NULL);
+ } else {
+ EfiSignalEventReadyToBoot();
+ //
+ // Report Status Code to indicate ReadyToBoot was signalled
+ //
+ REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_READY_TO_BOOT_EVENT));
+ //
+ // 4. Repair system through DriverHealth protocol
+ //
+ BmRepairAllControllers ();
+ }
+
+ PERF_START_EX (gImageHandle, "BdsAttempt", NULL, 0, (UINT32) OptionNumber);
+
+ //
+ // 5. Load EFI boot option to ImageHandle
+ //
+ ImageHandle = NULL;
+ if (DevicePathType (BootOption->FilePath) != BBS_DEVICE_PATH) {
+ Status = EFI_NOT_FOUND;
+ FileBuffer = BmGetLoadOptionBuffer (BootOption->FilePath, &FilePath, &FileSize);
+ DEBUG_CODE (
+ if (FileBuffer != NULL && CompareMem (BootOption->FilePath, FilePath, GetDevicePathSize (FilePath)) != 0) {
+ DEBUG ((EFI_D_INFO, "[Bds] DevicePath expand: "));
+ BmPrintDp (BootOption->FilePath);
+ DEBUG ((EFI_D_INFO, " -> "));
+ BmPrintDp (FilePath);
+ DEBUG ((EFI_D_INFO, "\n"));
+ }
+ );
+ if (BmIsLoadOptionPeHeaderValid (BootOption->OptionType, FileBuffer, FileSize)) {
+ REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderLoad));
+ Status = gBS->LoadImage (
+ TRUE,
+ gImageHandle,
+ FilePath,
+ FileBuffer,
+ FileSize,
+ &ImageHandle
+ );
+ }
+ if (FileBuffer != NULL) {
+ FreePool (FileBuffer);
+ }
+ if (FilePath != NULL) {
+ FreePool (FilePath);
+ }
+
+ if (EFI_ERROR (Status)) {
+ //
+ // Report Status Code to indicate that the failure to load boot option
+ //
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_EC_BOOT_OPTION_LOAD_ERROR)
+ );
+ BootOption->Status = Status;
+ return;
+ }
+ }
+
+ //
+ // 6. Adjust the different type memory page number just before booting
+ // and save the updated info into the variable for next boot to use
+ //
+ BmSetMemoryTypeInformationVariable (
+ (BOOLEAN) ((BootOption->Attributes & LOAD_OPTION_CATEGORY) == LOAD_OPTION_CATEGORY_BOOT)
+ );
+
+ DEBUG_CODE_BEGIN();
+ if (BootOption->Description == NULL) {
+ DEBUG ((DEBUG_INFO | DEBUG_LOAD, "[Bds]Booting from unknown device path\n"));
+ } else {
+ DEBUG ((DEBUG_INFO | DEBUG_LOAD, "[Bds]Booting %s\n", BootOption->Description));
+ }
+ DEBUG_CODE_END();
+
+ //
+ // Check to see if we should legacy BOOT. If yes then do the legacy boot
+ // Write boot to OS performance data for Legacy boot
+ //
+ if ((DevicePathType (BootOption->FilePath) == BBS_DEVICE_PATH) && (DevicePathSubType (BootOption->FilePath) == BBS_BBS_DP)) {
+ if (mBmLegacyBoot != NULL) {
+ //
+ // Write boot to OS performance data for legacy boot.
+ //
+ PERF_CODE (
+ //
+ // Create an event to be signalled when Legacy Boot occurs to write performance data.
+ //
+ Status = EfiCreateEventLegacyBootEx(
+ TPL_NOTIFY,
+ BmWriteBootToOsPerformanceData,
+ NULL,
+ &LegacyBootEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+ );
+
+ mBmLegacyBoot (BootOption);
+ } else {
+ BootOption->Status = EFI_UNSUPPORTED;
+ }
+
+ PERF_END_EX (gImageHandle, "BdsAttempt", NULL, 0, (UINT32) OptionNumber);
+ return;
+ }
+
+ //
+ // Provide the image with its load options
+ //
+ Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &ImageInfo);
+ ASSERT_EFI_ERROR (Status);
+
+ if (!BmIsAutoCreateBootOption (BootOption)) {
+ ImageInfo->LoadOptionsSize = BootOption->OptionalDataSize;
+ ImageInfo->LoadOptions = BootOption->OptionalData;
+ }
+
+ //
+ // Clean to NULL because the image is loaded directly from the firmwares boot manager.
+ //
+ ImageInfo->ParentHandle = NULL;
+
+ //
+ // Before calling the image, enable the Watchdog Timer for 5 minutes period
+ //
+ gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);
+
+ //
+ // Write boot to OS performance data for UEFI boot
+ //
+ PERF_CODE (
+ BmWriteBootToOsPerformanceData (NULL, NULL);
+ );
+
+ REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderStart));
+
+ Status = gBS->StartImage (ImageHandle, &BootOption->ExitDataSize, &BootOption->ExitData);
+ DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Image Return Status = %r\n", Status));
+ BootOption->Status = Status;
+ if (EFI_ERROR (Status)) {
+ //
+ // Report Status Code to indicate that boot failure
+ //
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_EC_BOOT_OPTION_FAILED)
+ );
+ }
+ PERF_END_EX (gImageHandle, "BdsAttempt", NULL, 0, (UINT32) OptionNumber);
+
+ //
+ // Clear the Watchdog Timer after the image returns
+ //
+ gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);
+
+ //
+ // Set Logo status invalid after trying one boot option
+ //
+ BootLogo = NULL;
+ Status = gBS->LocateProtocol (&gEfiBootLogoProtocolGuid, NULL, (VOID **) &BootLogo);
+ if (!EFI_ERROR (Status) && (BootLogo != NULL)) {
+ Status = BootLogo->SetBootLogo (BootLogo, NULL, 0, 0, 0, 0);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ //
+ // Clear Boot Current
+ //
+ Status = gRT->SetVariable (
+ L"BootCurrent",
+ &gEfiGlobalVariableGuid,
+ 0,
+ 0,
+ NULL
+ );
+ //
+ // Deleting variable with current variable implementation shouldn't fail.
+ // When BootXXXX (e.g.: BootManagerMenu) boots BootYYYY, exiting BootYYYY causes BootCurrent deleted,
+ // exiting BootXXXX causes deleting BootCurrent returns EFI_NOT_FOUND.
+ //
+ ASSERT (Status == EFI_SUCCESS || Status == EFI_NOT_FOUND);
+}
+
+/**
+ Check whether there is a instance in BlockIoDevicePath, which contain multi device path
+ instances, has the same partition node with HardDriveDevicePath device path
+
+ @param BlockIoDevicePath Multi device path instances which need to check
+ @param HardDriveDevicePath A device path which starts with a hard drive media
+ device path.
+
+ @retval TRUE There is a matched device path instance.
+ @retval FALSE There is no matched device path instance.
+
+**/
+BOOLEAN
+BmMatchPartitionDevicePathNode (
+ IN EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath,
+ IN HARDDRIVE_DEVICE_PATH *HardDriveDevicePath
+ )
+{
+ HARDDRIVE_DEVICE_PATH *Node;
+
+ if ((BlockIoDevicePath == NULL) || (HardDriveDevicePath == NULL)) {
+ return FALSE;
+ }
+
+ //
+ // find the partition device path node
+ //
+ while (!IsDevicePathEnd (BlockIoDevicePath)) {
+ if ((DevicePathType (BlockIoDevicePath) == MEDIA_DEVICE_PATH) &&
+ (DevicePathSubType (BlockIoDevicePath) == MEDIA_HARDDRIVE_DP)
+ ) {
+ break;
+ }
+
+ BlockIoDevicePath = NextDevicePathNode (BlockIoDevicePath);
+ }
+
+ if (IsDevicePathEnd (BlockIoDevicePath)) {
+ return FALSE;
+ }
+
+ //
+ // See if the harddrive device path in blockio matches the orig Hard Drive Node
+ //
+ Node = (HARDDRIVE_DEVICE_PATH *) BlockIoDevicePath;
+
+ //
+ // Match Signature and PartitionNumber.
+ // Unused bytes in Signature are initiaized with zeros.
+ //
+ return (BOOLEAN) (
+ (Node->PartitionNumber == HardDriveDevicePath->PartitionNumber) &&
+ (Node->MBRType == HardDriveDevicePath->MBRType) &&
+ (Node->SignatureType == HardDriveDevicePath->SignatureType) &&
+ (CompareMem (Node->Signature, HardDriveDevicePath->Signature, sizeof (Node->Signature)) == 0)
+ );
+}
+
+/**
+ Enumerate all boot option descriptions and append " 2"/" 3"/... to make
+ unique description.
+
+ @param BootOptions Array of boot options.
+ @param BootOptionCount Count of boot options.
+**/
+VOID
+BmMakeBootOptionDescriptionUnique (
+ EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions,
+ UINTN BootOptionCount
+ )
+{
+ UINTN Base;
+ UINTN Index;
+ UINTN DescriptionSize;
+ UINTN MaxSuffixSize;
+ BOOLEAN *Visited;
+ UINTN MatchCount;
+
+ if (BootOptionCount == 0) {
+ return;
+ }
+
+ //
+ // Calculate the maximum buffer size for the number suffix.
+ // The initial sizeof (CHAR16) is for the blank space before the number.
+ //
+ MaxSuffixSize = sizeof (CHAR16);
+ for (Index = BootOptionCount; Index != 0; Index = Index / 10) {
+ MaxSuffixSize += sizeof (CHAR16);
+ }
+
+ Visited = AllocateZeroPool (sizeof (BOOLEAN) * BootOptionCount);
+ ASSERT (Visited != NULL);
+
+ for (Base = 0; Base < BootOptionCount; Base++) {
+ if (!Visited[Base]) {
+ MatchCount = 1;
+ Visited[Base] = TRUE;
+ DescriptionSize = StrSize (BootOptions[Base].Description);
+ for (Index = Base + 1; Index < BootOptionCount; Index++) {
+ if (!Visited[Index] && StrCmp (BootOptions[Base].Description, BootOptions[Index].Description) == 0) {
+ Visited[Index] = TRUE;
+ MatchCount++;
+ FreePool (BootOptions[Index].Description);
+ BootOptions[Index].Description = AllocatePool (DescriptionSize + MaxSuffixSize);
+ UnicodeSPrint (
+ BootOptions[Index].Description, DescriptionSize + MaxSuffixSize,
+ L"%s %d",
+ BootOptions[Base].Description, MatchCount
+ );
+ }
+ }
+ }
+ }
+
+ FreePool (Visited);
+}
+
+/**
+ Emuerate all possible bootable medias in the following order:
+ 1. Removable BlockIo - The boot option only points to the removable media
+ device, like USB key, DVD, Floppy etc.
+ 2. Fixed BlockIo - The boot option only points to a Fixed blockIo device,
+ like HardDisk.
+ 3. Non-BlockIo SimpleFileSystem - The boot option points to a device supporting
+ SimpleFileSystem Protocol, but not supporting BlockIo
+ protocol.
+ 4. LoadFile - The boot option points to the media supporting
+ LoadFile protocol.
+ Reference: UEFI Spec chapter 3.3 Boot Option Variables Default Boot Behavior
+
+ @param BootOptionCount Return the boot option count which has been found.
+
+ @retval Pointer to the boot option array.
+**/
+EFI_BOOT_MANAGER_LOAD_OPTION *
+BmEnumerateBootOptions (
+ UINTN *BootOptionCount
+ )
+{
+ EFI_STATUS Status;
+ EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
+ UINTN HandleCount;
+ EFI_HANDLE *Handles;
+ EFI_BLOCK_IO_PROTOCOL *BlkIo;
+ UINTN Removable;
+ UINTN Index;
+ CHAR16 *Description;
+
+ ASSERT (BootOptionCount != NULL);
+
+ *BootOptionCount = 0;
+ BootOptions = NULL;
+
+ //
+ // Parse removable block io followed by fixed block io
+ //
+ gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiBlockIoProtocolGuid,
+ NULL,
+ &HandleCount,
+ &Handles
+ );
+
+ for (Removable = 0; Removable < 2; Removable++) {
+ for (Index = 0; Index < HandleCount; Index++) {
+ Status = gBS->HandleProtocol (
+ Handles[Index],
+ &gEfiBlockIoProtocolGuid,
+ (VOID **) &BlkIo
+ );
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ //
+ // Skip the logical partitions
+ //
+ if (BlkIo->Media->LogicalPartition) {
+ continue;
+ }
+
+ //
+ // Skip the fixed block io then the removable block io
+ //
+ if (BlkIo->Media->RemovableMedia == ((Removable == 0) ? FALSE : TRUE)) {
+ continue;
+ }
+
+ Description = BmGetBootDescription (Handles[Index]);
+ BootOptions = ReallocatePool (
+ sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount),
+ sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1),
+ BootOptions
+ );
+ ASSERT (BootOptions != NULL);
+
+ Status = EfiBootManagerInitializeLoadOption (
+ &BootOptions[(*BootOptionCount)++],
+ LoadOptionNumberUnassigned,
+ LoadOptionTypeBoot,
+ LOAD_OPTION_ACTIVE,
+ Description,
+ DevicePathFromHandle (Handles[Index]),
+ NULL,
+ 0
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ FreePool (Description);
+ }
+ }
+
+ if (HandleCount != 0) {
+ FreePool (Handles);
+ }
+
+ //
+ // Parse simple file system not based on block io
+ //
+ gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiSimpleFileSystemProtocolGuid,
+ NULL,
+ &HandleCount,
+ &Handles
+ );
+ for (Index = 0; Index < HandleCount; Index++) {
+ Status = gBS->HandleProtocol (
+ Handles[Index],
+ &gEfiBlockIoProtocolGuid,
+ (VOID **) &BlkIo
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Skip if the file system handle supports a BlkIo protocol, which we've handled in above
+ //
+ continue;
+ }
+ Description = BmGetBootDescription (Handles[Index]);
+ BootOptions = ReallocatePool (
+ sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount),
+ sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1),
+ BootOptions
+ );
+ ASSERT (BootOptions != NULL);
+
+ Status = EfiBootManagerInitializeLoadOption (
+ &BootOptions[(*BootOptionCount)++],
+ LoadOptionNumberUnassigned,
+ LoadOptionTypeBoot,
+ LOAD_OPTION_ACTIVE,
+ Description,
+ DevicePathFromHandle (Handles[Index]),
+ NULL,
+ 0
+ );
+ ASSERT_EFI_ERROR (Status);
+ FreePool (Description);
+ }
+
+ if (HandleCount != 0) {
+ FreePool (Handles);
+ }
+
+ //
+ // Parse load file, assuming UEFI Network boot option
+ //
+ gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiLoadFileProtocolGuid,
+ NULL,
+ &HandleCount,
+ &Handles
+ );
+ for (Index = 0; Index < HandleCount; Index++) {
+
+ Description = BmGetBootDescription (Handles[Index]);
+ BootOptions = ReallocatePool (
+ sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount),
+ sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1),
+ BootOptions
+ );
+ ASSERT (BootOptions != NULL);
+
+ Status = EfiBootManagerInitializeLoadOption (
+ &BootOptions[(*BootOptionCount)++],
+ LoadOptionNumberUnassigned,
+ LoadOptionTypeBoot,
+ LOAD_OPTION_ACTIVE,
+ Description,
+ DevicePathFromHandle (Handles[Index]),
+ NULL,
+ 0
+ );
+ ASSERT_EFI_ERROR (Status);
+ FreePool (Description);
+ }
+
+ if (HandleCount != 0) {
+ FreePool (Handles);
+ }
+
+ BmMakeBootOptionDescriptionUnique (BootOptions, *BootOptionCount);
+ return BootOptions;
+}
+
+/**
+ The function enumerates all boot options, creates them and registers them in the BootOrder variable.
+**/
+VOID
+EFIAPI
+EfiBootManagerRefreshAllBootOption (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_BOOT_MANAGER_LOAD_OPTION *NvBootOptions;
+ UINTN NvBootOptionCount;
+ EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
+ UINTN BootOptionCount;
+ UINTN Index;
+
+ //
+ // Optionally refresh the legacy boot option
+ //
+ if (mBmRefreshLegacyBootOption != NULL) {
+ mBmRefreshLegacyBootOption ();
+ }
+
+ BootOptions = BmEnumerateBootOptions (&BootOptionCount);
+ NvBootOptions = EfiBootManagerGetLoadOptions (&NvBootOptionCount, LoadOptionTypeBoot);
+
+ //
+ // Mark the boot option as added by BDS by setting OptionalData to a special GUID
+ //
+ for (Index = 0; Index < BootOptionCount; Index++) {
+ BootOptions[Index].OptionalData = AllocateCopyPool (sizeof (EFI_GUID), &mBmAutoCreateBootOptionGuid);
+ BootOptions[Index].OptionalDataSize = sizeof (EFI_GUID);
+ }
+
+ //
+ // Remove invalid EFI boot options from NV
+ //
+ for (Index = 0; Index < NvBootOptionCount; Index++) {
+ if (((DevicePathType (NvBootOptions[Index].FilePath) != BBS_DEVICE_PATH) ||
+ (DevicePathSubType (NvBootOptions[Index].FilePath) != BBS_BBS_DP)
+ ) && BmIsAutoCreateBootOption (&NvBootOptions[Index])
+ ) {
+ //
+ // Only check those added by BDS
+ // so that the boot options added by end-user or OS installer won't be deleted
+ //
+ if (BmFindLoadOption (&NvBootOptions[Index], BootOptions, BootOptionCount) == (UINTN) -1) {
+ Status = EfiBootManagerDeleteLoadOptionVariable (NvBootOptions[Index].OptionNumber, LoadOptionTypeBoot);
+ //
+ // Deleting variable with current variable implementation shouldn't fail.
+ //
+ ASSERT_EFI_ERROR (Status);
+ }
+ }
+ }
+
+ //
+ // Add new EFI boot options to NV
+ //
+ for (Index = 0; Index < BootOptionCount; Index++) {
+ if (BmFindLoadOption (&BootOptions[Index], NvBootOptions, NvBootOptionCount) == (UINTN) -1) {
+ EfiBootManagerAddLoadOptionVariable (&BootOptions[Index], (UINTN) -1);
+ //
+ // Try best to add the boot options so continue upon failure.
+ //
+ }
+ }
+
+ EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
+ EfiBootManagerFreeLoadOptions (NvBootOptions, NvBootOptionCount);
+}
+
+/**
+ This function is called to create the boot option for the Boot Manager Menu.
+
+ The Boot Manager Menu is shown after successfully booting a boot option.
+ Assume the BootManagerMenuFile is in the same FV as the module links to this library.
+
+ @param BootOption Return the boot option of the Boot Manager Menu
+
+ @retval EFI_SUCCESS Successfully register the Boot Manager Menu.
+ @retval Status Return status of gRT->SetVariable (). BootOption still points
+ to the Boot Manager Menu even the Status is not EFI_SUCCESS.
+**/
+EFI_STATUS
+BmRegisterBootManagerMenu (
+ OUT EFI_BOOT_MANAGER_LOAD_OPTION *BootOption
+ )
+{
+ EFI_STATUS Status;
+ CHAR16 *Description;
+ UINTN DescriptionLength;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
+ MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode;
+
+ Status = GetSectionFromFv (
+ PcdGetPtr (PcdBootManagerMenuFile),
+ EFI_SECTION_USER_INTERFACE,
+ 0,
+ (VOID **) &Description,
+ &DescriptionLength
+ );
+ if (EFI_ERROR (Status)) {
+ Description = NULL;
+ }
+
+ EfiInitializeFwVolDevicepathNode (&FileNode, PcdGetPtr (PcdBootManagerMenuFile));
+ Status = gBS->HandleProtocol (
+ gImageHandle,
+ &gEfiLoadedImageProtocolGuid,
+ (VOID **) &LoadedImage
+ );
+ ASSERT_EFI_ERROR (Status);
+ DevicePath = AppendDevicePathNode (
+ DevicePathFromHandle (LoadedImage->DeviceHandle),
+ (EFI_DEVICE_PATH_PROTOCOL *) &FileNode
+ );
+ ASSERT (DevicePath != NULL);
+
+ Status = EfiBootManagerInitializeLoadOption (
+ BootOption,
+ LoadOptionNumberUnassigned,
+ LoadOptionTypeBoot,
+ LOAD_OPTION_CATEGORY_APP | LOAD_OPTION_ACTIVE | LOAD_OPTION_HIDDEN,
+ (Description != NULL) ? Description : L"Boot Manager Menu",
+ DevicePath,
+ NULL,
+ 0
+ );
+ ASSERT_EFI_ERROR (Status);
+ FreePool (DevicePath);
+ if (Description != NULL) {
+ FreePool (Description);
+ }
+
+ DEBUG_CODE (
+ EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
+ UINTN BootOptionCount;
+
+ BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
+ ASSERT (BmFindLoadOption (BootOption, BootOptions, BootOptionCount) == -1);
+ EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
+ );
+
+ return EfiBootManagerAddLoadOptionVariable (BootOption, 0);
+}
+
+/**
+ Return the boot option corresponding to the Boot Manager Menu.
+ It may automatically create one if the boot option hasn't been created yet.
+
+ @param BootOption Return the Boot Manager Menu.
+
+ @retval EFI_SUCCESS The Boot Manager Menu is successfully returned.
+ @retval Status Return status of gRT->SetVariable (). BootOption still points
+ to the Boot Manager Menu even the Status is not EFI_SUCCESS.
+**/
+EFI_STATUS
+EFIAPI
+EfiBootManagerGetBootManagerMenu (
+ EFI_BOOT_MANAGER_LOAD_OPTION *BootOption
+ )
+{
+ EFI_STATUS Status;
+ UINTN BootOptionCount;
+ EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
+ UINTN Index;
+ EFI_DEVICE_PATH_PROTOCOL *Node;
+ EFI_HANDLE FvHandle;
+
+ BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
+
+ for (Index = 0; Index < BootOptionCount; Index++) {
+ Node = BootOptions[Index].FilePath;
+ Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &Node, &FvHandle);
+ if (!EFI_ERROR (Status)) {
+ if (CompareGuid (
+ EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) Node),
+ PcdGetPtr (PcdBootManagerMenuFile)
+ )
+ ) {
+ Status = EfiBootManagerInitializeLoadOption (
+ BootOption,
+ BootOptions[Index].OptionNumber,
+ BootOptions[Index].OptionType,
+ BootOptions[Index].Attributes,
+ BootOptions[Index].Description,
+ BootOptions[Index].FilePath,
+ BootOptions[Index].OptionalData,
+ BootOptions[Index].OptionalDataSize
+ );
+ ASSERT_EFI_ERROR (Status);
+ break;
+ }
+ }
+ }
+
+ EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
+
+ //
+ // Automatically create the Boot#### for Boot Manager Menu when not found.
+ //
+ if (Index == BootOptionCount) {
+ return BmRegisterBootManagerMenu (BootOption);
+ } else {
+ return EFI_SUCCESS;
+ }
+}
+
diff --git a/Core/MdeModulePkg/Library/UefiBootManagerLib/BmConnect.c b/Core/MdeModulePkg/Library/UefiBootManagerLib/BmConnect.c
new file mode 100644
index 0000000000..b1c94ad9d9
--- /dev/null
+++ b/Core/MdeModulePkg/Library/UefiBootManagerLib/BmConnect.c
@@ -0,0 +1,321 @@
+/** @file
+ Library functions which relate with connecting the device.
+
+Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "InternalBm.h"
+
+/**
+ Connect all the drivers to all the controllers.
+
+ This function makes sure all the current system drivers manage the correspoinding
+ controllers if have. And at the same time, makes sure all the system controllers
+ have driver to manage it if have.
+**/
+VOID
+BmConnectAllDriversToAllControllers (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ UINTN Index;
+
+ do {
+ //
+ // Connect All EFI 1.10 drivers following EFI 1.10 algorithm
+ //
+ gBS->LocateHandleBuffer (
+ AllHandles,
+ NULL,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+
+ for (Index = 0; Index < HandleCount; Index++) {
+ gBS->ConnectController (HandleBuffer[Index], NULL, NULL, TRUE);
+ }
+
+ if (HandleBuffer != NULL) {
+ FreePool (HandleBuffer);
+ }
+
+ //
+ // Check to see if it's possible to dispatch an more DXE drivers.
+ // The above code may have made new DXE drivers show up.
+ // If any new driver is dispatched (Status == EFI_SUCCESS) and we will try
+ // the connect again.
+ //
+ Status = gDS->Dispatch ();
+
+ } while (!EFI_ERROR (Status));
+}
+
+/**
+ This function will connect all the system driver to controller
+ first, and then special connect the default console, this make
+ sure all the system controller available and the platform default
+ console connected.
+
+**/
+VOID
+EFIAPI
+EfiBootManagerConnectAll (
+ VOID
+ )
+{
+ //
+ // Connect the platform console first
+ //
+ EfiBootManagerConnectAllDefaultConsoles ();
+
+ //
+ // Generic way to connect all the drivers
+ //
+ BmConnectAllDriversToAllControllers ();
+
+ //
+ // Here we have the assumption that we have already had
+ // platform default console
+ //
+ EfiBootManagerConnectAllDefaultConsoles ();
+}
+
+/**
+ This function will create all handles associate with every device
+ path node. If the handle associate with one device path node can not
+ be created successfully, then still give chance to do the dispatch,
+ which load the missing drivers if possible.
+
+ @param DevicePathToConnect The device path which will be connected, it can be
+ a multi-instance device path
+ @param MatchingHandle Return the controller handle closest to the DevicePathToConnect
+
+ @retval EFI_SUCCESS All handles associate with every device path node
+ have been created.
+ @retval EFI_OUT_OF_RESOURCES There is no resource to create new handles.
+ @retval EFI_NOT_FOUND Create the handle associate with one device path
+ node failed.
+ @retval EFI_SECURITY_VIOLATION The user has no permission to start UEFI device
+ drivers on the DevicePath.
+**/
+EFI_STATUS
+EFIAPI
+EfiBootManagerConnectDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePathToConnect,
+ OUT EFI_HANDLE *MatchingHandle OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath;
+ EFI_HANDLE Handle;
+ EFI_HANDLE PreviousHandle;
+ EFI_TPL CurrentTpl;
+
+ if (DevicePathToConnect == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CurrentTpl = EfiGetCurrentTpl ();
+ //
+ // Start the real work of connect with RemainingDevicePath
+ //
+ PreviousHandle = NULL;
+ do {
+ //
+ // Find the handle that best matches the Device Path. If it is only a
+ // partial match the remaining part of the device path is returned in
+ // RemainingDevicePath.
+ //
+ RemainingDevicePath = DevicePathToConnect;
+ Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &RemainingDevicePath, &Handle);
+ if (!EFI_ERROR (Status)) {
+ if (Handle == PreviousHandle) {
+ //
+ // If no forward progress is made try invoking the Dispatcher.
+ // A new FV may have been added to the system an new drivers
+ // may now be found.
+ // Status == EFI_SUCCESS means a driver was dispatched
+ // Status == EFI_NOT_FOUND means no new drivers were dispatched
+ //
+ if (CurrentTpl == TPL_APPLICATION) {
+ Status = gDS->Dispatch ();
+ } else {
+ //
+ // Always return EFI_NOT_FOUND here
+ // to prevent dead loop when control handle is found but connection failded case
+ //
+ Status = EFI_NOT_FOUND;
+ }
+ }
+
+
+ if (!EFI_ERROR (Status)) {
+ PreviousHandle = Handle;
+ //
+ // Connect all drivers that apply to Handle and RemainingDevicePath,
+ // the Recursive flag is FALSE so only one level will be expanded.
+ //
+ // If ConnectController fails to find a driver, then still give the chance to
+ // do dispatch, because partial RemainingDevicePath may be in the new FV
+ //
+ // 1. If the connect fail, RemainingDevicepath and handle will not
+ // change, so next time will do the dispatch, then dispatch's status
+ // will take effect
+ // 2. If the connect success, the RemainingDevicepath and handle will
+ // change, then avoid the dispatch, we have chance to continue the
+ // next connection
+ //
+ Status = gBS->ConnectController (Handle, NULL, RemainingDevicePath, FALSE);
+ if (Status == EFI_NOT_FOUND) {
+ Status = EFI_SUCCESS;
+ }
+ if (MatchingHandle != NULL) {
+ *MatchingHandle = Handle;
+ }
+ }
+ }
+ //
+ // Loop until RemainingDevicePath is an empty device path
+ //
+ } while (!EFI_ERROR (Status) && !IsDevicePathEnd (RemainingDevicePath));
+
+ ASSERT (EFI_ERROR (Status) || IsDevicePathEnd (RemainingDevicePath));
+
+ return Status;
+}
+
+/**
+ This function will disconnect all current system handles.
+
+ gBS->DisconnectController() is invoked for each handle exists in system handle buffer.
+ If handle is a bus type handle, all childrens also are disconnected recursively by
+ gBS->DisconnectController().
+**/
+VOID
+EFIAPI
+EfiBootManagerDisconnectAll (
+ VOID
+ )
+{
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ UINTN Index;
+
+ //
+ // Disconnect all
+ //
+ gBS->LocateHandleBuffer (
+ AllHandles,
+ NULL,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ for (Index = 0; Index < HandleCount; Index++) {
+ gBS->DisconnectController (HandleBuffer[Index], NULL, NULL);
+ }
+
+ if (HandleBuffer != NULL) {
+ FreePool (HandleBuffer);
+ }
+}
+
+/**
+ Connect the specific Usb device which match the short form device path,
+ and whose bus is determined by Host Controller (Uhci or Ehci).
+
+ @param DevicePath A short-form device path that starts with the first
+ element being a USB WWID or a USB Class device
+ path
+
+ @return EFI_INVALID_PARAMETER DevicePath is NULL pointer.
+ DevicePath is not a USB device path.
+
+ @return EFI_SUCCESS Success to connect USB device
+ @return EFI_NOT_FOUND Fail to find handle for USB controller to connect.
+
+**/
+EFI_STATUS
+BmConnectUsbShortFormDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE *Handles;
+ UINTN HandleCount;
+ UINTN Index;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT8 Class[3];
+ BOOLEAN AtLeastOneConnected;
+
+ //
+ // Check the passed in parameters
+ //
+ if (DevicePath == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((DevicePathType (DevicePath) != MESSAGING_DEVICE_PATH) ||
+ ((DevicePathSubType (DevicePath) != MSG_USB_CLASS_DP) && (DevicePathSubType (DevicePath) != MSG_USB_WWID_DP))
+ ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Find the usb host controller firstly, then connect with the remaining device path
+ //
+ AtLeastOneConnected = FALSE;
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiPciIoProtocolGuid,
+ NULL,
+ &HandleCount,
+ &Handles
+ );
+ if (!EFI_ERROR (Status)) {
+ for (Index = 0; Index < HandleCount; Index++) {
+ Status = gBS->HandleProtocol (
+ Handles[Index],
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Check whether the Pci device is the wanted usb host controller
+ //
+ Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x09, 3, &Class);
+ if (!EFI_ERROR (Status) &&
+ ((PCI_CLASS_SERIAL == Class[2]) && (PCI_CLASS_SERIAL_USB == Class[1]))
+ ) {
+ Status = gBS->ConnectController (
+ Handles[Index],
+ NULL,
+ DevicePath,
+ FALSE
+ );
+ if (!EFI_ERROR(Status)) {
+ AtLeastOneConnected = TRUE;
+ }
+ }
+ }
+ }
+
+ if (Handles != NULL) {
+ FreePool (Handles);
+ }
+ }
+
+ return AtLeastOneConnected ? EFI_SUCCESS : EFI_NOT_FOUND;
+}
diff --git a/Core/MdeModulePkg/Library/UefiBootManagerLib/BmConsole.c b/Core/MdeModulePkg/Library/UefiBootManagerLib/BmConsole.c
new file mode 100644
index 0000000000..86b4fac424
--- /dev/null
+++ b/Core/MdeModulePkg/Library/UefiBootManagerLib/BmConsole.c
@@ -0,0 +1,764 @@
+/** @file
+ Library functions which contain all the code to connect console device.
+
+Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "InternalBm.h"
+
+CHAR16 *mConVarName[] = {
+ L"ConIn",
+ L"ConOut",
+ L"ErrOut",
+ L"ConInDev",
+ L"ConOutDev",
+ L"ErrOutDev"
+};
+
+/**
+ Search out the video controller.
+
+ @return PCI device path of the video controller.
+**/
+EFI_HANDLE
+BmGetVideoController (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN RootBridgeHandleCount;
+ EFI_HANDLE *RootBridgeHandleBuffer;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ UINTN RootBridgeIndex;
+ UINTN Index;
+ EFI_HANDLE VideoController;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ PCI_TYPE00 Pci;
+
+ //
+ // Make all the PCI_IO protocols show up
+ //
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiPciRootBridgeIoProtocolGuid,
+ NULL,
+ &RootBridgeHandleCount,
+ &RootBridgeHandleBuffer
+ );
+ if (EFI_ERROR (Status) || (RootBridgeHandleCount == 0)) {
+ return NULL;
+ }
+
+ VideoController = NULL;
+ for (RootBridgeIndex = 0; RootBridgeIndex < RootBridgeHandleCount; RootBridgeIndex++) {
+ gBS->ConnectController (RootBridgeHandleBuffer[RootBridgeIndex], NULL, NULL, FALSE);
+
+ //
+ // Start to check all the pci io to find the first video controller
+ //
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiPciIoProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ for (Index = 0; Index < HandleCount; Index++) {
+ Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiPciIoProtocolGuid, (VOID **) &PciIo);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Check for all video controller
+ //
+ Status = PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint32,
+ 0,
+ sizeof (Pci) / sizeof (UINT32),
+ &Pci
+ );
+ if (!EFI_ERROR (Status) && IS_PCI_VGA (&Pci)) {
+ // TODO: use IS_PCI_DISPLAY??
+ VideoController = HandleBuffer[Index];
+ break;
+ }
+ }
+ }
+ FreePool (HandleBuffer);
+
+ if (VideoController != NULL) {
+ break;
+ }
+ }
+ FreePool (RootBridgeHandleBuffer);
+
+ return VideoController;
+}
+
+/**
+ Query all the children of VideoController and return the device paths of all the
+ children that support GraphicsOutput protocol.
+
+ @param VideoController PCI handle of video controller.
+
+ @return Device paths of all the children that support GraphicsOutput protocol.
+**/
+EFI_DEVICE_PATH_PROTOCOL *
+EFIAPI
+EfiBootManagerGetGopDevicePath (
+ IN EFI_HANDLE VideoController
+ )
+{
+ UINTN Index;
+ EFI_STATUS Status;
+ EFI_GUID **ProtocolBuffer;
+ UINTN ProtocolBufferCount;
+ UINTN ProtocolIndex;
+ EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;
+ UINTN EntryCount;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *Next;
+ EFI_DEVICE_PATH_PROTOCOL *Previous;
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *GopPool;
+ EFI_DEVICE_PATH_PROTOCOL *ReturnDevicePath;
+
+
+ Status = gBS->ProtocolsPerHandle (
+ VideoController,
+ &ProtocolBuffer,
+ &ProtocolBufferCount
+ );
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ GopPool = NULL;
+
+ for (ProtocolIndex = 0; ProtocolIndex < ProtocolBufferCount; ProtocolIndex++) {
+ Status = gBS->OpenProtocolInformation (
+ VideoController,
+ ProtocolBuffer[ProtocolIndex],
+ &OpenInfoBuffer,
+ &EntryCount
+ );
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ for (Index = 0; Index < EntryCount; Index++) {
+ //
+ // Query all the children
+ //
+ if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
+ Status = gBS->OpenProtocol (
+ OpenInfoBuffer[Index].ControllerHandle,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &DevicePath,
+ NULL,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ Previous = NULL;
+ for (Next = DevicePath; !IsDevicePathEnd (Next); Next = NextDevicePathNode (Next)) {
+ Previous = Next;
+ }
+ ASSERT (Previous != NULL);
+
+ if (DevicePathType (Previous) == ACPI_DEVICE_PATH && DevicePathSubType (Previous) == ACPI_ADR_DP) {
+ Status = gBS->OpenProtocol (
+ OpenInfoBuffer[Index].ControllerHandle,
+ &gEfiGraphicsOutputProtocolGuid,
+ NULL,
+ NULL,
+ NULL,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Append the device path to GOP pool when there is GOP protocol installed.
+ //
+ TempDevicePath = GopPool;
+ GopPool = AppendDevicePathInstance (GopPool, DevicePath);
+ gBS->FreePool (TempDevicePath);
+ }
+ }
+
+ if (DevicePathType (Previous) == HARDWARE_DEVICE_PATH && DevicePathSubType (Previous) == HW_CONTROLLER_DP) {
+ //
+ // Recursively look for GOP child in this frame buffer handle
+ //
+ DEBUG ((EFI_D_INFO, "[Bds] Looking for GOP child deeper ... \n"));
+ TempDevicePath = GopPool;
+ ReturnDevicePath = EfiBootManagerGetGopDevicePath (OpenInfoBuffer[Index].ControllerHandle);
+ GopPool = AppendDevicePathInstance (GopPool, ReturnDevicePath);
+ gBS->FreePool (ReturnDevicePath);
+ gBS->FreePool (TempDevicePath);
+ }
+ }
+ }
+
+ FreePool (OpenInfoBuffer);
+ }
+
+ FreePool (ProtocolBuffer);
+
+ return GopPool;
+}
+
+/**
+ Connect the platform active active video controller.
+
+ @param VideoController PCI handle of video controller.
+
+ @retval EFI_NOT_FOUND There is no active video controller.
+ @retval EFI_SUCCESS The video controller is connected.
+**/
+EFI_STATUS
+EFIAPI
+EfiBootManagerConnectVideoController (
+ EFI_HANDLE VideoController OPTIONAL
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *Gop;
+
+ if (VideoController == NULL) {
+ //
+ // Get the platform vga device
+ //
+ VideoController = BmGetVideoController ();
+ }
+
+ if (VideoController == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Try to connect the PCI device path, so that GOP dirver could start on this
+ // device and create child handles with GraphicsOutput Protocol installed
+ // on them, then we get device paths of these child handles and select
+ // them as possible console device.
+ //
+ gBS->ConnectController (VideoController, NULL, NULL, FALSE);
+
+ Gop = EfiBootManagerGetGopDevicePath (VideoController);
+ if (Gop == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ EfiBootManagerUpdateConsoleVariable (ConOut, Gop, NULL);
+ FreePool (Gop);
+
+ //
+ // Necessary for ConPlatform and ConSplitter driver to start up again after ConOut is updated.
+ //
+ return gBS->ConnectController (VideoController, NULL, NULL, TRUE);
+}
+
+/**
+ Fill console handle in System Table if there are no valid console handle in.
+
+ Firstly, check the validation of console handle in System Table. If it is invalid,
+ update it by the first console device handle from EFI console variable.
+
+ @param VarName The name of the EFI console variable.
+ @param ConsoleGuid Specified Console protocol GUID.
+ @param ConsoleHandle On IN, console handle in System Table to be checked.
+ On OUT, new console handle in system table.
+ @param ProtocolInterface On IN, console protocol on console handle in System Table to be checked.
+ On OUT, new console protocol on new console handle in system table.
+
+ @retval TRUE System Table has been updated.
+ @retval FALSE System Table hasn't been updated.
+
+**/
+BOOLEAN
+BmUpdateSystemTableConsole (
+ IN CHAR16 *VarName,
+ IN EFI_GUID *ConsoleGuid,
+ IN OUT EFI_HANDLE *ConsoleHandle,
+ IN OUT VOID **ProtocolInterface
+ )
+{
+ EFI_STATUS Status;
+ UINTN DevicePathSize;
+ EFI_DEVICE_PATH_PROTOCOL *FullDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *VarConsole;
+ EFI_DEVICE_PATH_PROTOCOL *Instance;
+ VOID *Interface;
+ EFI_HANDLE NewHandle;
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *TextOut;
+
+ ASSERT (VarName != NULL);
+ ASSERT (ConsoleHandle != NULL);
+ ASSERT (ConsoleGuid != NULL);
+ ASSERT (ProtocolInterface != NULL);
+
+ if (*ConsoleHandle != NULL) {
+ Status = gBS->HandleProtocol (
+ *ConsoleHandle,
+ ConsoleGuid,
+ &Interface
+ );
+ if (Status == EFI_SUCCESS && Interface == *ProtocolInterface) {
+ //
+ // If ConsoleHandle is valid and console protocol on this handle also
+ // also matched, just return.
+ //
+ return FALSE;
+ }
+ }
+
+ //
+ // Get all possible consoles device path from EFI variable
+ //
+ GetEfiGlobalVariable2 (VarName, (VOID **) &VarConsole, NULL);
+ if (VarConsole == NULL) {
+ //
+ // If there is no any console device, just return.
+ //
+ return FALSE;
+ }
+
+ FullDevicePath = VarConsole;
+
+ do {
+ //
+ // Check every instance of the console variable
+ //
+ Instance = GetNextDevicePathInstance (&VarConsole, &DevicePathSize);
+ if (Instance == NULL) {
+ DEBUG ((EFI_D_ERROR, "[Bds] No valid console instance is found for %s!\n", VarName));
+ // We should not ASSERT when all the console devices are removed.
+ // ASSERT_EFI_ERROR (EFI_NOT_FOUND);
+ FreePool (FullDevicePath);
+ return FALSE;
+ }
+
+ //
+ // Find console device handle by device path instance
+ //
+ Status = gBS->LocateDevicePath (
+ ConsoleGuid,
+ &Instance,
+ &NewHandle
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Get the console protocol on this console device handle
+ //
+ Status = gBS->HandleProtocol (
+ NewHandle,
+ ConsoleGuid,
+ &Interface
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Update new console handle in System Table.
+ //
+ *ConsoleHandle = NewHandle;
+ *ProtocolInterface = Interface;
+ if (CompareGuid (ConsoleGuid, &gEfiSimpleTextOutProtocolGuid)) {
+ //
+ // If it is console out device, set console mode 80x25 if current mode is invalid.
+ //
+ TextOut = (EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *) Interface;
+ if (TextOut->Mode->Mode == -1) {
+ TextOut->SetMode (TextOut, 0);
+ }
+ }
+ return TRUE;
+ }
+ }
+
+ } while (Instance != NULL);
+
+ //
+ // No any available console devcie found.
+ //
+ return FALSE;
+}
+
+/**
+ This function updates the console variable based on ConVarName. It can
+ add or remove one specific console device path from the variable
+
+ @param ConsoleType ConIn, ConOut, ErrOut, ConInDev, ConOutDev or ErrOutDev.
+ @param CustomizedConDevicePath The console device path to be added to
+ the console variable. Cannot be multi-instance.
+ @param ExclusiveDevicePath The console device path to be removed
+ from the console variable. Cannot be multi-instance.
+
+ @retval EFI_UNSUPPORTED The added device path is the same as a removed one.
+ @retval EFI_SUCCESS Successfully added or removed the device path from the
+ console variable.
+ @retval others Return status of RT->SetVariable().
+
+**/
+EFI_STATUS
+EFIAPI
+EfiBootManagerUpdateConsoleVariable (
+ IN CONSOLE_TYPE ConsoleType,
+ IN EFI_DEVICE_PATH_PROTOCOL *CustomizedConDevicePath,
+ IN EFI_DEVICE_PATH_PROTOCOL *ExclusiveDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *VarConsole;
+ EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *TempNewDevicePath;
+
+ if (ConsoleType >= sizeof (mConVarName) / sizeof (mConVarName[0])) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Notes: check the device path point, here should check
+ // with compare memory
+ //
+ if (CustomizedConDevicePath == ExclusiveDevicePath) {
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Delete the ExclusiveDevicePath from current default console
+ //
+ GetEfiGlobalVariable2 (mConVarName[ConsoleType], (VOID **) &VarConsole, NULL);
+ //
+ // Initialize NewDevicePath
+ //
+ NewDevicePath = VarConsole;
+
+ //
+ // If ExclusiveDevicePath is even the part of the instance in VarConsole, delete it.
+ // In the end, NewDevicePath is the final device path.
+ //
+ if (ExclusiveDevicePath != NULL && VarConsole != NULL) {
+ NewDevicePath = BmDelPartMatchInstance (VarConsole, ExclusiveDevicePath);
+ }
+ //
+ // Try to append customized device path to NewDevicePath.
+ //
+ if (CustomizedConDevicePath != NULL) {
+ if (!BmMatchDevicePaths (NewDevicePath, CustomizedConDevicePath)) {
+ //
+ // Check if there is part of CustomizedConDevicePath in NewDevicePath, delete it.
+ //
+ NewDevicePath = BmDelPartMatchInstance (NewDevicePath, CustomizedConDevicePath);
+ //
+ // In the first check, the default console variable will be _ModuleEntryPoint,
+ // just append current customized device path
+ //
+ TempNewDevicePath = NewDevicePath;
+ NewDevicePath = AppendDevicePathInstance (NewDevicePath, CustomizedConDevicePath);
+ if (TempNewDevicePath != NULL) {
+ FreePool(TempNewDevicePath);
+ }
+ }
+ }
+
+ //
+ // Finally, Update the variable of the default console by NewDevicePath
+ //
+ Status = gRT->SetVariable (
+ mConVarName[ConsoleType],
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS
+ | ((ConsoleType < ConInDev) ? EFI_VARIABLE_NON_VOLATILE : 0),
+ GetDevicePathSize (NewDevicePath),
+ NewDevicePath
+ );
+
+ if (VarConsole == NewDevicePath) {
+ if (VarConsole != NULL) {
+ FreePool(VarConsole);
+ }
+ } else {
+ if (VarConsole != NULL) {
+ FreePool(VarConsole);
+ }
+ if (NewDevicePath != NULL) {
+ FreePool(NewDevicePath);
+ }
+ }
+
+ return Status;
+}
+
+
+/**
+ Connect the console device base on the variable ConsoleType.
+
+ @param ConsoleType ConIn, ConOut or ErrOut.
+
+ @retval EFI_NOT_FOUND There is not any console devices connected
+ success
+ @retval EFI_SUCCESS Success connect any one instance of the console
+ device path base on the variable ConVarName.
+
+**/
+EFI_STATUS
+EFIAPI
+EfiBootManagerConnectConsoleVariable (
+ IN CONSOLE_TYPE ConsoleType
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *StartDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *Instance;
+ EFI_DEVICE_PATH_PROTOCOL *Next;
+ EFI_DEVICE_PATH_PROTOCOL *CopyOfDevicePath;
+ UINTN Size;
+ BOOLEAN DeviceExist;
+ EFI_HANDLE Handle;
+
+ if ((ConsoleType != ConIn) && (ConsoleType != ConOut) && (ConsoleType != ErrOut)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_SUCCESS;
+ DeviceExist = FALSE;
+ Handle = NULL;
+
+ //
+ // Check if the console variable exist
+ //
+ GetEfiGlobalVariable2 (mConVarName[ConsoleType], (VOID **) &StartDevicePath, NULL);
+ if (StartDevicePath == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ CopyOfDevicePath = StartDevicePath;
+ do {
+ //
+ // Check every instance of the console variable
+ //
+ Instance = GetNextDevicePathInstance (&CopyOfDevicePath, &Size);
+ if (Instance == NULL) {
+ FreePool (StartDevicePath);
+ return EFI_UNSUPPORTED;
+ }
+
+ Next = Instance;
+ while (!IsDevicePathEndType (Next)) {
+ Next = NextDevicePathNode (Next);
+ }
+
+ SetDevicePathEndNode (Next);
+ //
+ // Connect the USB console
+ // USB console device path is a short-form device path that
+ // starts with the first element being a USB WWID
+ // or a USB Class device path
+ //
+ if ((DevicePathType (Instance) == MESSAGING_DEVICE_PATH) &&
+ ((DevicePathSubType (Instance) == MSG_USB_CLASS_DP) || (DevicePathSubType (Instance) == MSG_USB_WWID_DP))
+ ) {
+ Status = BmConnectUsbShortFormDevicePath (Instance);
+ if (!EFI_ERROR (Status)) {
+ DeviceExist = TRUE;
+ }
+ } else {
+ for (Next = Instance; !IsDevicePathEnd (Next); Next = NextDevicePathNode (Next)) {
+ if (DevicePathType (Next) == ACPI_DEVICE_PATH && DevicePathSubType (Next) == ACPI_ADR_DP) {
+ break;
+ } else if (DevicePathType (Next) == HARDWARE_DEVICE_PATH &&
+ DevicePathSubType (Next) == HW_CONTROLLER_DP &&
+ DevicePathType (NextDevicePathNode (Next)) == ACPI_DEVICE_PATH &&
+ DevicePathSubType (NextDevicePathNode (Next)) == ACPI_ADR_DP
+ ) {
+ break;
+ }
+ }
+ if (!IsDevicePathEnd (Next)) {
+ //
+ // For GOP device path, start the video driver with NULL remaining device path
+ //
+ SetDevicePathEndNode (Next);
+ Status = EfiBootManagerConnectDevicePath (Instance, &Handle);
+ if (!EFI_ERROR (Status)) {
+ gBS->ConnectController (Handle, NULL, NULL, TRUE);
+ }
+ } else {
+ Status = EfiBootManagerConnectDevicePath (Instance, NULL);
+ }
+ if (EFI_ERROR (Status)) {
+ //
+ // Delete the instance from the console varialbe
+ //
+ EfiBootManagerUpdateConsoleVariable (ConsoleType, NULL, Instance);
+ } else {
+ DeviceExist = TRUE;
+ }
+ }
+ FreePool(Instance);
+ } while (CopyOfDevicePath != NULL);
+
+ FreePool (StartDevicePath);
+
+ if (!DeviceExist) {
+ return EFI_NOT_FOUND;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function will search every input/output device in current system,
+ and make every input/output device as potential console device.
+**/
+VOID
+EFIAPI
+EfiBootManagerConnectAllConsoles (
+ VOID
+ )
+{
+ UINTN Index;
+ EFI_DEVICE_PATH_PROTOCOL *ConDevicePath;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+
+ Index = 0;
+ HandleCount = 0;
+ HandleBuffer = NULL;
+ ConDevicePath = NULL;
+
+ //
+ // Update all the console variables
+ //
+ gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiSimpleTextInProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+
+ for (Index = 0; Index < HandleCount; Index++) {
+ gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &ConDevicePath
+ );
+ EfiBootManagerUpdateConsoleVariable (ConIn, ConDevicePath, NULL);
+ }
+
+ if (HandleBuffer != NULL) {
+ FreePool(HandleBuffer);
+ HandleBuffer = NULL;
+ }
+
+ gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiSimpleTextOutProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ for (Index = 0; Index < HandleCount; Index++) {
+ gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &ConDevicePath
+ );
+ EfiBootManagerUpdateConsoleVariable (ConOut, ConDevicePath, NULL);
+ EfiBootManagerUpdateConsoleVariable (ErrOut, ConDevicePath, NULL);
+ }
+
+ if (HandleBuffer != NULL) {
+ FreePool(HandleBuffer);
+ }
+
+ //
+ // Connect all console variables
+ //
+ EfiBootManagerConnectAllDefaultConsoles ();
+}
+
+
+/**
+ This function will connect all the console devices base on the console
+ device variable ConIn, ConOut and ErrOut.
+
+ @retval EFI_DEVICE_ERROR All the consoles were not connected due to an error.
+ @retval EFI_SUCCESS Success connect any one instance of the console
+ device path base on the variable ConVarName.
+**/
+EFI_STATUS
+EFIAPI
+EfiBootManagerConnectAllDefaultConsoles (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN OneConnected;
+ BOOLEAN SystemTableUpdated;
+
+ OneConnected = FALSE;
+
+ Status = EfiBootManagerConnectConsoleVariable (ConOut);
+ if (!EFI_ERROR (Status)) {
+ OneConnected = TRUE;
+ }
+ PERF_START (NULL, "ConOutReady", "BDS", 1);
+ PERF_END (NULL, "ConOutReady", "BDS", 0);
+
+
+ Status = EfiBootManagerConnectConsoleVariable (ConIn);
+ if (!EFI_ERROR (Status)) {
+ OneConnected = TRUE;
+ }
+ PERF_START (NULL, "ConInReady", "BDS", 1);
+ PERF_END (NULL, "ConInReady", "BDS", 0);
+
+ Status = EfiBootManagerConnectConsoleVariable (ErrOut);
+ if (!EFI_ERROR (Status)) {
+ OneConnected = TRUE;
+ }
+ PERF_START (NULL, "ErrOutReady", "BDS", 1);
+ PERF_END (NULL, "ErrOutReady", "BDS", 0);
+
+ SystemTableUpdated = FALSE;
+ //
+ // Fill console handles in System Table if no console device assignd.
+ //
+ if (BmUpdateSystemTableConsole (L"ConIn", &gEfiSimpleTextInProtocolGuid, &gST->ConsoleInHandle, (VOID **) &gST->ConIn)) {
+ SystemTableUpdated = TRUE;
+ }
+ if (BmUpdateSystemTableConsole (L"ConOut", &gEfiSimpleTextOutProtocolGuid, &gST->ConsoleOutHandle, (VOID **) &gST->ConOut)) {
+ SystemTableUpdated = TRUE;
+ }
+ if (BmUpdateSystemTableConsole (L"ErrOut", &gEfiSimpleTextOutProtocolGuid, &gST->StandardErrorHandle, (VOID **) &gST->StdErr)) {
+ SystemTableUpdated = TRUE;
+ }
+
+ if (SystemTableUpdated) {
+ //
+ // Update the CRC32 in the EFI System Table header
+ //
+ gST->Hdr.CRC32 = 0;
+ gBS->CalculateCrc32 (
+ (UINT8 *) &gST->Hdr,
+ gST->Hdr.HeaderSize,
+ &gST->Hdr.CRC32
+ );
+ }
+
+ return OneConnected ? EFI_SUCCESS : EFI_DEVICE_ERROR;
+}
diff --git a/Core/MdeModulePkg/Library/UefiBootManagerLib/BmDriverHealth.c b/Core/MdeModulePkg/Library/UefiBootManagerLib/BmDriverHealth.c
new file mode 100644
index 0000000000..bffbedaf84
--- /dev/null
+++ b/Core/MdeModulePkg/Library/UefiBootManagerLib/BmDriverHealth.c
@@ -0,0 +1,576 @@
+/** @file
+ Library functions which relates with driver health.
+
+(C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>
+Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "InternalBm.h"
+
+GLOBAL_REMOVE_IF_UNREFERENCED
+ CHAR16 *mBmHealthStatusText[] = {
+ L"Healthy",
+ L"Repair Required",
+ L"Configuration Required",
+ L"Failed",
+ L"Reconnect Required",
+ L"Reboot Required"
+ };
+
+/**
+ Return the controller name.
+
+ @param DriverHealthHandle The handle on which the Driver Health protocol instance is retrieved.
+ @param ControllerHandle The handle of a controller that the driver specified by DriverBindingHandle is managing.
+ This handle specifies the controller whose name is to be returned.
+ @param ChildHandle The handle of the child controller to retrieve the name of. This is an
+ optional parameter that may be NULL. It will be NULL for device drivers.
+ It will also be NULL for bus drivers that attempt to retrieve the name
+ of the bus controller. It will not be NULL for a bus driver that attempts
+ to retrieve the name of a child controller.
+
+ @return A pointer to the Unicode string to return. This Unicode string is the name of the controller
+ specified by ControllerHandle and ChildHandle.
+**/
+CHAR16 *
+BmGetControllerName (
+ IN EFI_HANDLE DriverHealthHandle,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle
+ )
+{
+ EFI_STATUS Status;
+ CHAR16 *ControllerName;
+ CHAR8 *LanguageVariable;
+ CHAR8 *BestLanguage;
+ BOOLEAN Iso639Language;
+ EFI_COMPONENT_NAME_PROTOCOL *ComponentName;
+
+ ControllerName = NULL;
+
+ //
+ // Locate Component Name (2) protocol on the driver binging handle.
+ //
+ Iso639Language = FALSE;
+ Status = gBS->HandleProtocol (
+ DriverHealthHandle,
+ &gEfiComponentName2ProtocolGuid,
+ (VOID **) &ComponentName
+ );
+ if (EFI_ERROR (Status)) {
+ Status = gBS->HandleProtocol (
+ DriverHealthHandle,
+ &gEfiComponentNameProtocolGuid,
+ (VOID **) &ComponentName
+ );
+ if (!EFI_ERROR (Status)) {
+ Iso639Language = TRUE;
+ }
+ }
+
+ if (!EFI_ERROR (Status)) {
+ GetEfiGlobalVariable2 (Iso639Language ? L"Lang" : L"PlatformLang", (VOID**)&LanguageVariable, NULL);
+ BestLanguage = GetBestLanguage(
+ ComponentName->SupportedLanguages,
+ Iso639Language,
+ (LanguageVariable != NULL) ? LanguageVariable : "",
+ Iso639Language ? "eng" : "en-US",
+ NULL
+ );
+ if (LanguageVariable != NULL) {
+ FreePool (LanguageVariable);
+ }
+
+ Status = ComponentName->GetControllerName (
+ ComponentName,
+ ControllerHandle,
+ ChildHandle,
+ BestLanguage,
+ &ControllerName
+ );
+ }
+
+ if (!EFI_ERROR (Status)) {
+ return AllocateCopyPool (StrSize (ControllerName), ControllerName);
+ } else {
+ return ConvertDevicePathToText (
+ DevicePathFromHandle (ChildHandle != NULL ? ChildHandle : ControllerHandle),
+ FALSE,
+ FALSE
+ );
+ }
+}
+
+/**
+ Display a set of messages returned by the GetHealthStatus () service of the EFI Driver Health Protocol
+
+ @param DriverHealthInfo Pointer to the Driver Health information entry.
+**/
+VOID
+BmDisplayMessages (
+ IN EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO *DriverHealthInfo
+ )
+{
+ UINTN Index;
+ EFI_STRING String;
+ CHAR16 *ControllerName;
+
+ if (DriverHealthInfo->MessageList == NULL ||
+ DriverHealthInfo->MessageList[0].HiiHandle == NULL) {
+ return;
+ }
+
+ ControllerName = BmGetControllerName (
+ DriverHealthInfo->DriverHealthHandle,
+ DriverHealthInfo->ControllerHandle,
+ DriverHealthInfo->ChildHandle
+ );
+
+ DEBUG ((EFI_D_INFO, "Controller: %s\n", ControllerName));
+ Print (L"Controller: %s\n", ControllerName);
+ for (Index = 0; DriverHealthInfo->MessageList[Index].HiiHandle != NULL; Index++) {
+ String = HiiGetString (
+ DriverHealthInfo->MessageList[Index].HiiHandle,
+ DriverHealthInfo->MessageList[Index].StringId,
+ NULL
+ );
+ if (String != NULL) {
+ Print (L" %s\n", String);
+ DEBUG ((EFI_D_INFO, " %s\n", String));
+ FreePool (String);
+ }
+ }
+
+ if (ControllerName != NULL) {
+ FreePool (ControllerName);
+ }
+}
+
+/**
+ The repair notify function.
+ @param Value A value between 0 and Limit that identifies the current progress
+ of the repair operation.
+ @param Limit The maximum value of Value for the current repair operation.
+ If Limit is 0, then the completion progress is indeterminate.
+ For example, a driver that wants to specify progress in percent
+ would use a Limit value of 100.
+
+ @retval EFI_SUCCESS Successfully return from the notify function.
+**/
+EFI_STATUS
+EFIAPI
+BmRepairNotify (
+ IN UINTN Value,
+ IN UINTN Limit
+ )
+{
+ DEBUG ((EFI_D_INFO, "[BDS]RepairNotify: %d/%d\n", Value, Limit));
+ Print (L"[BDS]RepairNotify: %d/%d\n", Value, Limit);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Collect the Driver Health status of a single controller.
+
+ @param DriverHealthInfo A pointer to the array containing all of the platform driver health information.
+ @param Count Return the updated array count.
+ @param DriverHealthHandle The handle on which the Driver Health protocol instance is retrieved.
+ @param ControllerHandle The handle of the controller..
+ @param ChildHandle The handle of the child controller to retrieve the health
+ status on. This is an optional parameter that may be NULL.
+
+ @retval Status The status returned from GetHealthStatus.
+ @retval EFI_ABORTED The health status is healthy so no further query is needed.
+
+**/
+EFI_STATUS
+BmGetSingleControllerHealthStatus (
+ IN OUT EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO **DriverHealthInfo,
+ IN OUT UINTN *Count,
+ IN EFI_HANDLE DriverHealthHandle,
+ IN EFI_HANDLE ControllerHandle, OPTIONAL
+ IN EFI_HANDLE ChildHandle OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_DRIVER_HEALTH_PROTOCOL *DriverHealth;
+ EFI_DRIVER_HEALTH_HII_MESSAGE *MessageList;
+ EFI_HII_HANDLE FormHiiHandle;
+ EFI_DRIVER_HEALTH_STATUS HealthStatus;
+
+ ASSERT (DriverHealthHandle != NULL);
+ //
+ // Retrieve the Driver Health Protocol from DriverHandle
+ //
+ Status = gBS->HandleProtocol (
+ DriverHealthHandle,
+ &gEfiDriverHealthProtocolGuid,
+ (VOID **) &DriverHealth
+ );
+ ASSERT_EFI_ERROR (Status);
+
+
+ if (ControllerHandle == NULL) {
+ //
+ // If ControllerHandle is NULL, the return the cumulative health status of the driver
+ //
+ Status = DriverHealth->GetHealthStatus (DriverHealth, NULL, NULL, &HealthStatus, NULL, NULL);
+ if (!EFI_ERROR (Status) && HealthStatus == EfiDriverHealthStatusHealthy) {
+ *DriverHealthInfo = ReallocatePool (
+ (*Count) * sizeof (EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO),
+ (*Count + 1) * sizeof (EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO),
+ *DriverHealthInfo
+ );
+ ASSERT (*DriverHealthInfo != NULL);
+
+ (*DriverHealthInfo)[*Count].DriverHealthHandle = DriverHealthHandle;
+ (*DriverHealthInfo)[*Count].DriverHealth = DriverHealth;
+ (*DriverHealthInfo)[*Count].HealthStatus = HealthStatus;
+
+ *Count = *Count + 1;
+
+ Status = EFI_ABORTED;
+ }
+ return Status;
+ }
+
+ MessageList = NULL;
+ FormHiiHandle = NULL;
+
+ //
+ // Collect the health status with the optional HII message list
+ //
+ Status = DriverHealth->GetHealthStatus (DriverHealth, ControllerHandle, ChildHandle, &HealthStatus, &MessageList, &FormHiiHandle);
+ if (!EFI_ERROR (Status)) {
+ *DriverHealthInfo = ReallocatePool (
+ (*Count) * sizeof (EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO),
+ (*Count + 1) * sizeof (EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO),
+ *DriverHealthInfo
+ );
+ ASSERT (*DriverHealthInfo != NULL);
+ (*DriverHealthInfo)[*Count].DriverHealth = DriverHealth;
+ (*DriverHealthInfo)[*Count].DriverHealthHandle = DriverHealthHandle;
+ (*DriverHealthInfo)[*Count].ControllerHandle = ControllerHandle;
+ (*DriverHealthInfo)[*Count].ChildHandle = ChildHandle;
+ (*DriverHealthInfo)[*Count].HiiHandle = FormHiiHandle;
+ (*DriverHealthInfo)[*Count].MessageList = MessageList;
+ (*DriverHealthInfo)[*Count].HealthStatus = HealthStatus;
+
+ *Count = *Count + 1;
+ }
+
+ return Status;
+}
+
+/**
+ Return all the Driver Health information.
+
+ When the cumulative health status of all the controllers managed by the
+ driver who produces the EFI_DRIVER_HEALTH_PROTOCOL is healthy, only one
+ EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO entry is created for such
+ EFI_DRIVER_HEALTH_PROTOCOL instance.
+ Otherwise, every controller creates one EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO
+ entry. Additionally every child controller creates one
+ EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO entry if the driver is a bus driver.
+
+ @param Count Return the count of the Driver Health information.
+
+ @retval NULL No Driver Health information is returned.
+ @retval !NULL Pointer to the Driver Health information array.
+**/
+EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO *
+EFIAPI
+EfiBootManagerGetDriverHealthInfo (
+ UINTN *Count
+ )
+{
+ EFI_STATUS Status;
+ UINTN NumHandles;
+ EFI_HANDLE *DriverHealthHandles;
+ UINTN DriverHealthIndex;
+ EFI_HANDLE *Handles;
+ UINTN HandleCount;
+ UINTN ControllerIndex;
+ UINTN ChildIndex;
+ EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO *DriverHealthInfo;
+
+ //
+ // Initialize local variables
+ //
+ *Count = 0;
+ DriverHealthInfo = NULL;
+ Handles = NULL;
+ DriverHealthHandles = NULL;
+ NumHandles = 0;
+ HandleCount = 0;
+
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiDriverHealthProtocolGuid,
+ NULL,
+ &NumHandles,
+ &DriverHealthHandles
+ );
+
+ if (Status == EFI_NOT_FOUND || NumHandles == 0) {
+ //
+ // If there are no Driver Health Protocols handles, then return EFI_NOT_FOUND
+ //
+ return NULL;
+ }
+
+ ASSERT_EFI_ERROR (Status);
+ ASSERT (DriverHealthHandles != NULL);
+
+ //
+ // Check the health status of all controllers in the platform
+ // Start by looping through all the Driver Health Protocol handles in the handle database
+ //
+ for (DriverHealthIndex = 0; DriverHealthIndex < NumHandles; DriverHealthIndex++) {
+ //
+ // Get the cumulative health status of the driver
+ //
+ Status = BmGetSingleControllerHealthStatus (&DriverHealthInfo, Count, DriverHealthHandles[DriverHealthIndex], NULL, NULL);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ //
+ // See if the list of all handles in the handle database has been retrieved
+ //
+ //
+ if (Handles == NULL) {
+ //
+ // Retrieve the list of all handles from the handle database
+ //
+ Status = gBS->LocateHandleBuffer (
+ AllHandles,
+ NULL,
+ NULL,
+ &HandleCount,
+ &Handles
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+ //
+ // Loop through all the controller handles in the handle database
+ //
+ for (ControllerIndex = 0; ControllerIndex < HandleCount; ControllerIndex++) {
+ Status = BmGetSingleControllerHealthStatus (&DriverHealthInfo, Count, DriverHealthHandles[DriverHealthIndex], Handles[ControllerIndex], NULL);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ //
+ // Loop through all the child handles in the handle database
+ //
+ for (ChildIndex = 0; ChildIndex < HandleCount; ChildIndex++) {
+ Status = BmGetSingleControllerHealthStatus (&DriverHealthInfo, Count, DriverHealthHandles[DriverHealthIndex], Handles[ControllerIndex], Handles[ChildIndex]);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+ }
+ }
+ }
+
+ Status = EFI_SUCCESS;
+
+ if (Handles != NULL) {
+ FreePool (Handles);
+ }
+ if (DriverHealthHandles != NULL) {
+ FreePool (DriverHealthHandles);
+ }
+
+ return DriverHealthInfo;
+}
+
+/**
+ Free the Driver Health information array.
+
+ @param DriverHealthInfo Pointer to array of the Driver Health information.
+ @param Count Count of the array.
+
+ @retval EFI_SUCCESS The array is freed.
+ @retval EFI_INVALID_PARAMETER The array is NULL.
+**/
+EFI_STATUS
+EFIAPI
+EfiBootManagerFreeDriverHealthInfo (
+ EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO *DriverHealthInfo,
+ UINTN Count
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index < Count; Index++) {
+ if (DriverHealthInfo[Index].MessageList != NULL) {
+ FreePool (DriverHealthInfo[Index].MessageList);
+ }
+ }
+ return gBS->FreePool (DriverHealthInfo);
+}
+
+/**
+ Repair all the controllers according to the Driver Health status queried.
+**/
+VOID
+BmRepairAllControllers (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO *DriverHealthInfo;
+ EFI_DRIVER_HEALTH_STATUS HealthStatus;
+ UINTN Count;
+ UINTN Index;
+ BOOLEAN RepairRequired;
+ BOOLEAN ConfigurationRequired;
+ BOOLEAN ReconnectRequired;
+ BOOLEAN RebootRequired;
+ EFI_HII_HANDLE *HiiHandles;
+ EFI_FORM_BROWSER2_PROTOCOL *FormBrowser2;
+
+ //
+ // Configure PcdDriverHealthConfigureForm to ZeroGuid to disable driver health check.
+ //
+ if (CompareGuid (PcdGetPtr (PcdDriverHealthConfigureForm), &gZeroGuid)) {
+ return;
+ }
+
+ Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **) &FormBrowser2);
+ ASSERT_EFI_ERROR (Status);
+
+ do {
+ RepairRequired = FALSE;
+ ConfigurationRequired = FALSE;
+
+ //
+ // Deal with Repair Required
+ //
+ DriverHealthInfo = EfiBootManagerGetDriverHealthInfo (&Count);
+ for (Index = 0; Index < Count; Index++) {
+ if (DriverHealthInfo[Index].HealthStatus == EfiDriverHealthStatusConfigurationRequired) {
+ ConfigurationRequired = TRUE;
+ }
+
+ if (DriverHealthInfo[Index].HealthStatus == EfiDriverHealthStatusRepairRequired) {
+ RepairRequired = TRUE;
+
+ BmDisplayMessages (&DriverHealthInfo[Index]);
+
+ Status = DriverHealthInfo[Index].DriverHealth->Repair (
+ DriverHealthInfo[Index].DriverHealth,
+ DriverHealthInfo[Index].ControllerHandle,
+ DriverHealthInfo[Index].ChildHandle,
+ BmRepairNotify
+ );
+ if (!EFI_ERROR (Status) && !ConfigurationRequired) {
+ Status = DriverHealthInfo[Index].DriverHealth->GetHealthStatus (
+ DriverHealthInfo[Index].DriverHealth,
+ DriverHealthInfo[Index].ControllerHandle,
+ DriverHealthInfo[Index].ChildHandle,
+ &HealthStatus,
+ NULL,
+ NULL
+ );
+ if (!EFI_ERROR (Status) && (HealthStatus == EfiDriverHealthStatusConfigurationRequired)) {
+ ConfigurationRequired = TRUE;
+ }
+ }
+ }
+ }
+
+ if (ConfigurationRequired) {
+ HiiHandles = HiiGetHiiHandles (NULL);
+ if (HiiHandles != NULL) {
+ for (Index = 0; HiiHandles[Index] != NULL; Index++) {
+ Status = FormBrowser2->SendForm (
+ FormBrowser2,
+ &HiiHandles[Index],
+ 1,
+ PcdGetPtr (PcdDriverHealthConfigureForm),
+ 0,
+ NULL,
+ NULL
+ );
+ if (!EFI_ERROR (Status)) {
+ break;
+ }
+ }
+ FreePool (HiiHandles);
+ }
+ }
+
+ EfiBootManagerFreeDriverHealthInfo (DriverHealthInfo, Count);
+ } while (RepairRequired || ConfigurationRequired);
+
+ RebootRequired = FALSE;
+ ReconnectRequired = FALSE;
+ DriverHealthInfo = EfiBootManagerGetDriverHealthInfo (&Count);
+ for (Index = 0; Index < Count; Index++) {
+
+ BmDisplayMessages (&DriverHealthInfo[Index]);
+
+ if (DriverHealthInfo[Index].HealthStatus == EfiDriverHealthStatusReconnectRequired) {
+ Status = gBS->DisconnectController (DriverHealthInfo[Index].ControllerHandle, NULL, NULL);
+ if (EFI_ERROR (Status)) {
+ //
+ // Disconnect failed. Need to promote reconnect to a reboot.
+ //
+ RebootRequired = TRUE;
+ } else {
+ gBS->ConnectController (DriverHealthInfo[Index].ControllerHandle, NULL, NULL, TRUE);
+ ReconnectRequired = TRUE;
+ }
+ }
+
+ if (DriverHealthInfo[Index].HealthStatus == EfiDriverHealthStatusRebootRequired) {
+ RebootRequired = TRUE;
+ }
+ }
+ EfiBootManagerFreeDriverHealthInfo (DriverHealthInfo, Count);
+
+
+ if (ReconnectRequired) {
+ BmRepairAllControllers ();
+ }
+
+ DEBUG_CODE (
+ CHAR16 *ControllerName;
+
+ DriverHealthInfo = EfiBootManagerGetDriverHealthInfo (&Count);
+ for (Index = 0; Index < Count; Index++) {
+ ControllerName = BmGetControllerName (
+ DriverHealthInfo[Index].DriverHealthHandle,
+ DriverHealthInfo[Index].ControllerHandle,
+ DriverHealthInfo[Index].ChildHandle
+ );
+ DEBUG ((
+ EFI_D_INFO,
+ "%02d: %s - %s\n",
+ Index,
+ ControllerName,
+ mBmHealthStatusText[DriverHealthInfo[Index].HealthStatus]
+ ));
+ if (ControllerName != NULL) {
+ FreePool (ControllerName);
+ }
+ }
+ EfiBootManagerFreeDriverHealthInfo (DriverHealthInfo, Count);
+ );
+
+ if (RebootRequired) {
+ DEBUG ((EFI_D_INFO, "[BDS] One of the Driver Health instances requires rebooting.\n"));
+ gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL);
+ }
+}
diff --git a/Core/MdeModulePkg/Library/UefiBootManagerLib/BmHotkey.c b/Core/MdeModulePkg/Library/UefiBootManagerLib/BmHotkey.c
new file mode 100644
index 0000000000..8d398fb4c6
--- /dev/null
+++ b/Core/MdeModulePkg/Library/UefiBootManagerLib/BmHotkey.c
@@ -0,0 +1,1101 @@
+/** @file
+ Hotkey library functions.
+
+Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "InternalBm.h"
+
+//
+// Lock for linked list
+//
+EFI_LOCK mBmHotkeyLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_NOTIFY);
+LIST_ENTRY mBmHotkeyList = INITIALIZE_LIST_HEAD_VARIABLE (mBmHotkeyList);
+EFI_EVENT mBmHotkeyTriggered = NULL;
+BOOLEAN mBmHotkeyServiceStarted = FALSE;
+UINTN mBmHotkeySupportCount = 0;
+
+//
+// Set OptionNumber as unassigned value to indicate the option isn't initialized
+//
+EFI_BOOT_MANAGER_LOAD_OPTION mBmHotkeyBootOption = { LoadOptionNumberUnassigned };
+
+EFI_BOOT_MANAGER_KEY_OPTION *mBmContinueKeyOption = NULL;
+VOID *mBmTxtInExRegistration = NULL;
+
+/**
+
+ Check whether the input key option is valid.
+
+ @param KeyOption Input key option info.
+
+ @retval TRUE Input key option is valid.
+ @retval FALSE Input key option is not valid.
+**/
+BOOLEAN
+BmIsKeyOptionValid (
+ IN EFI_BOOT_MANAGER_KEY_OPTION *KeyOption
+)
+{
+ UINT16 OptionName[sizeof (L"Boot####")];
+ UINT8 *BootOption;
+ UINTN BootOptionSize;
+ UINT32 Crc;
+
+ //
+ // Check whether corresponding Boot Option exist
+ //
+ UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", KeyOption->BootOption);
+ GetEfiGlobalVariable2 (OptionName, (VOID **) &BootOption, &BootOptionSize);
+
+ if (BootOption == NULL) {
+ return FALSE;
+ }
+
+ //
+ // Check CRC for Boot Option
+ //
+ gBS->CalculateCrc32 (BootOption, BootOptionSize, &Crc);
+ FreePool (BootOption);
+
+ return (BOOLEAN) (KeyOption->BootOptionCrc == Crc);
+}
+
+/**
+
+ Check whether the input variable is an key option variable.
+
+ @param Name Input variable name.
+ @param Guid Input variable guid.
+ @param OptionNumber The option number of this key option variable.
+
+ @retval TRUE Input variable is a key option variable.
+ @retval FALSE Input variable is not a key option variable.
+**/
+BOOLEAN
+BmIsKeyOptionVariable (
+ CHAR16 *Name,
+ EFI_GUID *Guid,
+ UINT16 *OptionNumber
+ )
+{
+ UINTN Index;
+
+ if (!CompareGuid (Guid, &gEfiGlobalVariableGuid) ||
+ (StrSize (Name) != sizeof (L"Key####")) ||
+ (StrnCmp (Name, L"Key", 3) != 0)
+ ) {
+ return FALSE;
+ }
+
+ *OptionNumber = 0;
+ for (Index = 3; Index < 7; Index++) {
+ if ((Name[Index] >= L'0') && (Name[Index] <= L'9')) {
+ *OptionNumber = *OptionNumber * 16 + Name[Index] - L'0';
+ } else if ((Name[Index] >= L'A') && (Name[Index] <= L'F')) {
+ *OptionNumber = *OptionNumber * 16 + Name[Index] - L'A' + 10;
+ } else {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+/**
+ Return the buffer size of the EFI_BOOT_MANAGER_KEY_OPTION data.
+
+ @param KeyOption The input key option info.
+
+ @retval The buffer size of the key option data.
+**/
+UINTN
+BmSizeOfKeyOption (
+ EFI_BOOT_MANAGER_KEY_OPTION *KeyOption
+ )
+{
+ return OFFSET_OF (EFI_BOOT_MANAGER_KEY_OPTION, Keys)
+ + KeyOption->KeyData.Options.InputKeyCount * sizeof (EFI_INPUT_KEY);
+}
+
+/**
+ Return the array of key options.
+
+ @param Count Return the number of key options.
+
+ @retval NULL No key option.
+ @retval Other Pointer to the key options.
+**/
+EFI_BOOT_MANAGER_KEY_OPTION *
+BmGetKeyOptions (
+ OUT UINTN *Count
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ CHAR16 *Name;
+ EFI_GUID Guid;
+ UINTN NameSize;
+ UINTN NewNameSize;
+ EFI_BOOT_MANAGER_KEY_OPTION *KeyOptions;
+ EFI_BOOT_MANAGER_KEY_OPTION *KeyOption;
+ UINT16 OptionNumber;
+
+ if (Count == NULL) {
+ return NULL;
+ }
+
+ *Count = 0;
+ KeyOptions = NULL;
+
+ NameSize = sizeof (CHAR16);
+ Name = AllocateZeroPool (NameSize);
+ ASSERT (Name != NULL);
+ while (TRUE) {
+ NewNameSize = NameSize;
+ Status = gRT->GetNextVariableName (&NewNameSize, Name, &Guid);
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ Name = ReallocatePool (NameSize, NewNameSize, Name);
+ ASSERT (Name != NULL);
+ Status = gRT->GetNextVariableName (&NewNameSize, Name, &Guid);
+ NameSize = NewNameSize;
+ }
+
+ if (Status == EFI_NOT_FOUND) {
+ break;
+ }
+ ASSERT_EFI_ERROR (Status);
+
+ if (BmIsKeyOptionVariable (Name ,&Guid, &OptionNumber)) {
+ GetEfiGlobalVariable2 (Name, (VOID**) &KeyOption, NULL);
+ ASSERT (KeyOption != NULL);
+ if (BmIsKeyOptionValid (KeyOption)) {
+ KeyOptions = ReallocatePool (
+ *Count * sizeof (EFI_BOOT_MANAGER_KEY_OPTION),
+ (*Count + 1) * sizeof (EFI_BOOT_MANAGER_KEY_OPTION),
+ KeyOptions
+ );
+ ASSERT (KeyOptions != NULL);
+ //
+ // Insert the key option in order
+ //
+ for (Index = 0; Index < *Count; Index++) {
+ if (OptionNumber < KeyOptions[Index].OptionNumber) {
+ break;
+ }
+ }
+ CopyMem (&KeyOptions[Index + 1], &KeyOptions[Index], (*Count - Index) * sizeof (EFI_BOOT_MANAGER_KEY_OPTION));
+ CopyMem (&KeyOptions[Index], KeyOption, BmSizeOfKeyOption (KeyOption));
+ KeyOptions[Index].OptionNumber = OptionNumber;
+ (*Count)++;
+ }
+ FreePool (KeyOption);
+ }
+ }
+
+ FreePool (Name);
+
+ return KeyOptions;
+}
+
+/**
+ Callback function for event.
+
+ @param Event Event for this callback function.
+ @param Context Context pass to this function.
+**/
+VOID
+EFIAPI
+BmEmptyFunction (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+}
+
+/**
+ Check whether the bit is set in the value.
+
+ @param Value The value need to be check.
+ @param Bit The bit filed need to be check.
+
+ @retval TRUE The bit is set.
+ @retval FALSE The bit is not set.
+**/
+BOOLEAN
+BmBitSet (
+ IN UINT32 Value,
+ IN UINT32 Bit
+ )
+{
+ return (BOOLEAN) ((Value & Bit) != 0);
+}
+
+/**
+ Initialize the KeyData and Key[] in the EFI_BOOT_MANAGER_KEY_OPTION.
+
+ @param Modifier Input key info.
+ @param Args Va_list info.
+ @param KeyOption Key info which need to update.
+
+ @retval EFI_SUCCESS Succeed to initialize the KeyData and Key[].
+ @return EFI_INVALID_PARAMETER Input parameter error.
+**/
+EFI_STATUS
+BmInitializeKeyFields (
+ IN UINT32 Modifier,
+ IN VA_LIST Args,
+ OUT EFI_BOOT_MANAGER_KEY_OPTION *KeyOption
+ )
+{
+ EFI_INPUT_KEY *Key;
+
+ if (KeyOption == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Key = NULL;
+ while (KeyOption->KeyData.Options.InputKeyCount < sizeof (KeyOption->Keys) / sizeof (KeyOption->Keys[0])) {
+ Key = VA_ARG (Args, EFI_INPUT_KEY *);
+ if (Key == NULL) {
+ break;
+ }
+ CopyMem (
+ &KeyOption->Keys[KeyOption->KeyData.Options.InputKeyCount],
+ Key,
+ sizeof (EFI_INPUT_KEY)
+ );
+ KeyOption->KeyData.Options.InputKeyCount++;
+ }
+
+ if (Key != NULL) {
+ //
+ // Too many keys
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Modifier & ~(EFI_BOOT_MANAGER_SHIFT_PRESSED
+ | EFI_BOOT_MANAGER_CONTROL_PRESSED
+ | EFI_BOOT_MANAGER_ALT_PRESSED
+ | EFI_BOOT_MANAGER_LOGO_PRESSED
+ | EFI_BOOT_MANAGER_MENU_KEY_PRESSED
+ | EFI_BOOT_MANAGER_SYS_REQ_PRESSED
+ )) != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BmBitSet (Modifier, EFI_BOOT_MANAGER_SHIFT_PRESSED)) {
+ KeyOption->KeyData.Options.ShiftPressed = 1;
+ }
+ if (BmBitSet (Modifier, EFI_BOOT_MANAGER_CONTROL_PRESSED)) {
+ KeyOption->KeyData.Options.ControlPressed = 1;
+ }
+ if (BmBitSet (Modifier, EFI_BOOT_MANAGER_ALT_PRESSED)) {
+ KeyOption->KeyData.Options.AltPressed = 1;
+ }
+ if (BmBitSet (Modifier, EFI_BOOT_MANAGER_LOGO_PRESSED)) {
+ KeyOption->KeyData.Options.LogoPressed = 1;
+ }
+ if (BmBitSet (Modifier, EFI_BOOT_MANAGER_MENU_KEY_PRESSED)) {
+ KeyOption->KeyData.Options.MenuPressed = 1;
+ }
+ if (BmBitSet (Modifier, EFI_BOOT_MANAGER_SYS_REQ_PRESSED)) {
+ KeyOption->KeyData.Options.SysReqPressed = 1;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Try to boot the boot option triggered by hot key.
+**/
+VOID
+EFIAPI
+EfiBootManagerHotkeyBoot (
+ VOID
+ )
+{
+ if (mBmHotkeyBootOption.OptionNumber != LoadOptionNumberUnassigned) {
+ EfiBootManagerBoot (&mBmHotkeyBootOption);
+ EfiBootManagerFreeLoadOption (&mBmHotkeyBootOption);
+ mBmHotkeyBootOption.OptionNumber = LoadOptionNumberUnassigned;
+ }
+}
+
+/**
+ This is the common notification function for HotKeys, it will be registered
+ with SimpleTextInEx protocol interface - RegisterKeyNotify() of ConIn handle.
+
+ @param KeyData A pointer to a buffer that is filled in with the keystroke
+ information for the key that was pressed.
+
+ @retval EFI_SUCCESS KeyData is successfully processed.
+ @return EFI_NOT_FOUND Fail to find boot option variable.
+**/
+EFI_STATUS
+EFIAPI
+BmHotkeyCallback (
+ IN EFI_KEY_DATA *KeyData
+)
+{
+ LIST_ENTRY *Link;
+ BM_HOTKEY *Hotkey;
+ CHAR16 OptionName[sizeof ("Boot####")];
+ EFI_STATUS Status;
+ EFI_KEY_DATA *HotkeyData;
+
+ if (mBmHotkeyBootOption.OptionNumber != LoadOptionNumberUnassigned) {
+ //
+ // Do not process sequential hotkey stroke until the current boot option returns
+ //
+ return EFI_SUCCESS;
+ }
+
+ DEBUG ((EFI_D_INFO, "[Bds]BmHotkeyCallback: %04x:%04x\n", KeyData->Key.ScanCode, KeyData->Key.UnicodeChar));
+
+ EfiAcquireLock (&mBmHotkeyLock);
+ for ( Link = GetFirstNode (&mBmHotkeyList)
+ ; !IsNull (&mBmHotkeyList, Link)
+ ; Link = GetNextNode (&mBmHotkeyList, Link)
+ ) {
+ Hotkey = BM_HOTKEY_FROM_LINK (Link);
+
+ //
+ // Is this Key Stroke we are waiting for?
+ //
+ ASSERT (Hotkey->WaitingKey < (sizeof (Hotkey->KeyData) / sizeof (Hotkey->KeyData[0])));
+ HotkeyData = &Hotkey->KeyData[Hotkey->WaitingKey];
+ if ((KeyData->Key.ScanCode == HotkeyData->Key.ScanCode) &&
+ (KeyData->Key.UnicodeChar == HotkeyData->Key.UnicodeChar) &&
+ (((KeyData->KeyState.KeyShiftState & EFI_SHIFT_STATE_VALID) != 0) ?
+ (KeyData->KeyState.KeyShiftState == HotkeyData->KeyState.KeyShiftState) : TRUE
+ )
+ ) {
+
+ //
+ // Receive an expecting key stroke, transit to next waiting state
+ //
+ Hotkey->WaitingKey++;
+
+ if (Hotkey->WaitingKey == Hotkey->CodeCount) {
+ //
+ // Reset to initial waiting state
+ //
+ Hotkey->WaitingKey = 0;
+ //
+ // Received the whole key stroke sequence
+ //
+ Status = gBS->SignalEvent (mBmHotkeyTriggered);
+ ASSERT_EFI_ERROR (Status);
+
+ if (!Hotkey->IsContinue) {
+ //
+ // Launch its BootOption
+ //
+ UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", Hotkey->BootOption);
+ Status = EfiBootManagerVariableToLoadOption (OptionName, &mBmHotkeyBootOption);
+ DEBUG ((EFI_D_INFO, "[Bds]Hotkey for %s pressed - %r\n", OptionName, Status));
+ if (EFI_ERROR (Status)) {
+ mBmHotkeyBootOption.OptionNumber = LoadOptionNumberUnassigned;
+ }
+ } else {
+ DEBUG ((EFI_D_INFO, "[Bds]Continue key pressed!\n"));
+ }
+ }
+ } else {
+ //
+ // Receive an unexpected key stroke, reset to initial waiting state
+ //
+ Hotkey->WaitingKey = 0;
+ }
+
+ }
+ EfiReleaseLock (&mBmHotkeyLock);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Unregister hotkey notify list.
+
+ @param Hotkey Hotkey list.
+
+ @retval EFI_SUCCESS Unregister hotkey notify success.
+ @retval Others Unregister hotkey notify failed.
+**/
+EFI_STATUS
+BmUnregisterHotkeyNotify (
+ IN BM_HOTKEY *Hotkey
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ UINTN KeyIndex;
+ EFI_HANDLE *Handles;
+ UINTN HandleCount;
+ EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *TxtInEx;
+ VOID *NotifyHandle;
+
+ gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiSimpleTextInputExProtocolGuid,
+ NULL,
+ &HandleCount,
+ &Handles
+ );
+ for (Index = 0; Index < HandleCount; Index++) {
+ Status = gBS->HandleProtocol (Handles[Index], &gEfiSimpleTextInputExProtocolGuid, (VOID **) &TxtInEx);
+ ASSERT_EFI_ERROR (Status);
+ for (KeyIndex = 0; KeyIndex < Hotkey->CodeCount; KeyIndex++) {
+ Status = TxtInEx->RegisterKeyNotify (
+ TxtInEx,
+ &Hotkey->KeyData[KeyIndex],
+ BmHotkeyCallback,
+ &NotifyHandle
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = TxtInEx->UnregisterKeyNotify (TxtInEx, NotifyHandle);
+ DEBUG ((EFI_D_INFO, "[Bds]UnregisterKeyNotify: %04x/%04x %r\n", Hotkey->KeyData[KeyIndex].Key.ScanCode, Hotkey->KeyData[KeyIndex].Key.UnicodeChar, Status));
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Register hotkey notify list.
+
+ @param TxtInEx Pointer to EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL protocol.
+ @param Hotkey Hotkey list.
+
+ @retval EFI_SUCCESS Register hotkey notify success.
+ @retval Others Register hotkey notify failed.
+**/
+EFI_STATUS
+BmRegisterHotkeyNotify (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *TxtInEx,
+ IN BM_HOTKEY *Hotkey
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ VOID *NotifyHandle;
+
+ for (Index = 0; Index < Hotkey->CodeCount; Index++) {
+ Status = TxtInEx->RegisterKeyNotify (
+ TxtInEx,
+ &Hotkey->KeyData[Index],
+ BmHotkeyCallback,
+ &NotifyHandle
+ );
+ DEBUG ((
+ EFI_D_INFO,
+ "[Bds]RegisterKeyNotify: %04x/%04x %08x/%02x %r\n",
+ Hotkey->KeyData[Index].Key.ScanCode,
+ Hotkey->KeyData[Index].Key.UnicodeChar,
+ Hotkey->KeyData[Index].KeyState.KeyShiftState,
+ Hotkey->KeyData[Index].KeyState.KeyToggleState,
+ Status
+ ));
+ if (EFI_ERROR (Status)) {
+ //
+ // some of the hotkey registry failed
+ // do not unregister all in case we have both CTRL-ALT-P and CTRL-ALT-P-R
+ //
+ break;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Generate key shift state base on the input key option info.
+
+ @param Depth Which key is checked.
+ @param KeyOption Input key option info.
+ @param KeyShiftState Input key shift state.
+ @param KeyShiftStates Return possible key shift state array.
+ @param KeyShiftStateCount Possible key shift state count.
+**/
+VOID
+BmGenerateKeyShiftState (
+ IN UINTN Depth,
+ IN EFI_BOOT_MANAGER_KEY_OPTION *KeyOption,
+ IN UINT32 KeyShiftState,
+ IN UINT32 *KeyShiftStates,
+ IN UINTN *KeyShiftStateCount
+ )
+{
+ switch (Depth) {
+ case 0:
+ if (KeyOption->KeyData.Options.ShiftPressed) {
+ BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState | EFI_RIGHT_SHIFT_PRESSED, KeyShiftStates, KeyShiftStateCount);
+ BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState | EFI_LEFT_SHIFT_PRESSED, KeyShiftStates, KeyShiftStateCount);
+ } else {
+ BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState, KeyShiftStates, KeyShiftStateCount);
+ }
+ break;
+
+ case 1:
+ if (KeyOption->KeyData.Options.ControlPressed) {
+ BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState | EFI_RIGHT_CONTROL_PRESSED, KeyShiftStates, KeyShiftStateCount);
+ BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState | EFI_LEFT_CONTROL_PRESSED, KeyShiftStates, KeyShiftStateCount);
+ } else {
+ BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState, KeyShiftStates, KeyShiftStateCount);
+ }
+ break;
+
+ case 2:
+ if (KeyOption->KeyData.Options.AltPressed) {
+ BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState | EFI_RIGHT_ALT_PRESSED, KeyShiftStates, KeyShiftStateCount);
+ BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState | EFI_LEFT_ALT_PRESSED, KeyShiftStates, KeyShiftStateCount);
+ } else {
+ BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState, KeyShiftStates, KeyShiftStateCount);
+ }
+ break;
+ case 3:
+ if (KeyOption->KeyData.Options.LogoPressed) {
+ BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState | EFI_RIGHT_LOGO_PRESSED, KeyShiftStates, KeyShiftStateCount);
+ BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState | EFI_LEFT_LOGO_PRESSED, KeyShiftStates, KeyShiftStateCount);
+ } else {
+ BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState, KeyShiftStates, KeyShiftStateCount);
+ }
+ break;
+ case 4:
+ if (KeyOption->KeyData.Options.MenuPressed) {
+ KeyShiftState |= EFI_MENU_KEY_PRESSED;
+ }
+ if (KeyOption->KeyData.Options.SysReqPressed) {
+ KeyShiftState |= EFI_SYS_REQ_PRESSED;
+ }
+ KeyShiftStates[*KeyShiftStateCount] = KeyShiftState;
+ (*KeyShiftStateCount)++;
+ break;
+ }
+}
+
+/**
+ Add it to hot key database, register it to existing TxtInEx.
+ New TxtInEx will be automatically registered with all the hot key in dababase
+
+ @param KeyOption Input key option info.
+**/
+EFI_STATUS
+BmProcessKeyOption (
+ IN EFI_BOOT_MANAGER_KEY_OPTION *KeyOption
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *TxtInEx;
+ EFI_HANDLE *Handles;
+ UINTN HandleCount;
+ UINTN HandleIndex;
+ UINTN Index;
+ BM_HOTKEY *Hotkey;
+ UINTN KeyIndex;
+ //
+ // 16 is enough to enumerate all the possible combination of LEFT_XXX and RIGHT_XXX
+ //
+ UINT32 KeyShiftStates[16];
+ UINTN KeyShiftStateCount;
+
+ if (KeyOption->KeyData.Options.InputKeyCount > mBmHotkeySupportCount) {
+ return EFI_UNSUPPORTED;
+ }
+
+ KeyShiftStateCount = 0;
+ BmGenerateKeyShiftState (0, KeyOption, EFI_SHIFT_STATE_VALID, KeyShiftStates, &KeyShiftStateCount);
+ ASSERT (KeyShiftStateCount <= sizeof (KeyShiftStates) / sizeof (KeyShiftStates[0]));
+
+ EfiAcquireLock (&mBmHotkeyLock);
+
+ for (Index = 0; Index < KeyShiftStateCount; Index++) {
+ Hotkey = AllocateZeroPool (sizeof (BM_HOTKEY));
+ ASSERT (Hotkey != NULL);
+
+ Hotkey->Signature = BM_HOTKEY_SIGNATURE;
+ Hotkey->BootOption = KeyOption->BootOption;
+ Hotkey->IsContinue = (BOOLEAN) (KeyOption == mBmContinueKeyOption);
+ Hotkey->CodeCount = (UINT8) KeyOption->KeyData.Options.InputKeyCount;
+
+ for (KeyIndex = 0; KeyIndex < Hotkey->CodeCount; KeyIndex++) {
+ CopyMem (&Hotkey->KeyData[KeyIndex].Key, &KeyOption->Keys[KeyIndex], sizeof (EFI_INPUT_KEY));
+ Hotkey->KeyData[KeyIndex].KeyState.KeyShiftState = KeyShiftStates[Index];
+ }
+ InsertTailList (&mBmHotkeyList, &Hotkey->Link);
+
+ gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiSimpleTextInputExProtocolGuid,
+ NULL,
+ &HandleCount,
+ &Handles
+ );
+ for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) {
+ Status = gBS->HandleProtocol (Handles[HandleIndex], &gEfiSimpleTextInputExProtocolGuid, (VOID **) &TxtInEx);
+ ASSERT_EFI_ERROR (Status);
+ BmRegisterHotkeyNotify (TxtInEx, Hotkey);
+ }
+ }
+
+ EfiReleaseLock (&mBmHotkeyLock);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Callback function for SimpleTextInEx protocol install events
+
+ @param Event the event that is signaled.
+ @param Context not used here.
+
+**/
+VOID
+EFIAPI
+BmTxtInExCallback (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ UINTN BufferSize;
+ EFI_HANDLE Handle;
+ EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *TxtInEx;
+ LIST_ENTRY *Link;
+
+ while (TRUE) {
+ BufferSize = sizeof (EFI_HANDLE);
+ Status = gBS->LocateHandle (
+ ByRegisterNotify,
+ NULL,
+ mBmTxtInExRegistration,
+ &BufferSize,
+ &Handle
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // If no more notification events exist
+ //
+ return ;
+ }
+
+ Status = gBS->HandleProtocol (
+ Handle,
+ &gEfiSimpleTextInputExProtocolGuid,
+ (VOID **) &TxtInEx
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Register the hot key notification for the existing items in the list
+ //
+ EfiAcquireLock (&mBmHotkeyLock);
+ for (Link = GetFirstNode (&mBmHotkeyList); !IsNull (&mBmHotkeyList, Link); Link = GetNextNode (&mBmHotkeyList, Link)) {
+ BmRegisterHotkeyNotify (TxtInEx, BM_HOTKEY_FROM_LINK (Link));
+ }
+ EfiReleaseLock (&mBmHotkeyLock);
+ }
+}
+
+/**
+ Free the key options returned from BmGetKeyOptions.
+
+ @param KeyOptions Pointer to the key options.
+ @param KeyOptionCount Number of the key options.
+
+ @retval EFI_SUCCESS The key options are freed.
+ @retval EFI_NOT_FOUND KeyOptions is NULL.
+**/
+EFI_STATUS
+BmFreeKeyOptions (
+ IN EFI_BOOT_MANAGER_KEY_OPTION *KeyOptions,
+ IN UINTN KeyOptionCount
+ )
+{
+ if (KeyOptions != NULL) {
+ FreePool (KeyOptions);
+ return EFI_SUCCESS;
+ } else {
+ return EFI_NOT_FOUND;
+ }
+}
+
+/**
+ Register the key option to exit the waiting of the Boot Manager timeout.
+ Platform should ensure that the continue key option isn't conflict with
+ other boot key options.
+
+ @param Modifier Key shift state.
+ @param ... Parameter list of pointer of EFI_INPUT_KEY.
+
+ @retval EFI_SUCCESS Successfully register the continue key option.
+ @retval EFI_ALREADY_STARTED The continue key option is already registered.
+**/
+EFI_STATUS
+EFIAPI
+EfiBootManagerRegisterContinueKeyOption (
+ IN UINT32 Modifier,
+ ...
+ )
+{
+ EFI_STATUS Status;
+ EFI_BOOT_MANAGER_KEY_OPTION KeyOption;
+ VA_LIST Args;
+
+ if (mBmContinueKeyOption != NULL) {
+ return EFI_ALREADY_STARTED;
+ }
+
+ ZeroMem (&KeyOption, sizeof (EFI_BOOT_MANAGER_KEY_OPTION));
+ VA_START (Args, Modifier);
+ Status = BmInitializeKeyFields (Modifier, Args, &KeyOption);
+ VA_END (Args);
+
+ if (!EFI_ERROR (Status)) {
+ mBmContinueKeyOption = AllocateCopyPool (sizeof (EFI_BOOT_MANAGER_KEY_OPTION), &KeyOption);
+ ASSERT (mBmContinueKeyOption != NULL);
+ if (mBmHotkeyServiceStarted) {
+ BmProcessKeyOption (mBmContinueKeyOption);
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Stop the hotkey processing.
+
+ @param Event Event pointer related to hotkey service.
+ @param Context Context pass to this function.
+**/
+VOID
+EFIAPI
+BmStopHotkeyService (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ LIST_ENTRY *Link;
+ BM_HOTKEY *Hotkey;
+
+ DEBUG ((EFI_D_INFO, "[Bds]Stop Hotkey Service!\n"));
+ gBS->CloseEvent (Event);
+
+ EfiAcquireLock (&mBmHotkeyLock);
+ for (Link = GetFirstNode (&mBmHotkeyList); !IsNull (&mBmHotkeyList, Link); ) {
+ Hotkey = BM_HOTKEY_FROM_LINK (Link);
+ BmUnregisterHotkeyNotify (Hotkey);
+ Link = RemoveEntryList (Link);
+ FreePool (Hotkey);
+ }
+ EfiReleaseLock (&mBmHotkeyLock);
+}
+
+/**
+ Start the hot key service so that the key press can trigger the boot option.
+
+ @param HotkeyTriggered Return the waitable event and it will be signaled
+ when a valid hot key is pressed.
+
+ @retval EFI_SUCCESS The hot key service is started.
+**/
+EFI_STATUS
+EFIAPI
+EfiBootManagerStartHotkeyService (
+ IN EFI_EVENT *HotkeyTriggered
+ )
+{
+ EFI_STATUS Status;
+ EFI_BOOT_MANAGER_KEY_OPTION *KeyOptions;
+ UINTN KeyOptionCount;
+ UINTN Index;
+ EFI_EVENT Event;
+ UINT32 *BootOptionSupport;
+
+ Status = GetEfiGlobalVariable2 (EFI_BOOT_OPTION_SUPPORT_VARIABLE_NAME, (VOID **) &BootOptionSupport, NULL);
+ ASSERT (BootOptionSupport != NULL);
+
+ if ((*BootOptionSupport & EFI_BOOT_OPTION_SUPPORT_KEY) != 0) {
+ mBmHotkeySupportCount = ((*BootOptionSupport & EFI_BOOT_OPTION_SUPPORT_COUNT) >> LowBitSet32 (EFI_BOOT_OPTION_SUPPORT_COUNT));
+ }
+ FreePool (BootOptionSupport);
+
+ if (mBmHotkeySupportCount == 0) {
+ DEBUG ((EFI_D_INFO, "Bds: BootOptionSupport NV variable forbids starting the hotkey service.\n"));
+ return EFI_UNSUPPORTED;
+ }
+
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_WAIT,
+ TPL_CALLBACK,
+ BmEmptyFunction,
+ NULL,
+ &mBmHotkeyTriggered
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ if (HotkeyTriggered != NULL) {
+ *HotkeyTriggered = mBmHotkeyTriggered;
+ }
+
+ KeyOptions = BmGetKeyOptions (&KeyOptionCount);
+ for (Index = 0; Index < KeyOptionCount; Index ++) {
+ BmProcessKeyOption (&KeyOptions[Index]);
+ }
+ BmFreeKeyOptions (KeyOptions, KeyOptionCount);
+
+ if (mBmContinueKeyOption != NULL) {
+ BmProcessKeyOption (mBmContinueKeyOption);
+ }
+
+ EfiCreateProtocolNotifyEvent (
+ &gEfiSimpleTextInputExProtocolGuid,
+ TPL_CALLBACK,
+ BmTxtInExCallback,
+ NULL,
+ &mBmTxtInExRegistration
+ );
+
+ Status = EfiCreateEventReadyToBootEx (
+ TPL_CALLBACK,
+ BmStopHotkeyService,
+ NULL,
+ &Event
+ );
+ ASSERT_EFI_ERROR (Status);
+
+
+ mBmHotkeyServiceStarted = TRUE;
+ return Status;
+}
+
+/**
+ Add the key option.
+ It adds the key option variable and the key option takes affect immediately.
+
+ @param AddedOption Return the added key option.
+ @param BootOptionNumber The boot option number for the key option.
+ @param Modifier Key shift state.
+ @param ... Parameter list of pointer of EFI_INPUT_KEY.
+
+ @retval EFI_SUCCESS The key option is added.
+ @retval EFI_ALREADY_STARTED The hot key is already used by certain key option.
+**/
+EFI_STATUS
+EFIAPI
+EfiBootManagerAddKeyOptionVariable (
+ OUT EFI_BOOT_MANAGER_KEY_OPTION *AddedOption, OPTIONAL
+ IN UINT16 BootOptionNumber,
+ IN UINT32 Modifier,
+ ...
+ )
+{
+ EFI_STATUS Status;
+ VA_LIST Args;
+ VOID *BootOption;
+ UINTN BootOptionSize;
+ CHAR16 BootOptionName[sizeof (L"Boot####")];
+ EFI_BOOT_MANAGER_KEY_OPTION KeyOption;
+ EFI_BOOT_MANAGER_KEY_OPTION *KeyOptions;
+ UINTN KeyOptionCount;
+ UINTN Index;
+ UINTN KeyOptionNumber;
+ CHAR16 KeyOptionName[sizeof (L"Key####")];
+
+ UnicodeSPrint (BootOptionName, sizeof (BootOptionName), L"Boot%04x", BootOptionNumber);
+ GetEfiGlobalVariable2 (BootOptionName, &BootOption, &BootOptionSize);
+
+ if (BootOption == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ ZeroMem (&KeyOption, sizeof (EFI_BOOT_MANAGER_KEY_OPTION));
+ KeyOption.BootOption = BootOptionNumber;
+ Status = gBS->CalculateCrc32 (BootOption, BootOptionSize, &KeyOption.BootOptionCrc);
+ ASSERT_EFI_ERROR (Status);
+ FreePool (BootOption);
+
+ VA_START (Args, Modifier);
+ Status = BmInitializeKeyFields (Modifier, Args, &KeyOption);
+ VA_END (Args);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ KeyOptionNumber = LoadOptionNumberUnassigned;
+ //
+ // Check if the hot key sequence was defined already
+ //
+ KeyOptions = BmGetKeyOptions (&KeyOptionCount);
+ for (Index = 0; Index < KeyOptionCount; Index++) {
+ if ((KeyOptions[Index].KeyData.PackedValue == KeyOption.KeyData.PackedValue) &&
+ (CompareMem (KeyOptions[Index].Keys, KeyOption.Keys, KeyOption.KeyData.Options.InputKeyCount * sizeof (EFI_INPUT_KEY)) == 0)) {
+ break;
+ }
+
+ if ((KeyOptionNumber == LoadOptionNumberUnassigned) &&
+ (KeyOptions[Index].OptionNumber > Index)
+ ){
+ KeyOptionNumber = Index;
+ }
+ }
+ BmFreeKeyOptions (KeyOptions, KeyOptionCount);
+
+ if (Index < KeyOptionCount) {
+ return EFI_ALREADY_STARTED;
+ }
+
+ if (KeyOptionNumber == LoadOptionNumberUnassigned) {
+ KeyOptionNumber = KeyOptionCount;
+ }
+
+ UnicodeSPrint (KeyOptionName, sizeof (KeyOptionName), L"Key%04x", KeyOptionNumber);
+
+ Status = gRT->SetVariable (
+ KeyOptionName,
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ BmSizeOfKeyOption (&KeyOption),
+ &KeyOption
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Return the Key Option in case needed by caller
+ //
+ if (AddedOption != NULL) {
+ CopyMem (AddedOption, &KeyOption, sizeof (EFI_BOOT_MANAGER_KEY_OPTION));
+ }
+
+ //
+ // Register the newly added hot key
+ // Calling this function before EfiBootManagerStartHotkeyService doesn't
+ // need to call BmProcessKeyOption
+ //
+ if (mBmHotkeyServiceStarted) {
+ BmProcessKeyOption (&KeyOption);
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Delete the Key Option variable and unregister the hot key
+
+ @param DeletedOption Return the deleted key options.
+ @param Modifier Key shift state.
+ @param ... Parameter list of pointer of EFI_INPUT_KEY.
+
+ @retval EFI_SUCCESS The key option is deleted.
+ @retval EFI_NOT_FOUND The key option cannot be found.
+**/
+EFI_STATUS
+EFIAPI
+EfiBootManagerDeleteKeyOptionVariable (
+ IN EFI_BOOT_MANAGER_KEY_OPTION *DeletedOption, OPTIONAL
+ IN UINT32 Modifier,
+ ...
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ VA_LIST Args;
+ EFI_BOOT_MANAGER_KEY_OPTION KeyOption;
+ EFI_BOOT_MANAGER_KEY_OPTION *KeyOptions;
+ UINTN KeyOptionCount;
+ LIST_ENTRY *Link;
+ BM_HOTKEY *Hotkey;
+ UINT32 ShiftState;
+ BOOLEAN Match;
+ CHAR16 KeyOptionName[sizeof (L"Key####")];
+
+ ZeroMem (&KeyOption, sizeof (EFI_BOOT_MANAGER_KEY_OPTION));
+ VA_START (Args, Modifier);
+ Status = BmInitializeKeyFields (Modifier, Args, &KeyOption);
+ VA_END (Args);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ EfiAcquireLock (&mBmHotkeyLock);
+ //
+ // Delete the key option from active hot key list
+ // Could have multiple entries when modifier isn't 0 because we map the ShiftPressed to RIGHT_SHIFT and RIGHT_SHIFT
+ //
+ for (Link = GetFirstNode (&mBmHotkeyList); !IsNull (&mBmHotkeyList, Link); ) {
+ Hotkey = BM_HOTKEY_FROM_LINK (Link);
+ Match = (BOOLEAN) (Hotkey->CodeCount == KeyOption.KeyData.Options.InputKeyCount);
+
+ for (Index = 0; Match && (Index < Hotkey->CodeCount); Index++) {
+ ShiftState = Hotkey->KeyData[Index].KeyState.KeyShiftState;
+ if (
+ (BmBitSet (ShiftState, EFI_RIGHT_SHIFT_PRESSED | EFI_LEFT_SHIFT_PRESSED) != KeyOption.KeyData.Options.ShiftPressed) ||
+ (BmBitSet (ShiftState, EFI_RIGHT_CONTROL_PRESSED | EFI_LEFT_CONTROL_PRESSED) != KeyOption.KeyData.Options.ControlPressed) ||
+ (BmBitSet (ShiftState, EFI_RIGHT_ALT_PRESSED | EFI_LEFT_ALT_PRESSED) != KeyOption.KeyData.Options.AltPressed) ||
+ (BmBitSet (ShiftState, EFI_RIGHT_LOGO_PRESSED | EFI_LEFT_LOGO_PRESSED) != KeyOption.KeyData.Options.LogoPressed) ||
+ (BmBitSet (ShiftState, EFI_MENU_KEY_PRESSED) != KeyOption.KeyData.Options.MenuPressed) ||
+ (BmBitSet (ShiftState, EFI_SYS_REQ_PRESSED) != KeyOption.KeyData.Options.SysReqPressed) ||
+ (CompareMem (&Hotkey->KeyData[Index].Key, &KeyOption.Keys[Index], sizeof (EFI_INPUT_KEY)) != 0)
+ ) {
+ //
+ // Break when any field doesn't match
+ //
+ Match = FALSE;
+ break;
+ }
+ }
+
+ if (Match) {
+ Link = RemoveEntryList (Link);
+ FreePool (Hotkey);
+ } else {
+ Link = GetNextNode (&mBmHotkeyList, Link);
+ }
+ }
+
+ //
+ // Delete the key option from the variable
+ //
+ Status = EFI_NOT_FOUND;
+ KeyOptions = BmGetKeyOptions (&KeyOptionCount);
+ for (Index = 0; Index < KeyOptionCount; Index++) {
+ if ((KeyOptions[Index].KeyData.PackedValue == KeyOption.KeyData.PackedValue) &&
+ (CompareMem (
+ KeyOptions[Index].Keys, KeyOption.Keys,
+ KeyOption.KeyData.Options.InputKeyCount * sizeof (EFI_INPUT_KEY)) == 0)
+ ) {
+ UnicodeSPrint (KeyOptionName, sizeof (KeyOptionName), L"Key%04x", KeyOptions[Index].OptionNumber);
+ Status = gRT->SetVariable (
+ KeyOptionName,
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ 0,
+ NULL
+ );
+ //
+ // Return the deleted key option in case needed by caller
+ //
+ if (DeletedOption != NULL) {
+ CopyMem (DeletedOption, &KeyOptions[Index], sizeof (EFI_BOOT_MANAGER_KEY_OPTION));
+ }
+ break;
+ }
+ }
+ BmFreeKeyOptions (KeyOptions, KeyOptionCount);
+
+ EfiReleaseLock (&mBmHotkeyLock);
+
+ return Status;
+}
diff --git a/Core/MdeModulePkg/Library/UefiBootManagerLib/BmLoadOption.c b/Core/MdeModulePkg/Library/UefiBootManagerLib/BmLoadOption.c
new file mode 100644
index 0000000000..6b9690a37c
--- /dev/null
+++ b/Core/MdeModulePkg/Library/UefiBootManagerLib/BmLoadOption.c
@@ -0,0 +1,1253 @@
+/** @file
+ Load option library functions which relate with creating and processing load options.
+
+Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "InternalBm.h"
+
+GLOBAL_REMOVE_IF_UNREFERENCED
+ CHAR16 *mBmLoadOptionName[] = {
+ L"Driver",
+ L"SysPrep",
+ L"Boot"
+ };
+
+GLOBAL_REMOVE_IF_UNREFERENCED
+ CHAR16 *mBmLoadOptionOrderName[] = {
+ EFI_DRIVER_ORDER_VARIABLE_NAME,
+ EFI_SYS_PREP_ORDER_VARIABLE_NAME,
+ EFI_BOOT_ORDER_VARIABLE_NAME
+ };
+
+/**
+ Call Visitor function for each variable in variable storage.
+
+ @param Visitor Visitor function.
+ @param Context The context passed to Visitor function.
+**/
+VOID
+BmForEachVariable (
+ VARIABLE_VISITOR Visitor,
+ VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ CHAR16 *Name;
+ EFI_GUID Guid;
+ UINTN NameSize;
+ UINTN NewNameSize;
+
+ NameSize = sizeof (CHAR16);
+ Name = AllocateZeroPool (NameSize);
+ ASSERT (Name != NULL);
+ while (TRUE) {
+ NewNameSize = NameSize;
+ Status = gRT->GetNextVariableName (&NewNameSize, Name, &Guid);
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ Name = ReallocatePool (NameSize, NewNameSize, Name);
+ ASSERT (Name != NULL);
+ Status = gRT->GetNextVariableName (&NewNameSize, Name, &Guid);
+ NameSize = NewNameSize;
+ }
+
+ if (Status == EFI_NOT_FOUND) {
+ break;
+ }
+ ASSERT_EFI_ERROR (Status);
+
+ Visitor (Name, &Guid, Context);
+ }
+
+ FreePool (Name);
+}
+
+/**
+ Get the Option Number that wasn't used.
+
+ @param LoadOptionType The load option type.
+ @param FreeOptionNumber Return the minimal free option number.
+
+ @retval EFI_SUCCESS The option number is found and will be returned.
+ @retval EFI_OUT_OF_RESOURCES There is no free option number that can be used.
+ @retval EFI_INVALID_PARAMETER FreeOptionNumber is NULL
+
+**/
+EFI_STATUS
+BmGetFreeOptionNumber (
+ IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LoadOptionType,
+ OUT UINT16 *FreeOptionNumber
+ )
+{
+
+ UINTN OptionNumber;
+ UINTN Index;
+ UINT16 *OptionOrder;
+ UINTN OptionOrderSize;
+ UINT16 *BootNext;
+
+ ASSERT (FreeOptionNumber != NULL);
+ ASSERT (LoadOptionType == LoadOptionTypeDriver ||
+ LoadOptionType == LoadOptionTypeBoot ||
+ LoadOptionType == LoadOptionTypeSysPrep);
+
+ GetEfiGlobalVariable2 (mBmLoadOptionOrderName[LoadOptionType], (VOID **) &OptionOrder, &OptionOrderSize);
+ ASSERT ((OptionOrder != NULL && OptionOrderSize != 0) || (OptionOrder == NULL && OptionOrderSize == 0));
+
+ BootNext = NULL;
+ if (LoadOptionType == LoadOptionTypeBoot) {
+ GetEfiGlobalVariable2 (L"BootNext", (VOID**) &BootNext, NULL);
+ }
+
+ for (OptionNumber = 0;
+ OptionNumber < OptionOrderSize / sizeof (UINT16)
+ + ((BootNext != NULL) ? 1 : 0);
+ OptionNumber++
+ ) {
+ //
+ // Search in OptionOrder whether the OptionNumber exists
+ //
+ for (Index = 0; Index < OptionOrderSize / sizeof (UINT16); Index++) {
+ if (OptionNumber == OptionOrder[Index]) {
+ break;
+ }
+ }
+
+ //
+ // We didn't find it in the ****Order array and it doesn't equal to BootNext
+ // Otherwise, OptionNumber equals to OptionOrderSize / sizeof (UINT16) + 1
+ //
+ if ((Index == OptionOrderSize / sizeof (UINT16)) &&
+ ((BootNext == NULL) || (OptionNumber != *BootNext))
+ ) {
+ break;
+ }
+ }
+ if (OptionOrder != NULL) {
+ FreePool (OptionOrder);
+ }
+
+ if (BootNext != NULL) {
+ FreePool (BootNext);
+ }
+
+ //
+ // When BootOrder & BootNext conver all numbers in the range [0 ... 0xffff],
+ // OptionNumber equals to 0x10000 which is not valid.
+ //
+ ASSERT (OptionNumber <= 0x10000);
+ if (OptionNumber == 0x10000) {
+ return EFI_OUT_OF_RESOURCES;
+ } else {
+ *FreeOptionNumber = (UINT16) OptionNumber;
+ return EFI_SUCCESS;
+ }
+}
+
+/**
+ Create the Boot####, Driver####, SysPrep####, variable from the load option.
+
+ @param LoadOption Pointer to the load option.
+
+ @retval EFI_SUCCESS The variable was created.
+ @retval Others Error status returned by RT->SetVariable.
+**/
+EFI_STATUS
+EFIAPI
+EfiBootManagerLoadOptionToVariable (
+ IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *Option
+ )
+{
+ UINTN VariableSize;
+ UINT8 *Variable;
+ UINT8 *Ptr;
+ CHAR16 OptionName[BM_OPTION_NAME_LEN];
+ CHAR16 *Description;
+ CHAR16 NullChar;
+ UINT32 VariableAttributes;
+
+ if ((Option->OptionNumber == LoadOptionNumberUnassigned) ||
+ (Option->FilePath == NULL) ||
+ ((UINT32) Option->OptionType >= LoadOptionTypeMax)
+ ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Convert NULL description to empty description
+ //
+ NullChar = L'\0';
+ Description = Option->Description;
+ if (Description == NULL) {
+ Description = &NullChar;
+ }
+
+ /*
+ UINT32 Attributes;
+ UINT16 FilePathListLength;
+ CHAR16 Description[];
+ EFI_DEVICE_PATH_PROTOCOL FilePathList[];
+ UINT8 OptionalData[];
+TODO: FilePathList[] IS:
+A packed array of UEFI device paths. The first element of the
+array is a device path that describes the device and location of the
+Image for this load option. The FilePathList[0] is specific
+to the device type. Other device paths may optionally exist in the
+FilePathList, but their usage is OSV specific. Each element
+in the array is variable length, and ends at the device path end
+structure.
+ */
+ VariableSize = sizeof (Option->Attributes)
+ + sizeof (UINT16)
+ + StrSize (Description)
+ + GetDevicePathSize (Option->FilePath)
+ + Option->OptionalDataSize;
+
+ Variable = AllocatePool (VariableSize);
+ ASSERT (Variable != NULL);
+
+ Ptr = Variable;
+ WriteUnaligned32 ((UINT32 *) Ptr, Option->Attributes);
+ Ptr += sizeof (Option->Attributes);
+
+ WriteUnaligned16 ((UINT16 *) Ptr, (UINT16) GetDevicePathSize (Option->FilePath));
+ Ptr += sizeof (UINT16);
+
+ CopyMem (Ptr, Description, StrSize (Description));
+ Ptr += StrSize (Description);
+
+ CopyMem (Ptr, Option->FilePath, GetDevicePathSize (Option->FilePath));
+ Ptr += GetDevicePathSize (Option->FilePath);
+
+ CopyMem (Ptr, Option->OptionalData, Option->OptionalDataSize);
+
+ UnicodeSPrint (OptionName, sizeof (OptionName), L"%s%04x", mBmLoadOptionName[Option->OptionType], Option->OptionNumber);
+
+ VariableAttributes = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE;
+
+ return gRT->SetVariable (
+ OptionName,
+ &gEfiGlobalVariableGuid,
+ VariableAttributes,
+ VariableSize,
+ Variable
+ );
+}
+
+/**
+ Update order variable .
+
+ @param OptionOrderName Order variable name which need to be updated.
+ @param OptionNumber Option number for the new option.
+ @param Position Position of the new load option to put in the ****Order variable.
+
+ @retval EFI_SUCCESS The boot#### or driver#### have been successfully registered.
+ @retval EFI_ALREADY_STARTED The option number of Option is being used already.
+ @retval EFI_STATUS Return the status of gRT->SetVariable ().
+
+**/
+EFI_STATUS
+BmAddOptionNumberToOrderVariable (
+ IN CHAR16 *OptionOrderName,
+ IN UINT16 OptionNumber,
+ IN UINTN Position
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ UINT16 *OptionOrder;
+ UINT16 *NewOptionOrder;
+ UINTN OptionOrderSize;
+ //
+ // Update the option order variable
+ //
+ GetEfiGlobalVariable2 (OptionOrderName, (VOID **) &OptionOrder, &OptionOrderSize);
+ ASSERT ((OptionOrder != NULL && OptionOrderSize != 0) || (OptionOrder == NULL && OptionOrderSize == 0));
+
+ Status = EFI_SUCCESS;
+ for (Index = 0; Index < OptionOrderSize / sizeof (UINT16); Index++) {
+ if (OptionOrder[Index] == OptionNumber) {
+ Status = EFI_ALREADY_STARTED;
+ break;
+ }
+ }
+
+ if (!EFI_ERROR (Status)) {
+ Position = MIN (Position, OptionOrderSize / sizeof (UINT16));
+
+ NewOptionOrder = AllocatePool (OptionOrderSize + sizeof (UINT16));
+ ASSERT (NewOptionOrder != NULL);
+ if (OptionOrderSize != 0) {
+ CopyMem (NewOptionOrder, OptionOrder, Position * sizeof (UINT16));
+ CopyMem (&NewOptionOrder[Position + 1], &OptionOrder[Position], OptionOrderSize - Position * sizeof (UINT16));
+ }
+ NewOptionOrder[Position] = OptionNumber;
+
+ Status = gRT->SetVariable (
+ OptionOrderName,
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ OptionOrderSize + sizeof (UINT16),
+ NewOptionOrder
+ );
+ FreePool (NewOptionOrder);
+ }
+
+ if (OptionOrder != NULL) {
+ FreePool (OptionOrder);
+ }
+
+ return Status;
+}
+
+/**
+ This function will register the new Boot####, Driver#### or SysPrep#### option.
+ After the *#### is updated, the *Order will also be updated.
+
+ @param Option Pointer to load option to add.
+ @param Position Position of the new load option to put in the ****Order variable.
+
+ @retval EFI_SUCCESS The *#### have been successfully registered.
+ @retval EFI_INVALID_PARAMETER The option number exceeds 0xFFFF.
+ @retval EFI_ALREADY_STARTED The option number of Option is being used already.
+ Note: this API only adds new load option, no replacement support.
+ @retval EFI_OUT_OF_RESOURCES There is no free option number that can be used when the
+ option number specified in the Option is LoadOptionNumberUnassigned.
+ @retval EFI_STATUS Return the status of gRT->SetVariable ().
+
+**/
+EFI_STATUS
+EFIAPI
+EfiBootManagerAddLoadOptionVariable (
+ IN EFI_BOOT_MANAGER_LOAD_OPTION *Option,
+ IN UINTN Position
+ )
+{
+ EFI_STATUS Status;
+ UINT16 OptionNumber;
+
+ if (Option == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Option->OptionType != LoadOptionTypeDriver &&
+ Option->OptionType != LoadOptionTypeSysPrep &&
+ Option->OptionType != LoadOptionTypeBoot
+ ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Get the free option number if the option number is unassigned
+ //
+ if (Option->OptionNumber == LoadOptionNumberUnassigned) {
+ Status = BmGetFreeOptionNumber (Option->OptionType, &OptionNumber);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Option->OptionNumber = OptionNumber;
+ }
+
+ if (Option->OptionNumber >= LoadOptionNumberMax) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = BmAddOptionNumberToOrderVariable (mBmLoadOptionOrderName[Option->OptionType], (UINT16) Option->OptionNumber, Position);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Save the Boot#### or Driver#### variable
+ //
+ Status = EfiBootManagerLoadOptionToVariable (Option);
+ if (EFI_ERROR (Status)) {
+ //
+ // Remove the #### from *Order variable when the Driver####/SysPrep####/Boot#### cannot be saved.
+ //
+ EfiBootManagerDeleteLoadOptionVariable (Option->OptionNumber, Option->OptionType);
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Sort the load option. The DriverOrder or BootOrder will be re-created to
+ reflect the new order.
+
+ @param OptionType Load option type
+ @param CompareFunction The comparator
+**/
+VOID
+EFIAPI
+EfiBootManagerSortLoadOptionVariable (
+ EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType,
+ SORT_COMPARE CompareFunction
+ )
+{
+ EFI_STATUS Status;
+ EFI_BOOT_MANAGER_LOAD_OPTION *LoadOption;
+ UINTN LoadOptionCount;
+ UINTN Index;
+ UINT16 *OptionOrder;
+
+ LoadOption = EfiBootManagerGetLoadOptions (&LoadOptionCount, OptionType);
+
+ //
+ // Insertion sort algorithm
+ //
+ PerformQuickSort (
+ LoadOption,
+ LoadOptionCount,
+ sizeof (EFI_BOOT_MANAGER_LOAD_OPTION),
+ CompareFunction
+ );
+
+ //
+ // Create new ****Order variable
+ //
+ OptionOrder = AllocatePool (LoadOptionCount * sizeof (UINT16));
+ ASSERT (OptionOrder != NULL);
+ for (Index = 0; Index < LoadOptionCount; Index++) {
+ OptionOrder[Index] = (UINT16) LoadOption[Index].OptionNumber;
+ }
+
+ Status = gRT->SetVariable (
+ mBmLoadOptionOrderName[OptionType],
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ LoadOptionCount * sizeof (UINT16),
+ OptionOrder
+ );
+ //
+ // Changing the *Order content without increasing its size with current variable implementation shouldn't fail.
+ //
+ ASSERT_EFI_ERROR (Status);
+
+ FreePool (OptionOrder);
+ EfiBootManagerFreeLoadOptions (LoadOption, LoadOptionCount);
+}
+
+/**
+ Initialize a load option.
+
+ @param Option Pointer to the load option to be initialized.
+ @param OptionNumber Option number of the load option.
+ @param OptionType Type of the load option.
+ @param Attributes Attributes of the load option.
+ @param Description Description of the load option.
+ @param FilePath Device path of the load option.
+ @param OptionalData Optional data of the load option.
+ @param OptionalDataSize Size of the optional data of the load option.
+
+ @retval EFI_SUCCESS The load option was initialized successfully.
+ @retval EFI_INVALID_PARAMETER Option, Description or FilePath is NULL.
+**/
+EFI_STATUS
+EFIAPI
+EfiBootManagerInitializeLoadOption (
+ IN OUT EFI_BOOT_MANAGER_LOAD_OPTION *Option,
+ IN UINTN OptionNumber,
+ IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType,
+ IN UINT32 Attributes,
+ IN CHAR16 *Description,
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ IN UINT8 *OptionalData, OPTIONAL
+ IN UINT32 OptionalDataSize
+ )
+{
+ if ((Option == NULL) || (Description == NULL) || (FilePath == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (((OptionalData != NULL) && (OptionalDataSize == 0)) ||
+ ((OptionalData == NULL) && (OptionalDataSize != 0))) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((UINT32) OptionType >= LoadOptionTypeMax) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ZeroMem (Option, sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));
+ Option->OptionNumber = OptionNumber;
+ Option->OptionType = OptionType;
+ Option->Attributes = Attributes;
+ Option->Description = AllocateCopyPool (StrSize (Description), Description);
+ Option->FilePath = DuplicateDevicePath (FilePath);
+ if (OptionalData != NULL) {
+ Option->OptionalData = AllocateCopyPool (OptionalDataSize, OptionalData);
+ Option->OptionalDataSize = OptionalDataSize;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Return the index of the load option in the load option array.
+
+ The function consider two load options are equal when the
+ OptionType, Attributes, Description, FilePath and OptionalData are equal.
+
+ @param Key Pointer to the load option to be found.
+ @param Array Pointer to the array of load options to be found.
+ @param Count Number of entries in the Array.
+
+ @retval -1 Key wasn't found in the Array.
+ @retval 0 ~ Count-1 The index of the Key in the Array.
+**/
+INTN
+BmFindLoadOption (
+ IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *Key,
+ IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *Array,
+ IN UINTN Count
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index < Count; Index++) {
+ if ((Key->OptionType == Array[Index].OptionType) &&
+ (Key->Attributes == Array[Index].Attributes) &&
+ (StrCmp (Key->Description, Array[Index].Description) == 0) &&
+ (CompareMem (Key->FilePath, Array[Index].FilePath, GetDevicePathSize (Key->FilePath)) == 0) &&
+ (Key->OptionalDataSize == Array[Index].OptionalDataSize) &&
+ (CompareMem (Key->OptionalData, Array[Index].OptionalData, Key->OptionalDataSize) == 0)) {
+ return (INTN) Index;
+ }
+ }
+
+ return -1;
+}
+
+/**
+ Delete the load option.
+
+ @param OptionNumber Indicate the option number of load option
+ @param OptionType Indicate the type of load option
+
+ @retval EFI_INVALID_PARAMETER OptionType or OptionNumber is invalid.
+ @retval EFI_NOT_FOUND The load option cannot be found
+ @retval EFI_SUCCESS The load option was deleted
+ @retval others Status of RT->SetVariable()
+**/
+EFI_STATUS
+EFIAPI
+EfiBootManagerDeleteLoadOptionVariable (
+ IN UINTN OptionNumber,
+ IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType
+ )
+{
+ UINT16 *OptionOrder;
+ UINTN OptionOrderSize;
+ EFI_STATUS Status;
+ UINTN Index;
+
+ if (((UINT32) OptionType >= LoadOptionTypeMax) || (OptionNumber >= LoadOptionNumberMax)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_NOT_FOUND;
+
+ if (OptionType == LoadOptionTypeDriver || OptionType == LoadOptionTypeSysPrep || OptionType == LoadOptionTypeBoot) {
+ //
+ // If the associated *Order exists, just remove the reference in *Order.
+ //
+ GetEfiGlobalVariable2 (mBmLoadOptionOrderName[OptionType], (VOID **) &OptionOrder, &OptionOrderSize);
+ ASSERT ((OptionOrder != NULL && OptionOrderSize != 0) || (OptionOrder == NULL && OptionOrderSize == 0));
+
+ for (Index = 0; Index < OptionOrderSize / sizeof (UINT16); Index++) {
+ if (OptionOrder[Index] == OptionNumber) {
+ OptionOrderSize -= sizeof (UINT16);
+ CopyMem (&OptionOrder[Index], &OptionOrder[Index + 1], OptionOrderSize - Index * sizeof (UINT16));
+ Status = gRT->SetVariable (
+ mBmLoadOptionOrderName[OptionType],
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ OptionOrderSize,
+ OptionOrder
+ );
+ break;
+ }
+ }
+ if (OptionOrder != NULL) {
+ FreePool (OptionOrder);
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Convert a single character to number.
+ It assumes the input Char is in the scope of L'0' ~ L'9' and L'A' ~ L'F'
+
+ @param Char The input char which need to convert to int.
+**/
+UINTN
+BmCharToUint (
+ IN CHAR16 Char
+ )
+{
+ if ((Char >= L'0') && (Char <= L'9')) {
+ return (UINTN) (Char - L'0');
+ }
+
+ if ((Char >= L'A') && (Char <= L'F')) {
+ return (UINTN) (Char - L'A' + 0xA);
+ }
+
+ ASSERT (FALSE);
+ return (UINTN) -1;
+}
+
+/**
+ Returns the size of a device path in bytes.
+
+ This function returns the size, in bytes, of the device path data structure
+ specified by DevicePath including the end of device path node. If DevicePath
+ is NULL, then 0 is returned. If the length of the device path is bigger than
+ MaxSize, also return 0 to indicate this is an invalidate device path.
+
+ @param DevicePath A pointer to a device path data structure.
+ @param MaxSize Max valid device path size. If big than this size,
+ return error.
+
+ @retval 0 An invalid device path.
+ @retval Others The size of a device path in bytes.
+
+**/
+UINTN
+BmGetDevicePathSizeEx (
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ IN UINTN MaxSize
+ )
+{
+ UINTN Size;
+ UINTN NodeSize;
+
+ if (DevicePath == NULL) {
+ return 0;
+ }
+
+ //
+ // Search for the end of the device path structure
+ //
+ Size = 0;
+ while (!IsDevicePathEnd (DevicePath)) {
+ NodeSize = DevicePathNodeLength (DevicePath);
+ if (NodeSize == 0) {
+ return 0;
+ }
+ Size += NodeSize;
+ if (Size > MaxSize) {
+ return 0;
+ }
+ DevicePath = NextDevicePathNode (DevicePath);
+ }
+ Size += DevicePathNodeLength (DevicePath);
+ if (Size > MaxSize) {
+ return 0;
+ }
+
+ return Size;
+}
+
+/**
+ Returns the length of a Null-terminated Unicode string. If the length is
+ bigger than MaxStringLen, return length 0 to indicate that this is an
+ invalidate string.
+
+ This function returns the number of Unicode characters in the Null-terminated
+ Unicode string specified by String.
+
+ If String is NULL, then ASSERT().
+ If String is not aligned on a 16-bit boundary, then ASSERT().
+
+ @param String A pointer to a Null-terminated Unicode string.
+ @param MaxStringLen Max string len in this string.
+
+ @retval 0 An invalid string.
+ @retval Others The length of String.
+
+**/
+UINTN
+BmStrSizeEx (
+ IN CONST CHAR16 *String,
+ IN UINTN MaxStringLen
+ )
+{
+ UINTN Length;
+
+ ASSERT (String != NULL && MaxStringLen != 0);
+ ASSERT (((UINTN) String & BIT0) == 0);
+
+ for (Length = 0; *String != L'\0' && MaxStringLen != Length; String++, Length+=2);
+
+ if (*String != L'\0' && MaxStringLen == Length) {
+ return 0;
+ }
+
+ return Length + 2;
+}
+
+/**
+ Validate the Boot####, Driver####, SysPrep#### variable (VendorGuid/Name)
+
+ @param Variable The variable data.
+ @param VariableSize The variable size.
+
+ @retval TRUE The variable data is correct.
+ @retval FALSE The variable data is corrupted.
+
+**/
+BOOLEAN
+BmValidateOption (
+ UINT8 *Variable,
+ UINTN VariableSize
+ )
+{
+ UINT16 FilePathSize;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ UINTN DescriptionSize;
+
+ if (VariableSize <= sizeof (UINT16) + sizeof (UINT32)) {
+ return FALSE;
+ }
+
+ //
+ // Skip the option attribute
+ //
+ Variable += sizeof (UINT32);
+
+ //
+ // Get the option's device path size
+ //
+ FilePathSize = ReadUnaligned16 ((UINT16 *) Variable);
+ Variable += sizeof (UINT16);
+
+ //
+ // Get the option's description string size
+ //
+ DescriptionSize = BmStrSizeEx ((CHAR16 *) Variable, VariableSize - sizeof (UINT16) - sizeof (UINT32));
+ Variable += DescriptionSize;
+
+ //
+ // Get the option's device path
+ //
+ DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) Variable;
+
+ //
+ // Validation boot option variable.
+ //
+ if ((FilePathSize == 0) || (DescriptionSize == 0)) {
+ return FALSE;
+ }
+
+ if (sizeof (UINT32) + sizeof (UINT16) + DescriptionSize + FilePathSize > VariableSize) {
+ return FALSE;
+ }
+
+ return (BOOLEAN) (BmGetDevicePathSizeEx (DevicePath, FilePathSize) != 0);
+}
+
+/**
+ Check whether the VariableName is a valid load option variable name
+ and return the load option type and option number.
+
+ @param VariableName The name of the load option variable.
+ @param OptionType Return the load option type.
+ @param OptionNumber Return the load option number.
+
+ @retval TRUE The variable name is valid; The load option type and
+ load option number is returned.
+ @retval FALSE The variable name is NOT valid.
+**/
+BOOLEAN
+BmIsValidLoadOptionVariableName (
+ IN CHAR16 *VariableName,
+ OUT EFI_BOOT_MANAGER_LOAD_OPTION_TYPE *OptionType,
+ OUT UINT16 *OptionNumber
+ )
+{
+ UINTN VariableNameLen;
+ UINTN Index;
+ UINTN Uint;
+
+ VariableNameLen = StrLen (VariableName);
+
+ if (VariableNameLen <= 4) {
+ return FALSE;
+ }
+
+ for (Index = 0; Index < sizeof (mBmLoadOptionName) / sizeof (mBmLoadOptionName[0]); Index++) {
+ if ((VariableNameLen - 4 == StrLen (mBmLoadOptionName[Index])) &&
+ (StrnCmp (VariableName, mBmLoadOptionName[Index], VariableNameLen - 4) == 0)
+ ) {
+ break;
+ }
+ }
+
+ if (Index == sizeof (mBmLoadOptionName) / sizeof (mBmLoadOptionName[0])) {
+ return FALSE;
+ }
+
+ *OptionType = (EFI_BOOT_MANAGER_LOAD_OPTION_TYPE) Index;
+ *OptionNumber = 0;
+ for (Index = VariableNameLen - 4; Index < VariableNameLen; Index++) {
+ Uint = BmCharToUint (VariableName[Index]);
+ if (Uint == -1) {
+ break;
+ } else {
+ *OptionNumber = (UINT16) Uint + *OptionNumber * 0x10;
+ }
+ }
+
+ return (BOOLEAN) (Index == VariableNameLen);
+}
+
+/**
+ Build the Boot#### or Driver#### option from the VariableName.
+
+ @param VariableName Variable name of the load option
+ @param VendorGuid Variable GUID of the load option
+ @param Option Return the load option.
+
+ @retval EFI_SUCCESS Get the option just been created
+ @retval EFI_NOT_FOUND Failed to get the new option
+
+**/
+EFI_STATUS
+EFIAPI
+EfiBootManagerVariableToLoadOptionEx (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN OUT EFI_BOOT_MANAGER_LOAD_OPTION *Option
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Attribute;
+ UINT16 FilePathSize;
+ UINT8 *Variable;
+ UINT8 *VariablePtr;
+ UINTN VariableSize;
+ EFI_DEVICE_PATH_PROTOCOL *FilePath;
+ UINT8 *OptionalData;
+ UINT32 OptionalDataSize;
+ CHAR16 *Description;
+ EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType;
+ UINT16 OptionNumber;
+
+ if ((VariableName == NULL) || (Option == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!BmIsValidLoadOptionVariableName (VariableName, &OptionType, &OptionNumber)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Read the variable
+ //
+ GetVariable2 (VariableName, VendorGuid, (VOID **) &Variable, &VariableSize);
+ if (Variable == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Validate *#### variable data.
+ //
+ if (!BmValidateOption(Variable, VariableSize)) {
+ FreePool (Variable);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Get the option attribute
+ //
+ VariablePtr = Variable;
+ Attribute = ReadUnaligned32 ((UINT32 *) VariablePtr);
+ VariablePtr += sizeof (UINT32);
+
+ //
+ // Get the option's device path size
+ //
+ FilePathSize = ReadUnaligned16 ((UINT16 *) VariablePtr);
+ VariablePtr += sizeof (UINT16);
+
+ //
+ // Get the option's description string
+ //
+ Description = (CHAR16 *) VariablePtr;
+
+ //
+ // Get the option's description string size
+ //
+ VariablePtr += StrSize ((CHAR16 *) VariablePtr);
+
+ //
+ // Get the option's device path
+ //
+ FilePath = (EFI_DEVICE_PATH_PROTOCOL *) VariablePtr;
+ VariablePtr += FilePathSize;
+
+ OptionalDataSize = (UINT32) (VariableSize - (UINTN) (VariablePtr - Variable));
+ if (OptionalDataSize == 0) {
+ OptionalData = NULL;
+ } else {
+ OptionalData = VariablePtr;
+ }
+
+ Status = EfiBootManagerInitializeLoadOption (
+ Option,
+ OptionNumber,
+ OptionType,
+ Attribute,
+ Description,
+ FilePath,
+ OptionalData,
+ OptionalDataSize
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ CopyGuid (&Option->VendorGuid, VendorGuid);
+
+ FreePool (Variable);
+ return Status;
+}
+
+/**
+Build the Boot#### or Driver#### option from the VariableName.
+
+@param VariableName EFI Variable name indicate if it is Boot#### or Driver####
+@param Option Return the Boot#### or Driver#### option.
+
+@retval EFI_SUCCESS Get the option just been created
+@retval EFI_NOT_FOUND Failed to get the new option
+**/
+EFI_STATUS
+EFIAPI
+EfiBootManagerVariableToLoadOption (
+ IN CHAR16 *VariableName,
+ IN OUT EFI_BOOT_MANAGER_LOAD_OPTION *Option
+ )
+{
+ return EfiBootManagerVariableToLoadOptionEx (VariableName, &gEfiGlobalVariableGuid, Option);
+}
+
+/**
+ Returns an array of load options based on the EFI variable
+ L"BootOrder"/L"DriverOrder" and the L"Boot####"/L"Driver####" variables impled by it.
+ #### is the hex value of the UINT16 in each BootOrder/DriverOrder entry.
+
+ @param LoadOptionCount Returns number of entries in the array.
+ @param LoadOptionType The type of the load option.
+
+ @retval NULL No load options exist.
+ @retval !NULL Array of load option entries.
+
+**/
+EFI_BOOT_MANAGER_LOAD_OPTION *
+EFIAPI
+EfiBootManagerGetLoadOptions (
+ OUT UINTN *OptionCount,
+ IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LoadOptionType
+ )
+{
+ EFI_STATUS Status;
+ UINT16 *OptionOrder;
+ UINTN OptionOrderSize;
+ UINTN Index;
+ UINTN OptionIndex;
+ EFI_BOOT_MANAGER_LOAD_OPTION *Options;
+ CHAR16 OptionName[BM_OPTION_NAME_LEN];
+ UINT16 OptionNumber;
+
+ *OptionCount = 0;
+
+ if (LoadOptionType == LoadOptionTypeDriver || LoadOptionType == LoadOptionTypeSysPrep || LoadOptionType == LoadOptionTypeBoot) {
+ //
+ // Read the BootOrder, or DriverOrder variable.
+ //
+ GetEfiGlobalVariable2 (mBmLoadOptionOrderName[LoadOptionType], (VOID **) &OptionOrder, &OptionOrderSize);
+ if (OptionOrder == NULL) {
+ return NULL;
+ }
+
+ *OptionCount = OptionOrderSize / sizeof (UINT16);
+
+ Options = AllocatePool (*OptionCount * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));
+ ASSERT (Options != NULL);
+
+ OptionIndex = 0;
+ for (Index = 0; Index < *OptionCount; Index++) {
+ OptionNumber = OptionOrder[Index];
+ UnicodeSPrint (OptionName, sizeof (OptionName), L"%s%04x", mBmLoadOptionName[LoadOptionType], OptionNumber);
+
+ Status = EfiBootManagerVariableToLoadOption (OptionName, &Options[OptionIndex]);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_INFO, "[Bds] %s doesn't exist - Update ****Order variable to remove the reference!!", OptionName));
+ EfiBootManagerDeleteLoadOptionVariable (OptionNumber, LoadOptionType);
+ } else {
+ ASSERT (Options[OptionIndex].OptionNumber == OptionNumber);
+ OptionIndex++;
+ }
+ }
+
+ if (OptionOrder != NULL) {
+ FreePool (OptionOrder);
+ }
+
+ if (OptionIndex < *OptionCount) {
+ Options = ReallocatePool (*OptionCount * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION), OptionIndex * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION), Options);
+ ASSERT (Options != NULL);
+ *OptionCount = OptionIndex;
+ }
+
+ } else {
+ return NULL;
+ }
+
+ return Options;
+}
+
+/**
+ Free an EFI_BOOT_MANGER_LOAD_OPTION entry that was allocate by the library.
+
+ @param LoadOption Pointer to boot option to Free.
+
+ @return EFI_SUCCESS BootOption was freed
+ @return EFI_NOT_FOUND BootOption == NULL
+
+**/
+EFI_STATUS
+EFIAPI
+EfiBootManagerFreeLoadOption (
+ IN EFI_BOOT_MANAGER_LOAD_OPTION *LoadOption
+ )
+{
+ if (LoadOption == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (LoadOption->Description != NULL) {
+ FreePool (LoadOption->Description);
+ }
+ if (LoadOption->FilePath != NULL) {
+ FreePool (LoadOption->FilePath);
+ }
+ if (LoadOption->OptionalData != NULL) {
+ FreePool (LoadOption->OptionalData);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Free an EFI_BOOT_MANGER_LOAD_OPTION array that was allocated by
+ EfiBootManagerGetLoadOptions().
+
+ @param Option Pointer to boot option array to free.
+ @param OptionCount Number of array entries in BootOption
+
+ @return EFI_SUCCESS BootOption was freed
+ @return EFI_NOT_FOUND BootOption == NULL
+
+**/
+EFI_STATUS
+EFIAPI
+EfiBootManagerFreeLoadOptions (
+ IN EFI_BOOT_MANAGER_LOAD_OPTION *Option,
+ IN UINTN OptionCount
+ )
+{
+ UINTN Index;
+
+ if (Option == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ for (Index = 0;Index < OptionCount; Index++) {
+ EfiBootManagerFreeLoadOption (&Option[Index]);
+ }
+
+ FreePool (Option);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Return whether the PE header of the load option is valid or not.
+
+ @param[in] Type The load option type.
+ @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) &&
+ EFI_IMAGE_MACHINE_TYPE_SUPPORTED (PeHeader->Pe32.FileHeader.Machine)
+ ) {
+ //
+ // 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 == 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)
+ ) {
+ return TRUE;
+ }
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ Process (load and execute) the load option.
+
+ @param LoadOption Pointer to the load option.
+
+ @retval EFI_INVALID_PARAMETER The load option type is invalid,
+ or the load option file path doesn't point to a valid file.
+ @retval EFI_UNSUPPORTED The load option type is of LoadOptionTypeBoot.
+ @retval EFI_SUCCESS The load option is inactive, or successfully loaded and executed.
+**/
+EFI_STATUS
+EFIAPI
+EfiBootManagerProcessLoadOption (
+ IN EFI_BOOT_MANAGER_LOAD_OPTION *LoadOption
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *FilePath;
+ EFI_HANDLE ImageHandle;
+ EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;
+ VOID *FileBuffer;
+ UINTN FileSize;
+
+ if ((UINT32) LoadOption->OptionType >= LoadOptionTypeMax) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (LoadOption->OptionType == LoadOptionTypeBoot) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // If a load option is not marked as LOAD_OPTION_ACTIVE,
+ // the boot manager will not automatically load the option.
+ //
+ if ((LoadOption->Attributes & LOAD_OPTION_ACTIVE) == 0) {
+ return EFI_SUCCESS;
+ }
+
+ Status = EFI_INVALID_PARAMETER;
+
+ //
+ // Load and start the load option.
+ //
+ DEBUG ((
+ DEBUG_INFO | DEBUG_LOAD, "Process Load Option (%s%04x) ...\n",
+ mBmLoadOptionName[LoadOption->OptionType], LoadOption->OptionNumber
+ ));
+ ImageHandle = NULL;
+ FileBuffer = BmGetLoadOptionBuffer (LoadOption->FilePath, &FilePath, &FileSize);
+ DEBUG_CODE (
+ if (FileBuffer != NULL && CompareMem (LoadOption->FilePath, FilePath, GetDevicePathSize (FilePath)) != 0) {
+ DEBUG ((EFI_D_INFO, "[Bds] DevicePath expand: "));
+ BmPrintDp (LoadOption->FilePath);
+ DEBUG ((EFI_D_INFO, " -> "));
+ BmPrintDp (FilePath);
+ DEBUG ((EFI_D_INFO, "\n"));
+ }
+ );
+ if (BmIsLoadOptionPeHeaderValid (LoadOption->OptionType, FileBuffer, FileSize)) {
+ Status = gBS->LoadImage (
+ FALSE,
+ gImageHandle,
+ FilePath,
+ FileBuffer,
+ FileSize,
+ &ImageHandle
+ );
+ }
+ if (FilePath != NULL) {
+ FreePool (FilePath);
+ }
+ if (FileBuffer != NULL) {
+ FreePool (FileBuffer);
+ }
+
+ if (!EFI_ERROR (Status)) {
+ Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &ImageInfo);
+ ASSERT_EFI_ERROR (Status);
+
+ ImageInfo->LoadOptionsSize = LoadOption->OptionalDataSize;
+ ImageInfo->LoadOptions = LoadOption->OptionalData;
+ //
+ // Before calling the image, enable the Watchdog Timer for the 5-minute period
+ //
+ gBS->SetWatchdogTimer (5 * 60, 0, 0, NULL);
+
+ LoadOption->Status = gBS->StartImage (ImageHandle, &LoadOption->ExitDataSize, &LoadOption->ExitData);
+ DEBUG ((
+ DEBUG_INFO | DEBUG_LOAD, "Load Option (%s%04x) Return Status = %r\n",
+ mBmLoadOptionName[LoadOption->OptionType], LoadOption->OptionNumber, LoadOption->Status
+ ));
+
+ //
+ // Clear the Watchdog Timer after the image returns
+ //
+ gBS->SetWatchdogTimer (0, 0, 0, NULL);
+ }
+
+ return Status;
+}
diff --git a/Core/MdeModulePkg/Library/UefiBootManagerLib/BmMisc.c b/Core/MdeModulePkg/Library/UefiBootManagerLib/BmMisc.c
new file mode 100644
index 0000000000..e675904857
--- /dev/null
+++ b/Core/MdeModulePkg/Library/UefiBootManagerLib/BmMisc.c
@@ -0,0 +1,391 @@
+/** @file
+ Misc library functions.
+
+Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "InternalBm.h"
+
+/**
+ Delete the instance in Multi which matches partly with Single instance
+
+ @param Multi A pointer to a multi-instance device path data
+ structure.
+ @param Single A pointer to a single-instance device path data
+ structure.
+
+ @return This function will remove the device path instances in Multi which partly
+ match with the Single, and return the result device path. If there is no
+ remaining device path as a result, this function will return NULL.
+
+**/
+EFI_DEVICE_PATH_PROTOCOL *
+BmDelPartMatchInstance (
+ IN EFI_DEVICE_PATH_PROTOCOL *Multi,
+ IN EFI_DEVICE_PATH_PROTOCOL *Single
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *Instance;
+ EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *TempNewDevicePath;
+ UINTN InstanceSize;
+ UINTN SingleDpSize;
+
+ NewDevicePath = NULL;
+ TempNewDevicePath = NULL;
+
+ if (Multi == NULL || Single == NULL) {
+ return Multi;
+ }
+
+ Instance = GetNextDevicePathInstance (&Multi, &InstanceSize);
+ SingleDpSize = GetDevicePathSize (Single) - END_DEVICE_PATH_LENGTH;
+ InstanceSize -= END_DEVICE_PATH_LENGTH;
+
+ while (Instance != NULL) {
+
+ if (CompareMem (Instance, Single, MIN (SingleDpSize, InstanceSize)) != 0) {
+ //
+ // Append the device path instance which does not match with Single
+ //
+ TempNewDevicePath = NewDevicePath;
+ NewDevicePath = AppendDevicePathInstance (NewDevicePath, Instance);
+ if (TempNewDevicePath != NULL) {
+ FreePool(TempNewDevicePath);
+ }
+ }
+ FreePool(Instance);
+ Instance = GetNextDevicePathInstance (&Multi, &InstanceSize);
+ InstanceSize -= END_DEVICE_PATH_LENGTH;
+ }
+
+ return NewDevicePath;
+}
+
+/**
+ Function compares a device path data structure to that of all the nodes of a
+ second device path instance.
+
+ @param Multi A pointer to a multi-instance device path data
+ structure.
+ @param Single A pointer to a single-instance device path data
+ structure.
+
+ @retval TRUE If the Single device path is contained within Multi device path.
+ @retval FALSE The Single device path is not match within Multi device path.
+
+**/
+BOOLEAN
+BmMatchDevicePaths (
+ IN EFI_DEVICE_PATH_PROTOCOL *Multi,
+ IN EFI_DEVICE_PATH_PROTOCOL *Single
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePathInst;
+ UINTN Size;
+
+ if (Multi == NULL || Single == NULL) {
+ return FALSE;
+ }
+
+ DevicePath = Multi;
+ DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size);
+
+ //
+ // Search for the match of 'Single' in 'Multi'
+ //
+ while (DevicePathInst != NULL) {
+ //
+ // If the single device path is found in multiple device paths,
+ // return success
+ //
+ if (CompareMem (Single, DevicePathInst, Size) == 0) {
+ FreePool (DevicePathInst);
+ return TRUE;
+ }
+
+ FreePool (DevicePathInst);
+ DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size);
+ }
+
+ return FALSE;
+}
+
+/**
+ This routine adjust the memory information for different memory type and
+ save them into the variables for next boot. It resets the system when
+ memory information is updated and the current boot option belongs to
+ boot category instead of application category.
+
+ @param Boot TRUE if current boot option belongs to boot category instead of
+ application category.
+**/
+VOID
+BmSetMemoryTypeInformationVariable (
+ IN BOOLEAN Boot
+ )
+{
+ EFI_STATUS Status;
+ EFI_MEMORY_TYPE_INFORMATION *PreviousMemoryTypeInformation;
+ EFI_MEMORY_TYPE_INFORMATION *CurrentMemoryTypeInformation;
+ UINTN VariableSize;
+ UINTN Index;
+ UINTN Index1;
+ UINT32 Previous;
+ UINT32 Current;
+ UINT32 Next;
+ EFI_HOB_GUID_TYPE *GuidHob;
+ BOOLEAN MemoryTypeInformationModified;
+ BOOLEAN MemoryTypeInformationVariableExists;
+ EFI_BOOT_MODE BootMode;
+
+ MemoryTypeInformationModified = FALSE;
+ MemoryTypeInformationVariableExists = FALSE;
+
+
+ BootMode = GetBootModeHob ();
+ //
+ // In BOOT_IN_RECOVERY_MODE, Variable region is not reliable.
+ //
+ if (BootMode == BOOT_IN_RECOVERY_MODE) {
+ return;
+ }
+
+ //
+ // Only check the the Memory Type Information variable in the boot mode
+ // other than BOOT_WITH_DEFAULT_SETTINGS because the Memory Type
+ // Information is not valid in this boot mode.
+ //
+ if (BootMode != BOOT_WITH_DEFAULT_SETTINGS) {
+ VariableSize = 0;
+ Status = gRT->GetVariable (
+ EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME,
+ &gEfiMemoryTypeInformationGuid,
+ NULL,
+ &VariableSize,
+ NULL
+ );
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ MemoryTypeInformationVariableExists = TRUE;
+ }
+ }
+
+ //
+ // Retrieve the current memory usage statistics. If they are not found, then
+ // no adjustments can be made to the Memory Type Information variable.
+ //
+ Status = EfiGetSystemConfigurationTable (
+ &gEfiMemoryTypeInformationGuid,
+ (VOID **) &CurrentMemoryTypeInformation
+ );
+ if (EFI_ERROR (Status) || CurrentMemoryTypeInformation == NULL) {
+ return;
+ }
+
+ //
+ // Get the Memory Type Information settings from Hob if they exist,
+ // PEI is responsible for getting them from variable and build a Hob to save them.
+ // If the previous Memory Type Information is not available, then set defaults
+ //
+ GuidHob = GetFirstGuidHob (&gEfiMemoryTypeInformationGuid);
+ if (GuidHob == NULL) {
+ //
+ // If Platform has not built Memory Type Info into the Hob, just return.
+ //
+ return;
+ }
+ PreviousMemoryTypeInformation = GET_GUID_HOB_DATA (GuidHob);
+ VariableSize = GET_GUID_HOB_DATA_SIZE (GuidHob);
+
+ //
+ // Use a heuristic to adjust the Memory Type Information for the next boot
+ //
+ DEBUG ((EFI_D_INFO, "Memory Previous Current Next \n"));
+ DEBUG ((EFI_D_INFO, " Type Pages Pages Pages \n"));
+ DEBUG ((EFI_D_INFO, "====== ======== ======== ========\n"));
+
+ for (Index = 0; PreviousMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {
+
+ for (Index1 = 0; CurrentMemoryTypeInformation[Index1].Type != EfiMaxMemoryType; Index1++) {
+ if (PreviousMemoryTypeInformation[Index].Type == CurrentMemoryTypeInformation[Index1].Type) {
+ break;
+ }
+ }
+ if (CurrentMemoryTypeInformation[Index1].Type == EfiMaxMemoryType) {
+ continue;
+ }
+
+ //
+ // Previous is the number of pages pre-allocated
+ // Current is the number of pages actually needed
+ //
+ Previous = PreviousMemoryTypeInformation[Index].NumberOfPages;
+ Current = CurrentMemoryTypeInformation[Index1].NumberOfPages;
+ Next = Previous;
+
+ //
+ // Inconsistent Memory Reserved across bootings may lead to S4 fail
+ // Write next varible to 125% * current when the pre-allocated memory is:
+ // 1. More than 150% of needed memory and boot mode is BOOT_WITH_DEFAULT_SETTING
+ // 2. Less than the needed memory
+ //
+ if ((Current + (Current >> 1)) < Previous) {
+ if (BootMode == BOOT_WITH_DEFAULT_SETTINGS) {
+ Next = Current + (Current >> 2);
+ }
+ } else if (Current > Previous) {
+ Next = Current + (Current >> 2);
+ }
+ if (Next > 0 && Next < 4) {
+ Next = 4;
+ }
+
+ if (Next != Previous) {
+ PreviousMemoryTypeInformation[Index].NumberOfPages = Next;
+ MemoryTypeInformationModified = TRUE;
+ }
+
+ DEBUG ((EFI_D_INFO, " %02x %08x %08x %08x\n", PreviousMemoryTypeInformation[Index].Type, Previous, Current, Next));
+ }
+
+ //
+ // If any changes were made to the Memory Type Information settings, then set the new variable value;
+ // Or create the variable in first boot.
+ //
+ if (MemoryTypeInformationModified || !MemoryTypeInformationVariableExists) {
+ Status = BmSetVariableAndReportStatusCodeOnError (
+ EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME,
+ &gEfiMemoryTypeInformationGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ VariableSize,
+ PreviousMemoryTypeInformation
+ );
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // If the Memory Type Information settings have been modified and the boot option belongs to boot category,
+ // then reset the platform so the new Memory Type Information setting will be used to guarantee that an S4
+ // entry/resume cycle will not fail.
+ //
+ if (MemoryTypeInformationModified && Boot && PcdGetBool (PcdResetOnMemoryTypeInformationChange)) {
+ DEBUG ((EFI_D_INFO, "Memory Type Information settings change. Warm Reset!!!\n"));
+ gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL);
+ }
+ } else {
+ DEBUG ((EFI_D_ERROR, "Memory Type Information settings cannot be saved. OS S4 may fail!\n"));
+ }
+ }
+}
+
+/**
+ Set the variable and report the error through status code upon failure.
+
+ @param VariableName A Null-terminated string that is the name of the vendor's variable.
+ Each VariableName is unique for each VendorGuid. VariableName must
+ contain 1 or more characters. If VariableName is an empty string,
+ then EFI_INVALID_PARAMETER is returned.
+ @param VendorGuid A unique identifier for the vendor.
+ @param Attributes Attributes bitmask to set for the variable.
+ @param DataSize The size in bytes of the Data buffer. Unless the EFI_VARIABLE_APPEND_WRITE,
+ EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, or
+ EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute is set, a size of zero
+ causes the variable to be deleted. When the EFI_VARIABLE_APPEND_WRITE attribute is
+ set, then a SetVariable() call with a DataSize of zero will not cause any change to
+ the variable value (the timestamp associated with the variable may be updated however
+ even if no new data value is provided,see the description of the
+ EFI_VARIABLE_AUTHENTICATION_2 descriptor below. In this case the DataSize will not
+ be zero since the EFI_VARIABLE_AUTHENTICATION_2 descriptor will be populated).
+ @param Data The contents for the variable.
+
+ @retval EFI_SUCCESS The firmware has successfully stored the variable and its data as
+ defined by the Attributes.
+ @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits, name, and GUID was supplied, or the
+ DataSize exceeds the maximum allowed.
+ @retval EFI_INVALID_PARAMETER VariableName is an empty string.
+ @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the variable and its data.
+ @retval EFI_DEVICE_ERROR The variable could not be retrieved due to a hardware error.
+ @retval EFI_WRITE_PROTECTED The variable in question is read-only.
+ @retval EFI_WRITE_PROTECTED The variable in question cannot be deleted.
+ @retval EFI_SECURITY_VIOLATION The variable could not be written due to EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
+ or EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACESS being set, but the AuthInfo
+ does NOT pass the validation check carried out by the firmware.
+
+ @retval EFI_NOT_FOUND The variable trying to be updated or deleted was not found.
+**/
+EFI_STATUS
+BmSetVariableAndReportStatusCodeOnError (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN UINT32 Attributes,
+ IN UINTN DataSize,
+ IN VOID *Data
+ )
+{
+ EFI_STATUS Status;
+ EDKII_SET_VARIABLE_STATUS *SetVariableStatus;
+ UINTN NameSize;
+
+ Status = gRT->SetVariable (
+ VariableName,
+ VendorGuid,
+ Attributes,
+ DataSize,
+ Data
+ );
+ if (EFI_ERROR (Status)) {
+ NameSize = StrSize (VariableName);
+ SetVariableStatus = AllocatePool (sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + DataSize);
+ if (SetVariableStatus != NULL) {
+ CopyGuid (&SetVariableStatus->Guid, VendorGuid);
+ SetVariableStatus->NameSize = NameSize;
+ SetVariableStatus->DataSize = DataSize;
+ SetVariableStatus->SetStatus = Status;
+ SetVariableStatus->Attributes = Attributes;
+ CopyMem (SetVariableStatus + 1, VariableName, NameSize);
+ CopyMem (((UINT8 *) (SetVariableStatus + 1)) + NameSize, Data, DataSize);
+
+ REPORT_STATUS_CODE_EX (
+ EFI_ERROR_CODE,
+ PcdGet32 (PcdErrorCodeSetVariable),
+ 0,
+ NULL,
+ &gEdkiiStatusCodeDataTypeVariableGuid,
+ SetVariableStatus,
+ sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + DataSize
+ );
+
+ FreePool (SetVariableStatus);
+ }
+ }
+
+ return Status;
+}
+
+
+/**
+ Print the device path info.
+
+ @param DevicePath The device path need to print.
+**/
+VOID
+BmPrintDp (
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ CHAR16 *Str;
+
+ Str = ConvertDevicePathToText (DevicePath, FALSE, FALSE);
+ DEBUG ((EFI_D_INFO, "%s", Str));
+ if (Str != NULL) {
+ FreePool (Str);
+ }
+}
diff --git a/Core/MdeModulePkg/Library/UefiBootManagerLib/BmPerformance.c b/Core/MdeModulePkg/Library/UefiBootManagerLib/BmPerformance.c
new file mode 100644
index 0000000000..0abd019440
--- /dev/null
+++ b/Core/MdeModulePkg/Library/UefiBootManagerLib/BmPerformance.c
@@ -0,0 +1,317 @@
+/** @file
+ This file include the file which can help to get the system
+ performance, all the function will only include if the performance
+ switch is set.
+
+Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "InternalBm.h"
+
+PERF_HEADER mBmPerfHeader;
+PERF_DATA mBmPerfData;
+EFI_PHYSICAL_ADDRESS mBmAcpiLowMemoryBase = 0x0FFFFFFFFULL;
+
+/**
+ Get the short verion of PDB file name to be
+ used in performance data logging.
+
+ @param PdbFileName The long PDB file name.
+ @param GaugeString The output string to be logged by performance logger.
+ @param StringSize The buffer size of GaugeString in bytes.
+
+**/
+VOID
+BmGetShortPdbFileName (
+ IN CONST CHAR8 *PdbFileName,
+ OUT CHAR8 *GaugeString,
+ IN UINTN StringSize
+ )
+{
+ UINTN Index;
+ UINTN Index1;
+ UINTN StartIndex;
+ UINTN EndIndex;
+
+ if (PdbFileName == NULL) {
+ AsciiStrCpyS (GaugeString, StringSize, " ");
+ } else {
+ StartIndex = 0;
+ for (EndIndex = 0; PdbFileName[EndIndex] != 0; EndIndex++)
+ ;
+
+ for (Index = 0; PdbFileName[Index] != 0; Index++) {
+ if (PdbFileName[Index] == '\\') {
+ StartIndex = Index + 1;
+ }
+
+ if (PdbFileName[Index] == '.') {
+ EndIndex = Index;
+ }
+ }
+
+ Index1 = 0;
+ for (Index = StartIndex; Index < EndIndex; Index++) {
+ GaugeString[Index1] = PdbFileName[Index];
+ Index1++;
+ if (Index1 == StringSize - 1) {
+ break;
+ }
+ }
+
+ GaugeString[Index1] = 0;
+ }
+
+ return ;
+}
+
+/**
+ Get the name from the Driver handle, which can be a handle with
+ EFI_LOADED_IMAGE_PROTOCOL or EFI_DRIVER_BINDING_PROTOCOL installed.
+ This name can be used in performance data logging.
+
+ @param Handle Driver handle.
+ @param GaugeString The output string to be logged by performance logger.
+ @param StringSize The buffer size of GaugeString in bytes.
+
+**/
+VOID
+BmGetNameFromHandle (
+ IN EFI_HANDLE Handle,
+ OUT CHAR8 *GaugeString,
+ IN UINTN StringSize
+ )
+{
+ EFI_STATUS Status;
+ EFI_LOADED_IMAGE_PROTOCOL *Image;
+ CHAR8 *PdbFileName;
+ EFI_DRIVER_BINDING_PROTOCOL *DriverBinding;
+
+ AsciiStrCpyS (GaugeString, StringSize, " ");
+
+ //
+ // Get handle name from image protocol
+ //
+ Status = gBS->HandleProtocol (
+ Handle,
+ &gEfiLoadedImageProtocolGuid,
+ (VOID **) &Image
+ );
+
+ if (EFI_ERROR (Status)) {
+ Status = gBS->OpenProtocol (
+ Handle,
+ &gEfiDriverBindingProtocolGuid,
+ (VOID **) &DriverBinding,
+ NULL,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return ;
+ }
+ //
+ // Get handle name from image protocol
+ //
+ Status = gBS->HandleProtocol (
+ DriverBinding->ImageHandle,
+ &gEfiLoadedImageProtocolGuid,
+ (VOID **) &Image
+ );
+ }
+
+ PdbFileName = PeCoffLoaderGetPdbPointer (Image->ImageBase);
+
+ if (PdbFileName != NULL) {
+ BmGetShortPdbFileName (PdbFileName, GaugeString, StringSize);
+ }
+
+ return ;
+}
+
+/**
+
+ Writes performance data of booting into the allocated memory.
+ OS can process these records.
+
+ @param Event The triggered event.
+ @param Context Context for this event.
+
+**/
+VOID
+EFIAPI
+BmWriteBootToOsPerformanceData (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ UINT32 LimitCount;
+ EFI_HANDLE *Handles;
+ UINTN NoHandles;
+ CHAR8 GaugeString[PERF_TOKEN_SIZE];
+ UINT8 *Ptr;
+ UINT32 Index;
+ UINT64 Ticker;
+ UINT64 Freq;
+ UINT32 Duration;
+ UINTN LogEntryKey;
+ CONST VOID *Handle;
+ CONST CHAR8 *Token;
+ CONST CHAR8 *Module;
+ UINT64 StartTicker;
+ UINT64 EndTicker;
+ UINT64 StartValue;
+ UINT64 EndValue;
+ BOOLEAN CountUp;
+ UINTN VarSize;
+ BOOLEAN Found;
+
+ //
+ // Record the performance data for End of BDS
+ //
+ PERF_END(NULL, "BDS", NULL, 0);
+
+ //
+ // Retrieve time stamp count as early as possible
+ //
+ Ticker = GetPerformanceCounter ();
+
+ Freq = GetPerformanceCounterProperties (&StartValue, &EndValue);
+
+ Freq = DivU64x32 (Freq, 1000);
+
+ mBmPerfHeader.CpuFreq = Freq;
+
+ //
+ // Record BDS raw performance data
+ //
+ if (EndValue >= StartValue) {
+ mBmPerfHeader.BDSRaw = Ticker - StartValue;
+ CountUp = TRUE;
+ } else {
+ mBmPerfHeader.BDSRaw = StartValue - Ticker;
+ CountUp = FALSE;
+ }
+
+ //
+ // Reset the entry count
+ //
+ mBmPerfHeader.Count = 0;
+
+ if (mBmAcpiLowMemoryBase == 0x0FFFFFFFF) {
+ VarSize = sizeof (EFI_PHYSICAL_ADDRESS);
+ Status = gRT->GetVariable (
+ L"PerfDataMemAddr",
+ &gPerformanceProtocolGuid,
+ NULL,
+ &VarSize,
+ &mBmAcpiLowMemoryBase
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Fail to get the variable, return.
+ //
+ return;
+ }
+ }
+
+ //
+ // Put Detailed performance data into memory
+ //
+ Handles = NULL;
+ Status = gBS->LocateHandleBuffer (
+ AllHandles,
+ NULL,
+ NULL,
+ &NoHandles,
+ &Handles
+ );
+ if (EFI_ERROR (Status)) {
+ return ;
+ }
+
+ Ptr = (UINT8 *) ((UINT32) mBmAcpiLowMemoryBase + sizeof (PERF_HEADER));
+ LimitCount = (UINT32) (PERF_DATA_MAX_LENGTH - sizeof (PERF_HEADER)) / sizeof (PERF_DATA);
+
+ //
+ // Get performance data
+ //
+ LogEntryKey = 0;
+ while ((LogEntryKey = GetPerformanceMeasurement (
+ LogEntryKey,
+ &Handle,
+ &Token,
+ &Module,
+ &StartTicker,
+ &EndTicker)) != 0) {
+ if (EndTicker != 0) {
+ if (StartTicker == 1) {
+ StartTicker = StartValue;
+ }
+ if (EndTicker == 1) {
+ EndTicker = StartValue;
+ }
+ Ticker = CountUp ? (EndTicker - StartTicker) : (StartTicker - EndTicker);
+
+ Duration = (UINT32) DivU64x32 (Ticker, (UINT32) Freq);
+ if (Duration == 0) {
+ continue;
+ }
+
+ ZeroMem (&mBmPerfData, sizeof (PERF_DATA));
+
+ mBmPerfData.Duration = Duration;
+
+ //
+ // See if the Handle is in the handle buffer
+ //
+ Found = FALSE;
+ for (Index = 0; Index < NoHandles; Index++) {
+ if (Handle == Handles[Index]) {
+ BmGetNameFromHandle (Handles[Index], GaugeString, PERF_TOKEN_SIZE);
+ AsciiStrCpyS (mBmPerfData.Token, PERF_TOKEN_SIZE, GaugeString);
+ Found = TRUE;
+ break;
+ }
+ }
+
+ if (!Found) {
+ AsciiStrnCpyS (mBmPerfData.Token, PERF_TOKEN_SIZE, Token, PERF_TOKEN_LENGTH);
+ }
+
+ CopyMem (Ptr, &mBmPerfData, sizeof (PERF_DATA));
+ Ptr += sizeof (PERF_DATA);
+
+ mBmPerfHeader.Count++;
+ if (mBmPerfHeader.Count == LimitCount) {
+ goto Done;
+ }
+ }
+ }
+
+Done:
+
+ FreePool (Handles);
+
+ mBmPerfHeader.Signiture = PERFORMANCE_SIGNATURE;
+
+ //
+ // Put performance data to Reserved memory
+ //
+ CopyMem (
+ (UINTN *) (UINTN) mBmAcpiLowMemoryBase,
+ &mBmPerfHeader,
+ sizeof (PERF_HEADER)
+ );
+
+ return ;
+}
diff --git a/Core/MdeModulePkg/Library/UefiBootManagerLib/InternalBm.h b/Core/MdeModulePkg/Library/UefiBootManagerLib/InternalBm.h
new file mode 100644
index 0000000000..c808ed2ffe
--- /dev/null
+++ b/Core/MdeModulePkg/Library/UefiBootManagerLib/InternalBm.h
@@ -0,0 +1,454 @@
+/** @file
+ BDS library definition, include the file and data structure
+
+Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _INTERNAL_BM_H_
+#define _INTERNAL_BM_H_
+
+#include <PiDxe.h>
+
+#include <IndustryStandard/Pci.h>
+#include <IndustryStandard/PeImage.h>
+#include <IndustryStandard/Atapi.h>
+#include <IndustryStandard/Scsi.h>
+
+#include <Protocol/PciRootBridgeIo.h>
+#include <Protocol/BlockIo.h>
+#include <Protocol/LoadedImage.h>
+#include <Protocol/SimpleFileSystem.h>
+#include <Protocol/LoadFile.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/SimpleTextIn.h>
+#include <Protocol/SimpleTextInEx.h>
+#include <Protocol/SimpleTextOut.h>
+#include <Protocol/SimpleNetwork.h>
+#include <Protocol/FirmwareVolume2.h>
+#include <Protocol/PciIo.h>
+#include <Protocol/GraphicsOutput.h>
+#include <Protocol/UsbIo.h>
+#include <Protocol/DiskInfo.h>
+#include <Protocol/IdeControllerInit.h>
+#include <Protocol/BootLogo.h>
+#include <Protocol/DriverHealth.h>
+#include <Protocol/FormBrowser2.h>
+
+#include <Guid/ZeroGuid.h>
+#include <Guid/MemoryTypeInformation.h>
+#include <Guid/FileInfo.h>
+#include <Guid/GlobalVariable.h>
+#include <Guid/Performance.h>
+#include <Guid/StatusCodeDataTypeVariable.h>
+
+#include <Library/PrintLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/HobLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/PerformanceLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PeCoffGetEntryPointLib.h>
+#include <Library/UefiBootManagerLib.h>
+#include <Library/TimerLib.h>
+#include <Library/DxeServicesLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/CapsuleLib.h>
+#include <Library/PerformanceLib.h>
+#include <Library/HiiLib.h>
+
+#if !defined (EFI_REMOVABLE_MEDIA_FILE_NAME)
+ #if defined (MDE_CPU_EBC)
+ //
+ // Uefi specification only defines the default boot file name for IA32, X64
+ // and IPF processor, so need define boot file name for EBC architecture here.
+ //
+ #define EFI_REMOVABLE_MEDIA_FILE_NAME L"\\EFI\\BOOT\\BOOTEBC.EFI"
+ #else
+ #error "Can not determine the default boot file name for unknown processor type!"
+ #endif
+#endif
+
+typedef enum {
+ BmAcpiFloppyBoot,
+ BmHardwareDeviceBoot,
+ BmMessageAtapiBoot,
+ BmMessageSataBoot,
+ BmMessageUsbBoot,
+ BmMessageScsiBoot,
+ BmMessageNetworkBoot,
+ BmMessageHttpBoot,
+ BmMiscBoot
+} BM_BOOT_TYPE;
+
+typedef
+CHAR16 *
+(* BM_GET_BOOT_DESCRIPTION) (
+ IN EFI_HANDLE Handle
+ );
+
+#define BM_OPTION_NAME_LEN sizeof ("SysPrep####")
+extern CHAR16 *mBmLoadOptionName[];
+
+typedef
+VOID
+(*VARIABLE_VISITOR) (
+ CHAR16 *Name,
+ EFI_GUID *Guid,
+ VOID *Context
+ );
+
+/**
+ Call Visitor function for each variable in variable storage.
+
+ @param Visitor Visitor function.
+ @param Context The context passed to Visitor function.
+**/
+VOID
+ForEachVariable (
+ VARIABLE_VISITOR Visitor,
+ VOID *Context
+ );
+
+#define BM_BOOT_DESCRIPTION_ENTRY_SIGNATURE SIGNATURE_32 ('b', 'm', 'd', 'h')
+typedef struct {
+ UINT32 Signature;
+ LIST_ENTRY Link;
+ EFI_BOOT_MANAGER_BOOT_DESCRIPTION_HANDLER Handler;
+} BM_BOOT_DESCRIPTION_ENTRY;
+
+/**
+ Repair all the controllers according to the Driver Health status queried.
+**/
+VOID
+BmRepairAllControllers (
+ VOID
+ );
+
+#define BM_HOTKEY_SIGNATURE SIGNATURE_32 ('b', 'm', 'h', 'k')
+typedef struct {
+ UINT32 Signature;
+ LIST_ENTRY Link;
+
+ BOOLEAN IsContinue;
+ UINT16 BootOption;
+ UINT8 CodeCount;
+ UINT8 WaitingKey;
+ EFI_KEY_DATA KeyData[3];
+} BM_HOTKEY;
+
+#define BM_HOTKEY_FROM_LINK(a) CR (a, BM_HOTKEY, Link, BM_HOTKEY_SIGNATURE)
+
+/**
+ Get the image file buffer data and buffer size by its device path.
+
+ @param FilePath On input, a pointer to an allocated buffer containing the device
+ path of the file.
+ On output the pointer could be NULL when the function fails to
+ load the boot option, or could point to an allocated buffer containing
+ the device path of the file.
+ It could be updated by either short-form device path expanding,
+ or default boot file path appending.
+ Caller is responsible to free it when it's non-NULL.
+ @param FileSize A pointer to the size of the file buffer.
+
+ @retval NULL File is NULL, or FileSize is NULL. Or, the file can't be found.
+ @retval other The file buffer. The caller is responsible to free the memory.
+**/
+VOID *
+BmLoadEfiBootOption (
+ IN OUT EFI_DEVICE_PATH_PROTOCOL **FilePath,
+ OUT UINTN *FileSize
+ );
+
+/**
+ Get the Option Number that wasn't used.
+
+ @param LoadOptionType Load option type.
+ @param FreeOptionNumber To receive the minimal free option number.
+
+ @retval EFI_SUCCESS The option number is found
+ @retval EFI_OUT_OF_RESOURCES There is no free option number that can be used.
+ @retval EFI_INVALID_PARAMETER FreeOptionNumber is NULL
+
+**/
+EFI_STATUS
+BmGetFreeOptionNumber (
+ IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LoadOptionType,
+ OUT UINT16 *FreeOptionNumber
+ );
+
+/**
+
+ Writes performance data of booting into the allocated memory.
+ OS can process these records.
+
+ @param Event The triggered event.
+ @param Context Context for this event.
+
+**/
+VOID
+EFIAPI
+BmWriteBootToOsPerformanceData (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+
+/**
+ Get the headers (dos, image, optional header) from an image
+
+ @param Device SimpleFileSystem device handle
+ @param FileName File name for the image
+ @param DosHeader Pointer to dos header
+ @param Hdr The buffer in which to return the PE32, PE32+, or TE header.
+
+ @retval EFI_SUCCESS Successfully get the machine type.
+ @retval EFI_NOT_FOUND The file is not found.
+ @retval EFI_LOAD_ERROR File is not a valid image file.
+
+**/
+EFI_STATUS
+BmGetImageHeader (
+ IN EFI_HANDLE Device,
+ IN CHAR16 *FileName,
+ OUT EFI_IMAGE_DOS_HEADER *DosHeader,
+ OUT EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
+ );
+
+/**
+ This routine adjust the memory information for different memory type and
+ save them into the variables for next boot. It resets the system when
+ memory information is updated and the current boot option belongs to
+ boot category instead of application category.
+
+ @param Boot TRUE if current boot option belongs to boot category instead of
+ application category.
+**/
+VOID
+BmSetMemoryTypeInformationVariable (
+ IN BOOLEAN Boot
+ );
+
+/**
+ Check whether there is a instance in BlockIoDevicePath, which contain multi device path
+ instances, has the same partition node with HardDriveDevicePath device path
+
+ @param BlockIoDevicePath Multi device path instances which need to check
+ @param HardDriveDevicePath A device path which starts with a hard drive media
+ device path.
+
+ @retval TRUE There is a matched device path instance.
+ @retval FALSE There is no matched device path instance.
+
+**/
+BOOLEAN
+BmMatchPartitionDevicePathNode (
+ IN EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath,
+ IN HARDDRIVE_DEVICE_PATH *HardDriveDevicePath
+ );
+
+/**
+ Connect the specific Usb device which match the short form device path.
+
+ @param DevicePath A short-form device path that starts with the first
+ element being a USB WWID or a USB Class device
+ path
+
+ @return EFI_INVALID_PARAMETER DevicePath is NULL pointer.
+ DevicePath is not a USB device path.
+
+ @return EFI_SUCCESS Success to connect USB device
+ @return EFI_NOT_FOUND Fail to find handle for USB controller to connect.
+
+**/
+EFI_STATUS
+BmConnectUsbShortFormDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ );
+
+/**
+ Stop the hotkey processing.
+
+ @param Event Event pointer related to hotkey service.
+ @param Context Context pass to this function.
+**/
+VOID
+EFIAPI
+BmStopHotkeyService (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+/**
+ Set the variable and report the error through status code upon failure.
+
+ @param VariableName A Null-terminated string that is the name of the vendor's variable.
+ Each VariableName is unique for each VendorGuid. VariableName must
+ contain 1 or more characters. If VariableName is an empty string,
+ then EFI_INVALID_PARAMETER is returned.
+ @param VendorGuid A unique identifier for the vendor.
+ @param Attributes Attributes bitmask to set for the variable.
+ @param DataSize The size in bytes of the Data buffer. Unless the EFI_VARIABLE_APPEND_WRITE,
+ EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, or
+ EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute is set, a size of zero
+ causes the variable to be deleted. When the EFI_VARIABLE_APPEND_WRITE attribute is
+ set, then a SetVariable() call with a DataSize of zero will not cause any change to
+ the variable value (the timestamp associated with the variable may be updated however
+ even if no new data value is provided,see the description of the
+ EFI_VARIABLE_AUTHENTICATION_2 descriptor below. In this case the DataSize will not
+ be zero since the EFI_VARIABLE_AUTHENTICATION_2 descriptor will be populated).
+ @param Data The contents for the variable.
+
+ @retval EFI_SUCCESS The firmware has successfully stored the variable and its data as
+ defined by the Attributes.
+ @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits, name, and GUID was supplied, or the
+ DataSize exceeds the maximum allowed.
+ @retval EFI_INVALID_PARAMETER VariableName is an empty string.
+ @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the variable and its data.
+ @retval EFI_DEVICE_ERROR The variable could not be retrieved due to a hardware error.
+ @retval EFI_WRITE_PROTECTED The variable in question is read-only.
+ @retval EFI_WRITE_PROTECTED The variable in question cannot be deleted.
+ @retval EFI_SECURITY_VIOLATION The variable could not be written due to EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
+ or EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACESS being set, but the AuthInfo
+ does NOT pass the validation check carried out by the firmware.
+
+ @retval EFI_NOT_FOUND The variable trying to be updated or deleted was not found.
+**/
+EFI_STATUS
+BmSetVariableAndReportStatusCodeOnError (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN UINT32 Attributes,
+ IN UINTN DataSize,
+ IN VOID *Data
+ );
+
+/**
+ Get the load option by its device path.
+
+ @param FilePath The device path pointing to a load option.
+ It could be a short-form device path.
+ @param FullPath Return the full device path of the load option after
+ short-form device path expanding.
+ Caller is responsible to free it.
+ @param FileSize Return the load option size.
+
+ @return The load option buffer. Caller is responsible to free the memory.
+**/
+VOID *
+BmGetLoadOptionBuffer (
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
+ OUT UINTN *FileSize
+ );
+
+/**
+ Return whether the PE header of the load option is valid or not.
+
+ @param[in] Type The load option type.
+ @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
+ );
+
+/**
+ Function compares a device path data structure to that of all the nodes of a
+ second device path instance.
+
+ @param Multi A pointer to a multi-instance device path data
+ structure.
+ @param Single A pointer to a single-instance device path data
+ structure.
+
+ @retval TRUE If the Single device path is contained within Multi device path.
+ @retval FALSE The Single device path is not match within Multi device path.
+
+**/
+BOOLEAN
+BmMatchDevicePaths (
+ IN EFI_DEVICE_PATH_PROTOCOL *Multi,
+ IN EFI_DEVICE_PATH_PROTOCOL *Single
+ );
+
+/**
+ Delete the instance in Multi which matches partly with Single instance
+
+ @param Multi A pointer to a multi-instance device path data
+ structure.
+ @param Single A pointer to a single-instance device path data
+ structure.
+
+ @return This function will remove the device path instances in Multi which partly
+ match with the Single, and return the result device path. If there is no
+ remaining device path as a result, this function will return NULL.
+
+**/
+EFI_DEVICE_PATH_PROTOCOL *
+BmDelPartMatchInstance (
+ IN EFI_DEVICE_PATH_PROTOCOL *Multi,
+ IN EFI_DEVICE_PATH_PROTOCOL *Single
+ );
+
+
+/**
+ Return the index of the load option in the load option array.
+
+ The function consider two load options are equal when the
+ OptionType, Attributes, Description, FilePath and OptionalData are equal.
+
+ @param Key Pointer to the load option to be found.
+ @param Array Pointer to the array of load options to be found.
+ @param Count Number of entries in the Array.
+
+ @retval -1 Key wasn't found in the Array.
+ @retval 0 ~ Count-1 The index of the Key in the Array.
+**/
+INTN
+BmFindLoadOption (
+ IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *Key,
+ IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *Array,
+ IN UINTN Count
+ );
+
+/**
+ Repair all the controllers according to the Driver Health status queried.
+**/
+VOID
+BmRepairAllControllers (
+ VOID
+ );
+
+/**
+ Print the device path info.
+
+ @param DevicePath The device path need to print.
+**/
+VOID
+BmPrintDp (
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ );
+
+#endif // _INTERNAL_BM_H_
diff --git a/Core/MdeModulePkg/Library/UefiBootManagerLib/UefiBootManagerLib.inf b/Core/MdeModulePkg/Library/UefiBootManagerLib/UefiBootManagerLib.inf
new file mode 100644
index 0000000000..a2c6441dbe
--- /dev/null
+++ b/Core/MdeModulePkg/Library/UefiBootManagerLib/UefiBootManagerLib.inf
@@ -0,0 +1,117 @@
+## @file
+# Define and produce general Boot Manager related interfaces.
+#
+# The implementation provides richful library functions supporting load option
+# manipulation, hotkey registration, UEFI boot, connect/disconnect, console
+# manipulation, driver health checking and etc.
+#
+# Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = UefiBootManagerLib
+ MODULE_UNI_FILE = UefiBootManagerLib.uni
+ FILE_GUID = 8D4752BC-595E-49a2-B4AF-F3F57B601DE9
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = UefiBootManagerLib|DXE_DRIVER DXE_RUNTIME_DRIVER UEFI_APPLICATION UEFI_DRIVER
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ BmPerformance.c
+ BmConnect.c
+ BmMisc.c
+ BmConsole.c
+ BmBoot.c
+ BmLoadOption.c
+ BmHotkey.c
+ BmDriverHealth.c
+ InternalBm.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ HobLib
+ PcdLib
+ BaseLib
+ UefiLib
+ TimerLib
+ DebugLib
+ PrintLib
+ BaseMemoryLib
+ DevicePathLib
+ PerformanceLib
+ PeCoffGetEntryPointLib
+ UefiBootServicesTableLib
+ UefiRuntimeServicesTableLib
+ DxeServicesTableLib
+ MemoryAllocationLib
+ DxeServicesLib
+ ReportStatusCodeLib
+ PerformanceLib
+ HiiLib
+ SortLib
+
+[Guids]
+ gEfiMemoryTypeInformationGuid ## CONSUMES ## GUID (The identifier of memory type information type in system table)
+ ## CONSUMES ## GUID HOB (The hob holding memory type information)
+ gEfiGlobalVariableGuid ## SOMETIMES_PRODUCES ## Variable:L"BootCurrent" (The boot option of current boot)
+ ## SOMETIMES_CONSUMES ## Variable:L"BootXX" (Boot option variable)
+ ## CONSUMES ## Variable:L"Timeout" (The time out value in second of showing progress bar)
+ ## SOMETIMES_CONSUMES ## Variable:L"BootOrder" (The boot option array)
+ ## SOMETIMES_CONSUMES ## Variable:L"DriverOrder" (The driver order list)
+ ## SOMETIMES_CONSUMES ## Variable:L"ConIn" (The device path of console in device)
+ ## SOMETIMES_CONSUMES ## Variable:L"ConOut" (The device path of console out device)
+ ## SOMETIMES_CONSUMES ## Variable:L"ErrOut" (The device path of error out device)
+ gEfiFileInfoGuid ## CONSUMES ## GUID
+ gPerformanceProtocolGuid ## SOMETIMES_PRODUCES ## Variable:L"PerfDataMemAddr" (The ACPI address of performance data)
+ gEdkiiStatusCodeDataTypeVariableGuid ## SOMETIMES_CONSUMES ## GUID
+ gEfiDiskInfoAhciInterfaceGuid ## SOMETIMES_CONSUMES ## GUID
+ gEfiDiskInfoIdeInterfaceGuid ## SOMETIMES_CONSUMES ## GUID
+ gEfiDiskInfoScsiInterfaceGuid ## SOMETIMES_CONSUMES ## GUID
+ gZeroGuid ## CONSUMES ## GUID
+
+[Protocols]
+ gEfiPciRootBridgeIoProtocolGuid ## CONSUMES
+ gEfiSimpleFileSystemProtocolGuid ## CONSUMES
+ gEfiLoadFileProtocolGuid ## CONSUMES
+ gEfiSimpleTextOutProtocolGuid ## CONSUMES
+ gEfiPciIoProtocolGuid ## CONSUMES
+ gEfiLoadedImageProtocolGuid ## CONSUMES
+ gEfiSimpleNetworkProtocolGuid ## CONSUMES
+ gEfiSimpleTextInProtocolGuid ## CONSUMES
+ gEfiBlockIoProtocolGuid ## CONSUMES
+ gEfiFirmwareVolume2ProtocolGuid ## CONSUMES
+ gEfiDevicePathProtocolGuid ## CONSUMES
+ gEfiBootLogoProtocolGuid ## CONSUMES
+ gEfiSimpleTextInputExProtocolGuid ## CONSUMES
+ gEfiGraphicsOutputProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiUsbIoProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiDiskInfoProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiDriverHealthProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiFormBrowser2ProtocolGuid ## SOMETIMES_CONSUMES
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdResetOnMemoryTypeInformationChange ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdProgressCodeOsLoaderLoad ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdProgressCodeOsLoaderStart ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdErrorCodeSetVariable ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdBootManagerMenuFile ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdDriverHealthConfigureForm ## SOMETIMES_CONSUMES
+
diff --git a/Core/MdeModulePkg/Library/UefiBootManagerLib/UefiBootManagerLib.uni b/Core/MdeModulePkg/Library/UefiBootManagerLib/UefiBootManagerLib.uni
new file mode 100644
index 0000000000..961fdcada2
--- /dev/null
+++ b/Core/MdeModulePkg/Library/UefiBootManagerLib/UefiBootManagerLib.uni
Binary files differ
diff --git a/Core/MdeModulePkg/Library/UefiHiiLib/HiiLanguage.c b/Core/MdeModulePkg/Library/UefiHiiLib/HiiLanguage.c
new file mode 100644
index 0000000000..2519afa7d4
--- /dev/null
+++ b/Core/MdeModulePkg/Library/UefiHiiLib/HiiLanguage.c
@@ -0,0 +1,96 @@
+/** @file
+ Language related HII Library implementation.
+
+ Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+
+#include "InternalHiiLib.h"
+
+/**
+ Retrieves a pointer to the a Null-terminated ASCII string containing the list
+ of languages that an HII handle in the HII Database supports. The returned
+ string is allocated using AllocatePool(). The caller is responsible for freeing
+ the returned string using FreePool(). The format of the returned string follows
+ the language format assumed the HII Database.
+
+ If HiiHandle is NULL, then ASSERT().
+
+ @param[in] HiiHandle A handle that was previously registered in the HII Database.
+
+ @retval NULL HiiHandle is not registered in the HII database
+ @retval NULL There are not enough resources available to retrieve the suported
+ languages.
+ @retval NULL The list of suported languages could not be retrieved.
+ @retval Other A pointer to the Null-terminated ASCII string of supported languages.
+
+**/
+CHAR8 *
+EFIAPI
+HiiGetSupportedLanguages (
+ IN EFI_HII_HANDLE HiiHandle
+ )
+{
+ EFI_STATUS Status;
+ UINTN LanguageSize;
+ CHAR8 TempSupportedLanguages;
+ CHAR8 *SupportedLanguages;
+
+ ASSERT (HiiHandle != NULL);
+
+ //
+ // Retrieve the size required for the supported languages buffer.
+ //
+ LanguageSize = 0;
+ Status = gHiiString->GetLanguages (gHiiString, HiiHandle, &TempSupportedLanguages, &LanguageSize);
+
+ //
+ // If GetLanguages() returns EFI_SUCCESS for a zero size,
+ // then there are no supported languages registered for HiiHandle. If GetLanguages()
+ // returns an error other than EFI_BUFFER_TOO_SMALL, then HiiHandle is not present
+ // in the HII Database
+ //
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ //
+ // Return NULL if the size can not be retrieved, or if HiiHandle is not in the HII Database
+ //
+ return NULL;
+ }
+
+ //
+ // Allocate the supported languages buffer.
+ //
+ SupportedLanguages = AllocateZeroPool (LanguageSize);
+ if (SupportedLanguages == NULL) {
+ //
+ // Return NULL if allocation fails.
+ //
+ return NULL;
+ }
+
+ //
+ // Retrieve the supported languages string
+ //
+ Status = gHiiString->GetLanguages (gHiiString, HiiHandle, SupportedLanguages, &LanguageSize);
+ if (EFI_ERROR (Status)) {
+ //
+ // Free the buffer and return NULL if the supported languages can not be retrieved.
+ //
+ FreePool (SupportedLanguages);
+ return NULL;
+ }
+
+ //
+ // Return the Null-terminated ASCII string of supported languages
+ //
+ return SupportedLanguages;
+}
+
diff --git a/Core/MdeModulePkg/Library/UefiHiiLib/HiiLib.c b/Core/MdeModulePkg/Library/UefiHiiLib/HiiLib.c
new file mode 100644
index 0000000000..66d72acf27
--- /dev/null
+++ b/Core/MdeModulePkg/Library/UefiHiiLib/HiiLib.c
@@ -0,0 +1,4231 @@
+/** @file
+ HII Library implementation that uses DXE protocols and services.
+
+ Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "InternalHiiLib.h"
+
+#define GUID_CONFIG_STRING_TYPE 0x00
+#define NAME_CONFIG_STRING_TYPE 0x01
+#define PATH_CONFIG_STRING_TYPE 0x02
+
+#define ACTION_SET_DEFAUTL_VALUE 0x01
+#define ACTION_VALIDATE_SETTING 0x02
+
+#define HII_LIB_DEFAULT_VARSTORE_SIZE 0x200
+
+typedef struct {
+ LIST_ENTRY Entry; // Link to Block array
+ UINT16 Offset;
+ UINT16 Width;
+ UINT8 OpCode;
+ UINT8 Scope;
+} IFR_BLOCK_DATA;
+
+typedef struct {
+ EFI_VARSTORE_ID VarStoreId;
+ UINT16 Size;
+} IFR_VARSTORAGE_DATA;
+
+//
+// <ConfigHdr> Template
+//
+GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR16 mConfigHdrTemplate[] = L"GUID=00000000000000000000000000000000&NAME=0000&PATH=00";
+
+EFI_FORM_BROWSER2_PROTOCOL *mUefiFormBrowser2 = NULL;
+
+//
+// Template used to mark the end of a list of packages
+//
+GLOBAL_REMOVE_IF_UNREFERENCED CONST EFI_HII_PACKAGE_HEADER mEndOfPakageList = {
+ sizeof (EFI_HII_PACKAGE_HEADER),
+ EFI_HII_PACKAGE_END
+};
+
+/**
+ Extract Hii package list GUID for given HII handle.
+
+ If HiiHandle could not be found in the HII database, then ASSERT.
+ If Guid is NULL, then ASSERT.
+
+ @param Handle Hii handle
+ @param Guid Package list GUID
+
+ @retval EFI_SUCCESS Successfully extract GUID from Hii database.
+
+**/
+EFI_STATUS
+EFIAPI
+InternalHiiExtractGuidFromHiiHandle (
+ IN EFI_HII_HANDLE Handle,
+ OUT EFI_GUID *Guid
+ )
+{
+ EFI_STATUS Status;
+ UINTN BufferSize;
+ EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList;
+
+ ASSERT (Guid != NULL);
+ ASSERT (Handle != NULL);
+
+ //
+ // Get HII PackageList
+ //
+ BufferSize = 0;
+ HiiPackageList = NULL;
+
+ Status = gHiiDatabase->ExportPackageLists (gHiiDatabase, Handle, &BufferSize, HiiPackageList);
+ ASSERT (Status != EFI_NOT_FOUND);
+
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ HiiPackageList = AllocatePool (BufferSize);
+ ASSERT (HiiPackageList != NULL);
+
+ Status = gHiiDatabase->ExportPackageLists (gHiiDatabase, Handle, &BufferSize, HiiPackageList);
+ }
+ if (EFI_ERROR (Status)) {
+ FreePool (HiiPackageList);
+ return Status;
+ }
+
+ //
+ // Extract GUID
+ //
+ CopyGuid (Guid, &HiiPackageList->PackageListGuid);
+
+ FreePool (HiiPackageList);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Registers a list of packages in the HII Database and returns the HII Handle
+ associated with that registration. If an HII Handle has already been registered
+ with the same PackageListGuid and DeviceHandle, then NULL is returned. If there
+ are not enough resources to perform the registration, then NULL is returned.
+ If an empty list of packages is passed in, then NULL is returned. If the size of
+ the list of package is 0, then NULL is returned.
+
+ The variable arguments are pointers which point to package header that defined
+ by UEFI VFR compiler and StringGather tool.
+
+ #pragma pack (push, 1)
+ typedef struct {
+ UINT32 BinaryLength;
+ EFI_HII_PACKAGE_HEADER PackageHeader;
+ } EDKII_AUTOGEN_PACKAGES_HEADER;
+ #pragma pack (pop)
+
+ @param[in] PackageListGuid The GUID of the package list.
+ @param[in] DeviceHandle If not NULL, the Device Handle on which
+ an instance of DEVICE_PATH_PROTOCOL is installed.
+ This Device Handle uniquely defines the device that
+ the added packages are associated with.
+ @param[in] ... The variable argument list that contains pointers
+ to packages terminated by a NULL.
+
+ @retval NULL A HII Handle has already been registered in the HII Database with
+ the same PackageListGuid and DeviceHandle.
+ @retval NULL The HII Handle could not be created.
+ @retval NULL An empty list of packages was passed in.
+ @retval NULL All packages are empty.
+ @retval Other The HII Handle associated with the newly registered package list.
+
+**/
+EFI_HII_HANDLE
+EFIAPI
+HiiAddPackages (
+ IN CONST EFI_GUID *PackageListGuid,
+ IN EFI_HANDLE DeviceHandle OPTIONAL,
+ ...
+ )
+{
+ EFI_STATUS Status;
+ VA_LIST Args;
+ UINT32 *Package;
+ EFI_HII_PACKAGE_LIST_HEADER *PackageListHeader;
+ EFI_HII_HANDLE HiiHandle;
+ UINT32 Length;
+ UINT8 *Data;
+
+ ASSERT (PackageListGuid != NULL);
+
+ //
+ // Calculate the length of all the packages in the variable argument list
+ //
+ for (Length = 0, VA_START (Args, DeviceHandle); (Package = VA_ARG (Args, UINT32 *)) != NULL; ) {
+ Length += (ReadUnaligned32 (Package) - sizeof (UINT32));
+ }
+ VA_END (Args);
+
+ //
+ // If there are no packages in the variable argument list or all the packages
+ // are empty, then return a NULL HII Handle
+ //
+ if (Length == 0) {
+ return NULL;
+ }
+
+ //
+ // Add the length of the Package List Header and the terminating Package Header
+ //
+ Length += sizeof (EFI_HII_PACKAGE_LIST_HEADER) + sizeof (EFI_HII_PACKAGE_HEADER);
+
+ //
+ // Allocate the storage for the entire Package List
+ //
+ PackageListHeader = AllocateZeroPool (Length);
+
+ //
+ // If the Package List can not be allocated, then return a NULL HII Handle
+ //
+ if (PackageListHeader == NULL) {
+ return NULL;
+ }
+
+ //
+ // Fill in the GUID and Length of the Package List Header
+ //
+ CopyGuid (&PackageListHeader->PackageListGuid, PackageListGuid);
+ PackageListHeader->PackageLength = Length;
+
+ //
+ // Initialize a pointer to the beginning if the Package List data
+ //
+ Data = (UINT8 *)(PackageListHeader + 1);
+
+ //
+ // Copy the data from each package in the variable argument list
+ //
+ for (VA_START (Args, DeviceHandle); (Package = VA_ARG (Args, UINT32 *)) != NULL; ) {
+ Length = ReadUnaligned32 (Package) - sizeof (UINT32);
+ CopyMem (Data, Package + 1, Length);
+ Data += Length;
+ }
+ VA_END (Args);
+
+ //
+ // Append a package of type EFI_HII_PACKAGE_END to mark the end of the package list
+ //
+ CopyMem (Data, &mEndOfPakageList, sizeof (mEndOfPakageList));
+
+ //
+ // Register the package list with the HII Database
+ //
+ Status = gHiiDatabase->NewPackageList (
+ gHiiDatabase,
+ PackageListHeader,
+ DeviceHandle,
+ &HiiHandle
+ );
+ if (EFI_ERROR (Status)) {
+ HiiHandle = NULL;
+ }
+
+ //
+ // Free the allocated package list
+ //
+ FreePool (PackageListHeader);
+
+ //
+ // Return the new HII Handle
+ //
+ return HiiHandle;
+}
+
+/**
+ Removes a package list from the HII database.
+
+ If HiiHandle is NULL, then ASSERT.
+ If HiiHandle is not a valid EFI_HII_HANDLE in the HII database, then ASSERT.
+
+ @param[in] HiiHandle The handle that was previously registered in the HII database
+
+**/
+VOID
+EFIAPI
+HiiRemovePackages (
+ IN EFI_HII_HANDLE HiiHandle
+ )
+{
+ EFI_STATUS Status;
+
+ ASSERT (HiiHandle != NULL);
+ Status = gHiiDatabase->RemovePackageList (gHiiDatabase, HiiHandle);
+ ASSERT_EFI_ERROR (Status);
+}
+
+
+/**
+ Retrieves the array of all the HII Handles or the HII handles of a specific
+ package list GUID in the HII Database.
+ This array is terminated with a NULL HII Handle.
+ This function allocates the returned array using AllocatePool().
+ The caller is responsible for freeing the array with FreePool().
+
+ @param[in] PackageListGuid An optional parameter that is used to request
+ HII Handles associated with a specific
+ Package List GUID. If this parameter is NULL,
+ then all the HII Handles in the HII Database
+ are returned. If this parameter is not NULL,
+ then zero or more HII Handles associated with
+ PackageListGuid are returned.
+
+ @retval NULL No HII handles were found in the HII database
+ @retval NULL The array of HII Handles could not be retrieved
+ @retval Other A pointer to the NULL terminated array of HII Handles
+
+**/
+EFI_HII_HANDLE *
+EFIAPI
+HiiGetHiiHandles (
+ IN CONST EFI_GUID *PackageListGuid OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ UINTN HandleBufferLength;
+ EFI_HII_HANDLE TempHiiHandleBuffer;
+ EFI_HII_HANDLE *HiiHandleBuffer;
+ EFI_GUID Guid;
+ UINTN Index1;
+ UINTN Index2;
+
+ //
+ // Retrieve the size required for the buffer of all HII handles.
+ //
+ HandleBufferLength = 0;
+ Status = gHiiDatabase->ListPackageLists (
+ gHiiDatabase,
+ EFI_HII_PACKAGE_TYPE_ALL,
+ NULL,
+ &HandleBufferLength,
+ &TempHiiHandleBuffer
+ );
+
+ //
+ // If ListPackageLists() returns EFI_SUCCESS for a zero size,
+ // then there are no HII handles in the HII database. If ListPackageLists()
+ // returns an error other than EFI_BUFFER_TOO_SMALL, then there are no HII
+ // handles in the HII database.
+ //
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ //
+ // Return NULL if the size can not be retrieved, or if there are no HII
+ // handles in the HII Database
+ //
+ return NULL;
+ }
+
+ //
+ // Allocate the array of HII handles to hold all the HII Handles and a NULL terminator
+ //
+ HiiHandleBuffer = AllocateZeroPool (HandleBufferLength + sizeof (EFI_HII_HANDLE));
+ if (HiiHandleBuffer == NULL) {
+ //
+ // Return NULL if allocation fails.
+ //
+ return NULL;
+ }
+
+ //
+ // Retrieve the array of HII Handles in the HII Database
+ //
+ Status = gHiiDatabase->ListPackageLists (
+ gHiiDatabase,
+ EFI_HII_PACKAGE_TYPE_ALL,
+ NULL,
+ &HandleBufferLength,
+ HiiHandleBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Free the buffer and return NULL if the HII handles can not be retrieved.
+ //
+ FreePool (HiiHandleBuffer);
+ return NULL;
+ }
+
+ if (PackageListGuid == NULL) {
+ //
+ // Return the NULL terminated array of HII handles in the HII Database
+ //
+ return HiiHandleBuffer;
+ } else {
+ for (Index1 = 0, Index2 = 0; HiiHandleBuffer[Index1] != NULL; Index1++) {
+ Status = InternalHiiExtractGuidFromHiiHandle (HiiHandleBuffer[Index1], &Guid);
+ ASSERT_EFI_ERROR (Status);
+ if (CompareGuid (&Guid, PackageListGuid)) {
+ HiiHandleBuffer[Index2++] = HiiHandleBuffer[Index1];
+ }
+ }
+ if (Index2 > 0) {
+ HiiHandleBuffer[Index2] = NULL;
+ return HiiHandleBuffer;
+ } else {
+ FreePool (HiiHandleBuffer);
+ return NULL;
+ }
+ }
+}
+
+/**
+ Converts all hex dtring characters in range ['A'..'F'] to ['a'..'f'] for
+ hex digits that appear between a '=' and a '&' in a config string.
+
+ If ConfigString is NULL, then ASSERT().
+
+ @param[in] ConfigString Pointer to a Null-terminated Unicode string.
+
+ @return Pointer to the Null-terminated Unicode result string.
+
+**/
+EFI_STRING
+EFIAPI
+InternalHiiLowerConfigString (
+ IN EFI_STRING ConfigString
+ )
+{
+ EFI_STRING String;
+ BOOLEAN Lower;
+
+ ASSERT (ConfigString != NULL);
+
+ //
+ // Convert all hex digits in range [A-F] in the configuration header to [a-f]
+ //
+ for (String = ConfigString, Lower = FALSE; *String != L'\0'; String++) {
+ if (*String == L'=') {
+ Lower = TRUE;
+ } else if (*String == L'&') {
+ Lower = FALSE;
+ } else if (Lower && *String >= L'A' && *String <= L'F') {
+ *String = (CHAR16) (*String - L'A' + L'a');
+ }
+ }
+
+ return ConfigString;
+}
+
+/**
+ Uses the BlockToConfig() service of the Config Routing Protocol to
+ convert <ConfigRequest> and a buffer to a <ConfigResp>
+
+ If ConfigRequest is NULL, then ASSERT().
+ If Block is NULL, then ASSERT().
+
+ @param[in] ConfigRequest Pointer to a Null-terminated Unicode string.
+ @param[in] Block Pointer to a block of data.
+ @param[in] BlockSize The zie, in bytes, of Block.
+
+ @retval NULL The <ConfigResp> string could not be generated.
+ @retval Other Pointer to the Null-terminated Unicode <ConfigResp> string.
+
+**/
+EFI_STRING
+EFIAPI
+InternalHiiBlockToConfig (
+ IN CONST EFI_STRING ConfigRequest,
+ IN CONST UINT8 *Block,
+ IN UINTN BlockSize
+ )
+{
+ EFI_STATUS Status;
+ EFI_STRING ConfigResp;
+ CHAR16 *Progress;
+
+ ASSERT (ConfigRequest != NULL);
+ ASSERT (Block != NULL);
+
+ //
+ // Convert <ConfigRequest> to <ConfigResp>
+ //
+ Status = gHiiConfigRouting->BlockToConfig (
+ gHiiConfigRouting,
+ ConfigRequest,
+ Block,
+ BlockSize,
+ &ConfigResp,
+ &Progress
+ );
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+ return ConfigResp;
+}
+
+/**
+ Uses the BrowserCallback() service of the Form Browser Protocol to retrieve
+ or set uncommitted data. If sata i being retrieved, then the buffer is
+ allocated using AllocatePool(). The caller is then responsible for freeing
+ the buffer using FreePool().
+
+ @param[in] VariableGuid Pointer to an EFI_GUID structure. This is an optional
+ parameter that may be NULL.
+ @param[in] VariableName Pointer to a Null-terminated Unicode string. This
+ is an optional parameter that may be NULL.
+ @param[in] SetResultsData If not NULL, then this parameter specified the buffer
+ of uncommited data to set. If this parameter is NULL,
+ then the caller is requesting to get the uncommited data
+ from the Form Browser.
+
+ @retval NULL The uncommitted data could not be retrieved.
+ @retval Other A pointer to a buffer containing the uncommitted data.
+
+**/
+EFI_STRING
+EFIAPI
+InternalHiiBrowserCallback (
+ IN CONST EFI_GUID *VariableGuid, OPTIONAL
+ IN CONST CHAR16 *VariableName, OPTIONAL
+ IN CONST EFI_STRING SetResultsData OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ UINTN ResultsDataSize;
+ EFI_STRING ResultsData;
+ CHAR16 TempResultsData;
+
+ //
+ // Locate protocols
+ //
+ if (mUefiFormBrowser2 == NULL) {
+ Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **) &mUefiFormBrowser2);
+ if (EFI_ERROR (Status) || mUefiFormBrowser2 == NULL) {
+ return NULL;
+ }
+ }
+
+ ResultsDataSize = 0;
+
+ if (SetResultsData != NULL) {
+ //
+ // Request to to set data in the uncommitted browser state information
+ //
+ ResultsData = SetResultsData;
+ } else {
+ //
+ // Retrieve the length of the buffer required ResultsData from the Browser Callback
+ //
+ Status = mUefiFormBrowser2->BrowserCallback (
+ mUefiFormBrowser2,
+ &ResultsDataSize,
+ &TempResultsData,
+ TRUE,
+ VariableGuid,
+ VariableName
+ );
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // No Resluts Data, only allocate one char for '\0'
+ //
+ ResultsData = AllocateZeroPool (sizeof (CHAR16));
+ return ResultsData;
+ }
+
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ return NULL;
+ }
+
+ //
+ // Allocate the ResultsData buffer
+ //
+ ResultsData = AllocateZeroPool (ResultsDataSize);
+ if (ResultsData == NULL) {
+ return NULL;
+ }
+ }
+
+ //
+ // Retrieve or set the ResultsData from the Browser Callback
+ //
+ Status = mUefiFormBrowser2->BrowserCallback (
+ mUefiFormBrowser2,
+ &ResultsDataSize,
+ ResultsData,
+ (BOOLEAN)(SetResultsData == NULL),
+ VariableGuid,
+ VariableName
+ );
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ return ResultsData;
+}
+
+/**
+ Allocates and returns a Null-terminated Unicode <ConfigHdr> string using routing
+ information that includes a GUID, an optional Unicode string name, and a device
+ path. The string returned is allocated with AllocatePool(). The caller is
+ responsible for freeing the allocated string with FreePool().
+
+ The format of a <ConfigHdr> is as follows:
+
+ GUID=<HexCh>32&NAME=<Char>NameLength&PATH=<HexChar>DevicePathSize<Null>
+
+ @param[in] Guid Pointer to an EFI_GUID that is the routing information
+ GUID. Each of the 16 bytes in Guid is converted to
+ a 2 Unicode character hexidecimal string. This is
+ an optional parameter that may be NULL.
+ @param[in] Name Pointer to a Null-terminated Unicode string that is
+ the routing information NAME. This is an optional
+ parameter that may be NULL. Each 16-bit Unicode
+ character in Name is converted to a 4 character Unicode
+ hexidecimal string.
+ @param[in] DriverHandle The driver handle which supports a Device Path Protocol
+ that is the routing information PATH. Each byte of
+ the Device Path associated with DriverHandle is converted
+ to a 2 Unicode character hexidecimal string.
+
+ @retval NULL DriverHandle does not support the Device Path Protocol.
+ @retval Other A pointer to the Null-terminate Unicode <ConfigHdr> string
+
+**/
+EFI_STRING
+EFIAPI
+HiiConstructConfigHdr (
+ IN CONST EFI_GUID *Guid, OPTIONAL
+ IN CONST CHAR16 *Name, OPTIONAL
+ IN EFI_HANDLE DriverHandle
+ )
+{
+ UINTN NameLength;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ UINTN DevicePathSize;
+ CHAR16 *String;
+ CHAR16 *ReturnString;
+ UINTN Index;
+ UINT8 *Buffer;
+ UINTN MaxLen;
+
+ //
+ // Compute the length of Name in Unicode characters.
+ // If Name is NULL, then the length is 0.
+ //
+ NameLength = 0;
+ if (Name != NULL) {
+ NameLength = StrLen (Name);
+ }
+
+ DevicePath = NULL;
+ DevicePathSize = 0;
+ //
+ // Retrieve DevicePath Protocol associated with DriverHandle
+ //
+ if (DriverHandle != NULL) {
+ DevicePath = DevicePathFromHandle (DriverHandle);
+ if (DevicePath == NULL) {
+ return NULL;
+ }
+ //
+ // Compute the size of the device path in bytes
+ //
+ DevicePathSize = GetDevicePathSize (DevicePath);
+ }
+
+ //
+ // GUID=<HexCh>32&NAME=<Char>NameLength&PATH=<HexChar>DevicePathSize <Null>
+ // | 5 | sizeof (EFI_GUID) * 2 | 6 | NameStrLen*4 | 6 | DevicePathSize * 2 | 1 |
+ //
+ MaxLen = 5 + sizeof (EFI_GUID) * 2 + 6 + NameLength * 4 + 6 + DevicePathSize * 2 + 1;
+ String = AllocateZeroPool (MaxLen * sizeof (CHAR16));
+ if (String == NULL) {
+ return NULL;
+ }
+
+ //
+ // Start with L"GUID="
+ //
+ StrCpyS (String, MaxLen, L"GUID=");
+ ReturnString = String;
+ String += StrLen (String);
+
+ if (Guid != NULL) {
+ //
+ // Append Guid converted to <HexCh>32
+ //
+ for (Index = 0, Buffer = (UINT8 *)Guid; Index < sizeof (EFI_GUID); Index++) {
+ String += UnicodeValueToString (String, PREFIX_ZERO | RADIX_HEX, *(Buffer++), 2);
+ }
+ }
+
+ //
+ // Append L"&NAME="
+ //
+ StrCatS (ReturnString, MaxLen, L"&NAME=");
+ String += StrLen (String);
+
+ if (Name != NULL) {
+ //
+ // Append Name converted to <Char>NameLength
+ //
+ for (; *Name != L'\0'; Name++) {
+ String += UnicodeValueToString (String, PREFIX_ZERO | RADIX_HEX, *Name, 4);
+ }
+ }
+
+ //
+ // Append L"&PATH="
+ //
+ StrCatS (ReturnString, MaxLen, L"&PATH=");
+ String += StrLen (String);
+
+ //
+ // Append the device path associated with DriverHandle converted to <HexChar>DevicePathSize
+ //
+ for (Index = 0, Buffer = (UINT8 *)DevicePath; Index < DevicePathSize; Index++) {
+ String += UnicodeValueToString (String, PREFIX_ZERO | RADIX_HEX, *(Buffer++), 2);
+ }
+
+ //
+ // Null terminate the Unicode string
+ //
+ *String = L'\0';
+
+ //
+ // Convert all hex digits in range [A-F] in the configuration header to [a-f]
+ //
+ return InternalHiiLowerConfigString (ReturnString);
+}
+
+/**
+ Convert the hex UNICODE encoding string of UEFI GUID, NAME or device path
+ to binary buffer from <ConfigHdr>.
+
+ This is a internal function.
+
+ @param String UEFI configuration string.
+ @param Flag Flag specifies what type buffer will be retrieved.
+ @param Buffer Binary of Guid, Name or Device path.
+
+ @retval EFI_INVALID_PARAMETER Any incoming parameter is invalid.
+ @retval EFI_OUT_OF_RESOURCES Lake of resources to store neccesary structures.
+ @retval EFI_SUCCESS The buffer data is retrieved and translated to
+ binary format.
+
+**/
+EFI_STATUS
+InternalHiiGetBufferFromString (
+ IN EFI_STRING String,
+ IN UINT8 Flag,
+ OUT UINT8 **Buffer
+ )
+{
+ UINTN Length;
+ EFI_STRING ConfigHdr;
+ CHAR16 *StringPtr;
+ UINT8 *DataBuffer;
+ CHAR16 TemStr[5];
+ UINTN Index;
+ UINT8 DigitUint8;
+
+ if (String == NULL || Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ DataBuffer = NULL;
+ StringPtr = NULL;
+ ConfigHdr = String;
+ //
+ // The content between 'GUID', 'NAME', 'PATH' of <ConfigHdr> and '&' of next element
+ // or '\0' (end of configuration string) is the UNICODE %02x bytes encoding string.
+ //
+ for (Length = 0; *String != 0 && *String != L'&'; String++, Length++);
+
+ switch (Flag) {
+ case GUID_CONFIG_STRING_TYPE:
+ case PATH_CONFIG_STRING_TYPE:
+ //
+ // The data in <ConfigHdr> is encoded as hex UNICODE %02x bytes in the same order
+ // as the device path and Guid resides in RAM memory.
+ // Translate the data into binary.
+ //
+ DataBuffer = (UINT8 *) AllocateZeroPool ((Length + 1) / 2);
+ if (DataBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Convert binary byte one by one
+ //
+ ZeroMem (TemStr, sizeof (TemStr));
+ for (Index = 0; Index < Length; Index ++) {
+ TemStr[0] = ConfigHdr[Index];
+ DigitUint8 = (UINT8) StrHexToUint64 (TemStr);
+ if ((Index & 1) == 0) {
+ DataBuffer [Index/2] = DigitUint8;
+ } else {
+ DataBuffer [Index/2] = (UINT8) ((DataBuffer [Index/2] << 4) + DigitUint8);
+ }
+ }
+
+ *Buffer = DataBuffer;
+ break;
+
+ case NAME_CONFIG_STRING_TYPE:
+ //
+ // Convert Config String to Unicode String, e.g. "0041004200430044" => "ABCD"
+ //
+
+ //
+ // Add the tailling char L'\0'
+ //
+ DataBuffer = (UINT8 *) AllocateZeroPool ((Length/4 + 1) * sizeof (CHAR16));
+ if (DataBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Convert character one by one
+ //
+ StringPtr = (CHAR16 *) DataBuffer;
+ ZeroMem (TemStr, sizeof (TemStr));
+ for (Index = 0; Index < Length; Index += 4) {
+ StrnCpyS (TemStr, sizeof (TemStr) / sizeof (CHAR16), ConfigHdr + Index, 4);
+ StringPtr[Index/4] = (CHAR16) StrHexToUint64 (TemStr);
+ }
+ //
+ // Add tailing L'\0' character
+ //
+ StringPtr[Index/4] = L'\0';
+
+ *Buffer = DataBuffer;
+ break;
+
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function checks VarOffset and VarWidth is in the block range.
+
+ @param BlockArray The block array is to be checked.
+ @param VarOffset Offset of var to the structure
+ @param VarWidth Width of var.
+
+ @retval TRUE This Var is in the block range.
+ @retval FALSE This Var is not in the block range.
+**/
+BOOLEAN
+BlockArrayCheck (
+ IN IFR_BLOCK_DATA *BlockArray,
+ IN UINT16 VarOffset,
+ IN UINT16 VarWidth
+ )
+{
+ LIST_ENTRY *Link;
+ IFR_BLOCK_DATA *BlockData;
+
+ //
+ // No Request Block array, all vars are got.
+ //
+ if (BlockArray == NULL) {
+ return TRUE;
+ }
+
+ //
+ // Check the input var is in the request block range.
+ //
+ for (Link = BlockArray->Entry.ForwardLink; Link != &BlockArray->Entry; Link = Link->ForwardLink) {
+ BlockData = BASE_CR (Link, IFR_BLOCK_DATA, Entry);
+ if ((VarOffset >= BlockData->Offset) && ((VarOffset + VarWidth) <= (BlockData->Offset + BlockData->Width))) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ Get the value of <Number> in <BlockConfig> format, i.e. the value of OFFSET
+ or WIDTH or VALUE.
+ <BlockConfig> ::= 'OFFSET='<Number>&'WIDTH='<Number>&'VALUE'=<Number>
+
+ @param ValueString String in <BlockConfig> format and points to the
+ first character of <Number>.
+ @param ValueData The output value. Caller takes the responsibility
+ to free memory.
+ @param ValueLength Length of the <Number>, in characters.
+
+ @retval EFI_OUT_OF_RESOURCES Insufficient resources to store neccessary
+ structures.
+ @retval EFI_SUCCESS Value of <Number> is outputted in Number
+ successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+InternalHiiGetValueOfNumber (
+ IN EFI_STRING ValueString,
+ OUT UINT8 **ValueData,
+ OUT UINTN *ValueLength
+ )
+{
+ EFI_STRING StringPtr;
+ UINTN Length;
+ UINT8 *Buf;
+ UINT8 DigitUint8;
+ UINTN Index;
+ CHAR16 TemStr[2];
+
+ ASSERT (ValueString != NULL && ValueData != NULL && ValueLength != NULL);
+ ASSERT (*ValueString != L'\0');
+
+ //
+ // Get the length of value string
+ //
+ StringPtr = ValueString;
+ while (*StringPtr != L'\0' && *StringPtr != L'&') {
+ StringPtr++;
+ }
+ Length = StringPtr - ValueString;
+
+ //
+ // Allocate buffer to store the value
+ //
+ Buf = (UINT8 *) AllocateZeroPool ((Length + 1) / 2);
+ if (Buf == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Convert character one by one to the value buffer
+ //
+ ZeroMem (TemStr, sizeof (TemStr));
+ for (Index = 0; Index < Length; Index ++) {
+ TemStr[0] = ValueString[Length - Index - 1];
+ DigitUint8 = (UINT8) StrHexToUint64 (TemStr);
+ if ((Index & 1) == 0) {
+ Buf [Index/2] = DigitUint8;
+ } else {
+ Buf [Index/2] = (UINT8) ((DigitUint8 << 4) + Buf [Index/2]);
+ }
+ }
+
+ //
+ // Set the converted value and string length.
+ //
+ *ValueData = Buf;
+ *ValueLength = Length;
+ return EFI_SUCCESS;
+}
+
+/**
+ Get value from config request resp string.
+
+ @param ConfigElement ConfigResp string contains the current setting.
+ @param VarName The variable name which need to get value.
+ @param VarValue The return value.
+
+ @retval EFI_SUCCESS Get the value for the VarName
+ @retval EFI_OUT_OF_RESOURCES The memory is not enough.
+**/
+EFI_STATUS
+GetValueFromRequest (
+ IN CHAR16 *ConfigElement,
+ IN CHAR16 *VarName,
+ OUT UINT64 *VarValue
+ )
+{
+ UINT8 *TmpBuffer;
+ CHAR16 *StringPtr;
+ UINTN Length;
+ EFI_STATUS Status;
+
+ //
+ // Find VarName related string.
+ //
+ StringPtr = StrStr (ConfigElement, VarName);
+ ASSERT (StringPtr != NULL);
+
+ //
+ // Skip the "VarName=" string
+ //
+ StringPtr += StrLen (VarName) + 1;
+
+ //
+ // Get Offset
+ //
+ Status = InternalHiiGetValueOfNumber (StringPtr, &TmpBuffer, &Length);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ *VarValue = 0;
+ CopyMem (VarValue, TmpBuffer, (((Length + 1) / 2) < sizeof (UINT64)) ? ((Length + 1) / 2) : sizeof (UINT64));
+
+ FreePool (TmpBuffer);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This internal function parses IFR data to validate current setting.
+
+ Base on the NameValueType, if it is TRUE, RequestElement and HiiHandle is valid;
+ else the VarBuffer and CurrentBlockArray is valid.
+
+ @param HiiPackageList Point to Hii package list.
+ @param PackageListLength The length of the pacakge.
+ @param VarGuid Guid of the buffer storage.
+ @param VarName Name of the buffer storage.
+ @param VarBuffer The data buffer for the storage.
+ @param CurrentBlockArray The block array from the config Requst string.
+ @param RequestElement The config string for this storage.
+ @param HiiHandle The HiiHandle for this formset.
+ @param NameValueType Whether current storage is name/value varstore or not.
+
+ @retval EFI_SUCCESS The current setting is valid.
+ @retval EFI_OUT_OF_RESOURCES The memory is not enough.
+ @retval EFI_INVALID_PARAMETER The config string or the Hii package is invalid.
+**/
+EFI_STATUS
+ValidateQuestionFromVfr (
+ IN EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList,
+ IN UINTN PackageListLength,
+ IN EFI_GUID *VarGuid,
+ IN CHAR16 *VarName,
+ IN UINT8 *VarBuffer,
+ IN IFR_BLOCK_DATA *CurrentBlockArray,
+ IN CHAR16 *RequestElement,
+ IN EFI_HII_HANDLE HiiHandle,
+ IN BOOLEAN NameValueType
+ )
+{
+ IFR_BLOCK_DATA VarBlockData;
+ UINT16 Offset;
+ UINT16 Width;
+ UINT64 VarValue;
+ EFI_IFR_TYPE_VALUE TmpValue;
+ EFI_STATUS Status;
+ EFI_HII_PACKAGE_HEADER PacakgeHeader;
+ UINT32 PackageOffset;
+ UINT8 *PackageData;
+ UINTN IfrOffset;
+ EFI_IFR_OP_HEADER *IfrOpHdr;
+ EFI_IFR_VARSTORE *IfrVarStore;
+ EFI_IFR_VARSTORE_NAME_VALUE *IfrNameValueStore;
+ EFI_IFR_VARSTORE_EFI *IfrEfiVarStore;
+ IFR_VARSTORAGE_DATA VarStoreData;
+ EFI_IFR_ONE_OF *IfrOneOf;
+ EFI_IFR_NUMERIC *IfrNumeric;
+ EFI_IFR_ONE_OF_OPTION *IfrOneOfOption;
+ EFI_IFR_CHECKBOX *IfrCheckBox;
+ EFI_IFR_STRING *IfrString;
+ CHAR8 *VarStoreName;
+ UINTN Index;
+ CHAR16 *QuestionName;
+ CHAR16 *StringPtr;
+
+ //
+ // Initialize the local variables.
+ //
+ Index = 0;
+ VarStoreName = NULL;
+ Status = EFI_SUCCESS;
+ VarValue = 0;
+ IfrVarStore = NULL;
+ IfrNameValueStore = NULL;
+ IfrEfiVarStore = NULL;
+ ZeroMem (&VarStoreData, sizeof (IFR_VARSTORAGE_DATA));
+ ZeroMem (&VarBlockData, sizeof (VarBlockData));
+
+ //
+ // Check IFR value is in block data, then Validate Value
+ //
+ PackageOffset = sizeof (EFI_HII_PACKAGE_LIST_HEADER);
+ while (PackageOffset < PackageListLength) {
+ CopyMem (&PacakgeHeader, (UINT8 *) HiiPackageList + PackageOffset, sizeof (PacakgeHeader));
+
+ //
+ // Parse IFR opcode from the form package.
+ //
+ if (PacakgeHeader.Type == EFI_HII_PACKAGE_FORMS) {
+ IfrOffset = sizeof (PacakgeHeader);
+ PackageData = (UINT8 *) HiiPackageList + PackageOffset;
+ while (IfrOffset < PacakgeHeader.Length) {
+ IfrOpHdr = (EFI_IFR_OP_HEADER *) (PackageData + IfrOffset);
+ //
+ // Validate current setting to the value built in IFR opcode
+ //
+ switch (IfrOpHdr->OpCode) {
+ case EFI_IFR_VARSTORE_OP:
+ //
+ // VarStoreId has been found. No further found.
+ //
+ if (VarStoreData.VarStoreId != 0) {
+ break;
+ }
+ //
+ // Find the matched VarStoreId to the input VarGuid and VarName
+ //
+ IfrVarStore = (EFI_IFR_VARSTORE *) IfrOpHdr;
+ if (CompareGuid ((EFI_GUID *) (VOID *) &IfrVarStore->Guid, VarGuid)) {
+ VarStoreName = (CHAR8 *) IfrVarStore->Name;
+ for (Index = 0; VarStoreName[Index] != 0; Index ++) {
+ if ((CHAR16) VarStoreName[Index] != VarName[Index]) {
+ break;
+ }
+ }
+ //
+ // The matched VarStore is found.
+ //
+ if ((VarStoreName[Index] != 0) || (VarName[Index] != 0)) {
+ IfrVarStore = NULL;
+ }
+ } else {
+ IfrVarStore = NULL;
+ }
+
+ if (IfrVarStore != NULL) {
+ VarStoreData.VarStoreId = IfrVarStore->VarStoreId;
+ VarStoreData.Size = IfrVarStore->Size;
+ }
+ break;
+ case EFI_IFR_VARSTORE_NAME_VALUE_OP:
+ //
+ // VarStoreId has been found. No further found.
+ //
+ if (VarStoreData.VarStoreId != 0) {
+ break;
+ }
+ //
+ // Find the matched VarStoreId to the input VarGuid
+ //
+ IfrNameValueStore = (EFI_IFR_VARSTORE_NAME_VALUE *) IfrOpHdr;
+ if (!CompareGuid ((EFI_GUID *) (VOID *) &IfrNameValueStore->Guid, VarGuid)) {
+ IfrNameValueStore = NULL;
+ }
+
+ if (IfrNameValueStore != NULL) {
+ VarStoreData.VarStoreId = IfrNameValueStore->VarStoreId;
+ }
+ break;
+ case EFI_IFR_VARSTORE_EFI_OP:
+ //
+ // VarStore is found. Don't need to search any more.
+ //
+ if (VarStoreData.VarStoreId != 0) {
+ break;
+ }
+
+ IfrEfiVarStore = (EFI_IFR_VARSTORE_EFI *) IfrOpHdr;
+
+ //
+ // If the length is small than the structure, this is from old efi
+ // varstore definition. Old efi varstore get config directly from
+ // GetVariable function.
+ //
+ if (IfrOpHdr->Length < sizeof (EFI_IFR_VARSTORE_EFI)) {
+ break;
+ }
+
+ if (CompareGuid ((EFI_GUID *) (VOID *) &IfrEfiVarStore->Guid, VarGuid)) {
+ VarStoreName = (CHAR8 *) IfrEfiVarStore->Name;
+ for (Index = 0; VarStoreName[Index] != 0; Index ++) {
+ if ((CHAR16) VarStoreName[Index] != VarName[Index]) {
+ break;
+ }
+ }
+ //
+ // The matched VarStore is found.
+ //
+ if ((VarStoreName[Index] != 0) || (VarName[Index] != 0)) {
+ IfrEfiVarStore = NULL;
+ }
+ } else {
+ IfrEfiVarStore = NULL;
+ }
+
+ if (IfrEfiVarStore != NULL) {
+ //
+ // Find the matched VarStore
+ //
+ VarStoreData.VarStoreId = IfrEfiVarStore->VarStoreId;
+ VarStoreData.Size = IfrEfiVarStore->Size;
+ }
+ break;
+ case EFI_IFR_FORM_OP:
+ case EFI_IFR_FORM_MAP_OP:
+ //
+ // Check the matched VarStoreId is found.
+ //
+ if (VarStoreData.VarStoreId == 0) {
+ return EFI_SUCCESS;
+ }
+ break;
+ case EFI_IFR_ONE_OF_OP:
+ //
+ // Check whether current value is the one of option.
+ //
+
+ //
+ // OneOf question is not in IFR Form. This IFR form is not valid.
+ //
+ if (VarStoreData.VarStoreId == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Check whether this question is for the requested varstore.
+ //
+ IfrOneOf = (EFI_IFR_ONE_OF *) IfrOpHdr;
+ if (IfrOneOf->Question.VarStoreId != VarStoreData.VarStoreId) {
+ break;
+ }
+
+ if (NameValueType) {
+ QuestionName = HiiGetString (HiiHandle, IfrOneOf->Question.VarStoreInfo.VarName, NULL);
+ ASSERT (QuestionName != NULL);
+
+ if (StrStr (RequestElement, QuestionName) == NULL) {
+ //
+ // This question is not in the current configuration string. Skip it.
+ //
+ break;
+ }
+
+ Status = GetValueFromRequest (RequestElement, QuestionName, &VarValue);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ } else {
+ //
+ // Get Offset by Question header and Width by DataType Flags
+ //
+ Offset = IfrOneOf->Question.VarStoreInfo.VarOffset;
+ Width = (UINT16) (1 << (IfrOneOf->Flags & EFI_IFR_NUMERIC_SIZE));
+ //
+ // Check whether this question is in current block array.
+ //
+ if (!BlockArrayCheck (CurrentBlockArray, Offset, Width)) {
+ //
+ // This question is not in the current configuration string. Skip it.
+ //
+ break;
+ }
+ //
+ // Check this var question is in the var storage
+ //
+ if ((Offset + Width) > VarStoreData.Size) {
+ //
+ // This question exceeds the var store size.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Get the current value for oneof opcode
+ //
+ VarValue = 0;
+ CopyMem (&VarValue, VarBuffer + Offset, Width);
+ }
+ //
+ // Set Block Data, to be checked in the following Oneof option opcode.
+ //
+ VarBlockData.OpCode = IfrOpHdr->OpCode;
+ VarBlockData.Scope = IfrOpHdr->Scope;
+ break;
+ case EFI_IFR_NUMERIC_OP:
+ //
+ // Check the current value is in the numeric range.
+ //
+
+ //
+ // Numeric question is not in IFR Form. This IFR form is not valid.
+ //
+ if (VarStoreData.VarStoreId == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Check whether this question is for the requested varstore.
+ //
+ IfrNumeric = (EFI_IFR_NUMERIC *) IfrOpHdr;
+ if (IfrNumeric->Question.VarStoreId != VarStoreData.VarStoreId) {
+ break;
+ }
+
+ if (NameValueType) {
+ QuestionName = HiiGetString (HiiHandle, IfrNumeric->Question.VarStoreInfo.VarName, NULL);
+ ASSERT (QuestionName != NULL);
+
+ if (StrStr (RequestElement, QuestionName) == NULL) {
+ //
+ // This question is not in the current configuration string. Skip it.
+ //
+ break;
+ }
+
+ Status = GetValueFromRequest (RequestElement, QuestionName, &VarValue);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ } else {
+ //
+ // Get Offset by Question header and Width by DataType Flags
+ //
+ Offset = IfrNumeric->Question.VarStoreInfo.VarOffset;
+ Width = (UINT16) (1 << (IfrNumeric->Flags & EFI_IFR_NUMERIC_SIZE));
+ //
+ // Check whether this question is in current block array.
+ //
+ if (!BlockArrayCheck (CurrentBlockArray, Offset, Width)) {
+ //
+ // This question is not in the current configuration string. Skip it.
+ //
+ break;
+ }
+ //
+ // Check this var question is in the var storage
+ //
+ if ((Offset + Width) > VarStoreData.Size) {
+ //
+ // This question exceeds the var store size.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check the current value is in the numeric range.
+ //
+ VarValue = 0;
+ CopyMem (&VarValue, VarBuffer + Offset, Width);
+ }
+ if ((IfrNumeric->Flags & EFI_IFR_DISPLAY) == 0) {
+ switch (IfrNumeric->Flags & EFI_IFR_NUMERIC_SIZE) {
+ case EFI_IFR_NUMERIC_SIZE_1:
+ if ((INT8) VarValue < (INT8) IfrNumeric->data.u8.MinValue || (INT8) VarValue > (INT8) IfrNumeric->data.u8.MaxValue) {
+ //
+ // Not in the valid range.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+ break;
+ case EFI_IFR_NUMERIC_SIZE_2:
+ if ((INT16) VarValue < (INT16) IfrNumeric->data.u16.MinValue || (INT16) VarValue > (INT16) IfrNumeric->data.u16.MaxValue) {
+ //
+ // Not in the valid range.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+ break;
+ case EFI_IFR_NUMERIC_SIZE_4:
+ if ((INT32) VarValue < (INT32) IfrNumeric->data.u32.MinValue || (INT32) VarValue > (INT32) IfrNumeric->data.u32.MaxValue) {
+ //
+ // Not in the valid range.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+ break;
+ case EFI_IFR_NUMERIC_SIZE_8:
+ if ((INT64) VarValue < (INT64) IfrNumeric->data.u64.MinValue || (INT64) VarValue > (INT64) IfrNumeric->data.u64.MaxValue) {
+ //
+ // Not in the valid range.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+ break;
+ }
+ } else {
+ switch (IfrNumeric->Flags & EFI_IFR_NUMERIC_SIZE) {
+ case EFI_IFR_NUMERIC_SIZE_1:
+ if ((UINT8) VarValue < IfrNumeric->data.u8.MinValue || (UINT8) VarValue > IfrNumeric->data.u8.MaxValue) {
+ //
+ // Not in the valid range.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+ break;
+ case EFI_IFR_NUMERIC_SIZE_2:
+ if ((UINT16) VarValue < IfrNumeric->data.u16.MinValue || (UINT16) VarValue > IfrNumeric->data.u16.MaxValue) {
+ //
+ // Not in the valid range.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+ break;
+ case EFI_IFR_NUMERIC_SIZE_4:
+ if ((UINT32) VarValue < IfrNumeric->data.u32.MinValue || (UINT32) VarValue > IfrNumeric->data.u32.MaxValue) {
+ //
+ // Not in the valid range.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+ break;
+ case EFI_IFR_NUMERIC_SIZE_8:
+ if ((UINT64) VarValue < IfrNumeric->data.u64.MinValue || (UINT64) VarValue > IfrNumeric->data.u64.MaxValue) {
+ //
+ // Not in the valid range.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+ break;
+ }
+ }
+ break;
+ case EFI_IFR_CHECKBOX_OP:
+ //
+ // Check value is BOOLEAN type, only 0 and 1 is valid.
+ //
+
+ //
+ // CheckBox question is not in IFR Form. This IFR form is not valid.
+ //
+ if (VarStoreData.VarStoreId == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check whether this question is for the requested varstore.
+ //
+ IfrCheckBox = (EFI_IFR_CHECKBOX *) IfrOpHdr;
+ if (IfrCheckBox->Question.VarStoreId != VarStoreData.VarStoreId) {
+ break;
+ }
+
+ if (NameValueType) {
+ QuestionName = HiiGetString (HiiHandle, IfrCheckBox->Question.VarStoreInfo.VarName, NULL);
+ ASSERT (QuestionName != NULL);
+
+ if (StrStr (RequestElement, QuestionName) == NULL) {
+ //
+ // This question is not in the current configuration string. Skip it.
+ //
+ break;
+ }
+
+ Status = GetValueFromRequest (RequestElement, QuestionName, &VarValue);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ } else {
+ //
+ // Get Offset by Question header
+ //
+ Offset = IfrCheckBox->Question.VarStoreInfo.VarOffset;
+ Width = (UINT16) sizeof (BOOLEAN);
+ //
+ // Check whether this question is in current block array.
+ //
+ if (!BlockArrayCheck (CurrentBlockArray, Offset, Width)) {
+ //
+ // This question is not in the current configuration string. Skip it.
+ //
+ break;
+ }
+ //
+ // Check this var question is in the var storage
+ //
+ if ((Offset + Width) > VarStoreData.Size) {
+ //
+ // This question exceeds the var store size.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Check the current value is in the numeric range.
+ //
+ VarValue = 0;
+ CopyMem (&VarValue, VarBuffer + Offset, Width);
+ }
+ //
+ // Boolean type, only 1 and 0 is valid.
+ //
+ if (VarValue > 1) {
+ return EFI_INVALID_PARAMETER;
+ }
+ break;
+ case EFI_IFR_STRING_OP:
+ //
+ // Check current string length is less than maxsize
+ //
+
+ //
+ // CheckBox question is not in IFR Form. This IFR form is not valid.
+ //
+ if (VarStoreData.VarStoreId == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check whether this question is for the requested varstore.
+ //
+ IfrString = (EFI_IFR_STRING *) IfrOpHdr;
+ if (IfrString->Question.VarStoreId != VarStoreData.VarStoreId) {
+ break;
+ }
+ //
+ // Get Width by OneOf Flags
+ //
+ Width = (UINT16) (IfrString->MaxSize * sizeof (UINT16));
+ if (NameValueType) {
+ QuestionName = HiiGetString (HiiHandle, IfrString->Question.VarStoreInfo.VarName, NULL);
+ ASSERT (QuestionName != NULL);
+
+ StringPtr = StrStr (RequestElement, QuestionName);
+ if (StringPtr == NULL) {
+ //
+ // This question is not in the current configuration string. Skip it.
+ //
+ break;
+ }
+
+ //
+ // Skip the "=".
+ //
+ StringPtr += 1;
+
+ //
+ // Check current string length is less than maxsize
+ //
+ if (StrSize (StringPtr) > Width) {
+ return EFI_INVALID_PARAMETER;
+ }
+ } else {
+ //
+ // Get Offset/Width by Question header and OneOf Flags
+ //
+ Offset = IfrString->Question.VarStoreInfo.VarOffset;
+ //
+ // Check whether this question is in current block array.
+ //
+ if (!BlockArrayCheck (CurrentBlockArray, Offset, Width)) {
+ //
+ // This question is not in the current configuration string. Skip it.
+ //
+ break;
+ }
+ //
+ // Check this var question is in the var storage
+ //
+ if ((Offset + Width) > VarStoreData.Size) {
+ //
+ // This question exceeds the var store size.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check current string length is less than maxsize
+ //
+ if (StrSize ((CHAR16 *) (VarBuffer + Offset)) > Width) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ break;
+ case EFI_IFR_ONE_OF_OPTION_OP:
+ //
+ // Opcode Scope is zero. This one of option is not to be checked.
+ //
+ if (VarBlockData.Scope == 0) {
+ break;
+ }
+
+ //
+ // Only check for OneOf and OrderList opcode
+ //
+ IfrOneOfOption = (EFI_IFR_ONE_OF_OPTION *) IfrOpHdr;
+ if (VarBlockData.OpCode == EFI_IFR_ONE_OF_OP) {
+ //
+ // Check current value is the value of one of option.
+ //
+ ASSERT (IfrOneOfOption->Type <= EFI_IFR_TYPE_NUM_SIZE_64);
+ ZeroMem (&TmpValue, sizeof (EFI_IFR_TYPE_VALUE));
+ CopyMem (&TmpValue, &IfrOneOfOption->Value, IfrOneOfOption->Header.Length - OFFSET_OF (EFI_IFR_ONE_OF_OPTION, Value));
+ if (VarValue == TmpValue.u64) {
+ //
+ // The value is one of option value.
+ // Set OpCode to Zero, don't need check again.
+ //
+ VarBlockData.OpCode = 0;
+ }
+ }
+ break;
+ case EFI_IFR_END_OP:
+ //
+ // Decrease opcode scope for the validated opcode
+ //
+ if (VarBlockData.Scope > 0) {
+ VarBlockData.Scope --;
+ }
+
+ //
+ // OneOf value doesn't belong to one of option value.
+ //
+ if ((VarBlockData.Scope == 0) && (VarBlockData.OpCode == EFI_IFR_ONE_OF_OP)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ break;
+ default:
+ //
+ // Increase Scope for the validated opcode
+ //
+ if (VarBlockData.Scope > 0) {
+ VarBlockData.Scope = (UINT8) (VarBlockData.Scope + IfrOpHdr->Scope);
+ }
+ break;
+ }
+ //
+ // Go to the next opcode
+ //
+ IfrOffset += IfrOpHdr->Length;
+ }
+ //
+ // Only one form is in a package list.
+ //
+ break;
+ }
+
+ //
+ // Go to next package.
+ //
+ PackageOffset += PacakgeHeader.Length;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This internal function parses IFR data to validate current setting.
+
+ @param ConfigElement ConfigResp element string contains the current setting.
+ @param CurrentBlockArray Current block array.
+ @param VarBuffer Data buffer for this varstore.
+
+ @retval EFI_SUCCESS The current setting is valid.
+ @retval EFI_OUT_OF_RESOURCES The memory is not enough.
+ @retval EFI_INVALID_PARAMETER The config string or the Hii package is invalid.
+**/
+EFI_STATUS
+GetBlockDataInfo (
+ IN CHAR16 *ConfigElement,
+ OUT IFR_BLOCK_DATA **CurrentBlockArray,
+ OUT UINT8 **VarBuffer
+ )
+{
+ IFR_BLOCK_DATA *BlockData;
+ IFR_BLOCK_DATA *NewBlockData;
+ EFI_STRING StringPtr;
+ UINTN Length;
+ UINT8 *TmpBuffer;
+ UINT16 Offset;
+ UINT16 Width;
+ LIST_ENTRY *Link;
+ UINTN MaxBufferSize;
+ EFI_STATUS Status;
+ IFR_BLOCK_DATA *BlockArray;
+ UINT8 *DataBuffer;
+
+ //
+ // Initialize the local variables.
+ //
+ Status = EFI_SUCCESS;
+ BlockData = NULL;
+ NewBlockData = NULL;
+ TmpBuffer = NULL;
+ BlockArray = NULL;
+ MaxBufferSize = HII_LIB_DEFAULT_VARSTORE_SIZE;
+ DataBuffer = AllocateZeroPool (MaxBufferSize);
+ if (DataBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Init BlockArray
+ //
+ BlockArray = (IFR_BLOCK_DATA *) AllocateZeroPool (sizeof (IFR_BLOCK_DATA));
+ if (BlockArray == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ InitializeListHead (&BlockArray->Entry);
+
+ StringPtr = StrStr (ConfigElement, L"&OFFSET=");
+ ASSERT (StringPtr != NULL);
+
+ //
+ // Parse each <RequestElement> if exists
+ // Only <BlockName> format is supported by this help function.
+ // <BlockName> ::= &'OFFSET='<Number>&'WIDTH='<Number>
+ //
+ while (*StringPtr != 0 && StrnCmp (StringPtr, L"&OFFSET=", StrLen (L"&OFFSET=")) == 0) {
+ //
+ // Skip the &OFFSET= string
+ //
+ StringPtr += StrLen (L"&OFFSET=");
+
+ //
+ // Get Offset
+ //
+ Status = InternalHiiGetValueOfNumber (StringPtr, &TmpBuffer, &Length);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ Offset = 0;
+ CopyMem (
+ &Offset,
+ TmpBuffer,
+ (((Length + 1) / 2) < sizeof (UINT16)) ? ((Length + 1) / 2) : sizeof (UINT16)
+ );
+ FreePool (TmpBuffer);
+ TmpBuffer = NULL;
+
+ StringPtr += Length;
+ if (StrnCmp (StringPtr, L"&WIDTH=", StrLen (L"&WIDTH=")) != 0) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ StringPtr += StrLen (L"&WIDTH=");
+
+ //
+ // Get Width
+ //
+ Status = InternalHiiGetValueOfNumber (StringPtr, &TmpBuffer, &Length);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ Width = 0;
+ CopyMem (
+ &Width,
+ TmpBuffer,
+ (((Length + 1) / 2) < sizeof (UINT16)) ? ((Length + 1) / 2) : sizeof (UINT16)
+ );
+ FreePool (TmpBuffer);
+ TmpBuffer = NULL;
+
+ StringPtr += Length;
+ if (*StringPtr != 0 && *StringPtr != L'&') {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ if (StrnCmp (StringPtr, L"&VALUE=", StrLen (L"&VALUE=")) != 0) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ StringPtr += StrLen (L"&VALUE=");
+
+ //
+ // Get Value
+ //
+ Status = InternalHiiGetValueOfNumber (StringPtr, &TmpBuffer, &Length);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ StringPtr += Length;
+ if (*StringPtr != 0 && *StringPtr != L'&') {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ //
+ // Check whether VarBuffer is enough
+ //
+ if ((UINTN) (Offset + Width) > MaxBufferSize) {
+ DataBuffer = ReallocatePool (
+ MaxBufferSize,
+ Offset + Width + HII_LIB_DEFAULT_VARSTORE_SIZE,
+ DataBuffer
+ );
+ if (DataBuffer == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ MaxBufferSize = Offset + Width + HII_LIB_DEFAULT_VARSTORE_SIZE;
+ }
+
+ //
+ // Update the Block with configuration info
+ //
+ CopyMem (DataBuffer + Offset, TmpBuffer, Width);
+ FreePool (TmpBuffer);
+ TmpBuffer = NULL;
+
+ //
+ // Set new Block Data
+ //
+ NewBlockData = (IFR_BLOCK_DATA *) AllocateZeroPool (sizeof (IFR_BLOCK_DATA));
+ if (NewBlockData == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ NewBlockData->Offset = Offset;
+ NewBlockData->Width = Width;
+
+ //
+ // Insert the new block data into the block data array.
+ //
+ for (Link = BlockArray->Entry.ForwardLink; Link != &BlockArray->Entry; Link = Link->ForwardLink) {
+ BlockData = BASE_CR (Link, IFR_BLOCK_DATA, Entry);
+ if (NewBlockData->Offset == BlockData->Offset) {
+ if (NewBlockData->Width > BlockData->Width) {
+ BlockData->Width = NewBlockData->Width;
+ }
+ FreePool (NewBlockData);
+ break;
+ } else if (NewBlockData->Offset < BlockData->Offset) {
+ //
+ // Insert new block data as the previous one of this link.
+ //
+ InsertTailList (Link, &NewBlockData->Entry);
+ break;
+ }
+ }
+
+ //
+ // Insert new block data into the array tail.
+ //
+ if (Link == &BlockArray->Entry) {
+ InsertTailList (Link, &NewBlockData->Entry);
+ }
+
+ //
+ // If '\0', parsing is finished.
+ //
+ if (*StringPtr == 0) {
+ break;
+ }
+ //
+ // Go to next ConfigBlock
+ //
+ }
+
+ //
+ // Merge the aligned block data into the single block data.
+ //
+ Link = BlockArray->Entry.ForwardLink;
+ while ((Link != &BlockArray->Entry) && (Link->ForwardLink != &BlockArray->Entry)) {
+ BlockData = BASE_CR (Link, IFR_BLOCK_DATA, Entry);
+ NewBlockData = BASE_CR (Link->ForwardLink, IFR_BLOCK_DATA, Entry);
+ if ((NewBlockData->Offset >= BlockData->Offset) && (NewBlockData->Offset <= (BlockData->Offset + BlockData->Width))) {
+ if ((NewBlockData->Offset + NewBlockData->Width) > (BlockData->Offset + BlockData->Width)) {
+ BlockData->Width = (UINT16) (NewBlockData->Offset + NewBlockData->Width - BlockData->Offset);
+ }
+ RemoveEntryList (Link->ForwardLink);
+ FreePool (NewBlockData);
+ continue;
+ }
+ Link = Link->ForwardLink;
+ }
+
+ *VarBuffer = DataBuffer;
+ *CurrentBlockArray = BlockArray;
+ return EFI_SUCCESS;
+
+Done:
+ if (DataBuffer != NULL) {
+ FreePool (DataBuffer);
+ }
+
+ if (BlockArray != NULL) {
+ //
+ // Free Link Array CurrentBlockArray
+ //
+ while (!IsListEmpty (&BlockArray->Entry)) {
+ BlockData = BASE_CR (BlockArray->Entry.ForwardLink, IFR_BLOCK_DATA, Entry);
+ RemoveEntryList (&BlockData->Entry);
+ FreePool (BlockData);
+ }
+ FreePool (BlockArray);
+ }
+
+ return Status;
+}
+
+/**
+ This internal function parses IFR data to validate current setting.
+
+ @param ConfigResp ConfigResp string contains the current setting.
+ @param HiiPackageList Point to Hii package list.
+ @param PackageListLength The length of the pacakge.
+ @param VarGuid Guid of the buffer storage.
+ @param VarName Name of the buffer storage.
+ @param HiiHandle The HiiHandle for this package.
+
+ @retval EFI_SUCCESS The current setting is valid.
+ @retval EFI_OUT_OF_RESOURCES The memory is not enough.
+ @retval EFI_INVALID_PARAMETER The config string or the Hii package is invalid.
+**/
+EFI_STATUS
+EFIAPI
+InternalHiiValidateCurrentSetting (
+ IN EFI_STRING ConfigResp,
+ IN EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList,
+ IN UINTN PackageListLength,
+ IN EFI_GUID *VarGuid,
+ IN CHAR16 *VarName,
+ IN EFI_HII_HANDLE HiiHandle
+ )
+{
+ CHAR16 *StringPtr;
+ EFI_STATUS Status;
+ IFR_BLOCK_DATA *CurrentBlockArray;
+ IFR_BLOCK_DATA *BlockData;
+ UINT8 *VarBuffer;
+ BOOLEAN NameValueType;
+
+ CurrentBlockArray = NULL;
+ VarBuffer = NULL;
+ StringPtr = NULL;
+ Status = EFI_SUCCESS;
+
+ //
+ // If StringPtr != NULL, get the request elements.
+ //
+ if (StrStr (ConfigResp, L"&OFFSET=") != NULL) {
+ Status = GetBlockDataInfo(ConfigResp, &CurrentBlockArray, &VarBuffer);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ NameValueType = FALSE;
+ } else {
+ //
+ // Skip header part.
+ //
+ StringPtr = StrStr (ConfigResp, L"PATH=");
+ ASSERT (StringPtr != NULL);
+
+ if (StrStr (StringPtr, L"&") != NULL) {
+ NameValueType = TRUE;
+ } else {
+ //
+ // Not found Request element, return success.
+ //
+ return EFI_SUCCESS;
+ }
+ }
+
+ Status = ValidateQuestionFromVfr(
+ HiiPackageList,
+ PackageListLength,
+ VarGuid,
+ VarName,
+ VarBuffer,
+ CurrentBlockArray,
+ ConfigResp,
+ HiiHandle,
+ NameValueType
+ );
+
+ if (VarBuffer != NULL) {
+ FreePool (VarBuffer);
+ }
+
+ if (CurrentBlockArray != NULL) {
+ //
+ // Free Link Array CurrentBlockArray
+ //
+ while (!IsListEmpty (&CurrentBlockArray->Entry)) {
+ BlockData = BASE_CR (CurrentBlockArray->Entry.ForwardLink, IFR_BLOCK_DATA, Entry);
+ RemoveEntryList (&BlockData->Entry);
+ FreePool (BlockData);
+ }
+ FreePool (CurrentBlockArray);
+ }
+
+ return Status;
+}
+
+/**
+ Check whether the ConfigRequest string has the request elements.
+ For EFI_HII_VARSTORE_BUFFER type, the request has "&OFFSET=****&WIDTH=****..." format.
+ For EFI_HII_VARSTORE_NAME_VALUE type, the request has "&NAME1**&NAME2..." format.
+
+ @param ConfigRequest The input config request string.
+
+ @retval TRUE The input include config request elements.
+ @retval FALSE The input string not includes.
+
+**/
+BOOLEAN
+GetElementsFromRequest (
+ IN EFI_STRING ConfigRequest
+ )
+{
+ EFI_STRING TmpRequest;
+
+ TmpRequest = StrStr (ConfigRequest, L"PATH=");
+ ASSERT (TmpRequest != NULL);
+
+ if ((StrStr (TmpRequest, L"&OFFSET=") != NULL) || (StrStr (TmpRequest, L"&") != NULL)) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ This function parses the input ConfigRequest string and its matched IFR code
+ string for setting default value and validating current setting.
+
+ 1. For setting default action, Reset the default value specified by DefaultId
+ to the driver configuration got by Request string.
+ 2. For validating current setting, Validate the current configuration
+ by parsing HII form IFR opcode.
+
+ NULL request string support depends on the ExportConfig interface of
+ HiiConfigRouting protocol in UEFI specification.
+
+ @param Request A null-terminated Unicode string in
+ <MultiConfigRequest> format. It can be NULL.
+ If it is NULL, all current configuration for the
+ entirety of the current HII database will be validated.
+ If it is NULL, all configuration for the
+ entirety of the current HII database will be reset.
+ @param DefaultId Specifies the type of defaults to retrieve only for setting default action.
+ @param ActionType Action supports setting defaults and validate current setting.
+
+ @retval TURE Action runs successfully.
+ @retval FALSE Action is not valid or Action can't be executed successfully..
+**/
+BOOLEAN
+EFIAPI
+InternalHiiIfrValueAction (
+ IN CONST EFI_STRING Request, OPTIONAL
+ IN UINT16 DefaultId,
+ IN UINT8 ActionType
+ )
+{
+ EFI_STRING ConfigAltResp;
+ EFI_STRING ConfigAltHdr;
+ EFI_STRING ConfigResp;
+ EFI_STRING Progress;
+ EFI_STRING StringPtr;
+ EFI_STRING StringHdr;
+ EFI_STATUS Status;
+ EFI_HANDLE DriverHandle;
+ EFI_HANDLE TempDriverHandle;
+ EFI_HII_HANDLE *HiiHandleBuffer;
+ EFI_HII_HANDLE HiiHandle;
+ UINT32 Index;
+ EFI_GUID *VarGuid;
+ EFI_STRING VarName;
+
+ EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList;
+ UINTN PackageListLength;
+ UINTN MaxLen;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
+
+ ConfigAltResp = NULL;
+ ConfigResp = NULL;
+ VarGuid = NULL;
+ VarName = NULL;
+ DevicePath = NULL;
+ ConfigAltHdr = NULL;
+ HiiHandleBuffer = NULL;
+ Index = 0;
+ TempDriverHandle = NULL;
+ HiiHandle = NULL;
+ HiiPackageList = NULL;
+
+ //
+ // Only support set default and validate setting action.
+ //
+ if ((ActionType != ACTION_SET_DEFAUTL_VALUE) && (ActionType != ACTION_VALIDATE_SETTING)) {
+ return FALSE;
+ }
+
+ //
+ // Get the full requested value and deault value string.
+ //
+ if (Request != NULL) {
+ Status = gHiiConfigRouting->ExtractConfig (
+ gHiiConfigRouting,
+ Request,
+ &Progress,
+ &ConfigAltResp
+ );
+ } else {
+ Status = gHiiConfigRouting->ExportConfig (
+ gHiiConfigRouting,
+ &ConfigAltResp
+ );
+ }
+
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ StringPtr = ConfigAltResp;
+
+ while (StringPtr != L'\0') {
+ //
+ // 1. Find <ConfigHdr> GUID=...&NAME=...&PATH=...
+ //
+ StringHdr = StringPtr;
+
+ //
+ // Get Guid value
+ //
+ if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ StringPtr += StrLen (L"GUID=");
+ Status = InternalHiiGetBufferFromString (StringPtr, GUID_CONFIG_STRING_TYPE, (UINT8 **) &VarGuid);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Get Name value VarName
+ //
+ while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&NAME=", StrLen (L"&NAME=")) != 0) {
+ StringPtr++;
+ }
+ if (*StringPtr == L'\0') {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ StringPtr += StrLen (L"&NAME=");
+ Status = InternalHiiGetBufferFromString (StringPtr, NAME_CONFIG_STRING_TYPE, (UINT8 **) &VarName);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Get Path value DevicePath
+ //
+ while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&PATH=", StrLen (L"&PATH=")) != 0) {
+ StringPtr++;
+ }
+ if (*StringPtr == L'\0') {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ StringPtr += StrLen (L"&PATH=");
+ Status = InternalHiiGetBufferFromString (StringPtr, PATH_CONFIG_STRING_TYPE, (UINT8 **) &DevicePath);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Get the Driver handle by the got device path.
+ //
+ TempDevicePath = DevicePath;
+ Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &TempDevicePath, &DriverHandle);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Find the matched Hii Handle for the found Driver handle
+ //
+ HiiHandleBuffer = HiiGetHiiHandles (NULL);
+ if (HiiHandleBuffer == NULL) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+
+ for (Index = 0; HiiHandleBuffer[Index] != NULL; Index ++) {
+ gHiiDatabase->GetPackageListHandle (gHiiDatabase, HiiHandleBuffer[Index], &TempDriverHandle);
+ if (TempDriverHandle == DriverHandle) {
+ break;
+ }
+ }
+
+ HiiHandle = HiiHandleBuffer[Index];
+ FreePool (HiiHandleBuffer);
+
+ if (HiiHandle == NULL) {
+ //
+ // This request string has no its Hii package.
+ // Its default value and validating can't execute by parsing IFR data.
+ // Directly jump into the next ConfigAltResp string for another pair Guid, Name, and Path.
+ //
+ Status = EFI_SUCCESS;
+ goto NextConfigAltResp;
+ }
+
+ //
+ // 2. Get HiiPackage by HiiHandle
+ //
+ PackageListLength = 0;
+ HiiPackageList = NULL;
+ Status = gHiiDatabase->ExportPackageLists (gHiiDatabase, HiiHandle, &PackageListLength, HiiPackageList);
+
+ //
+ // The return status should always be EFI_BUFFER_TOO_SMALL as input buffer's size is 0.
+ //
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ HiiPackageList = AllocatePool (PackageListLength);
+ if (HiiPackageList == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ //
+ // Get PackageList on HiiHandle
+ //
+ Status = gHiiDatabase->ExportPackageLists (gHiiDatabase, HiiHandle, &PackageListLength, HiiPackageList);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // 3. Call ConfigRouting GetAltCfg(ConfigRoute, <ConfigResponse>, Guid, Name, DevicePath, AltCfgId, AltCfgResp)
+ // Get the default configuration string according to the default ID.
+ //
+ Status = gHiiConfigRouting->GetAltConfig (
+ gHiiConfigRouting,
+ ConfigAltResp,
+ VarGuid,
+ VarName,
+ DevicePath,
+ (ActionType == ACTION_SET_DEFAUTL_VALUE) ? &DefaultId:NULL, // it can be NULL to get the current setting.
+ &ConfigResp
+ );
+
+ //
+ // The required setting can't be found. So, it is not required to be validated and set.
+ //
+ if (EFI_ERROR (Status)) {
+ Status = EFI_SUCCESS;
+ goto NextConfigAltResp;
+ }
+ //
+ // Only the ConfigHdr is found. Not any block data is found. No data is required to be validated and set.
+ //
+ if (!GetElementsFromRequest (ConfigResp)) {
+ goto NextConfigAltResp;
+ }
+
+ //
+ // 4. Set the default configuration information or Validate current setting by parse IFR code.
+ // Current Setting is in ConfigResp, will be set into buffer, then check it again.
+ //
+ if (ActionType == ACTION_SET_DEFAUTL_VALUE) {
+ //
+ // Set the default configuration information.
+ //
+ Status = gHiiConfigRouting->RouteConfig (gHiiConfigRouting, ConfigResp, &Progress);
+ } else {
+ //
+ // Current Setting is in ConfigResp, will be set into buffer, then check it again.
+ //
+ Status = InternalHiiValidateCurrentSetting (ConfigResp, HiiPackageList, PackageListLength, VarGuid, VarName, HiiHandle);
+ }
+
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+NextConfigAltResp:
+ //
+ // Free the allocated pacakge buffer and the got ConfigResp string.
+ //
+ if (HiiPackageList != NULL) {
+ FreePool (HiiPackageList);
+ HiiPackageList = NULL;
+ }
+
+ if (ConfigResp != NULL) {
+ FreePool (ConfigResp);
+ ConfigResp = NULL;
+ }
+
+ //
+ // Free the allocated buffer.
+ //
+ FreePool (VarGuid);
+ VarGuid = NULL;
+
+ FreePool (VarName);
+ VarName = NULL;
+
+ FreePool (DevicePath);
+ DevicePath = NULL;
+
+ //
+ // 5. Jump to next ConfigAltResp for another Guid, Name, Path.
+ //
+
+ //
+ // Get and Skip ConfigHdr
+ //
+ while (*StringPtr != L'\0' && *StringPtr != L'&') {
+ StringPtr++;
+ }
+ if (*StringPtr == L'\0') {
+ break;
+ }
+
+ //
+ // Construct ConfigAltHdr string "&<ConfigHdr>&ALTCFG=\0"
+ // | 1 | StrLen (ConfigHdr) | 8 | 1 |
+ //
+ MaxLen = 1 + StringPtr - StringHdr + 8 + 1;
+ ConfigAltHdr = AllocateZeroPool ( MaxLen * sizeof (CHAR16));
+ if (ConfigAltHdr == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ StrCpyS (ConfigAltHdr, MaxLen, L"&");
+ StrnCatS (ConfigAltHdr, MaxLen, StringHdr, StringPtr - StringHdr);
+ StrCatS (ConfigAltHdr, MaxLen, L"&ALTCFG=");
+
+ //
+ // Skip all AltResp (AltConfigHdr ConfigBody) for the same ConfigHdr
+ //
+ while ((StringHdr = StrStr (StringPtr, ConfigAltHdr)) != NULL) {
+ StringPtr = StringHdr + StrLen (ConfigAltHdr);
+ if (*StringPtr == L'\0') {
+ break;
+ }
+ }
+
+ //
+ // Free the allocated ConfigAltHdr string
+ //
+ FreePool (ConfigAltHdr);
+ if (*StringPtr == L'\0') {
+ break;
+ }
+
+ //
+ // Find &GUID as the next ConfigHdr
+ //
+ StringPtr = StrStr (StringPtr, L"&GUID");
+ if (StringPtr == NULL) {
+ break;
+ }
+
+ //
+ // Skip char '&'
+ //
+ StringPtr ++;
+ }
+
+Done:
+ if (VarGuid != NULL) {
+ FreePool (VarGuid);
+ }
+
+ if (VarName != NULL) {
+ FreePool (VarName);
+ }
+
+ if (DevicePath != NULL) {
+ FreePool (DevicePath);
+ }
+
+ if (ConfigResp != NULL) {
+ FreePool (ConfigResp);
+ }
+
+ if (ConfigAltResp != NULL) {
+ FreePool (ConfigAltResp);
+ }
+
+ if (HiiPackageList != NULL) {
+ FreePool (HiiPackageList);
+ }
+
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ Validate the current configuration by parsing HII form IFR opcode.
+
+ NULL request string support depends on the ExportConfig interface of
+ HiiConfigRouting protocol in UEFI specification.
+
+ @param Request A null-terminated Unicode string in
+ <MultiConfigRequest> format. It can be NULL.
+ If it is NULL, all current configuration for the
+ entirety of the current HII database will be validated.
+
+ @retval TRUE Current configuration is valid.
+ @retval FALSE Current configuration is invalid.
+**/
+BOOLEAN
+EFIAPI
+HiiValidateSettings (
+ IN CONST EFI_STRING Request OPTIONAL
+ )
+{
+ return InternalHiiIfrValueAction (Request, 0, ACTION_VALIDATE_SETTING);
+}
+
+/**
+ Reset the default value specified by DefaultId to the driver
+ configuration got by Request string.
+
+ NULL request string support depends on the ExportConfig interface of
+ HiiConfigRouting protocol in UEFI specification.
+
+ @param Request A null-terminated Unicode string in
+ <MultiConfigRequest> format. It can be NULL.
+ If it is NULL, all configuration for the
+ entirety of the current HII database will be reset.
+ @param DefaultId Specifies the type of defaults to retrieve.
+
+ @retval TURE The default value is set successfully.
+ @retval FALSE The default value can't be found and set.
+**/
+BOOLEAN
+EFIAPI
+HiiSetToDefaults (
+ IN CONST EFI_STRING Request, OPTIONAL
+ IN UINT16 DefaultId
+ )
+{
+ return InternalHiiIfrValueAction (Request, DefaultId, ACTION_SET_DEFAUTL_VALUE);
+}
+
+/**
+ Determines if two values in config strings match.
+
+ Compares the substring between StartSearchString and StopSearchString in
+ FirstString to the substring between StartSearchString and StopSearchString
+ in SecondString. If the two substrings match, then TRUE is returned. If the
+ two substrings do not match, then FALSE is returned.
+
+ If FirstString is NULL, then ASSERT().
+ If SecondString is NULL, then ASSERT().
+ If StartSearchString is NULL, then ASSERT().
+ If StopSearchString is NULL, then ASSERT().
+
+ @param FirstString Pointer to the first Null-terminated Unicode string.
+ @param SecondString Pointer to the second Null-terminated Unicode string.
+ @param StartSearchString Pointer to the Null-terminated Unicode string that
+ marks the start of the value string to compare.
+ @param StopSearchString Pointer to the Null-terminated Unicode string that
+ marks the end of the value string to compare.
+
+ @retval FALSE StartSearchString is not present in FirstString.
+ @retval FALSE StartSearchString is not present in SecondString.
+ @retval FALSE StopSearchString is not present in FirstString.
+ @retval FALSE StopSearchString is not present in SecondString.
+ @retval FALSE The length of the substring in FirstString is not the
+ same length as the substring in SecondString.
+ @retval FALSE The value string in FirstString does not matche the
+ value string in SecondString.
+ @retval TRUE The value string in FirstString matches the value
+ string in SecondString.
+
+**/
+BOOLEAN
+EFIAPI
+InternalHiiCompareSubString (
+ IN CHAR16 *FirstString,
+ IN CHAR16 *SecondString,
+ IN CHAR16 *StartSearchString,
+ IN CHAR16 *StopSearchString
+ )
+{
+ CHAR16 *EndFirstString;
+ CHAR16 *EndSecondString;
+
+ ASSERT (FirstString != NULL);
+ ASSERT (SecondString != NULL);
+ ASSERT (StartSearchString != NULL);
+ ASSERT (StopSearchString != NULL);
+
+ FirstString = StrStr (FirstString, StartSearchString);
+ if (FirstString == NULL) {
+ return FALSE;
+ }
+
+ SecondString = StrStr (SecondString, StartSearchString);
+ if (SecondString == NULL) {
+ return FALSE;
+ }
+
+ EndFirstString = StrStr (FirstString, StopSearchString);
+ if (EndFirstString == NULL) {
+ return FALSE;
+ }
+
+ EndSecondString = StrStr (SecondString, StopSearchString);
+ if (EndSecondString == NULL) {
+ return FALSE;
+ }
+
+ if ((EndFirstString - FirstString) != (EndSecondString - SecondString)) {
+ return FALSE;
+ }
+
+ return (BOOLEAN)(StrnCmp (FirstString, SecondString, EndFirstString - FirstString) == 0);
+}
+
+/**
+ Determines if the routing data specified by GUID and NAME match a <ConfigHdr>.
+
+ If ConfigHdr is NULL, then ASSERT().
+
+ @param[in] ConfigHdr Either <ConfigRequest> or <ConfigResp>.
+ @param[in] Guid GUID of the storage.
+ @param[in] Name NAME of the storage.
+
+ @retval TRUE Routing information matches <ConfigHdr>.
+ @retval FALSE Routing information does not match <ConfigHdr>.
+
+**/
+BOOLEAN
+EFIAPI
+HiiIsConfigHdrMatch (
+ IN CONST EFI_STRING ConfigHdr,
+ IN CONST EFI_GUID *Guid, OPTIONAL
+ IN CONST CHAR16 *Name OPTIONAL
+ )
+{
+ EFI_STRING CompareConfigHdr;
+ BOOLEAN Result;
+
+ ASSERT (ConfigHdr != NULL);
+
+ //
+ // Use Guid and Name to generate a <ConfigHdr> string
+ //
+ CompareConfigHdr = HiiConstructConfigHdr (Guid, Name, NULL);
+ if (CompareConfigHdr == NULL) {
+ return FALSE;
+ }
+
+ Result = TRUE;
+ if (Guid != NULL) {
+ //
+ // Compare GUID value strings
+ //
+ Result = InternalHiiCompareSubString (ConfigHdr, CompareConfigHdr, L"GUID=", L"&NAME=");
+ }
+
+ if (Result && Name != NULL) {
+ //
+ // Compare NAME value strings
+ //
+ Result = InternalHiiCompareSubString (ConfigHdr, CompareConfigHdr, L"&NAME=", L"&PATH=");
+ }
+
+ //
+ // Free the <ConfigHdr> string
+ //
+ FreePool (CompareConfigHdr);
+
+ return Result;
+}
+
+/**
+ Retrieves uncommitted data from the Form Browser and converts it to a binary
+ buffer.
+
+ @param[in] VariableGuid Pointer to an EFI_GUID structure. This is an optional
+ parameter that may be NULL.
+ @param[in] VariableName Pointer to a Null-terminated Unicode string. This
+ is an optional parameter that may be NULL.
+ @param[in] BufferSize Length in bytes of buffer to hold retrieved data.
+ @param[out] Buffer Buffer of data to be updated.
+
+ @retval FALSE The uncommitted data could not be retrieved.
+ @retval TRUE The uncommitted data was retrieved.
+
+**/
+BOOLEAN
+EFIAPI
+HiiGetBrowserData (
+ IN CONST EFI_GUID *VariableGuid, OPTIONAL
+ IN CONST CHAR16 *VariableName, OPTIONAL
+ IN UINTN BufferSize,
+ OUT UINT8 *Buffer
+ )
+{
+ EFI_STRING ResultsData;
+ UINTN Size;
+ EFI_STRING ConfigResp;
+ EFI_STATUS Status;
+ CHAR16 *Progress;
+
+ //
+ // Retrieve the results data from the Browser Callback
+ //
+ ResultsData = InternalHiiBrowserCallback (VariableGuid, VariableName, NULL);
+ if (ResultsData == NULL) {
+ return FALSE;
+ }
+
+ //
+ // Construct <ConfigResp> mConfigHdrTemplate L'&' ResultsData L'\0'
+ //
+ Size = (StrLen (mConfigHdrTemplate) + 1) * sizeof (CHAR16);
+ Size = Size + (StrLen (ResultsData) + 1) * sizeof (CHAR16);
+ ConfigResp = AllocateZeroPool (Size);
+ UnicodeSPrint (ConfigResp, Size, L"%s&%s", mConfigHdrTemplate, ResultsData);
+
+ //
+ // Free the allocated buffer
+ //
+ FreePool (ResultsData);
+ if (ConfigResp == NULL) {
+ return FALSE;
+ }
+
+ //
+ // Convert <ConfigResp> to a buffer
+ //
+ Status = gHiiConfigRouting->ConfigToBlock (
+ gHiiConfigRouting,
+ ConfigResp,
+ Buffer,
+ &BufferSize,
+ &Progress
+ );
+ //
+ // Free the allocated buffer
+ //
+ FreePool (ConfigResp);
+
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ Updates uncommitted data in the Form Browser.
+
+ If Buffer is NULL, then ASSERT().
+
+ @param[in] VariableGuid Pointer to an EFI_GUID structure. This is an optional
+ parameter that may be NULL.
+ @param[in] VariableName Pointer to a Null-terminated Unicode string. This
+ is an optional parameter that may be NULL.
+ @param[in] BufferSize Length, in bytes, of Buffer.
+ @param[in] Buffer Buffer of data to commit.
+ @param[in] RequestElement An optional field to specify which part of the
+ buffer data will be send back to Browser. If NULL,
+ the whole buffer of data will be committed to
+ Browser.
+ <RequestElement> ::= &OFFSET=<Number>&WIDTH=<Number>*
+
+ @retval FALSE The uncommitted data could not be updated.
+ @retval TRUE The uncommitted data was updated.
+
+**/
+BOOLEAN
+EFIAPI
+HiiSetBrowserData (
+ IN CONST EFI_GUID *VariableGuid, OPTIONAL
+ IN CONST CHAR16 *VariableName, OPTIONAL
+ IN UINTN BufferSize,
+ IN CONST UINT8 *Buffer,
+ IN CONST CHAR16 *RequestElement OPTIONAL
+ )
+{
+ UINTN Size;
+ EFI_STRING ConfigRequest;
+ EFI_STRING ConfigResp;
+ EFI_STRING ResultsData;
+
+ ASSERT (Buffer != NULL);
+
+ //
+ // Construct <ConfigRequest>
+ //
+ if (RequestElement == NULL) {
+ //
+ // Allocate and fill a buffer large enough to hold the <ConfigHdr> template
+ // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator
+ //
+ Size = (StrLen (mConfigHdrTemplate) + 32 + 1) * sizeof (CHAR16);
+ ConfigRequest = AllocateZeroPool (Size);
+ UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=0&WIDTH=%016LX", mConfigHdrTemplate, (UINT64)BufferSize);
+ } else {
+ //
+ // Allocate and fill a buffer large enough to hold the <ConfigHdr> template
+ // followed by <RequestElement> followed by a Null-terminator
+ //
+ Size = StrLen (mConfigHdrTemplate) * sizeof (CHAR16);
+ Size = Size + (StrLen (RequestElement) + 1) * sizeof (CHAR16);
+ ConfigRequest = AllocateZeroPool (Size);
+ UnicodeSPrint (ConfigRequest, Size, L"%s%s", mConfigHdrTemplate, RequestElement);
+ }
+ if (ConfigRequest == NULL) {
+ return FALSE;
+ }
+
+ //
+ // Convert <ConfigRequest> to <ConfigResp>
+ //
+ ConfigResp = InternalHiiBlockToConfig (ConfigRequest, Buffer, BufferSize);
+ FreePool (ConfigRequest);
+ if (ConfigResp == NULL) {
+ return FALSE;
+ }
+
+ //
+ // Set data in the uncommitted browser state information
+ //
+ ResultsData = InternalHiiBrowserCallback (VariableGuid, VariableName, ConfigResp + StrLen(mConfigHdrTemplate) + 1);
+ FreePool (ConfigResp);
+
+ return (BOOLEAN)(ResultsData != NULL);
+}
+
+/////////////////////////////////////////
+/////////////////////////////////////////
+/// IFR Functions
+/////////////////////////////////////////
+/////////////////////////////////////////
+
+#define HII_LIB_OPCODE_ALLOCATION_SIZE 0x200
+
+typedef struct {
+ UINT8 *Buffer;
+ UINTN BufferSize;
+ UINTN Position;
+} HII_LIB_OPCODE_BUFFER;
+
+///
+/// Lookup table that converts EFI_IFR_TYPE_X enum values to a width in bytes
+///
+GLOBAL_REMOVE_IF_UNREFERENCED CONST UINT8 mHiiDefaultTypeToWidth[] = {
+ 1, // EFI_IFR_TYPE_NUM_SIZE_8
+ 2, // EFI_IFR_TYPE_NUM_SIZE_16
+ 4, // EFI_IFR_TYPE_NUM_SIZE_32
+ 8, // EFI_IFR_TYPE_NUM_SIZE_64
+ 1, // EFI_IFR_TYPE_BOOLEAN
+ 3, // EFI_IFR_TYPE_TIME
+ 4, // EFI_IFR_TYPE_DATE
+ 2 // EFI_IFR_TYPE_STRING
+};
+
+/**
+ Allocates and returns a new OpCode Handle. OpCode Handles must be freed with
+ HiiFreeOpCodeHandle().
+
+ @retval NULL There are not enough resources to allocate a new OpCode Handle.
+ @retval Other A new OpCode handle.
+
+**/
+VOID *
+EFIAPI
+HiiAllocateOpCodeHandle (
+ VOID
+ )
+{
+ HII_LIB_OPCODE_BUFFER *OpCodeBuffer;
+
+ OpCodeBuffer = (HII_LIB_OPCODE_BUFFER *)AllocatePool (sizeof (HII_LIB_OPCODE_BUFFER));
+ if (OpCodeBuffer == NULL) {
+ return NULL;
+ }
+ OpCodeBuffer->Buffer = (UINT8 *)AllocatePool (HII_LIB_OPCODE_ALLOCATION_SIZE);
+ if (OpCodeBuffer->Buffer == NULL) {
+ FreePool (OpCodeBuffer);
+ return NULL;
+ }
+ OpCodeBuffer->BufferSize = HII_LIB_OPCODE_ALLOCATION_SIZE;
+ OpCodeBuffer->Position = 0;
+ return (VOID *)OpCodeBuffer;
+}
+
+/**
+ Frees an OpCode Handle that was previously allocated with HiiAllocateOpCodeHandle().
+ When an OpCode Handle is freed, all of the opcodes associated with the OpCode
+ Handle are also freed.
+
+ If OpCodeHandle is NULL, then ASSERT().
+
+ @param[in] OpCodeHandle Handle to the buffer of opcodes.
+
+**/
+VOID
+EFIAPI
+HiiFreeOpCodeHandle (
+ VOID *OpCodeHandle
+ )
+{
+ HII_LIB_OPCODE_BUFFER *OpCodeBuffer;
+
+ ASSERT (OpCodeHandle != NULL);
+
+ OpCodeBuffer = (HII_LIB_OPCODE_BUFFER *)OpCodeHandle;
+ if (OpCodeBuffer->Buffer != NULL) {
+ FreePool (OpCodeBuffer->Buffer);
+ }
+ FreePool (OpCodeBuffer);
+}
+
+/**
+ Internal function gets the current position of opcode buffer.
+
+ @param[in] OpCodeHandle Handle to the buffer of opcodes.
+
+ @return Current position of opcode buffer.
+**/
+UINTN
+EFIAPI
+InternalHiiOpCodeHandlePosition (
+ IN VOID *OpCodeHandle
+ )
+{
+ return ((HII_LIB_OPCODE_BUFFER *)OpCodeHandle)->Position;
+}
+
+/**
+ Internal function gets the start pointer of opcode buffer.
+
+ @param[in] OpCodeHandle Handle to the buffer of opcodes.
+
+ @return Pointer to the opcode buffer base.
+**/
+UINT8 *
+EFIAPI
+InternalHiiOpCodeHandleBuffer (
+ IN VOID *OpCodeHandle
+ )
+{
+ return ((HII_LIB_OPCODE_BUFFER *)OpCodeHandle)->Buffer;
+}
+
+/**
+ Internal function reserves the enough buffer for current opcode.
+ When the buffer is not enough, Opcode buffer will be extended.
+
+ @param[in] OpCodeHandle Handle to the buffer of opcodes.
+ @param[in] Size Size of current opcode.
+
+ @return Pointer to the current opcode.
+**/
+UINT8 *
+EFIAPI
+InternalHiiGrowOpCodeHandle (
+ IN VOID *OpCodeHandle,
+ IN UINTN Size
+ )
+{
+ HII_LIB_OPCODE_BUFFER *OpCodeBuffer;
+ UINT8 *Buffer;
+
+ ASSERT (OpCodeHandle != NULL);
+
+ OpCodeBuffer = (HII_LIB_OPCODE_BUFFER *)OpCodeHandle;
+ if (OpCodeBuffer->Position + Size > OpCodeBuffer->BufferSize) {
+ Buffer = ReallocatePool (
+ OpCodeBuffer->BufferSize,
+ OpCodeBuffer->BufferSize + (Size + HII_LIB_OPCODE_ALLOCATION_SIZE),
+ OpCodeBuffer->Buffer
+ );
+ ASSERT (Buffer != NULL);
+ OpCodeBuffer->Buffer = Buffer;
+ OpCodeBuffer->BufferSize += (Size + HII_LIB_OPCODE_ALLOCATION_SIZE);
+ }
+ Buffer = OpCodeBuffer->Buffer + OpCodeBuffer->Position;
+ OpCodeBuffer->Position += Size;
+ return Buffer;
+}
+
+/**
+ Internal function creates opcode based on the template opcode.
+
+ @param[in] OpCodeHandle Handle to the buffer of opcodes.
+ @param[in] OpCodeTemplate Pointer to the template buffer of opcode.
+ @param[in] OpCode OpCode IFR value.
+ @param[in] OpCodeSize Size of opcode.
+ @param[in] ExtensionSize Size of extended opcode.
+ @param[in] Scope Scope bit of opcode.
+
+ @return Pointer to the current opcode with opcode data.
+**/
+UINT8 *
+EFIAPI
+InternalHiiCreateOpCodeExtended (
+ IN VOID *OpCodeHandle,
+ IN VOID *OpCodeTemplate,
+ IN UINT8 OpCode,
+ IN UINTN OpCodeSize,
+ IN UINTN ExtensionSize,
+ IN UINT8 Scope
+ )
+{
+ EFI_IFR_OP_HEADER *Header;
+ UINT8 *Buffer;
+
+ ASSERT (OpCodeTemplate != NULL);
+ ASSERT ((OpCodeSize + ExtensionSize) <= 0x7F);
+
+ Header = (EFI_IFR_OP_HEADER *)OpCodeTemplate;
+ Header->OpCode = OpCode;
+ Header->Scope = Scope;
+ Header->Length = (UINT8)(OpCodeSize + ExtensionSize);
+ Buffer = InternalHiiGrowOpCodeHandle (OpCodeHandle, Header->Length);
+ return (UINT8 *)CopyMem (Buffer, Header, OpCodeSize);
+}
+
+/**
+ Internal function creates opcode based on the template opcode for the normal opcode.
+
+ @param[in] OpCodeHandle Handle to the buffer of opcodes.
+ @param[in] OpCodeTemplate Pointer to the template buffer of opcode.
+ @param[in] OpCode OpCode IFR value.
+ @param[in] OpCodeSize Size of opcode.
+
+ @return Pointer to the current opcode with opcode data.
+**/
+UINT8 *
+EFIAPI
+InternalHiiCreateOpCode (
+ IN VOID *OpCodeHandle,
+ IN VOID *OpCodeTemplate,
+ IN UINT8 OpCode,
+ IN UINTN OpCodeSize
+ )
+{
+ return InternalHiiCreateOpCodeExtended (OpCodeHandle, OpCodeTemplate, OpCode, OpCodeSize, 0, 0);
+}
+
+/**
+ Append raw opcodes to an OpCodeHandle.
+
+ If OpCodeHandle is NULL, then ASSERT().
+ If RawBuffer is NULL, then ASSERT();
+
+ @param[in] OpCodeHandle Handle to the buffer of opcodes.
+ @param[in] RawBuffer Buffer of opcodes to append.
+ @param[in] RawBufferSize The size, in bytes, of Buffer.
+
+ @retval NULL There is not enough space left in Buffer to add the opcode.
+ @retval Other A pointer to the appended opcodes.
+
+**/
+UINT8 *
+EFIAPI
+HiiCreateRawOpCodes (
+ IN VOID *OpCodeHandle,
+ IN UINT8 *RawBuffer,
+ IN UINTN RawBufferSize
+ )
+{
+ UINT8 *Buffer;
+
+ ASSERT (RawBuffer != NULL);
+
+ Buffer = InternalHiiGrowOpCodeHandle (OpCodeHandle, RawBufferSize);
+ return (UINT8 *)CopyMem (Buffer, RawBuffer, RawBufferSize);
+}
+
+/**
+ Append opcodes from one OpCode Handle to another OpCode handle.
+
+ If OpCodeHandle is NULL, then ASSERT().
+ If RawOpCodeHandle is NULL, then ASSERT();
+
+ @param[in] OpCodeHandle Handle to the buffer of opcodes.
+ @param[in] RawOpCodeHandle Handle to the buffer of opcodes.
+
+ @retval NULL There is not enough space left in Buffer to add the opcode.
+ @retval Other A pointer to the appended opcodes.
+
+**/
+UINT8 *
+EFIAPI
+InternalHiiAppendOpCodes (
+ IN VOID *OpCodeHandle,
+ IN VOID *RawOpCodeHandle
+ )
+{
+ HII_LIB_OPCODE_BUFFER *RawOpCodeBuffer;
+
+ ASSERT (RawOpCodeHandle != NULL);
+
+ RawOpCodeBuffer = (HII_LIB_OPCODE_BUFFER *)RawOpCodeHandle;
+ return HiiCreateRawOpCodes (OpCodeHandle, RawOpCodeBuffer->Buffer, RawOpCodeBuffer->Position);
+}
+
+/**
+ Create EFI_IFR_END_OP opcode.
+
+ If OpCodeHandle is NULL, then ASSERT().
+
+ @param[in] OpCodeHandle Handle to the buffer of opcodes.
+
+ @retval NULL There is not enough space left in Buffer to add the opcode.
+ @retval Other A pointer to the created opcode.
+
+**/
+UINT8 *
+EFIAPI
+HiiCreateEndOpCode (
+ IN VOID *OpCodeHandle
+ )
+{
+ EFI_IFR_END OpCode;
+
+ return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_END_OP, sizeof (OpCode));
+}
+
+/**
+ Create EFI_IFR_ONE_OF_OPTION_OP opcode.
+
+ If OpCodeHandle is NULL, then ASSERT().
+ If Type is invalid, then ASSERT().
+ If Flags is invalid, then ASSERT().
+
+ @param[in] OpCodeHandle Handle to the buffer of opcodes.
+ @param[in] StringId StringId for the option
+ @param[in] Flags Flags for the option
+ @param[in] Type Type for the option
+ @param[in] Value Value for the option
+
+ @retval NULL There is not enough space left in Buffer to add the opcode.
+ @retval Other A pointer to the created opcode.
+
+**/
+UINT8 *
+EFIAPI
+HiiCreateOneOfOptionOpCode (
+ IN VOID *OpCodeHandle,
+ IN UINT16 StringId,
+ IN UINT8 Flags,
+ IN UINT8 Type,
+ IN UINT64 Value
+ )
+{
+ EFI_IFR_ONE_OF_OPTION OpCode;
+
+ ASSERT (Type < EFI_IFR_TYPE_OTHER);
+
+ ZeroMem (&OpCode, sizeof (OpCode));
+ OpCode.Option = StringId;
+ OpCode.Flags = (UINT8) (Flags & (EFI_IFR_OPTION_DEFAULT | EFI_IFR_OPTION_DEFAULT_MFG));
+ OpCode.Type = Type;
+ CopyMem (&OpCode.Value, &Value, mHiiDefaultTypeToWidth[Type]);
+
+ return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_ONE_OF_OPTION_OP, OFFSET_OF(EFI_IFR_ONE_OF_OPTION, Value) + mHiiDefaultTypeToWidth[Type]);
+}
+
+/**
+ Create EFI_IFR_DEFAULT_OP opcode.
+
+ If OpCodeHandle is NULL, then ASSERT().
+ If Type is invalid, then ASSERT().
+
+ @param[in] OpCodeHandle Handle to the buffer of opcodes.
+ @param[in] DefaultId DefaultId for the default
+ @param[in] Type Type for the default
+ @param[in] Value Value for the default
+
+ @retval NULL There is not enough space left in Buffer to add the opcode.
+ @retval Other A pointer to the created opcode.
+
+**/
+UINT8 *
+EFIAPI
+HiiCreateDefaultOpCode (
+ IN VOID *OpCodeHandle,
+ IN UINT16 DefaultId,
+ IN UINT8 Type,
+ IN UINT64 Value
+ )
+{
+ EFI_IFR_DEFAULT OpCode;
+
+ ASSERT (Type < EFI_IFR_TYPE_OTHER);
+
+ ZeroMem (&OpCode, sizeof (OpCode));
+ OpCode.Type = Type;
+ OpCode.DefaultId = DefaultId;
+ CopyMem (&OpCode.Value, &Value, mHiiDefaultTypeToWidth[Type]);
+
+ return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_DEFAULT_OP, OFFSET_OF(EFI_IFR_DEFAULT, Value) + mHiiDefaultTypeToWidth[Type]);
+}
+
+/**
+ Create EFI_IFR_GUID opcode.
+
+ If OpCodeHandle is NULL, then ASSERT().
+ If Guid is NULL, then ASSERT().
+ If OpCodeSize < sizeof (EFI_IFR_GUID), then ASSERT().
+
+ @param[in] OpCodeHandle Handle to the buffer of opcodes.
+ @param[in] Guid Pointer to EFI_GUID of this guided opcode.
+ @param[in] GuidOpCode Pointer to an EFI_IFR_GUID opcode. This is an
+ optional parameter that may be NULL. If this
+ parameter is NULL, then the GUID extension
+ region of the created opcode is filled with zeros.
+ If this parameter is not NULL, then the GUID
+ extension region of GuidData will be copied to
+ the GUID extension region of the created opcode.
+ @param[in] OpCodeSize The size, in bytes, of created opcode. This value
+ must be >= sizeof(EFI_IFR_GUID).
+
+ @retval NULL There is not enough space left in Buffer to add the opcode.
+ @retval Other A pointer to the created opcode.
+
+**/
+UINT8 *
+EFIAPI
+HiiCreateGuidOpCode (
+ IN VOID *OpCodeHandle,
+ IN CONST EFI_GUID *Guid,
+ IN CONST VOID *GuidOpCode, OPTIONAL
+ IN UINTN OpCodeSize
+ )
+{
+ EFI_IFR_GUID OpCode;
+ EFI_IFR_GUID *OpCodePointer;
+
+ ASSERT (Guid != NULL);
+ ASSERT (OpCodeSize >= sizeof (OpCode));
+
+ ZeroMem (&OpCode, sizeof (OpCode));
+ CopyGuid ((EFI_GUID *)(VOID *)&OpCode.Guid, Guid);
+
+ OpCodePointer = (EFI_IFR_GUID *)InternalHiiCreateOpCodeExtended (
+ OpCodeHandle,
+ &OpCode,
+ EFI_IFR_GUID_OP,
+ sizeof (OpCode),
+ OpCodeSize - sizeof (OpCode),
+ 0
+ );
+ if (OpCodePointer != NULL && GuidOpCode != NULL) {
+ CopyMem (OpCodePointer + 1, (EFI_IFR_GUID *)GuidOpCode + 1, OpCodeSize - sizeof (OpCode));
+ }
+ return (UINT8 *)OpCodePointer;
+}
+
+/**
+ Create EFI_IFR_ACTION_OP opcode.
+
+ If OpCodeHandle is NULL, then ASSERT().
+ If any reserved bits are set in QuestionFlags, then ASSERT().
+
+ @param[in] OpCodeHandle Handle to the buffer of opcodes.
+ @param[in] QuestionId Question ID
+ @param[in] Prompt String ID for Prompt
+ @param[in] Help String ID for Help
+ @param[in] QuestionFlags Flags in Question Header
+ @param[in] QuestionConfig String ID for configuration
+
+ @retval NULL There is not enough space left in Buffer to add the opcode.
+ @retval Other A pointer to the created opcode.
+
+**/
+UINT8 *
+EFIAPI
+HiiCreateActionOpCode (
+ IN VOID *OpCodeHandle,
+ IN EFI_QUESTION_ID QuestionId,
+ IN EFI_STRING_ID Prompt,
+ IN EFI_STRING_ID Help,
+ IN UINT8 QuestionFlags,
+ IN EFI_STRING_ID QuestionConfig
+ )
+{
+ EFI_IFR_ACTION OpCode;
+
+ ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED))) == 0);
+
+ ZeroMem (&OpCode, sizeof (OpCode));
+ OpCode.Question.QuestionId = QuestionId;
+ OpCode.Question.Header.Prompt = Prompt;
+ OpCode.Question.Header.Help = Help;
+ OpCode.Question.Flags = QuestionFlags;
+ OpCode.QuestionConfig = QuestionConfig;
+
+ return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_ACTION_OP, sizeof (OpCode));
+}
+
+/**
+ Create EFI_IFR_SUBTITLE_OP opcode.
+
+ If OpCodeHandle is NULL, then ASSERT().
+ If any reserved bits are set in Flags, then ASSERT().
+ If Scope > 1, then ASSERT().
+
+ @param[in] OpCodeHandle Handle to the buffer of opcodes.
+ @param[in] Prompt String ID for Prompt
+ @param[in] Help String ID for Help
+ @param[in] Flags Subtitle opcode flags
+ @param[in] Scope 1 if this opcpde is the beginning of a new scope.
+ 0 if this opcode is within the current scope.
+
+ @retval NULL There is not enough space left in Buffer to add the opcode.
+ @retval Other A pointer to the created opcode.
+
+**/
+UINT8 *
+EFIAPI
+HiiCreateSubTitleOpCode (
+ IN VOID *OpCodeHandle,
+ IN EFI_STRING_ID Prompt,
+ IN EFI_STRING_ID Help,
+ IN UINT8 Flags,
+ IN UINT8 Scope
+ )
+{
+ EFI_IFR_SUBTITLE OpCode;
+
+ ASSERT (Scope <= 1);
+ ASSERT ((Flags & (~(EFI_IFR_FLAGS_HORIZONTAL))) == 0);
+
+ ZeroMem (&OpCode, sizeof (OpCode));
+ OpCode.Statement.Prompt = Prompt;
+ OpCode.Statement.Help = Help;
+ OpCode.Flags = Flags;
+
+ return InternalHiiCreateOpCodeExtended (
+ OpCodeHandle,
+ &OpCode,
+ EFI_IFR_SUBTITLE_OP,
+ sizeof (OpCode),
+ 0,
+ Scope
+ );
+}
+
+/**
+ Create EFI_IFR_REF_OP opcode.
+
+ If OpCodeHandle is NULL, then ASSERT().
+ If any reserved bits are set in QuestionFlags, then ASSERT().
+
+ @param[in] OpCodeHandle Handle to the buffer of opcodes.
+ @param[in] FormId Destination Form ID
+ @param[in] Prompt String ID for Prompt
+ @param[in] Help String ID for Help
+ @param[in] QuestionFlags Flags in Question Header
+ @param[in] QuestionId Question ID
+
+ @retval NULL There is not enough space left in Buffer to add the opcode.
+ @retval Other A pointer to the created opcode.
+
+**/
+UINT8 *
+EFIAPI
+HiiCreateGotoOpCode (
+ IN VOID *OpCodeHandle,
+ IN EFI_FORM_ID FormId,
+ IN EFI_STRING_ID Prompt,
+ IN EFI_STRING_ID Help,
+ IN UINT8 QuestionFlags,
+ IN EFI_QUESTION_ID QuestionId
+ )
+{
+ EFI_IFR_REF OpCode;
+
+ ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED))) == 0);
+
+ ZeroMem (&OpCode, sizeof (OpCode));
+ OpCode.Question.Header.Prompt = Prompt;
+ OpCode.Question.Header.Help = Help;
+ OpCode.Question.QuestionId = QuestionId;
+ OpCode.Question.Flags = QuestionFlags;
+ OpCode.FormId = FormId;
+
+ return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_REF_OP, sizeof (OpCode));
+}
+
+/**
+ Create EFI_IFR_REF_OP, EFI_IFR_REF2_OP, EFI_IFR_REF3_OP and EFI_IFR_REF4_OP opcode.
+
+ When RefDevicePath is not zero, EFI_IFR_REF4 opcode will be created.
+ When RefDevicePath is zero and RefFormSetId is not NULL, EFI_IFR_REF3 opcode will be created.
+ When RefDevicePath is zero, RefFormSetId is NULL and RefQuestionId is not zero, EFI_IFR_REF2 opcode will be created.
+ When RefDevicePath is zero, RefFormSetId is NULL and RefQuestionId is zero, EFI_IFR_REF opcode will be created.
+
+ If OpCodeHandle is NULL, then ASSERT().
+ If any reserved bits are set in QuestionFlags, then ASSERT().
+
+ @param[in] OpCodeHandle The handle to the buffer of opcodes.
+ @param[in] RefFormId The Destination Form ID.
+ @param[in] Prompt The string ID for Prompt.
+ @param[in] Help The string ID for Help.
+ @param[in] QuestionFlags The flags in Question Header
+ @param[in] QuestionId Question ID.
+ @param[in] RefQuestionId The question on the form to which this link is referring.
+ If its value is zero, then the link refers to the top of the form.
+ @param[in] RefFormSetId The form set to which this link is referring. If its value is NULL, and RefDevicePath is
+ zero, then the link is to the current form set.
+ @param[in] RefDevicePath The string identifier that specifies the string containing the text representation of
+ the device path to which the form set containing the form specified by FormId.
+ If its value is zero, then the link refers to the current page.
+
+ @retval NULL There is not enough space left in Buffer to add the opcode.
+ @retval Other A pointer to the created opcode.
+
+**/
+UINT8 *
+EFIAPI
+HiiCreateGotoExOpCode (
+ IN VOID *OpCodeHandle,
+ IN EFI_FORM_ID RefFormId,
+ IN EFI_STRING_ID Prompt,
+ IN EFI_STRING_ID Help,
+ IN UINT8 QuestionFlags,
+ IN EFI_QUESTION_ID QuestionId,
+ IN EFI_QUESTION_ID RefQuestionId,
+ IN EFI_GUID *RefFormSetId, OPTIONAL
+ IN EFI_STRING_ID RefDevicePath
+ )
+{
+ EFI_IFR_REF4 OpCode;
+ UINTN OpCodeSize;
+
+ ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED))) == 0);
+
+ ZeroMem (&OpCode, sizeof (OpCode));
+ OpCode.Question.Header.Prompt = Prompt;
+ OpCode.Question.Header.Help = Help;
+ OpCode.Question.QuestionId = QuestionId;
+ OpCode.Question.Flags = QuestionFlags;
+ OpCode.FormId = RefFormId;
+ OpCode.QuestionId = RefQuestionId;
+ OpCode.DevicePath = RefDevicePath;
+ if (RefFormSetId != NULL) {
+ CopyMem (&OpCode.FormSetId, RefFormSetId, sizeof (OpCode.FormSetId));
+ }
+
+ //
+ // Cacluate OpCodeSize based on the input Ref value.
+ // Try to use the small OpCode to save size.
+ //
+ OpCodeSize = sizeof (EFI_IFR_REF);
+ if (RefDevicePath != 0) {
+ OpCodeSize = sizeof (EFI_IFR_REF4);
+ } else if (RefFormSetId != NULL) {
+ OpCodeSize = sizeof (EFI_IFR_REF3);
+ } else if (RefQuestionId != 0) {
+ OpCodeSize = sizeof (EFI_IFR_REF2);
+ }
+
+ return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_REF_OP, OpCodeSize);
+}
+
+/**
+ Create EFI_IFR_CHECKBOX_OP opcode.
+
+ If OpCodeHandle is NULL, then ASSERT().
+ If any reserved bits are set in QuestionFlags, then ASSERT().
+ If any reserved bits are set in CheckBoxFlags, then ASSERT().
+
+ @param[in] OpCodeHandle Handle to the buffer of opcodes.
+ @param[in] QuestionId Question ID
+ @param[in] VarStoreId Storage ID
+ @param[in] VarOffset Offset in Storage or String ID of the name (VarName)
+ for this name/value pair.
+ @param[in] Prompt String ID for Prompt
+ @param[in] Help String ID for Help
+ @param[in] QuestionFlags Flags in Question Header
+ @param[in] CheckBoxFlags Flags for checkbox opcode
+ @param[in] DefaultsOpCodeHandle Handle for a buffer of DEFAULT opcodes. This
+ is an optional parameter that may be NULL.
+
+ @retval NULL There is not enough space left in Buffer to add the opcode.
+ @retval Other A pointer to the created opcode.
+
+**/
+UINT8 *
+EFIAPI
+HiiCreateCheckBoxOpCode (
+ IN VOID *OpCodeHandle,
+ IN EFI_QUESTION_ID QuestionId,
+ IN EFI_VARSTORE_ID VarStoreId,
+ IN UINT16 VarOffset,
+ IN EFI_STRING_ID Prompt,
+ IN EFI_STRING_ID Help,
+ IN UINT8 QuestionFlags,
+ IN UINT8 CheckBoxFlags,
+ IN VOID *DefaultsOpCodeHandle OPTIONAL
+ )
+{
+ EFI_IFR_CHECKBOX OpCode;
+ UINTN Position;
+
+ ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED))) == 0);
+
+ ZeroMem (&OpCode, sizeof (OpCode));
+ OpCode.Question.QuestionId = QuestionId;
+ OpCode.Question.VarStoreId = VarStoreId;
+ OpCode.Question.VarStoreInfo.VarOffset = VarOffset;
+ OpCode.Question.Header.Prompt = Prompt;
+ OpCode.Question.Header.Help = Help;
+ OpCode.Question.Flags = QuestionFlags;
+ OpCode.Flags = CheckBoxFlags;
+
+ if (DefaultsOpCodeHandle == NULL) {
+ return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_CHECKBOX_OP, sizeof (OpCode));
+ }
+
+ Position = InternalHiiOpCodeHandlePosition (OpCodeHandle);
+ InternalHiiCreateOpCodeExtended (OpCodeHandle, &OpCode, EFI_IFR_CHECKBOX_OP, sizeof (OpCode), 0, 1);
+ InternalHiiAppendOpCodes (OpCodeHandle, DefaultsOpCodeHandle);
+ HiiCreateEndOpCode (OpCodeHandle);
+ return InternalHiiOpCodeHandleBuffer (OpCodeHandle) + Position;
+}
+
+/**
+ Create EFI_IFR_NUMERIC_OP opcode.
+
+ If OpCodeHandle is NULL, then ASSERT().
+ If any reserved bits are set in QuestionFlags, then ASSERT().
+ If any reserved bits are set in NumericFlags, then ASSERT().
+
+ @param[in] OpCodeHandle Handle to the buffer of opcodes.
+ @param[in] QuestionId Question ID
+ @param[in] VarStoreId Storage ID
+ @param[in] VarOffset Offset in Storage or String ID of the name (VarName)
+ for this name/value pair.
+ @param[in] Prompt String ID for Prompt
+ @param[in] Help String ID for Help
+ @param[in] QuestionFlags Flags in Question Header
+ @param[in] NumericFlags Flags for numeric opcode
+ @param[in] Minimum Numeric minimum value
+ @param[in] Maximum Numeric maximum value
+ @param[in] Step Numeric step for edit
+ @param[in] DefaultsOpCodeHandle Handle for a buffer of DEFAULT opcodes. This
+ is an optional parameter that may be NULL.
+
+ @retval NULL There is not enough space left in Buffer to add the opcode.
+ @retval Other A pointer to the created opcode.
+
+**/
+UINT8 *
+EFIAPI
+HiiCreateNumericOpCode (
+ IN VOID *OpCodeHandle,
+ IN EFI_QUESTION_ID QuestionId,
+ IN EFI_VARSTORE_ID VarStoreId,
+ IN UINT16 VarOffset,
+ IN EFI_STRING_ID Prompt,
+ IN EFI_STRING_ID Help,
+ IN UINT8 QuestionFlags,
+ IN UINT8 NumericFlags,
+ IN UINT64 Minimum,
+ IN UINT64 Maximum,
+ IN UINT64 Step,
+ IN VOID *DefaultsOpCodeHandle OPTIONAL
+ )
+{
+ EFI_IFR_NUMERIC OpCode;
+ UINTN Position;
+ UINTN Length;
+
+ ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED))) == 0);
+
+ Length = 0;
+ ZeroMem (&OpCode, sizeof (OpCode));
+ OpCode.Question.QuestionId = QuestionId;
+ OpCode.Question.VarStoreId = VarStoreId;
+ OpCode.Question.VarStoreInfo.VarOffset = VarOffset;
+ OpCode.Question.Header.Prompt = Prompt;
+ OpCode.Question.Header.Help = Help;
+ OpCode.Question.Flags = QuestionFlags;
+ OpCode.Flags = NumericFlags;
+
+ switch (NumericFlags & EFI_IFR_NUMERIC_SIZE) {
+ case EFI_IFR_NUMERIC_SIZE_1:
+ OpCode.data.u8.MinValue = (UINT8)Minimum;
+ OpCode.data.u8.MaxValue = (UINT8)Maximum;
+ OpCode.data.u8.Step = (UINT8)Step;
+ Length = 3;
+ break;
+
+ case EFI_IFR_NUMERIC_SIZE_2:
+ OpCode.data.u16.MinValue = (UINT16)Minimum;
+ OpCode.data.u16.MaxValue = (UINT16)Maximum;
+ OpCode.data.u16.Step = (UINT16)Step;
+ Length = 6;
+ break;
+
+ case EFI_IFR_NUMERIC_SIZE_4:
+ OpCode.data.u32.MinValue = (UINT32)Minimum;
+ OpCode.data.u32.MaxValue = (UINT32)Maximum;
+ OpCode.data.u32.Step = (UINT32)Step;
+ Length = 12;
+ break;
+
+ case EFI_IFR_NUMERIC_SIZE_8:
+ OpCode.data.u64.MinValue = Minimum;
+ OpCode.data.u64.MaxValue = Maximum;
+ OpCode.data.u64.Step = Step;
+ Length = 24;
+ break;
+ }
+
+ Length += OFFSET_OF (EFI_IFR_NUMERIC, data);
+
+ if (DefaultsOpCodeHandle == NULL) {
+ return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_NUMERIC_OP, Length);
+ }
+
+ Position = InternalHiiOpCodeHandlePosition (OpCodeHandle);
+ InternalHiiCreateOpCodeExtended (OpCodeHandle, &OpCode, EFI_IFR_NUMERIC_OP, Length, 0, 1);
+ InternalHiiAppendOpCodes (OpCodeHandle, DefaultsOpCodeHandle);
+ HiiCreateEndOpCode (OpCodeHandle);
+ return InternalHiiOpCodeHandleBuffer (OpCodeHandle) + Position;
+}
+
+/**
+ Create EFI_IFR_STRING_OP opcode.
+
+ If OpCodeHandle is NULL, then ASSERT().
+ If any reserved bits are set in QuestionFlags, then ASSERT().
+ If any reserved bits are set in StringFlags, then ASSERT().
+
+ @param[in] OpCodeHandle Handle to the buffer of opcodes.
+ @param[in] QuestionId Question ID
+ @param[in] VarStoreId Storage ID
+ @param[in] VarOffset Offset in Storage or String ID of the name (VarName)
+ for this name/value pair.
+ @param[in] Prompt String ID for Prompt
+ @param[in] Help String ID for Help
+ @param[in] QuestionFlags Flags in Question Header
+ @param[in] StringFlags Flags for string opcode
+ @param[in] MinSize String minimum length
+ @param[in] MaxSize String maximum length
+ @param[in] DefaultsOpCodeHandle Handle for a buffer of DEFAULT opcodes. This
+ is an optional parameter that may be NULL.
+
+ @retval NULL There is not enough space left in Buffer to add the opcode.
+ @retval Other A pointer to the created opcode.
+
+**/
+UINT8 *
+EFIAPI
+HiiCreateStringOpCode (
+ IN VOID *OpCodeHandle,
+ IN EFI_QUESTION_ID QuestionId,
+ IN EFI_VARSTORE_ID VarStoreId,
+ IN UINT16 VarOffset,
+ IN EFI_STRING_ID Prompt,
+ IN EFI_STRING_ID Help,
+ IN UINT8 QuestionFlags,
+ IN UINT8 StringFlags,
+ IN UINT8 MinSize,
+ IN UINT8 MaxSize,
+ IN VOID *DefaultsOpCodeHandle OPTIONAL
+ )
+{
+ EFI_IFR_STRING OpCode;
+ UINTN Position;
+
+ ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED))) == 0);
+
+ ZeroMem (&OpCode, sizeof (OpCode));
+ OpCode.Question.Header.Prompt = Prompt;
+ OpCode.Question.Header.Help = Help;
+ OpCode.Question.QuestionId = QuestionId;
+ OpCode.Question.VarStoreId = VarStoreId;
+ OpCode.Question.VarStoreInfo.VarOffset = VarOffset;
+ OpCode.Question.Flags = QuestionFlags;
+ OpCode.MinSize = MinSize;
+ OpCode.MaxSize = MaxSize;
+ OpCode.Flags = (UINT8) (StringFlags & EFI_IFR_STRING_MULTI_LINE);
+
+ if (DefaultsOpCodeHandle == NULL) {
+ return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_STRING_OP, sizeof (OpCode));
+ }
+
+ Position = InternalHiiOpCodeHandlePosition (OpCodeHandle);
+ InternalHiiCreateOpCodeExtended (OpCodeHandle, &OpCode, EFI_IFR_STRING_OP, sizeof (OpCode), 0, 1);
+ InternalHiiAppendOpCodes (OpCodeHandle, DefaultsOpCodeHandle);
+ HiiCreateEndOpCode (OpCodeHandle);
+ return InternalHiiOpCodeHandleBuffer (OpCodeHandle) + Position;
+}
+
+/**
+ Create EFI_IFR_ONE_OF_OP opcode.
+
+ If OpCodeHandle is NULL, then ASSERT().
+ If any reserved bits are set in QuestionFlags, then ASSERT().
+ If any reserved bits are set in OneOfFlags, then ASSERT().
+
+ @param[in] OpCodeHandle Handle to the buffer of opcodes.
+ @param[in] QuestionId Question ID
+ @param[in] VarStoreId Storage ID
+ @param[in] VarOffset Offset in Storage or String ID of the name (VarName)
+ for this name/value pair.
+ @param[in] Prompt String ID for Prompt
+ @param[in] Help String ID for Help
+ @param[in] QuestionFlags Flags in Question Header
+ @param[in] OneOfFlags Flags for oneof opcode
+ @param[in] OptionsOpCodeHandle Handle for a buffer of ONE_OF_OPTION opcodes.
+ @param[in] DefaultsOpCodeHandle Handle for a buffer of DEFAULT opcodes. This
+ is an optional parameter that may be NULL.
+
+ @retval NULL There is not enough space left in Buffer to add the opcode.
+ @retval Other A pointer to the created opcode.
+
+**/
+UINT8 *
+EFIAPI
+HiiCreateOneOfOpCode (
+ IN VOID *OpCodeHandle,
+ IN EFI_QUESTION_ID QuestionId,
+ IN EFI_VARSTORE_ID VarStoreId,
+ IN UINT16 VarOffset,
+ IN EFI_STRING_ID Prompt,
+ IN EFI_STRING_ID Help,
+ IN UINT8 QuestionFlags,
+ IN UINT8 OneOfFlags,
+ IN VOID *OptionsOpCodeHandle,
+ IN VOID *DefaultsOpCodeHandle OPTIONAL
+ )
+{
+ EFI_IFR_ONE_OF OpCode;
+ UINTN Position;
+ UINTN Length;
+
+ ASSERT (OptionsOpCodeHandle != NULL);
+ ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED | EFI_IFR_FLAG_OPTIONS_ONLY))) == 0);
+
+ ZeroMem (&OpCode, sizeof (OpCode));
+ OpCode.Question.Header.Prompt = Prompt;
+ OpCode.Question.Header.Help = Help;
+ OpCode.Question.QuestionId = QuestionId;
+ OpCode.Question.VarStoreId = VarStoreId;
+ OpCode.Question.VarStoreInfo.VarOffset = VarOffset;
+ OpCode.Question.Flags = QuestionFlags;
+ OpCode.Flags = OneOfFlags;
+
+ Length = OFFSET_OF (EFI_IFR_ONE_OF, data);
+ Length += (1 << (OneOfFlags & EFI_IFR_NUMERIC_SIZE)) * 3;
+
+ Position = InternalHiiOpCodeHandlePosition (OpCodeHandle);
+ InternalHiiCreateOpCodeExtended (OpCodeHandle, &OpCode, EFI_IFR_ONE_OF_OP, Length, 0, 1);
+ InternalHiiAppendOpCodes (OpCodeHandle, OptionsOpCodeHandle);
+ if (DefaultsOpCodeHandle != NULL) {
+ InternalHiiAppendOpCodes (OpCodeHandle, DefaultsOpCodeHandle);
+ }
+ HiiCreateEndOpCode (OpCodeHandle);
+ return InternalHiiOpCodeHandleBuffer (OpCodeHandle) + Position;
+}
+
+/**
+ Create EFI_IFR_ORDERED_LIST_OP opcode.
+
+ If OpCodeHandle is NULL, then ASSERT().
+ If any reserved bits are set in QuestionFlags, then ASSERT().
+ If any reserved bits are set in OrderedListFlags, then ASSERT().
+
+ @param[in] OpCodeHandle Handle to the buffer of opcodes.
+ @param[in] QuestionId Question ID
+ @param[in] VarStoreId Storage ID
+ @param[in] VarOffset Offset in Storage or String ID of the name (VarName)
+ for this name/value pair.
+ @param[in] Prompt String ID for Prompt
+ @param[in] Help String ID for Help
+ @param[in] QuestionFlags Flags in Question Header
+ @param[in] OrderedListFlags Flags for ordered list opcode
+ @param[in] DataType Type for option value
+ @param[in] MaxContainers Maximum count for options in this ordered list
+ @param[in] OptionsOpCodeHandle Handle for a buffer of ONE_OF_OPTION opcodes.
+ @param[in] DefaultsOpCodeHandle Handle for a buffer of DEFAULT opcodes. This
+ is an optional parameter that may be NULL.
+
+ @retval NULL There is not enough space left in Buffer to add the opcode.
+ @retval Other A pointer to the created opcode.
+
+**/
+UINT8 *
+EFIAPI
+HiiCreateOrderedListOpCode (
+ IN VOID *OpCodeHandle,
+ IN EFI_QUESTION_ID QuestionId,
+ IN EFI_VARSTORE_ID VarStoreId,
+ IN UINT16 VarOffset,
+ IN EFI_STRING_ID Prompt,
+ IN EFI_STRING_ID Help,
+ IN UINT8 QuestionFlags,
+ IN UINT8 OrderedListFlags,
+ IN UINT8 DataType,
+ IN UINT8 MaxContainers,
+ IN VOID *OptionsOpCodeHandle,
+ IN VOID *DefaultsOpCodeHandle OPTIONAL
+ )
+{
+ EFI_IFR_ORDERED_LIST OpCode;
+ UINTN Position;
+
+ ASSERT (OptionsOpCodeHandle != NULL);
+ ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED | EFI_IFR_FLAG_OPTIONS_ONLY))) == 0);
+
+ ZeroMem (&OpCode, sizeof (OpCode));
+ OpCode.Question.Header.Prompt = Prompt;
+ OpCode.Question.Header.Help = Help;
+ OpCode.Question.QuestionId = QuestionId;
+ OpCode.Question.VarStoreId = VarStoreId;
+ OpCode.Question.VarStoreInfo.VarOffset = VarOffset;
+ OpCode.Question.Flags = QuestionFlags;
+ OpCode.MaxContainers = MaxContainers;
+ OpCode.Flags = OrderedListFlags;
+
+ Position = InternalHiiOpCodeHandlePosition (OpCodeHandle);
+ InternalHiiCreateOpCodeExtended (OpCodeHandle, &OpCode, EFI_IFR_ORDERED_LIST_OP, sizeof (OpCode), 0, 1);
+ InternalHiiAppendOpCodes (OpCodeHandle, OptionsOpCodeHandle);
+ if (DefaultsOpCodeHandle != NULL) {
+ InternalHiiAppendOpCodes (OpCodeHandle, DefaultsOpCodeHandle);
+ }
+ HiiCreateEndOpCode (OpCodeHandle);
+ return InternalHiiOpCodeHandleBuffer (OpCodeHandle) + Position;
+}
+
+/**
+ Create EFI_IFR_TEXT_OP opcode.
+
+ If OpCodeHandle is NULL, then ASSERT().
+
+ @param[in] OpCodeHandle Handle to the buffer of opcodes.
+ @param[in] Prompt String ID for Prompt.
+ @param[in] Help String ID for Help.
+ @param[in] TextTwo String ID for TextTwo.
+
+ @retval NULL There is not enough space left in Buffer to add the opcode.
+ @retval Other A pointer to the created opcode.
+
+**/
+UINT8 *
+EFIAPI
+HiiCreateTextOpCode (
+ IN VOID *OpCodeHandle,
+ IN EFI_STRING_ID Prompt,
+ IN EFI_STRING_ID Help,
+ IN EFI_STRING_ID TextTwo
+ )
+{
+ EFI_IFR_TEXT OpCode;
+
+ ZeroMem (&OpCode, sizeof (OpCode));
+ OpCode.Statement.Prompt = Prompt;
+ OpCode.Statement.Help = Help;
+ OpCode.TextTwo = TextTwo;
+
+ return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_TEXT_OP, sizeof (OpCode));
+}
+
+/**
+ Create EFI_IFR_DATE_OP opcode.
+
+ If OpCodeHandle is NULL, then ASSERT().
+ If any reserved bits are set in QuestionFlags, then ASSERT().
+ If any reserved bits are set in DateFlags, then ASSERT().
+
+ @param[in] OpCodeHandle Handle to the buffer of opcodes.
+ @param[in] QuestionId Question ID
+ @param[in] VarStoreId Storage ID, optional. If DateFlags is not
+ QF_DATE_STORAGE_NORMAL, this parameter is ignored.
+ @param[in] VarOffset Offset in Storage or String ID of the name (VarName)
+ for this name/value pair, optional. If DateFlags is not
+ QF_DATE_STORAGE_NORMAL, this parameter is ignored.
+ @param[in] Prompt String ID for Prompt
+ @param[in] Help String ID for Help
+ @param[in] QuestionFlags Flags in Question Header
+ @param[in] DateFlags Flags for date opcode
+ @param[in] DefaultsOpCodeHandle Handle for a buffer of DEFAULT opcodes. This
+ is an optional parameter that may be NULL.
+
+ @retval NULL There is not enough space left in Buffer to add the opcode.
+ @retval Other A pointer to the created opcode.
+
+**/
+UINT8 *
+EFIAPI
+HiiCreateDateOpCode (
+ IN VOID *OpCodeHandle,
+ IN EFI_QUESTION_ID QuestionId,
+ IN EFI_VARSTORE_ID VarStoreId, OPTIONAL
+ IN UINT16 VarOffset, OPTIONAL
+ IN EFI_STRING_ID Prompt,
+ IN EFI_STRING_ID Help,
+ IN UINT8 QuestionFlags,
+ IN UINT8 DateFlags,
+ IN VOID *DefaultsOpCodeHandle OPTIONAL
+ )
+{
+ EFI_IFR_DATE OpCode;
+ UINTN Position;
+
+ ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED))) == 0);
+ ASSERT ((DateFlags & (~(EFI_QF_DATE_YEAR_SUPPRESS | EFI_QF_DATE_MONTH_SUPPRESS | EFI_QF_DATE_DAY_SUPPRESS | EFI_QF_DATE_STORAGE))) == 0);
+
+ ZeroMem (&OpCode, sizeof (OpCode));
+ OpCode.Question.Header.Prompt = Prompt;
+ OpCode.Question.Header.Help = Help;
+ OpCode.Question.QuestionId = QuestionId;
+ OpCode.Question.VarStoreId = VarStoreId;
+ OpCode.Question.VarStoreInfo.VarOffset = VarOffset;
+ OpCode.Question.Flags = QuestionFlags;
+ OpCode.Flags = DateFlags;
+
+ if (DefaultsOpCodeHandle == NULL) {
+ return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_DATE_OP, sizeof (OpCode));
+ }
+
+ Position = InternalHiiOpCodeHandlePosition (OpCodeHandle);
+ InternalHiiCreateOpCodeExtended (OpCodeHandle, &OpCode, EFI_IFR_DATE_OP, sizeof (OpCode), 0, 1);
+ InternalHiiAppendOpCodes (OpCodeHandle, DefaultsOpCodeHandle);
+ HiiCreateEndOpCode (OpCodeHandle);
+ return InternalHiiOpCodeHandleBuffer (OpCodeHandle) + Position;
+}
+
+/**
+ Create EFI_IFR_TIME_OP opcode.
+
+ If OpCodeHandle is NULL, then ASSERT().
+ If any reserved bits are set in QuestionFlags, then ASSERT().
+ If any reserved bits are set in TimeFlags, then ASSERT().
+
+ @param[in] OpCodeHandle Handle to the buffer of opcodes.
+ @param[in] QuestionId Question ID
+ @param[in] VarStoreId Storage ID, optional. If TimeFlags is not
+ QF_TIME_STORAGE_NORMAL, this parameter is ignored.
+ @param[in] VarOffset Offset in Storage or String ID of the name (VarName)
+ for this name/value pair, optional. If TimeFlags is not
+ QF_TIME_STORAGE_NORMAL, this parameter is ignored.
+ @param[in] Prompt String ID for Prompt
+ @param[in] Help String ID for Help
+ @param[in] QuestionFlags Flags in Question Header
+ @param[in] TimeFlags Flags for time opcode
+ @param[in] DefaultsOpCodeHandle Handle for a buffer of DEFAULT opcodes. This
+ is an optional parameter that may be NULL.
+
+ @retval NULL There is not enough space left in Buffer to add the opcode.
+ @retval Other A pointer to the created opcode.
+
+**/
+UINT8 *
+EFIAPI
+HiiCreateTimeOpCode (
+ IN VOID *OpCodeHandle,
+ IN EFI_QUESTION_ID QuestionId,
+ IN EFI_VARSTORE_ID VarStoreId, OPTIONAL
+ IN UINT16 VarOffset, OPTIONAL
+ IN EFI_STRING_ID Prompt,
+ IN EFI_STRING_ID Help,
+ IN UINT8 QuestionFlags,
+ IN UINT8 TimeFlags,
+ IN VOID *DefaultsOpCodeHandle OPTIONAL
+ )
+{
+ EFI_IFR_TIME OpCode;
+ UINTN Position;
+
+ ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED))) == 0);
+ ASSERT ((TimeFlags & (~(QF_TIME_HOUR_SUPPRESS | QF_TIME_MINUTE_SUPPRESS | QF_TIME_SECOND_SUPPRESS | QF_TIME_STORAGE))) == 0);
+
+ ZeroMem (&OpCode, sizeof (OpCode));
+ OpCode.Question.Header.Prompt = Prompt;
+ OpCode.Question.Header.Help = Help;
+ OpCode.Question.QuestionId = QuestionId;
+ OpCode.Question.VarStoreId = VarStoreId;
+ OpCode.Question.VarStoreInfo.VarOffset = VarOffset;
+ OpCode.Question.Flags = QuestionFlags;
+ OpCode.Flags = TimeFlags;
+
+ if (DefaultsOpCodeHandle == NULL) {
+ return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_TIME_OP, sizeof (OpCode));
+ }
+
+ Position = InternalHiiOpCodeHandlePosition (OpCodeHandle);
+ InternalHiiCreateOpCodeExtended (OpCodeHandle, &OpCode, EFI_IFR_TIME_OP, sizeof (OpCode), 0, 1);
+ InternalHiiAppendOpCodes (OpCodeHandle, DefaultsOpCodeHandle);
+ HiiCreateEndOpCode (OpCodeHandle);
+ return InternalHiiOpCodeHandleBuffer (OpCodeHandle) + Position;
+}
+
+/**
+ This is the internal worker function to update the data in
+ a form specified by FormSetGuid, FormId and Label.
+
+ @param[in] FormSetGuid The optional Formset GUID.
+ @param[in] FormId The Form ID.
+ @param[in] Package The package header.
+ @param[in] OpCodeBufferStart An OpCode buffer that contains the set of IFR
+ opcodes to be inserted or replaced in the form.
+ @param[in] OpCodeBufferEnd An OpCcode buffer that contains the IFR opcode
+ that marks the end of a replace operation in the form.
+ @param[out] TempPackage The resultant package.
+
+ @retval EFI_SUCCESS The function completes successfully.
+ @retval EFI_NOT_FOUND The updated opcode or endopcode is not found.
+
+**/
+EFI_STATUS
+EFIAPI
+InternalHiiUpdateFormPackageData (
+ IN EFI_GUID *FormSetGuid, OPTIONAL
+ IN EFI_FORM_ID FormId,
+ IN EFI_HII_PACKAGE_HEADER *Package,
+ IN HII_LIB_OPCODE_BUFFER *OpCodeBufferStart,
+ IN HII_LIB_OPCODE_BUFFER *OpCodeBufferEnd, OPTIONAL
+ OUT EFI_HII_PACKAGE_HEADER *TempPackage
+ )
+{
+ UINTN AddSize;
+ UINT8 *BufferPos;
+ EFI_HII_PACKAGE_HEADER PackageHeader;
+ UINTN Offset;
+ EFI_IFR_OP_HEADER *IfrOpHdr;
+ EFI_IFR_OP_HEADER *UpdateIfrOpHdr;
+ BOOLEAN GetFormSet;
+ BOOLEAN GetForm;
+ BOOLEAN Updated;
+ UINTN UpdatePackageLength;
+
+ CopyMem (TempPackage, Package, sizeof (EFI_HII_PACKAGE_HEADER));
+ UpdatePackageLength = sizeof (EFI_HII_PACKAGE_HEADER);
+ BufferPos = (UINT8 *) (TempPackage + 1);
+
+ CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
+ IfrOpHdr = (EFI_IFR_OP_HEADER *)((UINT8 *) Package + sizeof (EFI_HII_PACKAGE_HEADER));
+ Offset = sizeof (EFI_HII_PACKAGE_HEADER);
+ GetFormSet = (BOOLEAN) ((FormSetGuid == NULL) ? TRUE : FALSE);
+ GetForm = FALSE;
+ Updated = FALSE;
+
+ while (Offset < PackageHeader.Length) {
+ CopyMem (BufferPos, IfrOpHdr, IfrOpHdr->Length);
+ BufferPos += IfrOpHdr->Length;
+ UpdatePackageLength += IfrOpHdr->Length;
+
+ //
+ // Find the matched FormSet and Form
+ //
+ if ((IfrOpHdr->OpCode == EFI_IFR_FORM_SET_OP) && (FormSetGuid != NULL)) {
+ if (CompareGuid((GUID *)(VOID *)&((EFI_IFR_FORM_SET *) IfrOpHdr)->Guid, FormSetGuid)) {
+ GetFormSet = TRUE;
+ } else {
+ GetFormSet = FALSE;
+ }
+ } else if (IfrOpHdr->OpCode == EFI_IFR_FORM_OP || IfrOpHdr->OpCode == EFI_IFR_FORM_MAP_OP) {
+ if (CompareMem (&((EFI_IFR_FORM *) IfrOpHdr)->FormId, &FormId, sizeof (EFI_FORM_ID)) == 0) {
+ GetForm = TRUE;
+ } else {
+ GetForm = FALSE;
+ }
+ }
+
+ //
+ // The matched Form is found, and Update data in this form
+ //
+ if (GetFormSet && GetForm) {
+ UpdateIfrOpHdr = (EFI_IFR_OP_HEADER *) OpCodeBufferStart->Buffer;
+ if ((UpdateIfrOpHdr->Length == IfrOpHdr->Length) && \
+ (CompareMem (IfrOpHdr, UpdateIfrOpHdr, UpdateIfrOpHdr->Length) == 0)) {
+ //
+ // Remove the original data when End OpCode buffer exist.
+ //
+ if (OpCodeBufferEnd != NULL) {
+ Offset += IfrOpHdr->Length;
+ IfrOpHdr = (EFI_IFR_OP_HEADER *) ((UINT8 *) (IfrOpHdr) + IfrOpHdr->Length);
+ UpdateIfrOpHdr = (EFI_IFR_OP_HEADER *) OpCodeBufferEnd->Buffer;
+ while (Offset < PackageHeader.Length) {
+ //
+ // Search the matched end opcode
+ //
+ if ((UpdateIfrOpHdr->Length == IfrOpHdr->Length) && \
+ (CompareMem (IfrOpHdr, UpdateIfrOpHdr, UpdateIfrOpHdr->Length) == 0)) {
+ break;
+ }
+ //
+ // Go to the next Op-Code
+ //
+ Offset += IfrOpHdr->Length;
+ IfrOpHdr = (EFI_IFR_OP_HEADER *) ((UINT8 *) (IfrOpHdr) + IfrOpHdr->Length);
+ }
+
+ if (Offset >= PackageHeader.Length) {
+ //
+ // The end opcode is not found.
+ //
+ return EFI_NOT_FOUND;
+ }
+ }
+
+ //
+ // Insert the updated data
+ //
+ AddSize = ((EFI_IFR_OP_HEADER *) OpCodeBufferStart->Buffer)->Length;
+ CopyMem (BufferPos, OpCodeBufferStart->Buffer + AddSize, OpCodeBufferStart->Position - AddSize);
+ BufferPos += OpCodeBufferStart->Position - AddSize;
+ UpdatePackageLength += OpCodeBufferStart->Position - AddSize;
+
+ if (OpCodeBufferEnd != NULL) {
+ //
+ // Add the end opcode
+ //
+ CopyMem (BufferPos, IfrOpHdr, IfrOpHdr->Length);
+ BufferPos += IfrOpHdr->Length;
+ UpdatePackageLength += IfrOpHdr->Length;
+ }
+
+ //
+ // Copy the left package data.
+ //
+ Offset += IfrOpHdr->Length;
+ CopyMem (BufferPos, (UINT8 *) Package + Offset, PackageHeader.Length - Offset);
+ UpdatePackageLength += PackageHeader.Length - Offset;
+
+ //
+ // Set update flag
+ //
+ Updated = TRUE;
+ break;
+ }
+ }
+
+ //
+ // Go to the next Op-Code
+ //
+ Offset += IfrOpHdr->Length;
+ IfrOpHdr = (EFI_IFR_OP_HEADER *) ((CHAR8 *) (IfrOpHdr) + IfrOpHdr->Length);
+ }
+
+ if (!Updated) {
+ //
+ // The updated opcode buffer is not found.
+ //
+ return EFI_NOT_FOUND;
+ }
+ //
+ // Update the package length.
+ //
+ PackageHeader.Length = (UINT32) UpdatePackageLength;
+ CopyMem (TempPackage, &PackageHeader, sizeof (EFI_HII_PACKAGE_HEADER));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function updates a form that has previously been registered with the HII
+ Database. This function will perform at most one update operation.
+
+ The form to update is specified by Handle, FormSetGuid, and FormId. Binary
+ comparisons of IFR opcodes are performed from the beginning of the form being
+ updated until an IFR opcode is found that exactly matches the first IFR opcode
+ specified by StartOpCodeHandle. The following rules are used to determine if
+ an insert, replace, or delete operation is performed.
+
+ 1) If no matches are found, then NULL is returned.
+ 2) If a match is found, and EndOpCodeHandle is NULL, then all of the IFR opcodes
+ from StartOpCodeHandle except the first opcode are inserted immediately after
+ the matching IFR opcode in the form to be updated.
+ 3) If a match is found, and EndOpCodeHandle is not NULL, then a search is made
+ from the matching IFR opcode until an IFR opcode exactly matches the first
+ IFR opcode specified by EndOpCodeHandle. If no match is found for the first
+ IFR opcode specified by EndOpCodeHandle, then NULL is returned. If a match
+ is found, then all of the IFR opcodes between the start match and the end
+ match are deleted from the form being updated and all of the IFR opcodes
+ from StartOpCodeHandle except the first opcode are inserted immediately after
+ the matching start IFR opcode. If StartOpCcodeHandle only contains one
+ IFR instruction, then the result of this operation will delete all of the IFR
+ opcodes between the start end matches.
+
+ If HiiHandle is NULL, then ASSERT().
+ If StartOpCodeHandle is NULL, then ASSERT().
+
+ @param[in] HiiHandle The HII Handle of the form to update.
+ @param[in] FormSetGuid The Formset GUID of the form to update. This
+ is an optional parameter that may be NULL.
+ If it is NULL, all FormSet will be updated.
+ @param[in] FormId The ID of the form to update.
+ @param[in] StartOpCodeHandle An OpCode Handle that contains the set of IFR
+ opcodes to be inserted or replaced in the form.
+ The first IFR instruction in StartOpCodeHandle
+ is used to find matching IFR opcode in the
+ form.
+ @param[in] EndOpCodeHandle An OpCcode Handle that contains the IFR opcode
+ that marks the end of a replace operation in
+ the form. This is an optional parameter that
+ may be NULL. If it is NULL, then an the IFR
+ opcodes specified by StartOpCodeHandle are
+ inserted into the form.
+
+ @retval EFI_OUT_OF_RESOURCES No enough memory resource is allocated.
+ @retval EFI_NOT_FOUND The following cases will return EFI_NOT_FOUND.
+ 1) The form specified by HiiHandle, FormSetGuid,
+ and FormId could not be found in the HII Database.
+ 2) No IFR opcodes in the target form match the first
+ IFR opcode in StartOpCodeHandle.
+ 3) EndOpCOde is not NULL, and no IFR opcodes in the
+ target form following a matching start opcode match
+ the first IFR opcode in EndOpCodeHandle.
+ @retval EFI_SUCCESS The matched form is updated by StartOpcode.
+
+**/
+EFI_STATUS
+EFIAPI
+HiiUpdateForm (
+ IN EFI_HII_HANDLE HiiHandle,
+ IN EFI_GUID *FormSetGuid, OPTIONAL
+ IN EFI_FORM_ID FormId,
+ IN VOID *StartOpCodeHandle,
+ IN VOID *EndOpCodeHandle OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList;
+ UINT32 PackageListLength;
+ UINT32 Offset;
+ EFI_HII_PACKAGE_LIST_HEADER *UpdatePackageList;
+ UINTN BufferSize;
+ UINT8 *UpdateBufferPos;
+ EFI_HII_PACKAGE_HEADER *Package;
+ EFI_HII_PACKAGE_HEADER *TempPacakge;
+ EFI_HII_PACKAGE_HEADER PackageHeader;
+ BOOLEAN Updated;
+ HII_LIB_OPCODE_BUFFER *OpCodeBufferStart;
+ HII_LIB_OPCODE_BUFFER *OpCodeBufferEnd;
+
+ //
+ // Input update data can't be NULL.
+ //
+ ASSERT (HiiHandle != NULL);
+ ASSERT (StartOpCodeHandle != NULL);
+ UpdatePackageList = NULL;
+ TempPacakge = NULL;
+ HiiPackageList = NULL;
+
+ //
+ // Retrieve buffer data from Opcode Handle
+ //
+ OpCodeBufferStart = (HII_LIB_OPCODE_BUFFER *) StartOpCodeHandle;
+ OpCodeBufferEnd = (HII_LIB_OPCODE_BUFFER *) EndOpCodeHandle;
+
+ //
+ // Get the original package list
+ //
+ BufferSize = 0;
+ HiiPackageList = NULL;
+ Status = gHiiDatabase->ExportPackageLists (gHiiDatabase, HiiHandle, &BufferSize, HiiPackageList);
+ //
+ // The return status should always be EFI_BUFFER_TOO_SMALL as input buffer's size is 0.
+ //
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ return Status;
+ }
+
+ HiiPackageList = AllocatePool (BufferSize);
+ if (HiiPackageList == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Finish;
+ }
+
+ Status = gHiiDatabase->ExportPackageLists (gHiiDatabase, HiiHandle, &BufferSize, HiiPackageList);
+ if (EFI_ERROR (Status)) {
+ goto Finish;
+ }
+
+ //
+ // Calculate and allocate space for retrieval of IFR data
+ //
+ BufferSize += OpCodeBufferStart->Position;
+ UpdatePackageList = AllocateZeroPool (BufferSize);
+ if (UpdatePackageList == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Finish;
+ }
+
+ //
+ // Allocate temp buffer to store the temp updated package buffer
+ //
+ TempPacakge = AllocateZeroPool (BufferSize);
+ if (TempPacakge == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Finish;
+ }
+
+ UpdateBufferPos = (UINT8 *) UpdatePackageList;
+
+ //
+ // Copy the package list header
+ //
+ CopyMem (UpdateBufferPos, HiiPackageList, sizeof (EFI_HII_PACKAGE_LIST_HEADER));
+ UpdateBufferPos += sizeof (EFI_HII_PACKAGE_LIST_HEADER);
+
+ //
+ // Go through each package to find the matched package and update one by one
+ //
+ Updated = FALSE;
+ Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER);
+ PackageListLength = ReadUnaligned32 (&HiiPackageList->PackageLength);
+ while (Offset < PackageListLength) {
+ Package = (EFI_HII_PACKAGE_HEADER *) (((UINT8 *) HiiPackageList) + Offset);
+ CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
+ Offset += Package->Length;
+
+ if (Package->Type == EFI_HII_PACKAGE_FORMS) {
+ //
+ // Check this package is the matched package.
+ //
+ Status = InternalHiiUpdateFormPackageData (FormSetGuid, FormId, Package, OpCodeBufferStart, OpCodeBufferEnd, TempPacakge);
+ //
+ // The matched package is found. Its package buffer will be updated by the input new data.
+ //
+ if (!EFI_ERROR(Status)) {
+ //
+ // Set Update Flag
+ //
+ Updated = TRUE;
+ //
+ // Add updated package buffer
+ //
+ Package = TempPacakge;
+ }
+ }
+
+ //
+ // Add pacakge buffer
+ //
+ CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
+ CopyMem (UpdateBufferPos, Package, PackageHeader.Length);
+ UpdateBufferPos += PackageHeader.Length;
+ }
+
+ if (Updated) {
+ //
+ // Update package list length
+ //
+ BufferSize = UpdateBufferPos - (UINT8 *) UpdatePackageList;
+ WriteUnaligned32 (&UpdatePackageList->PackageLength, (UINT32) BufferSize);
+
+ //
+ // Update Package to show form
+ //
+ Status = gHiiDatabase->UpdatePackageList (gHiiDatabase, HiiHandle, UpdatePackageList);
+ } else {
+ //
+ // Not matched form is found and updated.
+ //
+ Status = EFI_NOT_FOUND;
+ }
+
+Finish:
+ if (HiiPackageList != NULL) {
+ FreePool (HiiPackageList);
+ }
+
+ if (UpdatePackageList != NULL) {
+ FreePool (UpdatePackageList);
+ }
+
+ if (TempPacakge != NULL) {
+ FreePool (TempPacakge);
+ }
+
+ return Status;
+}
diff --git a/Core/MdeModulePkg/Library/UefiHiiLib/HiiString.c b/Core/MdeModulePkg/Library/UefiHiiLib/HiiString.c
new file mode 100644
index 0000000000..bfae3f8fc0
--- /dev/null
+++ b/Core/MdeModulePkg/Library/UefiHiiLib/HiiString.c
@@ -0,0 +1,355 @@
+/** @file
+ HII Library implementation that uses DXE protocols and services.
+
+ Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+
+#include "InternalHiiLib.h"
+
+/**
+ This function create a new string in String Package or updates an existing
+ string in a String Package. If StringId is 0, then a new string is added to
+ a String Package. If StringId is not zero, then a string in String Package is
+ updated. If SupportedLanguages is NULL, then the string is added or updated
+ for all the languages that the String Package supports. If SupportedLanguages
+ is not NULL, then the string is added or updated for the set of languages
+ specified by SupportedLanguages.
+
+ If HiiHandle is NULL, then ASSERT().
+ If String is NULL, then ASSERT().
+
+ @param[in] HiiHandle A handle that was previously registered in the
+ HII Database.
+ @param[in] StringId If zero, then a new string is created in the
+ String Package associated with HiiHandle. If
+ non-zero, then the string specified by StringId
+ is updated in the String Package associated
+ with HiiHandle.
+ @param[in] String A pointer to the Null-terminated Unicode string
+ to add or update in the String Package associated
+ with HiiHandle.
+ @param[in] SupportedLanguages A pointer to a Null-terminated ASCII string of
+ language codes. If this parameter is NULL, then
+ String is added or updated in the String Package
+ associated with HiiHandle for all the languages
+ that the String Package supports. If this
+ parameter is not NULL, then then String is added
+ or updated in the String Package associated with
+ HiiHandle for the set oflanguages specified by
+ SupportedLanguages. The format of
+ SupportedLanguages must follow the language
+ format assumed the HII Database.
+
+ @retval 0 The string could not be added or updated in the String Package.
+ @retval Other The EFI_STRING_ID of the newly added or updated string.
+
+**/
+EFI_STRING_ID
+EFIAPI
+HiiSetString (
+ IN EFI_HII_HANDLE HiiHandle,
+ IN EFI_STRING_ID StringId, OPTIONAL
+ IN CONST EFI_STRING String,
+ IN CONST CHAR8 *SupportedLanguages OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ CHAR8 *AllocatedLanguages;
+ CHAR8 *Supported;
+ CHAR8 *Language;
+
+ ASSERT (HiiHandle != NULL);
+ ASSERT (String != NULL);
+
+ if (SupportedLanguages == NULL) {
+ //
+ // Retrieve the languages that the package specified by HiiHandle supports
+ //
+ AllocatedLanguages = HiiGetSupportedLanguages (HiiHandle);
+ } else {
+ //
+ // Allocate a copy of the SupportLanguages string that passed in
+ //
+ AllocatedLanguages = AllocateCopyPool (AsciiStrSize (SupportedLanguages), SupportedLanguages);
+ }
+
+ //
+ // If there are not enough resources for the supported languages string, then return a StringId of 0
+ //
+ if (AllocatedLanguages == NULL) {
+ return (EFI_STRING_ID)(0);
+ }
+
+ Status = EFI_INVALID_PARAMETER;
+ //
+ // Loop through each language that the string supports
+ //
+ for (Supported = AllocatedLanguages; *Supported != '\0'; ) {
+ //
+ // Cache a pointer to the beginning of the current language in the list of languages
+ //
+ Language = Supported;
+
+ //
+ // Search for the next language seperator and replace it with a Null-terminator
+ //
+ for (; *Supported != 0 && *Supported != ';'; Supported++);
+ if (*Supported != 0) {
+ *(Supported++) = '\0';
+ }
+
+ if ((SupportedLanguages == NULL) && AsciiStrnCmp (Language, UEFI_CONFIG_LANG, AsciiStrLen (UEFI_CONFIG_LANG)) == 0) {
+ //
+ // Skip string package used for keyword protocol.
+ //
+ continue;
+ }
+
+ //
+ // If StringId is 0, then call NewString(). Otherwise, call SetString()
+ //
+ if (StringId == (EFI_STRING_ID)(0)) {
+ Status = gHiiString->NewString (gHiiString, HiiHandle, &StringId, Language, NULL, String, NULL);
+ } else {
+ Status = gHiiString->SetString (gHiiString, HiiHandle, StringId, Language, String, NULL);
+ }
+
+ //
+ // If there was an error, then break out of the loop and return a StringId of 0
+ //
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ }
+
+ //
+ // Free the buffer of supported languages
+ //
+ FreePool (AllocatedLanguages);
+
+ if (EFI_ERROR (Status)) {
+ return (EFI_STRING_ID)(0);
+ } else {
+ return StringId;
+ }
+}
+
+
+/**
+ Retrieves a string from a string package names by GUID in a specific language.
+ If the language is not specified, then a string from a string package in the
+ current platform language is retrieved. If the string can not be retrieved
+ using the specified language or the current platform language, then the string
+ is retrieved from the string package in the first language the string package
+ supports. The returned string is allocated using AllocatePool(). The caller
+ is responsible for freeing the allocated buffer using FreePool().
+
+ If PackageListGuid is NULL, then ASSERT().
+ If StringId is 0, then ASSERT.
+
+ @param[in] PackageListGuid The GUID of a package list that was previously
+ registered in the HII Database.
+ @param[in] StringId The identifier of the string to retrieved from the
+ string package associated with PackageListGuid.
+ @param[in] Language The language of the string to retrieve. If this
+ parameter is NULL, then the current platform
+ language is used. The format of Language must
+ follow the language format assumed the HII Database.
+
+ @retval NULL The package list specified by PackageListGuid is not present in the
+ HII Database.
+ @retval NULL The string specified by StringId is not present in the string package.
+ @retval Other The string was returned.
+
+**/
+EFI_STRING
+EFIAPI
+HiiGetPackageString (
+ IN CONST EFI_GUID *PackageListGuid,
+ IN EFI_STRING_ID StringId,
+ IN CONST CHAR8 *Language OPTIONAL
+ )
+{
+ EFI_HANDLE *HiiHandleBuffer;
+ EFI_HANDLE HiiHandle;
+
+ ASSERT (PackageListGuid != NULL);
+
+ HiiHandleBuffer = HiiGetHiiHandles (PackageListGuid);
+ if (HiiHandleBuffer == NULL) {
+ return NULL;
+ }
+
+ HiiHandle = HiiHandleBuffer[0];
+ FreePool (HiiHandleBuffer);
+
+ return HiiGetString (HiiHandle, StringId, Language);
+}
+
+/**
+ Retrieves a string from a string package in a specific language. If the language
+ is not specified, then a string from a string package in the current platform
+ language is retrieved. If the string can not be retrieved using the specified
+ language or the current platform language, then the string is retrieved from
+ the string package in the first language the string package supports. The
+ returned string is allocated using AllocatePool(). The caller is responsible
+ for freeing the allocated buffer using FreePool().
+
+ If HiiHandle is NULL, then ASSERT().
+ If StringId is 0, then ASSET.
+
+ @param[in] HiiHandle A handle that was previously registered in the HII Database.
+ @param[in] StringId The identifier of the string to retrieved from the string
+ package associated with HiiHandle.
+ @param[in] Language The language of the string to retrieve. If this parameter
+ is NULL, then the current platform language is used. The
+ format of Language must follow the language format assumed
+ the HII Database.
+
+ @retval NULL The string specified by StringId is not present in the string package.
+ @retval Other The string was returned.
+
+**/
+EFI_STRING
+EFIAPI
+HiiGetString (
+ IN EFI_HII_HANDLE HiiHandle,
+ IN EFI_STRING_ID StringId,
+ IN CONST CHAR8 *Language OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ UINTN StringSize;
+ CHAR16 TempString;
+ EFI_STRING String;
+ CHAR8 *SupportedLanguages;
+ CHAR8 *PlatformLanguage;
+ CHAR8 *BestLanguage;
+
+ ASSERT (HiiHandle != NULL);
+ ASSERT (StringId != 0);
+
+ //
+ // Initialize all allocated buffers to NULL
+ //
+ SupportedLanguages = NULL;
+ PlatformLanguage = NULL;
+ BestLanguage = NULL;
+ String = NULL;
+
+ //
+ // Get the languages that the package specified by HiiHandle supports
+ //
+ SupportedLanguages = HiiGetSupportedLanguages (HiiHandle);
+ if (SupportedLanguages == NULL) {
+ goto Error;
+ }
+
+ //
+ // Get the current platform language setting
+ //
+ GetEfiGlobalVariable2 (L"PlatformLang", (VOID**)&PlatformLanguage, NULL);
+
+ //
+ // If Languag is NULL, then set it to an empty string, so it will be
+ // skipped by GetBestLanguage()
+ //
+ if (Language == NULL) {
+ Language = "";
+ }
+
+ //
+ // Get the best matching language from SupportedLanguages
+ //
+ BestLanguage = GetBestLanguage (
+ SupportedLanguages,
+ FALSE, // RFC 4646 mode
+ Language, // Highest priority
+ PlatformLanguage != NULL ? PlatformLanguage : "", // Next highest priority
+ SupportedLanguages, // Lowest priority
+ NULL
+ );
+ if (BestLanguage == NULL) {
+ goto Error;
+ }
+
+ //
+ // Retrieve the size of the string in the string package for the BestLanguage
+ //
+ StringSize = 0;
+ Status = gHiiString->GetString (
+ gHiiString,
+ BestLanguage,
+ HiiHandle,
+ StringId,
+ &TempString,
+ &StringSize,
+ NULL
+ );
+ //
+ // If GetString() returns EFI_SUCCESS for a zero size,
+ // then there are no supported languages registered for HiiHandle. If GetString()
+ // returns an error other than EFI_BUFFER_TOO_SMALL, then HiiHandle is not present
+ // in the HII Database
+ //
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ goto Error;
+ }
+
+ //
+ // Allocate a buffer for the return string
+ //
+ String = AllocateZeroPool (StringSize);
+ if (String == NULL) {
+ goto Error;
+ }
+
+ //
+ // Retrieve the string from the string package
+ //
+ Status = gHiiString->GetString (
+ gHiiString,
+ BestLanguage,
+ HiiHandle,
+ StringId,
+ String,
+ &StringSize,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Free the buffer and return NULL if the supported languages can not be retrieved.
+ //
+ FreePool (String);
+ String = NULL;
+ }
+
+Error:
+ //
+ // Free allocated buffers
+ //
+ if (SupportedLanguages != NULL) {
+ FreePool (SupportedLanguages);
+ }
+ if (PlatformLanguage != NULL) {
+ FreePool (PlatformLanguage);
+ }
+ if (BestLanguage != NULL) {
+ FreePool (BestLanguage);
+ }
+
+ //
+ // Return the Null-terminated Unicode string
+ //
+ return String;
+}
+
diff --git a/Core/MdeModulePkg/Library/UefiHiiLib/InternalHiiLib.h b/Core/MdeModulePkg/Library/UefiHiiLib/InternalHiiLib.h
new file mode 100644
index 0000000000..9bf7696ea3
--- /dev/null
+++ b/Core/MdeModulePkg/Library/UefiHiiLib/InternalHiiLib.h
@@ -0,0 +1,34 @@
+/** @file
+ Internal include file for the HII Library instance.
+
+ Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __INTERNAL_HII_LIB_H__
+#define __INTERNAL_HII_LIB_H__
+
+#include <Uefi.h>
+
+#include <Protocol/DevicePath.h>
+#include <Protocol/FormBrowser2.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/HiiLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/UefiHiiServicesLib.h>
+#include <Library/PrintLib.h>
+#include <Library/UefiLib.h>
+
+#endif
diff --git a/Core/MdeModulePkg/Library/UefiHiiLib/UefiHiiLib.inf b/Core/MdeModulePkg/Library/UefiHiiLib/UefiHiiLib.inf
new file mode 100644
index 0000000000..62f435a089
--- /dev/null
+++ b/Core/MdeModulePkg/Library/UefiHiiLib/UefiHiiLib.inf
@@ -0,0 +1,53 @@
+## @file
+# HII Library implementation using UEFI HII protocols and services.
+#
+# Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = UefiHiiLib
+ MODULE_UNI_FILE = UefiHiiLib.uni
+ FILE_GUID = 3143687A-7C80-404e-B5FE-2D88980E1B1C
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = HiiLib|DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SAL_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER
+
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ HiiLib.c
+ HiiString.c
+ HiiLanguage.c
+ InternalHiiLib.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ MemoryAllocationLib
+ BaseMemoryLib
+ BaseLib
+ DebugLib
+ UefiBootServicesTableLib
+ DevicePathLib
+ UefiLib
+ UefiHiiServicesLib
+ PrintLib
+
+[Protocols]
+ gEfiFormBrowser2ProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiDevicePathProtocolGuid ## SOMETIMES_CONSUMES
diff --git a/Core/MdeModulePkg/Library/UefiHiiLib/UefiHiiLib.uni b/Core/MdeModulePkg/Library/UefiHiiLib/UefiHiiLib.uni
new file mode 100644
index 0000000000..7385c4db9d
--- /dev/null
+++ b/Core/MdeModulePkg/Library/UefiHiiLib/UefiHiiLib.uni
Binary files differ
diff --git a/Core/MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.c b/Core/MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.c
new file mode 100644
index 0000000000..bd3a125603
--- /dev/null
+++ b/Core/MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.c
@@ -0,0 +1,113 @@
+/** @file
+ This library retrieves pointers to the UEFI HII Protocol instances in the
+ library's constructor. All of the UEFI HII related protocols are optional,
+ so the consumers of this library class must verify that the global variable
+ pointers are not NULL before use.
+
+ Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Uefi.h>
+
+#include <Library/UefiHiiServicesLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DebugLib.h>
+
+#include <Protocol/HiiFont.h>
+#include <Protocol/HiiString.h>
+#include <Protocol/HiiImage.h>
+#include <Protocol/HiiDatabase.h>
+#include <Protocol/HiiConfigRouting.h>
+
+///
+/// Pointer to the UEFI HII Font Protocol
+///
+EFI_HII_FONT_PROTOCOL *gHiiFont = NULL;
+
+///
+/// Pointer to the UEFI HII String Protocol
+///
+EFI_HII_STRING_PROTOCOL *gHiiString = NULL;
+
+///
+/// Pointer to the UEFI HII Image Protocol
+///
+EFI_HII_IMAGE_PROTOCOL *gHiiImage = NULL;
+
+///
+/// Pointer to the UEFI HII Database Protocol
+///
+EFI_HII_DATABASE_PROTOCOL *gHiiDatabase = NULL;
+
+///
+/// Pointer to the UEFI HII Config Rounting Protocol
+///
+EFI_HII_CONFIG_ROUTING_PROTOCOL *gHiiConfigRouting = NULL;
+
+/**
+ The constructor function retrieves pointers to the UEFI HII protocol instances
+
+ The constructor function retrieves pointers to the four UEFI HII protocols from the
+ handle database. These include the UEFI HII Font Protocol, the UEFI HII String
+ Protocol, the UEFI HII Image Protocol, the UEFI HII Database Protocol, and the
+ UEFI HII Config Routing Protocol. This function always return EFI_SUCCESS.
+ All of these protocols are optional if the platform does not support configuration
+ and the UEFI HII Image Protocol and the UEFI HII Font Protocol are optional if
+ the platform does not support a graphical console. As a result, the consumers
+ of this library much check the protocol pointers againt NULL before using them,
+ or use dependency expressions to guarantee that some of them are present before
+ assuming they are not NULL.
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
+
+**/
+EFI_STATUS
+EFIAPI
+UefiHiiServicesLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Retrieve the pointer to the UEFI HII String Protocol
+ //
+ Status = gBS->LocateProtocol (&gEfiHiiStringProtocolGuid, NULL, (VOID **) &gHiiString);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Retrieve the pointer to the UEFI HII Database Protocol
+ //
+ Status = gBS->LocateProtocol (&gEfiHiiDatabaseProtocolGuid, NULL, (VOID **) &gHiiDatabase);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Retrieve the pointer to the UEFI HII Config Routing Protocol
+ //
+ Status = gBS->LocateProtocol (&gEfiHiiConfigRoutingProtocolGuid, NULL, (VOID **) &gHiiConfigRouting);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Retrieve the pointer to the optional UEFI HII Font Protocol
+ //
+ gBS->LocateProtocol (&gEfiHiiFontProtocolGuid, NULL, (VOID **) &gHiiFont);
+
+ //
+ // Retrieve the pointer to the optional UEFI HII Image Protocol
+ //
+ gBS->LocateProtocol (&gEfiHiiImageProtocolGuid, NULL, (VOID **) &gHiiImage);
+
+ return EFI_SUCCESS;
+}
diff --git a/Core/MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.inf b/Core/MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.inf
new file mode 100644
index 0000000000..a009e9a715
--- /dev/null
+++ b/Core/MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.inf
@@ -0,0 +1,67 @@
+## @file
+# UEFI HII Services Library implementation.
+#
+# Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = UefiHiiServicesLib
+ MODULE_UNI_FILE = UefiHiiServicesLib.uni
+ FILE_GUID = 894DC1B6-07A3-4a9d-8CDD-333580B3D4B1
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = UefiHiiServicesLib|DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SAL_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER
+
+ CONSTRUCTOR = UefiHiiServicesLibConstructor
+
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ UefiHiiServicesLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiBootServicesTableLib
+ DebugLib
+
+[Protocols]
+ gEfiHiiFontProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiHiiStringProtocolGuid ## CONSUMES
+ gEfiHiiImageProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiHiiDatabaseProtocolGuid ## CONSUMES
+ gEfiHiiConfigRoutingProtocolGuid ## CONSUMES
+
+[Depex.common.DXE_DRIVER]
+ gEfiHiiStringProtocolGuid AND
+ gEfiHiiDatabaseProtocolGuid AND
+ gEfiHiiConfigRoutingProtocolGuid
+
+[Depex.common.DXE_RUNTIME_DRIVER]
+ gEfiHiiStringProtocolGuid AND
+ gEfiHiiDatabaseProtocolGuid AND
+ gEfiHiiConfigRoutingProtocolGuid
+
+[Depex.common.DXE_SAL_DRIVER]
+ gEfiHiiStringProtocolGuid AND
+ gEfiHiiDatabaseProtocolGuid AND
+ gEfiHiiConfigRoutingProtocolGuid
+
+[Depex.common.DXE_SMM_DRIVER]
+ gEfiHiiStringProtocolGuid AND
+ gEfiHiiDatabaseProtocolGuid AND
+ gEfiHiiConfigRoutingProtocolGuid
diff --git a/Core/MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.uni b/Core/MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.uni
new file mode 100644
index 0000000000..f7ad669b8e
--- /dev/null
+++ b/Core/MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.uni
Binary files differ
diff --git a/Core/MdeModulePkg/Library/UefiSortLib/UefiSortLib.c b/Core/MdeModulePkg/Library/UefiSortLib/UefiSortLib.c
new file mode 100644
index 0000000000..8a45cd0d9f
--- /dev/null
+++ b/Core/MdeModulePkg/Library/UefiSortLib/UefiSortLib.c
@@ -0,0 +1,322 @@
+/** @file
+ Library used for sorting routines.
+
+ Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved. <BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Uefi.h>
+
+#include <Protocol/UnicodeCollation.h>
+#include <Protocol/DevicePath.h>
+
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/SortLib.h>
+#include <Library/DevicePathLib.h>
+
+STATIC EFI_UNICODE_COLLATION_PROTOCOL *mUnicodeCollation = NULL;
+
+#define USL_FREE_NON_NULL(Pointer) \
+{ \
+ if ((Pointer) != NULL) { \
+ FreePool((Pointer)); \
+ (Pointer) = NULL; \
+ } \
+}
+
+/**
+ Worker function for QuickSorting. This function is identical to PerformQuickSort,
+ except that is uses the pre-allocated buffer so the in place sorting does not need to
+ allocate and free buffers constantly.
+
+ Each element must be equal sized.
+
+ if BufferToSort is NULL, then ASSERT.
+ if CompareFunction is NULL, then ASSERT.
+ if Buffer is NULL, then ASSERT.
+
+ if Count is < 2 then perform no action.
+ if Size is < 1 then perform no action.
+
+ @param[in, out] BufferToSort on call a Buffer of (possibly sorted) elements
+ on return a buffer of sorted elements
+ @param[in] Count the number of elements in the buffer to sort
+ @param[in] ElementSize Size of an element in bytes
+ @param[in] CompareFunction The function to call to perform the comparison
+ of any 2 elements
+ @param[in] Buffer Buffer of size ElementSize for use in swapping
+**/
+VOID
+EFIAPI
+QuickSortWorker (
+ IN OUT VOID *BufferToSort,
+ IN CONST UINTN Count,
+ IN CONST UINTN ElementSize,
+ IN SORT_COMPARE CompareFunction,
+ IN VOID *Buffer
+ )
+{
+ VOID *Pivot;
+ UINTN LoopCount;
+ UINTN NextSwapLocation;
+
+ ASSERT(BufferToSort != NULL);
+ ASSERT(CompareFunction != NULL);
+ ASSERT(Buffer != NULL);
+
+ if ( Count < 2
+ || ElementSize < 1
+ ){
+ return;
+ }
+
+ NextSwapLocation = 0;
+
+ //
+ // pick a pivot (we choose last element)
+ //
+ Pivot = ((UINT8*)BufferToSort+((Count-1)*ElementSize));
+
+ //
+ // Now get the pivot such that all on "left" are below it
+ // and everything "right" are above it
+ //
+ for ( LoopCount = 0
+ ; LoopCount < Count -1
+ ; LoopCount++
+ ){
+ //
+ // if the element is less than the pivot
+ //
+ if (CompareFunction((VOID*)((UINT8*)BufferToSort+((LoopCount)*ElementSize)),Pivot) <= 0){
+ //
+ // swap
+ //
+ CopyMem (Buffer, (UINT8*)BufferToSort+(NextSwapLocation*ElementSize), ElementSize);
+ CopyMem ((UINT8*)BufferToSort+(NextSwapLocation*ElementSize), (UINT8*)BufferToSort+((LoopCount)*ElementSize), ElementSize);
+ CopyMem ((UINT8*)BufferToSort+((LoopCount)*ElementSize), Buffer, ElementSize);
+
+ //
+ // increment NextSwapLocation
+ //
+ NextSwapLocation++;
+ }
+ }
+ //
+ // swap pivot to it's final position (NextSwapLocaiton)
+ //
+ CopyMem (Buffer, Pivot, ElementSize);
+ CopyMem (Pivot, (UINT8*)BufferToSort+(NextSwapLocation*ElementSize), ElementSize);
+ CopyMem ((UINT8*)BufferToSort+(NextSwapLocation*ElementSize), Buffer, ElementSize);
+
+ //
+ // Now recurse on 2 paritial lists. neither of these will have the 'pivot' element
+ // IE list is sorted left half, pivot element, sorted right half...
+ //
+ if (NextSwapLocation >= 2) {
+ QuickSortWorker(
+ BufferToSort,
+ NextSwapLocation,
+ ElementSize,
+ CompareFunction,
+ Buffer);
+ }
+
+ if ((Count - NextSwapLocation - 1) >= 2) {
+ QuickSortWorker(
+ (UINT8 *)BufferToSort + (NextSwapLocation+1) * ElementSize,
+ Count - NextSwapLocation - 1,
+ ElementSize,
+ CompareFunction,
+ Buffer);
+ }
+
+ return;
+}
+/**
+ Function to perform a Quick Sort alogrithm on a buffer of comparable elements.
+
+ Each element must be equal sized.
+
+ if BufferToSort is NULL, then ASSERT.
+ if CompareFunction is NULL, then ASSERT.
+
+ if Count is < 2 then perform no action.
+ if Size is < 1 then perform no action.
+
+ @param[in, out] BufferToSort on call a Buffer of (possibly sorted) elements
+ on return a buffer of sorted elements
+ @param[in] Count the number of elements in the buffer to sort
+ @param[in] ElementSize Size of an element in bytes
+ @param[in] CompareFunction The function to call to perform the comparison
+ of any 2 elements
+**/
+VOID
+EFIAPI
+PerformQuickSort (
+ IN OUT VOID *BufferToSort,
+ IN CONST UINTN Count,
+ IN CONST UINTN ElementSize,
+ IN SORT_COMPARE CompareFunction
+ )
+{
+ VOID *Buffer;
+
+ ASSERT(BufferToSort != NULL);
+ ASSERT(CompareFunction != NULL);
+
+ Buffer = AllocateZeroPool(ElementSize);
+ ASSERT(Buffer != NULL);
+
+ QuickSortWorker(
+ BufferToSort,
+ Count,
+ ElementSize,
+ CompareFunction,
+ Buffer);
+
+ FreePool(Buffer);
+ return;
+}
+
+/**
+ Function to compare 2 device paths for use in QuickSort.
+
+ @param[in] Buffer1 pointer to Device Path poiner to compare
+ @param[in] Buffer2 pointer to second DevicePath pointer to compare
+
+ @retval 0 Buffer1 equal to Buffer2
+ @retval <0 Buffer1 is less than Buffer2
+ @retval >0 Buffer1 is greater than Buffer2
+**/
+INTN
+EFIAPI
+DevicePathCompare (
+ IN CONST VOID *Buffer1,
+ IN CONST VOID *Buffer2
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath1;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath2;
+ CHAR16 *TextPath1;
+ CHAR16 *TextPath2;
+ EFI_STATUS Status;
+ INTN RetVal;
+
+ DevicePath1 = *(EFI_DEVICE_PATH_PROTOCOL**)Buffer1;
+ DevicePath2 = *(EFI_DEVICE_PATH_PROTOCOL**)Buffer2;
+
+ if (DevicePath1 == NULL) {
+ if (DevicePath2 == NULL) {
+ return 0;
+ }
+
+ return -1;
+ }
+
+ if (DevicePath2 == NULL) {
+ return 1;
+ }
+
+ if (mUnicodeCollation == NULL) {
+ Status = gBS->LocateProtocol(
+ &gEfiUnicodeCollation2ProtocolGuid,
+ NULL,
+ (VOID**)&mUnicodeCollation);
+
+ ASSERT_EFI_ERROR(Status);
+ }
+
+ TextPath1 = ConvertDevicePathToText(
+ DevicePath1,
+ FALSE,
+ FALSE);
+
+ TextPath2 = ConvertDevicePathToText(
+ DevicePath2,
+ FALSE,
+ FALSE);
+
+ if (TextPath1 == NULL) {
+ RetVal = -1;
+ } else if (TextPath2 == NULL) {
+ RetVal = 1;
+ } else {
+ RetVal = mUnicodeCollation->StriColl(
+ mUnicodeCollation,
+ TextPath1,
+ TextPath2);
+ }
+
+ USL_FREE_NON_NULL(TextPath1);
+ USL_FREE_NON_NULL(TextPath2);
+
+ return (RetVal);
+}
+
+/**
+ Function to compare 2 strings without regard to case of the characters.
+
+ @param[in] Buffer1 Pointer to String to compare.
+ @param[in] Buffer2 Pointer to second String to compare.
+
+ @retval 0 Buffer1 equal to Buffer2.
+ @retval <0 Buffer1 is less than Buffer2.
+ @retval >0 Buffer1 is greater than Buffer2.
+**/
+INTN
+EFIAPI
+StringNoCaseCompare (
+ IN CONST VOID *Buffer1,
+ IN CONST VOID *Buffer2
+ )
+{
+ EFI_STATUS Status;
+ if (mUnicodeCollation == NULL) {
+ Status = gBS->LocateProtocol(
+ &gEfiUnicodeCollation2ProtocolGuid,
+ NULL,
+ (VOID**)&mUnicodeCollation);
+
+ ASSERT_EFI_ERROR(Status);
+ }
+
+ return (mUnicodeCollation->StriColl(
+ mUnicodeCollation,
+ *(CHAR16**)Buffer1,
+ *(CHAR16**)Buffer2));
+}
+
+
+/**
+ Function to compare 2 strings.
+
+ @param[in] Buffer1 Pointer to String to compare (CHAR16**).
+ @param[in] Buffer2 Pointer to second String to compare (CHAR16**).
+
+ @retval 0 Buffer1 equal to Buffer2.
+ @retval <0 Buffer1 is less than Buffer2.
+ @retval >0 Buffer1 is greater than Buffer2.
+**/
+INTN
+EFIAPI
+StringCompare (
+ IN CONST VOID *Buffer1,
+ IN CONST VOID *Buffer2
+ )
+{
+ return (StrCmp(
+ *(CHAR16**)Buffer1,
+ *(CHAR16**)Buffer2));
+}
diff --git a/Core/MdeModulePkg/Library/UefiSortLib/UefiSortLib.inf b/Core/MdeModulePkg/Library/UefiSortLib/UefiSortLib.inf
new file mode 100644
index 0000000000..32c02b012f
--- /dev/null
+++ b/Core/MdeModulePkg/Library/UefiSortLib/UefiSortLib.inf
@@ -0,0 +1,47 @@
+## @file
+# Library used for sorting routines.
+#
+# Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved. <BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010006
+ BASE_NAME = UefiSortLib
+ MODULE_UNI_FILE = UefiSortLib.uni
+ FILE_GUID = 4264A823-45A3-42db-B92C-AA078555CBD3
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = SortLib|UEFI_APPLICATION UEFI_DRIVER UEFI_DRIVER DXE_RUNTIME_DRIVER DXE_DRIVER
+
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources.common]
+ UefiSortLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ MemoryAllocationLib
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ UefiBootServicesTableLib
+ DevicePathLib
+
+[Protocols]
+ gEfiUnicodeCollation2ProtocolGuid ## CONSUMES
+ gEfiDevicePathProtocolGuid ## CONSUMES
+
diff --git a/Core/MdeModulePkg/Library/UefiSortLib/UefiSortLib.uni b/Core/MdeModulePkg/Library/UefiSortLib/UefiSortLib.uni
new file mode 100644
index 0000000000..2163301c42
--- /dev/null
+++ b/Core/MdeModulePkg/Library/UefiSortLib/UefiSortLib.uni
Binary files differ
diff --git a/Core/MdeModulePkg/Library/VarCheckHiiLib/InternalVarCheckStructure.h b/Core/MdeModulePkg/Library/VarCheckHiiLib/InternalVarCheckStructure.h
new file mode 100644
index 0000000000..a9faed48d9
--- /dev/null
+++ b/Core/MdeModulePkg/Library/VarCheckHiiLib/InternalVarCheckStructure.h
@@ -0,0 +1,82 @@
+/** @file
+ Internal structure for Var Check Hii.
+
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _VAR_CHECK_STRUCTURE_H_
+#define _VAR_CHECK_STRUCTURE_H_
+
+//
+// Alignment for Hii Variable and Question header.
+//
+#define HEADER_ALIGNMENT 4
+#define HEADER_ALIGN(Header) (((UINTN) (Header) + HEADER_ALIGNMENT - 1) & (~(HEADER_ALIGNMENT - 1)))
+
+#pragma pack (1)
+
+#define VAR_CHECK_HII_REVISION 0x0001
+
+typedef struct {
+ UINT16 Revision;
+ UINT16 HeaderLength;
+ UINT32 Length; // Length include this header
+ UINT8 OpCode;
+ UINT8 Reserved;
+ UINT16 Size;
+ UINT32 Attributes;
+ EFI_GUID Guid;
+//CHAR16 Name[];
+} VAR_CHECK_HII_VARIABLE_HEADER;
+
+typedef struct {
+ UINT8 OpCode;
+ UINT8 Length; // Length include this header
+ UINT16 VarOffset;
+ UINT8 StorageWidth;
+} VAR_CHECK_HII_QUESTION_HEADER;
+
+typedef struct {
+ UINT8 OpCode;
+ UINT8 Length; // Length include this header
+ UINT16 VarOffset;
+ UINT8 StorageWidth;
+//UINTx Data[]; // x = UINT8/UINT16/UINT32/UINT64;
+} VAR_CHECK_HII_QUESTION_ONEOF;
+
+typedef struct {
+ UINT8 OpCode;
+ UINT8 Length; // Length include this header
+ UINT16 VarOffset;
+ UINT8 StorageWidth;
+} VAR_CHECK_HII_QUESTION_CHECKBOX;
+
+typedef struct {
+ UINT8 OpCode;
+ UINT8 Length; // Length include this header
+ UINT16 VarOffset;
+ UINT8 StorageWidth;
+//UINTx Minimum; // x = UINT8/UINT16/UINT32/UINT64;
+//UINTx Maximum; // x = UINT8/UINT16/UINT32/UINT64;
+} VAR_CHECK_HII_QUESTION_NUMERIC;
+
+typedef struct {
+ UINT8 OpCode;
+ UINT8 Length; // Length include this header
+ UINT16 VarOffset;
+ UINT8 StorageWidth;
+ UINT8 MaxContainers;
+//UINTx Data[]; // x = UINT8/UINT16/UINT32/UINT64;
+} VAR_CHECK_HII_QUESTION_ORDEREDLIST;
+
+#pragma pack ()
+
+#endif
diff --git a/Core/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHii.h b/Core/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHii.h
new file mode 100644
index 0000000000..d770785490
--- /dev/null
+++ b/Core/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHii.h
@@ -0,0 +1,63 @@
+/** @file
+ Include file for Var Check Hii handler and bin.
+
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _VAR_CHECK_HII_H_
+#define _VAR_CHECK_HII_H_
+
+#include <Library/VarCheckLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+#include <Guid/ZeroGuid.h>
+
+#include <Protocol/HiiDatabase.h>
+#include <Protocol/FirmwareVolume2.h>
+#include <Protocol/FirmwareVolumeBlock.h>
+
+#include "InternalVarCheckStructure.h"
+#include "VarCheckHiiGen.h"
+
+//#define DUMP_VAR_CHECK_HII
+//#define DUMP_HII_DATA
+
+typedef struct {
+ UINT8 HiiOpCode;
+ CHAR8 *HiiOpCodeStr;
+} VAR_CHECK_HII_OPCODE_STRING;
+
+typedef struct {
+ UINT8 PackageType;
+ CHAR8 *PackageTypeStr;
+} VAR_CHECK_HII_PACKAGE_TYPE_STRING;
+
+/**
+ Dump Var Check HII.
+
+ @param[in] VarCheckHiiBin Pointer to VarCheckHiiBin.
+ @param[in] VarCheckHiiBinSize VarCheckHiiBin size.
+
+**/
+VOID
+DumpVarCheckHii (
+ IN VOID *VarCheckHiiBin,
+ IN UINTN VarCheckHiiBinSize
+ );
+
+extern VAR_CHECK_HII_VARIABLE_HEADER *mVarCheckHiiBin;
+extern UINTN mVarCheckHiiBinSize;
+
+#endif
diff --git a/Core/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiGen.c b/Core/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiGen.c
new file mode 100644
index 0000000000..cab92967aa
--- /dev/null
+++ b/Core/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiGen.c
@@ -0,0 +1,1483 @@
+/** @file
+ Var Check Hii bin generation.
+
+Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "VarCheckHiiGen.h"
+
+LIST_ENTRY mVarCheckHiiList = INITIALIZE_LIST_HEAD_VARIABLE (mVarCheckHiiList);
+
+#define VAR_CHECK_HII_VARIABLE_NODE_SIGNATURE SIGNATURE_32 ('V', 'C', 'H', 'V')
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link;
+ VAR_CHECK_HII_VARIABLE_HEADER *HiiVariable;
+ EFI_VARSTORE_ID VarStoreId;
+
+ VAR_CHECK_HII_QUESTION_HEADER **HiiQuestionArray;
+} VAR_CHECK_HII_VARIABLE_NODE;
+
+#define VAR_CHECK_HII_VARIABLE_FROM_LINK(a) CR (a, VAR_CHECK_HII_VARIABLE_NODE, Link, VAR_CHECK_HII_VARIABLE_NODE_SIGNATURE)
+
+CHAR16 *mVarName = NULL;
+UINTN mMaxVarNameSize = 0;
+
+#ifdef DUMP_HII_DATA
+GLOBAL_REMOVE_IF_UNREFERENCED VAR_CHECK_HII_OPCODE_STRING mIfrOpCodeStringTable[] = {
+ {EFI_IFR_VARSTORE_OP, "EFI_IFR_VARSTORE_OP"},
+ {EFI_IFR_VARSTORE_EFI_OP, "EFI_IFR_VARSTORE_EFI_OP"},
+ {EFI_IFR_ONE_OF_OP, "EFI_IFR_ONE_OF_OP"},
+ {EFI_IFR_CHECKBOX_OP, "EFI_IFR_CHECKBOX_OP"},
+ {EFI_IFR_NUMERIC_OP, "EFI_IFR_NUMERIC_OP"},
+ {EFI_IFR_ORDERED_LIST_OP, "EFI_IFR_ORDERED_LIST_OP"},
+ {EFI_IFR_ONE_OF_OPTION_OP, "EFI_IFR_ONE_OF_OPTION_OP"},
+};
+
+/**
+ Ifr opcode to string.
+
+ @param[in] IfrOpCode Ifr OpCode.
+
+ @return Pointer to string.
+
+**/
+CHAR8 *
+IfrOpCodeToStr (
+ IN UINT8 IfrOpCode
+ )
+{
+ UINTN Index;
+ for (Index = 0; Index < sizeof (mIfrOpCodeStringTable) / sizeof (mIfrOpCodeStringTable[0]); Index++) {
+ if (mIfrOpCodeStringTable[Index].HiiOpCode == IfrOpCode) {
+ return mIfrOpCodeStringTable[Index].HiiOpCodeStr;
+ }
+ }
+
+ return "<UnknownIfrOpCode>";
+}
+
+GLOBAL_REMOVE_IF_UNREFERENCED VAR_CHECK_HII_PACKAGE_TYPE_STRING mPackageTypeStringTable[] = {
+ {EFI_HII_PACKAGE_TYPE_ALL, "EFI_HII_PACKAGE_TYPE_ALL"},
+ {EFI_HII_PACKAGE_TYPE_GUID, "EFI_HII_PACKAGE_TYPE_GUID"},
+ {EFI_HII_PACKAGE_FORMS, "EFI_HII_PACKAGE_FORMS"},
+ {EFI_HII_PACKAGE_STRINGS, "EFI_HII_PACKAGE_STRINGS"},
+ {EFI_HII_PACKAGE_FONTS, "EFI_HII_PACKAGE_FONTS"},
+ {EFI_HII_PACKAGE_IMAGES, "EFI_HII_PACKAGE_IMAGES"},
+ {EFI_HII_PACKAGE_SIMPLE_FONTS, "EFI_HII_PACKAGE_SIMPLE_FONTS"},
+ {EFI_HII_PACKAGE_DEVICE_PATH, "EFI_HII_PACKAGE_DEVICE_PATH"},
+ {EFI_HII_PACKAGE_KEYBOARD_LAYOUT, "EFI_HII_PACKAGE_KEYBOARD_LAYOUT"},
+ {EFI_HII_PACKAGE_ANIMATIONS, "EFI_HII_PACKAGE_ANIMATIONS"},
+ {EFI_HII_PACKAGE_END, "EFI_HII_PACKAGE_END"},
+ {EFI_HII_PACKAGE_TYPE_SYSTEM_BEGIN, "EFI_HII_PACKAGE_TYPE_SYSTEM_BEGIN"},
+ {EFI_HII_PACKAGE_TYPE_SYSTEM_END, "EFI_HII_PACKAGE_TYPE_SYSTEM_END"},
+};
+
+/**
+ Hii Package type to string.
+
+ @param[in] PackageType Package Type
+
+ @return Pointer to string.
+
+**/
+CHAR8 *
+HiiPackageTypeToStr (
+ IN UINT8 PackageType
+ )
+{
+ UINTN Index;
+ for (Index = 0; Index < sizeof (mPackageTypeStringTable) / sizeof (mPackageTypeStringTable[0]); Index++) {
+ if (mPackageTypeStringTable[Index].PackageType == PackageType) {
+ return mPackageTypeStringTable[Index].PackageTypeStr;
+ }
+ }
+
+ return "<UnknownPackageType>";
+}
+
+/**
+ Dump Hii Package.
+
+ @param[in] HiiPackage Pointer to Hii Package.
+
+**/
+VOID
+DumpHiiPackage (
+ IN VOID *HiiPackage
+ )
+{
+ EFI_HII_PACKAGE_HEADER *HiiPackageHeader;
+ EFI_IFR_OP_HEADER *IfrOpCodeHeader;
+ EFI_IFR_VARSTORE *IfrVarStore;
+ EFI_IFR_VARSTORE_EFI *IfrEfiVarStore;
+
+ HiiPackageHeader = (EFI_HII_PACKAGE_HEADER *) HiiPackage;
+
+ DEBUG ((EFI_D_INFO, " HiiPackageHeader->Type - 0x%02x (%a)\n", HiiPackageHeader->Type, HiiPackageTypeToStr ((UINT8) HiiPackageHeader->Type)));
+ DEBUG ((EFI_D_INFO, " HiiPackageHeader->Length - 0x%06x\n", HiiPackageHeader->Length));
+
+ switch (HiiPackageHeader->Type) {
+ case EFI_HII_PACKAGE_FORMS:
+ IfrOpCodeHeader = (EFI_IFR_OP_HEADER *) (HiiPackageHeader + 1);
+
+ while ((UINTN) IfrOpCodeHeader < ((UINTN) HiiPackageHeader + HiiPackageHeader->Length)) {
+ switch (IfrOpCodeHeader->OpCode) {
+ case EFI_IFR_VARSTORE_OP:
+ IfrVarStore = (EFI_IFR_VARSTORE *) IfrOpCodeHeader;
+ DEBUG ((EFI_D_INFO, " IfrOpCodeHeader->OpCode - 0x%02x (%a)\n", IfrOpCodeHeader->OpCode, IfrOpCodeToStr (IfrOpCodeHeader->OpCode)));
+ DEBUG ((EFI_D_INFO, " IfrOpCodeHeader->Length - 0x%02x\n", IfrOpCodeHeader->Length));
+ DEBUG ((EFI_D_INFO, " IfrOpCodeHeader->Scope - 0x%02x\n", IfrOpCodeHeader->Scope));
+ DEBUG ((EFI_D_INFO, " Guid - %g\n", &IfrVarStore->Guid));
+ DEBUG ((EFI_D_INFO, " VarStoreId - 0x%04x\n", IfrVarStore->VarStoreId));
+ DEBUG ((EFI_D_INFO, " Size - 0x%04x\n", IfrVarStore->Size));
+ DEBUG ((EFI_D_INFO, " Name - %a\n", IfrVarStore->Name));
+ break;
+
+ case EFI_IFR_VARSTORE_EFI_OP:
+ IfrEfiVarStore = (EFI_IFR_VARSTORE_EFI *) IfrOpCodeHeader;
+ if (IfrEfiVarStore->Header.Length >= sizeof (EFI_IFR_VARSTORE_EFI)) {
+ DEBUG ((EFI_D_INFO, " IfrOpCodeHeader->OpCode - 0x%02x (%a)\n", IfrOpCodeHeader->OpCode, IfrOpCodeToStr (IfrOpCodeHeader->OpCode)));
+ DEBUG ((EFI_D_INFO, " IfrOpCodeHeader->Length - 0x02%x\n", IfrOpCodeHeader->Length));
+ DEBUG ((EFI_D_INFO, " IfrOpCodeHeader->Scope - 0x02%x\n", IfrOpCodeHeader->Scope));
+ DEBUG ((EFI_D_INFO, " Guid - %g\n", &IfrEfiVarStore->Guid));
+ DEBUG ((EFI_D_INFO, " VarStoreId - 0x%04x\n", IfrEfiVarStore->VarStoreId));
+ DEBUG ((EFI_D_INFO, " Size - 0x%04x\n", IfrEfiVarStore->Size));
+ DEBUG ((EFI_D_INFO, " Attributes - 0x%08x\n", IfrEfiVarStore->Attributes));
+ DEBUG ((EFI_D_INFO, " Name - %a\n", IfrEfiVarStore->Name));
+ }
+ break;
+
+ case EFI_IFR_ONE_OF_OP:
+ case EFI_IFR_CHECKBOX_OP:
+ case EFI_IFR_NUMERIC_OP:
+ case EFI_IFR_ORDERED_LIST_OP:
+ DEBUG ((EFI_D_INFO, " IfrOpCodeHeader->OpCode - 0x%02x (%a)\n", IfrOpCodeHeader->OpCode, IfrOpCodeToStr (IfrOpCodeHeader->OpCode)));
+ DEBUG ((EFI_D_INFO, " IfrOpCodeHeader->Length - 0x02%x\n", IfrOpCodeHeader->Length));
+ DEBUG ((EFI_D_INFO, " IfrOpCodeHeader->Scope - 0x02%x\n", IfrOpCodeHeader->Scope));
+ DEBUG ((EFI_D_INFO, " Prompt - 0x%04x\n", ((EFI_IFR_ONE_OF *) IfrOpCodeHeader)->Question.Header.Prompt));
+ DEBUG ((EFI_D_INFO, " Help - 0x%04x\n", ((EFI_IFR_ONE_OF *) IfrOpCodeHeader)->Question.Header.Help));
+ DEBUG ((EFI_D_INFO, " QuestionId - 0x%04x\n", ((EFI_IFR_ONE_OF *) IfrOpCodeHeader)->Question.QuestionId));
+ DEBUG ((EFI_D_INFO, " VarStoreId - 0x%04x\n", ((EFI_IFR_ONE_OF *) IfrOpCodeHeader)->Question.VarStoreId));
+ DEBUG ((EFI_D_INFO, " VarStoreInfo - 0x%04x\n", ((EFI_IFR_ONE_OF * )IfrOpCodeHeader)->Question.VarStoreInfo.VarOffset));
+ {
+ EFI_IFR_ONE_OF *IfrOneOf;
+ EFI_IFR_CHECKBOX *IfrCheckBox;
+ EFI_IFR_NUMERIC *IfrNumeric;
+ EFI_IFR_ORDERED_LIST *IfrOrderedList;
+
+ switch (IfrOpCodeHeader->OpCode) {
+ case EFI_IFR_ONE_OF_OP:
+ IfrOneOf = (EFI_IFR_ONE_OF *) IfrOpCodeHeader;
+ DEBUG ((EFI_D_INFO, " Flags - 0x%02x\n", IfrOneOf->Flags));
+ switch (IfrOneOf->Flags & EFI_IFR_NUMERIC_SIZE) {
+ case EFI_IFR_NUMERIC_SIZE_1:
+ DEBUG ((EFI_D_INFO, " MinValue - 0x%02x\n", IfrOneOf->data.u8.MinValue));
+ DEBUG ((EFI_D_INFO, " MaxValue - 0x%02x\n", IfrOneOf->data.u8.MaxValue));
+ DEBUG ((EFI_D_INFO, " Step - 0x%02x\n", IfrOneOf->data.u8.Step));
+ break;
+ case EFI_IFR_NUMERIC_SIZE_2:
+ DEBUG ((EFI_D_INFO, " MinValue - 0x%04x\n", IfrOneOf->data.u16.MinValue));
+ DEBUG ((EFI_D_INFO, " MaxValue - 0x%04x\n", IfrOneOf->data.u16.MaxValue));
+ DEBUG ((EFI_D_INFO, " Step - 0x%04x\n", IfrOneOf->data.u16.Step));
+ break;
+ case EFI_IFR_NUMERIC_SIZE_4:
+ DEBUG ((EFI_D_INFO, " MinValue - 0x%08x\n", IfrOneOf->data.u32.MinValue));
+ DEBUG ((EFI_D_INFO, " MaxValue - 0x%08x\n", IfrOneOf->data.u32.MaxValue));
+ DEBUG ((EFI_D_INFO, " Step - 0x%08x\n", IfrOneOf->data.u32.Step));
+ break;
+ case EFI_IFR_NUMERIC_SIZE_8:
+ DEBUG ((EFI_D_INFO, " MinValue - 0x%016lx\n", IfrOneOf->data.u64.MinValue));
+ DEBUG ((EFI_D_INFO, " MaxValue - 0x%016lx\n", IfrOneOf->data.u64.MaxValue));
+ DEBUG ((EFI_D_INFO, " Step - 0x%016lx\n", IfrOneOf->data.u64.Step));
+ break;
+ }
+ break;
+ case EFI_IFR_CHECKBOX_OP:
+ IfrCheckBox = (EFI_IFR_CHECKBOX *) IfrOpCodeHeader;
+ DEBUG ((EFI_D_INFO, " Flags - 0x%02x\n", IfrCheckBox->Flags));
+ break;
+ case EFI_IFR_NUMERIC_OP:
+ IfrNumeric = (EFI_IFR_NUMERIC *) IfrOpCodeHeader;
+ DEBUG ((EFI_D_INFO, " Flags - 0x%02x\n", IfrNumeric->Flags));
+ switch (IfrNumeric->Flags & EFI_IFR_NUMERIC_SIZE) {
+ case EFI_IFR_NUMERIC_SIZE_1:
+ DEBUG ((EFI_D_INFO, " MinValue - 0x%02x\n", IfrNumeric->data.u8.MinValue));
+ DEBUG ((EFI_D_INFO, " MaxValue - 0x%02x\n", IfrNumeric->data.u8.MaxValue));
+ DEBUG ((EFI_D_INFO, " Step - 0x%02x\n", IfrNumeric->data.u8.Step));
+ break;
+ case EFI_IFR_NUMERIC_SIZE_2:
+ DEBUG ((EFI_D_INFO, " MinValue - 0x%04x\n", IfrNumeric->data.u16.MinValue));
+ DEBUG ((EFI_D_INFO, " MaxValue - 0x%04x\n", IfrNumeric->data.u16.MaxValue));
+ DEBUG ((EFI_D_INFO, " Step - 0x%04x\n", IfrNumeric->data.u16.Step));
+ break;
+ case EFI_IFR_NUMERIC_SIZE_4:
+ DEBUG ((EFI_D_INFO, " MinValue - 0x%08x\n", IfrNumeric->data.u32.MinValue));
+ DEBUG ((EFI_D_INFO, " MaxValue - 0x%08x\n", IfrNumeric->data.u32.MaxValue));
+ DEBUG ((EFI_D_INFO, " Step - 0x%08x\n", IfrNumeric->data.u32.Step));
+ break;
+ case EFI_IFR_NUMERIC_SIZE_8:
+ DEBUG ((EFI_D_INFO, " MinValue - 0x%016lx\n", IfrNumeric->data.u64.MinValue));
+ DEBUG ((EFI_D_INFO, " MaxValue - 0x%016lx\n", IfrNumeric->data.u64.MaxValue));
+ DEBUG ((EFI_D_INFO, " Step - 0x%016lx\n", IfrNumeric->data.u64.Step));
+ break;
+ }
+ break;
+ case EFI_IFR_ORDERED_LIST_OP:
+ IfrOrderedList = (EFI_IFR_ORDERED_LIST *) IfrOpCodeHeader;
+ DEBUG ((EFI_D_INFO, " MaxContainers - 0x%02x\n", IfrOrderedList->MaxContainers));
+ DEBUG ((EFI_D_INFO, " Flags - 0x%02x\n", IfrOrderedList->Flags));
+ break;
+ default:
+ break;
+ }
+
+ if (IfrOpCodeHeader->Scope != 0) {
+ UINTN Scope;
+ EFI_IFR_ONE_OF_OPTION *IfrOneOfOption;
+
+ IfrOpCodeHeader = (EFI_IFR_OP_HEADER *) ((UINTN) IfrOpCodeHeader + IfrOpCodeHeader->Length);
+ Scope = 1;
+ while (Scope != 0) {
+ switch (IfrOpCodeHeader->OpCode) {
+ case EFI_IFR_ONE_OF_OPTION_OP:
+ IfrOneOfOption = (EFI_IFR_ONE_OF_OPTION *)IfrOpCodeHeader;
+ DEBUG ((EFI_D_INFO, "!!!! IfrOpCodeHeader->OpCode - 0x%02x (%a)\n", (UINTN)IfrOpCodeHeader->OpCode, IfrOpCodeToStr (IfrOpCodeHeader->OpCode)));
+ DEBUG ((EFI_D_INFO, "!!!! IfrOpCodeHeader->Scope - 0x%02x\n", IfrOpCodeHeader->Scope));
+ DEBUG ((EFI_D_INFO, "!!!! Option - 0x%04x\n", IfrOneOfOption->Option));
+ DEBUG ((EFI_D_INFO, "!!!! Flags - 0x%02x\n", IfrOneOfOption->Flags));
+ DEBUG ((EFI_D_INFO, "!!!! Type - 0x%02x\n", IfrOneOfOption->Type));
+ switch (IfrOneOfOption->Type) {
+ case EFI_IFR_TYPE_NUM_SIZE_8:
+ DEBUG ((EFI_D_INFO, "!!!! Value - 0x%02x\n", IfrOneOfOption->Value.u8));
+ break;
+ case EFI_IFR_TYPE_NUM_SIZE_16:
+ DEBUG ((EFI_D_INFO, "!!!! Value - 0x%04x\n", IfrOneOfOption->Value.u16));
+ break;
+ case EFI_IFR_TYPE_NUM_SIZE_32:
+ DEBUG ((EFI_D_INFO, "!!!! Value - 0x%08x\n", IfrOneOfOption->Value.u32));
+ break;
+ case EFI_IFR_TYPE_NUM_SIZE_64:
+ DEBUG ((EFI_D_INFO, "!!!! Value - 0x%016lx\n", IfrOneOfOption->Value.u64));
+ break;
+ case EFI_IFR_TYPE_BOOLEAN:
+ DEBUG ((EFI_D_INFO, "!!!! Value - 0x%02x\n", IfrOneOfOption->Value.b));
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+
+ if (IfrOpCodeHeader->OpCode == EFI_IFR_END_OP) {
+ ASSERT (Scope > 0);
+ Scope--;
+ if (Scope == 0) {
+ break;
+ }
+ } else if (IfrOpCodeHeader->Scope != 0) {
+ Scope++;
+ }
+ IfrOpCodeHeader = (EFI_IFR_OP_HEADER *) ((UINTN) IfrOpCodeHeader + IfrOpCodeHeader->Length);
+ }
+ }
+ }
+ default:
+ break;
+ }
+ IfrOpCodeHeader = (EFI_IFR_OP_HEADER *) ((UINTN) IfrOpCodeHeader + IfrOpCodeHeader->Length);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+/**
+ Dump Hii Database.
+
+ @param[in] HiiDatabase Pointer to Hii Database.
+ @param[in] HiiDatabaseSize Hii Database size.
+
+**/
+VOID
+DumpHiiDatabase (
+ IN VOID *HiiDatabase,
+ IN UINTN HiiDatabaseSize
+ )
+{
+ EFI_HII_PACKAGE_LIST_HEADER *HiiPackageListHeader;
+ EFI_HII_PACKAGE_HEADER *HiiPackageHeader;
+
+ DEBUG ((EFI_D_INFO, "HiiDatabaseSize - 0x%x\n", HiiDatabaseSize));
+ HiiPackageListHeader = (EFI_HII_PACKAGE_LIST_HEADER *) HiiDatabase;
+
+ while ((UINTN) HiiPackageListHeader < ((UINTN) HiiDatabase + HiiDatabaseSize)) {
+ DEBUG ((EFI_D_INFO, "HiiPackageListHeader->PackageListGuid - %g\n", &HiiPackageListHeader->PackageListGuid));
+ DEBUG ((EFI_D_INFO, "HiiPackageListHeader->PackageLength - 0x%x\n", (UINTN)HiiPackageListHeader->PackageLength));
+ HiiPackageHeader = (EFI_HII_PACKAGE_HEADER *)(HiiPackageListHeader + 1);
+
+ while ((UINTN) HiiPackageHeader < (UINTN) HiiPackageListHeader + HiiPackageListHeader->PackageLength) {
+
+ DumpHiiPackage (HiiPackageHeader);
+
+ HiiPackageHeader = (EFI_HII_PACKAGE_HEADER *) ((UINTN) HiiPackageHeader + HiiPackageHeader->Length);
+ }
+
+ HiiPackageListHeader = (EFI_HII_PACKAGE_LIST_HEADER *) ((UINTN) HiiPackageListHeader + HiiPackageListHeader->PackageLength);
+ }
+
+ return ;
+}
+#endif
+
+/**
+ Allocates a buffer of a certain pool type.
+
+ Allocates the number bytes specified by AllocationSize of a certain pool type and returns a
+ pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is
+ returned. If there is not enough memory remaining to satisfy the request, then NULL is returned.
+
+ @param MemoryType The type of memory to allocate.
+ @param AllocationSize The number of bytes to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+InternalVarCheckAllocatePool (
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN AllocationSize
+ )
+{
+ EFI_STATUS Status;
+ VOID *Memory;
+
+ Status = gBS->AllocatePool (MemoryType, AllocationSize, &Memory);
+ if (EFI_ERROR (Status)) {
+ Memory = NULL;
+ }
+ return Memory;
+}
+
+/**
+ Allocates and zeros a buffer of type EfiBootServicesData.
+
+ Allocates the number bytes specified by AllocationSize of type EfiBootServicesData, clears the
+ buffer with zeros, and returns a pointer to the allocated buffer. If AllocationSize is 0, then a
+ valid buffer of 0 size is returned. If there is not enough memory remaining to satisfy the
+ request, then NULL is returned.
+
+ @param AllocationSize The number of bytes to allocate and zero.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+InternalVarCheckAllocateZeroPool (
+ IN UINTN AllocationSize
+ )
+{
+ VOID *Memory;
+
+ Memory = InternalVarCheckAllocatePool (EfiBootServicesData, AllocationSize);
+ if (Memory != NULL) {
+ Memory = ZeroMem (Memory, AllocationSize);
+ }
+ return Memory;
+}
+
+/**
+ Frees a buffer that was previously allocated with one of the pool allocation functions in the
+ Memory Allocation Library.
+
+ Frees the buffer specified by Buffer. Buffer must have been allocated on a previous call to the
+ pool allocation services of the Memory Allocation Library. If it is not possible to free pool
+ resources, then this function will perform no actions.
+
+ If Buffer was not allocated with a pool allocation function in the Memory Allocation Library,
+ then ASSERT().
+
+ @param Buffer The pointer to the buffer to free.
+
+**/
+VOID
+EFIAPI
+InternalVarCheckFreePool (
+ IN VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+
+ Status = gBS->FreePool (Buffer);
+ ASSERT_EFI_ERROR (Status);
+}
+
+/**
+ Reallocates a buffer of type EfiBootServicesData.
+
+ Allocates and zeros the number bytes specified by NewSize from memory of type
+ EfiBootServicesData. If OldBuffer is not NULL, then the smaller of OldSize and
+ NewSize bytes are copied from OldBuffer to the newly allocated buffer, and
+ OldBuffer is freed. A pointer to the newly allocated buffer is returned.
+ If NewSize is 0, then a valid buffer of 0 size is returned. If there is not
+ enough memory remaining to satisfy the request, then NULL is returned.
+
+ If the allocation of the new buffer is successful and the smaller of NewSize and OldSize
+ is greater than (MAX_ADDRESS - OldBuffer + 1), then ASSERT().
+
+ @param OldSize The size, in bytes, of OldBuffer.
+ @param NewSize The size, in bytes, of the buffer to reallocate.
+ @param OldBuffer The buffer to copy to the allocated buffer. This is an optional
+ parameter that may be NULL.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+InternalVarCheckReallocatePool (
+ IN UINTN OldSize,
+ IN UINTN NewSize,
+ IN VOID *OldBuffer OPTIONAL
+ )
+{
+ VOID *NewBuffer;
+
+ NewBuffer = InternalVarCheckAllocateZeroPool (NewSize);
+ if (NewBuffer != NULL && OldBuffer != NULL) {
+ CopyMem (NewBuffer, OldBuffer, MIN (OldSize, NewSize));
+ InternalVarCheckFreePool (OldBuffer);
+ }
+ return NewBuffer;
+}
+
+/**
+ Merge Hii Question.
+
+ @param[in, out] HiiVariableNode Pointer to Hii Variable node.
+ @param[in] HiiQuestion Pointer to Hii Question.
+ @param[in] FromFv Hii Question from FV.
+
+**/
+VOID
+MergeHiiQuestion (
+ IN OUT VAR_CHECK_HII_VARIABLE_NODE *HiiVariableNode,
+ IN VAR_CHECK_HII_QUESTION_HEADER *HiiQuestion,
+ IN BOOLEAN FromFv
+ )
+{
+ VAR_CHECK_HII_QUESTION_HEADER *HiiQuestion1;
+ VAR_CHECK_HII_QUESTION_HEADER *HiiQuestion2;
+ VAR_CHECK_HII_QUESTION_HEADER *NewHiiQuestion;
+ UINT8 NewLength;
+ UINT64 Minimum1;
+ UINT64 Maximum1;
+ UINT64 OneValue1;
+ UINT64 Minimum2;
+ UINT64 Maximum2;
+ UINT64 OneValue2;
+ UINT8 *Ptr;
+ UINT8 *Ptr1;
+ UINT8 *Ptr2;
+
+ //
+ // Hii Question from Hii Database has high priority.
+ // Do not to merge Hii Question from Fv to Hii Question from Hii Database.
+ //
+ if (FromFv) {
+ InternalVarCheckFreePool (HiiQuestion);
+ return;
+ }
+
+ HiiQuestion1 = HiiVariableNode->HiiQuestionArray[HiiQuestion->VarOffset];
+ HiiQuestion2 = HiiQuestion;
+
+ ASSERT ((HiiQuestion1->OpCode == HiiQuestion2->OpCode) && (HiiQuestion1->StorageWidth == HiiQuestion2->StorageWidth));
+
+ switch (HiiQuestion1->OpCode) {
+ case EFI_IFR_ONE_OF_OP:
+ DEBUG ((EFI_D_INFO, "MergeHiiQuestion - EFI_IFR_ONE_OF_OP VarOffset = 0x%04x\n", HiiQuestion1->VarOffset));
+ //
+ // Get the length of Hii Question 1.
+ //
+ NewLength = HiiQuestion1->Length;
+
+ //
+ // Check if the one of options in Hii Question 2 have been in Hii Question 1.
+ //
+ Ptr2 = (UINT8 *) ((VAR_CHECK_HII_QUESTION_ONEOF *) HiiQuestion2 + 1);
+ while ((UINTN) Ptr2 < (UINTN) HiiQuestion2 + HiiQuestion2->Length) {
+ OneValue2 = 0;
+ CopyMem (&OneValue2, Ptr2, HiiQuestion2->StorageWidth);
+
+ Ptr1 = (UINT8 *) ((VAR_CHECK_HII_QUESTION_ONEOF *) HiiQuestion1 + 1);
+ while ((UINTN) Ptr1 < (UINTN) HiiQuestion1 + HiiQuestion1->Length) {
+ OneValue1 = 0;
+ CopyMem (&OneValue1, Ptr1, HiiQuestion1->StorageWidth);
+ if (OneValue2 == OneValue1) {
+ //
+ // Match
+ //
+ break;
+ }
+ Ptr1 += HiiQuestion1->StorageWidth;
+ }
+ if ((UINTN) Ptr1 >= ((UINTN) HiiQuestion1 + HiiQuestion1->Length)) {
+ //
+ // No match
+ //
+ NewLength = (UINT8) (NewLength + HiiQuestion1->StorageWidth);
+ }
+ Ptr2 += HiiQuestion2->StorageWidth;
+ }
+
+ if (NewLength > HiiQuestion1->Length) {
+ //
+ // Merge the one of options of Hii Question 2 and Hii Question 1.
+ //
+ NewHiiQuestion = InternalVarCheckAllocateZeroPool (NewLength);
+ ASSERT (NewHiiQuestion != NULL);
+ CopyMem (NewHiiQuestion, HiiQuestion1, HiiQuestion1->Length);
+ //
+ // Use the new length.
+ //
+ NewHiiQuestion->Length = NewLength;
+ Ptr = (UINT8 *) NewHiiQuestion + HiiQuestion1->Length;
+
+ Ptr2 = (UINT8 *) ((VAR_CHECK_HII_QUESTION_ONEOF *) HiiQuestion2 + 1);
+ while ((UINTN) Ptr2 < (UINTN) HiiQuestion2 + HiiQuestion2->Length) {
+ OneValue2 = 0;
+ CopyMem (&OneValue2, Ptr2, HiiQuestion2->StorageWidth);
+
+ Ptr1 = (UINT8 *) ((VAR_CHECK_HII_QUESTION_ONEOF *) HiiQuestion1 + 1);
+ while ((UINTN) Ptr1 < (UINTN) HiiQuestion1 + HiiQuestion1->Length) {
+ OneValue1 = 0;
+ CopyMem (&OneValue1, Ptr1, HiiQuestion1->StorageWidth);
+ if (OneValue2 == OneValue1) {
+ //
+ // Match
+ //
+ break;
+ }
+ Ptr1 += HiiQuestion1->StorageWidth;
+ }
+ if ((UINTN) Ptr1 >= ((UINTN) HiiQuestion1 + HiiQuestion1->Length)) {
+ //
+ // No match
+ //
+ CopyMem (Ptr, &OneValue2, HiiQuestion1->StorageWidth);
+ Ptr += HiiQuestion1->StorageWidth;
+ }
+ Ptr2 += HiiQuestion2->StorageWidth;
+ }
+
+ HiiVariableNode->HiiQuestionArray[HiiQuestion1->VarOffset] = NewHiiQuestion;
+ InternalVarCheckFreePool (HiiQuestion1);
+ }
+ break;
+
+ case EFI_IFR_CHECKBOX_OP:
+ DEBUG ((EFI_D_INFO, "MergeHiiQuestion - EFI_IFR_CHECKBOX_OP VarOffset = 0x%04x\n", HiiQuestion1->VarOffset));
+ break;
+
+ case EFI_IFR_NUMERIC_OP:
+ DEBUG ((EFI_D_INFO, "MergeHiiQuestion - EFI_IFR_NUMERIC_OP VarOffset = 0x%04x\n", HiiQuestion1->VarOffset));
+ //
+ // Get minimum and maximum of Hii Question 1.
+ //
+ Minimum1 = 0;
+ Maximum1 = 0;
+ Ptr = (UINT8 *) ((VAR_CHECK_HII_QUESTION_NUMERIC *) HiiQuestion1 + 1);
+ CopyMem (&Minimum1, Ptr, HiiQuestion1->StorageWidth);
+ Ptr += HiiQuestion1->StorageWidth;
+ CopyMem (&Maximum1, Ptr, HiiQuestion1->StorageWidth);
+
+ //
+ // Get minimum and maximum of Hii Question 2.
+ //
+ Minimum2 = 0;
+ Maximum2 = 0;
+ Ptr = (UINT8 *) ((VAR_CHECK_HII_QUESTION_NUMERIC *) HiiQuestion2 + 1);
+ CopyMem (&Minimum2, Ptr, HiiQuestion2->StorageWidth);
+ Ptr += HiiQuestion2->StorageWidth;
+ CopyMem (&Maximum2, Ptr, HiiQuestion2->StorageWidth);
+
+ //
+ // Update minimum.
+ //
+ Ptr = (UINT8 *) ((VAR_CHECK_HII_QUESTION_NUMERIC *) HiiQuestion1 + 1);
+ if (Minimum2 < Minimum1) {
+ Minimum1 = Minimum2;
+ CopyMem (Ptr, &Minimum1, HiiQuestion1->StorageWidth);
+ }
+ //
+ // Update maximum.
+ //
+ Ptr += HiiQuestion1->StorageWidth;
+ if (Maximum2 > Maximum1) {
+ Maximum1 = Maximum2;
+ CopyMem (Ptr, &Maximum1, HiiQuestion1->StorageWidth);
+ }
+ break;
+
+ case EFI_IFR_ORDERED_LIST_OP:
+ DEBUG ((EFI_D_INFO, "MergeHiiQuestion - EFI_IFR_ORDERED_LIST_OP VarOffset = 0x%04x\n", HiiQuestion1->VarOffset));
+ //
+ // Get the length of Hii Question 1.
+ //
+ NewLength = HiiQuestion1->Length;
+
+ //
+ // Check if the one of options in Hii Question 2 have been in Hii Question 1.
+ //
+ Ptr2 = (UINT8 *) ((VAR_CHECK_HII_QUESTION_ORDEREDLIST *) HiiQuestion2 + 1);
+ while ((UINTN) Ptr2 < (UINTN) HiiQuestion2 + HiiQuestion2->Length) {
+ OneValue2 = 0;
+ CopyMem (&OneValue2, Ptr2, HiiQuestion2->StorageWidth);
+
+ Ptr1 = (UINT8 *) ((VAR_CHECK_HII_QUESTION_ORDEREDLIST *) HiiQuestion1 + 1);
+ while ((UINTN) Ptr1 < (UINTN) HiiQuestion1 + HiiQuestion1->Length) {
+ OneValue1 = 0;
+ CopyMem (&OneValue1, Ptr1, HiiQuestion1->StorageWidth);
+ if (OneValue2 == OneValue1) {
+ //
+ // Match
+ //
+ break;
+ }
+ Ptr1 += HiiQuestion1->StorageWidth;
+ }
+ if ((UINTN) Ptr1 >= ((UINTN) HiiQuestion1 + HiiQuestion1->Length)) {
+ //
+ // No match
+ //
+ NewLength = (UINT8) (NewLength + HiiQuestion1->StorageWidth);
+ }
+ Ptr2 += HiiQuestion2->StorageWidth;
+ }
+
+ if (NewLength > HiiQuestion1->Length) {
+ //
+ // Merge the one of options of Hii Question 2 and Hii Question 1.
+ //
+ NewHiiQuestion = InternalVarCheckAllocateZeroPool (NewLength);
+ ASSERT (NewHiiQuestion != NULL);
+ CopyMem (NewHiiQuestion, HiiQuestion1, HiiQuestion1->Length);
+ //
+ // Use the new length.
+ //
+ NewHiiQuestion->Length = NewLength;
+ Ptr = (UINT8 *) NewHiiQuestion + HiiQuestion1->Length;
+
+ Ptr2 = (UINT8 *) ((VAR_CHECK_HII_QUESTION_ORDEREDLIST *) HiiQuestion2 + 1);
+ while ((UINTN) Ptr2 < (UINTN) HiiQuestion2 + HiiQuestion2->Length) {
+ OneValue2 = 0;
+ CopyMem (&OneValue2, Ptr2, HiiQuestion2->StorageWidth);
+
+ Ptr1 = (UINT8 *) ((VAR_CHECK_HII_QUESTION_ORDEREDLIST *) HiiQuestion1 + 1);
+ while ((UINTN) Ptr1 < (UINTN) HiiQuestion1 + HiiQuestion1->Length) {
+ OneValue1 = 0;
+ CopyMem (&OneValue1, Ptr1, HiiQuestion1->StorageWidth);
+ if (OneValue2 == OneValue1) {
+ //
+ // Match
+ //
+ break;
+ }
+ Ptr1 += HiiQuestion1->StorageWidth;
+ }
+ if ((UINTN) Ptr1 >= ((UINTN) HiiQuestion1 + HiiQuestion1->Length)) {
+ //
+ // No match
+ //
+ CopyMem (Ptr, &OneValue2, HiiQuestion1->StorageWidth);
+ Ptr += HiiQuestion1->StorageWidth;
+ }
+ Ptr2 += HiiQuestion2->StorageWidth;
+ }
+
+ HiiVariableNode->HiiQuestionArray[HiiQuestion1->VarOffset] = NewHiiQuestion;
+ InternalVarCheckFreePool (HiiQuestion1);
+ }
+ break;
+
+ default:
+ ASSERT (FALSE);
+ return;
+ break;
+ }
+
+ //
+ //
+ // Hii Question 2 has been merged with Hii Question 1.
+ //
+ InternalVarCheckFreePool (HiiQuestion2);
+}
+
+/**
+ Get OneOf option data.
+
+ @param[in] IfrOpCodeHeader Pointer to Ifr OpCode header.
+ @param[out] Count Pointer to option count.
+ @param[out] Width Pointer to option width.
+ @param[out] OptionBuffer Pointer to option buffer.
+
+**/
+VOID
+GetOneOfOption (
+ IN EFI_IFR_OP_HEADER *IfrOpCodeHeader,
+ OUT UINTN *Count,
+ OUT UINT8 *Width,
+ OUT VOID *OptionBuffer OPTIONAL
+ )
+{
+ UINTN Scope;
+ EFI_IFR_ONE_OF_OPTION *IfrOneOfOption;
+
+ //
+ // Assume all OPTION has same Width.
+ //
+ *Count = 0;
+
+ if (IfrOpCodeHeader->Scope != 0) {
+ //
+ // Nested OpCode.
+ //
+ Scope = 1;
+ IfrOpCodeHeader = (EFI_IFR_OP_HEADER *) ((UINTN) IfrOpCodeHeader + IfrOpCodeHeader->Length);
+ while (Scope != 0) {
+ switch (IfrOpCodeHeader->OpCode) {
+ case EFI_IFR_ONE_OF_OPTION_OP:
+ IfrOneOfOption = (EFI_IFR_ONE_OF_OPTION *) IfrOpCodeHeader;
+ switch (IfrOneOfOption->Type) {
+ case EFI_IFR_TYPE_NUM_SIZE_8:
+ *Count = *Count + 1;
+ *Width = sizeof (UINT8);
+ if (OptionBuffer != NULL) {
+ CopyMem (OptionBuffer, &IfrOneOfOption->Value.u8, sizeof (UINT8));
+ OptionBuffer = (UINT8 *) OptionBuffer + 1;
+ }
+ break;
+ case EFI_IFR_TYPE_NUM_SIZE_16:
+ *Count = *Count + 1;
+ *Width = sizeof (UINT16);
+ if (OptionBuffer != NULL) {
+ CopyMem (OptionBuffer, &IfrOneOfOption->Value.u16, sizeof (UINT16));
+ OptionBuffer = (UINT16 *) OptionBuffer + 1;
+ }
+ break;
+ case EFI_IFR_TYPE_NUM_SIZE_32:
+ *Count = *Count + 1;
+ *Width = sizeof (UINT32);
+ if (OptionBuffer != NULL) {
+ CopyMem (OptionBuffer, &IfrOneOfOption->Value.u32, sizeof (UINT32));
+ OptionBuffer = (UINT32 *) OptionBuffer + 1;
+ }
+ break;
+ case EFI_IFR_TYPE_NUM_SIZE_64:
+ *Count = *Count + 1;
+ *Width = sizeof (UINT64);
+ if (OptionBuffer != NULL) {
+ CopyMem (OptionBuffer, &IfrOneOfOption->Value.u64, sizeof (UINT64));
+ OptionBuffer = (UINT64 *) OptionBuffer + 1;
+ }
+ break;
+ case EFI_IFR_TYPE_BOOLEAN:
+ *Count = *Count + 1;
+ *Width = sizeof (BOOLEAN);
+ if (OptionBuffer != NULL) {
+ CopyMem (OptionBuffer, &IfrOneOfOption->Value.b, sizeof (BOOLEAN));
+ OptionBuffer = (BOOLEAN *) OptionBuffer + 1;
+ }
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+
+ //
+ // Until End OpCode.
+ //
+ if (IfrOpCodeHeader->OpCode == EFI_IFR_END_OP) {
+ ASSERT (Scope > 0);
+ Scope--;
+ if (Scope == 0) {
+ break;
+ }
+ } else if (IfrOpCodeHeader->Scope != 0) {
+ //
+ // Nested OpCode.
+ //
+ Scope++;
+ }
+ IfrOpCodeHeader = (EFI_IFR_OP_HEADER *) ((UINTN) IfrOpCodeHeader + IfrOpCodeHeader->Length);
+ }
+ }
+
+ return ;
+}
+
+/**
+ Parse Hii Question Oneof.
+
+ @param[in] IfrOpCodeHeader Pointer to Ifr OpCode header.
+
+ return Pointer to Hii Question.
+
+**/
+VAR_CHECK_HII_QUESTION_HEADER *
+ParseHiiQuestionOneOf (
+ IN EFI_IFR_OP_HEADER *IfrOpCodeHeader
+ )
+{
+ EFI_IFR_ONE_OF *IfrOneOf;
+ VAR_CHECK_HII_QUESTION_ONEOF *OneOf;
+ UINTN Length;
+ UINT8 Width;
+ UINTN OptionCount;
+ UINT8 OptionWidth;
+
+ IfrOneOf = (EFI_IFR_ONE_OF *) IfrOpCodeHeader;
+
+ Width = (UINT8) (1 << (IfrOneOf->Flags & EFI_IFR_NUMERIC_SIZE));
+
+ GetOneOfOption (IfrOpCodeHeader, &OptionCount, &OptionWidth, NULL);
+ ASSERT (Width == OptionWidth);
+
+ Length = sizeof (*OneOf) + OptionCount * Width;
+
+ OneOf = InternalVarCheckAllocateZeroPool (Length);
+ ASSERT (OneOf != NULL);
+ OneOf->OpCode = EFI_IFR_ONE_OF_OP;
+ OneOf->Length = (UINT8) Length;
+ OneOf->VarOffset = IfrOneOf->Question.VarStoreInfo.VarOffset;
+ OneOf->StorageWidth = Width;
+
+ GetOneOfOption (IfrOpCodeHeader, &OptionCount, &OptionWidth, OneOf + 1);
+
+ return (VAR_CHECK_HII_QUESTION_HEADER *) OneOf;
+}
+
+/**
+ Parse Hii Question CheckBox.
+
+ @param[in] IfrOpCodeHeader Pointer to Ifr OpCode header.
+
+ return Pointer to Hii Question.
+
+**/
+VAR_CHECK_HII_QUESTION_HEADER *
+ParseHiiQuestionCheckBox (
+ IN EFI_IFR_OP_HEADER *IfrOpCodeHeader
+ )
+{
+ EFI_IFR_CHECKBOX *IfrCheckBox;
+ VAR_CHECK_HII_QUESTION_CHECKBOX *CheckBox;
+
+ IfrCheckBox = (EFI_IFR_CHECKBOX *) IfrOpCodeHeader;
+
+ CheckBox = InternalVarCheckAllocateZeroPool (sizeof (*CheckBox));
+ ASSERT (CheckBox != NULL);
+ CheckBox->OpCode = EFI_IFR_CHECKBOX_OP;
+ CheckBox->Length = (UINT8) sizeof (*CheckBox);;
+ CheckBox->VarOffset = IfrCheckBox->Question.VarStoreInfo.VarOffset;
+ CheckBox->StorageWidth = (UINT8) sizeof (BOOLEAN);
+
+ return (VAR_CHECK_HII_QUESTION_HEADER *) CheckBox;
+}
+
+/**
+ Parse Hii Question Numeric.
+
+ @param[in] IfrOpCodeHeader Pointer to Ifr OpCode header.
+
+ return Pointer to Hii Question.
+
+**/
+VAR_CHECK_HII_QUESTION_HEADER *
+ParseHiiQuestionNumeric (
+ IN EFI_IFR_OP_HEADER *IfrOpCodeHeader
+ )
+{
+ EFI_IFR_NUMERIC *IfrNumeric;
+ VAR_CHECK_HII_QUESTION_NUMERIC *Numeric;
+ UINT8 Width;
+
+ IfrNumeric = (EFI_IFR_NUMERIC *) IfrOpCodeHeader;
+
+ Numeric = InternalVarCheckAllocateZeroPool (sizeof (VAR_CHECK_HII_QUESTION_NUMERIC) + 2 * sizeof (UINT64));
+ ASSERT (Numeric != NULL);
+
+ Width = (UINT8) (1 << (IfrNumeric->Flags & EFI_IFR_NUMERIC_SIZE));
+
+ Numeric->OpCode = EFI_IFR_NUMERIC_OP;
+ Numeric->Length = (UINT8) (sizeof (VAR_CHECK_HII_QUESTION_NUMERIC) + 2 * Width);
+ Numeric->VarOffset = IfrNumeric->Question.VarStoreInfo.VarOffset;
+ Numeric->StorageWidth = Width;
+
+ CopyMem (Numeric + 1, &IfrNumeric->data, Width * 2);
+
+ return (VAR_CHECK_HII_QUESTION_HEADER *) Numeric;
+}
+
+/**
+ Parse Hii Question OrderedList.
+
+ @param[in] IfrOpCodeHeader Pointer to Ifr OpCode header.
+
+ return Pointer to Hii Question.
+
+**/
+VAR_CHECK_HII_QUESTION_HEADER *
+ParseHiiQuestionOrderedList (
+ IN EFI_IFR_OP_HEADER *IfrOpCodeHeader
+ )
+{
+ EFI_IFR_ORDERED_LIST *IfrOrderedList;
+ VAR_CHECK_HII_QUESTION_ORDEREDLIST *OrderedList;
+ UINTN Length;
+ UINTN OptionCount;
+ UINT8 OptionWidth;
+
+ IfrOrderedList = (EFI_IFR_ORDERED_LIST *) IfrOpCodeHeader;
+
+ GetOneOfOption (IfrOpCodeHeader, &OptionCount, &OptionWidth, NULL);
+
+ Length = sizeof (*OrderedList) + OptionCount * OptionWidth;
+
+ OrderedList = InternalVarCheckAllocateZeroPool (Length);
+ ASSERT (OrderedList != NULL);
+ OrderedList->OpCode = EFI_IFR_ORDERED_LIST_OP;
+ OrderedList->Length = (UINT8) Length;
+ OrderedList->VarOffset = IfrOrderedList->Question.VarStoreInfo.VarOffset;
+ OrderedList->StorageWidth = OptionWidth;
+ OrderedList->MaxContainers = IfrOrderedList->MaxContainers;
+
+ GetOneOfOption (IfrOpCodeHeader, &OptionCount, &OptionWidth, OrderedList + 1);
+
+ return (VAR_CHECK_HII_QUESTION_HEADER *) OrderedList;
+}
+
+/**
+ Parse and create Hii Question node.
+
+ @param[in] HiiVariableNode Pointer to Hii Variable node.
+ @param[in] IfrOpCodeHeader Pointer to Ifr OpCode header.
+ @param[in] FromFv Hii Question from FV.
+
+**/
+VOID
+ParseHiiQuestion (
+ IN VAR_CHECK_HII_VARIABLE_NODE *HiiVariableNode,
+ IN EFI_IFR_OP_HEADER *IfrOpCodeHeader,
+ IN BOOLEAN FromFv
+ )
+{
+ VAR_CHECK_HII_QUESTION_HEADER *HiiQuestion;
+
+ switch (IfrOpCodeHeader->OpCode) {
+ case EFI_IFR_ONE_OF_OP:
+ HiiQuestion = ParseHiiQuestionOneOf (IfrOpCodeHeader);
+ break;
+
+ case EFI_IFR_CHECKBOX_OP:
+ HiiQuestion = ParseHiiQuestionCheckBox (IfrOpCodeHeader);
+ break;
+
+ case EFI_IFR_NUMERIC_OP:
+ HiiQuestion = ParseHiiQuestionNumeric (IfrOpCodeHeader);
+ break;
+
+ case EFI_IFR_ORDERED_LIST_OP:
+ HiiQuestion = ParseHiiQuestionOrderedList (IfrOpCodeHeader);
+ break;
+
+ default:
+ ASSERT (FALSE);
+ return;
+ break;
+ }
+
+ if (HiiVariableNode->HiiQuestionArray[HiiQuestion->VarOffset] != NULL) {
+ MergeHiiQuestion (HiiVariableNode, HiiQuestion, FromFv);
+ } else {
+ HiiVariableNode->HiiQuestionArray[HiiQuestion->VarOffset] = HiiQuestion;
+ }
+}
+
+/**
+ Find Hii variable node by name and GUID.
+
+ @param[in] Name Pointer to variable name.
+ @param[in] Guid Pointer to vendor GUID.
+
+ @return Pointer to Hii Variable node.
+
+**/
+VAR_CHECK_HII_VARIABLE_NODE *
+FindHiiVariableNode (
+ IN CHAR16 *Name,
+ IN EFI_GUID *Guid
+ )
+{
+ VAR_CHECK_HII_VARIABLE_NODE *HiiVariableNode;
+ LIST_ENTRY *Link;
+
+ for (Link = mVarCheckHiiList.ForwardLink
+ ;Link != &mVarCheckHiiList
+ ;Link = Link->ForwardLink) {
+ HiiVariableNode = VAR_CHECK_HII_VARIABLE_FROM_LINK (Link);
+
+ if ((StrCmp (Name, (CHAR16 *) (HiiVariableNode->HiiVariable + 1)) == 0) &&
+ CompareGuid (Guid, &HiiVariableNode->HiiVariable->Guid)) {
+ return HiiVariableNode;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ Find Hii variable node by var store id.
+
+ @param[in] VarStoreId Var store id.
+
+ @return Pointer to Hii Variable node.
+
+**/
+VAR_CHECK_HII_VARIABLE_NODE *
+FindHiiVariableNodeByVarStoreId (
+ IN EFI_VARSTORE_ID VarStoreId
+ )
+{
+ VAR_CHECK_HII_VARIABLE_NODE *HiiVariableNode;
+ LIST_ENTRY *Link;
+
+ if (VarStoreId == 0) {
+ //
+ // The variable store identifier, which is unique within the current form set.
+ // A value of zero is invalid.
+ //
+ return NULL;
+ }
+
+ for (Link = mVarCheckHiiList.ForwardLink
+ ;Link != &mVarCheckHiiList
+ ;Link = Link->ForwardLink) {
+ HiiVariableNode = VAR_CHECK_HII_VARIABLE_FROM_LINK (Link);
+ //
+ // The variable store identifier, which is unique within the current form set.
+ //
+ if (VarStoreId == HiiVariableNode->VarStoreId) {
+ return HiiVariableNode;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ Destroy var store id in the Hii Variable node after parsing one Hii Package.
+
+**/
+VOID
+DestroyVarStoreId (
+ VOID
+ )
+{
+ VAR_CHECK_HII_VARIABLE_NODE *HiiVariableNode;
+ LIST_ENTRY *Link;
+
+ for (Link = mVarCheckHiiList.ForwardLink
+ ;Link != &mVarCheckHiiList
+ ;Link = Link->ForwardLink) {
+ HiiVariableNode = VAR_CHECK_HII_VARIABLE_FROM_LINK (Link);
+ //
+ // The variable store identifier, which is unique within the current form set.
+ // A value of zero is invalid.
+ //
+ HiiVariableNode->VarStoreId = 0;
+ }
+}
+
+/**
+ Create Hii Variable node.
+
+ @param[in] IfrEfiVarStore Pointer to EFI VARSTORE.
+
+**/
+VOID
+CreateHiiVariableNode (
+ IN EFI_IFR_VARSTORE_EFI *IfrEfiVarStore
+ )
+{
+ VAR_CHECK_HII_VARIABLE_NODE *HiiVariableNode;
+ VAR_CHECK_HII_VARIABLE_HEADER *HiiVariable;
+ UINTN HeaderLength;
+ CHAR16 *VarName;
+ UINTN VarNameSize;
+
+ //
+ // Get variable name.
+ //
+ VarNameSize = AsciiStrSize ((CHAR8 *) IfrEfiVarStore->Name) * sizeof (CHAR16);
+ if (VarNameSize > mMaxVarNameSize) {
+ mVarName = InternalVarCheckReallocatePool (mMaxVarNameSize, VarNameSize, mVarName);
+ ASSERT (mVarName != NULL);
+ mMaxVarNameSize = VarNameSize;
+ }
+ AsciiStrToUnicodeStrS ((CHAR8 *) IfrEfiVarStore->Name, mVarName, mMaxVarNameSize / sizeof (CHAR16));
+ VarName = mVarName;
+
+ HiiVariableNode = FindHiiVariableNode (
+ VarName,
+ &IfrEfiVarStore->Guid
+ );
+ if (HiiVariableNode == NULL) {
+ //
+ // Not found, then create new.
+ //
+ HeaderLength = sizeof (*HiiVariable) + VarNameSize;
+ HiiVariable = InternalVarCheckAllocateZeroPool (HeaderLength);
+ ASSERT (HiiVariable != NULL);
+ HiiVariable->Revision = VAR_CHECK_HII_REVISION;
+ HiiVariable->OpCode = EFI_IFR_VARSTORE_EFI_OP;
+ HiiVariable->HeaderLength = (UINT16) HeaderLength;
+ HiiVariable->Size = IfrEfiVarStore->Size;
+ HiiVariable->Attributes = IfrEfiVarStore->Attributes;
+ CopyGuid (&HiiVariable->Guid, &IfrEfiVarStore->Guid);
+ StrCpyS ((CHAR16 *) (HiiVariable + 1), VarNameSize / sizeof (CHAR16), VarName);
+
+ HiiVariableNode = InternalVarCheckAllocateZeroPool (sizeof (*HiiVariableNode));
+ ASSERT (HiiVariableNode != NULL);
+ HiiVariableNode->Signature = VAR_CHECK_HII_VARIABLE_NODE_SIGNATURE;
+ HiiVariableNode->HiiVariable = HiiVariable;
+ //
+ // The variable store identifier, which is unique within the current form set.
+ //
+ HiiVariableNode->VarStoreId = IfrEfiVarStore->VarStoreId;
+ HiiVariableNode->HiiQuestionArray = InternalVarCheckAllocateZeroPool (IfrEfiVarStore->Size * sizeof (VAR_CHECK_HII_QUESTION_HEADER *));
+
+ InsertTailList (&mVarCheckHiiList, &HiiVariableNode->Link);
+ } else {
+ HiiVariableNode->VarStoreId = IfrEfiVarStore->VarStoreId;
+ }
+}
+
+/**
+ Parse and create Hii Variable node list.
+
+ @param[in] HiiPackage Pointer to Hii Package.
+
+**/
+VOID
+ParseHiiVariable (
+ IN VOID *HiiPackage
+ )
+{
+ EFI_HII_PACKAGE_HEADER *HiiPackageHeader;
+ EFI_IFR_OP_HEADER *IfrOpCodeHeader;
+ EFI_IFR_VARSTORE_EFI *IfrEfiVarStore;
+
+ HiiPackageHeader = (EFI_HII_PACKAGE_HEADER *) HiiPackage;
+
+ switch (HiiPackageHeader->Type) {
+ case EFI_HII_PACKAGE_FORMS:
+ IfrOpCodeHeader = (EFI_IFR_OP_HEADER *) (HiiPackageHeader + 1);
+
+ while ((UINTN) IfrOpCodeHeader < (UINTN) HiiPackageHeader + HiiPackageHeader->Length) {
+ switch (IfrOpCodeHeader->OpCode) {
+ case EFI_IFR_VARSTORE_EFI_OP:
+ //
+ // Come to EFI VARSTORE in Form Package.
+ //
+ IfrEfiVarStore = (EFI_IFR_VARSTORE_EFI *) IfrOpCodeHeader;
+ if ((IfrEfiVarStore->Header.Length >= sizeof (EFI_IFR_VARSTORE_EFI)) &&
+ ((IfrEfiVarStore->Attributes & EFI_VARIABLE_NON_VOLATILE) != 0)) {
+ //
+ // Only create node list for Hii Variable with NV attribute.
+ //
+ CreateHiiVariableNode (IfrEfiVarStore);
+ }
+ break;
+
+ default:
+ break;
+ }
+ IfrOpCodeHeader = (EFI_IFR_OP_HEADER *) ((UINTN) IfrOpCodeHeader + IfrOpCodeHeader->Length);
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+/**
+ Var Check Parse Hii Package.
+
+ @param[in] HiiPackage Pointer to Hii Package.
+ @param[in] FromFv Hii Package from FV.
+
+**/
+VOID
+VarCheckParseHiiPackage (
+ IN VOID *HiiPackage,
+ IN BOOLEAN FromFv
+ )
+{
+ EFI_HII_PACKAGE_HEADER *HiiPackageHeader;
+ EFI_IFR_OP_HEADER *IfrOpCodeHeader;
+ VAR_CHECK_HII_VARIABLE_NODE *HiiVariableNode;
+
+ //
+ // Parse and create Hii Variable node list for this Hii Package.
+ //
+ ParseHiiVariable (HiiPackage);
+
+ HiiPackageHeader = (EFI_HII_PACKAGE_HEADER *) HiiPackage;
+
+ switch (HiiPackageHeader->Type) {
+ case EFI_HII_PACKAGE_FORMS:
+ IfrOpCodeHeader = (EFI_IFR_OP_HEADER *) (HiiPackageHeader + 1);
+
+ while ((UINTN) IfrOpCodeHeader < (UINTN) HiiPackageHeader + HiiPackageHeader->Length) {
+ switch (IfrOpCodeHeader->OpCode) {
+ case EFI_IFR_ONE_OF_OP:
+ case EFI_IFR_CHECKBOX_OP:
+ case EFI_IFR_NUMERIC_OP:
+ case EFI_IFR_ORDERED_LIST_OP:
+ HiiVariableNode = FindHiiVariableNodeByVarStoreId (((EFI_IFR_ONE_OF *) IfrOpCodeHeader)->Question.VarStoreId);
+ if ((HiiVariableNode == NULL) ||
+ //
+ // No related Hii Variable node found.
+ //
+ ((((EFI_IFR_ONE_OF *) IfrOpCodeHeader)->Question.Header.Prompt == 0) && (((EFI_IFR_ONE_OF *) IfrOpCodeHeader)->Question.Header.Help == 0))) {
+ //
+ // meanless IFR item introduced by ECP.
+ //
+ } else {
+ //
+ // Normal IFR
+ //
+ ParseHiiQuestion (HiiVariableNode, IfrOpCodeHeader, FromFv);
+ }
+ default:
+ break;
+ }
+ IfrOpCodeHeader = (EFI_IFR_OP_HEADER *) ((UINTN) IfrOpCodeHeader + IfrOpCodeHeader->Length);
+ }
+ break;
+
+ default:
+ break;
+ }
+ DestroyVarStoreId ();
+}
+
+/**
+ Var Check Parse Hii Database.
+
+ @param[in] HiiDatabase Pointer to Hii Database.
+ @param[in] HiiDatabaseSize Hii Database size.
+
+**/
+VOID
+VarCheckParseHiiDatabase (
+ IN VOID *HiiDatabase,
+ IN UINTN HiiDatabaseSize
+ )
+{
+ EFI_HII_PACKAGE_LIST_HEADER *HiiPackageListHeader;
+ EFI_HII_PACKAGE_HEADER *HiiPackageHeader;
+
+ HiiPackageListHeader = (EFI_HII_PACKAGE_LIST_HEADER *) HiiDatabase;
+
+ while ((UINTN) HiiPackageListHeader < ((UINTN) HiiDatabase + HiiDatabaseSize)) {
+ HiiPackageHeader = (EFI_HII_PACKAGE_HEADER *) (HiiPackageListHeader + 1);
+
+ while ((UINTN) HiiPackageHeader < ((UINTN) HiiPackageListHeader + HiiPackageListHeader->PackageLength)) {
+ //
+ // Parse Hii Pacakge.
+ //
+ VarCheckParseHiiPackage (HiiPackageHeader, FALSE);
+
+ HiiPackageHeader = (EFI_HII_PACKAGE_HEADER *) ((UINTN) HiiPackageHeader + HiiPackageHeader->Length);
+ }
+
+ HiiPackageListHeader = (EFI_HII_PACKAGE_LIST_HEADER *) ((UINTN) HiiPackageListHeader + HiiPackageListHeader->PackageLength);
+ }
+}
+
+/**
+ Destroy Hii Variable node.
+
+**/
+VOID
+DestroyHiiVariableNode (
+ VOID
+ )
+{
+ VAR_CHECK_HII_VARIABLE_NODE *HiiVariableNode;
+ LIST_ENTRY *HiiVariableLink;
+ UINTN Index;
+
+ while (mVarCheckHiiList.ForwardLink != &mVarCheckHiiList) {
+ HiiVariableLink = mVarCheckHiiList.ForwardLink;
+ HiiVariableNode = VAR_CHECK_HII_VARIABLE_FROM_LINK (HiiVariableLink);
+
+ RemoveEntryList (&HiiVariableNode->Link);
+
+ //
+ // Free the allocated buffer.
+ //
+ for (Index = 0; Index < HiiVariableNode->HiiVariable->Size; Index++) {
+ if (HiiVariableNode->HiiQuestionArray[Index] != NULL) {
+ InternalVarCheckFreePool (HiiVariableNode->HiiQuestionArray[Index]);
+ }
+ }
+ InternalVarCheckFreePool (HiiVariableNode->HiiQuestionArray);
+ InternalVarCheckFreePool (HiiVariableNode->HiiVariable);
+ InternalVarCheckFreePool (HiiVariableNode);
+ }
+}
+
+/**
+ Build VarCheckHiiBin.
+
+ @param[out] Size Pointer to VarCheckHii size.
+
+ @return Pointer to VarCheckHiiBin.
+
+**/
+VOID *
+BuildVarCheckHiiBin (
+ OUT UINTN *Size
+ )
+{
+ VAR_CHECK_HII_VARIABLE_NODE *HiiVariableNode;
+ LIST_ENTRY *HiiVariableLink;
+ UINTN Index;
+ VOID *Data;
+ UINT8 *Ptr;
+ UINT32 BinSize;
+ UINT32 HiiVariableLength;
+
+ //
+ // Get Size
+ //
+ BinSize = 0;
+
+ for (HiiVariableLink = mVarCheckHiiList.ForwardLink
+ ;HiiVariableLink != &mVarCheckHiiList
+ ;HiiVariableLink = HiiVariableLink->ForwardLink) {
+ //
+ // For Hii Variable header align.
+ //
+ BinSize = (UINT32) HEADER_ALIGN (BinSize);
+
+ HiiVariableNode = VAR_CHECK_HII_VARIABLE_FROM_LINK (HiiVariableLink);
+ HiiVariableLength = HiiVariableNode->HiiVariable->HeaderLength;
+
+ for (Index = 0; Index < HiiVariableNode->HiiVariable->Size; Index++) {
+ if (HiiVariableNode->HiiQuestionArray[Index] != NULL) {
+ //
+ // For Hii Question header align.
+ //
+ HiiVariableLength = (UINT32) HEADER_ALIGN (HiiVariableLength);
+ HiiVariableLength += HiiVariableNode->HiiQuestionArray[Index]->Length;
+ }
+ }
+
+ HiiVariableNode->HiiVariable->Length = HiiVariableLength;
+ BinSize += HiiVariableLength;
+ }
+
+ DEBUG ((EFI_D_INFO, "VarCheckHiiBin - size = 0x%x\n", BinSize));
+ if (BinSize == 0) {
+ *Size = BinSize;
+ return NULL;
+ }
+
+ //
+ // AllocatePages () and AllocatePool () from gBS are used for the process of VarCheckHiiBin generation.
+ // Only here AllocateRuntimeZeroPool () from MemoryAllocateLib is used for runtime access
+ // in SetVariable check handler.
+ //
+ Data = AllocateRuntimeZeroPool (BinSize);
+ ASSERT (Data != NULL);
+ DEBUG ((EFI_D_INFO, "VarCheckHiiBin - built at 0x%x\n", Data));
+
+ //
+ // Gen Data
+ //
+ Ptr = Data;
+ for (HiiVariableLink = mVarCheckHiiList.ForwardLink
+ ;HiiVariableLink != &mVarCheckHiiList
+ ;HiiVariableLink = HiiVariableLink->ForwardLink) {
+ //
+ // For Hii Variable header align.
+ //
+ Ptr = (UINT8 *) HEADER_ALIGN (Ptr);
+
+ HiiVariableNode = VAR_CHECK_HII_VARIABLE_FROM_LINK (HiiVariableLink);
+ CopyMem (Ptr, HiiVariableNode->HiiVariable, HiiVariableNode->HiiVariable->HeaderLength);
+ Ptr += HiiVariableNode->HiiVariable->HeaderLength;
+
+ for (Index = 0; Index < HiiVariableNode->HiiVariable->Size; Index++) {
+ if (HiiVariableNode->HiiQuestionArray[Index] != NULL) {
+ //
+ // For Hii Question header align.
+ //
+ Ptr = (UINT8 *) HEADER_ALIGN (Ptr);
+ CopyMem (Ptr, HiiVariableNode->HiiQuestionArray[Index], HiiVariableNode->HiiQuestionArray[Index]->Length);
+ Ptr += HiiVariableNode->HiiQuestionArray[Index]->Length;
+ }
+ }
+ }
+
+ *Size = BinSize;
+ return Data;
+}
+
+/**
+ Generate VarCheckHiiBin from Hii Database and FV.
+
+**/
+VOID
+EFIAPI
+VarCheckHiiGen (
+ VOID
+ )
+{
+ VarCheckHiiGenFromHiiDatabase ();
+ VarCheckHiiGenFromFv ();
+
+ mVarCheckHiiBin = BuildVarCheckHiiBin (&mVarCheckHiiBinSize);
+ if (mVarCheckHiiBin == NULL) {
+ DEBUG ((EFI_D_INFO, "[VarCheckHii] This driver could be removed from *.dsc and *.fdf\n"));
+ return;
+ }
+
+ DestroyHiiVariableNode ();
+ if (mVarName != NULL) {
+ InternalVarCheckFreePool (mVarName);
+ }
+
+#ifdef DUMP_VAR_CHECK_HII
+ DEBUG_CODE (
+ DumpVarCheckHii (mVarCheckHiiBin, mVarCheckHiiBinSize);
+ );
+#endif
+}
+
diff --git a/Core/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiGen.h b/Core/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiGen.h
new file mode 100644
index 0000000000..f81be2ea88
--- /dev/null
+++ b/Core/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiGen.h
@@ -0,0 +1,136 @@
+/** @file
+ Include file for Var Check Hii bin generation.
+
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _VAR_CHECK_HII_GEN_H_
+#define _VAR_CHECK_HII_GEN_H_
+
+#include "VarCheckHii.h"
+
+/**
+ Dump Hii Package.
+
+ @param[in] HiiPackage Pointer to Hii Package.
+
+**/
+VOID
+DumpHiiPackage (
+ IN VOID *HiiPackage
+ );
+
+/**
+ Dump Hii Database.
+
+ @param[in] HiiDatabase Pointer to Hii Database.
+ @param[in] HiiDatabaseSize Hii Database size.
+
+**/
+VOID
+DumpHiiDatabase (
+ IN VOID *HiiDatabase,
+ IN UINTN HiiDatabaseSize
+ );
+
+/**
+ Allocates and zeros a buffer of type EfiBootServicesData.
+
+ Allocates the number bytes specified by AllocationSize of type EfiBootServicesData, clears the
+ buffer with zeros, and returns a pointer to the allocated buffer. If AllocationSize is 0, then a
+ valid buffer of 0 size is returned. If there is not enough memory remaining to satisfy the
+ request, then NULL is returned.
+
+ @param AllocationSize The number of bytes to allocate and zero.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+InternalVarCheckAllocateZeroPool (
+ IN UINTN AllocationSize
+ );
+
+/**
+ Frees a buffer that was previously allocated with one of the pool allocation functions in the
+ Memory Allocation Library.
+
+ Frees the buffer specified by Buffer. Buffer must have been allocated on a previous call to the
+ pool allocation services of the Memory Allocation Library. If it is not possible to free pool
+ resources, then this function will perform no actions.
+
+ If Buffer was not allocated with a pool allocation function in the Memory Allocation Library,
+ then ASSERT().
+
+ @param Buffer The pointer to the buffer to free.
+
+**/
+VOID
+EFIAPI
+InternalVarCheckFreePool (
+ IN VOID *Buffer
+ );
+
+/**
+ Var Check Parse Hii Package.
+
+ @param[in] HiiPackage Pointer to Hii Package.
+ @param[in] FromFv Hii Package from FV.
+
+**/
+VOID
+VarCheckParseHiiPackage (
+ IN VOID *HiiPackage,
+ IN BOOLEAN FromFv
+ );
+
+/**
+ Var Check Parse Hii Database.
+
+ @param[in] HiiDatabase Pointer to Hii Database.
+ @param[in] HiiDatabaseSize Hii Database size.
+
+**/
+VOID
+VarCheckParseHiiDatabase (
+ IN VOID *HiiDatabase,
+ IN UINTN HiiDatabaseSize
+ );
+
+/**
+ Generate from FV.
+
+**/
+VOID
+VarCheckHiiGenFromFv (
+ VOID
+ );
+
+/**
+ Generate from Hii Database.
+
+**/
+VOID
+VarCheckHiiGenFromHiiDatabase (
+ VOID
+ );
+
+/**
+ Generate VarCheckHiiBin from Hii Database and FV.
+
+**/
+VOID
+EFIAPI
+VarCheckHiiGen (
+ VOID
+ );
+
+#endif
diff --git a/Core/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiGenFromFv.c b/Core/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiGenFromFv.c
new file mode 100644
index 0000000000..21fc80e89c
--- /dev/null
+++ b/Core/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiGenFromFv.c
@@ -0,0 +1,443 @@
+/** @file
+ Var Check Hii generation from FV.
+
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "VarCheckHiiGen.h"
+
+// {d0bc7cb4-6a47-495f-aa11-710746da06a2}
+#define EFI_VFR_ATTRACT_GUID \
+{ 0xd0bc7cb4, 0x6a47, 0x495f, { 0xaa, 0x11, 0x71, 0x7, 0x46, 0xda, 0x6, 0xa2 } }
+
+EFI_GUID gVfrArrayAttractGuid = EFI_VFR_ATTRACT_GUID;
+
+#define ALL_FF_GUID \
+{ 0xFFFFFFFF, 0xFFFF, 0xFFFF, { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } }
+
+EFI_GUID mAllFfGuid = ALL_FF_GUID;
+
+#define VAR_CHECK_VFR_DRIVER_INFO_SIGNATURE SIGNATURE_32 ('V', 'D', 'R', 'I')
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link;
+ EFI_GUID *DriverGuid;
+} VAR_CHECK_VFR_DRIVER_INFO;
+
+LIST_ENTRY mVfrDriverList = INITIALIZE_LIST_HEAD_VARIABLE (mVfrDriverList);
+
+#define VAR_CHECK_VFR_DRIVER_INFO_FROM_LINK(a) CR (a, VAR_CHECK_VFR_DRIVER_INFO, Link, VAR_CHECK_VFR_DRIVER_INFO_SIGNATURE)
+
+#define MAX_MATCH_GUID_NUM 100
+
+/**
+ Get the address by Guid.
+
+ Parse the FFS and find the GUID address.
+ There may be multiple Guids matching the searched Guid.
+
+ @param Ffs Pointer to the FFS.
+ @param Guid Guid to find.
+ @param Length The length of FFS.
+ @param Offset Pointer to pointer to the offset.
+ @param NumOfMatchingGuid The number of matching Guid.
+
+ @retval EFI_SUCCESS One or multiple Guids matching the searched Guid.
+ @retval EFI_NOT_FOUND No Guid matching the searched Guid.
+
+**/
+EFI_STATUS
+GetAddressByGuid (
+ IN VOID *Ffs,
+ IN EFI_GUID *Guid,
+ IN UINTN Length,
+ OUT UINTN **Offset,
+ OUT UINT8 *NumOfMatchingGuid
+ )
+{
+ UINTN LoopControl;
+ BOOLEAN Found;
+
+ if((Ffs == NULL) || (Guid == NULL) || (Length == 0)){
+ return EFI_NOT_FOUND;
+ }
+
+ if (NumOfMatchingGuid != NULL) {
+ *NumOfMatchingGuid = 0;
+ }
+
+ Found = FALSE;
+ for (LoopControl = 0; LoopControl < Length; LoopControl++) {
+ if (CompareGuid (Guid, (EFI_GUID *) ((UINT8 *) Ffs + LoopControl))) {
+ Found = TRUE;
+ //
+ // If NumOfMatchGuid or Offset are NULL, means user only want
+ // to check whether current FFS includes this Guid or not.
+ //
+ if ((NumOfMatchingGuid != NULL) && (Offset != NULL)) {
+ if (*NumOfMatchingGuid == 0) {
+ *Offset = InternalVarCheckAllocateZeroPool (sizeof (UINTN) * MAX_MATCH_GUID_NUM);
+ ASSERT (*Offset != NULL);
+ }
+ *(*Offset + *NumOfMatchingGuid) = LoopControl + sizeof (EFI_GUID);
+ (*NumOfMatchingGuid)++;
+ } else {
+ break;
+ }
+ }
+ }
+
+ return (Found ? EFI_SUCCESS : EFI_NOT_FOUND);
+}
+
+/**
+ Search the VfrBin Base address.
+
+ According to the known GUID gVfrArrayAttractGuid to get the base address from FFS.
+
+ @param Ffs Pointer to the FFS.
+ @param EfiAddr Pointer to the EFI in FFS
+ @param Length The length of FFS.
+ @param Offset Pointer to pointer to the Addr (Offset).
+ @param NumOfMatchingOffset The number of Addr (Offset).
+
+ @retval EFI_SUCCESS Get the address successfully.
+ @retval EFI_NOT_FOUND No VfrBin found.
+
+**/
+EFI_STATUS
+SearchVfrBinInFfs (
+ IN VOID *Ffs,
+ IN VOID *EfiAddr,
+ IN UINTN Length,
+ OUT UINTN **Offset,
+ OUT UINT8 *NumOfMatchingOffset
+ )
+{
+ UINTN Index;
+ EFI_STATUS Status;
+ UINTN VirOffValue;
+
+ if ((Ffs == NULL) || (Offset == NULL)) {
+ return EFI_NOT_FOUND;
+ }
+ Status = GetAddressByGuid (
+ Ffs,
+ &gVfrArrayAttractGuid,
+ Length,
+ Offset,
+ NumOfMatchingOffset
+ );
+ if (Status != EFI_SUCCESS) {
+ return Status;
+ }
+
+ for (Index = 0; Index < *NumOfMatchingOffset; Index++) {
+ //
+ // Got the virOffset after the GUID
+ //
+ VirOffValue = *(UINTN *) ((UINTN) Ffs + *(*Offset + Index));
+ //
+ // Transfer the offset to the VA address. One modules may own multiple VfrBin address.
+ //
+ *(*Offset + Index) = (UINTN) EfiAddr + VirOffValue;
+ }
+
+ return Status;
+}
+
+/**
+ Parse FFS.
+
+ @param[in] Fv2 Pointer to Fv2 protocol.
+ @param[in] DriverGuid Pointer to driver GUID.
+
+ @return Found the driver in the FV or not.
+
+**/
+BOOLEAN
+ParseFfs (
+ IN EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv2,
+ IN EFI_GUID *DriverGuid
+ )
+{
+ EFI_STATUS Status;
+ EFI_FV_FILETYPE FoundType;
+ EFI_FV_FILE_ATTRIBUTES FileAttributes;
+ UINT32 AuthenticationStatus;
+ UINTN Size;
+ VOID *Buffer;
+ UINTN SectionSize;
+ VOID *SectionBuffer;
+ UINTN VfrBinIndex;
+ UINT8 NumberofMatchingVfrBin;
+ UINTN *VfrBinBaseAddress;
+
+ Status = Fv2->ReadFile (
+ Fv2,
+ DriverGuid,
+ NULL,
+ &Size,
+ &FoundType,
+ &FileAttributes,
+ &AuthenticationStatus
+ );
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ Buffer = NULL;
+ Status = Fv2->ReadSection (
+ Fv2,
+ DriverGuid,
+ EFI_SECTION_RAW,
+ 0, // Instance
+ &Buffer,
+ &Size,
+ &AuthenticationStatus
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = SearchVfrBinInFfs (Buffer, 0, Size, &VfrBinBaseAddress, &NumberofMatchingVfrBin);
+ if (!EFI_ERROR (Status)) {
+ SectionBuffer = NULL;
+ Status = Fv2->ReadSection (
+ Fv2,
+ DriverGuid,
+ EFI_SECTION_PE32,
+ 0, // Instance
+ &SectionBuffer,
+ &SectionSize,
+ &AuthenticationStatus
+ );
+ if (!EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_INFO, "FfsNameGuid - %g\n", DriverGuid));
+ DEBUG ((EFI_D_INFO, "NumberofMatchingVfrBin - 0x%02x\n", NumberofMatchingVfrBin));
+
+ for (VfrBinIndex = 0; VfrBinIndex < NumberofMatchingVfrBin; VfrBinIndex++) {
+#ifdef DUMP_HII_DATA
+ DEBUG_CODE (
+ DumpHiiPackage ((UINT8 *) (UINTN) SectionBuffer + VfrBinBaseAddress[VfrBinIndex] + sizeof (UINT32));
+ );
+#endif
+ VarCheckParseHiiPackage ((UINT8 *) (UINTN) SectionBuffer + VfrBinBaseAddress[VfrBinIndex] + sizeof (UINT32), TRUE);
+ }
+
+ FreePool (SectionBuffer);
+ }
+
+ InternalVarCheckFreePool (VfrBinBaseAddress);
+ }
+
+ FreePool (Buffer);
+ }
+
+ return TRUE;
+}
+
+/**
+ Parse FVs.
+
+ @param[in] ScanAll Scan all modules in all FVs or not.
+
+**/
+VOID
+ParseFv (
+ IN BOOLEAN ScanAll
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE *HandleBuffer;
+ UINTN HandleCount;
+ UINTN Index;
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv2;
+ VOID *Key;
+ EFI_FV_FILETYPE FileType;
+ EFI_GUID NameGuid;
+ EFI_FV_FILE_ATTRIBUTES FileAttributes;
+ UINTN Size;
+ UINTN FfsIndex;
+ VAR_CHECK_VFR_DRIVER_INFO *VfrDriverInfo;
+ LIST_ENTRY *VfrDriverLink;
+
+ HandleBuffer = NULL;
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiFirmwareVolume2ProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ //
+ // Search all FVs
+ //
+ for (Index = 0; Index < HandleCount; Index++) {
+ DEBUG ((EFI_D_INFO, "FvIndex - %x\n", Index));
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiFirmwareVolume2ProtocolGuid,
+ (VOID **) &Fv2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ DEBUG_CODE (
+ EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *Fvb2;
+ EFI_PHYSICAL_ADDRESS FvAddress;
+ UINT64 FvSize;
+
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiFirmwareVolumeBlock2ProtocolGuid,
+ (VOID **) &Fvb2
+ );
+ ASSERT_EFI_ERROR (Status);
+ Status = Fvb2->GetPhysicalAddress (Fvb2, &FvAddress);
+ if (!EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_INFO, "FvAddress - 0x%08x\n", FvAddress));
+ FvSize = ((EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) FvAddress)->FvLength;
+ DEBUG ((EFI_D_INFO, "FvSize - 0x%08x\n", FvSize));
+ }
+ );
+
+ if (ScanAll) {
+ //
+ // Need to parse all modules in all FVs.
+ //
+ Key = InternalVarCheckAllocateZeroPool (Fv2->KeySize);
+ ASSERT (Key != NULL);
+
+ for (FfsIndex = 0; ; FfsIndex++) {
+ FileType = EFI_FV_FILETYPE_ALL;
+ Status = Fv2->GetNextFile (
+ Fv2,
+ Key,
+ &FileType,
+ &NameGuid,
+ &FileAttributes,
+ &Size
+ );
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ ParseFfs (Fv2, &NameGuid);
+ }
+
+ InternalVarCheckFreePool (Key);
+ } else {
+ //
+ // Only parse drivers in the VFR drivers list.
+ //
+ VfrDriverLink = mVfrDriverList.ForwardLink;
+ while (VfrDriverLink != &mVfrDriverList) {
+ VfrDriverInfo = VAR_CHECK_VFR_DRIVER_INFO_FROM_LINK (VfrDriverLink);
+ VfrDriverLink = VfrDriverLink->ForwardLink;
+ if (ParseFfs (Fv2, VfrDriverInfo->DriverGuid)) {
+ //
+ // Found the driver in the FV.
+ //
+ RemoveEntryList (&VfrDriverInfo->Link);
+ InternalVarCheckFreePool (VfrDriverInfo);
+ }
+ }
+ }
+ }
+
+ FreePool (HandleBuffer);
+}
+
+/**
+ Create Vfr Driver List.
+
+ @param[in] DriverGuidArray Driver Guid Array
+
+**/
+VOID
+CreateVfrDriverList (
+ IN EFI_GUID *DriverGuidArray
+ )
+{
+ UINTN Index;
+ VAR_CHECK_VFR_DRIVER_INFO *VfrDriverInfo;
+
+ for (Index = 0; !CompareGuid (&DriverGuidArray[Index], &gZeroGuid); Index++) {
+ DEBUG ((EFI_D_INFO, "CreateVfrDriverList: %g\n", &DriverGuidArray[Index]));
+ VfrDriverInfo = InternalVarCheckAllocateZeroPool (sizeof (*VfrDriverInfo));
+ ASSERT (VfrDriverInfo != NULL);
+ VfrDriverInfo->Signature = VAR_CHECK_VFR_DRIVER_INFO_SIGNATURE;
+ VfrDriverInfo->DriverGuid = &DriverGuidArray[Index];
+ InsertTailList (&mVfrDriverList, &VfrDriverInfo->Link);
+ }
+}
+
+/**
+ Destroy Vfr Driver List.
+
+**/
+VOID
+DestroyVfrDriverList (
+ VOID
+ )
+{
+ VAR_CHECK_VFR_DRIVER_INFO *VfrDriverInfo;
+ LIST_ENTRY *VfrDriverLink;
+
+ while (mVfrDriverList.ForwardLink != &mVfrDriverList) {
+ VfrDriverLink = mVfrDriverList.ForwardLink;
+ VfrDriverInfo = VAR_CHECK_VFR_DRIVER_INFO_FROM_LINK (VfrDriverLink);
+ RemoveEntryList (&VfrDriverInfo->Link);
+ InternalVarCheckFreePool (VfrDriverInfo);
+ }
+}
+
+/**
+ Generate from FV.
+
+**/
+VOID
+VarCheckHiiGenFromFv (
+ VOID
+ )
+{
+ EFI_GUID *DriverGuidArray;
+ BOOLEAN ScanAll;
+
+ DEBUG ((EFI_D_INFO, "VarCheckHiiGenDxeFromFv\n"));
+
+ //
+ // Get vfr driver guid array from PCD.
+ //
+ DriverGuidArray = (EFI_GUID *) PcdGetPtr (PcdVarCheckVfrDriverGuidArray);
+
+ if (CompareGuid (&DriverGuidArray[0], &gZeroGuid)) {
+ //
+ // No VFR driver will be parsed from FVs.
+ //
+ return;
+ }
+
+ if (CompareGuid (&DriverGuidArray[0], &mAllFfGuid)) {
+ ScanAll = TRUE;
+ } else {
+ ScanAll = FALSE;
+ CreateVfrDriverList (DriverGuidArray);
+ }
+
+ ParseFv (ScanAll);
+
+ if (!ScanAll) {
+ DestroyVfrDriverList ();
+ }
+}
diff --git a/Core/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiGenFromHii.c b/Core/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiGenFromHii.c
new file mode 100644
index 0000000000..41cde34af7
--- /dev/null
+++ b/Core/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiGenFromHii.c
@@ -0,0 +1,73 @@
+/** @file
+ Var Check Hii generation from Hii Database.
+
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "VarCheckHiiGen.h"
+
+/**
+ Generate from Hii Database.
+
+**/
+VOID
+VarCheckHiiGenFromHiiDatabase (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN BufferSize;
+ VOID *Buffer;
+ EFI_PHYSICAL_ADDRESS BufferAddress;
+ EFI_HII_DATABASE_PROTOCOL *HiiDatabase;
+
+ //
+ // Locate HII Database protocol
+ //
+ Status = gBS->LocateProtocol (&gEfiHiiDatabaseProtocolGuid, NULL, (VOID **) &HiiDatabase);
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ //
+ // Call first time with zero buffer length.
+ // Should fail with EFI_BUFFER_TOO_SMALL.
+ //
+ BufferSize = 0;
+ Buffer = NULL;
+ Status = HiiDatabase->ExportPackageLists (HiiDatabase, 0, &BufferSize, Buffer);
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ //
+ // Allocate buffer to hold the HII Database.
+ //
+ Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesData, EFI_SIZE_TO_PAGES (BufferSize), &BufferAddress);
+ ASSERT_EFI_ERROR (Status);
+ Buffer = (VOID *) (UINTN) BufferAddress;
+
+ //
+ // Export HII Database into the buffer.
+ //
+ Status = HiiDatabase->ExportPackageLists (HiiDatabase, 0, &BufferSize, Buffer);
+ ASSERT_EFI_ERROR (Status);
+
+ DEBUG ((EFI_D_INFO, "VarCheckHiiGenDxeFromHii - HII Database exported at 0x%x, size = 0x%x\n", Buffer, BufferSize));
+
+#ifdef DUMP_HII_DATA
+ DEBUG_CODE (
+ DumpHiiDatabase (Buffer, BufferSize);
+ );
+#endif
+
+ VarCheckParseHiiDatabase (Buffer, BufferSize);
+
+ gBS->FreePages (BufferAddress, EFI_SIZE_TO_PAGES (BufferSize));
+ }
+}
diff --git a/Core/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLib.inf b/Core/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLib.inf
new file mode 100644
index 0000000000..24d24c5dd5
--- /dev/null
+++ b/Core/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLib.inf
@@ -0,0 +1,58 @@
+## @file
+# NULL class library to register var check HII handler.
+#
+# Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions
+# of the BSD License which accompanies this distribution. The
+# full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = VarCheckHiiLib
+ MODULE_UNI_FILE = VarCheckHiiLib.uni
+ FILE_GUID = A34FBDD0-05D3-4AF7-A720-560E91AC8CDF
+ MODULE_TYPE = DXE_RUNTIME_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = NULL|DXE_RUNTIME_DRIVER DXE_SMM_DRIVER
+ CONSTRUCTOR = VarCheckHiiLibNullClassConstructor
+
+[Sources]
+ VarCheckHiiLibNullClass.c
+ VarCheckHii.h
+ VarCheckHiiGenFromFv.c
+ VarCheckHiiGenFromHii.c
+ VarCheckHiiGen.c
+ VarCheckHiiGen.h
+ InternalVarCheckStructure.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ DebugLib
+ BaseMemoryLib
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ PcdLib
+ VarCheckLib
+
+[Guids]
+ gZeroGuid ## SOMETIMES_CONSUMES ## GUID
+
+[Protocols]
+ gEfiFirmwareVolume2ProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiFirmwareVolumeBlock2ProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiHiiDatabaseProtocolGuid ## SOMETIMES_CONSUMES
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdVarCheckVfrDriverGuidArray ## SOMETIMES_CONSUMES
diff --git a/Core/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLib.uni b/Core/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLib.uni
new file mode 100644
index 0000000000..e4a0debafa
--- /dev/null
+++ b/Core/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLib.uni
Binary files differ
diff --git a/Core/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLibNullClass.c b/Core/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLibNullClass.c
new file mode 100644
index 0000000000..3afa7962aa
--- /dev/null
+++ b/Core/MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLibNullClass.c
@@ -0,0 +1,539 @@
+/** @file
+ Var Check Hii handler.
+
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "VarCheckHii.h"
+
+GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 mVarCheckHiiHex[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
+
+/**
+ Dump some hexadecimal data.
+
+ @param[in] Indent How many spaces to indent the output.
+ @param[in] Offset The offset of the dump.
+ @param[in] DataSize The size in bytes of UserData.
+ @param[in] UserData The data to dump.
+
+**/
+VOID
+VarCheckHiiInternalDumpHex (
+ IN UINTN Indent,
+ IN UINTN Offset,
+ IN UINTN DataSize,
+ IN VOID *UserData
+ )
+{
+ UINT8 *Data;
+
+ CHAR8 Val[50];
+
+ CHAR8 Str[20];
+
+ UINT8 TempByte;
+ UINTN Size;
+ UINTN Index;
+
+ Data = UserData;
+ while (DataSize != 0) {
+ Size = 16;
+ if (Size > DataSize) {
+ Size = DataSize;
+ }
+
+ for (Index = 0; Index < Size; Index += 1) {
+ TempByte = Data[Index];
+ Val[Index * 3 + 0] = mVarCheckHiiHex[TempByte >> 4];
+ Val[Index * 3 + 1] = mVarCheckHiiHex[TempByte & 0xF];
+ Val[Index * 3 + 2] = (CHAR8) ((Index == 7) ? '-' : ' ');
+ Str[Index] = (CHAR8) ((TempByte < ' ' || TempByte > 'z') ? '.' : TempByte);
+ }
+
+ Val[Index * 3] = 0;
+ Str[Index] = 0;
+ DEBUG ((EFI_D_INFO, "%*a%08X: %-48a *%a*\r\n", Indent, "", Offset, Val, Str));
+
+ Data += Size;
+ Offset += Size;
+ DataSize -= Size;
+ }
+}
+
+/**
+ Var Check Hii Question.
+
+ @param[in] HiiQuestion Pointer to Hii Question
+ @param[in] Data Data pointer.
+ @param[in] DataSize Size of Data to set.
+
+ @retval TRUE Check pass
+ @retval FALSE Check fail.
+
+**/
+BOOLEAN
+VarCheckHiiQuestion (
+ IN VAR_CHECK_HII_QUESTION_HEADER *HiiQuestion,
+ IN VOID *Data,
+ IN UINTN DataSize
+ )
+{
+ UINT64 OneData;
+ UINT64 Minimum;
+ UINT64 Maximum;
+ UINT64 OneValue;
+ UINT8 *Ptr;
+ UINT8 Index;
+ UINT8 MaxContainers;
+
+ if ((UINTN) (HiiQuestion->VarOffset + HiiQuestion->StorageWidth) > DataSize) {
+ DEBUG ((EFI_D_INFO, "VarCheckHiiQuestion fail: (VarOffset(0x%04x) + StorageWidth(0x%02x)) > Size(0x%x)\n", HiiQuestion->VarOffset, HiiQuestion->StorageWidth, DataSize));
+ return FALSE;
+ }
+
+ OneData = 0;
+ CopyMem (&OneData, (UINT8 *) Data + HiiQuestion->VarOffset, HiiQuestion->StorageWidth);
+
+ switch (HiiQuestion->OpCode) {
+ case EFI_IFR_ONE_OF_OP:
+ Ptr = (UINT8 *) ((VAR_CHECK_HII_QUESTION_ONEOF *) HiiQuestion + 1);
+ while ((UINTN) Ptr < (UINTN) HiiQuestion + HiiQuestion->Length) {
+ OneValue = 0;
+ CopyMem (&OneValue, Ptr, HiiQuestion->StorageWidth);
+ if (OneData == OneValue) {
+ //
+ // Match
+ //
+ break;
+ }
+ Ptr += HiiQuestion->StorageWidth;
+ }
+ if ((UINTN) Ptr >= ((UINTN) HiiQuestion + HiiQuestion->Length)) {
+ //
+ // No match
+ //
+ DEBUG ((EFI_D_INFO, "VarCheckHiiQuestion fail: OneOf mismatch (0x%lx)\n", OneData));
+ DEBUG_CODE (VarCheckHiiInternalDumpHex (2, 0, HiiQuestion->Length, (UINT8 *) HiiQuestion););
+ return FALSE;
+ }
+ break;
+
+ case EFI_IFR_CHECKBOX_OP:
+ if ((OneData != 0) && (OneData != 1)) {
+ DEBUG ((EFI_D_INFO, "VarCheckHiiQuestion fail: CheckBox mismatch (0x%lx)\n", OneData));
+ DEBUG_CODE (VarCheckHiiInternalDumpHex (2, 0, HiiQuestion->Length, (UINT8 *) HiiQuestion););
+ return FALSE;
+ }
+ break;
+
+ case EFI_IFR_NUMERIC_OP:
+ Minimum = 0;
+ Maximum = 0;
+ Ptr = (UINT8 *) ((VAR_CHECK_HII_QUESTION_NUMERIC *) HiiQuestion + 1);
+ CopyMem (&Minimum, Ptr, HiiQuestion->StorageWidth);
+ Ptr += HiiQuestion->StorageWidth;
+ CopyMem (&Maximum, Ptr, HiiQuestion->StorageWidth);
+ Ptr += HiiQuestion->StorageWidth;
+
+ //
+ // No need to check Step, because it is ONLY for UI.
+ //
+ if ((OneData < Minimum) || (OneData > Maximum)) {
+ DEBUG ((EFI_D_INFO, "VarCheckHiiQuestion fail: Numeric mismatch (0x%lx)\n", OneData));
+ DEBUG_CODE (VarCheckHiiInternalDumpHex (2, 0, HiiQuestion->Length, (UINT8 *) HiiQuestion););
+ return FALSE;
+ }
+ break;
+
+ case EFI_IFR_ORDERED_LIST_OP:
+ MaxContainers = ((VAR_CHECK_HII_QUESTION_ORDEREDLIST *) HiiQuestion)->MaxContainers;
+ if ((UINTN) (HiiQuestion->VarOffset + HiiQuestion->StorageWidth * MaxContainers) > DataSize) {
+ DEBUG ((EFI_D_INFO, "VarCheckHiiQuestion fail: (VarOffset(0x%04x) + StorageWidth(0x%02x) * MaxContainers(0x%02x)) > Size(0x%x)\n", HiiQuestion->VarOffset, HiiQuestion->StorageWidth, MaxContainers, DataSize));
+ return FALSE;
+ }
+ for (Index = 0; Index < MaxContainers; Index++) {
+ OneData = 0;
+ CopyMem (&OneData, (UINT8 *) Data + HiiQuestion->VarOffset + HiiQuestion->StorageWidth * Index, HiiQuestion->StorageWidth);
+ if (OneData == 0) {
+ //
+ // The value of 0 is used to determine if a particular "slot" in the array is empty.
+ //
+ continue;
+ }
+
+ Ptr = (UINT8 *) ((VAR_CHECK_HII_QUESTION_ORDEREDLIST *) HiiQuestion + 1);
+ while ((UINTN) Ptr < ((UINTN) HiiQuestion + HiiQuestion->Length)) {
+ OneValue = 0;
+ CopyMem (&OneValue, Ptr, HiiQuestion->StorageWidth);
+ if (OneData == OneValue) {
+ //
+ // Match
+ //
+ break;
+ }
+ Ptr += HiiQuestion->StorageWidth;
+ }
+ if ((UINTN) Ptr >= ((UINTN) HiiQuestion + HiiQuestion->Length)) {
+ //
+ // No match
+ //
+ DEBUG ((EFI_D_INFO, "VarCheckHiiQuestion fail: OrderedList mismatch\n"));
+ DEBUG_CODE (VarCheckHiiInternalDumpHex (2, 0, HiiQuestion->StorageWidth * MaxContainers, (UINT8 *) Data + HiiQuestion->VarOffset););
+ DEBUG_CODE (VarCheckHiiInternalDumpHex (2, 0, HiiQuestion->Length, (UINT8 *) HiiQuestion););
+ return FALSE;
+ }
+ }
+ break;
+
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+
+ return TRUE;
+}
+
+VAR_CHECK_HII_VARIABLE_HEADER *mVarCheckHiiBin = NULL;
+UINTN mVarCheckHiiBinSize = 0;
+
+/**
+ SetVariable check handler HII.
+
+ @param[in] VariableName Name of Variable to set.
+ @param[in] VendorGuid Variable vendor GUID.
+ @param[in] Attributes Attribute value of the variable.
+ @param[in] DataSize Size of Data to set.
+ @param[in] Data Data pointer.
+
+ @retval EFI_SUCCESS The SetVariable check result was success.
+ @retval EFI_SECURITY_VIOLATION Check fail.
+
+**/
+EFI_STATUS
+EFIAPI
+SetVariableCheckHandlerHii (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN UINT32 Attributes,
+ IN UINTN DataSize,
+ IN VOID *Data
+ )
+{
+ VAR_CHECK_HII_VARIABLE_HEADER *HiiVariable;
+ VAR_CHECK_HII_QUESTION_HEADER *HiiQuestion;
+
+ if (mVarCheckHiiBin == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ if ((((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) && (DataSize == 0)) || (Attributes == 0)) {
+ //
+ // Do not check delete variable.
+ //
+ return EFI_SUCCESS;
+ }
+
+ //
+ // For Hii Variable header align.
+ //
+ HiiVariable = (VAR_CHECK_HII_VARIABLE_HEADER *) HEADER_ALIGN (mVarCheckHiiBin);
+ while ((UINTN) HiiVariable < ((UINTN) mVarCheckHiiBin + mVarCheckHiiBinSize)) {
+ if ((StrCmp ((CHAR16 *) (HiiVariable + 1), VariableName) == 0) &&
+ (CompareGuid (&HiiVariable->Guid, VendorGuid))) {
+ //
+ // Found the Hii Variable that could be used to do check.
+ //
+ DEBUG ((EFI_D_INFO, "VarCheckHiiVariable - %s:%g with Attributes = 0x%08x Size = 0x%x\n", VariableName, VendorGuid, Attributes, DataSize));
+ if (HiiVariable->Attributes != Attributes) {
+ DEBUG ((EFI_D_INFO, "VarCheckHiiVariable fail for Attributes - 0x%08x\n", HiiVariable->Attributes));
+ return EFI_SECURITY_VIOLATION;
+ }
+
+ if (DataSize == 0) {
+ DEBUG ((EFI_D_INFO, "VarCheckHiiVariable - CHECK PASS with DataSize == 0 !\n"));
+ return EFI_SUCCESS;
+ }
+
+ if (HiiVariable->Size != DataSize) {
+ DEBUG ((EFI_D_INFO, "VarCheckHiiVariable fail for Size - 0x%x\n", HiiVariable->Size));
+ return EFI_SECURITY_VIOLATION;
+ }
+
+ //
+ // Do the check.
+ // For Hii Question header align.
+ //
+ HiiQuestion = (VAR_CHECK_HII_QUESTION_HEADER *) HEADER_ALIGN (((UINTN) HiiVariable + HiiVariable->HeaderLength));
+ while ((UINTN) HiiQuestion < ((UINTN) HiiVariable + HiiVariable->Length)) {
+ if (!VarCheckHiiQuestion (HiiQuestion, Data, DataSize)) {
+ return EFI_SECURITY_VIOLATION;
+ }
+ //
+ // For Hii Question header align.
+ //
+ HiiQuestion = (VAR_CHECK_HII_QUESTION_HEADER *) HEADER_ALIGN (((UINTN) HiiQuestion + HiiQuestion->Length));
+ }
+
+ DEBUG ((EFI_D_INFO, "VarCheckHiiVariable - ALL CHECK PASS!\n"));
+ return EFI_SUCCESS;
+ }
+ //
+ // For Hii Variable header align.
+ //
+ HiiVariable = (VAR_CHECK_HII_VARIABLE_HEADER *) HEADER_ALIGN (((UINTN) HiiVariable + HiiVariable->Length));
+ }
+
+ // Not found, so pass.
+ return EFI_SUCCESS;
+}
+
+#ifdef DUMP_VAR_CHECK_HII
+GLOBAL_REMOVE_IF_UNREFERENCED VAR_CHECK_HII_OPCODE_STRING mHiiOpCodeStringTable[] = {
+ {EFI_IFR_VARSTORE_EFI_OP, "EfiVarStore"},
+ {EFI_IFR_ONE_OF_OP, "OneOf"},
+ {EFI_IFR_CHECKBOX_OP, "CheckBox"},
+ {EFI_IFR_NUMERIC_OP, "Numeric"},
+ {EFI_IFR_ORDERED_LIST_OP, "OrderedList"},
+};
+
+/**
+ HII opcode to string.
+
+ @param[in] HiiOpCode Hii OpCode.
+
+ @return Pointer to string.
+
+**/
+CHAR8 *
+HiiOpCodeToStr (
+ IN UINT8 HiiOpCode
+ )
+{
+ UINTN Index;
+ for (Index = 0; Index < sizeof (mHiiOpCodeStringTable) / sizeof (mHiiOpCodeStringTable[0]); Index++) {
+ if (mHiiOpCodeStringTable[Index].HiiOpCode == HiiOpCode) {
+ return mHiiOpCodeStringTable[Index].HiiOpCodeStr;
+ }
+ }
+
+ return "<UnknownHiiOpCode>";
+}
+
+/**
+ Dump Hii Question.
+
+ @param[in] HiiQuestion Pointer to Hii Question.
+
+**/
+VOID
+DumpHiiQuestion (
+ IN VAR_CHECK_HII_QUESTION_HEADER *HiiQuestion
+ )
+{
+ UINT64 Minimum;
+ UINT64 Maximum;
+ UINT64 OneValue;
+ UINT8 *Ptr;
+
+ DEBUG ((EFI_D_INFO, " VAR_CHECK_HII_QUESTION_HEADER\n"));
+ DEBUG ((EFI_D_INFO, " OpCode - 0x%02x (%a)\n", HiiQuestion->OpCode, HiiOpCodeToStr (HiiQuestion->OpCode)));
+ DEBUG ((EFI_D_INFO, " Length - 0x%02x\n", HiiQuestion->Length));
+ DEBUG ((EFI_D_INFO, " VarOffset - 0x%04x\n", HiiQuestion->VarOffset));
+ DEBUG ((EFI_D_INFO, " StorageWidth - 0x%02x\n", HiiQuestion->StorageWidth));
+
+ switch (HiiQuestion->OpCode) {
+ case EFI_IFR_ONE_OF_OP:
+ Ptr = (UINT8 *) ((VAR_CHECK_HII_QUESTION_ONEOF *) HiiQuestion + 1);
+ while ((UINTN) Ptr < ((UINTN) HiiQuestion + HiiQuestion->Length)) {
+ OneValue = 0;
+ CopyMem (&OneValue, Ptr, HiiQuestion->StorageWidth);
+ switch (HiiQuestion->StorageWidth) {
+ case sizeof (UINT8):
+ DEBUG ((EFI_D_INFO, " OneOfOption - 0x%02x\n", OneValue));
+ break;
+ case sizeof (UINT16):
+ DEBUG ((EFI_D_INFO, " OneOfOption - 0x%04x\n", OneValue));
+ break;
+ case sizeof (UINT32):
+ DEBUG ((EFI_D_INFO, " OneOfOption - 0x%08x\n", OneValue));
+ break;
+ case sizeof (UINT64):
+ DEBUG ((EFI_D_INFO, " OneOfOption - 0x%016lx\n", OneValue));
+ break;
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+ Ptr += HiiQuestion->StorageWidth;
+ }
+ break;
+
+ case EFI_IFR_CHECKBOX_OP:
+ break;
+
+ case EFI_IFR_NUMERIC_OP:
+ Minimum = 0;
+ Maximum = 0;
+ Ptr = (UINT8 *) ((VAR_CHECK_HII_QUESTION_NUMERIC *) HiiQuestion + 1);
+ CopyMem (&Minimum, Ptr, HiiQuestion->StorageWidth);
+ Ptr += HiiQuestion->StorageWidth;
+ CopyMem (&Maximum, Ptr, HiiQuestion->StorageWidth);
+ Ptr += HiiQuestion->StorageWidth;
+
+ switch (HiiQuestion->StorageWidth) {
+ case sizeof (UINT8):
+ DEBUG ((EFI_D_INFO, " Minimum - 0x%02x\n", Minimum));
+ DEBUG ((EFI_D_INFO, " Maximum - 0x%02x\n", Maximum));
+ break;
+ case sizeof (UINT16):
+ DEBUG ((EFI_D_INFO, " Minimum - 0x%04x\n", Minimum));
+ DEBUG ((EFI_D_INFO, " Maximum - 0x%04x\n", Maximum));
+ break;
+ case sizeof (UINT32):
+ DEBUG ((EFI_D_INFO, " Minimum - 0x%08x\n", Minimum));
+ DEBUG ((EFI_D_INFO, " Maximum - 0x%08x\n", Maximum));
+ break;
+ case sizeof (UINT64):
+ DEBUG ((EFI_D_INFO, " Minimum - 0x%016lx\n", Minimum));
+ DEBUG ((EFI_D_INFO, " Maximum - 0x%016lx\n", Maximum));
+ break;
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+ break;
+
+ case EFI_IFR_ORDERED_LIST_OP:
+ DEBUG ((EFI_D_INFO, " MaxContainers - 0x%02x\n", ((VAR_CHECK_HII_QUESTION_ORDEREDLIST *) HiiQuestion)->MaxContainers));
+ Ptr = (UINT8 *) ((VAR_CHECK_HII_QUESTION_ORDEREDLIST *) HiiQuestion + 1);
+ while ((UINTN) Ptr < ((UINTN) HiiQuestion + HiiQuestion->Length)) {
+ OneValue = 0;
+ CopyMem (&OneValue, Ptr, HiiQuestion->StorageWidth);
+ switch (HiiQuestion->StorageWidth) {
+ case sizeof (UINT8):
+ DEBUG ((EFI_D_INFO, " OneOfOption - 0x%02x\n", OneValue));
+ break;
+ case sizeof (UINT16):
+ DEBUG ((EFI_D_INFO, " OneOfOption - 0x%04x\n", OneValue));
+ break;
+ case sizeof (UINT32):
+ DEBUG ((EFI_D_INFO, " OneOfOption - 0x%08x\n", OneValue));
+ break;
+ case sizeof (UINT64):
+ DEBUG ((EFI_D_INFO, " OneOfOption - 0x%016lx\n", OneValue));
+ break;
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+ Ptr += HiiQuestion->StorageWidth;
+ }
+ break;
+
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+}
+
+/**
+ Dump Hii Variable.
+
+ @param[in] HiiVariable Pointer to Hii Variable.
+
+**/
+VOID
+DumpHiiVariable (
+ IN VAR_CHECK_HII_VARIABLE_HEADER *HiiVariable
+ )
+{
+ VAR_CHECK_HII_QUESTION_HEADER *HiiQuestion;
+
+ DEBUG ((EFI_D_INFO, "VAR_CHECK_HII_VARIABLE_HEADER\n"));
+ DEBUG ((EFI_D_INFO, " Revision - 0x%04x\n", HiiVariable->Revision));
+ DEBUG ((EFI_D_INFO, " HeaderLength - 0x%04x\n", HiiVariable->HeaderLength));
+ DEBUG ((EFI_D_INFO, " Length - 0x%08x\n", HiiVariable->Length));
+ DEBUG ((EFI_D_INFO, " OpCode - 0x%02x (%a)\n", HiiVariable->OpCode, HiiOpCodeToStr (HiiVariable->OpCode)));
+ DEBUG ((EFI_D_INFO, " Size - 0x%04x\n", HiiVariable->Size));
+ DEBUG ((EFI_D_INFO, " Attributes - 0x%08x\n", HiiVariable->Attributes));
+ DEBUG ((EFI_D_INFO, " Guid - %g\n", &HiiVariable->Guid));
+ DEBUG ((EFI_D_INFO, " Name - %s\n", HiiVariable + 1));
+
+ //
+ // For Hii Question header align.
+ //
+ HiiQuestion = (VAR_CHECK_HII_QUESTION_HEADER *) HEADER_ALIGN (((UINTN) HiiVariable + HiiVariable->HeaderLength));
+ while ((UINTN) HiiQuestion < ((UINTN) HiiVariable + HiiVariable->Length)) {
+ //
+ // Dump Hii Question related to the Hii Variable.
+ //
+ DumpHiiQuestion (HiiQuestion);
+ //
+ // For Hii Question header align.
+ //
+ HiiQuestion = (VAR_CHECK_HII_QUESTION_HEADER *) HEADER_ALIGN (((UINTN) HiiQuestion + HiiQuestion->Length));
+ }
+}
+
+/**
+ Dump Var Check HII.
+
+ @param[in] VarCheckHiiBin Pointer to VarCheckHiiBin.
+ @param[in] VarCheckHiiBinSize VarCheckHiiBin size.
+
+**/
+VOID
+DumpVarCheckHii (
+ IN VOID *VarCheckHiiBin,
+ IN UINTN VarCheckHiiBinSize
+ )
+{
+ VAR_CHECK_HII_VARIABLE_HEADER *HiiVariable;
+
+ DEBUG ((EFI_D_INFO, "DumpVarCheckHii\n"));
+
+ //
+ // For Hii Variable header align.
+ //
+ HiiVariable = (VAR_CHECK_HII_VARIABLE_HEADER *) HEADER_ALIGN (VarCheckHiiBin);
+ while ((UINTN) HiiVariable < ((UINTN) VarCheckHiiBin + VarCheckHiiBinSize)) {
+ DumpHiiVariable (HiiVariable);
+ //
+ // For Hii Variable header align.
+ //
+ HiiVariable = (VAR_CHECK_HII_VARIABLE_HEADER *) HEADER_ALIGN (((UINTN) HiiVariable + HiiVariable->Length));
+ }
+}
+#endif
+
+/**
+ Constructor function of VarCheckHiiLib to register var check HII handler.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The constructor executed correctly.
+
+**/
+EFI_STATUS
+EFIAPI
+VarCheckHiiLibNullClassConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ VarCheckLibRegisterEndOfDxeCallback (VarCheckHiiGen);
+ VarCheckLibRegisterAddressPointer ((VOID **) &mVarCheckHiiBin);
+ VarCheckLibRegisterSetVariableCheckHandler (SetVariableCheckHandlerHii);
+
+ return EFI_SUCCESS;
+}
+
diff --git a/Core/MdeModulePkg/Library/VarCheckLib/VarCheckLib.c b/Core/MdeModulePkg/Library/VarCheckLib/VarCheckLib.c
new file mode 100644
index 0000000000..60c141a6b9
--- /dev/null
+++ b/Core/MdeModulePkg/Library/VarCheckLib/VarCheckLib.c
@@ -0,0 +1,663 @@
+/** @file
+ Implementation functions and structures for var check services.
+
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Library/VarCheckLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+#include <Guid/GlobalVariable.h>
+#include <Guid/HardwareErrorVariable.h>
+
+BOOLEAN mVarCheckLibEndOfDxe = FALSE;
+
+#define VAR_CHECK_TABLE_SIZE 0x8
+
+UINTN mVarCheckLibEndOfDxeCallbackCount = 0;
+UINTN mVarCheckLibEndOfDxeCallbackMaxCount = 0;
+VAR_CHECK_END_OF_DXE_CALLBACK *mVarCheckLibEndOfDxeCallback = NULL;
+
+UINTN mVarCheckLibAddressPointerCount = 0;
+UINTN mVarCheckLibAddressPointerMaxCount = 0;
+VOID ***mVarCheckLibAddressPointer = NULL;
+
+UINTN mNumberOfVarCheckHandler = 0;
+UINTN mMaxNumberOfVarCheckHandler = 0;
+VAR_CHECK_SET_VARIABLE_CHECK_HANDLER *mVarCheckHandlerTable = NULL;
+
+typedef struct {
+ EFI_GUID Guid;
+ VAR_CHECK_VARIABLE_PROPERTY VariableProperty;
+ //CHAR16 *Name;
+} VAR_CHECK_VARIABLE_ENTRY;
+
+UINTN mNumberOfVarCheckVariable = 0;
+UINTN mMaxNumberOfVarCheckVariable = 0;
+VARIABLE_ENTRY_PROPERTY **mVarCheckVariableTable = NULL;
+
+//
+// Handle variables with wildcard name specially.
+//
+VARIABLE_ENTRY_PROPERTY mVarCheckVariableWithWildcardName[] = {
+ {
+ &gEfiGlobalVariableGuid,
+ L"Boot####",
+ {
+ 0
+ },
+ },
+ {
+ &gEfiGlobalVariableGuid,
+ L"Driver####",
+ {
+ 0
+ },
+ },
+ {
+ &gEfiGlobalVariableGuid,
+ L"SysPrep####",
+ {
+ 0
+ },
+ },
+ {
+ &gEfiGlobalVariableGuid,
+ L"Key####",
+ {
+ 0
+ },
+ },
+ {
+ &gEfiHardwareErrorVariableGuid,
+ L"HwErrRec####",
+ {
+ 0
+ },
+ },
+};
+
+/**
+ Check if a Unicode character is a hexadecimal character.
+
+ This function checks if a Unicode character is a
+ hexadecimal character. The valid hexadecimal character is
+ L'0' to L'9', L'a' to L'f', or L'A' to L'F'.
+
+
+ @param[in] Char The character to check against.
+
+ @retval TRUE If the Char is a hexadecmial character.
+ @retval FALSE If the Char is not a hexadecmial character.
+
+**/
+BOOLEAN
+EFIAPI
+VarCheckInternalIsHexaDecimalDigitCharacter (
+ IN CHAR16 Char
+ )
+{
+ return (BOOLEAN) ((Char >= L'0' && Char <= L'9') || (Char >= L'A' && Char <= L'F') || (Char >= L'a' && Char <= L'f'));
+}
+
+/**
+ Variable property get with wildcard name.
+
+ @param[in] VariableName Pointer to variable name.
+ @param[in] VendorGuid Pointer to variable vendor GUID.
+ @param[in] WildcardMatch Try wildcard match or not.
+
+ @return Pointer to variable property.
+
+**/
+VAR_CHECK_VARIABLE_PROPERTY *
+VariablePropertyGetWithWildcardName (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN BOOLEAN WildcardMatch
+ )
+{
+ UINTN Index;
+ UINTN NameLength;
+
+ NameLength = StrLen (VariableName) - 4;
+ for (Index = 0; Index < sizeof (mVarCheckVariableWithWildcardName)/sizeof (mVarCheckVariableWithWildcardName[0]); Index++) {
+ if (CompareGuid (mVarCheckVariableWithWildcardName[Index].Guid, VendorGuid)){
+ if (WildcardMatch) {
+ if ((StrLen (VariableName) == StrLen (mVarCheckVariableWithWildcardName[Index].Name)) &&
+ (StrnCmp (VariableName, mVarCheckVariableWithWildcardName[Index].Name, NameLength) == 0) &&
+ VarCheckInternalIsHexaDecimalDigitCharacter (VariableName[NameLength]) &&
+ VarCheckInternalIsHexaDecimalDigitCharacter (VariableName[NameLength + 1]) &&
+ VarCheckInternalIsHexaDecimalDigitCharacter (VariableName[NameLength + 2]) &&
+ VarCheckInternalIsHexaDecimalDigitCharacter (VariableName[NameLength + 3])) {
+ return &mVarCheckVariableWithWildcardName[Index].VariableProperty;
+ }
+ }
+ if (StrCmp (mVarCheckVariableWithWildcardName[Index].Name, VariableName) == 0) {
+ return &mVarCheckVariableWithWildcardName[Index].VariableProperty;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ Variable property get function.
+
+ @param[in] Name Pointer to the variable name.
+ @param[in] Guid Pointer to the vendor GUID.
+ @param[in] WildcardMatch Try wildcard match or not.
+
+ @return Pointer to the property of variable specified by the Name and Guid.
+
+**/
+VAR_CHECK_VARIABLE_PROPERTY *
+VariablePropertyGetFunction (
+ IN CHAR16 *Name,
+ IN EFI_GUID *Guid,
+ IN BOOLEAN WildcardMatch
+ )
+{
+ UINTN Index;
+ VAR_CHECK_VARIABLE_ENTRY *Entry;
+ CHAR16 *VariableName;
+
+ for (Index = 0; Index < mNumberOfVarCheckVariable; Index++) {
+ Entry = (VAR_CHECK_VARIABLE_ENTRY *) mVarCheckVariableTable[Index];
+ VariableName = (CHAR16 *) ((UINTN) Entry + sizeof (*Entry));
+ if (CompareGuid (&Entry->Guid, Guid) && (StrCmp (VariableName, Name) == 0)) {
+ return &Entry->VariableProperty;
+ }
+ }
+
+ return VariablePropertyGetWithWildcardName (Name, Guid, WildcardMatch);
+}
+
+/**
+ Var check add table entry.
+
+ @param[in, out] Table Pointer to table buffer.
+ @param[in, out] MaxNumber Pointer to maximum number of entry in the table.
+ @param[in, out] CurrentNumber Pointer to current number of entry in the table.
+ @param[in] Entry Entry will be added to the table.
+
+ @retval EFI_SUCCESS Reallocate memory successfully.
+ @retval EFI_OUT_OF_RESOURCES No enough memory to allocate.
+
+**/
+EFI_STATUS
+VarCheckAddTableEntry (
+ IN OUT UINTN **Table,
+ IN OUT UINTN *MaxNumber,
+ IN OUT UINTN *CurrentNumber,
+ IN UINTN Entry
+ )
+{
+ UINTN *TempTable;
+
+ //
+ // Check whether the table is enough to store new entry.
+ //
+ if (*CurrentNumber == *MaxNumber) {
+ //
+ // Reallocate memory for the table.
+ //
+ TempTable = ReallocateRuntimePool (
+ *MaxNumber * sizeof (UINTN),
+ (*MaxNumber + VAR_CHECK_TABLE_SIZE) * sizeof (UINTN),
+ *Table
+ );
+
+ //
+ // No enough resource to allocate.
+ //
+ if (TempTable == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ *Table = TempTable;
+ //
+ // Increase max number.
+ //
+ *MaxNumber += VAR_CHECK_TABLE_SIZE;
+ }
+
+ //
+ // Add entry to the table.
+ //
+ (*Table)[*CurrentNumber] = Entry;
+ (*CurrentNumber)++;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Register END_OF_DXE callback.
+ The callback will be invoked by VarCheckLibInitializeAtEndOfDxe().
+
+ @param[in] Callback END_OF_DXE callback.
+
+ @retval EFI_SUCCESS The callback was registered successfully.
+ @retval EFI_INVALID_PARAMETER Callback is NULL.
+ @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
+ already been signaled.
+ @retval EFI_OUT_OF_RESOURCES There is not enough resource for the callback register request.
+
+**/
+EFI_STATUS
+EFIAPI
+VarCheckLibRegisterEndOfDxeCallback (
+ IN VAR_CHECK_END_OF_DXE_CALLBACK Callback
+ )
+{
+ EFI_STATUS Status;
+
+ if (Callback == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (mVarCheckLibEndOfDxe) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ Status = VarCheckAddTableEntry (
+ (UINTN **) &mVarCheckLibEndOfDxeCallback,
+ &mVarCheckLibEndOfDxeCallbackMaxCount,
+ &mVarCheckLibEndOfDxeCallbackCount,
+ (UINTN) Callback
+ );
+
+ DEBUG ((EFI_D_INFO, "VarCheckLibRegisterEndOfDxeCallback - 0x%x %r\n", Callback, Status));
+
+ return Status;
+}
+
+/**
+ Var check initialize at END_OF_DXE.
+
+ This function needs to be called at END_OF_DXE.
+ Address pointers may be returned,
+ and caller needs to ConvertPointer() for the pointers.
+
+ @param[in, out] AddressPointerCount Output pointer to address pointer count.
+
+ @return Address pointer buffer, NULL if input AddressPointerCount is NULL.
+
+**/
+VOID ***
+EFIAPI
+VarCheckLibInitializeAtEndOfDxe (
+ IN OUT UINTN *AddressPointerCount OPTIONAL
+ )
+{
+ VOID *TempTable;
+ UINTN TotalCount;
+ UINTN Index;
+
+ for (Index = 0; Index < mVarCheckLibEndOfDxeCallbackCount; Index++) {
+ //
+ // Invoke the callback registered by VarCheckLibRegisterEndOfDxeCallback().
+ //
+ mVarCheckLibEndOfDxeCallback[Index] ();
+ }
+ if (mVarCheckLibEndOfDxeCallback != NULL) {
+ //
+ // Free the callback buffer.
+ //
+ mVarCheckLibEndOfDxeCallbackCount = 0;
+ mVarCheckLibEndOfDxeCallbackMaxCount = 0;
+ FreePool ((VOID *) mVarCheckLibEndOfDxeCallback);
+ mVarCheckLibEndOfDxeCallback = NULL;
+ }
+
+ mVarCheckLibEndOfDxe = TRUE;
+
+ if (AddressPointerCount == NULL) {
+ if (mVarCheckLibAddressPointer != NULL) {
+ //
+ // Free the address pointer buffer.
+ //
+ mVarCheckLibAddressPointerCount = 0;
+ mVarCheckLibAddressPointerMaxCount = 0;
+ FreePool ((VOID *) mVarCheckLibAddressPointer);
+ mVarCheckLibAddressPointer = NULL;
+ }
+ return NULL;
+ }
+
+ //
+ // Get the total count needed.
+ // Also cover VarCheckHandler and the entries, and VarCheckVariable and the entries.
+ //
+ TotalCount = mVarCheckLibAddressPointerCount + (mNumberOfVarCheckHandler + 1) + (mNumberOfVarCheckVariable + 1);
+ TempTable = ReallocateRuntimePool (
+ mVarCheckLibAddressPointerMaxCount * sizeof (VOID **),
+ TotalCount * sizeof (VOID **),
+ (VOID *) mVarCheckLibAddressPointer
+ );
+
+ if (TempTable != NULL) {
+ mVarCheckLibAddressPointer = (VOID ***) TempTable;
+
+ //
+ // Cover VarCheckHandler and the entries.
+ //
+ mVarCheckLibAddressPointer[mVarCheckLibAddressPointerCount++] = (VOID **) &mVarCheckHandlerTable;
+ for (Index = 0; Index < mNumberOfVarCheckHandler; Index++) {
+ mVarCheckLibAddressPointer[mVarCheckLibAddressPointerCount++] = (VOID **) &mVarCheckHandlerTable[Index];
+ }
+
+ //
+ // Cover VarCheckVariable and the entries.
+ //
+ mVarCheckLibAddressPointer[mVarCheckLibAddressPointerCount++] = (VOID **) &mVarCheckVariableTable;
+ for (Index = 0; Index < mNumberOfVarCheckVariable; Index++) {
+ mVarCheckLibAddressPointer[mVarCheckLibAddressPointerCount++] = (VOID **) &mVarCheckVariableTable[Index];
+ }
+
+ ASSERT (mVarCheckLibAddressPointerCount == TotalCount);
+ mVarCheckLibAddressPointerMaxCount = mVarCheckLibAddressPointerCount;
+ }
+
+ *AddressPointerCount = mVarCheckLibAddressPointerCount;
+ return mVarCheckLibAddressPointer;
+}
+
+/**
+ Register address pointer.
+ The AddressPointer may be returned by VarCheckLibInitializeAtEndOfDxe().
+
+ @param[in] AddressPointer Address pointer.
+
+ @retval EFI_SUCCESS The address pointer was registered successfully.
+ @retval EFI_INVALID_PARAMETER AddressPointer is NULL.
+ @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
+ already been signaled.
+ @retval EFI_OUT_OF_RESOURCES There is not enough resource for the address pointer register request.
+
+**/
+EFI_STATUS
+EFIAPI
+VarCheckLibRegisterAddressPointer (
+ IN VOID **AddressPointer
+ )
+{
+ EFI_STATUS Status;
+
+ if (AddressPointer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (mVarCheckLibEndOfDxe) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ Status = VarCheckAddTableEntry(
+ (UINTN **) &mVarCheckLibAddressPointer,
+ &mVarCheckLibAddressPointerMaxCount,
+ &mVarCheckLibAddressPointerCount,
+ (UINTN) AddressPointer
+ );
+
+ DEBUG ((EFI_D_INFO, "VarCheckLibRegisterAddressPointer - 0x%x %r\n", AddressPointer, Status));
+
+ return Status;
+}
+
+/**
+ Register SetVariable check handler.
+
+ @param[in] Handler Pointer to check handler.
+
+ @retval EFI_SUCCESS The SetVariable check handler was registered successfully.
+ @retval EFI_INVALID_PARAMETER Handler is NULL.
+ @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
+ already been signaled.
+ @retval EFI_OUT_OF_RESOURCES There is not enough resource for the SetVariable check handler register request.
+ @retval EFI_UNSUPPORTED This interface is not implemented.
+ For example, it is unsupported in VarCheck protocol if both VarCheck and SmmVarCheck protocols are present.
+
+**/
+EFI_STATUS
+EFIAPI
+VarCheckLibRegisterSetVariableCheckHandler (
+ IN VAR_CHECK_SET_VARIABLE_CHECK_HANDLER Handler
+ )
+{
+ EFI_STATUS Status;
+
+ if (Handler == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (mVarCheckLibEndOfDxe) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ Status = VarCheckAddTableEntry(
+ (UINTN **) &mVarCheckHandlerTable,
+ &mMaxNumberOfVarCheckHandler,
+ &mNumberOfVarCheckHandler,
+ (UINTN) Handler
+ );
+
+ DEBUG ((EFI_D_INFO, "VarCheckLibRegisterSetVariableCheckHandler - 0x%x %r\n", Handler, Status));
+
+ return Status;
+}
+
+/**
+ Variable property set.
+
+ @param[in] Name Pointer to the variable name.
+ @param[in] Guid Pointer to the vendor GUID.
+ @param[in] VariableProperty Pointer to the input variable property.
+
+ @retval EFI_SUCCESS The property of variable specified by the Name and Guid was set successfully.
+ @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string,
+ or the fields of VariableProperty are not valid.
+ @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
+ already been signaled.
+ @retval EFI_OUT_OF_RESOURCES There is not enough resource for the variable property set request.
+
+**/
+EFI_STATUS
+EFIAPI
+VarCheckLibVariablePropertySet (
+ IN CHAR16 *Name,
+ IN EFI_GUID *Guid,
+ IN VAR_CHECK_VARIABLE_PROPERTY *VariableProperty
+ )
+{
+ EFI_STATUS Status;
+ VAR_CHECK_VARIABLE_ENTRY *Entry;
+ CHAR16 *VariableName;
+ VAR_CHECK_VARIABLE_PROPERTY *Property;
+
+ if (Name == NULL || Name[0] == 0 || Guid == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (VariableProperty == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (VariableProperty->Revision != VAR_CHECK_VARIABLE_PROPERTY_REVISION) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (mVarCheckLibEndOfDxe) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ Status = EFI_SUCCESS;
+
+ //
+ // Get the pointer of property data for set.
+ //
+ Property = VariablePropertyGetFunction (Name, Guid, FALSE);
+ if (Property != NULL) {
+ CopyMem (Property, VariableProperty, sizeof (*VariableProperty));
+ } else {
+ Entry = AllocateRuntimeZeroPool (sizeof (*Entry) + StrSize (Name));
+ if (Entry == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ VariableName = (CHAR16 *) ((UINTN) Entry + sizeof (*Entry));
+ StrCpyS (VariableName, StrSize (Name)/sizeof (CHAR16), Name);
+ CopyGuid (&Entry->Guid, Guid);
+ CopyMem (&Entry->VariableProperty, VariableProperty, sizeof (*VariableProperty));
+
+ Status = VarCheckAddTableEntry(
+ (UINTN **) &mVarCheckVariableTable,
+ &mMaxNumberOfVarCheckVariable,
+ &mNumberOfVarCheckVariable,
+ (UINTN) Entry
+ );
+
+ if (EFI_ERROR (Status)) {
+ FreePool (Entry);
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Variable property get.
+
+ @param[in] Name Pointer to the variable name.
+ @param[in] Guid Pointer to the vendor GUID.
+ @param[out] VariableProperty Pointer to the output variable property.
+
+ @retval EFI_SUCCESS The property of variable specified by the Name and Guid was got successfully.
+ @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string.
+ @retval EFI_NOT_FOUND The property of variable specified by the Name and Guid was not found.
+
+**/
+EFI_STATUS
+EFIAPI
+VarCheckLibVariablePropertyGet (
+ IN CHAR16 *Name,
+ IN EFI_GUID *Guid,
+ OUT VAR_CHECK_VARIABLE_PROPERTY *VariableProperty
+ )
+{
+ VAR_CHECK_VARIABLE_PROPERTY *Property;
+
+ if (Name == NULL || Name[0] == 0 || Guid == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (VariableProperty == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Property = VariablePropertyGetFunction (Name, Guid, TRUE);
+ //
+ // Also check the property revision before using the property data.
+ // There is no property set to this variable(wildcard name)
+ // if the revision is not VAR_CHECK_VARIABLE_PROPERTY_REVISION.
+ //
+ if ((Property != NULL) && (Property->Revision == VAR_CHECK_VARIABLE_PROPERTY_REVISION)) {
+ CopyMem (VariableProperty, Property, sizeof (*VariableProperty));
+ return EFI_SUCCESS;
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ SetVariable check.
+
+ @param[in] VariableName Name of Variable to set.
+ @param[in] VendorGuid Variable vendor GUID.
+ @param[in] Attributes Attribute value of the variable.
+ @param[in] DataSize Size of Data to set.
+ @param[in] Data Data pointer.
+ @param[in] RequestSource Request source.
+
+ @retval EFI_SUCCESS The SetVariable check result was success.
+ @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits, name, GUID,
+ DataSize and Data value was supplied.
+ @retval EFI_WRITE_PROTECTED The variable in question is read-only.
+ @retval Others The other return status from check handler.
+
+**/
+EFI_STATUS
+EFIAPI
+VarCheckLibSetVariableCheck (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN UINT32 Attributes,
+ IN UINTN DataSize,
+ IN VOID *Data,
+ IN VAR_CHECK_REQUEST_SOURCE RequestSource
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ VAR_CHECK_VARIABLE_PROPERTY *Property;
+
+ if (!mVarCheckLibEndOfDxe) {
+ //
+ // Only do check after End Of Dxe.
+ //
+ return EFI_SUCCESS;
+ }
+
+ Property = VariablePropertyGetFunction (VariableName, VendorGuid, TRUE);
+ //
+ // Also check the property revision before using the property data.
+ // There is no property set to this variable(wildcard name)
+ // if the revision is not VAR_CHECK_VARIABLE_PROPERTY_REVISION.
+ //
+ if ((Property != NULL) && (Property->Revision == VAR_CHECK_VARIABLE_PROPERTY_REVISION)) {
+ if ((RequestSource != VarCheckFromTrusted) && ((Property->Property & VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY) != 0)) {
+ DEBUG ((EFI_D_INFO, "Variable Check ReadOnly variable fail %r - %g:%s\n", EFI_WRITE_PROTECTED, VendorGuid, VariableName));
+ return EFI_WRITE_PROTECTED;
+ }
+ if (!((((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) && (DataSize == 0)) || (Attributes == 0))) {
+ //
+ // Not to delete variable.
+ //
+ if ((Property->Attributes != 0) && ((Attributes & (~EFI_VARIABLE_APPEND_WRITE)) != Property->Attributes)) {
+ DEBUG ((EFI_D_INFO, "Variable Check Attributes(0x%08x to 0x%08x) fail %r - %g:%s\n", Property->Attributes, Attributes, EFI_INVALID_PARAMETER, VendorGuid, VariableName));
+ return EFI_INVALID_PARAMETER;
+ }
+ if (DataSize != 0) {
+ if ((DataSize < Property->MinSize) || (DataSize > Property->MaxSize)) {
+ DEBUG ((EFI_D_INFO, "Variable Check DataSize fail(0x%x not in 0x%x - 0x%x) %r - %g:%s\n", DataSize, Property->MinSize, Property->MaxSize, EFI_INVALID_PARAMETER, VendorGuid, VariableName));
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ }
+ }
+
+ for (Index = 0; Index < mNumberOfVarCheckHandler; Index++) {
+ Status = mVarCheckHandlerTable[Index] (
+ VariableName,
+ VendorGuid,
+ Attributes,
+ DataSize,
+ Data
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_INFO, "Variable Check handler fail %r - %g:%s\n", Status, VendorGuid, VariableName));
+ return Status;
+ }
+ }
+ return EFI_SUCCESS;
+}
diff --git a/Core/MdeModulePkg/Library/VarCheckLib/VarCheckLib.inf b/Core/MdeModulePkg/Library/VarCheckLib/VarCheckLib.inf
new file mode 100644
index 0000000000..099f83dd6a
--- /dev/null
+++ b/Core/MdeModulePkg/Library/VarCheckLib/VarCheckLib.inf
@@ -0,0 +1,51 @@
+## @file
+# Provides variable check services and database management.
+#
+# Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions
+# of the BSD License which accompanies this distribution. The
+# full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = VarCheckLib
+ MODULE_UNI_FILE = VarCheckLib.uni
+ FILE_GUID = 63E12D08-0C5D-47F8-95E4-09F89D7506C5
+ MODULE_TYPE = DXE_RUNTIME_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = VarCheckLib|DXE_RUNTIME_DRIVER DXE_SMM_DRIVER
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ VarCheckLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ MemoryAllocationLib
+
+[Guids]
+ ## SOMETIMES_CONSUMES ## Variable:L"Boot####"
+ ## SOMETIMES_CONSUMES ## Variable:L"Driver####"
+ ## SOMETIMES_CONSUMES ## Variable:L"SysPrep####"
+ ## SOMETIMES_CONSUMES ## Variable:L"Key####"
+ gEfiGlobalVariableGuid
+ gEfiHardwareErrorVariableGuid ## SOMETIMES_CONSUMES ## Variable:L"HwErrRec####"
diff --git a/Core/MdeModulePkg/Library/VarCheckLib/VarCheckLib.uni b/Core/MdeModulePkg/Library/VarCheckLib/VarCheckLib.uni
new file mode 100644
index 0000000000..d9761a1103
--- /dev/null
+++ b/Core/MdeModulePkg/Library/VarCheckLib/VarCheckLib.uni
Binary files differ
diff --git a/Core/MdeModulePkg/Library/VarCheckPcdLib/VarCheckPcdLib.inf b/Core/MdeModulePkg/Library/VarCheckPcdLib/VarCheckPcdLib.inf
new file mode 100644
index 0000000000..b9d235be60
--- /dev/null
+++ b/Core/MdeModulePkg/Library/VarCheckPcdLib/VarCheckPcdLib.inf
@@ -0,0 +1,65 @@
+## @file
+# NULL class library to register var check PCD handler.
+#
+# In platform *.fdf, the example build rule for the driver this library linked to.
+# [Rule.Common.DXE_RUNTIME_DRIVER.VARCHECKPCD]
+# FILE DRIVER = $(NAMED_GUID) {
+# RAW BIN $(WORKSPACE)/$(OUTPUT_DIRECTORY)/$(TARGET)_$(TOOL_CHAIN_TAG)/FV/PcdVarCheck.bin
+# DXE_DEPEX DXE_DEPEX Optional $(INF_OUTPUT)/$(MODULE_NAME).depex
+# PE32 PE32 $(INF_OUTPUT)/$(MODULE_NAME).efi
+# UI STRING="$(MODULE_NAME)" Optional
+# VERSION STRING="$(INF_VERSION)" Optional BUILD_NUM=$(BUILD_NUMBER)
+# }
+#
+# or
+#
+# [Rule.Common.DXE_SMM_DRIVER.VARCHECKPCD]
+# FILE SMM = $(NAMED_GUID) {
+# RAW BIN $(WORKSPACE)/$(OUTPUT_DIRECTORY)/$(TARGET)_$(TOOL_CHAIN_TAG)/FV/PcdVarCheck.bin
+# DXE_DEPEX DXE_DEPEX Optional $(INF_OUTPUT)/$(MODULE_NAME).depex
+# PE32 PE32 $(INF_OUTPUT)/$(MODULE_NAME).efi
+# UI STRING="$(MODULE_NAME)" Optional
+# VERSION STRING="$(INF_VERSION)" Optional BUILD_NUM=$(BUILD_NUMBER)
+# }
+#
+# In platform *.dsc, also need add one line below to enable PcdVarCheck.bin generation by BaseTools.
+# PCD_VAR_CHECK_GENERATION = TRUE
+#
+# Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions
+# of the BSD License which accompanies this distribution. The
+# full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = VarCheckPcdLib
+ MODULE_UNI_FILE = VarCheckPcdLib.uni
+ FILE_GUID = D4FA5311-5F1F-4B1E-9AC3-90C4DFC029F1
+ MODULE_TYPE = DXE_RUNTIME_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = NULL|DXE_RUNTIME_DRIVER DXE_SMM_DRIVER
+ CONSTRUCTOR = VarCheckPcdLibNullClassConstructor
+
+[Sources]
+ VarCheckPcdLibNullClass.c
+ VarCheckPcdStructure.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ DebugLib
+ BaseMemoryLib
+ DxeServicesLib
+ MemoryAllocationLib
+ VarCheckLib
diff --git a/Core/MdeModulePkg/Library/VarCheckPcdLib/VarCheckPcdLib.uni b/Core/MdeModulePkg/Library/VarCheckPcdLib/VarCheckPcdLib.uni
new file mode 100644
index 0000000000..4a3d932be9
--- /dev/null
+++ b/Core/MdeModulePkg/Library/VarCheckPcdLib/VarCheckPcdLib.uni
Binary files differ
diff --git a/Core/MdeModulePkg/Library/VarCheckPcdLib/VarCheckPcdLibNullClass.c b/Core/MdeModulePkg/Library/VarCheckPcdLib/VarCheckPcdLibNullClass.c
new file mode 100644
index 0000000000..72b0363b19
--- /dev/null
+++ b/Core/MdeModulePkg/Library/VarCheckPcdLib/VarCheckPcdLibNullClass.c
@@ -0,0 +1,474 @@
+/** @file
+ Var Check PCD handler.
+
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Library/VarCheckLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DxeServicesLib.h>
+
+#include "VarCheckPcdStructure.h"
+
+//#define DUMP_VAR_CHECK_PCD
+
+GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 mVarCheckPcdHex[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
+
+/**
+ Dump some hexadecimal data.
+
+ @param[in] Indent How many spaces to indent the output.
+ @param[in] Offset The offset of the dump.
+ @param[in] DataSize The size in bytes of UserData.
+ @param[in] UserData The data to dump.
+
+**/
+VOID
+VarCheckPcdInternalDumpHex (
+ IN UINTN Indent,
+ IN UINTN Offset,
+ IN UINTN DataSize,
+ IN VOID *UserData
+ )
+{
+ UINT8 *Data;
+
+ CHAR8 Val[50];
+
+ CHAR8 Str[20];
+
+ UINT8 TempByte;
+ UINTN Size;
+ UINTN Index;
+
+ Data = UserData;
+ while (DataSize != 0) {
+ Size = 16;
+ if (Size > DataSize) {
+ Size = DataSize;
+ }
+
+ for (Index = 0; Index < Size; Index += 1) {
+ TempByte = Data[Index];
+ Val[Index * 3 + 0] = mVarCheckPcdHex[TempByte >> 4];
+ Val[Index * 3 + 1] = mVarCheckPcdHex[TempByte & 0xF];
+ Val[Index * 3 + 2] = (CHAR8) ((Index == 7) ? '-' : ' ');
+ Str[Index] = (CHAR8) ((TempByte < ' ' || TempByte > 'z') ? '.' : TempByte);
+ }
+
+ Val[Index * 3] = 0;
+ Str[Index] = 0;
+ DEBUG ((EFI_D_INFO, "%*a%08X: %-48a *%a*\r\n", Indent, "", Offset, Val, Str));
+
+ Data += Size;
+ Offset += Size;
+ DataSize -= Size;
+ }
+}
+
+/**
+ Var Check Pcd ValidData.
+
+ @param[in] PcdValidData Pointer to Pcd ValidData
+ @param[in] Data Data pointer.
+ @param[in] DataSize Size of Data to set.
+
+ @retval TRUE Check pass
+ @retval FALSE Check fail.
+
+**/
+BOOLEAN
+VarCheckPcdValidData (
+ IN VAR_CHECK_PCD_VALID_DATA_HEADER *PcdValidData,
+ IN VOID *Data,
+ IN UINTN DataSize
+ )
+{
+ UINT64 OneData;
+ UINT64 Minimum;
+ UINT64 Maximum;
+ UINT64 OneValue;
+ UINT8 *Ptr;
+
+ OneData = 0;
+ CopyMem (&OneData, (UINT8 *) Data + PcdValidData->VarOffset, PcdValidData->StorageWidth);
+
+ switch (PcdValidData->Type) {
+ case VarCheckPcdValidList:
+ Ptr = (UINT8 *) ((VAR_CHECK_PCD_VALID_LIST *) PcdValidData + 1);
+ while ((UINTN) Ptr < (UINTN) PcdValidData + PcdValidData->Length) {
+ OneValue = 0;
+ CopyMem (&OneValue, Ptr, PcdValidData->StorageWidth);
+ if (OneData == OneValue) {
+ //
+ // Match
+ //
+ break;
+ }
+ Ptr += PcdValidData->StorageWidth;
+ }
+ if ((UINTN) Ptr >= ((UINTN) PcdValidData + PcdValidData->Length)) {
+ //
+ // No match
+ //
+ DEBUG ((EFI_D_INFO, "VarCheckPcdValidData fail: ValidList mismatch (0x%lx)\n", OneData));
+ DEBUG_CODE (VarCheckPcdInternalDumpHex (2, 0, PcdValidData->Length, (UINT8 *) PcdValidData););
+ return FALSE;
+ }
+ break;
+
+ case VarCheckPcdValidRange:
+ Minimum = 0;
+ Maximum = 0;
+ Ptr = (UINT8 *) ((VAR_CHECK_PCD_VALID_RANGE *) PcdValidData + 1);
+ while ((UINTN) Ptr < (UINTN) PcdValidData + PcdValidData->Length) {
+ CopyMem (&Minimum, Ptr, PcdValidData->StorageWidth);
+ Ptr += PcdValidData->StorageWidth;
+ CopyMem (&Maximum, Ptr, PcdValidData->StorageWidth);
+ Ptr += PcdValidData->StorageWidth;
+
+ if ((OneData >= Minimum) && (OneData <= Maximum)) {
+ return TRUE;
+ }
+ }
+ DEBUG ((EFI_D_INFO, "VarCheckPcdValidData fail: ValidRange mismatch (0x%lx)\n", OneData));
+ DEBUG_CODE (VarCheckPcdInternalDumpHex (2, 0, PcdValidData->Length, (UINT8 *) PcdValidData););
+ return FALSE;
+ break;
+
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+
+ return TRUE;
+}
+
+VAR_CHECK_PCD_VARIABLE_HEADER *mVarCheckPcdBin = NULL;
+UINTN mVarCheckPcdBinSize = 0;
+
+/**
+ SetVariable check handler PCD.
+
+ @param[in] VariableName Name of Variable to set.
+ @param[in] VendorGuid Variable vendor GUID.
+ @param[in] Attributes Attribute value of the variable.
+ @param[in] DataSize Size of Data to set.
+ @param[in] Data Data pointer.
+
+ @retval EFI_SUCCESS The SetVariable check result was success.
+ @retval EFI_SECURITY_VIOLATION Check fail.
+
+**/
+EFI_STATUS
+EFIAPI
+SetVariableCheckHandlerPcd (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN UINT32 Attributes,
+ IN UINTN DataSize,
+ IN VOID *Data
+ )
+{
+ VAR_CHECK_PCD_VARIABLE_HEADER *PcdVariable;
+ VAR_CHECK_PCD_VALID_DATA_HEADER *PcdValidData;
+
+ if (mVarCheckPcdBin == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ if ((((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) && (DataSize == 0)) || (Attributes == 0)) {
+ //
+ // Do not check delete variable.
+ //
+ return EFI_SUCCESS;
+ }
+
+ //
+ // For Pcd Variable header align.
+ //
+ PcdVariable = (VAR_CHECK_PCD_VARIABLE_HEADER *) HEADER_ALIGN (mVarCheckPcdBin);
+ while ((UINTN) PcdVariable < ((UINTN) mVarCheckPcdBin + mVarCheckPcdBinSize)) {
+ if ((StrCmp ((CHAR16 *) (PcdVariable + 1), VariableName) == 0) &&
+ (CompareGuid (&PcdVariable->Guid, VendorGuid))) {
+ //
+ // Found the Pcd Variable that could be used to do check.
+ //
+ DEBUG ((EFI_D_INFO, "VarCheckPcdVariable - %s:%g with Attributes = 0x%08x Size = 0x%x\n", VariableName, VendorGuid, Attributes, DataSize));
+ if ((PcdVariable->Attributes != 0) && PcdVariable->Attributes != Attributes) {
+ DEBUG ((EFI_D_INFO, "VarCheckPcdVariable fail for Attributes - 0x%08x\n", PcdVariable->Attributes));
+ return EFI_SECURITY_VIOLATION;
+ }
+
+ if (DataSize == 0) {
+ DEBUG ((EFI_D_INFO, "VarCheckPcdVariable - CHECK PASS with DataSize == 0 !\n"));
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Do the check.
+ // For Pcd ValidData header align.
+ //
+ PcdValidData = (VAR_CHECK_PCD_VALID_DATA_HEADER *) HEADER_ALIGN (((UINTN) PcdVariable + PcdVariable->HeaderLength));
+ while ((UINTN) PcdValidData < ((UINTN) PcdVariable + PcdVariable->Length)) {
+ if (((UINTN) PcdValidData->VarOffset + PcdValidData->StorageWidth) <= DataSize) {
+ if (!VarCheckPcdValidData (PcdValidData, Data, DataSize)) {
+ return EFI_SECURITY_VIOLATION;
+ }
+ }
+ //
+ // For Pcd ValidData header align.
+ //
+ PcdValidData = (VAR_CHECK_PCD_VALID_DATA_HEADER *) HEADER_ALIGN (((UINTN) PcdValidData + PcdValidData->Length));
+ }
+
+ DEBUG ((EFI_D_INFO, "VarCheckPcdVariable - ALL CHECK PASS!\n"));
+ return EFI_SUCCESS;
+ }
+ //
+ // For Pcd Variable header align.
+ //
+ PcdVariable = (VAR_CHECK_PCD_VARIABLE_HEADER *) HEADER_ALIGN (((UINTN) PcdVariable + PcdVariable->Length));
+ }
+
+ // Not found, so pass.
+ return EFI_SUCCESS;
+}
+
+#ifdef DUMP_VAR_CHECK_PCD
+/**
+ Dump Pcd ValidData.
+
+ @param[in] PcdValidData Pointer to Pcd ValidData.
+
+**/
+VOID
+DumpPcdValidData (
+ IN VAR_CHECK_PCD_VALID_DATA_HEADER *PcdValidData
+ )
+{
+ UINT64 Minimum;
+ UINT64 Maximum;
+ UINT64 OneValue;
+ UINT8 *Ptr;
+
+ DEBUG ((EFI_D_INFO, " VAR_CHECK_PCD_VALID_DATA_HEADER\n"));
+ DEBUG ((EFI_D_INFO, " Type - 0x%02x\n", PcdValidData->Type));
+ DEBUG ((EFI_D_INFO, " Length - 0x%02x\n", PcdValidData->Length));
+ DEBUG ((EFI_D_INFO, " VarOffset - 0x%04x\n", PcdValidData->VarOffset));
+ DEBUG ((EFI_D_INFO, " StorageWidth - 0x%02x\n", PcdValidData->StorageWidth));
+
+ switch (PcdValidData->Type) {
+ case VarCheckPcdValidList:
+ Ptr = (UINT8 *) ((VAR_CHECK_PCD_VALID_LIST *) PcdValidData + 1);
+ while ((UINTN) Ptr < ((UINTN) PcdValidData + PcdValidData->Length)) {
+ OneValue = 0;
+ CopyMem (&OneValue, Ptr, PcdValidData->StorageWidth);
+ switch (PcdValidData->StorageWidth) {
+ case sizeof (UINT8):
+ DEBUG ((EFI_D_INFO, " ValidList - 0x%02x\n", OneValue));
+ break;
+ case sizeof (UINT16):
+ DEBUG ((EFI_D_INFO, " ValidList - 0x%04x\n", OneValue));
+ break;
+ case sizeof (UINT32):
+ DEBUG ((EFI_D_INFO, " ValidList - 0x%08x\n", OneValue));
+ break;
+ case sizeof (UINT64):
+ DEBUG ((EFI_D_INFO, " ValidList - 0x%016lx\n", OneValue));
+ break;
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+ Ptr += PcdValidData->StorageWidth;
+ }
+ break;
+
+ case VarCheckPcdValidRange:
+ Minimum = 0;
+ Maximum = 0;
+ Ptr = (UINT8 *) ((VAR_CHECK_PCD_VALID_RANGE *) PcdValidData + 1);
+ while ((UINTN) Ptr < (UINTN) PcdValidData + PcdValidData->Length) {
+ CopyMem (&Minimum, Ptr, PcdValidData->StorageWidth);
+ Ptr += PcdValidData->StorageWidth;
+ CopyMem (&Maximum, Ptr, PcdValidData->StorageWidth);
+ Ptr += PcdValidData->StorageWidth;
+
+ switch (PcdValidData->StorageWidth) {
+ case sizeof (UINT8):
+ DEBUG ((EFI_D_INFO, " Minimum - 0x%02x\n", Minimum));
+ DEBUG ((EFI_D_INFO, " Maximum - 0x%02x\n", Maximum));
+ break;
+ case sizeof (UINT16):
+ DEBUG ((EFI_D_INFO, " Minimum - 0x%04x\n", Minimum));
+ DEBUG ((EFI_D_INFO, " Maximum - 0x%04x\n", Maximum));
+ break;
+ case sizeof (UINT32):
+ DEBUG ((EFI_D_INFO, " Minimum - 0x%08x\n", Minimum));
+ DEBUG ((EFI_D_INFO, " Maximum - 0x%08x\n", Maximum));
+ break;
+ case sizeof (UINT64):
+ DEBUG ((EFI_D_INFO, " Minimum - 0x%016lx\n", Minimum));
+ DEBUG ((EFI_D_INFO, " Maximum - 0x%016lx\n", Maximum));
+ break;
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+ }
+ break;
+
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+}
+
+/**
+ Dump Pcd Variable.
+
+ @param[in] PcdVariable Pointer to Pcd Variable.
+
+**/
+VOID
+DumpPcdVariable (
+ IN VAR_CHECK_PCD_VARIABLE_HEADER *PcdVariable
+ )
+{
+ VAR_CHECK_PCD_VALID_DATA_HEADER *PcdValidData;
+
+ DEBUG ((EFI_D_INFO, "VAR_CHECK_PCD_VARIABLE_HEADER\n"));
+ DEBUG ((EFI_D_INFO, " Revision - 0x%04x\n", PcdVariable->Revision));
+ DEBUG ((EFI_D_INFO, " HeaderLength - 0x%04x\n", PcdVariable->HeaderLength));
+ DEBUG ((EFI_D_INFO, " Length - 0x%08x\n", PcdVariable->Length));
+ DEBUG ((EFI_D_INFO, " Type - 0x%02x\n", PcdVariable->Type));
+ DEBUG ((EFI_D_INFO, " Attributes - 0x%08x\n", PcdVariable->Attributes));
+ DEBUG ((EFI_D_INFO, " Guid - %g\n", &PcdVariable->Guid));
+ DEBUG ((EFI_D_INFO, " Name - %s\n", PcdVariable + 1));
+
+ //
+ // For Pcd ValidData header align.
+ //
+ PcdValidData = (VAR_CHECK_PCD_VALID_DATA_HEADER *) HEADER_ALIGN (((UINTN) PcdVariable + PcdVariable->HeaderLength));
+ while ((UINTN) PcdValidData < ((UINTN) PcdVariable + PcdVariable->Length)) {
+ //
+ // Dump Pcd ValidData related to the Pcd Variable.
+ //
+ DumpPcdValidData (PcdValidData);
+ //
+ // For Pcd ValidData header align.
+ //
+ PcdValidData = (VAR_CHECK_PCD_VALID_DATA_HEADER *) HEADER_ALIGN (((UINTN) PcdValidData + PcdValidData->Length));
+ }
+}
+
+/**
+ Dump Var Check PCD.
+
+ @param[in] VarCheckPcdBin Pointer to VarCheckPcdBin.
+ @param[in] VarCheckPcdBinSize VarCheckPcdBin size.
+
+**/
+VOID
+DumpVarCheckPcd (
+ IN VOID *VarCheckPcdBin,
+ IN UINTN VarCheckPcdBinSize
+ )
+{
+ VAR_CHECK_PCD_VARIABLE_HEADER *PcdVariable;
+
+ DEBUG ((EFI_D_INFO, "DumpVarCheckPcd\n"));
+
+ //
+ // For Pcd Variable header align.
+ //
+ PcdVariable = (VAR_CHECK_PCD_VARIABLE_HEADER *) HEADER_ALIGN (VarCheckPcdBin);
+ while ((UINTN) PcdVariable < ((UINTN) VarCheckPcdBin + VarCheckPcdBinSize)) {
+ DumpPcdVariable (PcdVariable);
+ //
+ // For Pcd Variable header align.
+ //
+ PcdVariable = (VAR_CHECK_PCD_VARIABLE_HEADER *) HEADER_ALIGN (((UINTN) PcdVariable + PcdVariable->Length));
+ }
+}
+#endif
+
+/**
+ Locate VarCheckPcdBin.
+
+**/
+VOID
+EFIAPI
+LocateVarCheckPcdBin (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ VAR_CHECK_PCD_VARIABLE_HEADER *VarCheckPcdBin;
+ UINTN VarCheckPcdBinSize;
+
+ //
+ // Search the VarCheckPcdBin from the first RAW section of current FFS.
+ //
+ Status = GetSectionFromFfs (
+ EFI_SECTION_RAW,
+ 0,
+ (VOID **) &VarCheckPcdBin,
+ &VarCheckPcdBinSize
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // AllocateRuntimeZeroPool () from MemoryAllocateLib is used for runtime access
+ // in SetVariable check handler.
+ //
+ mVarCheckPcdBin = AllocateRuntimeCopyPool (VarCheckPcdBinSize, VarCheckPcdBin);
+ ASSERT (mVarCheckPcdBin != NULL);
+ mVarCheckPcdBinSize = VarCheckPcdBinSize;
+ FreePool (VarCheckPcdBin);
+
+ DEBUG ((EFI_D_INFO, "VarCheckPcdBin - at 0x%x size = 0x%x\n", mVarCheckPcdBin, mVarCheckPcdBinSize));
+
+#ifdef DUMP_VAR_CHECK_PCD
+ DEBUG_CODE (
+ DumpVarCheckPcd (mVarCheckPcdBin, mVarCheckPcdBinSize);
+ );
+#endif
+ } else {
+ DEBUG ((EFI_D_INFO, "[VarCheckPcd] No VarCheckPcdBin found at the first RAW section\n"));
+ }
+}
+
+/**
+ Constructor function of VarCheckPcdLib to register var check PCD handler.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The constructor executed correctly.
+
+**/
+EFI_STATUS
+EFIAPI
+VarCheckPcdLibNullClassConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ LocateVarCheckPcdBin ();
+ VarCheckLibRegisterAddressPointer ((VOID **) &mVarCheckPcdBin);
+ VarCheckLibRegisterSetVariableCheckHandler (SetVariableCheckHandlerPcd);
+
+ return EFI_SUCCESS;
+}
diff --git a/Core/MdeModulePkg/Library/VarCheckPcdLib/VarCheckPcdStructure.h b/Core/MdeModulePkg/Library/VarCheckPcdLib/VarCheckPcdStructure.h
new file mode 100644
index 0000000000..8180bc5cfd
--- /dev/null
+++ b/Core/MdeModulePkg/Library/VarCheckPcdLib/VarCheckPcdStructure.h
@@ -0,0 +1,76 @@
+/** @file
+ Internal structure for Var Check Pcd.
+
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _VAR_CHECK_STRUCTURE_H_
+#define _VAR_CHECK_STRUCTURE_H_
+
+//
+// Alignment for PCD Variable and check data header.
+//
+#define HEADER_ALIGNMENT 4
+#define HEADER_ALIGN(Header) (((UINTN) (Header) + HEADER_ALIGNMENT - 1) & (~(HEADER_ALIGNMENT - 1)))
+
+#pragma pack (1)
+
+#define VAR_CHECK_PCD_REVISION 0x0001
+
+typedef enum {
+ VarCheckPcdVariableHeader,
+ VarCheckPcdValidList,
+ VarCheckPcdValidRange,
+ VarCheckPcdCheckTypeMax,
+} VAR_CHECK_PCD_CHECK_TYPE;
+
+typedef struct {
+ UINT16 Revision;
+ UINT16 HeaderLength;
+ UINT32 Length; // Length include this header
+ UINT8 Type;
+ UINT8 Reserved[3];
+ UINT32 Attributes;
+ EFI_GUID Guid;
+//CHAR16 Name[];
+} VAR_CHECK_PCD_VARIABLE_HEADER;
+
+typedef struct {
+ UINT8 Type;
+ UINT8 Length; // Length include this header
+ UINT16 VarOffset;
+ UINT8 StorageWidth;
+} VAR_CHECK_PCD_VALID_DATA_HEADER;
+
+typedef struct {
+ UINT8 Type;
+ UINT8 Length; // Length include this header
+ UINT16 VarOffset;
+ UINT8 StorageWidth;
+//UINTx Data[]; // x = UINT8/UINT16/UINT32/UINT64;
+} VAR_CHECK_PCD_VALID_LIST;
+
+//typedef struct {
+// UINTx Minimum; // x = UINT8/UINT16/UINT32/UINT64
+// UINTx Maximum; // x = UINT8/UINT16/UINT32/UINT64
+//} VAR_CHECK_PCD_VALID_RANGE_DATA;
+
+typedef struct {
+ UINT8 Type;
+ UINT8 Length; // Length include this header
+ UINT16 VarOffset;
+ UINT8 StorageWidth;
+// VAR_CHECK_PCD_VALID_RANGE_DATA ValidRange[];
+} VAR_CHECK_PCD_VALID_RANGE;
+
+#pragma pack ()
+
+#endif \ No newline at end of file
diff --git a/Core/MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLib.inf b/Core/MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLib.inf
new file mode 100644
index 0000000000..77ef210fb2
--- /dev/null
+++ b/Core/MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLib.inf
@@ -0,0 +1,88 @@
+## @file
+# NULL class library to register var check handler and variable property set for UEFI defined variables.
+#
+# Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions
+# of the BSD License which accompanies this distribution. The
+# full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = VarCheckUefiLib
+ MODULE_UNI_FILE = VarCheckUefiLib.uni
+ FILE_GUID = AC24A4C7-F845-4665-90E5-6431D6E28DC0
+ MODULE_TYPE = DXE_RUNTIME_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = NULL|DXE_RUNTIME_DRIVER DXE_SMM_DRIVER
+ CONSTRUCTOR = VarCheckUefiLibNullClassConstructor
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ VarCheckUefiLibNullClass.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ DevicePathLib
+ VarCheckLib
+
+[Guids]
+ ## CONSUMES ## Variable:L"LangCodes"
+ ## CONSUMES ## Variable:L"Lang"
+ ## CONSUMES ## Variable:L"Timeout"
+ ## CONSUMES ## Variable:L"PlatformLangCodes"
+ ## CONSUMES ## Variable:L"PlatformLang"
+ ## CONSUMES ## Variable:L"ConIn"
+ ## CONSUMES ## Variable:L"ConOut"
+ ## CONSUMES ## Variable:L"ErrOut"
+ ## CONSUMES ## Variable:L"ConInDev"
+ ## CONSUMES ## Variable:L"ConOutDev"
+ ## CONSUMES ## Variable:L"ErrOutDev"
+ ## CONSUMES ## Variable:L"BootOrder"
+ ## CONSUMES ## Variable:L"BootNext"
+ ## CONSUMES ## Variable:L"BootCurrent"
+ ## CONSUMES ## Variable:L"BootOptionSupport"
+ ## CONSUMES ## Variable:L"DriverOrder"
+ ## CONSUMES ## Variable:L"SysPrepOrder"
+ ## CONSUMES ## Variable:L"HwErrRecSupport"
+ ## CONSUMES ## Variable:L"SetupMode"
+ ## CONSUMES ## Variable:L"PK"
+ ## CONSUMES ## Variable:L"KEK"
+ ## CONSUMES ## Variable:L"SignatureSupport"
+ ## CONSUMES ## Variable:L"SecureBoot"
+ ## CONSUMES ## Variable:L"KEKDefault"
+ ## CONSUMES ## Variable:L"PKDefault"
+ ## CONSUMES ## Variable:L"dbDefault"
+ ## CONSUMES ## Variable:L"dbxDefault"
+ ## CONSUMES ## Variable:L"dbtDefault"
+ ## CONSUMES ## Variable:L"OsIndicationsSupported"
+ ## CONSUMES ## Variable:L"OsIndications"
+ ## CONSUMES ## Variable:L"VendorKeys"
+ ## CONSUMES ## Variable:L"Boot####"
+ ## CONSUMES ## Variable:L"Driver####"
+ ## CONSUMES ## Variable:L"SysPrep####"
+ ## CONSUMES ## Variable:L"Key####"
+ gEfiGlobalVariableGuid
+ ## CONSUMES ## Variable:L"DB"
+ ## CONSUMES ## Variable:L"DBX"
+ ## CONSUMES ## Variable:L"DBT"
+ gEfiImageSecurityDatabaseGuid
+ gEfiHardwareErrorVariableGuid ## CONSUMES ## Variable:L"HwErrRec####"
diff --git a/Core/MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLib.uni b/Core/MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLib.uni
new file mode 100644
index 0000000000..a18cbfa5a8
--- /dev/null
+++ b/Core/MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLib.uni
Binary files differ
diff --git a/Core/MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLibNullClass.c b/Core/MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLibNullClass.c
new file mode 100644
index 0000000000..15144bd4c0
--- /dev/null
+++ b/Core/MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLibNullClass.c
@@ -0,0 +1,930 @@
+/** @file
+ Implementation functions and structures for var check uefi library.
+
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Library/VarCheckLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DevicePathLib.h>
+
+#include <Guid/VariableFormat.h>
+#include <Guid/GlobalVariable.h>
+#include <Guid/HardwareErrorVariable.h>
+#include <Guid/ImageAuthentication.h>
+
+typedef
+EFI_STATUS
+(EFIAPI *INTERNAL_VAR_CHECK_FUNCTION) (
+ IN VAR_CHECK_VARIABLE_PROPERTY *Propery,
+ IN UINTN DataSize,
+ IN VOID *Data
+ );
+
+typedef struct {
+ CHAR16 *Name;
+ VAR_CHECK_VARIABLE_PROPERTY VariableProperty;
+ INTERNAL_VAR_CHECK_FUNCTION CheckFunction;
+} UEFI_DEFINED_VARIABLE_ENTRY;
+
+/**
+ Internal check for load option.
+
+ @param[in] VariablePropery Pointer to variable property.
+ @param[in] DataSize Data size.
+ @param[in] Data Pointer to data buffer.
+
+ @retval EFI_SUCCESS The SetVariable check result was success.
+ @retval EFI_INVALID_PARAMETER The data buffer is not a valid load option.
+
+**/
+EFI_STATUS
+EFIAPI
+InternalVarCheckLoadOption (
+ IN VAR_CHECK_VARIABLE_PROPERTY *VariablePropery,
+ IN UINTN DataSize,
+ IN VOID *Data
+ )
+{
+ UINT16 FilePathListLength;
+ CHAR16 *Description;
+ EFI_DEVICE_PATH_PROTOCOL *FilePathList;
+
+ FilePathListLength = *((UINT16 *) ((UINTN) Data + sizeof (UINT32)));
+
+ //
+ // Check Description
+ //
+ Description = (CHAR16 *) ((UINTN) Data + sizeof (UINT32) + sizeof (UINT16));
+ while (Description < (CHAR16 *) ((UINTN) Data + DataSize)) {
+ if (*Description == L'\0') {
+ break;
+ }
+ Description++;
+ }
+ if ((UINTN) Description >= ((UINTN) Data + DataSize)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ Description++;
+
+ //
+ // Check FilePathList
+ //
+ FilePathList = (EFI_DEVICE_PATH_PROTOCOL *) Description;
+ if ((UINTN) FilePathList > (MAX_ADDRESS - FilePathListLength)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (((UINTN) FilePathList + FilePathListLength) > ((UINTN) Data + DataSize)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (FilePathListLength < sizeof (EFI_DEVICE_PATH_PROTOCOL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (!IsDevicePathValid (FilePathList, FilePathListLength)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Internal check for key option.
+
+ @param[in] VariablePropery Pointer to variable property.
+ @param[in] DataSize Data size.
+ @param[in] Data Pointer to data buffer.
+
+ @retval EFI_SUCCESS The SetVariable check result was success.
+ @retval EFI_INVALID_PARAMETER The data buffer is not a valid key option.
+
+**/
+EFI_STATUS
+EFIAPI
+InternalVarCheckKeyOption (
+ IN VAR_CHECK_VARIABLE_PROPERTY *VariablePropery,
+ IN UINTN DataSize,
+ IN VOID *Data
+ )
+{
+ if (((DataSize - sizeof (EFI_KEY_OPTION)) % sizeof (EFI_INPUT_KEY)) != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Internal check for device path.
+
+ @param[in] VariablePropery Pointer to variable property.
+ @param[in] DataSize Data size.
+ @param[in] Data Pointer to data buffer.
+
+ @retval EFI_SUCCESS The SetVariable check result was success.
+ @retval EFI_INVALID_PARAMETER The data buffer is not a valid device path.
+
+**/
+EFI_STATUS
+EFIAPI
+InternalVarCheckDevicePath (
+ IN VAR_CHECK_VARIABLE_PROPERTY *VariablePropery,
+ IN UINTN DataSize,
+ IN VOID *Data
+ )
+{
+ if (!IsDevicePathValid ((EFI_DEVICE_PATH_PROTOCOL *) Data, DataSize)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Internal check for ASCII string.
+
+ @param[in] VariablePropery Pointer to variable property.
+ @param[in] DataSize Data size.
+ @param[in] Data Pointer to data buffer.
+
+ @retval EFI_SUCCESS The SetVariable check result was success.
+ @retval EFI_INVALID_PARAMETER The data buffer is not a Null-terminated ASCII string.
+
+**/
+EFI_STATUS
+EFIAPI
+InternalVarCheckAsciiString (
+ IN VAR_CHECK_VARIABLE_PROPERTY *VariablePropery,
+ IN UINTN DataSize,
+ IN VOID *Data
+ )
+{
+ CHAR8 *String;
+ UINTN Index;
+
+ String = (CHAR8 *) Data;
+ if (String[DataSize - 1] == '\0') {
+ return EFI_SUCCESS;
+ } else {
+ for (Index = 1; Index < DataSize && (String[DataSize - 1 - Index] != '\0'); Index++);
+ if (Index == DataSize) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Internal check for size array.
+
+ @param[in] VariablePropery Pointer to variable property.
+ @param[in] DataSize Data size.
+ @param[in] Data Pointer to data buffer.
+
+ @retval EFI_SUCCESS The SetVariable check result was success.
+ @retval EFI_INVALID_PARAMETER The DataSize is not size array.
+
+**/
+EFI_STATUS
+EFIAPI
+InternalVarCheckSizeArray (
+ IN VAR_CHECK_VARIABLE_PROPERTY *VariablePropery,
+ IN UINTN DataSize,
+ IN VOID *Data
+ )
+{
+ if ((DataSize % VariablePropery->MinSize) != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+ return EFI_SUCCESS;
+}
+
+//
+// To prevent name collisions with possible future globally defined variables,
+// other internal firmware data variables that are not defined here must be
+// saved with a unique VendorGuid other than EFI_GLOBAL_VARIABLE or
+// any other GUID defined by the UEFI Specification. Implementations must
+// only permit the creation of variables with a UEFI Specification-defined
+// VendorGuid when these variables are documented in the UEFI Specification.
+//
+UEFI_DEFINED_VARIABLE_ENTRY mGlobalVariableList[] = {
+ {
+ EFI_LANG_CODES_VARIABLE_NAME,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ 0,
+ VARIABLE_ATTRIBUTE_BS_RT,
+ 1,
+ MAX_UINTN
+ },
+ InternalVarCheckAsciiString
+ },
+ {
+ EFI_LANG_VARIABLE_NAME,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ 0,
+ VARIABLE_ATTRIBUTE_NV_BS_RT,
+ 1,
+ MAX_UINTN
+ },
+ InternalVarCheckAsciiString
+ },
+ {
+ EFI_TIME_OUT_VARIABLE_NAME,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ 0,
+ VARIABLE_ATTRIBUTE_NV_BS_RT,
+ sizeof (UINT16),
+ sizeof (UINT16)
+ },
+ NULL
+ },
+ {
+ EFI_PLATFORM_LANG_CODES_VARIABLE_NAME,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ 0,
+ VARIABLE_ATTRIBUTE_BS_RT,
+ 1,
+ MAX_UINTN
+ },
+ InternalVarCheckAsciiString
+ },
+ {
+ EFI_PLATFORM_LANG_VARIABLE_NAME,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ 0,
+ VARIABLE_ATTRIBUTE_NV_BS_RT,
+ 1,
+ MAX_UINTN
+ },
+ InternalVarCheckAsciiString
+ },
+ {
+ EFI_CON_IN_VARIABLE_NAME,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ 0,
+ VARIABLE_ATTRIBUTE_NV_BS_RT,
+ sizeof (EFI_DEVICE_PATH_PROTOCOL),
+ MAX_UINTN
+ },
+ InternalVarCheckDevicePath
+ },
+ {
+ EFI_CON_OUT_VARIABLE_NAME,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ 0,
+ VARIABLE_ATTRIBUTE_NV_BS_RT,
+ sizeof (EFI_DEVICE_PATH_PROTOCOL),
+ MAX_UINTN
+ },
+ InternalVarCheckDevicePath
+ },
+ {
+ EFI_ERR_OUT_VARIABLE_NAME,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ 0,
+ VARIABLE_ATTRIBUTE_NV_BS_RT,
+ sizeof (EFI_DEVICE_PATH_PROTOCOL),
+ MAX_UINTN
+ },
+ InternalVarCheckDevicePath
+ },
+ {
+ EFI_CON_IN_DEV_VARIABLE_NAME,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ 0,
+ VARIABLE_ATTRIBUTE_BS_RT,
+ sizeof (EFI_DEVICE_PATH_PROTOCOL),
+ MAX_UINTN
+ },
+ InternalVarCheckDevicePath
+ },
+ {
+ EFI_CON_OUT_DEV_VARIABLE_NAME,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ 0,
+ VARIABLE_ATTRIBUTE_BS_RT,
+ sizeof (EFI_DEVICE_PATH_PROTOCOL),
+ MAX_UINTN
+ },
+ InternalVarCheckDevicePath
+ },
+ {
+ EFI_ERR_OUT_DEV_VARIABLE_NAME,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ 0,
+ VARIABLE_ATTRIBUTE_BS_RT,
+ sizeof (EFI_DEVICE_PATH_PROTOCOL),
+ MAX_UINTN
+ },
+ InternalVarCheckDevicePath
+ },
+ {
+ EFI_BOOT_ORDER_VARIABLE_NAME,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ 0,
+ VARIABLE_ATTRIBUTE_NV_BS_RT,
+ sizeof (UINT16),
+ MAX_UINTN
+ },
+ InternalVarCheckSizeArray
+ },
+ {
+ EFI_BOOT_NEXT_VARIABLE_NAME,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ 0,
+ VARIABLE_ATTRIBUTE_NV_BS_RT,
+ sizeof (UINT16),
+ sizeof (UINT16)
+ },
+ NULL
+ },
+ {
+ EFI_BOOT_CURRENT_VARIABLE_NAME,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ 0,
+ VARIABLE_ATTRIBUTE_BS_RT,
+ sizeof (UINT16),
+ sizeof (UINT16)
+ },
+ NULL
+ },
+ {
+ EFI_BOOT_OPTION_SUPPORT_VARIABLE_NAME,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ 0,
+ VARIABLE_ATTRIBUTE_BS_RT,
+ sizeof (UINT32),
+ sizeof (UINT32)
+ },
+ NULL
+ },
+ {
+ EFI_DRIVER_ORDER_VARIABLE_NAME,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ 0,
+ VARIABLE_ATTRIBUTE_NV_BS_RT,
+ sizeof (UINT16),
+ MAX_UINTN
+ },
+ InternalVarCheckSizeArray
+ },
+ {
+ EFI_SYS_PREP_ORDER_VARIABLE_NAME,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ 0,
+ VARIABLE_ATTRIBUTE_NV_BS_RT,
+ sizeof (UINT16),
+ MAX_UINTN
+ },
+ InternalVarCheckSizeArray
+ },
+ {
+ EFI_HW_ERR_REC_SUPPORT_VARIABLE_NAME,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ 0,
+ VARIABLE_ATTRIBUTE_NV_BS_RT,
+ sizeof (UINT16),
+ sizeof (UINT16)
+ },
+ NULL
+ },
+ {
+ EFI_SETUP_MODE_NAME,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY,
+ VARIABLE_ATTRIBUTE_BS_RT,
+ sizeof (UINT8),
+ sizeof (UINT8)
+ },
+ NULL
+ },
+ {
+ EFI_KEY_EXCHANGE_KEY_NAME,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ 0,
+ VARIABLE_ATTRIBUTE_NV_BS_RT_AT,
+ 1,
+ MAX_UINTN
+ },
+ NULL
+ },
+ {
+ EFI_PLATFORM_KEY_NAME,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ 0,
+ VARIABLE_ATTRIBUTE_NV_BS_RT_AT,
+ 1,
+ MAX_UINTN
+ },
+ NULL
+ },
+ {
+ EFI_SIGNATURE_SUPPORT_NAME,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY,
+ VARIABLE_ATTRIBUTE_BS_RT,
+ sizeof (EFI_GUID),
+ MAX_UINTN
+ },
+ InternalVarCheckSizeArray
+ },
+ {
+ EFI_SECURE_BOOT_MODE_NAME,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY,
+ VARIABLE_ATTRIBUTE_BS_RT,
+ sizeof (UINT8),
+ sizeof (UINT8)
+ },
+ NULL
+ },
+ {
+ EFI_KEK_DEFAULT_VARIABLE_NAME,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY,
+ VARIABLE_ATTRIBUTE_BS_RT,
+ 1,
+ MAX_UINTN
+ },
+ NULL
+ },
+ {
+ EFI_PK_DEFAULT_VARIABLE_NAME,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY,
+ VARIABLE_ATTRIBUTE_BS_RT,
+ 1,
+ MAX_UINTN
+ },
+ NULL
+ },
+ {
+ EFI_DB_DEFAULT_VARIABLE_NAME,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY,
+ VARIABLE_ATTRIBUTE_BS_RT,
+ 1,
+ MAX_UINTN
+ },
+ NULL
+ },
+ {
+ EFI_DBX_DEFAULT_VARIABLE_NAME,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY,
+ VARIABLE_ATTRIBUTE_BS_RT,
+ 1,
+ MAX_UINTN
+ },
+ NULL
+ },
+ {
+ EFI_DBT_DEFAULT_VARIABLE_NAME,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY,
+ VARIABLE_ATTRIBUTE_BS_RT,
+ 1,
+ MAX_UINTN
+ },
+ NULL
+ },
+ {
+ EFI_OS_INDICATIONS_SUPPORT_VARIABLE_NAME,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ 0,
+ VARIABLE_ATTRIBUTE_BS_RT,
+ sizeof (UINT64),
+ sizeof (UINT64)
+ },
+ NULL
+ },
+ {
+ EFI_OS_INDICATIONS_VARIABLE_NAME,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ 0,
+ VARIABLE_ATTRIBUTE_NV_BS_RT,
+ sizeof (UINT64),
+ sizeof (UINT64)
+ },
+ NULL
+ },
+ {
+ EFI_VENDOR_KEYS_VARIABLE_NAME,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY,
+ VARIABLE_ATTRIBUTE_BS_RT,
+ sizeof (UINT8),
+ sizeof (UINT8)
+ },
+ NULL
+ },
+};
+
+UEFI_DEFINED_VARIABLE_ENTRY mGlobalVariableList2[] = {
+ {
+ L"Boot####",
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ 0,
+ VARIABLE_ATTRIBUTE_NV_BS_RT,
+ sizeof (UINT32) + sizeof (UINT16),
+ MAX_UINTN
+ },
+ InternalVarCheckLoadOption
+ },
+ {
+ L"Driver####",
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ 0,
+ VARIABLE_ATTRIBUTE_NV_BS_RT,
+ sizeof (UINT32) + sizeof (UINT16),
+ MAX_UINTN
+ },
+ InternalVarCheckLoadOption
+ },
+ {
+ L"SysPrep####",
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ 0,
+ VARIABLE_ATTRIBUTE_NV_BS_RT,
+ sizeof (UINT32) + sizeof (UINT16),
+ MAX_UINTN
+ },
+ InternalVarCheckLoadOption
+ },
+ {
+ L"Key####",
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ 0,
+ VARIABLE_ATTRIBUTE_NV_BS_RT,
+ sizeof (EFI_KEY_OPTION),
+ sizeof (EFI_KEY_OPTION) + 3 * sizeof (EFI_INPUT_KEY)
+ },
+ InternalVarCheckKeyOption
+ },
+};
+
+//
+// EFI_IMAGE_SECURITY_DATABASE_GUID
+//
+UEFI_DEFINED_VARIABLE_ENTRY mImageSecurityVariableList[] = {
+ {
+ EFI_IMAGE_SECURITY_DATABASE,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ 0,
+ VARIABLE_ATTRIBUTE_NV_BS_RT_AT,
+ 1,
+ MAX_UINTN
+ },
+ NULL
+ },
+ {
+ EFI_IMAGE_SECURITY_DATABASE1,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ 0,
+ VARIABLE_ATTRIBUTE_NV_BS_RT_AT,
+ 1,
+ MAX_UINTN
+ },
+ NULL
+ },
+ {
+ EFI_IMAGE_SECURITY_DATABASE2,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ 0,
+ VARIABLE_ATTRIBUTE_NV_BS_RT_AT,
+ 1,
+ MAX_UINTN
+ },
+ NULL
+ },
+};
+
+//
+// EFI_HARDWARE_ERROR_VARIABLE
+//
+UEFI_DEFINED_VARIABLE_ENTRY mHwErrRecVariable = {
+ L"HwErrRec####",
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ 0,
+ VARIABLE_ATTRIBUTE_NV_BS_RT_HR,
+ 1,
+ MAX_UINTN
+ },
+ NULL
+};
+
+EFI_GUID *mUefiDefinedGuid[] = {
+ &gEfiGlobalVariableGuid,
+ &gEfiImageSecurityDatabaseGuid,
+ &gEfiHardwareErrorVariableGuid
+};
+
+/**
+ Check if a Unicode character is a hexadecimal character.
+
+ This function checks if a Unicode character is a
+ hexadecimal character. The valid hexadecimal character is
+ L'0' to L'9', L'a' to L'f', or L'A' to L'F'.
+
+
+ @param[in] Char The character to check against.
+
+ @retval TRUE If the Char is a hexadecmial character.
+ @retval FALSE If the Char is not a hexadecmial character.
+
+**/
+BOOLEAN
+EFIAPI
+VarCheckUefiIsHexaDecimalDigitCharacter (
+ IN CHAR16 Char
+ )
+{
+ return (BOOLEAN) ((Char >= L'0' && Char <= L'9') || (Char >= L'A' && Char <= L'F') || (Char >= L'a' && Char <= L'f'));
+}
+
+/**
+
+ This code checks if variable is hardware error record variable or not.
+
+ According to UEFI spec, hardware error record variable should use the EFI_HARDWARE_ERROR_VARIABLE VendorGuid
+ and have the L"HwErrRec####" name convention, #### is a printed hex value and no 0x or h is included in the hex value.
+
+ @param[in] VariableName Pointer to variable name.
+ @param[in] VendorGuid Variable Vendor Guid.
+
+ @retval TRUE Variable is hardware error record variable.
+ @retval FALSE Variable is not hardware error record variable.
+
+**/
+BOOLEAN
+EFIAPI
+IsHwErrRecVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid
+ )
+{
+ if (!CompareGuid (VendorGuid, &gEfiHardwareErrorVariableGuid) ||
+ (StrLen (VariableName) != StrLen (L"HwErrRec####")) ||
+ (StrnCmp(VariableName, L"HwErrRec", StrLen (L"HwErrRec")) != 0) ||
+ !VarCheckUefiIsHexaDecimalDigitCharacter (VariableName[0x8]) ||
+ !VarCheckUefiIsHexaDecimalDigitCharacter (VariableName[0x9]) ||
+ !VarCheckUefiIsHexaDecimalDigitCharacter (VariableName[0xA]) ||
+ !VarCheckUefiIsHexaDecimalDigitCharacter (VariableName[0xB])) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ Get UEFI defined var check function.
+
+ @param[in] VariableName Pointer to variable name.
+ @param[in] VendorGuid Pointer to variable vendor GUID.
+ @param[out] VariableProperty Pointer to variable property.
+
+ @return Internal var check function, NULL if no specific check function.
+
+**/
+INTERNAL_VAR_CHECK_FUNCTION
+GetUefiDefinedVarCheckFunction (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ OUT VAR_CHECK_VARIABLE_PROPERTY **VariableProperty
+ )
+{
+ UINTN Index;
+ UINTN NameLength;
+
+ if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid)) {
+ //
+ // Try list 1, exactly match.
+ //
+ for (Index = 0; Index < sizeof (mGlobalVariableList)/sizeof (mGlobalVariableList[0]); Index++) {
+ if (StrCmp (mGlobalVariableList[Index].Name, VariableName) == 0) {
+ *VariableProperty = &(mGlobalVariableList[Index].VariableProperty);
+ return mGlobalVariableList[Index].CheckFunction;
+ }
+ }
+
+ //
+ // Try list 2.
+ //
+ NameLength = StrLen (VariableName) - 4;
+ for (Index = 0; Index < sizeof (mGlobalVariableList2)/sizeof (mGlobalVariableList2[0]); Index++) {
+ if ((StrLen (VariableName) == StrLen (mGlobalVariableList2[Index].Name)) &&
+ (StrnCmp (VariableName, mGlobalVariableList2[Index].Name, NameLength) == 0) &&
+ VarCheckUefiIsHexaDecimalDigitCharacter (VariableName[NameLength]) &&
+ VarCheckUefiIsHexaDecimalDigitCharacter (VariableName[NameLength + 1]) &&
+ VarCheckUefiIsHexaDecimalDigitCharacter (VariableName[NameLength + 2]) &&
+ VarCheckUefiIsHexaDecimalDigitCharacter (VariableName[NameLength + 3])) {
+ *VariableProperty = &(mGlobalVariableList2[Index].VariableProperty);
+ return mGlobalVariableList2[Index].CheckFunction;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ SetVariable check handler UEFI defined.
+
+ @param[in] VariableName Name of Variable to set.
+ @param[in] VendorGuid Variable vendor GUID.
+ @param[in] Attributes Attribute value of the variable.
+ @param[in] DataSize Size of Data to set.
+ @param[in] Data Data pointer.
+
+ @retval EFI_SUCCESS The SetVariable check result was success.
+ @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits, name, GUID,
+ DataSize and Data value was supplied.
+ @retval EFI_WRITE_PROTECTED The variable in question is read-only.
+
+**/
+EFI_STATUS
+EFIAPI
+SetVariableCheckHandlerUefiDefined (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN UINT32 Attributes,
+ IN UINTN DataSize,
+ IN VOID *Data
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ VAR_CHECK_VARIABLE_PROPERTY Property;
+ VAR_CHECK_VARIABLE_PROPERTY *VarCheckProperty;
+ INTERNAL_VAR_CHECK_FUNCTION VarCheckFunction;
+
+ if ((((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) && (DataSize == 0)) || (Attributes == 0)) {
+ //
+ // Do not check delete variable.
+ //
+ return EFI_SUCCESS;
+ }
+
+ if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
+ if (!IsHwErrRecVariable (VariableName, VendorGuid)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ for (Index = 0; Index < sizeof (mUefiDefinedGuid)/sizeof (mUefiDefinedGuid[0]); Index++) {
+ if (CompareGuid (VendorGuid, mUefiDefinedGuid[Index])) {
+ if (VarCheckLibVariablePropertyGet (VariableName, VendorGuid, &Property) == EFI_NOT_FOUND) {
+ //
+ // To prevent name collisions with possible future globally defined variables,
+ // other internal firmware data variables that are not defined here must be
+ // saved with a unique VendorGuid other than EFI_GLOBAL_VARIABLE or
+ // any other GUID defined by the UEFI Specification. Implementations must
+ // only permit the creation of variables with a UEFI Specification-defined
+ // VendorGuid when these variables are documented in the UEFI Specification.
+ //
+ DEBUG ((EFI_D_INFO, "UEFI Variable Check fail %r - %s not in %g namespace\n", EFI_INVALID_PARAMETER, VariableName, VendorGuid));
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ }
+
+ if (DataSize == 0) {
+ return EFI_SUCCESS;
+ }
+
+ VarCheckProperty = NULL;
+ VarCheckFunction = GetUefiDefinedVarCheckFunction (VariableName, VendorGuid, &VarCheckProperty);
+ if (VarCheckFunction != NULL) {
+ Status = VarCheckFunction (
+ VarCheckProperty,
+ DataSize,
+ Data
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_INFO, "UEFI Variable Check function fail %r - %g:%s\n", Status, VendorGuid, VariableName));
+ return Status;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Variable property set for UEFI defined variables.
+
+**/
+VOID
+VariablePropertySetUefiDefined (
+ VOID
+ )
+{
+ UINTN Index;
+
+ //
+ // EFI_GLOBAL_VARIABLE
+ //
+ for (Index = 0; Index < sizeof (mGlobalVariableList)/sizeof (mGlobalVariableList[0]); Index++) {
+ VarCheckLibVariablePropertySet (
+ mGlobalVariableList[Index].Name,
+ &gEfiGlobalVariableGuid,
+ &mGlobalVariableList[Index].VariableProperty
+ );
+ }
+ for (Index = 0; Index < sizeof (mGlobalVariableList2)/sizeof (mGlobalVariableList2[0]); Index++) {
+ VarCheckLibVariablePropertySet (
+ mGlobalVariableList2[Index].Name,
+ &gEfiGlobalVariableGuid,
+ &mGlobalVariableList2[Index].VariableProperty
+ );
+ }
+
+ //
+ // EFI_IMAGE_SECURITY_DATABASE_GUID
+ //
+ for (Index = 0; Index < sizeof (mImageSecurityVariableList)/sizeof (mImageSecurityVariableList[0]); Index++) {
+ VarCheckLibVariablePropertySet (
+ mImageSecurityVariableList[Index].Name,
+ &gEfiImageSecurityDatabaseGuid,
+ &mImageSecurityVariableList[Index].VariableProperty
+ );
+ }
+
+ //
+ // EFI_HARDWARE_ERROR_VARIABLE
+ //
+ VarCheckLibVariablePropertySet (
+ mHwErrRecVariable.Name,
+ &gEfiHardwareErrorVariableGuid,
+ &mHwErrRecVariable.VariableProperty
+ );
+}
+
+/**
+ Constructor function of VarCheckUefiLib to set property and
+ register SetVariable check handler for UEFI defined variables.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The constructor executed correctly.
+
+**/
+EFI_STATUS
+EFIAPI
+VarCheckUefiLibNullClassConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ VariablePropertySetUefiDefined ();
+ VarCheckLibRegisterSetVariableCheckHandler (SetVariableCheckHandlerUefiDefined);
+
+ return EFI_SUCCESS;
+}