/** @file
Copyright (c) 2017, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
UINTN mSmmTestPointDatabaseSize;
VOID *mSmmTestPointDatabase;
VOID
PublishPeiTestPoint (
VOID
)
{
EFI_PEI_HOB_POINTERS Hob;
ADAPTER_INFO_PLATFORM_TEST_POINT *TestPoint;
UINTN TestPointSize;
DEBUG ((DEBUG_INFO, "PublishPeiTestPoint\n"));
Hob.Raw = GetHobList ();
while (TRUE) {
Hob.Raw = GetNextGuidHob (&gAdapterInfoPlatformTestPointGuid, Hob.Raw);
if (Hob.Raw == NULL) {
return ;
}
TestPoint = GET_GUID_HOB_DATA (Hob);
TestPointSize = GET_GUID_HOB_DATA_SIZE (Hob);
TestPointLibSetTable (TestPoint, TestPointSize);
Hob.Raw = GET_NEXT_HOB (Hob);
if (Hob.Raw == NULL) {
return ;
}
}
}
VOID
TestPointStubForPei (
VOID
)
{
PublishPeiTestPoint ();
}
VOID
GetTestPointDataSmm (
VOID
)
{
EFI_STATUS Status;
UINTN CommSize;
UINT8 *CommBuffer;
EFI_SMM_COMMUNICATE_HEADER *CommHeader;
SMI_HANDLER_TEST_POINT_PARAMETER_GET_INFO *CommGetInfo;
SMI_HANDLER_TEST_POINT_PARAMETER_GET_DATA_BY_OFFSET *CommGetData;
EFI_SMM_COMMUNICATION_PROTOCOL *SmmCommunication;
UINTN MinimalSizeNeeded;
EDKII_PI_SMM_COMMUNICATION_REGION_TABLE *PiSmmCommunicationRegionTable;
UINT32 Index;
EFI_MEMORY_DESCRIPTOR *Entry;
VOID *Buffer;
UINTN Size;
UINTN Offset;
Status = gBS->LocateProtocol(&gEfiSmmCommunicationProtocolGuid, NULL, (VOID **)&SmmCommunication);
if (EFI_ERROR(Status)) {
DEBUG ((DEBUG_INFO, "SmiHandlerTestPoint: Locate SmmCommunication protocol - %r\n", Status));
return ;
}
MinimalSizeNeeded = EFI_PAGE_SIZE;
Status = EfiGetSystemConfigurationTable(
&gEdkiiPiSmmCommunicationRegionTableGuid,
(VOID **)&PiSmmCommunicationRegionTable
);
if (EFI_ERROR(Status)) {
DEBUG ((DEBUG_INFO, "SmiHandlerTestPoint: Get PiSmmCommunicationRegionTable - %r\n", Status));
return ;
}
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 >= MinimalSizeNeeded) {
break;
}
}
Entry = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)Entry + PiSmmCommunicationRegionTable->DescriptorSize);
}
ASSERT(Index < PiSmmCommunicationRegionTable->NumberOfEntries);
CommBuffer = (UINT8 *)(UINTN)Entry->PhysicalStart;
//
// Get Size
//
CommHeader = (EFI_SMM_COMMUNICATE_HEADER *)&CommBuffer[0];
CopyMem(&CommHeader->HeaderGuid, &gAdapterInfoPlatformTestPointGuid, sizeof(gAdapterInfoPlatformTestPointGuid));
CommHeader->MessageLength = sizeof(SMI_HANDLER_TEST_POINT_PARAMETER_GET_INFO);
CommGetInfo = (SMI_HANDLER_TEST_POINT_PARAMETER_GET_INFO *)&CommBuffer[OFFSET_OF(EFI_SMM_COMMUNICATE_HEADER, Data)];
CommGetInfo->Header.Command = SMI_HANDLER_TEST_POINT_COMMAND_GET_INFO;
CommGetInfo->Header.DataLength = sizeof(*CommGetInfo);
CommGetInfo->Header.ReturnStatus = (UINT64)-1;
CommGetInfo->DataSize = 0;
CommSize = OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data) + (UINTN)CommHeader->MessageLength;
Status = SmmCommunication->Communicate(SmmCommunication, CommBuffer, &CommSize);
if (EFI_ERROR(Status)) {
DEBUG ((DEBUG_INFO, "SmiHandlerTestPoint: SmmCommunication - %r\n", Status));
return ;
}
if (CommGetInfo->Header.ReturnStatus != 0) {
DEBUG ((DEBUG_INFO, "SmiHandlerTestPoint: GetInfo - 0x%0x\n", CommGetInfo->Header.ReturnStatus));
return ;
}
mSmmTestPointDatabaseSize = (UINTN)CommGetInfo->DataSize;
//
// Get Data
//
mSmmTestPointDatabase = AllocateZeroPool(mSmmTestPointDatabaseSize);
if (mSmmTestPointDatabase == NULL) {
Status = EFI_OUT_OF_RESOURCES;
DEBUG ((DEBUG_INFO, "SmiHandlerTestPoint: AllocateZeroPool (0x%x) for dump buffer - %r\n", mSmmTestPointDatabaseSize, Status));
return ;
}
CommHeader = (EFI_SMM_COMMUNICATE_HEADER *)&CommBuffer[0];
CopyMem(&CommHeader->HeaderGuid, &gAdapterInfoPlatformTestPointGuid, sizeof(gAdapterInfoPlatformTestPointGuid));
CommHeader->MessageLength = sizeof(SMI_HANDLER_TEST_POINT_PARAMETER_GET_DATA_BY_OFFSET);
CommGetData = (SMI_HANDLER_TEST_POINT_PARAMETER_GET_DATA_BY_OFFSET *)&CommBuffer[OFFSET_OF(EFI_SMM_COMMUNICATE_HEADER, Data)];
CommGetData->Header.Command = SMI_HANDLER_TEST_POINT_COMMAND_GET_DATA_BY_OFFSET;
CommGetData->Header.DataLength = sizeof(*CommGetData);
CommGetData->Header.ReturnStatus = (UINT64)-1;
CommSize = OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data) + (UINTN)CommHeader->MessageLength;
Buffer = (UINT8 *)CommHeader + CommSize;
Size -= CommSize;
CommGetData->DataBuffer = (PHYSICAL_ADDRESS)(UINTN)Buffer;
CommGetData->DataOffset = 0;
while (CommGetData->DataOffset < mSmmTestPointDatabaseSize) {
Offset = (UINTN)CommGetData->DataOffset;
if (Size <= (mSmmTestPointDatabaseSize - CommGetData->DataOffset)) {
CommGetData->DataSize = (UINT64)Size;
} else {
CommGetData->DataSize = (UINT64)(mSmmTestPointDatabaseSize - CommGetData->DataOffset);
}
Status = SmmCommunication->Communicate(SmmCommunication, CommBuffer, &CommSize);
ASSERT_EFI_ERROR(Status);
if (CommGetData->Header.ReturnStatus != 0) {
FreePool(mSmmTestPointDatabase);
mSmmTestPointDatabase = NULL;
DEBUG ((DEBUG_INFO, "SmiHandlerTestPoint: GetData - 0x%x\n", CommGetData->Header.ReturnStatus));
return ;
}
CopyMem((UINT8 *)mSmmTestPointDatabase + Offset, (VOID *)(UINTN)CommGetData->DataBuffer, (UINTN)CommGetData->DataSize);
}
DEBUG ((DEBUG_INFO, "SmmTestPointDatabaseSize - 0x%x\n", mSmmTestPointDatabaseSize));
return ;
}
UINTN
GetTestPointInfoSize (
IN ADAPTER_INFO_PLATFORM_TEST_POINT *TestPoint,
IN UINTN MaxSize
)
{
CHAR16 *ErrorString;
UINTN ErrorStringLength;
UINTN ErrorStringMaxSize;
CHAR16 ErrorChar;
ErrorString = (CHAR16 *)((UINTN)TestPoint + sizeof(ADAPTER_INFO_PLATFORM_TEST_POINT) + TEST_POINT_FEATURES_ITEM_NUMBER * TestPoint->FeaturesSize);
ErrorStringMaxSize = MaxSize - sizeof(ADAPTER_INFO_PLATFORM_TEST_POINT) - TestPoint->FeaturesSize * TEST_POINT_FEATURES_ITEM_NUMBER;
//
// ErrorString might not be CHAR16 aligned.
//
CopyMem (&ErrorChar, ErrorString, sizeof(ErrorChar));
for (ErrorStringLength = 0; (ErrorChar != 0) && (ErrorStringLength < (ErrorStringMaxSize/2)); ErrorStringLength++) {
ErrorString++;
CopyMem (&ErrorChar, ErrorString, sizeof(ErrorChar));
}
return sizeof(ADAPTER_INFO_PLATFORM_TEST_POINT) + TEST_POINT_FEATURES_ITEM_NUMBER * TestPoint->FeaturesSize + (ErrorStringLength + 1) * sizeof(CHAR16);
}
VOID
PublishSmmTestPoint (
VOID
)
{
ADAPTER_INFO_PLATFORM_TEST_POINT *TestPoint;
UINTN TestPointSize;
DEBUG ((DEBUG_INFO, "PublishSmmTestPoint\n"));
GetTestPointDataSmm ();
if (mSmmTestPointDatabaseSize == 0) {
return ;
}
if (mSmmTestPointDatabase == NULL) {
return ;
}
TestPoint = mSmmTestPointDatabase;
while ((UINTN)TestPoint < (UINTN)mSmmTestPointDatabase + mSmmTestPointDatabaseSize) {
TestPointSize = GetTestPointInfoSize (TestPoint, (UINTN)mSmmTestPointDatabase + mSmmTestPointDatabaseSize - (UINTN)TestPoint);
TestPointLibSetTable (TestPoint, TestPointSize);
TestPoint = (ADAPTER_INFO_PLATFORM_TEST_POINT *)((UINTN)TestPoint + TestPointSize);
}
}
/**
Notification function of EVT_GROUP_READY_TO_BOOT event group.
It runs after most ReadyToBoot event signaled.
This is a notification function registered on EVT_GROUP_READY_TO_BOOT event group.
When the Boot Manager is about to load and execute a boot option, it reclaims variable
storage if free size is below the threshold.
@param[in] Event Event whose notification function is being invoked.
@param[in] Context Pointer to the notification function's context.
**/
VOID
EFIAPI
OnReadyToBootLater (
IN EFI_EVENT Event,
IN VOID *Context
)
{
gBS->CloseEvent (Event);
PublishSmmTestPoint ();
}
/**
Notification function of EVT_GROUP_READY_TO_BOOT event group.
This is a notification function registered on EVT_GROUP_READY_TO_BOOT event group.
When the Boot Manager is about to load and execute a boot option, it reclaims variable
storage if free size is below the threshold.
@param[in] Event Event whose notification function is being invoked.
@param[in] Context Pointer to the notification function's context.
**/
VOID
EFIAPI
OnReadyToBoot (
IN EFI_EVENT Event,
IN VOID *Context
)
{
EFI_STATUS Status;
EFI_EVENT ReadyToBootLaterEvent;
gBS->CloseEvent (Event);
Status = gBS->CreateEvent (
EVT_NOTIFY_SIGNAL,
TPL_CALLBACK,
OnReadyToBootLater,
NULL,
&ReadyToBootLaterEvent
);
ASSERT_EFI_ERROR (Status);
gBS->SignalEvent (ReadyToBootLaterEvent);
}
VOID
TestPointStubForSmm (
VOID
)
{
EFI_STATUS Status;
EFI_EVENT ReadyToBootEvent;
Status = EfiCreateEventReadyToBootEx (
TPL_CALLBACK,
OnReadyToBoot,
NULL,
&ReadyToBootEvent
);
ASSERT_EFI_ERROR (Status);
}
/**
Initialize TestPointStub.
@param[in] ImageHandle Image handle of this driver.
@param[in] SystemTable Global system service table.
@retval EFI_SUCCESS Initialization complete.
@exception EFI_UNSUPPORTED The chipset is unsupported by this driver.
@retval EFI_OUT_OF_RESOURCES Do not have enough resources to initialize the driver.
@retval EFI_DEVICE_ERROR Device error, driver exits abnormally.
**/
EFI_STATUS
EFIAPI
TestPointStubDxeEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
TestPointStubForPei ();
TestPointStubForSmm ();
return EFI_SUCCESS;
}