mirror of https://github.com/acidanthera/audk.git
MdeModulePkg: Add GenericMemoryTestDxe driver
Signed-off-by: jljusten Reviewed-by: mdkinney git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@11937 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
parent
ab94587a7d
commit
7c636bd022
|
@ -245,6 +245,7 @@
|
||||||
MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/EnglishDxe.inf
|
MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/EnglishDxe.inf
|
||||||
MdeModulePkg/Universal/DriverSampleDxe/DriverSampleDxe.inf
|
MdeModulePkg/Universal/DriverSampleDxe/DriverSampleDxe.inf
|
||||||
MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseDxe.inf
|
MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseDxe.inf
|
||||||
|
MdeModulePkg/Universal/MemoryTest/GenericMemoryTestDxe/GenericMemoryTestDxe.inf
|
||||||
MdeModulePkg/Universal/MemoryTest/NullMemoryTestDxe/NullMemoryTestDxe.inf
|
MdeModulePkg/Universal/MemoryTest/NullMemoryTestDxe/NullMemoryTestDxe.inf
|
||||||
MdeModulePkg/Universal/Metronome/Metronome.inf
|
MdeModulePkg/Universal/Metronome/Metronome.inf
|
||||||
MdeModulePkg/Universal/MonotonicCounterRuntimeDxe/MonotonicCounterRuntimeDxe.inf
|
MdeModulePkg/Universal/MonotonicCounterRuntimeDxe/MonotonicCounterRuntimeDxe.inf
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
## @file
|
||||||
|
# Component description file for Generic memory test.
|
||||||
|
#
|
||||||
|
# This driver first constructs the non-tested memory range,
|
||||||
|
# then performs the R/W/V memory test.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
#
|
||||||
|
##
|
||||||
|
|
||||||
|
[Defines]
|
||||||
|
INF_VERSION = 0x00010005
|
||||||
|
BASE_NAME = GenericMemoryTestDxe
|
||||||
|
FILE_GUID = 9C1080EE-D02E-487f-9432-F3BF086EC180
|
||||||
|
MODULE_TYPE = DXE_DRIVER
|
||||||
|
VERSION_STRING = 1.0
|
||||||
|
|
||||||
|
ENTRY_POINT = GenericMemoryTestEntryPoint
|
||||||
|
|
||||||
|
#
|
||||||
|
# The following information is for reference only and not required by the build tools.
|
||||||
|
#
|
||||||
|
# VALID_ARCHITECTURES = IA32 X64 IPF EBC
|
||||||
|
#
|
||||||
|
|
||||||
|
[Sources]
|
||||||
|
LightMemoryTest.h
|
||||||
|
LightMemoryTest.c
|
||||||
|
|
||||||
|
[Packages]
|
||||||
|
MdePkg/MdePkg.dec
|
||||||
|
MdeModulePkg/MdeModulePkg.dec
|
||||||
|
|
||||||
|
[LibraryClasses]
|
||||||
|
UefiBootServicesTableLib
|
||||||
|
MemoryAllocationLib
|
||||||
|
BaseMemoryLib
|
||||||
|
BaseLib
|
||||||
|
ReportStatusCodeLib
|
||||||
|
DxeServicesTableLib
|
||||||
|
HobLib
|
||||||
|
UefiDriverEntryPoint
|
||||||
|
DebugLib
|
||||||
|
|
||||||
|
[Protocols]
|
||||||
|
gEfiCpuArchProtocolGuid # PROTOCOL ALWAYS_CONSUMED
|
||||||
|
gEfiGenericMemTestProtocolGuid # PROTOCOL ALWAYS_PRODUCED
|
||||||
|
|
||||||
|
[Depex]
|
||||||
|
gEfiCpuArchProtocolGuid
|
||||||
|
|
|
@ -0,0 +1,906 @@
|
||||||
|
/** @file
|
||||||
|
|
||||||
|
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 "LightMemoryTest.h"
|
||||||
|
|
||||||
|
//
|
||||||
|
// Global:
|
||||||
|
// Since this driver will only ever produce one instance of the memory test
|
||||||
|
// protocol, so we do not need to dynamically allocate the PrivateData.
|
||||||
|
//
|
||||||
|
EFI_PHYSICAL_ADDRESS mCurrentAddress;
|
||||||
|
LIST_ENTRY *mCurrentLink;
|
||||||
|
NONTESTED_MEMORY_RANGE *mCurrentRange;
|
||||||
|
UINT64 mTestedSystemMemory;
|
||||||
|
UINT64 mNonTestedSystemMemory;
|
||||||
|
|
||||||
|
UINT32 GenericMemoryTestMonoPattern[GENERIC_CACHELINE_SIZE / 4] = {
|
||||||
|
0x5a5a5a5a,
|
||||||
|
0xa5a5a5a5,
|
||||||
|
0x5a5a5a5a,
|
||||||
|
0xa5a5a5a5,
|
||||||
|
0x5a5a5a5a,
|
||||||
|
0xa5a5a5a5,
|
||||||
|
0x5a5a5a5a,
|
||||||
|
0xa5a5a5a5,
|
||||||
|
0x5a5a5a5a,
|
||||||
|
0xa5a5a5a5,
|
||||||
|
0x5a5a5a5a,
|
||||||
|
0xa5a5a5a5,
|
||||||
|
0x5a5a5a5a,
|
||||||
|
0xa5a5a5a5,
|
||||||
|
0x5a5a5a5a,
|
||||||
|
0xa5a5a5a5
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
Compares the contents of two buffers.
|
||||||
|
|
||||||
|
This function compares Length bytes of SourceBuffer to Length bytes of DestinationBuffer.
|
||||||
|
If all Length bytes of the two buffers are identical, then 0 is returned. Otherwise, the
|
||||||
|
value returned is the first mismatched byte in SourceBuffer subtracted from the first
|
||||||
|
mismatched byte in DestinationBuffer.
|
||||||
|
|
||||||
|
If Length = 0, then ASSERT().
|
||||||
|
|
||||||
|
@param[in] DestinationBuffer The pointer to the destination buffer to compare.
|
||||||
|
@param[in] SourceBuffer The pointer to the source buffer to compare.
|
||||||
|
@param[in] Length The number of bytes to compare.
|
||||||
|
|
||||||
|
@return 0 All Length bytes of the two buffers are identical.
|
||||||
|
@retval Non-zero The first mismatched byte in SourceBuffer subtracted from the first
|
||||||
|
mismatched byte in DestinationBuffer.
|
||||||
|
|
||||||
|
**/
|
||||||
|
INTN
|
||||||
|
EFIAPI
|
||||||
|
CompareMemWithoutCheckArgument (
|
||||||
|
IN CONST VOID *DestinationBuffer,
|
||||||
|
IN CONST VOID *SourceBuffer,
|
||||||
|
IN UINTN Length
|
||||||
|
)
|
||||||
|
{
|
||||||
|
ASSERT (Length > 0);
|
||||||
|
while ((--Length != 0) &&
|
||||||
|
(*(INT8*)DestinationBuffer == *(INT8*)SourceBuffer)) {
|
||||||
|
DestinationBuffer = (INT8*)DestinationBuffer + 1;
|
||||||
|
SourceBuffer = (INT8*)SourceBuffer + 1;
|
||||||
|
}
|
||||||
|
return (INTN)*(UINT8*)DestinationBuffer - (INTN)*(UINT8*)SourceBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Construct the system base memory range through GCD service.
|
||||||
|
|
||||||
|
@param[in] Private Point to generic memory test driver's private data.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS Successful construct the base memory range through GCD service.
|
||||||
|
@retval EFI_OUT_OF_RESOURCE Could not allocate needed resource from base memory.
|
||||||
|
@retval Others Failed to construct base memory range through GCD service.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
ConstructBaseMemoryRange (
|
||||||
|
IN GENERIC_MEMORY_TEST_PRIVATE *Private
|
||||||
|
)
|
||||||
|
{
|
||||||
|
UINTN NumberOfDescriptors;
|
||||||
|
EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap;
|
||||||
|
UINTN Index;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Base memory will always below 4G
|
||||||
|
//
|
||||||
|
gDS->GetMemorySpaceMap (&NumberOfDescriptors, &MemorySpaceMap);
|
||||||
|
|
||||||
|
for (Index = 0; Index < NumberOfDescriptors; Index++) {
|
||||||
|
if (MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeSystemMemory) {
|
||||||
|
Private->BaseMemorySize += MemorySpaceMap[Index].Length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Destroy the link list base on the correspond link list type.
|
||||||
|
|
||||||
|
@param[in] Private Point to generic memory test driver's private data.
|
||||||
|
|
||||||
|
**/
|
||||||
|
VOID
|
||||||
|
DestroyLinkList (
|
||||||
|
IN GENERIC_MEMORY_TEST_PRIVATE *Private
|
||||||
|
)
|
||||||
|
{
|
||||||
|
LIST_ENTRY *Link;
|
||||||
|
NONTESTED_MEMORY_RANGE *NontestedRange;
|
||||||
|
|
||||||
|
Link = Private->NonTestedMemRanList.BackLink;
|
||||||
|
|
||||||
|
while (Link != &Private->NonTestedMemRanList) {
|
||||||
|
RemoveEntryList (Link);
|
||||||
|
NontestedRange = NONTESTED_MEMORY_RANGE_FROM_LINK (Link);
|
||||||
|
gBS->FreePool (NontestedRange);
|
||||||
|
Link = Private->NonTestedMemRanList.BackLink;;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Add the extened memory to whole system memory map.
|
||||||
|
|
||||||
|
@param[in] Private Point to generic memory test driver's private data.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS Successful add all the extended memory to system memory map.
|
||||||
|
@retval Others Failed to add the tested extended memory.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
UpdateMemoryMap (
|
||||||
|
IN GENERIC_MEMORY_TEST_PRIVATE *Private
|
||||||
|
)
|
||||||
|
{
|
||||||
|
LIST_ENTRY *Link;
|
||||||
|
NONTESTED_MEMORY_RANGE *Range;
|
||||||
|
|
||||||
|
Link = Private->NonTestedMemRanList.ForwardLink;
|
||||||
|
|
||||||
|
while (Link != &Private->NonTestedMemRanList) {
|
||||||
|
Range = NONTESTED_MEMORY_RANGE_FROM_LINK (Link);
|
||||||
|
|
||||||
|
gDS->RemoveMemorySpace (
|
||||||
|
Range->StartAddress,
|
||||||
|
Range->Length
|
||||||
|
);
|
||||||
|
|
||||||
|
gDS->AddMemorySpace (
|
||||||
|
EfiGcdMemoryTypeSystemMemory,
|
||||||
|
Range->StartAddress,
|
||||||
|
Range->Length,
|
||||||
|
Range->Capabilities &~(EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED | EFI_MEMORY_RUNTIME)
|
||||||
|
);
|
||||||
|
|
||||||
|
Link = Link->ForwardLink;
|
||||||
|
}
|
||||||
|
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Test a range of the memory directly .
|
||||||
|
|
||||||
|
@param[in] Private Point to generic memory test driver's private data.
|
||||||
|
@param[in] StartAddress Starting address of the memory range to be tested.
|
||||||
|
@param[in] Length Length in bytes of the memory range to be tested.
|
||||||
|
@param[in] Capabilities The bit mask of attributes that the memory range supports.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS Successful test the range of memory.
|
||||||
|
@retval Others Failed to test the range of memory.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
DirectRangeTest (
|
||||||
|
IN GENERIC_MEMORY_TEST_PRIVATE *Private,
|
||||||
|
IN EFI_PHYSICAL_ADDRESS StartAddress,
|
||||||
|
IN UINT64 Length,
|
||||||
|
IN UINT64 Capabilities
|
||||||
|
)
|
||||||
|
{
|
||||||
|
EFI_STATUS Status;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Perform a dummy memory test, so directly write the pattern to all range
|
||||||
|
//
|
||||||
|
WriteMemory (Private, StartAddress, Length);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Verify the memory range
|
||||||
|
//
|
||||||
|
Status = VerifyMemory (Private, StartAddress, Length);
|
||||||
|
if (EFI_ERROR (Status)) {
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// Add the tested compatible memory to system memory using GCD service
|
||||||
|
//
|
||||||
|
gDS->RemoveMemorySpace (
|
||||||
|
StartAddress,
|
||||||
|
Length
|
||||||
|
);
|
||||||
|
|
||||||
|
gDS->AddMemorySpace (
|
||||||
|
EfiGcdMemoryTypeSystemMemory,
|
||||||
|
StartAddress,
|
||||||
|
Length,
|
||||||
|
Capabilities &~(EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED | EFI_MEMORY_RUNTIME)
|
||||||
|
);
|
||||||
|
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Construct the system non-tested memory range through GCD service.
|
||||||
|
|
||||||
|
@param[in] Private Point to generic memory test driver's private data.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS Successful construct the non-tested memory range through GCD service.
|
||||||
|
@retval EFI_OUT_OF_RESOURCE Could not allocate needed resource from base memory.
|
||||||
|
@retval Others Failed to construct non-tested memory range through GCD service.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
ConstructNonTestedMemoryRange (
|
||||||
|
IN GENERIC_MEMORY_TEST_PRIVATE *Private
|
||||||
|
)
|
||||||
|
{
|
||||||
|
NONTESTED_MEMORY_RANGE *Range;
|
||||||
|
BOOLEAN NoFound;
|
||||||
|
UINTN NumberOfDescriptors;
|
||||||
|
EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap;
|
||||||
|
UINTN Index;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Non tested memory range may be span 4G here
|
||||||
|
//
|
||||||
|
NoFound = TRUE;
|
||||||
|
|
||||||
|
gDS->GetMemorySpaceMap (&NumberOfDescriptors, &MemorySpaceMap);
|
||||||
|
|
||||||
|
for (Index = 0; Index < NumberOfDescriptors; Index++) {
|
||||||
|
if (MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeReserved &&
|
||||||
|
(MemorySpaceMap[Index].Capabilities & (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED)) ==
|
||||||
|
(EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED)
|
||||||
|
) {
|
||||||
|
NoFound = FALSE;
|
||||||
|
//
|
||||||
|
// Light version do not need to process >4G memory range
|
||||||
|
//
|
||||||
|
gBS->AllocatePool (
|
||||||
|
EfiBootServicesData,
|
||||||
|
sizeof (NONTESTED_MEMORY_RANGE),
|
||||||
|
(VOID **) &Range
|
||||||
|
);
|
||||||
|
|
||||||
|
Range->Signature = EFI_NONTESTED_MEMORY_RANGE_SIGNATURE;
|
||||||
|
Range->StartAddress = MemorySpaceMap[Index].BaseAddress;
|
||||||
|
Range->Length = MemorySpaceMap[Index].Length;
|
||||||
|
Range->Capabilities = MemorySpaceMap[Index].Capabilities;
|
||||||
|
|
||||||
|
mNonTestedSystemMemory += MemorySpaceMap[Index].Length;
|
||||||
|
InsertTailList (&Private->NonTestedMemRanList, &Range->Link);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NoFound) {
|
||||||
|
return EFI_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Write the memory test pattern into a range of physical memory.
|
||||||
|
|
||||||
|
@param[in] Private Point to generic memory test driver's private data.
|
||||||
|
@param[in] Start The memory range's start address.
|
||||||
|
@param[in] Size The memory range's size.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS Successful write the test pattern into the non-tested memory.
|
||||||
|
@retval Others The test pattern may not really write into the physical memory.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
WriteMemory (
|
||||||
|
IN GENERIC_MEMORY_TEST_PRIVATE *Private,
|
||||||
|
IN EFI_PHYSICAL_ADDRESS Start,
|
||||||
|
IN UINT64 Size
|
||||||
|
)
|
||||||
|
{
|
||||||
|
EFI_PHYSICAL_ADDRESS Address;
|
||||||
|
|
||||||
|
Address = Start;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Add 4G memory address check for IA32 platform
|
||||||
|
// NOTE: Without page table, there is no way to use memory above 4G.
|
||||||
|
//
|
||||||
|
if (Start + Size > MAX_ADDRESS) {
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (Address < (Start + Size)) {
|
||||||
|
CopyMem ((VOID *) (UINTN) Address, Private->MonoPattern, Private->MonoTestSize);
|
||||||
|
Address += Private->CoverageSpan;
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// bug bug: we may need GCD service to make the code cache and data uncache,
|
||||||
|
// if GCD do not support it or return fail, then just flush the whole cache.
|
||||||
|
//
|
||||||
|
if (Private->Cpu != NULL) {
|
||||||
|
Private->Cpu->FlushDataCache (Private->Cpu, Start, Size, EfiCpuFlushTypeWriteBackInvalidate);
|
||||||
|
}
|
||||||
|
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Verify the range of physical memory which covered by memory test pattern.
|
||||||
|
|
||||||
|
This function will also do not return any informatin just cause system reset,
|
||||||
|
because the handle error encount fatal error and disable the bad DIMMs.
|
||||||
|
|
||||||
|
@param[in] Private Point to generic memory test driver's private data.
|
||||||
|
@param[in] Start The memory range's start address.
|
||||||
|
@param[in] Size The memory range's size.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS Successful verify the range of memory, no errors' location found.
|
||||||
|
@retval Others The range of memory have errors contained.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
VerifyMemory (
|
||||||
|
IN GENERIC_MEMORY_TEST_PRIVATE *Private,
|
||||||
|
IN EFI_PHYSICAL_ADDRESS Start,
|
||||||
|
IN UINT64 Size
|
||||||
|
)
|
||||||
|
{
|
||||||
|
EFI_PHYSICAL_ADDRESS Address;
|
||||||
|
INTN ErrorFound;
|
||||||
|
EFI_MEMORY_EXTENDED_ERROR_DATA *ExtendedErrorData;
|
||||||
|
|
||||||
|
Address = Start;
|
||||||
|
ExtendedErrorData = NULL;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Add 4G memory address check for IA32 platform
|
||||||
|
// NOTE: Without page table, there is no way to use memory above 4G.
|
||||||
|
//
|
||||||
|
if (Start + Size > MAX_ADDRESS) {
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Use the software memory test to check whether have detected miscompare
|
||||||
|
// error here. If there is miscompare error here then check if generic
|
||||||
|
// memory test driver can disable the bad DIMM.
|
||||||
|
//
|
||||||
|
while (Address < (Start + Size)) {
|
||||||
|
ErrorFound = CompareMemWithoutCheckArgument (
|
||||||
|
(VOID *) (UINTN) (Address),
|
||||||
|
Private->MonoPattern,
|
||||||
|
Private->MonoTestSize
|
||||||
|
);
|
||||||
|
if (ErrorFound != 0) {
|
||||||
|
//
|
||||||
|
// Report uncorrectable errors
|
||||||
|
//
|
||||||
|
ExtendedErrorData = AllocateZeroPool (sizeof (EFI_MEMORY_EXTENDED_ERROR_DATA));
|
||||||
|
if (ExtendedErrorData == NULL) {
|
||||||
|
return EFI_OUT_OF_RESOURCES;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExtendedErrorData->DataHeader.HeaderSize = (UINT16) sizeof (EFI_STATUS_CODE_DATA);
|
||||||
|
ExtendedErrorData->DataHeader.Size = (UINT16) (sizeof (EFI_MEMORY_EXTENDED_ERROR_DATA) - sizeof (EFI_STATUS_CODE_DATA));
|
||||||
|
ExtendedErrorData->Granularity = EFI_MEMORY_ERROR_DEVICE;
|
||||||
|
ExtendedErrorData->Operation = EFI_MEMORY_OPERATION_READ;
|
||||||
|
ExtendedErrorData->Syndrome = 0x0;
|
||||||
|
ExtendedErrorData->Address = Address;
|
||||||
|
ExtendedErrorData->Resolution = 0x40;
|
||||||
|
|
||||||
|
REPORT_STATUS_CODE_EX (
|
||||||
|
EFI_ERROR_CODE,
|
||||||
|
EFI_COMPUTING_UNIT_MEMORY | EFI_CU_MEMORY_EC_UNCORRECTABLE,
|
||||||
|
0,
|
||||||
|
&gEfiGenericMemTestProtocolGuid,
|
||||||
|
NULL,
|
||||||
|
(UINT8 *) ExtendedErrorData + sizeof (EFI_STATUS_CODE_DATA),
|
||||||
|
ExtendedErrorData->DataHeader.Size
|
||||||
|
);
|
||||||
|
|
||||||
|
return EFI_DEVICE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
Address += Private->CoverageSpan;
|
||||||
|
}
|
||||||
|
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Initialize the generic memory test.
|
||||||
|
|
||||||
|
@param[in] This The protocol instance pointer.
|
||||||
|
@param[in] Level The coverage level of the memory test.
|
||||||
|
@param[out] RequireSoftECCInit Indicate if the memory need software ECC init.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS The generic memory test is initialized correctly.
|
||||||
|
@retval EFI_NO_MEDIA The system had no memory to be tested.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
EFIAPI
|
||||||
|
InitializeMemoryTest (
|
||||||
|
IN EFI_GENERIC_MEMORY_TEST_PROTOCOL *This,
|
||||||
|
IN EXTENDMEM_COVERAGE_LEVEL Level,
|
||||||
|
OUT BOOLEAN *RequireSoftECCInit
|
||||||
|
)
|
||||||
|
{
|
||||||
|
EFI_STATUS Status;
|
||||||
|
GENERIC_MEMORY_TEST_PRIVATE *Private;
|
||||||
|
EFI_CPU_ARCH_PROTOCOL *Cpu;
|
||||||
|
|
||||||
|
Private = GENERIC_MEMORY_TEST_PRIVATE_FROM_THIS (This);
|
||||||
|
*RequireSoftECCInit = FALSE;
|
||||||
|
|
||||||
|
//
|
||||||
|
// This is initialize for default value, but some value may be reset base on
|
||||||
|
// platform memory test driver.
|
||||||
|
//
|
||||||
|
Private->CoverLevel = Level;
|
||||||
|
Private->BdsBlockSize = TEST_BLOCK_SIZE;
|
||||||
|
Private->MonoPattern = GenericMemoryTestMonoPattern;
|
||||||
|
Private->MonoTestSize = GENERIC_CACHELINE_SIZE;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Initialize several internal link list
|
||||||
|
//
|
||||||
|
InitializeListHead (&Private->NonTestedMemRanList);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Construct base memory range
|
||||||
|
//
|
||||||
|
ConstructBaseMemoryRange (Private);
|
||||||
|
|
||||||
|
//
|
||||||
|
// get the cpu arch protocol to support flash cache
|
||||||
|
//
|
||||||
|
Status = gBS->LocateProtocol (
|
||||||
|
&gEfiCpuArchProtocolGuid,
|
||||||
|
NULL,
|
||||||
|
(VOID **) &Cpu
|
||||||
|
);
|
||||||
|
if (!EFI_ERROR (Status)) {
|
||||||
|
Private->Cpu = Cpu;
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// Create the CoverageSpan of the memory test base on the coverage level
|
||||||
|
//
|
||||||
|
switch (Private->CoverLevel) {
|
||||||
|
case EXTENSIVE:
|
||||||
|
Private->CoverageSpan = GENERIC_CACHELINE_SIZE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SPARSE:
|
||||||
|
Private->CoverageSpan = SPARSE_SPAN_SIZE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Even the BDS do not need to test any memory, but in some case it
|
||||||
|
// still need to init ECC memory.
|
||||||
|
//
|
||||||
|
default:
|
||||||
|
Private->CoverageSpan = QUICK_SPAN_SIZE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// This is the first time we construct the non-tested memory range, if no
|
||||||
|
// extended memory found, we know the system have not any extended memory
|
||||||
|
// need to be test
|
||||||
|
//
|
||||||
|
Status = ConstructNonTestedMemoryRange (Private);
|
||||||
|
if (Status == EFI_NOT_FOUND) {
|
||||||
|
return EFI_NO_MEDIA;
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// ready to perform the R/W/V memory test
|
||||||
|
//
|
||||||
|
mTestedSystemMemory = Private->BaseMemorySize;
|
||||||
|
mCurrentLink = Private->NonTestedMemRanList.ForwardLink;
|
||||||
|
mCurrentRange = NONTESTED_MEMORY_RANGE_FROM_LINK (mCurrentLink);
|
||||||
|
mCurrentAddress = mCurrentRange->StartAddress;
|
||||||
|
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Perform the memory test.
|
||||||
|
|
||||||
|
@param[in] This The protocol instance pointer.
|
||||||
|
@param[out] TestedMemorySize Return the tested extended memory size.
|
||||||
|
@param[out] TotalMemorySize Return the whole system physical memory size.
|
||||||
|
The total memory size does not include memory in a slot with a disabled DIMM.
|
||||||
|
@param[out] ErrorOut TRUE if the memory error occured.
|
||||||
|
@param[in] IfTestAbort Indicates that the user pressed "ESC" to skip the memory test.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS One block of memory passed the test.
|
||||||
|
@retval EFI_NOT_FOUND All memory blocks have already been tested.
|
||||||
|
@retval EFI_DEVICE_ERROR Memory device error occured, and no agent can handle it.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
EFIAPI
|
||||||
|
GenPerformMemoryTest (
|
||||||
|
IN EFI_GENERIC_MEMORY_TEST_PROTOCOL *This,
|
||||||
|
OUT UINT64 *TestedMemorySize,
|
||||||
|
OUT UINT64 *TotalMemorySize,
|
||||||
|
OUT BOOLEAN *ErrorOut,
|
||||||
|
IN BOOLEAN TestAbort
|
||||||
|
)
|
||||||
|
{
|
||||||
|
EFI_STATUS Status;
|
||||||
|
GENERIC_MEMORY_TEST_PRIVATE *Private;
|
||||||
|
EFI_MEMORY_RANGE_EXTENDED_DATA *RangeData;
|
||||||
|
UINT64 BlockBoundary;
|
||||||
|
|
||||||
|
Private = GENERIC_MEMORY_TEST_PRIVATE_FROM_THIS (This);
|
||||||
|
*ErrorOut = FALSE;
|
||||||
|
RangeData = NULL;
|
||||||
|
BlockBoundary = 0;
|
||||||
|
|
||||||
|
//
|
||||||
|
// In extensive mode the boundary of "mCurrentRange->Length" may will lost
|
||||||
|
// some range that is not Private->BdsBlockSize size boundry, so need
|
||||||
|
// the software mechanism to confirm all memory location be covered.
|
||||||
|
//
|
||||||
|
if (mCurrentAddress < (mCurrentRange->StartAddress + mCurrentRange->Length)) {
|
||||||
|
if ((mCurrentAddress + Private->BdsBlockSize) <= (mCurrentRange->StartAddress + mCurrentRange->Length)) {
|
||||||
|
BlockBoundary = Private->BdsBlockSize;
|
||||||
|
} else {
|
||||||
|
BlockBoundary = mCurrentRange->StartAddress + mCurrentRange->Length - mCurrentAddress;
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// If TestAbort is true, means user cancel the memory test
|
||||||
|
//
|
||||||
|
if (!TestAbort && Private->CoverLevel != IGNORE) {
|
||||||
|
//
|
||||||
|
// Report status code of every memory range
|
||||||
|
//
|
||||||
|
RangeData = AllocateZeroPool (sizeof (EFI_MEMORY_RANGE_EXTENDED_DATA));
|
||||||
|
if (RangeData == NULL) {
|
||||||
|
return EFI_OUT_OF_RESOURCES;
|
||||||
|
}
|
||||||
|
RangeData->DataHeader.HeaderSize = (UINT16) sizeof (EFI_STATUS_CODE_DATA);
|
||||||
|
RangeData->DataHeader.Size = (UINT16) (sizeof (EFI_MEMORY_RANGE_EXTENDED_DATA) - sizeof (EFI_STATUS_CODE_DATA));
|
||||||
|
RangeData->Start = mCurrentAddress;
|
||||||
|
RangeData->Length = BlockBoundary;
|
||||||
|
|
||||||
|
REPORT_STATUS_CODE_EX (
|
||||||
|
EFI_PROGRESS_CODE,
|
||||||
|
EFI_COMPUTING_UNIT_MEMORY | EFI_CU_MEMORY_PC_TEST,
|
||||||
|
0,
|
||||||
|
&gEfiGenericMemTestProtocolGuid,
|
||||||
|
NULL,
|
||||||
|
(UINT8 *) RangeData + sizeof (EFI_STATUS_CODE_DATA),
|
||||||
|
RangeData->DataHeader.Size
|
||||||
|
);
|
||||||
|
|
||||||
|
//
|
||||||
|
// The software memory test (R/W/V) perform here. It will detect the
|
||||||
|
// memory mis-compare error.
|
||||||
|
//
|
||||||
|
WriteMemory (Private, mCurrentAddress, BlockBoundary);
|
||||||
|
|
||||||
|
Status = VerifyMemory (Private, mCurrentAddress, BlockBoundary);
|
||||||
|
if (EFI_ERROR (Status)) {
|
||||||
|
//
|
||||||
|
// If perform here, means there is mis-compare error, and no agent can
|
||||||
|
// handle it, so we return to BDS EFI_DEVICE_ERROR.
|
||||||
|
//
|
||||||
|
*ErrorOut = TRUE;
|
||||||
|
return EFI_DEVICE_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mTestedSystemMemory += BlockBoundary;
|
||||||
|
*TestedMemorySize = mTestedSystemMemory;
|
||||||
|
|
||||||
|
//
|
||||||
|
// If the memory test restart after the platform driver disable dimms,
|
||||||
|
// the NonTestSystemMemory may be changed, but the base memory size will
|
||||||
|
// not changed, so we can get the current total memory size.
|
||||||
|
//
|
||||||
|
*TotalMemorySize = Private->BaseMemorySize + mNonTestedSystemMemory;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Update the current test address pointing to next BDS BLOCK
|
||||||
|
//
|
||||||
|
mCurrentAddress += Private->BdsBlockSize;
|
||||||
|
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// Change to next non tested memory range
|
||||||
|
//
|
||||||
|
mCurrentLink = mCurrentLink->ForwardLink;
|
||||||
|
if (mCurrentLink != &Private->NonTestedMemRanList) {
|
||||||
|
mCurrentRange = NONTESTED_MEMORY_RANGE_FROM_LINK (mCurrentLink);
|
||||||
|
mCurrentAddress = mCurrentRange->StartAddress;
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
} else {
|
||||||
|
//
|
||||||
|
// Here means all the memory test have finished
|
||||||
|
//
|
||||||
|
*TestedMemorySize = mTestedSystemMemory;
|
||||||
|
*TotalMemorySize = Private->BaseMemorySize + mNonTestedSystemMemory;
|
||||||
|
return EFI_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Finish the memory test.
|
||||||
|
|
||||||
|
@param[in] This The protocol instance pointer.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS Success. All resources used in the memory test are freed.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
EFIAPI
|
||||||
|
GenMemoryTestFinished (
|
||||||
|
IN EFI_GENERIC_MEMORY_TEST_PROTOCOL *This
|
||||||
|
)
|
||||||
|
{
|
||||||
|
EFI_STATUS Status;
|
||||||
|
GENERIC_MEMORY_TEST_PRIVATE *Private;
|
||||||
|
|
||||||
|
Private = GENERIC_MEMORY_TEST_PRIVATE_FROM_THIS (This);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Perform Data and Address line test
|
||||||
|
//
|
||||||
|
Status = PerformAddressDataLineTest (Private);
|
||||||
|
ASSERT_EFI_ERROR (Status);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Add the non tested memory range to system memory map through GCD service
|
||||||
|
//
|
||||||
|
UpdateMemoryMap (Private);
|
||||||
|
|
||||||
|
//
|
||||||
|
// we need to free all the memory allocate
|
||||||
|
//
|
||||||
|
DestroyLinkList (Private);
|
||||||
|
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Provides the capability to test the compatible range used by some special drivers.
|
||||||
|
|
||||||
|
@param[in] This The protocol instance pointer.
|
||||||
|
@param[in] StartAddress The start address of the compatible memory range that
|
||||||
|
must be below 16M.
|
||||||
|
@param[in] Length The compatible memory range's length.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS The compatible memory range pass the memory test.
|
||||||
|
@retval EFI_INVALID_PARAMETER The compatible memory range are not below Low 16M.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
EFIAPI
|
||||||
|
GenCompatibleRangeTest (
|
||||||
|
IN EFI_GENERIC_MEMORY_TEST_PROTOCOL *This,
|
||||||
|
IN EFI_PHYSICAL_ADDRESS StartAddress,
|
||||||
|
IN UINT64 Length
|
||||||
|
)
|
||||||
|
{
|
||||||
|
EFI_STATUS Status;
|
||||||
|
GENERIC_MEMORY_TEST_PRIVATE *Private;
|
||||||
|
EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;
|
||||||
|
EFI_PHYSICAL_ADDRESS CurrentBase;
|
||||||
|
UINT64 CurrentLength;
|
||||||
|
|
||||||
|
Private = GENERIC_MEMORY_TEST_PRIVATE_FROM_THIS (This);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Check if the parameter is below 16MB
|
||||||
|
//
|
||||||
|
if (StartAddress + Length > 0x1000000) {
|
||||||
|
return EFI_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
CurrentBase = StartAddress;
|
||||||
|
do {
|
||||||
|
//
|
||||||
|
// Check the required memory range status; if the required memory range span
|
||||||
|
// the different GCD memory descriptor, it may be cause different action.
|
||||||
|
//
|
||||||
|
Status = gDS->GetMemorySpaceDescriptor (
|
||||||
|
CurrentBase,
|
||||||
|
&Descriptor
|
||||||
|
);
|
||||||
|
if (EFI_ERROR (Status)) {
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Descriptor.GcdMemoryType == EfiGcdMemoryTypeReserved &&
|
||||||
|
(Descriptor.Capabilities & (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED)) ==
|
||||||
|
(EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED)
|
||||||
|
) {
|
||||||
|
CurrentLength = Descriptor.BaseAddress + Descriptor.Length - CurrentBase;
|
||||||
|
if (CurrentBase + CurrentLength > StartAddress + Length) {
|
||||||
|
CurrentLength = StartAddress + Length - CurrentBase;
|
||||||
|
}
|
||||||
|
Status = DirectRangeTest (
|
||||||
|
Private,
|
||||||
|
CurrentBase,
|
||||||
|
CurrentLength,
|
||||||
|
Descriptor.Capabilities
|
||||||
|
);
|
||||||
|
if (EFI_ERROR (Status)) {
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CurrentBase = Descriptor.BaseAddress + Descriptor.Length;
|
||||||
|
} while (CurrentBase < StartAddress + Length);
|
||||||
|
//
|
||||||
|
// Here means the required range already be tested, so just return success.
|
||||||
|
//
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Perform the address line walking ones test.
|
||||||
|
|
||||||
|
@param[in] Private Point to generic memory test driver's private data.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS Successful finished walking ones test.
|
||||||
|
@retval EFI_OUT_OF_RESOURCE Could not get resource in base memory.
|
||||||
|
@retval EFI_ACCESS_DENIED Code may can not run here because if walking one test
|
||||||
|
failed, system may be already halt.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
PerformAddressDataLineTest (
|
||||||
|
IN GENERIC_MEMORY_TEST_PRIVATE *Private
|
||||||
|
)
|
||||||
|
{
|
||||||
|
LIST_ENTRY *ExtendedLink;
|
||||||
|
NONTESTED_MEMORY_RANGE *ExtendedRange;
|
||||||
|
BOOLEAN InExtendedRange;
|
||||||
|
EFI_PHYSICAL_ADDRESS TestAddress;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Light version no data line test, only perform the address line test
|
||||||
|
//
|
||||||
|
TestAddress = (EFI_PHYSICAL_ADDRESS) 0x1;
|
||||||
|
while (TestAddress < MAX_ADDRESS && TestAddress > 0) {
|
||||||
|
//
|
||||||
|
// only test if the address falls in the enabled range
|
||||||
|
//
|
||||||
|
InExtendedRange = FALSE;
|
||||||
|
ExtendedLink = Private->NonTestedMemRanList.BackLink;
|
||||||
|
while (ExtendedLink != &Private->NonTestedMemRanList) {
|
||||||
|
ExtendedRange = NONTESTED_MEMORY_RANGE_FROM_LINK (ExtendedLink);
|
||||||
|
if ((TestAddress >= ExtendedRange->StartAddress) &&
|
||||||
|
(TestAddress < (ExtendedRange->StartAddress + ExtendedRange->Length))
|
||||||
|
) {
|
||||||
|
InExtendedRange = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExtendedLink = ExtendedLink->BackLink;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (InExtendedRange) {
|
||||||
|
*(EFI_PHYSICAL_ADDRESS *) (UINTN) TestAddress = TestAddress;
|
||||||
|
Private->Cpu->FlushDataCache (Private->Cpu, TestAddress, 1, EfiCpuFlushTypeWriteBackInvalidate);
|
||||||
|
if (*(EFI_PHYSICAL_ADDRESS *) (UINTN) TestAddress != TestAddress) {
|
||||||
|
return EFI_ACCESS_DENIED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TestAddress = LShiftU64 (TestAddress, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// Driver entry here
|
||||||
|
//
|
||||||
|
GENERIC_MEMORY_TEST_PRIVATE mGenericMemoryTestPrivate = {
|
||||||
|
EFI_GENERIC_MEMORY_TEST_PRIVATE_SIGNATURE,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
{
|
||||||
|
InitializeMemoryTest,
|
||||||
|
GenPerformMemoryTest,
|
||||||
|
GenMemoryTestFinished,
|
||||||
|
GenCompatibleRangeTest
|
||||||
|
},
|
||||||
|
(EXTENDMEM_COVERAGE_LEVEL) 0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
NULL,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
{
|
||||||
|
NULL,
|
||||||
|
NULL
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
The generic memory test driver's entry point.
|
||||||
|
|
||||||
|
It initializes private data to default value.
|
||||||
|
|
||||||
|
@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 entry point is executed successfully.
|
||||||
|
@retval EFI_NOT_FOUND Can't find HandOff Hob in HobList.
|
||||||
|
@retval other Some error occurs when executing this entry point.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
EFIAPI
|
||||||
|
GenericMemoryTestEntryPoint (
|
||||||
|
IN EFI_HANDLE ImageHandle,
|
||||||
|
IN EFI_SYSTEM_TABLE *SystemTable
|
||||||
|
)
|
||||||
|
{
|
||||||
|
EFI_STATUS Status;
|
||||||
|
VOID *HobList;
|
||||||
|
EFI_BOOT_MODE BootMode;
|
||||||
|
EFI_PEI_HOB_POINTERS Hob;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Use the generic pattern to test compatible memory range
|
||||||
|
//
|
||||||
|
mGenericMemoryTestPrivate.MonoPattern = GenericMemoryTestMonoPattern;
|
||||||
|
mGenericMemoryTestPrivate.MonoTestSize = GENERIC_CACHELINE_SIZE;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Get the platform boot mode
|
||||||
|
//
|
||||||
|
HobList = GetHobList ();
|
||||||
|
|
||||||
|
Hob.Raw = HobList;
|
||||||
|
if (Hob.Header->HobType != EFI_HOB_TYPE_HANDOFF) {
|
||||||
|
return EFI_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
BootMode = Hob.HandoffInformationTable->BootMode;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Get the platform boot mode and create the default memory test coverage
|
||||||
|
// level and span size for compatible memory test using
|
||||||
|
//
|
||||||
|
switch (BootMode) {
|
||||||
|
case BOOT_WITH_FULL_CONFIGURATION:
|
||||||
|
case BOOT_WITH_DEFAULT_SETTINGS:
|
||||||
|
mGenericMemoryTestPrivate.CoverageSpan = SPARSE_SPAN_SIZE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BOOT_WITH_FULL_CONFIGURATION_PLUS_DIAGNOSTICS:
|
||||||
|
mGenericMemoryTestPrivate.CoverageSpan = GENERIC_CACHELINE_SIZE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
mGenericMemoryTestPrivate.CoverageSpan = QUICK_SPAN_SIZE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// Install the protocol
|
||||||
|
//
|
||||||
|
Status = gBS->InstallProtocolInterface (
|
||||||
|
&mGenericMemoryTestPrivate.Handle,
|
||||||
|
&gEfiGenericMemTestProtocolGuid,
|
||||||
|
EFI_NATIVE_INTERFACE,
|
||||||
|
&mGenericMemoryTestPrivate.GenericMemoryTest
|
||||||
|
);
|
||||||
|
|
||||||
|
return Status;
|
||||||
|
}
|
|
@ -0,0 +1,342 @@
|
||||||
|
/** @file
|
||||||
|
The generic memory test driver definition
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
**/
|
||||||
|
|
||||||
|
#ifndef _GENERIC_MEMORY_TEST_H_
|
||||||
|
#define _GENERIC_MEMORY_TEST_H_
|
||||||
|
|
||||||
|
#include <Guid/StatusCodeDataTypeId.h>
|
||||||
|
#include <Protocol/GenericMemoryTest.h>
|
||||||
|
#include <Protocol/Cpu.h>
|
||||||
|
|
||||||
|
#include <Library/DebugLib.h>
|
||||||
|
#include <Library/UefiDriverEntryPoint.h>
|
||||||
|
#include <Library/HobLib.h>
|
||||||
|
#include <Library/DxeServicesTableLib.h>
|
||||||
|
#include <Library/ReportStatusCodeLib.h>
|
||||||
|
#include <Library/BaseLib.h>
|
||||||
|
#include <Library/BaseMemoryLib.h>
|
||||||
|
#include <Library/MemoryAllocationLib.h>
|
||||||
|
#include <Library/UefiBootServicesTableLib.h>
|
||||||
|
|
||||||
|
//
|
||||||
|
// Some global define
|
||||||
|
//
|
||||||
|
#define GENERIC_CACHELINE_SIZE 0x40
|
||||||
|
|
||||||
|
//
|
||||||
|
// attributes for reserved memory before it is promoted to system memory
|
||||||
|
//
|
||||||
|
#define EFI_MEMORY_PRESENT 0x0100000000000000ULL
|
||||||
|
#define EFI_MEMORY_INITIALIZED 0x0200000000000000ULL
|
||||||
|
#define EFI_MEMORY_TESTED 0x0400000000000000ULL
|
||||||
|
|
||||||
|
//
|
||||||
|
// The SPARSE_SPAN_SIZE size can not small then the MonoTestSize
|
||||||
|
//
|
||||||
|
#define TEST_BLOCK_SIZE 0x2000000
|
||||||
|
#define QUICK_SPAN_SIZE (TEST_BLOCK_SIZE >> 2)
|
||||||
|
#define SPARSE_SPAN_SIZE (TEST_BLOCK_SIZE >> 4)
|
||||||
|
|
||||||
|
//
|
||||||
|
// This structure records every nontested memory range parsed through GCD
|
||||||
|
// service.
|
||||||
|
//
|
||||||
|
#define EFI_NONTESTED_MEMORY_RANGE_SIGNATURE SIGNATURE_32 ('N', 'T', 'M', 'E')
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
UINTN Signature;
|
||||||
|
LIST_ENTRY Link;
|
||||||
|
EFI_PHYSICAL_ADDRESS StartAddress;
|
||||||
|
UINT64 Length;
|
||||||
|
UINT64 Capabilities;
|
||||||
|
BOOLEAN Above4G;
|
||||||
|
BOOLEAN AlreadyMapped;
|
||||||
|
} NONTESTED_MEMORY_RANGE;
|
||||||
|
|
||||||
|
#define NONTESTED_MEMORY_RANGE_FROM_LINK(link) \
|
||||||
|
CR ( \
|
||||||
|
link, \
|
||||||
|
NONTESTED_MEMORY_RANGE, \
|
||||||
|
Link, \
|
||||||
|
EFI_NONTESTED_MEMORY_RANGE_SIGNATURE \
|
||||||
|
)
|
||||||
|
|
||||||
|
//
|
||||||
|
// This is the memory test driver's structure definition
|
||||||
|
//
|
||||||
|
#define EFI_GENERIC_MEMORY_TEST_PRIVATE_SIGNATURE SIGNATURE_32 ('G', 'E', 'M', 'T')
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
|
||||||
|
UINTN Signature;
|
||||||
|
EFI_HANDLE Handle;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Cpu arch protocol's pointer
|
||||||
|
//
|
||||||
|
EFI_CPU_ARCH_PROTOCOL *Cpu;
|
||||||
|
|
||||||
|
//
|
||||||
|
// generic memory test driver's protocol
|
||||||
|
//
|
||||||
|
EFI_GENERIC_MEMORY_TEST_PROTOCOL GenericMemoryTest;
|
||||||
|
|
||||||
|
//
|
||||||
|
// memory test covered spans
|
||||||
|
//
|
||||||
|
EXTENDMEM_COVERAGE_LEVEL CoverLevel;
|
||||||
|
UINTN CoverageSpan;
|
||||||
|
UINT64 BdsBlockSize;
|
||||||
|
|
||||||
|
//
|
||||||
|
// the memory test pattern and size every time R/W/V memory
|
||||||
|
//
|
||||||
|
VOID *MonoPattern;
|
||||||
|
UINTN MonoTestSize;
|
||||||
|
|
||||||
|
//
|
||||||
|
// base memory's size which tested in PEI phase
|
||||||
|
//
|
||||||
|
UINT64 BaseMemorySize;
|
||||||
|
|
||||||
|
//
|
||||||
|
// memory range list
|
||||||
|
//
|
||||||
|
LIST_ENTRY NonTestedMemRanList;
|
||||||
|
|
||||||
|
} GENERIC_MEMORY_TEST_PRIVATE;
|
||||||
|
|
||||||
|
#define GENERIC_MEMORY_TEST_PRIVATE_FROM_THIS(a) \
|
||||||
|
CR ( \
|
||||||
|
a, \
|
||||||
|
GENERIC_MEMORY_TEST_PRIVATE, \
|
||||||
|
GenericMemoryTest, \
|
||||||
|
EFI_GENERIC_MEMORY_TEST_PRIVATE_SIGNATURE \
|
||||||
|
)
|
||||||
|
|
||||||
|
//
|
||||||
|
// Function Prototypes
|
||||||
|
//
|
||||||
|
|
||||||
|
/**
|
||||||
|
Construct the system base memory range through GCD service.
|
||||||
|
|
||||||
|
@param[in] Private Point to generic memory test driver's private data.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS Successful construct the base memory range through GCD service.
|
||||||
|
@retval EFI_OUT_OF_RESOURCE Could not allocate needed resource from base memory.
|
||||||
|
@retval Others Failed to construct base memory range through GCD service.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
ConstructBaseMemoryRange (
|
||||||
|
IN GENERIC_MEMORY_TEST_PRIVATE *Private
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Construct the system non-tested memory range through GCD service.
|
||||||
|
|
||||||
|
@param[in] Private Point to generic memory test driver's private data.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS Successful construct the non-tested memory range through GCD service.
|
||||||
|
@retval EFI_OUT_OF_RESOURCE Could not allocate needed resource from base memory.
|
||||||
|
@retval Others Failed to construct non-tested memory range through GCD service.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
ConstructNonTestedMemoryRange (
|
||||||
|
IN GENERIC_MEMORY_TEST_PRIVATE *Private
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Perform the address line walking ones test.
|
||||||
|
|
||||||
|
@param[in] Private Point to generic memory test driver's private data.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS Successful finished walking ones test.
|
||||||
|
@retval EFI_OUT_OF_RESOURCE Could not get resource in base memory.
|
||||||
|
@retval EFI_ACCESS_DENIED Code may can not run here because if walking one test
|
||||||
|
failed, system may be already halt.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
PerformAddressDataLineTest (
|
||||||
|
IN GENERIC_MEMORY_TEST_PRIVATE *Private
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Destroy the link list base on the correspond link list type.
|
||||||
|
|
||||||
|
@param[in] Private Point to generic memory test driver's private data.
|
||||||
|
|
||||||
|
**/
|
||||||
|
VOID
|
||||||
|
DestroyLinkList (
|
||||||
|
IN GENERIC_MEMORY_TEST_PRIVATE *Private
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Add the extened memory to whole system memory map.
|
||||||
|
|
||||||
|
@param[in] Private Point to generic memory test driver's private data.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS Successful add all the extended memory to system memory map.
|
||||||
|
@retval Others Failed to add the tested extended memory.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
UpdateMemoryMap (
|
||||||
|
IN GENERIC_MEMORY_TEST_PRIVATE *Private
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Write the memory test pattern into a range of physical memory.
|
||||||
|
|
||||||
|
@param[in] Private Point to generic memory test driver's private data.
|
||||||
|
@param[in] Start The memory range's start address.
|
||||||
|
@param[in] Size The memory range's size.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS Successful write the test pattern into the non-tested memory.
|
||||||
|
@retval Others The test pattern may not really write into the physical memory.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
WriteMemory (
|
||||||
|
IN GENERIC_MEMORY_TEST_PRIVATE *Private,
|
||||||
|
IN EFI_PHYSICAL_ADDRESS Start,
|
||||||
|
IN UINT64 Size
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Verify the range of physical memory which covered by memory test pattern.
|
||||||
|
|
||||||
|
This function will also do not return any informatin just cause system reset,
|
||||||
|
because the handle error encount fatal error and disable the bad DIMMs.
|
||||||
|
|
||||||
|
@param[in] Private Point to generic memory test driver's private data.
|
||||||
|
@param[in] Start The memory range's start address.
|
||||||
|
@param[in] Size The memory range's size.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS Successful verify the range of memory, no errors' location found.
|
||||||
|
@retval Others The range of memory have errors contained.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
VerifyMemory (
|
||||||
|
IN GENERIC_MEMORY_TEST_PRIVATE *Private,
|
||||||
|
IN EFI_PHYSICAL_ADDRESS Start,
|
||||||
|
IN UINT64 Size
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Test a range of the memory directly .
|
||||||
|
|
||||||
|
@param[in] Private Point to generic memory test driver's private data.
|
||||||
|
@param[in] StartAddress Starting address of the memory range to be tested.
|
||||||
|
@param[in] Length Length in bytes of the memory range to be tested.
|
||||||
|
@param[in] Capabilities The bit mask of attributes that the memory range supports.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS Successful test the range of memory.
|
||||||
|
@retval Others Failed to test the range of memory.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
DirectRangeTest (
|
||||||
|
IN GENERIC_MEMORY_TEST_PRIVATE *Private,
|
||||||
|
IN EFI_PHYSICAL_ADDRESS StartAddress,
|
||||||
|
IN UINT64 Length,
|
||||||
|
IN UINT64 Capabilities
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Initialize the generic memory test.
|
||||||
|
|
||||||
|
@param[in] This The protocol instance pointer.
|
||||||
|
@param[in] Level The coverage level of the memory test.
|
||||||
|
@param[out] RequireSoftECCInit Indicate if the memory need software ECC init.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS The generic memory test is initialized correctly.
|
||||||
|
@retval EFI_NO_MEDIA The system had no memory to be tested.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
EFIAPI
|
||||||
|
InitializeMemoryTest (
|
||||||
|
IN EFI_GENERIC_MEMORY_TEST_PROTOCOL *This,
|
||||||
|
IN EXTENDMEM_COVERAGE_LEVEL Level,
|
||||||
|
OUT BOOLEAN *RequireSoftECCInit
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Perform the memory test.
|
||||||
|
|
||||||
|
@param[in] This The protocol instance pointer.
|
||||||
|
@param[out] TestedMemorySize Return the tested extended memory size.
|
||||||
|
@param[out] TotalMemorySize Return the whole system physical memory size.
|
||||||
|
The total memory size does not include memory in a slot with a disabled DIMM.
|
||||||
|
@param[out] ErrorOut TRUE if the memory error occured.
|
||||||
|
@param[in] IfTestAbort Indicates that the user pressed "ESC" to skip the memory test.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS One block of memory passed the test.
|
||||||
|
@retval EFI_NOT_FOUND All memory blocks have already been tested.
|
||||||
|
@retval EFI_DEVICE_ERROR Memory device error occured, and no agent can handle it.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
EFIAPI
|
||||||
|
GenPerformMemoryTest (
|
||||||
|
IN EFI_GENERIC_MEMORY_TEST_PROTOCOL *This,
|
||||||
|
OUT UINT64 *TestedMemorySize,
|
||||||
|
OUT UINT64 *TotalMemorySize,
|
||||||
|
OUT BOOLEAN *ErrorOut,
|
||||||
|
IN BOOLEAN TestAbort
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Finish the memory test.
|
||||||
|
|
||||||
|
@param[in] This The protocol instance pointer.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS Success. All resources used in the memory test are freed.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
EFIAPI
|
||||||
|
GenMemoryTestFinished (
|
||||||
|
IN EFI_GENERIC_MEMORY_TEST_PROTOCOL *This
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Provides the capability to test the compatible range used by some special drivers.
|
||||||
|
|
||||||
|
@param[in] This The protocol instance pointer.
|
||||||
|
@param[in] StartAddress The start address of the compatible memory range that
|
||||||
|
must be below 16M.
|
||||||
|
@param[in] Length The compatible memory range's length.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS The compatible memory range pass the memory test.
|
||||||
|
@retval EFI_INVALID_PARAMETER The compatible memory range are not below Low 16M.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
EFIAPI
|
||||||
|
GenCompatibleRangeTest (
|
||||||
|
IN EFI_GENERIC_MEMORY_TEST_PROTOCOL *This,
|
||||||
|
IN EFI_PHYSICAL_ADDRESS StartAddress,
|
||||||
|
IN UINT64 Length
|
||||||
|
);
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue