/** @file
Copyright (c) 2017, Intel Corporation. All rights reserved.
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
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "TestPointInternal.h"
GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID mTestPointSmmCommunciationGuid = TEST_POINT_SMM_COMMUNICATION_GUID;
EFI_STATUS
TestPointCheckSmrr (
VOID
);
EFI_STATUS
TestPointDumpSmmLoadedImage (
VOID
);
EFI_STATUS
TestPointCheckSmmMemAttribute (
VOID
);
EFI_STATUS
TestPointCheckSmmPaging (
VOID
);
EFI_STATUS
TestPointCheckSmmCommunicationBuffer (
IN EFI_MEMORY_DESCRIPTOR *UefiMemoryMap,
IN UINTN UefiMemoryMapSize,
IN UINTN UefiDescriptorSize,
IN EFI_MEMORY_ATTRIBUTES_TABLE *MemoryAttributesTable
);
VOID
TestPointDumpGcd (
OUT EFI_GCD_MEMORY_SPACE_DESCRIPTOR **GcdMemoryMap, OPTIONAL
OUT UINTN *GcdMemoryMapNumberOfDescriptors, OPTIONAL
OUT EFI_GCD_IO_SPACE_DESCRIPTOR **GcdIoMap, OPTIONAL
OUT UINTN *GcdIoMapNumberOfDescriptors, OPTIONAL
IN BOOLEAN DumpPrint
);
VOID
TestPointDumpUefiMemoryMap (
OUT EFI_MEMORY_DESCRIPTOR **UefiMemoryMap, OPTIONAL
OUT UINTN *UefiMemoryMapSize, OPTIONAL
OUT UINTN *UefiDescriptorSize, OPTIONAL
IN BOOLEAN DumpPrint
);
GLOBAL_REMOVE_IF_UNREFERENCED EFI_MEMORY_DESCRIPTOR *mUefiMemoryMap;
GLOBAL_REMOVE_IF_UNREFERENCED UINTN mUefiMemoryMapSize;
GLOBAL_REMOVE_IF_UNREFERENCED UINTN mUefiDescriptorSize;
GLOBAL_REMOVE_IF_UNREFERENCED EFI_GCD_MEMORY_SPACE_DESCRIPTOR *mGcdMemoryMap;
GLOBAL_REMOVE_IF_UNREFERENCED EFI_GCD_IO_SPACE_DESCRIPTOR *mGcdIoMap;
GLOBAL_REMOVE_IF_UNREFERENCED UINTN mGcdMemoryMapNumberOfDescriptors;
GLOBAL_REMOVE_IF_UNREFERENCED UINTN mGcdIoMapNumberOfDescriptors;
EFI_MEMORY_ATTRIBUTES_TABLE *mUefiMemoryAttributesTable;
GLOBAL_REMOVE_IF_UNREFERENCED ADAPTER_INFO_PLATFORM_TEST_POINT_STRUCT mTestPointStruct = {
PLATFORM_TEST_POINT_VERSION,
PLATFORM_TEST_POINT_ROLE_PLATFORM_IBV,
{TEST_POINT_IMPLEMENTATION_ID_PLATFORM_SMM},
TEST_POINT_FEATURE_SIZE,
{0}, // FeaturesImplemented
{0}, // FeaturesVerified
0,
};
GLOBAL_REMOVE_IF_UNREFERENCED UINT8 mFeatureImplemented[TEST_POINT_FEATURE_SIZE];
EFI_STATUS
EFIAPI
TestPointSmmEndOfDxeSmrrFunctional (
VOID
)
{
EFI_STATUS Status;
BOOLEAN Result;
if ((mFeatureImplemented[5] & TEST_POINT_BYTE6_SMM_END_OF_DXE_SMRR_FUNCTIONAL) == 0) {
return EFI_SUCCESS;
}
DEBUG ((DEBUG_INFO, "======== TestPointSmmEndOfDxeSmrrFunctional - Enter\n"));
Result = TRUE;
Status = TestPointCheckSmrr ();
if (EFI_ERROR(Status)) {
Result = FALSE;
}
if (Result) {
TestPointLibSetFeaturesVerified (
PLATFORM_TEST_POINT_ROLE_PLATFORM_IBV,
NULL,
5,
TEST_POINT_BYTE6_SMM_END_OF_DXE_SMRR_FUNCTIONAL
);
}
DEBUG ((DEBUG_INFO, "======== TestPointSmmEndOfDxe - Exit\n"));
return EFI_SUCCESS;
}
EFI_STATUS
EFIAPI
TestPointSmmReadyToLockSmmMemoryAttributeTableFunctional (
VOID
)
{
EFI_STATUS Status;
BOOLEAN Result;
if ((mFeatureImplemented[6] & TEST_POINT_BYTE6_SMM_READY_TO_LOCK_SMM_MEMORY_ATTRIBUTE_TABLE_FUNCTIONAL) == 0) {
return EFI_SUCCESS;
}
DEBUG ((DEBUG_INFO, "======== TestPointSmmReadyToLock - Enter\n"));
Result = TRUE;
TestPointDumpSmmLoadedImage ();
Status = TestPointCheckSmmMemAttribute ();
if (EFI_ERROR(Status)) {
Result = FALSE;
}
if (Result) {
TestPointLibSetFeaturesVerified (
PLATFORM_TEST_POINT_ROLE_PLATFORM_IBV,
NULL,
6,
TEST_POINT_BYTE6_SMM_READY_TO_LOCK_SMM_MEMORY_ATTRIBUTE_TABLE_FUNCTIONAL
);
}
DEBUG ((DEBUG_INFO, "======== TestPointSmmReadyToLock - Exit\n"));
return EFI_SUCCESS;
}
EFI_STATUS
EFIAPI
TestPointSmmReadyToLockSecureSmmCommunicationBuffer (
VOID
)
{
EFI_STATUS Status;
EFI_MEMORY_ATTRIBUTES_TABLE *MemoryAttributesTable;
UINTN MemoryAttributesTableSize;
if ((mFeatureImplemented[6] & TEST_POINT_BYTE6_SMM_READY_TO_LOCK_SECURE_SMM_COMMUNICATION_BUFFER) == 0) {
return EFI_SUCCESS;
}
DEBUG ((DEBUG_INFO, "======== TestPointSmmReadyToLockSecureSmmCommunicationBuffer - Enter\n"));
//
// Collect information here, because it is last chance to access outside SMRAM.
//
TestPointDumpUefiMemoryMap (&mUefiMemoryMap, &mUefiMemoryMapSize, &mUefiDescriptorSize, TRUE);
TestPointDumpGcd (&mGcdMemoryMap, &mGcdMemoryMapNumberOfDescriptors, &mGcdIoMap, &mGcdIoMapNumberOfDescriptors, TRUE);
Status = EfiGetSystemConfigurationTable (&gEfiMemoryAttributesTableGuid, &MemoryAttributesTable);
if (!EFI_ERROR (Status)) {
MemoryAttributesTableSize = sizeof(EFI_MEMORY_ATTRIBUTES_TABLE) + MemoryAttributesTable->DescriptorSize * MemoryAttributesTable->NumberOfEntries;
mUefiMemoryAttributesTable = AllocateCopyPool (MemoryAttributesTableSize, MemoryAttributesTable);
ASSERT (mUefiMemoryAttributesTable != NULL);
}
//
// Defer the validation to TestPointSmmReadyToBootSecureSmmCommunicationBuffer, because page table setup later.
//
DEBUG ((DEBUG_INFO, "======== TestPointSmmReadyToLockSecureSmmCommunicationBuffer - Exit\n"));
return EFI_SUCCESS;
}
EFI_STATUS
EFIAPI
TestPointSmmReadyToBootSmmPageProtection (
VOID
)
{
EFI_STATUS Status;
BOOLEAN Result;
if ((mFeatureImplemented[6] & TEST_POINT_BYTE6_SMM_READY_TO_BOOT_SMM_PAGE_LEVEL_PROTECTION) == 0) {
return EFI_SUCCESS;
}
DEBUG ((DEBUG_INFO, "======== TestPointSmmReadyToBootSmmPageProtection - Enter\n"));
Result = TRUE;
Status = TestPointCheckSmmPaging ();
if (EFI_ERROR(Status)) {
Result = FALSE;
}
if (Result) {
TestPointLibSetFeaturesVerified (
PLATFORM_TEST_POINT_ROLE_PLATFORM_IBV,
NULL,
6,
TEST_POINT_BYTE6_SMM_READY_TO_BOOT_SMM_PAGE_LEVEL_PROTECTION
);
}
if (mUefiMemoryMap != NULL) {
Result = TRUE;
Status = TestPointCheckSmmCommunicationBuffer (mUefiMemoryMap, mUefiMemoryMapSize, mUefiDescriptorSize, mUefiMemoryAttributesTable);
if (EFI_ERROR(Status)) {
Result = FALSE;
}
if (Result) {
TestPointLibSetFeaturesVerified (
PLATFORM_TEST_POINT_ROLE_PLATFORM_IBV,
NULL,
6,
TEST_POINT_BYTE6_SMM_READY_TO_LOCK_SECURE_SMM_COMMUNICATION_BUFFER
);
}
}
DEBUG ((DEBUG_INFO, "======== TestPointSmmReadyToBootSmmPageProtection - Exit\n"));
return EFI_SUCCESS;
}
/**
Dispatch function for a Software SMI handler.
Caution: This function may receive untrusted input.
Communicate buffer and buffer size are external input, so this function will do basic validation.
@param CommBuffer A pointer to a collection of data in memory that will
be conveyed from a non-SMM environment into an SMM environment.
@param CommBufferSize The size of the CommBuffer.
@retval EFI_SUCCESS Command is handled successfully.
**/
EFI_STATUS
TestPointSmmReadyToBootSmmPageProtectionHandler (
IN OUT VOID *CommBuffer OPTIONAL,
IN OUT UINTN *CommBufferSize OPTIONAL
)
{
EFI_STATUS Status;
BOOLEAN Result;
TEST_POINT_SMM_COMMUNICATION_UEFI_GCD_MAP_INFO *CommData;
UINTN TempCommBufferSize;
if ((mFeatureImplemented[6] & TEST_POINT_BYTE6_SMM_READY_TO_BOOT_SMM_PAGE_LEVEL_PROTECTION) == 0) {
return EFI_SUCCESS;
}
DEBUG ((DEBUG_INFO, "======== TestPointSmmReadyToBootSmmPageProtectionHandler - Enter\n"));
TempCommBufferSize = *CommBufferSize;
if (TempCommBufferSize < sizeof(TEST_POINT_SMM_COMMUNICATION_UEFI_GCD_MAP_INFO)) {
DEBUG((DEBUG_ERROR, "TestPointSmmReadyToBootSmmPageProtectionHandler: SMM communication buffer size invalid!\n"));
return EFI_SUCCESS;
}
if (!SmmIsBufferOutsideSmmValid((UINTN)CommBuffer, TempCommBufferSize)) {
DEBUG((DEBUG_ERROR, "TestPointSmmReadyToBootSmmPageProtectionHandler: SMM communication buffer in SMRAM or overflow!\n"));
return EFI_SUCCESS;
}
DEBUG ((DEBUG_INFO, "TempCommBufferSize - 0x%x\n", TempCommBufferSize));
CommData = AllocateCopyPool (TempCommBufferSize, CommBuffer);
if (CommData == NULL) {
DEBUG((DEBUG_ERROR, "TestPointSmmReadyToBootSmmPageProtectionHandler: SMM communication buffer size too big!\n"));
return EFI_SUCCESS;
}
if (CommData->UefiMemoryMapOffset != sizeof(TEST_POINT_SMM_COMMUNICATION_UEFI_GCD_MAP_INFO)) {
DEBUG((DEBUG_ERROR, "TestPointSmmReadyToBootSmmPageProtectionHandler: UefiMemoryMapOffset invalid!\n"));
goto Done;
}
if (CommData->UefiMemoryMapSize >= TempCommBufferSize - CommData->UefiMemoryMapOffset) {
DEBUG((DEBUG_ERROR, "TestPointSmmReadyToBootSmmPageProtectionHandler: UefiMemoryMapSize invalid!\n"));
goto Done;
}
if (CommData->GcdMemoryMapOffset != CommData->UefiMemoryMapOffset + CommData->UefiMemoryMapSize) {
DEBUG((DEBUG_ERROR, "TestPointSmmReadyToBootSmmPageProtectionHandler: GcdMemoryMapOffset invalid!\n"));
goto Done;
}
if (CommData->GcdMemoryMapSize >= TempCommBufferSize - CommData->GcdMemoryMapOffset) {
DEBUG((DEBUG_ERROR, "TestPointSmmReadyToBootSmmPageProtectionHandler: GcdMemoryMapSize invalid!\n"));
goto Done;
}
if (CommData->GcdIoMapOffset != CommData->GcdMemoryMapOffset + CommData->GcdMemoryMapSize) {
DEBUG((DEBUG_ERROR, "TestPointSmmReadyToBootSmmPageProtectionHandler: GcdIoMapOffset invalid!\n"));
goto Done;
}
if (CommData->GcdIoMapSize >= TempCommBufferSize - CommData->GcdIoMapOffset) {
DEBUG((DEBUG_ERROR, "TestPointSmmReadyToBootSmmPageProtectionHandler: GcdIoMapSize invalid!\n"));
goto Done;
}
if (CommData->UefiMemoryAttributeTableOffset != CommData->GcdIoMapOffset + CommData->GcdIoMapSize) {
DEBUG((DEBUG_ERROR, "TestPointSmmReadyToBootSmmPageProtectionHandler: UefiMemoryAttributeTableOffset invalid!\n"));
goto Done;
}
if (CommData->UefiMemoryAttributeTableSize != TempCommBufferSize - CommData->UefiMemoryAttributeTableOffset) {
DEBUG((DEBUG_ERROR, "TestPointSmmReadyToBootSmmPageProtectionHandler: UefiMemoryAttributeTableSize invalid!\n"));
goto Done;
}
if (CommData->UefiMemoryMapSize != 0) {
Result = TRUE;
Status = TestPointCheckSmmCommunicationBuffer (
(EFI_MEMORY_DESCRIPTOR *)(UINTN)((UINTN)CommData + CommData->UefiMemoryMapOffset),
(UINTN)CommData->UefiMemoryMapSize,
mUefiDescriptorSize,
(CommData->UefiMemoryAttributeTableSize != 0) ? (EFI_MEMORY_ATTRIBUTES_TABLE *)(UINTN)((UINTN)CommData + CommData->UefiMemoryAttributeTableOffset) : NULL
);
if (EFI_ERROR(Status)) {
Result = FALSE;
}
if (Result) {
TestPointLibSetFeaturesVerified (
PLATFORM_TEST_POINT_ROLE_PLATFORM_IBV,
NULL,
6,
TEST_POINT_BYTE6_SMM_READY_TO_LOCK_SECURE_SMM_COMMUNICATION_BUFFER
);
} else {
TestPointLibClearFeaturesVerified (
PLATFORM_TEST_POINT_ROLE_PLATFORM_IBV,
NULL,
6,
TEST_POINT_BYTE6_SMM_READY_TO_LOCK_SECURE_SMM_COMMUNICATION_BUFFER
);
}
}
Done:
FreePool (CommData);
DEBUG ((DEBUG_INFO, "======== TestPointSmmReadyToBootSmmPageProtectionHandler - Exit\n"));
return EFI_SUCCESS;
}
/**
Dispatch function for a Software SMI handler.
Caution: This function may receive untrusted input.
Communicate buffer and buffer size are external input, so this function will do basic validation.
@param DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
@param Context Points to an optional handler context which was specified when the
handler was registered.
@param CommBuffer A pointer to a collection of data in memory that will
be conveyed from a non-SMM environment into an SMM environment.
@param CommBufferSize The size of the CommBuffer.
@retval EFI_SUCCESS Command is handled successfully.
**/
EFI_STATUS
EFIAPI
TestPointSmmHandler (
IN EFI_HANDLE DispatchHandle,
IN CONST VOID *Context OPTIONAL,
IN OUT VOID *CommBuffer OPTIONAL,
IN OUT UINTN *CommBufferSize OPTIONAL
)
{
TEST_POINT_SMM_COMMUNICATION_HEADER CommData;
UINTN TempCommBufferSize;
//
// If input is invalid, stop processing this SMI
//
if (CommBuffer == NULL || CommBufferSize == NULL) {
return EFI_SUCCESS;
}
TempCommBufferSize = *CommBufferSize;
if (TempCommBufferSize < sizeof(TEST_POINT_SMM_COMMUNICATION_HEADER)) {
DEBUG((DEBUG_ERROR, "TestPointSmmHandler: SMM communication buffer size invalid!\n"));
return EFI_SUCCESS;
}
CopyMem (&CommData, CommBuffer, sizeof(CommData));
if (CommData.Version != TEST_POINT_SMM_COMMUNICATION_VERSION) {
DEBUG((DEBUG_ERROR, "TestPointSmmHandler: SMM communication Version invalid!\n"));
return EFI_SUCCESS;
}
switch (CommData.FuncId) {
case TEST_POINT_SMM_COMMUNICATION_FUNC_ID_UEFI_GCD_MAP_INFO:
return TestPointSmmReadyToBootSmmPageProtectionHandler (CommBuffer, CommBufferSize);
}
return EFI_SUCCESS;
}
EFI_STATUS
EFIAPI
TestPointSmmExitBootServices (
VOID
)
{
DEBUG ((DEBUG_INFO, "======== TestPointSmmExitBootServices - Enter\n"));
DEBUG ((DEBUG_INFO, "======== TestPointSmmExitBootServices - Exit\n"));
return EFI_SUCCESS;
}
/**
Register SMM Test Point handler.
**/
VOID
RegisterSmmTestPointHandler (
VOID
)
{
EFI_STATUS Status;
EFI_HANDLE DispatchHandle;
Status = gSmst->SmiHandlerRegister (
TestPointSmmHandler,
&mTestPointSmmCommunciationGuid,
&DispatchHandle
);
ASSERT_EFI_ERROR (Status);
}
/**
Initialize feature data
**/
VOID
InitData (
IN UINT32 Role
)
{
EFI_STATUS Status;
ASSERT (PcdGetSize(PcdTestPointIbvPlatformFeature) == sizeof(mFeatureImplemented));
CopyMem (mFeatureImplemented, PcdGetPtr(PcdTestPointIbvPlatformFeature), sizeof(mFeatureImplemented));
mTestPointStruct.Role = Role;
CopyMem (mTestPointStruct.FeaturesImplemented, mFeatureImplemented, sizeof(mFeatureImplemented));
Status = TestPointLibSetTable (
&mTestPointStruct,
sizeof(mTestPointStruct)
);
if (EFI_ERROR (Status)) {
if (Status != EFI_ALREADY_STARTED) {
ASSERT_EFI_ERROR (Status);
}
}
}
EFI_STATUS
EFIAPI
SmmTestPointCheckLibConstructor (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
InitData (PLATFORM_TEST_POINT_ROLE_PLATFORM_IBV);
RegisterSmmTestPointHandler ();
return EFI_SUCCESS;
}