MdeModulePkg: Add Standalone MM Core performance support

Adds a new library instance to support MM core functionality for
performance in Standalone MM.

- Add StandaloneMmCorePerformanceLib instance
- Move common MM logic to a new file `MmCorePerformanceLib.c`
- Define interfaces with implementation specific to MM environment
  type in `SmmCorePerformanceLibInternal.h` and implement those
  functions in the Standalone MM and Traditional MM specific C files

Note: StandaloneMmCorePerformanceLib supports both
      `MM_CORE_STANDALONE` and `MM_STANDALONE` as some Standalone MM
	  environments have privilege separation and need to link this
	  functionality in a ring 3 Standalone MM driver that is outside
	  the ring 0 Standalone MM core driver.

Signed-off-by: Michael Kubacki <michael.kubacki@microsoft.com>
This commit is contained in:
Michael Kubacki 2025-02-03 10:01:15 -05:00 committed by mergify[bot]
parent 874c24baae
commit 11b44c5cd1
8 changed files with 1854 additions and 1372 deletions

View File

@ -234,9 +234,11 @@ InternalGetSmmPerfData (
EDKII_PI_SMM_COMMUNICATION_REGION_TABLE *SmmCommRegionTable;
EFI_MEMORY_DESCRIPTOR *SmmCommMemRegion;
UINTN Index;
VOID *CurrentBootRecordData;
VOID *SmmBootRecordData;
UINTN SmmBootRecordDataSize;
UINTN ReservedMemSize;
UINTN BootRecordDataPayloadSize;
UINTN SmmBootRecordDataRetrieved;
//
@ -291,6 +293,11 @@ InternalGetSmmPerfData (
SmmCommData->Function = SMM_FPDT_FUNCTION_GET_BOOT_RECORD_SIZE;
SmmCommData->BootRecordData = NULL;
Status = Communication->Communicate (Communication, SmmBootRecordCommBuffer, &CommSize);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_WARN, "Perf handler MMI not found or communicate failed. Status = %r.\n", Status));
} else if (EFI_ERROR (SmmCommData->ReturnStatus)) {
DEBUG ((DEBUG_ERROR, "Perf handler MMI returned an error. Status = %r.\n", SmmCommData->ReturnStatus));
}
if (!EFI_ERROR (Status) && !EFI_ERROR (SmmCommData->ReturnStatus) && (SmmCommData->BootRecordSize != 0)) {
if (SkipGetPerfData) {
@ -307,26 +314,39 @@ InternalGetSmmPerfData (
SmmBootRecordData = AllocateZeroPool (SmmBootRecordDataSize);
SmmBootRecordDataRetrieved = 0;
ASSERT (SmmBootRecordData != NULL);
SmmCommData->BootRecordData = (VOID *)((UINTN)SmmCommMemRegion->PhysicalStart + SMM_BOOT_RECORD_COMM_SIZE);
SmmCommData->BootRecordSize = ReservedMemSize - SMM_BOOT_RECORD_COMM_SIZE;
while (SmmBootRecordDataRetrieved < SmmBootRecordDataSize) {
Status = Communication->Communicate (Communication, SmmBootRecordCommBuffer, &CommSize);
ASSERT_EFI_ERROR (Status);
ASSERT_EFI_ERROR (SmmCommData->ReturnStatus);
if (SmmBootRecordDataRetrieved + SmmCommData->BootRecordSize > SmmBootRecordDataSize) {
CopyMem ((UINT8 *)SmmBootRecordData + SmmBootRecordDataRetrieved, SmmCommData->BootRecordData, SmmBootRecordDataSize - SmmBootRecordDataRetrieved);
} else {
CopyMem ((UINT8 *)SmmBootRecordData + SmmBootRecordDataRetrieved, SmmCommData->BootRecordData, SmmCommData->BootRecordSize);
if (SmmBootRecordData != NULL) {
CurrentBootRecordData = (VOID *)((UINTN)SmmCommMemRegion->PhysicalStart + SMM_BOOT_RECORD_COMM_SIZE);
while (SmmBootRecordDataRetrieved < SmmBootRecordDataSize) {
// Note: Maximum comm buffer data payload size is ReservedMemSize - SMM_BOOT_RECORD_COMM_SIZE
BootRecordDataPayloadSize = MIN (
ReservedMemSize - SMM_BOOT_RECORD_COMM_SIZE,
SmmBootRecordDataSize - SmmBootRecordDataRetrieved - SMM_BOOT_RECORD_COMM_SIZE
);
MmCommBufferHeader->MessageLength = sizeof (SMM_BOOT_RECORD_COMMUNICATE) + BootRecordDataPayloadSize;
CommSize = sizeof (EFI_MM_COMMUNICATE_HEADER) + (UINTN)MmCommBufferHeader->MessageLength;
Status = Communication->Communicate (Communication, SmmBootRecordCommBuffer, &CommSize);
ASSERT_EFI_ERROR (Status);
if (EFI_ERROR (Status) || EFI_ERROR (SmmCommData->ReturnStatus)) {
break;
}
if (SmmBootRecordDataRetrieved + SmmCommData->BootRecordSize > SmmBootRecordDataSize) {
CopyMem ((UINT8 *)SmmBootRecordData + SmmBootRecordDataRetrieved, CurrentBootRecordData, SmmBootRecordDataSize - SmmBootRecordDataRetrieved);
} else {
CopyMem ((UINT8 *)SmmBootRecordData + SmmBootRecordDataRetrieved, CurrentBootRecordData, SmmCommData->BootRecordSize);
}
SmmBootRecordDataRetrieved += SmmCommData->BootRecordSize;
SmmCommData->BootRecordOffset += SmmCommData->BootRecordSize;
}
SmmBootRecordDataRetrieved += SmmCommData->BootRecordSize;
SmmCommData->BootRecordOffset += SmmCommData->BootRecordSize;
mSmmBootRecordOffset = SmmCommData->BootRecordOffset;
*SmmPerfData = SmmBootRecordData;
*SmmPerfDataSize = SmmBootRecordDataSize;
}
mSmmBootRecordOffset = SmmCommData->BootRecordOffset;
*SmmPerfData = SmmBootRecordData;
*SmmPerfDataSize = SmmBootRecordDataSize;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -9,18 +9,19 @@
# SMM Performance and PerformanceEx Protocol are installed at the very beginning of SMM phase.
#
# Copyright (c) 2011 - 2023, Intel Corporation. All rights reserved.<BR>
# Copyright (c) Microsoft Corporation.
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
##
[Defines]
INF_VERSION = 0x00010005
INF_VERSION = 0x0001001B
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
PI_SPECIFICATION_VERSION = 0x00010032
LIBRARY_CLASS = PerformanceLib|SMM_CORE
CONSTRUCTOR = SmmCorePerformanceLibConstructor
@ -32,33 +33,33 @@
#
[Sources]
SmmCorePerformanceLib.c
MmCorePerformanceLib.c
SmmCorePerformanceLibInternal.h
SmmCorePerformanceLib.c
[Packages]
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec
[LibraryClasses]
MemoryAllocationLib
UefiBootServicesTableLib
PcdLib
TimerLib
BaseMemoryLib
BaseLib
BaseMemoryLib
DebugLib
SynchronizationLib
SmmServicesTableLib
SmmMemLib
UefiLib
ReportStatusCodeLib
PeCoffGetEntryPointLib
DxeServicesLib
MemoryAllocationLib
MmServicesTableLib
PcdLib
PeCoffGetEntryPointLib
SmmMemLib
SynchronizationLib
TimerLib
UefiBootServicesTableLib
UefiLib
[Protocols]
gEfiSmmBase2ProtocolGuid ## CONSUMES
gEdkiiSmmExitBootServicesProtocolGuid ## CONSUMES
gEdkiiSmmExitBootServicesProtocolGuid ## CONSUMES ## NOTIFY
gEfiLoadedImageProtocolGuid ## CONSUMES
[Guids]
## PRODUCES ## SystemTable

View File

@ -5,6 +5,7 @@
library instance at its constructor.
Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
Copyright (c) Microsoft Corporation.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
@ -12,32 +13,135 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
#ifndef _SMM_CORE_PERFORMANCE_LIB_INTERNAL_H_
#define _SMM_CORE_PERFORMANCE_LIB_INTERNAL_H_
#include <Guid/Performance.h>
#include <Guid/PerformanceMeasurement.h>
#include <Guid/EventGroup.h>
#include <Guid/ExtendedFirmwarePerformance.h>
#include <Guid/FirmwarePerformance.h>
#include <Guid/Performance.h>
#include <Guid/PerformanceMeasurement.h>
#include <Guid/ZeroGuid.h>
#include <Guid/EventGroup.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/DebugLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/SynchronizationLib.h>
#include <Library/SmmMemLib.h>
#include <Library/ReportStatusCodeLib.h>
#include <Library/DxeServicesLib.h>
#include <Library/MmServicesTableLib.h>
#include <Library/PcdLib.h>
#include <Library/PeCoffGetEntryPointLib.h>
#include <Library/PerformanceLib.h>
#include <Library/SmmMemLib.h>
#include <Library/SynchronizationLib.h>
#include <Library/TimerLib.h>
#include <Protocol/SmmBase2.h>
#include <Protocol/LoadedImage.h>
#include <Protocol/DevicePathToText.h>
#include <Protocol/LoadedImage.h>
#define STRING_SIZE (FPDT_STRING_EVENT_RECORD_NAME_LENGTH * sizeof (CHAR8))
#define FIRMWARE_RECORD_BUFFER 0x1000
#define CACHE_HANDLE_GUID_COUNT 0x100
extern BOOLEAN mPerformanceMeasurementEnabled;
//
// Library internal function declarations
//
/**
Return a pointer to the loaded image protocol for the given handle.
@param[in] Handle A handle to query for the loaded image protocol.
@return A pointer to a loaded image protocol instance or null if the handle does not support load image protocol.
**/
EFI_LOADED_IMAGE_PROTOCOL *
GetLoadedImageProtocol (
IN EFI_HANDLE Handle
);
/**
Get the module name from the PDB file name in the image header.
@param[in] ImageBase The base address of the image.
@param[out] NameString The buffer to store the name string.
@param[in] BufferSize The size of the buffer in bytes.
@retval EFI_SUCCESS The name string is successfully retrieved.
@retval EFI_INVALID_PARAMETER A pointer argument provided is null.
@retval EFI_NOT_FOUND The module name was not found.
**/
EFI_STATUS
GetModuleNameFromPdbString (
IN VOID *ImageBase,
OUT CHAR8 *NameString,
IN UINTN BufferSize
);
/**
Get the module name from the user interface section.
@param[in] ModuleGuid The GUID of the module.
@param[out] NameString The buffer to store the name string.
@param[in] BufferSize The size of the buffer in bytes.
@retval EFI_SUCCESS The name string is successfully retrieved.
@retval EFI_NOT_FOUND The module name was not found.
**/
EFI_STATUS
GetNameFromUiSection (
IN EFI_GUID *ModuleGuid,
OUT CHAR8 *NameString,
IN UINTN BufferSize
);
/**
Common initialization code for the MM Core Performance Library.
@param[in] ExitBootServicesProtocolGuid The GUID of the ExitBootServices protocol.
@retval EFI_SUCCESS The MM Core Performance Library was initialized successfully.
@retval Others The MM Core Performance Library was not initialized successfully.
**/
EFI_STATUS
InitializeMmCorePerformanceLibCommon (
IN CONST EFI_GUID *ExitBootServicesProtocolGuid
);
/**
A library internal MM-instance specific implementation to check if a buffer outside MM is valid.
This function is provided so Standalone MM and Traditional MM may use a different implementation
of data buffer check logic.
@param[in] Buffer The buffer start address to be checked.
@param[in] Length The buffer length to be checked.
@retval TRUE This buffer is valid per processor architecture.
@retval FALSE This buffer is not valid per processor architecture.
**/
BOOLEAN
MmCorePerformanceIsNonPrimaryBufferValid (
IN EFI_PHYSICAL_ADDRESS Buffer,
IN UINT64 Length
);
/**
A library internal MM-instance specific implementation to check if a comm buffer is valid.
This function is provided so Standalone MM and Traditional MM may use a different implementation
of comm buffer check logic.
@param[in] Buffer The buffer start address to be checked.
@param[in] Length The buffer length to be checked.
@retval TRUE This communicate buffer is valid per processor architecture.
@retval FALSE This communicate buffer is not valid per processor architecture.
**/
BOOLEAN
MmCorePerformanceIsPrimaryBufferValid (
IN EFI_PHYSICAL_ADDRESS Buffer,
IN UINT64 Length
);
//
// Interface declarations for SMM PerformanceMeasurement Protocol.

View File

@ -0,0 +1,147 @@
/** @file
This library is mainly used by the Standalone MM Core to start performance logging to ensure that
Standalone MM Performance and PerformanceEx Protocol are installed as early as possible in the MM phase.
Caution: This module requires additional review when modified.
- This driver will have external input - performance data and communicate buffer in MM 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) Microsoft Corporation.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "SmmCorePerformanceLibInternal.h"
#include <Guid/EventGroup.h>
#include <Library/StandaloneMmMemLib.h>
/**
A library internal MM-instance specific implementation to check if a buffer outside MM is valid.
This function is provided so Standalone MM and Traditional MM may use a different implementation
of data buffer check logic.
@param[in] Buffer The buffer start address to be checked.
@param[in] Length The buffer length to be checked.
@retval TRUE This buffer is valid per processor architecture.
@retval FALSE This buffer is not valid per processor architecture.
**/
BOOLEAN
MmCorePerformanceIsNonPrimaryBufferValid (
IN EFI_PHYSICAL_ADDRESS Buffer,
IN UINT64 Length
)
{
return MmIsBufferOutsideMmValid (Buffer, Length);
}
/**
A library internal MM-instance specific implementation to check if a comm buffer is valid.
This function is provided so Standalone MM and Traditional MM may use a different implementation
of comm buffer check logic.
@param[in] Buffer The buffer start address to be checked.
@param[in] Length The buffer length to be checked.
@retval TRUE This communicate buffer is valid per processor architecture.
@retval FALSE This communicate buffer is not valid per processor architecture.
**/
BOOLEAN
MmCorePerformanceIsPrimaryBufferValid (
IN EFI_PHYSICAL_ADDRESS Buffer,
IN UINT64 Length
)
{
return TRUE;
}
/**
Return a pointer to the loaded image protocol for the given handle.
@param[in] Handle A handle to query for the loaded image protocol.
@return A pointer to a loaded image protocol instance or null if the handle does not support load image protocol.
**/
EFI_LOADED_IMAGE_PROTOCOL *
GetLoadedImageProtocol (
IN EFI_HANDLE Handle
)
{
EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
if (Handle == NULL) {
return NULL;
}
LoadedImage = NULL;
gMmst->MmHandleProtocol (
Handle,
&gEfiLoadedImageProtocolGuid,
(VOID **)&LoadedImage
);
return LoadedImage;
}
/**
Get the module name from the user interface section.
@param[in] ModuleGuid The GUID of the module.
@param[out] NameString The buffer to store the name string.
@param[in] BufferSize The size of the buffer in bytes.
@retval EFI_SUCCESS The name string is successfully retrieved.
@retval EFI_NOT_FOUND The module name was not found.
**/
EFI_STATUS
GetNameFromUiSection (
IN EFI_GUID *ModuleGuid,
OUT CHAR8 *NameString,
IN UINTN BufferSize
)
{
return EFI_NOT_FOUND;
}
/**
The constructor function initializes the Standalone MM Core performance library.
It will ASSERT() if one of these operations fails and it will always return EFI_SUCCESS.
@param[in] ImageHandle The firmware allocated handle for the image.
@param[in] MmSystemTable A pointer to the MM System Table.
@retval EFI_SUCCESS The constructor successfully gets HobList.
@retval Other value The constructor can't get HobList.
**/
EFI_STATUS
EFIAPI
StandaloneMmCorePerformanceLibConstructor (
IN EFI_HANDLE ImageHandle,
IN EFI_MM_SYSTEM_TABLE *MmSystemTable
)
{
EFI_STATUS Status;
mPerformanceMeasurementEnabled = (BOOLEAN)((FixedPcdGet8 (PcdPerformanceLibraryPropertyMask) & PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED) != 0);
if (!PerformanceMeasurementEnabled ()) {
DEBUG ((DEBUG_WARN, "[%a] - Performance library is linked but performance tracing is not enabled.\n", __func__));
//
// Do not initialize performance infrastructure if not required.
//
return EFI_SUCCESS;
}
Status = InitializeMmCorePerformanceLibCommon (&gEfiEventExitBootServicesGuid);
ASSERT_EFI_ERROR (Status);
return EFI_SUCCESS;
}

View File

@ -0,0 +1,55 @@
## @file
# Performance library instance used by a Standalone MM Core or an early Standlaone MM module that
# should install performance measurement services.
#
# Installs the MM performance measurement protocol and returns MM performance data via MM communicate.
#
# Copyright (c) Microsoft Corporation.
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
##
[Defines]
INF_VERSION = 0x0001001B
BASE_NAME = StandaloneMmCorePerformanceLib
FILE_GUID = 8585D462-DE63-4080-882A-A73974CE5609
MODULE_TYPE = MM_CORE_STANDALONE
VERSION_STRING = 1.0
PI_SPECIFICATION_VERSION = 0x00010032
LIBRARY_CLASS = PerformanceLib|MM_CORE_STANDALONE MM_STANDALONE
CONSTRUCTOR = StandaloneMmCorePerformanceLibConstructor
[Sources]
MmCorePerformanceLib.c
SmmCorePerformanceLibInternal.h
StandaloneMmCorePerformanceLib.c
[Packages]
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec
StandaloneMmPkg/StandaloneMmPkg.dec
[LibraryClasses]
BaseLib
BaseMemoryLib
DebugLib
MemoryAllocationLib
MemLib
MmServicesTableLib
PcdLib
PeCoffGetEntryPointLib
SynchronizationLib
TimerLib
[Protocols]
gEdkiiSmmExitBootServicesProtocolGuid ## CONSUMES ## NOTIFY
gEfiLoadedImageProtocolGuid ## CONSUMES
[Guids]
gEfiFirmwarePerformanceGuid ## SOMETIMES_PRODUCES # SmiHandlerRegister
gEdkiiSmmPerformanceMeasurementProtocolGuid ## PRODUCES # Install protocol
gZeroGuid ## SOMETIMES_CONSUMES ## GUID
[FixedPcd]
gEfiMdePkgTokenSpaceGuid.PcdPerformanceLibraryPropertyMask ## CONSUMES
gEfiMdeModulePkgTokenSpaceGuid.PcdEdkiiFpdtStringRecordEnableOnly ## CONSUMES

View File

@ -503,6 +503,7 @@
MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/PiSmmCoreMemoryAllocationProfileLib.inf
MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/PiSmmCoreMemoryAllocationLib.inf
MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLib.inf
MdeModulePkg/Library/SmmCorePerformanceLib/StandaloneMmCorePerformanceLib.inf
MdeModulePkg/Library/SmmPerformanceLib/SmmPerformanceLib.inf
MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.inf
MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.inf