/** @file
|
|
Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
**/
|
|
#include <Uefi.h>
|
#include <PiPei.h>
|
#include <Library/TestPointCheckLib.h>
|
#include <Library/TestPointLib.h>
|
#include <Library/DebugLib.h>
|
#include <Library/HobLib.h>
|
#include <Library/BaseMemoryLib.h>
|
#include <Library/MtrrLib.h>
|
|
#define MEMORY_ATTRIBUTE_MASK (EFI_RESOURCE_ATTRIBUTE_PRESENT | \
|
EFI_RESOURCE_ATTRIBUTE_INITIALIZED | \
|
EFI_RESOURCE_ATTRIBUTE_TESTED | \
|
EFI_RESOURCE_ATTRIBUTE_16_BIT_IO | \
|
EFI_RESOURCE_ATTRIBUTE_32_BIT_IO | \
|
EFI_RESOURCE_ATTRIBUTE_64_BIT_IO \
|
)
|
|
#define TESTED_MEMORY_ATTRIBUTES (EFI_RESOURCE_ATTRIBUTE_PRESENT | EFI_RESOURCE_ATTRIBUTE_INITIALIZED | EFI_RESOURCE_ATTRIBUTE_TESTED)
|
|
#define INITIALIZED_MEMORY_ATTRIBUTES (EFI_RESOURCE_ATTRIBUTE_PRESENT | EFI_RESOURCE_ATTRIBUTE_INITIALIZED)
|
|
#define PRESENT_MEMORY_ATTRIBUTES (EFI_RESOURCE_ATTRIBUTE_PRESENT)
|
|
MTRR_MEMORY_CACHE_TYPE
|
SetCurrentCacheType (
|
IN MTRR_MEMORY_CACHE_TYPE CurrentCacheType,
|
IN MTRR_MEMORY_CACHE_TYPE NewCacheType
|
)
|
{
|
switch (CurrentCacheType) {
|
case CacheUncacheable:
|
return CacheUncacheable;
|
break;
|
case CacheWriteBack:
|
if (NewCacheType == CacheWriteThrough) {
|
return CacheWriteThrough;
|
} else {
|
return CacheInvalid;
|
}
|
break;
|
case CacheWriteThrough:
|
if (NewCacheType == CacheWriteBack) {
|
return CacheWriteThrough;
|
} else {
|
return CacheInvalid;
|
}
|
break;
|
default:
|
if (NewCacheType == CacheUncacheable) {
|
return CacheUncacheable;
|
} else {
|
return CacheInvalid;
|
}
|
break;
|
}
|
}
|
|
EFI_STATUS
|
TestPointCheckCacheType (
|
IN MTRR_SETTINGS *Mtrrs,
|
IN VARIABLE_MTRR *VariableMtrr,
|
IN UINT64 Base,
|
IN UINT64 Length,
|
IN MTRR_MEMORY_CACHE_TYPE ExpectedCacheType
|
)
|
{
|
UINT64 TempBase;
|
UINT64 TempLength;
|
UINTN VariableMtrrIndex;
|
UINTN VariableMtrrCount;
|
|
if (Base < BASE_1MB) {
|
// Check Fixed MTRR
|
return EFI_SUCCESS;
|
}
|
|
//
|
// Check
|
//
|
VariableMtrrCount = GetVariableMtrrCount ();
|
for (VariableMtrrIndex = 0; VariableMtrrIndex < VariableMtrrCount; VariableMtrrIndex++) {
|
if (!VariableMtrr[VariableMtrrIndex].Valid) {
|
continue;
|
}
|
if (((Base >= VariableMtrr[VariableMtrrIndex].BaseAddress) && (Base < VariableMtrr[VariableMtrrIndex].BaseAddress + VariableMtrr[VariableMtrrIndex].Length)) ||
|
((VariableMtrr[VariableMtrrIndex].BaseAddress >= Base) && (VariableMtrr[VariableMtrrIndex].BaseAddress < Base + Length))) {
|
// Overlap check
|
if (VariableMtrr[VariableMtrrIndex].Type != ExpectedCacheType) {
|
DEBUG ((DEBUG_ERROR, "Cache [0x%lx, 0x%lx] is not expected\n", Base, Length));
|
return EFI_INVALID_PARAMETER;
|
}
|
}
|
}
|
TempBase = Base;
|
TempLength = Length;
|
for (VariableMtrrIndex = 0; VariableMtrrIndex < VariableMtrrCount; VariableMtrrIndex++) {
|
if (!VariableMtrr[VariableMtrrIndex].Valid) {
|
continue;
|
}
|
if (((TempBase >= VariableMtrr[VariableMtrrIndex].BaseAddress) && (TempBase < VariableMtrr[VariableMtrrIndex].BaseAddress + VariableMtrr[VariableMtrrIndex].Length)) ||
|
((VariableMtrr[VariableMtrrIndex].BaseAddress >= TempBase) && (VariableMtrr[VariableMtrrIndex].BaseAddress < TempBase + TempLength))) {
|
// Update checked region
|
if (TempBase >= VariableMtrr[VariableMtrrIndex].BaseAddress) {
|
if (TempBase + TempLength > VariableMtrr[VariableMtrrIndex].BaseAddress + VariableMtrr[VariableMtrrIndex].Length) {
|
TempLength = TempBase + TempLength - (VariableMtrr[VariableMtrrIndex].BaseAddress + VariableMtrr[VariableMtrrIndex].Length);
|
TempBase = VariableMtrr[VariableMtrrIndex].BaseAddress + VariableMtrr[VariableMtrrIndex].Length;
|
} else {
|
TempLength = 0;
|
}
|
} else {
|
TempLength = VariableMtrr[VariableMtrrIndex].BaseAddress - TempBase;
|
}
|
}
|
}
|
|
if (TempLength != 0) {
|
if ((Mtrrs->MtrrDefType & 0xFF) != ExpectedCacheType) {
|
DEBUG ((DEBUG_ERROR, "Cache [0x%lx, 0x%lx] is not expected in default\n", TempBase, TempLength));
|
return EFI_INVALID_PARAMETER;
|
}
|
}
|
|
return EFI_SUCCESS;
|
}
|
|
EFI_STATUS
|
TestPointCheckMtrrMask (
|
IN MTRR_SETTINGS *Mtrrs
|
)
|
{
|
UINTN Index;
|
UINT64 Length;
|
UINT32 RegEax;
|
UINT8 PhysicalAddressBits;
|
UINTN VariableMtrrCount;
|
|
AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
|
if (RegEax >= 0x80000008) {
|
AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
|
PhysicalAddressBits = (UINT8) RegEax;
|
} else {
|
PhysicalAddressBits = 36;
|
}
|
|
VariableMtrrCount = GetVariableMtrrCount ();
|
for (Index = 0; Index < VariableMtrrCount; Index++) {
|
if ((Mtrrs->Variables.Mtrr[Index].Mask & BIT11) == 0) {
|
continue;
|
}
|
Length = Mtrrs->Variables.Mtrr[Index].Mask & ~0xFFFull;
|
Length = ~Length + 1;
|
Length = Length & (LShiftU64 (1, PhysicalAddressBits) - 1);
|
if (Length != GetPowerOfTwo64 (Length)) {
|
DEBUG ((DEBUG_ERROR, "MTRR Mask (0x%016lx) is invalid\n", Mtrrs->Variables.Mtrr[Index].Mask));
|
return EFI_INVALID_PARAMETER;
|
}
|
}
|
return EFI_SUCCESS;
|
}
|
|
VOID
|
TestPointMtrrConvert (
|
IN MTRR_SETTINGS *Mtrrs,
|
OUT VARIABLE_MTRR *VariableMtrr
|
)
|
{
|
UINT32 RegEax;
|
UINT8 PhysicalAddressBits;
|
VARIABLE_MTRR TempVariableMtrr;
|
UINTN Index;
|
UINTN VariableMtrrIndex;
|
UINTN VariableMtrrCount;
|
|
AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
|
if (RegEax >= 0x80000008) {
|
AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
|
PhysicalAddressBits = (UINT8) RegEax;
|
} else {
|
PhysicalAddressBits = 36;
|
}
|
|
//
|
// Calculate Length
|
//
|
VariableMtrrIndex = 0;
|
VariableMtrrCount = GetVariableMtrrCount ();
|
for (Index = 0; Index < VariableMtrrCount; Index++) {
|
if ((Mtrrs->Variables.Mtrr[Index].Mask & BIT11) == 0) {
|
continue;
|
}
|
VariableMtrr[VariableMtrrIndex].Length = Mtrrs->Variables.Mtrr[Index].Mask & ~0xFFFull;
|
VariableMtrr[VariableMtrrIndex].Length = ~VariableMtrr[VariableMtrrIndex].Length + 1;
|
VariableMtrr[VariableMtrrIndex].Length = VariableMtrr[VariableMtrrIndex].Length & (LShiftU64 (1, PhysicalAddressBits) - 1);
|
VariableMtrr[VariableMtrrIndex].BaseAddress = Mtrrs->Variables.Mtrr[Index].Base & ~0xFFFull;
|
VariableMtrr[VariableMtrrIndex].Type = Mtrrs->Variables.Mtrr[Index].Base & 0xFF;
|
VariableMtrr[VariableMtrrIndex].Valid = TRUE;
|
VariableMtrrIndex ++;
|
}
|
VariableMtrrCount = VariableMtrrIndex;
|
|
//
|
// Sort
|
//
|
if (VariableMtrrCount > 1) {
|
for (VariableMtrrIndex = 0; VariableMtrrIndex < VariableMtrrCount; VariableMtrrIndex++) {
|
Index = VariableMtrrIndex + 1;
|
for (Index = VariableMtrrIndex + 1; Index < VariableMtrrCount; Index++) {
|
if (VariableMtrr[VariableMtrrIndex].BaseAddress > VariableMtrr[Index].BaseAddress) {
|
CopyMem (&TempVariableMtrr, &VariableMtrr[VariableMtrrIndex], sizeof(VARIABLE_MTRR));
|
CopyMem (&VariableMtrr[VariableMtrrIndex], &VariableMtrr[Index], sizeof(VARIABLE_MTRR));
|
CopyMem (&VariableMtrr[Index], &TempVariableMtrr, sizeof(VARIABLE_MTRR));
|
}
|
}
|
}
|
}
|
|
//
|
// Dump
|
//
|
DEBUG ((DEBUG_INFO, "CACHE Result:\n"));
|
for (VariableMtrrIndex = 0; VariableMtrrIndex < VariableMtrrCount; VariableMtrrIndex++) {
|
if (VariableMtrr[VariableMtrrIndex].Valid) {
|
DEBUG ((DEBUG_INFO, "CACHE - 0x%016lx 0x%016lx %d\n",
|
VariableMtrr[VariableMtrrIndex].BaseAddress,
|
VariableMtrr[VariableMtrrIndex].Length,
|
VariableMtrr[VariableMtrrIndex].Type
|
));
|
}
|
}
|
|
//
|
// Remove overlap
|
//
|
if (VariableMtrrCount > 1) {
|
for (VariableMtrrIndex = 0; VariableMtrrIndex < VariableMtrrCount; VariableMtrrIndex++) {
|
Index = VariableMtrrIndex + 1;
|
for (Index = VariableMtrrIndex + 1; Index < VariableMtrrCount - 1; Index++) {
|
if (VariableMtrr[VariableMtrrIndex].BaseAddress + VariableMtrr[VariableMtrrIndex].Length > VariableMtrr[Index].BaseAddress) {
|
VariableMtrr[VariableMtrrIndex].Length = VariableMtrr[Index].BaseAddress - VariableMtrr[VariableMtrrIndex].BaseAddress;
|
}
|
}
|
}
|
}
|
|
//
|
// Dump
|
//
|
DEBUG ((DEBUG_INFO, "CACHE Final:\n"));
|
for (VariableMtrrIndex = 0; VariableMtrrIndex < VariableMtrrCount; VariableMtrrIndex++) {
|
if (VariableMtrr[VariableMtrrIndex].Valid) {
|
DEBUG ((DEBUG_INFO, "CACHE - 0x%016lx 0x%016lx %d\n",
|
VariableMtrr[VariableMtrrIndex].BaseAddress,
|
VariableMtrr[VariableMtrrIndex].Length,
|
VariableMtrr[VariableMtrrIndex].Type
|
));
|
}
|
}
|
}
|
|
EFI_STATUS
|
TestPointCheckMtrrForPei (
|
IN MTRR_SETTINGS *Mtrrs,
|
IN VARIABLE_MTRR *VariableMtrr
|
)
|
{
|
EFI_STATUS Status;
|
VOID *HobList;
|
EFI_HOB_HANDOFF_INFO_TABLE *PhitHob;
|
|
HobList = GetHobList ();
|
PhitHob = HobList;
|
|
//
|
// DRAM must be WB
|
//
|
DEBUG ((DEBUG_INFO, "MTRR Checking 0x%lx 0x%lx\n", PhitHob->EfiMemoryBottom, PhitHob->EfiMemoryTop - PhitHob->EfiMemoryBottom));
|
Status = TestPointCheckCacheType (
|
Mtrrs,
|
VariableMtrr,
|
PhitHob->EfiMemoryBottom,
|
PhitHob->EfiMemoryTop - PhitHob->EfiMemoryBottom,
|
CacheWriteBack
|
);
|
if (EFI_ERROR(Status)) {
|
return Status;
|
}
|
|
//
|
// FV must be WB or WP
|
//
|
|
//
|
// MMIO must be UC
|
//
|
|
return EFI_SUCCESS;
|
}
|
|
EFI_STATUS
|
TestPointCheckMtrrForDxe (
|
IN MTRR_SETTINGS *Mtrrs,
|
IN VARIABLE_MTRR *VariableMtrr
|
)
|
{
|
EFI_STATUS Status;
|
VOID *HobList;
|
EFI_PEI_HOB_POINTERS Hob;
|
EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob;
|
|
HobList = GetHobList ();
|
|
//
|
// DRAM must be WB
|
//
|
for (Hob.Raw = HobList; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {
|
if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
|
ResourceHob = Hob.ResourceDescriptor;
|
switch (ResourceHob->ResourceType) {
|
case EFI_RESOURCE_SYSTEM_MEMORY:
|
if (((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) == TESTED_MEMORY_ATTRIBUTES) ||
|
((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) == INITIALIZED_MEMORY_ATTRIBUTES)) {
|
DEBUG ((DEBUG_INFO, "MTRR Checking 0x%lx 0x%lx\n", ResourceHob->PhysicalStart, ResourceHob->ResourceLength));
|
Status = TestPointCheckCacheType (
|
Mtrrs,
|
VariableMtrr,
|
ResourceHob->PhysicalStart,
|
ResourceHob->ResourceLength,
|
CacheWriteBack
|
);
|
if (EFI_ERROR(Status)) {
|
return Status;
|
}
|
}
|
break;
|
default:
|
break;
|
}
|
}
|
}
|
|
//
|
// FV must be WB or WP
|
//
|
|
//
|
// MMIO must be UC
|
//
|
|
return EFI_SUCCESS;
|
}
|
|
EFI_STATUS
|
TestPointCheckMtrr (
|
IN BOOLEAN IsForDxe
|
)
|
{
|
EFI_STATUS Status;
|
MTRR_SETTINGS LocalMtrrs;
|
MTRR_SETTINGS *Mtrrs;
|
UINTN Index;
|
UINTN VariableMtrrCount;
|
BOOLEAN Result;
|
VARIABLE_MTRR VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];
|
|
DEBUG ((DEBUG_INFO, "==== TestPointCheckMtrr - Enter\n"));
|
|
MtrrGetAllMtrrs (&LocalMtrrs);
|
Mtrrs = &LocalMtrrs;
|
DEBUG ((DEBUG_INFO, "MTRR Default Type: %016lx\n", Mtrrs->MtrrDefType));
|
for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
|
DEBUG ((DEBUG_INFO, "Fixed MTRR[%02d] : %016lx\n", Index, Mtrrs->Fixed.Mtrr[Index]));
|
}
|
|
VariableMtrrCount = GetVariableMtrrCount ();
|
for (Index = 0; Index < VariableMtrrCount; Index++) {
|
DEBUG ((DEBUG_INFO, "Variable MTRR[%02d]: Base=%016lx Mask=%016lx\n",
|
Index,
|
Mtrrs->Variables.Mtrr[Index].Base,
|
Mtrrs->Variables.Mtrr[Index].Mask
|
));
|
}
|
DEBUG ((DEBUG_INFO, "\n"));
|
DEBUG ((DEBUG_INFO, "==== TestPointCheckMtrr - Exit\n"));
|
|
//
|
// Check Mask
|
//
|
Status = TestPointCheckMtrrMask (Mtrrs);
|
if (EFI_ERROR(Status)) {
|
Result = FALSE;
|
} else {
|
|
ZeroMem (VariableMtrr, sizeof(VariableMtrr));
|
TestPointMtrrConvert (Mtrrs, VariableMtrr);
|
|
if (IsForDxe) {
|
Status = TestPointCheckMtrrForDxe (Mtrrs, VariableMtrr);
|
} else {
|
Status = TestPointCheckMtrrForPei (Mtrrs, VariableMtrr);
|
}
|
if (EFI_ERROR(Status)) {
|
Result = FALSE;
|
} else {
|
Result = TRUE;
|
}
|
}
|
|
if (!Result) {
|
if (IsForDxe) {
|
TestPointLibAppendErrorString (
|
PLATFORM_TEST_POINT_ROLE_PLATFORM_IBV,
|
NULL,
|
TEST_POINT_BYTE2_END_OF_PEI_MTRR_FUNCTIONAL_ERROR_CODE \
|
TEST_POINT_END_OF_PEI \
|
TEST_POINT_BYTE2_END_OF_PEI_MTRR_FUNCTIONAL_ERROR_STRING
|
);
|
} else {
|
TestPointLibAppendErrorString (
|
PLATFORM_TEST_POINT_ROLE_PLATFORM_IBV,
|
NULL,
|
TEST_POINT_BYTE1_MEMORY_DISCOVERED_MTRR_FUNCTIONAL_ERROR_CODE \
|
TEST_POINT_MEMORY_DISCOVERED \
|
TEST_POINT_BYTE1_MEMORY_DISCOVERED_MTRR_FUNCTIONAL_ERROR_STRING
|
);
|
}
|
}
|
|
return Status;
|
}
|